-
Notifications
You must be signed in to change notification settings - Fork 743
Description
The TLS 1.3 spec says in https://datatracker.ietf.org/doc/html/rfc8446#appendix-E.1.4:
[B]ecause these secrets can be used to compute any
exporter value, they SHOULD be erased as soon as possible. If the
total set of exporter labels is known, then implementations SHOULD
pre-compute the inner Derive-Secret stage of the exporter computation
for all those labels, then erase the [early_]exporter_master_secret,
followed by each inner value as soon as it is known that it will not
be needed again.
However, the design of the export_keying_material()
API makes this erasure recommendation impossible to implement, because we currently support calling export_keying_material()
at any time after the handshake completes, and so we have to retain the exporter key.
Note that TLS doesn't provide any way to rotate the exporter key; the KeyUpdate
mechanism only applies to traffic keys. This design pretty much forces us to implement the erasure recommendation above, if we want to have long-lived connections that minimize their ability to expose secrets.
I propose:
- We remove
export_keying_material()
from the public API. - Add a "handshake" callback. (Note that this suggested interface is intended to be easily extensible in a way that maintains SemVer compatibility):
pub trait HandshakeComplete {
/// Called just after the the peer's handshake messages and identity (if any) have been successfully validated.
///
///
pub fn handshake_complete(&self, handshake_data: HandshakeData) -> Result<(), Box<dyn Debug>>
}
pub struct HandshakeData {
/// <The current export_keying_material API>
fn export_keying_material(&mut self, ....) -> ....;
}
- When the handshake completes, call this callback.
- Move
current_exporter_secret
out ofKeyScheduleTraffic
to the implementation(s) ofHandshakeData
. (It should probably be lazily constructed the first timeexport_keying_material
is called, since most applications don't need it.) - The new
export_keying_material()
API should implement additional validation of its parameters as suggested in the TLS 1.3 specification and the and common sense (e.g. that the label and other parameters that should be non-empty aren't empty).. - Since
HandshakeData
is moved into the callback, its contents (in particular, the exporter key) will be destroyed automatically, implementing the semantics that the TLS 1.3 spec recommends.
Besides being safer, this would also:
- Slightly reduce the memory requirements for each connection
- Make it easier to split the
KeySchedule
into read and write parts, which I think is probably useful for full-duplex mode.