-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Remove pre-EIP-8 RLPx handshake support #10257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -54,11 +54,7 @@ public class ECIESHandshaker implements Handshaker { | |
| private static final Logger LOG = LoggerFactory.getLogger(ECIESHandshaker.class); | ||
| private static final SecureRandom RANDOM = SecureRandomProvider.publicSecureRandom(); | ||
|
|
||
| static final int SIGNATURE_LENGTH = 65; | ||
| static final int HASH_EPH_PUBKEY_LENGTH = 32; | ||
| static final int PUBKEY_LENGTH = 64; | ||
| static final int NONCE_LENGTH = 32; | ||
| static final int TOKEN_FLAG_LENGTH = 1; | ||
|
|
||
| // Keypairs under our control. | ||
| private NodeKey nodeKey; | ||
|
|
@@ -86,8 +82,6 @@ public class ECIESHandshaker implements Handshaker { | |
| new AtomicReference<>(Handshaker.HandshakeStatus.UNINITIALIZED); | ||
| private HandshakeSecrets secrets; | ||
|
|
||
| private boolean version4 = true; | ||
|
|
||
| private final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance(); | ||
|
|
||
| @Override | ||
|
|
@@ -130,21 +124,11 @@ public ByteBuf firstMessage() throws HandshakeException { | |
| "illegal invocation of firstMessage, handshake had already started"); | ||
|
|
||
| final Bytes32 staticSharedSecret = nodeKey.calculateECDHKeyAgreement(partyPubKey); | ||
| if (version4) { | ||
| initiatorMsg = | ||
| InitiatorHandshakeMessageV4.create( | ||
| nodeKey.getPublicKey(), ephKeyPair, staticSharedSecret, initiatorNonce); | ||
| } else { | ||
| initiatorMsg = | ||
| InitiatorHandshakeMessageV1.create( | ||
| nodeKey.getPublicKey(), ephKeyPair, staticSharedSecret, initiatorNonce, false); | ||
| } | ||
| initiatorMsg = | ||
| InitiatorHandshakeMessageV4.create( | ||
| nodeKey.getPublicKey(), ephKeyPair, staticSharedSecret, initiatorNonce); | ||
| try { | ||
| if (version4) { | ||
| initiatorMsgEnc = EncryptedMessage.encryptMsgEip8(initiatorMsg.encode(), partyPubKey); | ||
| } else { | ||
| initiatorMsgEnc = EncryptedMessage.encryptMsg(initiatorMsg.encode(), partyPubKey); | ||
| } | ||
| initiatorMsgEnc = EncryptedMessage.encryptMsgEip8(initiatorMsg.encode(), partyPubKey); | ||
| } catch (final InvalidCipherTextException e) { | ||
| status.set(Handshaker.HandshakeStatus.FAILED); | ||
| throw new HandshakeException("Encrypting the first handshake message failed", e); | ||
|
|
@@ -161,51 +145,26 @@ public Optional<ByteBuf> handleMessage(final ByteBuf buf) throws HandshakeExcept | |
| status.get() == Handshaker.HandshakeStatus.IN_PROGRESS, | ||
| "illegal invocation of onMessage on handshake that is not in progress"); | ||
|
|
||
| // Take as many bytes as expected in the next message. | ||
| int expectedLength = ECIESEncryptionEngine.ENCRYPTION_OVERHEAD; | ||
| expectedLength += | ||
| initiator | ||
| ? ResponderHandshakeMessageV1.MESSAGE_LENGTH | ||
| : InitiatorHandshakeMessageV1.MESSAGE_LENGTH; | ||
|
|
||
| if (buf.readableBytes() < expectedLength) { | ||
| buf.markReaderIndex(); | ||
| final int size = buf.readUnsignedShort(); | ||
| if (size > buf.readableBytes() + 2) { | ||
| buf.resetReaderIndex(); | ||
| return Optional.empty(); | ||
| } | ||
| expectedLength = size; | ||
| // Read the EIP-8 size prefix to determine the full message length. | ||
| buf.markReaderIndex(); | ||
| if (buf.readableBytes() < 2) { | ||
| return Optional.empty(); | ||
| } | ||
| final int size = buf.readUnsignedShort(); | ||
| if (size > buf.readableBytes()) { | ||
| buf.resetReaderIndex(); | ||
| return Optional.empty(); | ||
| } | ||
|
|
||
| buf.markReaderIndex(); | ||
| final ByteBuf bufferedBytes = buf.readSlice(expectedLength); | ||
| final byte[] encryptedBytes = new byte[bufferedBytes.readableBytes()]; | ||
| bufferedBytes.getBytes(0, encryptedBytes); | ||
| Bytes bytes = Bytes.wrap(encryptedBytes); | ||
| // Read the full EIP-8 message (size prefix + payload). | ||
| buf.resetReaderIndex(); | ||
| final byte[] fullMessage = new byte[size + 2]; | ||
| buf.readBytes(fullMessage); | ||
| final Bytes encryptedMsg = Bytes.wrap(fullMessage); | ||
|
Comment on lines
+148
to
+163
|
||
|
|
||
| Bytes encryptedMsg = bytes; | ||
| final Bytes bytes; | ||
| try { | ||
| // Decrypt the message with our private key. | ||
| try { | ||
| // Assume new format | ||
| final int size = bufferedBytes.readUnsignedShort(); | ||
| if (buf.writerIndex() >= size) { | ||
| bufferedBytes.readerIndex(0); | ||
| final byte[] fullMessage = new byte[size + 2]; | ||
| bufferedBytes.readBytes(fullMessage, 0, expectedLength); | ||
| buf.readBytes(fullMessage, expectedLength, size - expectedLength + 2); | ||
| encryptedMsg = Bytes.wrap(fullMessage); | ||
| bytes = EncryptedMessage.decryptMsgEIP8(encryptedMsg, nodeKey); | ||
| version4 = true; | ||
| } else { | ||
| throw new HandshakeException("Failed to decrypt handshake message"); | ||
| } | ||
| } catch (final Exception ex) { | ||
| bytes = EncryptedMessage.decryptMsg(bytes, nodeKey); | ||
| version4 = false; | ||
| } | ||
| bytes = EncryptedMessage.decryptMsgEIP8(encryptedMsg, nodeKey); | ||
| } catch (final InvalidCipherTextException e) { | ||
| status.set(Handshaker.HandshakeStatus.FAILED); | ||
| throw new HandshakeException("Decrypting an incoming handshake message failed", e); | ||
|
|
@@ -226,11 +185,7 @@ public Optional<ByteBuf> handleMessage(final ByteBuf buf) throws HandshakeExcept | |
|
|
||
| // Store the message, as we need it to generating our ingress and egress MACs. | ||
| responderMsgEnc = encryptedMsg; | ||
| if (version4) { | ||
| responderMsg = ResponderHandshakeMessageV4.decode(bytes); | ||
| } else { | ||
| responderMsg = ResponderHandshakeMessageV1.decode(bytes); | ||
| } | ||
| responderMsg = ResponderHandshakeMessageV4.decode(bytes); | ||
|
|
||
| // Extract the responder's nonce and ephemeral pubkey, which will be used to generate the | ||
| // shared secrets. | ||
|
|
@@ -253,11 +208,7 @@ public Optional<ByteBuf> handleMessage(final ByteBuf buf) throws HandshakeExcept | |
| // Store the message, as we need it to generating our ingress and egress MACs. | ||
| initiatorMsgEnc = encryptedMsg; | ||
| try { | ||
| if (version4) { | ||
| initiatorMsg = InitiatorHandshakeMessageV4.decode(bytes, nodeKey); | ||
| } else { | ||
| initiatorMsg = InitiatorHandshakeMessageV1.decode(bytes, nodeKey); | ||
| } | ||
| initiatorMsg = InitiatorHandshakeMessageV4.decode(bytes, nodeKey); | ||
| } catch (final SecurityModuleException e) { | ||
| status.set(Handshaker.HandshakeStatus.FAILED); | ||
| throw new HandshakeException( | ||
|
|
@@ -279,25 +230,15 @@ public Optional<ByteBuf> handleMessage(final ByteBuf buf) throws HandshakeExcept | |
| "keccak hash of recovered ephemeral pubkey does not match announced hash"); | ||
|
|
||
| // Build the response message. | ||
| if (version4) { | ||
| responderMsg = | ||
| ResponderHandshakeMessageV4.create(ephKeyPair.getPublicKey(), responderNonce); | ||
| } else { | ||
| responderMsg = | ||
| ResponderHandshakeMessageV1.create(ephKeyPair.getPublicKey(), responderNonce, false); | ||
| } | ||
| responderMsg = ResponderHandshakeMessageV4.create(ephKeyPair.getPublicKey(), responderNonce); | ||
|
|
||
| LOG.trace( | ||
| "Generated responder's ECIES handshake message against peer {}...: {}", | ||
| partyPubKey.getEncodedBytes().slice(0, 16), | ||
| responderMsg); | ||
|
|
||
| try { | ||
| if (version4) { | ||
| responderMsgEnc = EncryptedMessage.encryptMsgEip8(responderMsg.encode(), partyPubKey); | ||
| } else { | ||
| responderMsgEnc = EncryptedMessage.encryptMsg(responderMsg.encode(), partyPubKey); | ||
| } | ||
| responderMsgEnc = EncryptedMessage.encryptMsgEip8(responderMsg.encode(), partyPubKey); | ||
| } catch (final InvalidCipherTextException e) { | ||
| status.set(Handshaker.HandshakeStatus.FAILED); | ||
| throw new HandshakeException("Encrypting the next handshake message failed", e); | ||
|
|
@@ -435,14 +376,4 @@ Bytes32 getResponderNonce() { | |
| void setResponderNonce(final Bytes32 responderNonce) { | ||
| this.responderNonce = responderNonce; | ||
| } | ||
|
|
||
| @VisibleForTesting | ||
| void setInitiatorMsgEnc(final Bytes initiatorMsgEnc) { | ||
| this.initiatorMsgEnc = initiatorMsgEnc; | ||
| } | ||
|
|
||
| @VisibleForTesting | ||
| void setResponderMsgEnc(final Bytes responderMsgEnc) { | ||
| this.responderMsgEnc = responderMsgEnc; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On HELLO/handshake identity mismatch, the code closes the channel without sending a devp2p
Disconnectreason (previous behavior usedUNEXPECTED_ID). This can make the disconnect harder to diagnose for the remote side and may deviate from expected protocol behavior. Consider emitting aDisconnectMessagewith an appropriate reason before closing (or moving this check to a point where aRlpxConnectionexists soconnection.disconnect(...)can be used), then closing after flush.