From 21f6dd1f879017a3b07462dd7242e8887b38f430 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 27 Apr 2012 21:58:58 -0700 Subject: [PATCH] Add basic ssl support for peer connections. --- src/ConnectionPool.cpp | 15 +++++-- src/ConnectionPool.h | 3 ++ src/Peer.cpp | 89 ++++++++++++++++++++++++------------------ src/Peer.h | 16 ++++---- src/PeerDoor.cpp | 40 +++++++++++++++++-- src/PeerDoor.h | 11 ++++-- src/RPCDoor.cpp | 3 +- 7 files changed, 118 insertions(+), 59 deletions(-) diff --git a/src/ConnectionPool.cpp b/src/ConnectionPool.cpp index 685ad2f41..df16ef820 100644 --- a/src/ConnectionPool.cpp +++ b/src/ConnectionPool.cpp @@ -8,10 +8,17 @@ #include "Application.h" #include "utils.h" - ConnectionPool::ConnectionPool() : - iConnecting(0) -{ ; } + iConnecting(0), + mCtx(boost::asio::ssl::context::sslv23) +{ + mCtx.set_options( + boost::asio::ssl::context::default_workarounds + | boost::asio::ssl::context::no_sslv2 + | boost::asio::ssl::context::single_dh_use); + + SSL_CTX_set_cipher_list(mCtx.native_handle(), "ALL:!LOW:!EXP:!MD5:@STRENGTH"); +} void ConnectionPool::start() @@ -80,7 +87,7 @@ bool ConnectionPool::connectTo(const std::string& strIp, int iPort) std::cerr << "ConnectionPool::connectTo: Connectting: " << strIp << " " << iPort << std::endl; - Peer::pointer peer(Peer::create(theApp->getIOService())); + Peer::pointer peer(Peer::create(theApp->getIOService(), mCtx)); mIpMap[ip] = peer; diff --git a/src/ConnectionPool.h b/src/ConnectionPool.h index 135ab3b25..5d76d5a04 100644 --- a/src/ConnectionPool.h +++ b/src/ConnectionPool.h @@ -1,6 +1,7 @@ #ifndef __CONNECTION_POOL__ #define __CONNECTION_POOL__ +#include #include #include "Peer.h" @@ -27,6 +28,8 @@ private: // Non-thin peers which we are connected to. boost::unordered_map mConnectedMap; + boost::asio::ssl::context mCtx; + public: ConnectionPool(); diff --git a/src/Peer.cpp b/src/Peer.cpp index 4192d070b..9c67d98f9 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -16,10 +16,8 @@ #include "SerializedTransaction.h" #include "utils.h" -Peer::Peer(boost::asio::io_service& io_service) - : mSocket(io_service), - mCtx(boost::asio::ssl::context::sslv23), - mSocketSsl(io_service, mCtx) +Peer::Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx) + : mSocketSsl(io_service, ctx) { } @@ -54,7 +52,7 @@ void Peer::handle_write(const boost::system::error_code& error, size_t bytes_tra void Peer::detach() { mSendQ.clear(); - mSocket.close(); + // mSocketSsl.close(); if (!mIpPort.first.empty()) { theApp->getConnectionPool().peerDisconnected(shared_from_this()); @@ -86,30 +84,33 @@ void Peer::connect(const std::string strIp, int iPort) else { std::cerr << "Peer::connect: Connectting: " << mIpPort.first << " " << mIpPort.second << std::endl; -#if 1 - boost::asio::async_connect( - mSocket, - itrEndpoint, - boost::bind( - &Peer::handleConnect, - shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::iterator)); -#else - // Connect via ssl. - // XXX Why doesn't handler need an iterator? + boost::asio::async_connect( mSocketSsl.lowest_layer(), itrEndpoint, boost::bind( &Peer::handleConnect, shared_from_this(), - boost::asio::placeholders::error)); -#endif + boost::asio::placeholders::error, + boost::asio::placeholders::iterator)); } } -// SSL connection. +void Peer::handleStart(const boost::system::error_code& error) +{ + if (error) + { + std::cout << "Peer::handleStart: failed:" << error << std::endl; + detach(); + } + else + { + start_read_header(); + sendHello(); + } +} + +// Connect as client. void Peer::handleConnect(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator it) { if (error) @@ -121,15 +122,23 @@ void Peer::handleConnect(const boost::system::error_code& error, boost::asio::ip { std::cout << "Socket Connected." << std::endl; - start_read_header(); - sendHello(); + mSocketSsl.lowest_layer().set_option(boost::asio::ip::tcp::no_delay(true)); + mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none); + + // XXX Do what? + // mSocketSsl.set_verify_callback(boost::asio::ssl::rfc2818_verification(mDeqSites[0]), mShutdown); + + mSocketSsl.async_handshake(boost::asio::ssl::stream::client, + boost::bind(&Peer::handleStart, + shared_from_this(), + boost::asio::placeholders::error)); } } -// Peer connected via door. +// Connect as server. void Peer::connected(const boost::system::error_code& error) { - boost::asio::ip::tcp::endpoint ep = mSocket.remote_endpoint(); + boost::asio::ip::tcp::endpoint ep = mSocketSsl.lowest_layer().remote_endpoint(); int iPort = ep.port(); std::string strIp = ep.address().to_string(); @@ -158,15 +167,23 @@ void Peer::connected(const boost::system::error_code& error) mIpPort = make_pair(strIp, iPort); - start_read_header(); - sendHello(); + mSocketSsl.lowest_layer().set_option(boost::asio::ip::tcp::no_delay(true)); + mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none); + + // XXX Do what? + // mSocketSsl.set_verify_callback(boost::asio::ssl::rfc2818_verification(mDeqSites[0]), mShutdown); + + mSocketSsl.async_handshake(boost::asio::ssl::stream::server, + boost::bind(&Peer::handleStart, + shared_from_this(), + boost::asio::placeholders::error)); } } void Peer::sendPacketForce(PackedMessage::pointer packet) { mSendingPacket=packet; - boost::asio::async_write(mSocket, boost::asio::buffer(packet->getBuffer()), + boost::asio::async_write(mSocketSsl, boost::asio::buffer(packet->getBuffer()), boost::bind(&Peer::handle_write, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); @@ -194,7 +211,7 @@ void Peer::start_read_header() #endif mReadbuf.clear(); mReadbuf.resize(HEADER_SIZE); - boost::asio::async_read(mSocket, boost::asio::buffer(mReadbuf), + boost::asio::async_read(mSocketSsl, boost::asio::buffer(mReadbuf), boost::bind(&Peer::handle_read_header, shared_from_this(), boost::asio::placeholders::error)); } @@ -205,13 +222,13 @@ void Peer::start_read_body(unsigned msg_len) // read into the body. // mReadbuf.resize(HEADER_SIZE + msg_len); - boost::asio::async_read(mSocket, boost::asio::buffer(&mReadbuf[HEADER_SIZE], msg_len), + boost::asio::async_read(mSocketSsl, boost::asio::buffer(&mReadbuf[HEADER_SIZE], msg_len), boost::bind(&Peer::handle_read_body, shared_from_this(), boost::asio::placeholders::error)); } void Peer::handle_read_header(const boost::system::error_code& error) { - if(!error) + if (!error) { unsigned msg_len = PackedMessage::getLength(mReadbuf); // WRITEME: Compare to maximum message length, abort if too large @@ -225,13 +242,13 @@ void Peer::handle_read_header(const boost::system::error_code& error) else { detach(); - std::cout << "Peer::connected Error: " << error << std::endl; //else BOOST_LOG_TRIVIAL(info) << "Error: " << error; + std::cout << "Peer::handle_read_header: Error: " << error << std::endl; //else BOOST_LOG_TRIVIAL(info) << "Error: " << error; } } void Peer::handle_read_body(const boost::system::error_code& error) { - if(!error) + if (!error) { processReadBuffer(); start_read_header(); @@ -239,7 +256,7 @@ void Peer::handle_read_body(const boost::system::error_code& error) else { detach(); - std::cout << "Peer::connected Error: " << error << std::endl; //else BOOST_LOG_TRIVIAL(info) << "Error: " << error; + std::cout << "Peer::handle_read_body: Error: " << error << std::endl; //else BOOST_LOG_TRIVIAL(info) << "Error: " << error; } } @@ -360,7 +377,7 @@ void Peer::processReadBuffer() } break; - #if 0 +#if 0 case newcoin::mtPROPOSE_LEDGER: { newcoin::TM msg; @@ -396,9 +413,7 @@ void Peer::processReadBuffer() else std::cout << "pars error: " << type << std::endl; } break; - - #endif - +#endif case newcoin::mtGET_OBJECT: { newcoin::TMGetObjectByHash msg; diff --git a/src/Peer.h b/src/Peer.h index f86937688..d1bee4a2c 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -34,12 +34,10 @@ public: void handleConnect(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator it); private: - bool bRegistered; - - boost::asio::ip::tcp::socket mSocket; - boost::asio::ssl::context mCtx; boost::asio::ssl::stream mSocketSsl; + void handleStart(const boost::system::error_code& error); + protected: std::vector mReadbuf; @@ -47,7 +45,7 @@ protected: PackedMessage::pointer mSendingPacket; std::bitset<32> mPeerBits; - Peer(boost::asio::io_service& io_service); + Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx); void handle_write(const boost::system::error_code& error, size_t bytes_transferred); //void handle_read(const boost::system::error_code& error, size_t bytes_transferred); @@ -85,14 +83,14 @@ public: //bool operator == (const Peer& other); - static pointer create(boost::asio::io_service& io_service) + static pointer create(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx) { - return pointer(new Peer(io_service)); + return pointer(new Peer(io_service, ctx)); } - boost::asio::ip::tcp::socket& getSocket() + boost::asio::ssl::stream::lowest_layer_type& getSocket() { - return mSocket; + return mSocketSsl.lowest_layer(); } void connect(const std::string strIp, int iPort); diff --git a/src/PeerDoor.cpp b/src/PeerDoor.cpp index 5acf2a688..e417ab012 100644 --- a/src/PeerDoor.cpp +++ b/src/PeerDoor.cpp @@ -4,23 +4,55 @@ #include #include +#include //#include +#include #include "Config.h" using namespace std; using namespace boost::asio::ip; -PeerDoor::PeerDoor(boost::asio::io_service& io_service) : - mAcceptor(io_service, tcp::endpoint(address().from_string(theConfig.PEER_IP), theConfig.PEER_PORT)) +// Generate DH for SSL connection. +static DH* handleTmpDh(SSL* ssl, int is_export, int keylength) { - cout << "Opening peer door on port: " << theConfig.PEER_PORT << endl; + // We don't care if for export or what length was requested. Always do 512. + static DH* mDh512 = 0; + + if (!mDh512) + { + int iCodes; + + do { + mDh512 = DH_generate_parameters(512, DH_GENERATOR_5, NULL, NULL); + iCodes = 0; + DH_check(mDh512, &iCodes); + } while (iCodes & (DH_CHECK_P_NOT_PRIME|DH_CHECK_P_NOT_SAFE_PRIME|DH_UNABLE_TO_CHECK_GENERATOR|DH_NOT_SUITABLE_GENERATOR)); + } + + return mDh512; +} + +PeerDoor::PeerDoor(boost::asio::io_service& io_service) : + mAcceptor(io_service, tcp::endpoint(address().from_string(theConfig.PEER_IP), theConfig.PEER_PORT)), + mCtx(boost::asio::ssl::context::sslv23) +{ + mCtx.set_options( + boost::asio::ssl::context::default_workarounds + | boost::asio::ssl::context::no_sslv2 + | boost::asio::ssl::context::single_dh_use); + + SSL_CTX_set_tmp_dh_callback(mCtx.native_handle(), handleTmpDh); + SSL_CTX_set_cipher_list(mCtx.native_handle(), "ALL:!LOW:!EXP:!MD5:@STRENGTH"); + + cerr << "Peer port: " << theConfig.PEER_IP << " " << theConfig.PEER_PORT << endl; + startListening(); } void PeerDoor::startListening() { - Peer::pointer new_connection = Peer::create(mAcceptor.get_io_service()); + Peer::pointer new_connection = Peer::create(mAcceptor.get_io_service(), mCtx); mAcceptor.async_accept(new_connection->getSocket(), boost::bind(&PeerDoor::handleConnect, this, new_connection, diff --git a/src/PeerDoor.h b/src/PeerDoor.h index a53defc6e..52b8fae1e 100644 --- a/src/PeerDoor.h +++ b/src/PeerDoor.h @@ -2,6 +2,7 @@ #include #include +#include #include "Peer.h" @@ -11,10 +12,12 @@ Handles incoming connections from other Peers class PeerDoor { - boost::asio::ip::tcp::acceptor mAcceptor; - void startListening(); - void handleConnect(Peer::pointer new_connection, - const boost::system::error_code& error); +private: + boost::asio::ip::tcp::acceptor mAcceptor; + boost::asio::ssl::context mCtx; + + void startListening(); + void handleConnect(Peer::pointer new_connection, const boost::system::error_code& error); public: PeerDoor(boost::asio::io_service& io_service); diff --git a/src/RPCDoor.cpp b/src/RPCDoor.cpp index 95a0aee15..2e85cad71 100644 --- a/src/RPCDoor.cpp +++ b/src/RPCDoor.cpp @@ -10,7 +10,7 @@ using namespace boost::asio::ip; RPCDoor::RPCDoor(boost::asio::io_service& io_service) : mAcceptor(io_service, tcp::endpoint(address::from_string(theConfig.RPC_IP), theConfig.RPC_PORT)) { - cout << "Opening rpc door on port: " << theConfig.RPC_PORT << endl; + cerr << "RPC port: " << theConfig.RPC_IP << " " << theConfig.RPC_PORT << endl; startListening(); } @@ -47,3 +47,4 @@ void RPCDoor::handleConnect(RPCServer::pointer new_connection, startListening(); } +// vim:ts=4