Skip to content

Conversation

cpu
Copy link
Member

@cpu cpu commented Nov 14, 2023

This branch introduces a trait for a hybrid public key encryption (HPKE) provider. HPKE is specified in RFC 9180, and is a pre-requisite for implementing encrypted client hello (ECH). Implementations of these traits can use the cryptographic provider of their choice to provide HPKE using existing primitives from the crypto provider.

We've tailored the HPKE trait in Rustls to just what is required for ECH, e.g. it doesn't support modes other than the unauthenticated 'base' mode, and it only offers the "single-shot" APIs.

Demonstration of implementing the traits is achieved using hpke-rs with the rust-crypto backend. Separately we expect to implement a HPKE provider using the ring crypto provider for proper ECH support.

Since the HPKE traits are not yet used in Rustls a unit test of the provider-example HPKE provider based on the RFC 9180 test vectors is added to prevent bitrot and ensure the traits are workable. Likely in the future we will want to move this test logic somewhere outside of the provider-example crate and use it to test the other HPKE provider implementations.

Copy link
Member

@djc djc left a comment

Choose a reason for hiding this comment

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

Feels like the trait is fairly specialized to the hpke-rs interface, might be good to think about the conceptually ideal interface for this?

@cpu
Copy link
Member Author

cpu commented Nov 14, 2023

Feels like the trait is fairly specialized to the hpke-rs interface, might be good to think about the conceptually ideal interface for this?

I think it is pretty close to the ideal interface. The main change I can think to suggest is to tailor the traits to only supporting Mode::Base since that's all ECH will require and the rest is speculative. That would let us remove the Option args to setup_sender and setup_receiver. Otherwise I think it maps very closely to what ECH requires and I'm not sure I can think of conceptual improvements. I'm open to suggestions though!

Copy link

codecov bot commented Nov 14, 2023

Codecov Report

Attention: 6 lines in your changes are missing coverage. Please review.

Comparison is base (c157689) 96.13% compared to head (2f350f7) 96.09%.

Files Patch % Lines
rustls/src/crypto/hpke.rs 0.00% 6 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1589      +/-   ##
==========================================
- Coverage   96.13%   96.09%   -0.04%     
==========================================
  Files          76       77       +1     
  Lines       15745    15738       -7     
==========================================
- Hits        15137    15124      -13     
- Misses        608      614       +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@djc
Copy link
Member

djc commented Nov 14, 2023

The main change I can think to suggest is to tailor the traits to only supporting Mode::Base since that's all ECH will require and the rest is speculative.

I think this makes sense -- no need to make this trait generic enough for non-TLS use cases.

///
/// This is a stateful object that can be used to seal messages for receipt by
/// a receiver.
pub trait HpkeSender: Debug + Send + Sync {
Copy link
Member

Choose a reason for hiding this comment

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

I would be minded to start with a one-shot interface for the sake of simplicity. Then move to a streaming interface once everything is up and running?

That would obviate HpkeSender and HpkeReceiver, and make the methods in trait Hpke something like:

fn open(&self, 
        pk_r: &HpkePublicKey,
        info: &[u8],
        aad; &[u8],
        pt: &[u8],
) -> Result<(EncapsulatedSecret, Vec<u8>), Error>;

Copy link
Member Author

Choose a reason for hiding this comment

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

Switched to one-shot.

Copy link
Member Author

Choose a reason for hiding this comment

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

I would be minded to start with a one-shot interface for the sake of simplicity.

Leaving a note here: we do need the non-one-shot interface for ECH: specifically for handling HelloRetryRequests.

Section 6.1.5 "Handshaking with ClientHelloInner" says:

It encrypts EncodedClientHelloInner as described in Section 6.1.1, using the second partial ClientHelloOuterAAD, to obtain a second ClientHelloOuter. It reuses the original HPKE encryption context computed in Section 6.1 and uses the empty string for enc.

The HPKE context maintains a sequence number, so this operation internally uses a fresh nonce for each AEAD operation. Reusing the HPKE context avoids an attack described in Section 10.11.2.

So we specifically need to maintain the HPKE context used for the original client hello so that we can re-use it when creating the updated extension for a HRR response.

I'm trying to bundle up some required changes and will make sure this is one of them.

@cpu cpu force-pushed the cpu-hpke-provider-trait branch from 73d45ca to 70ab492 Compare November 15, 2023 16:44
This commit introduces a trait for a hybrid public key encryption (HPKE)
provider. HPKE is specified in RFC 9180[0], and is a pre-requisite for
implementing encrypted client hello (ECH).

Implementations of this trait can use the cryptographic provider of
their choice to provide HPKE using existing primitives from the crypto
provider.

We've tailored the HPKE trait in Rustls to just what is required for
ECH, e.g. it doesn't support modes other than the unauthenticated 'base'
mode, and it only offers the "single-shot" APIs.

[0]: https://www.rfc-editor.org/rfc/rfc9180
@cpu cpu force-pushed the cpu-hpke-provider-trait branch 2 times, most recently from fd06b54 to 18485b8 Compare November 16, 2023 18:21
This commit implements the Rustls HPKE provider traits using hpke-rs[0]
with the rust-crypto backend.

Since HPKE is not yet used in Rustls (but will be for ECH support),
a unit test based on the RFC 9180 test vectors is added.

Likely in the future we will want to move this test somewhere outside of
the provider-example crate and use it to test a *ring* HPKE
implementation using the same test vector data.

[0]: https://github.com/franziskuskiefer/hpke-rs
@cpu cpu force-pushed the cpu-hpke-provider-trait branch from 18485b8 to 2f350f7 Compare November 16, 2023 19:05
@cpu cpu added this pull request to the merge queue Nov 16, 2023
Merged via the queue into rustls:main with commit b7a6091 Nov 16, 2023
@cpu cpu deleted the cpu-hpke-provider-trait branch November 16, 2023 19:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants