pub trait HybridKeyExchange: ActiveKeyExchange {
// Required methods
fn component(&self) -> (NamedGroup, &[u8]);
fn complete_component(
self: Box<Self>,
peer_pub_key: &[u8],
) -> Result<SharedSecret, Error>;
fn as_key_exchange(&self) -> &(dyn ActiveKeyExchange + 'static);
fn into_key_exchange(self: Box<Self>) -> Box<dyn ActiveKeyExchange>;
}Expand description
An in-progress hybrid key exchange originating from a SupportedKxGroup.
“Hybrid” means a key exchange algorithm which is constructed from two (or more) independent component algorithms. Usually one is post-quantum-secure, and the other is “classical”. See https://datatracker.ietf.org/doc/draft-ietf-tls-hybrid-design/11/
There is no requirement for a hybrid scheme (or any other!) to implement
HybridKeyExchange if it is not desirable for it to be “split” like this.
It only enables an optimization; described below.
§Background
Rustls always sends a presumptive key share in its ClientHello, using
(absent any other information) the first item in
CryptoProvider::kx_groups.
If the server accepts the client’s selection, it can complete the handshake
using that key share. If not, the server sends a HelloRetryRequest instructing
the client to send a different key share instead.
This request costs an extra round trip, and wastes the key exchange computation
(in SupportedKxGroup::start()) the client already did. We would
like to avoid those wastes if possible.
It is early days for post-quantum-secure hybrid key exchange deployment.
This means (commonly) continuing to offer both the hybrid and classical
key exchanges, so the handshake can be completed without a HelloRetryRequest
for servers that support the offered hybrid or classical schemes.
Implementing HybridKeyExchange enables two optimizations:
-
Sending both the hybrid and classical key shares in the
ClientHello. -
Performing the classical key exchange setup only once. This is important because the classical key exchange setup is relatively expensive. This optimization is permitted and described in https://www.ietf.org/archive/id/draft-ietf-tls-hybrid-design-11.html#section-3.2
Both of these only happen if the classical algorithm appears separately in
the client’s CryptoProvider::kx_groups,
and if the hybrid algorithm appears first in that list.
§How it works
This function is only called by rustls for clients. It is called when
constructing the initial ClientHello. rustls follows these steps:
- If the return value is
None, nothing further happens. - If the given
NamedGroupdoes not appear inCryptoProvider::kx_groups, nothing further happens. - The given key share is added to the
ClientHello, after the hybrid entry.
Then, one of three things may happen when the server replies to the ClientHello:
- The server sends a
HelloRetryRequest. Everything is thrown away and we start again. - The server agrees to our hybrid key exchange: rustls calls
ActiveKeyExchange::complete()consumingself. - The server agrees to our classical key exchange: rustls calls
HybridKeyExchange::complete_component()which discards the hybrid key data, and completes just the classical key exchange.
Required Methods§
Sourcefn component(&self) -> (NamedGroup, &[u8])
fn component(&self) -> (NamedGroup, &[u8])
Returns the NamedGroup and public key “share” for the component.
Sourcefn complete_component(
self: Box<Self>,
peer_pub_key: &[u8],
) -> Result<SharedSecret, Error>
fn complete_component( self: Box<Self>, peer_pub_key: &[u8], ) -> Result<SharedSecret, Error>
Completes the classical component of the key exchange, given the peer’s public key.
This method must return an error if peer_pub_key is invalid: either
misencoded, or an invalid public key (such as, but not limited to, being
in a small order subgroup).
The shared secret is returned as a SharedSecret which can be constructed
from a &[u8].
See the documentation on HybridKeyExchange for explanation.
Sourcefn as_key_exchange(&self) -> &(dyn ActiveKeyExchange + 'static)
fn as_key_exchange(&self) -> &(dyn ActiveKeyExchange + 'static)
Obtain the value as a dyn ActiveKeyExchange
Sourcefn into_key_exchange(self: Box<Self>) -> Box<dyn ActiveKeyExchange>
fn into_key_exchange(self: Box<Self>) -> Box<dyn ActiveKeyExchange>
Remove the ability to do hybrid key exchange on this object.