diff --git a/libp2p/RLPxFrameIO.cpp b/libp2p/RLPxFrameIO.cpp index 2c233c1d4..cb768bfeb 100644 --- a/libp2p/RLPxFrameIO.cpp +++ b/libp2p/RLPxFrameIO.cpp @@ -104,9 +104,8 @@ void RLPXFrameIO::writeSingleFramePacket(bytesConstRef _packet, bytes& o_bytes) // TODO: SECURITY check that header is <= 16 bytes - bytes headerWithMac; - header.swapOut(headerWithMac); - headerWithMac.resize(32); + bytes headerWithMac(h256::size); + bytesConstRef(&header.out()).copyTo(bytesRef(&headerWithMac)); m_frameEnc.ProcessData(headerWithMac.data(), headerWithMac.data(), 16); updateEgressMACWithHeader(bytesConstRef(&headerWithMac).cropped(0, 16)); egressDigest().ref().copyTo(bytesRef(&headerWithMac).cropped(h128::size,h128::size)); diff --git a/libp2p/RLPxFrameIO.h b/libp2p/RLPxFrameIO.h index 3a0fd35e0..0f0504e48 100644 --- a/libp2p/RLPxFrameIO.h +++ b/libp2p/RLPxFrameIO.h @@ -41,6 +41,12 @@ class RLPXHandshake; /** * @brief Encoder/decoder transport for RLPx connections established by RLPXHandshake. * Managed (via shared_ptr) socket for use by RLPXHandshake and RLPXFrameIO. + * + * Thread Safety + * Distinct Objects: Safe. + * Shared objects: Unsafe. + * * an instance method must not be called concurrently + * * a writeSingleFramePacket can be called concurrent to authAndDecryptHeader OR authAndDecryptFrame */ class RLPXSocket: public std::enable_shared_from_this { diff --git a/libp2p/RLPxHandshake.cpp b/libp2p/RLPxHandshake.cpp index a1ede6056..801848107 100644 --- a/libp2p/RLPxHandshake.cpp +++ b/libp2p/RLPxHandshake.cpp @@ -133,6 +133,8 @@ void RLPXHandshake::error() { clog(NetConnect) << "Disconnecting " << m_socket->remoteEndpoint() << " (Handshake Failed)"; m_socket->close(); + if (m_io != nullptr) + delete m_io; } void RLPXHandshake::transition(boost::system::error_code _ech) @@ -175,7 +177,7 @@ void RLPXHandshake::transition(boost::system::error_code _ech) << m_host->protocolVersion() << m_host->m_clientVersion << m_host->caps() - << m_host->m_tcpPublic.port() + << m_host->listenPort() << m_host->id(); bytes packet; s.swapOut(packet); @@ -252,7 +254,6 @@ void RLPXHandshake::transition(boost::system::error_code _ech) } clog(NetNote) << (m_originated ? "p2p.connect.egress" : "p2p.connect.ingress") << "hello frame: success. starting session."; - RLP rlp(frame.cropped(1)); m_host->startPeerSession(m_remote, rlp, m_io, m_socket->remoteEndpoint()); } diff --git a/libp2p/RLPxHandshake.h b/libp2p/RLPxHandshake.h index cd5e7fb83..7ea95173f 100644 --- a/libp2p/RLPxHandshake.h +++ b/libp2p/RLPxHandshake.h @@ -36,66 +36,89 @@ namespace dev namespace p2p { +/** + * @brief Setup inbound or outbound connection for communication over RLPXFrameIO. + * RLPx Spec: https://github.com/ethereum/devp2p/blob/master/rlpx.md#encrypted-handshake + * + * @todo Implement StartSession transition via lambda which is passed to constructor. + * + * Thread Safety + * Distinct Objects: Safe. + * Shared objects: Unsafe. + */ class RLPXHandshake: public std::enable_shared_from_this { friend class RLPXFrameIO; + + /// Sequential states of handshake enum State { Error = -1, - New, // New->AckAuth [egress: tx auth, ingress: rx auth] - AckAuth, // AckAuth->WriteHello [egress: rx ack, ingress: tx ack] - WriteHello, // WriteHello [tx caps, rx caps, writehello] + New, + AckAuth, + WriteHello, ReadHello, StartSession }; public: - /// Handshake for ingress connection. Takes ownership of socket. + /// Setup incoming connection. RLPXHandshake(Host* _host, std::shared_ptr const& _socket): m_host(_host), m_originated(false), m_socket(_socket) { crypto::Nonce::get().ref().copyTo(m_nonce.ref()); } - /// Handshake for egress connection to _remote. Takes ownership of socket. + /// Setup outbound connection. RLPXHandshake(Host* _host, std::shared_ptr const& _socket, NodeId _remote): m_host(_host), m_remote(_remote), m_originated(true), m_socket(_socket) { crypto::Nonce::get().ref().copyTo(m_nonce.ref()); } ~RLPXHandshake() {} + /// Start handshake. void start() { transition(); } protected: + /// Write Auth message to socket and transitions to AckAuth. void writeAuth(); + + /// Reads Auth message from socket and transitions to AckAuth. void readAuth(); + /// Write Ack message to socket and transitions to WriteHello. void writeAck(); + + /// Reads Auth message from socket and transitions to WriteHello. void readAck(); + /// Closes connection and ends transitions. void error(); + + /// Performs transition for m_nextState. void transition(boost::system::error_code _ech = boost::system::error_code()); - /// Current state of handshake. - State m_nextState = New; + State m_nextState = New; ///< Current or expected state of transition. - Host* m_host; + Host* m_host; ///< Host which provides m_alias, protocolVersion(), m_clientVersion, caps(), and TCP listenPort(). /// Node id of remote host for socket. - NodeId m_remote; - bool m_originated = false; + NodeId m_remote; ///< Public address of remote host. + bool m_originated = false; ///< True if connection is outbound. /// Buffers for encoded and decoded handshake phases - bytes m_auth; - bytes m_authCipher; - bytes m_ack; - bytes m_ackCipher; - bytes m_handshakeOutBuffer; - bytes m_handshakeInBuffer; - - crypto::ECDHE m_ecdhe; - h256 m_nonce; - - Public m_remoteEphemeral; - h256 m_remoteNonce; - - /// Frame IO is used to read frame for last step of handshake authentication. - RLPXFrameIO* m_io; - std::shared_ptr m_socket; + bytes m_auth; ///< Plaintext of egress or ingress Auth message. + bytes m_authCipher; ///< Ciphertext of egress or ingress Auth message. + bytes m_ack; ///< Plaintext of egress or ingress Ack message. + bytes m_ackCipher; ///< Ciphertext of egress or ingress Ack message. + bytes m_handshakeOutBuffer; ///< Frame buffer for egress Hello packet. + bytes m_handshakeInBuffer; ///< Frame buffer for ingress Hello packet. + + crypto::ECDHE m_ecdhe; ///< Ephemeral ECDH secret and agreement. + h256 m_nonce; ///< Nonce generated by this host for handshake. + + Public m_remoteEphemeral; ///< Remote ephemeral public key. + h256 m_remoteNonce; ///< Nonce generated by remote host for handshake. + + /// Used to read and write RLPx encrypted frames for last step of handshake authentication. + /// Passed onto Host which will take ownership. + RLPXFrameIO* m_io = nullptr; + + std::shared_ptr m_socket; ///< Socket. }; }