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
NamedGroup
does 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.