From 8e0e396ecec0180ecf2e5f2889cb9ff9ac3a46c8 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sun, 29 Apr 2012 13:58:52 -0700 Subject: [PATCH] Verify connected nodes identity. --- src/Peer.cpp | 65 +++++++++++++++++++++++++++-------------------- src/Peer.h | 3 ++- src/newcoin.proto | 7 ++--- 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/src/Peer.cpp b/src/Peer.cpp index c38008be8..9d6f612ec 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -97,7 +97,6 @@ void Peer::connect(const std::string strIp, int iPort) { int iPortAct = iPort < 0 ? SYSTEM_PEER_PORT : iPort; - // XXX Should not print IP if not known sane. std::cerr << "Peer::connect: " << strIp << " " << iPort << std::endl; mIpPort = make_pair(strIp, iPort); @@ -142,7 +141,7 @@ void Peer::connect(const std::string strIp, int iPort) // We have an ecrypted connection to the peer. // Have it say who it is so we know to avoid redundant connections. // Establish that it really who we are talking to by having it sign a connection detail. -// XXX Also need to establish no man in the middle attack is in progress. +// Also need to establish no man in the middle attack is in progress. void Peer::handleStart(const boost::system::error_code& error) { if (error) @@ -173,9 +172,7 @@ void Peer::handleConnect(const boost::system::error_code& error, boost::asio::ip mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none); mSocketSsl.async_handshake(boost::asio::ssl::stream::client, - boost::bind(&Peer::handleStart, - shared_from_this(), - boost::asio::placeholders::error)); + boost::bind(&Peer::handleStart, shared_from_this(), boost::asio::placeholders::error)); } } @@ -215,9 +212,7 @@ void Peer::connected(const boost::system::error_code& error) mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none); mSocketSsl.async_handshake(boost::asio::ssl::stream::server, - boost::bind(&Peer::handleStart, - shared_from_this(), - boost::asio::placeholders::error)); + boost::bind(&Peer::handleStart, shared_from_this(), boost::asio::placeholders::error)); } } @@ -488,14 +483,15 @@ void Peer::recvHello(newcoin::TMHello& packet) #endif bool bDetach = true; - if (mNodePublic.isValid()) - { - std::cerr << "Recv(Hello): Disconnect: Extraneous node public key." << std::endl; - } - else if (!mNodePublic.setNodePublic(packet.nodepublic())) + if (!mNodePublic.setNodePublic(packet.nodepublic())) { std::cerr << "Recv(Hello): Disconnect: Bad node public key." << std::endl; } + else if (!mNodePublic.verifyNodePublic(mCookieHash, packet.nodeproof())) + { + // Unable to verify they have private key for claimed public key. + std::cerr << "Recv(Hello): Disconnect: Failed to verify session." << std::endl; + } else if (!theApp->getConnectionPool().peerConnected(shared_from_this(), mNodePublic)) { // Already connected, self, or some other reason. @@ -504,12 +500,13 @@ void Peer::recvHello(newcoin::TMHello& packet) else { // Successful connection. + + // Cancel verification timeout. + (void) mVerifyTimer.cancel(); + // XXX Set timer: connection is in grace period to be useful. // XXX Set timer: connection idle (idle may vary depending on connection type.) - // XXX Only kill if verified no man-in-the-middle. - (void) mVerifyTimer.cancel(); - bDetach = false; } @@ -712,36 +709,50 @@ void Peer::recvLedger(newcoin::TMLedgerData& packet) punishPeer(PP_UNWANTED_DATA); } -std::vector Peer::getSessionCookie() +// Get session information we can sign to prevent man in the middle attack. +// (both sides get the same information, neither side controls it) +void Peer::getSessionCookie(std::string& strDst) { - // get session information we can sign - // (both sides get the same information, neither side controls it) SSL* ssl = mSocketSsl.native_handle(); if (!ssl) throw std::runtime_error("No underlying connection"); // Get both finished messages unsigned char s1[1024], s2[1024]; - int l1 = SSL_get_finished(ssl, s1, 1024); - int l2 = SSL_get_finished(ssl, s2, 1024); - if ((l1 < 16) || (l2 < 16)) throw std::runtime_error("Connection setup not complete"); + int l1 = SSL_get_finished(ssl, s1, sizeof(s1)); + int l2 = SSL_get_peer_finished(ssl, s2, sizeof(s2)); + + if ((l1 < 12) || (l2 < 12)) + throw std::runtime_error(str(boost::format("Connection setup not complete: %d %d") % l1 % l2)); // Hash them and XOR the results - unsigned char sha1[32], sha2[32]; + unsigned char sha1[64], sha2[64]; + SHA512(s1, l1, sha1); SHA512(s2, l2, sha2); - for(int i=0; i<32; i++) sha1[i]^=sha2[i]; - return std::vector(sha1, sha1+33); + + for (int i=0; i vchSig; + + getSessionCookie(strCookie); + mCookieHash = Serializer::getSHA512Half(strCookie); + + theApp->getWallet().getNodePrivate().signNodePrivate(mCookieHash, vchSig); + newcoin::TMHello* h=new newcoin::TMHello(); - // set up parameters + h->set_version(theConfig.VERSION); h->set_ledgerindex(theApp->getOPs().getCurrentLedgerID()); h->set_nettime(theApp->getOPs().getNetworkTime()); h->set_nodepublic(theApp->getWallet().getNodePublic().humanNodePublic()); + h->set_nodeproof(&vchSig[0], vchSig.size()); h->set_ipv4port(theConfig.PEER_PORT); Ledger::pointer closingLedger=theApp->getMasterLedger().getClosingLedger(); diff --git a/src/Peer.h b/src/Peer.h index f86cd2bf4..1c4240934 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -33,6 +33,7 @@ public: private: NewcoinAddress mNodePublic; // Node public key of peer. ipPort mIpPort; + uint256 mCookieHash; boost::asio::ssl::stream mSocketSsl; @@ -81,7 +82,7 @@ protected: void recvGetLedger(newcoin::TMGetLedger& packet); void recvLedger(newcoin::TMLedgerData& packet); - std::vector getSessionCookie(); + void getSessionCookie(std::string& strDst); public: typedef boost::shared_ptr pointer; diff --git a/src/newcoin.proto b/src/newcoin.proto index 538f0f98f..ab67b2571 100644 --- a/src/newcoin.proto +++ b/src/newcoin.proto @@ -38,9 +38,10 @@ message TMHello { required uint32 version = 1; optional uint32 ledgerIndex = 2; optional uint64 netTime = 3; - optional bytes nodePublic = 4; // node may opt to remain anonymous - optional uint32 ipv4Port = 5; - optional bytes closedLedger = 6; + optional bytes nodePublic = 4; // node may opt to remain anonymous + optional bytes nodeProof = 5; + optional uint32 ipv4Port = 6; + optional bytes closedLedger = 7; }