Skip to content
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

BIP324: Add encrypted p2p transport {de}serializer #23233

Closed
wants to merge 10 commits into from

Conversation

dhruv
Copy link
Contributor

@dhruv dhruv commented Oct 8, 2021

Revives #18242. Depends on #25361 (please review that first, the last 4 commits are to be reviewed here).

This PR adds a p2p message transport {de}serializer for encrypted packets leveraging the BIP324 specification.

The dependency tree for BIP324 PRs is here.

@dhruv
Copy link
Contributor Author

dhruv commented Oct 8, 2021

Rebased and lint errors fixed. Ready for review.

Comment on lines 40 to 41
uint32_t len = aead.DecryptLength(in.data());
len = 0; // addressing the [[nodiscard]] and otherwise unused variable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
uint32_t len = aead.DecryptLength(in.data());
len = 0; // addressing the [[nodiscard]] and otherwise unused variable
(void)aead.DecryptLength(in.data());

Does this not work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That does indeed work. Thank you.

I've updated the commit in PR #20962 (where it originally belongs) and also here(this PR is based off that one).

@DrahtBot
Copy link
Contributor

DrahtBot commented Oct 9, 2021

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Reviews

See the guideline for information on the review process.

Type Reviewers
Concept ACK stratospher

If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #27534 (rpc: add 'getnetmsgstats', new rpc to view network message statistics by satsie)
  • #27530 (Remove now-unnecessary poll, fcntl includes from net(base).cpp by Empact)
  • #27479 (BIP324: ElligatorSwift integrations by sipa)
  • #27411 (p2p: Restrict self-advertisements with privacy networks to avoid fingerprinting by mzumsande)
  • #27407 (net, refactor: Privatise CNode send queue by dergoegge)
  • #27385 (net, refactor: extract Network and BIP155Network logic to node/network by jonatack)
  • #26684 (bench: add readblock benchmark by andrewtoth)
  • #26593 (tracing: Only prepare tracepoint arguments when actually tracing by 0xB10C)
  • #25572 (refactor: Introduce EvictionManager and use it for the inbound eviction logic by dergoegge)
  • #25268 (refactor: Introduce EvictionManager by dergoegge)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@dhruv
Copy link
Contributor Author

dhruv commented Oct 10, 2021

Addressed #23233 (comment) - ready for further review.

@dhruv
Copy link
Contributor Author

dhruv commented Oct 22, 2021

Rebased. Ready for further review.

Copy link
Contributor

@stratospher stratospher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK ab5b49d. This PR nicely implements the v2 transport serialisation and deserialisation process.

  • 4be7638
    • To introduce short-IDs, allNetMessageTypes[] is represented as a map and functions to convert short-ID to a message and vice versa are added. Verified that changes don’t need to be made to other files due to this commit.
  • a53a06c
    • The v2TransportDeserializer contains:
      • readHeader() : copies the header from msg_bytes to location in vRecv[] which is addressed by m_hdr_pos. After the entire header is read, it switches to read message data mode(m_in_data = true).
      • readData() : copies the data from msg_bytes to location in vRecv[] which is addressed by CHACHA20_POLY1305_AEAD_AAD_LEN + m_data_pos. vRecv[] is resized to at max 256 KiB forward if there’s no space to hold msg_bytes.
      • GetMessage() : performs decryption of vRecv[] and chops off the AAD and MAC tag if successful decryption occurs. It reads the first byte of the payload in size_or_shortid. If size_or_shortid is a number between 1 and 12, then it’s a string command and the next size_or_shortid bytes is read into command_name. If size_or_shortid is larger than 12, then it’s a Message-Type-ID and if it's string mapping is found, it's stored in command_name. Otherwise the size_or_shortid is appended with the prefix ‘unknown’ and stored in command_name. CNetMessage msg is constructed and returned.
    • The v2TransportSerializer contains:
      • prepareForTransport() : prepares the CSerializedNetMsg msg for serialisation. serialized_command_size is used to store the size of short id (1 byte) or the size of message command string if short id isn’t assigned. packet_length contains the length of the message type id and payload which is stored in a LE representation in serialized_header. The short id/ command string is also appended to it. serialized_header is then inserted into the beginning of msg buffer. Encryption is performed on msg and returns true when successful.

src/net.cpp Outdated
}

// we got the AAD bytes at this point (3 bytes encrypted packet length)
// we keep the sequence numbers unchanged at this point. Once the message is authenticated and decrypted, we increase the sequence numbers (or the aad_pos)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// we keep the sequence numbers unchanged at this point. Once the message is authenticated and decrypted, we increase the sequence numbers (or the aad_pos)

This comment can be removed since it's related to the AEAD cipher suite implementation and doesn't play a role here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good find. Removed.

src/net.cpp Outdated
m_message_size = m_aead->DecryptLength((const uint8_t*)vRecv.data());

// reject messages larger than MAX_SIZE
if (m_message_size > MAX_SIZE) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will need to be updated to be consistent with the BIP since MAX_SIZE is 2^25 bytes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the catch. Fixed.

src/net.cpp Outdated
return copy_bytes;
}

std::optional<CNetMessage> V2TransportDeserializer::GetMessage(std::chrono::microseconds time, uint32_t& out_err_raw_size)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function can be modified to keep it's format consistent with the v1 GetMessage since #22735 got merged.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Rebased with master.

src/net.cpp Outdated
// encode as varstr, max 12 chars
serialized_command_size = ::GetSerializeSize(msg.m_type, PROTOCOL_VERSION);
}
// prepare the packet length that will later be encrypted and part of the MAC (AD)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// prepare the packet length that will later be encrypted and part of the MAC (AD)
// prepare the packet length that will later be encrypted and part of the MAC (AAD)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

src/net.cpp Outdated

// insert header directly into the CSerializedNetMsg data buffer (insert at begin)
// TODO: if we refactor the ChaCha20Poly1350 crypt function to allow separate buffers for
// the AD, payload and MAC, we could avoid a insert and thus a potential reallocation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// the AD, payload and MAC, we could avoid a insert and thus a potential reallocation
// the AAD, payload and MAC, we could avoid a insert and thus a potential reallocation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

src/net.cpp Outdated
}

// insert header directly into the CSerializedNetMsg data buffer (insert at begin)
// TODO: if we refactor the ChaCha20Poly1350 crypt function to allow separate buffers for
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// TODO: if we refactor the ChaCha20Poly1350 crypt function to allow separate buffers for
// TODO: if we refactor the ChaCha20Poly1305 crypt function to allow separate buffers for

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

src/net.cpp Outdated

std::optional<CNetMessage> V2TransportDeserializer::GetMessage(std::chrono::microseconds time, uint32_t& out_err_raw_size)
{
// In v2, vRecv contains the encrypted payload plus the MAC tag (1+bytes serialized message command + ? bytes message payload + 16 byte mac tag)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// In v2, vRecv contains the encrypted payload plus the MAC tag (1+bytes serialized message command + ? bytes message payload + 16 byte mac tag)
// In v2, vRecv contains the AAD, encrypted payload plus the MAC tag (3 byte AAD + 1+bytes serialized message command + ? bytes message payload + 16 byte mac tag)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

// second: read the encrypted payload (if required)
Span<const uint8_t> span_msg(msg.data.data(), msg.data.size());
if (msg.data.size() > 0) read_bytes += deserializer->Read(span_msg);
if (msg.data.size() > read_bytes && msg.data.size() - read_bytes > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (msg.data.size() > read_bytes && msg.data.size() - read_bytes > 0) {
if (msg.data.size() > read_bytes) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, that was quite silly. Thanks for reviewing closely. Done.

Comment on lines 752 to 753
uint32_t out_err_raw_size{0};
std::optional<CNetMessage> result{deserializer->GetMessage(GetTime<std::chrono::microseconds>(), out_err_raw_size)};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be updated to keep it consistent with 22735's change.

Suggested change
uint32_t out_err_raw_size{0};
std::optional<CNetMessage> result{deserializer->GetMessage(GetTime<std::chrono::microseconds>(), out_err_raw_size)};
bool reject_message{false};
CNetMessage result{deserializer->GetMessage(GetTime<std::chrono::microseconds>(), reject_message)};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment on lines 29 to 30
uint32_t out_err_raw_size{0};
std::optional<CNetMessage> result{deserializer.GetMessage(m_time, out_err_raw_size)};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
uint32_t out_err_raw_size{0};
std::optional<CNetMessage> result{deserializer.GetMessage(m_time, out_err_raw_size)};
bool reject_message{false};
CNetMessage result{deserializer.GetMessage(m_time, reject_message)};

Here also.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@dhruv
Copy link
Contributor Author

dhruv commented Nov 9, 2021

Rebased to bring in changes from #22735, and addressed comments from @stratospher (Thank you!). Ready for further review.

src/net.cpp Show resolved Hide resolved
@dhruv
Copy link
Contributor Author

dhruv commented Nov 23, 2021

Pushed changes to enforce connection termination upon finding an invalid mac tag. Ready for further review.

@dhruv
Copy link
Contributor Author

dhruv commented Feb 2, 2023

Rebased. Brought in upstream changes.

@dhruv
Copy link
Contributor Author

dhruv commented Feb 21, 2023

Rebased.

@dhruv
Copy link
Contributor Author

dhruv commented Mar 8, 2023

Latest push:

  • Implemented changes from BIP324: Fixed length message type IDs bips#1428 involving fixed length message type ids (there's also a relevant discussion on the ML)
  • While implementing it, I found a bug in the arm of code that serialized/deserialized message types without assigned short ids. That branch of code was previously unexercised by any tests. This is no longer the case.

@dhruv
Copy link
Contributor Author

dhruv commented Mar 21, 2023

Latest push:

@fanquake
Copy link
Member

fanquake commented May 6, 2023

Closing for now. This will be picked up again later. BIP324 review attention should be directed towards #27479 and bitcoin-core/secp256k1#1129.

@fanquake fanquake closed this May 6, 2023
@sipa sipa mentioned this pull request May 12, 2023
43 tasks
@bitcoin bitcoin locked and limited conversation to collaborators May 5, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
No open projects
Status: Needs review
Development

Successfully merging this pull request may close these issues.

7 participants