forked from ethereum/aleth
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRLPxHandshake.h
148 lines (113 loc) · 5.05 KB
/
RLPxHandshake.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file RLPXHandshake.h
* @author Alex Leverington <nessence@gmail.com>
* @date 2015
*/
#pragma once
#include <memory>
#include <libdevcrypto/Common.h>
#include "RLPXSocket.h"
#include "RLPXFrameCoder.h"
#include "Common.h"
namespace ba = boost::asio;
namespace bi = boost::asio::ip;
namespace dev
{
namespace p2p
{
static const unsigned c_rlpxVersion = 4;
/**
* @brief Setup inbound or outbound connection for communication over RLPXFrameCoder.
* 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<RLPXHandshake>
{
friend class RLPXFrameCoder;
public:
/// Setup incoming connection.
RLPXHandshake(Host* _host, std::shared_ptr<RLPXSocket> const& _socket): m_host(_host), m_originated(false), m_socket(_socket), m_idleTimer(m_socket->ref().get_io_service()) { crypto::Nonce::get().ref().copyTo(m_nonce.ref()); }
/// Setup outbound connection.
RLPXHandshake(Host* _host, std::shared_ptr<RLPXSocket> const& _socket, NodeID _remote): m_host(_host), m_remote(_remote), m_originated(true), m_socket(_socket), m_idleTimer(m_socket->ref().get_io_service()) { crypto::Nonce::get().ref().copyTo(m_nonce.ref()); }
virtual ~RLPXHandshake() = default;
/// Start handshake.
void start() { transition(); }
/// Aborts the handshake.
void cancel();
protected:
/// Sequential states of handshake
enum State
{
Error = -1,
New,
AckAuth,
AckAuthEIP8,
WriteHello,
ReadHello,
StartSession
};
/// Write Auth message to socket and transitions to AckAuth.
void writeAuth();
/// Reads Auth message from socket and transitions to AckAuth.
void readAuth();
/// Continues reading Auth message in EIP-8 format and transitions to AckAuthEIP8.
void readAuthEIP8();
/// Derives ephemeral secret from signature and sets members after Auth has been decrypted.
void setAuthValues(Signature const& sig, Public const& remotePubk, h256 const& remoteNonce, uint64_t remoteVersion);
/// Write Ack message to socket and transitions to WriteHello.
void writeAck();
/// Write Ack message in EIP-8 format to socket and transitions to WriteHello.
void writeAckEIP8();
/// Reads Auth message from socket and transitions to WriteHello.
void readAck();
/// Continues reading Ack message in EIP-8 format and transitions to WriteHello.
void readAckEIP8();
/// Closes connection and ends transitions.
void error();
/// Performs transition for m_nextState.
virtual void transition(boost::system::error_code _ech = boost::system::error_code());
/// Timeout for remote to respond to transition events. Enforced by m_idleTimer and refreshed by transition().
boost::posix_time::milliseconds const c_timeout = boost::posix_time::milliseconds(1800);
State m_nextState = New; ///< Current or expected state of transition.
bool m_cancel = false; ///< Will be set to true if connection was canceled.
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; ///< Public address of remote host.
bool m_originated = false; ///< True if connection is outbound.
/// Buffers for encoded and decoded handshake phases
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.
KeyPair m_ecdheLocal = KeyPair::create(); ///< Ephemeral ECDH secret and agreement.
h256 m_nonce; ///< Nonce generated by this host for handshake.
Public m_ecdheRemote; ///< Remote ephemeral public key.
h256 m_remoteNonce; ///< Nonce generated by remote host for handshake.
uint64_t m_remoteVersion;
/// Used to read and write RLPx encrypted frames for last step of handshake authentication.
/// Passed onto Host which will take ownership.
std::unique_ptr<RLPXFrameCoder> m_io;
std::shared_ptr<RLPXSocket> m_socket; ///< Socket.
boost::asio::deadline_timer m_idleTimer; ///< Timer which enforces c_timeout.
};
}
}