rustls/
kx.rs

1use std::fmt;
2
3use crate::error::{Error, PeerMisbehaved};
4use crate::msgs::enums::NamedGroup;
5
6/// An in-progress key exchange.  This has the algorithm,
7/// our private key, and our public key.
8pub(crate) struct KeyExchange {
9    skxg: &'static SupportedKxGroup,
10    privkey: ring::agreement::EphemeralPrivateKey,
11    pub(crate) pubkey: ring::agreement::PublicKey,
12}
13
14impl KeyExchange {
15    /// Choose a SupportedKxGroup by name, from a list of supported groups.
16    pub(crate) fn choose(
17        name: NamedGroup,
18        supported: &[&'static SupportedKxGroup],
19    ) -> Option<&'static SupportedKxGroup> {
20        supported
21            .iter()
22            .find(|skxg| skxg.name == name)
23            .cloned()
24    }
25
26    /// Start a key exchange, using the given SupportedKxGroup.
27    ///
28    /// This generates an ephemeral key pair and stores it in the returned KeyExchange object.
29    pub(crate) fn start(skxg: &'static SupportedKxGroup) -> Option<Self> {
30        let rng = ring::rand::SystemRandom::new();
31        let ours =
32            ring::agreement::EphemeralPrivateKey::generate(skxg.agreement_algorithm, &rng).ok()?;
33
34        let pubkey = ours.compute_public_key().ok()?;
35
36        Some(Self {
37            skxg,
38            privkey: ours,
39            pubkey,
40        })
41    }
42
43    /// Return the group being used.
44    pub(crate) fn group(&self) -> NamedGroup {
45        self.skxg.name
46    }
47
48    /// Completes the key exchange, given the peer's public key.
49    ///
50    /// The shared secret is passed into the closure passed down in `f`, and the result of calling
51    /// `f` is returned to the caller.
52    pub(crate) fn complete<T>(self, peer: &[u8], f: impl FnOnce(&[u8]) -> T) -> Result<T, Error> {
53        let peer_key = ring::agreement::UnparsedPublicKey::new(self.skxg.agreement_algorithm, peer);
54        ring::agreement::agree_ephemeral(self.privkey, &peer_key, f)
55            .map_err(|_| PeerMisbehaved::InvalidKeyShare.into())
56    }
57}
58
59/// A key-exchange group supported by rustls.
60///
61/// All possible instances of this class are provided by the library in
62/// the `ALL_KX_GROUPS` array.
63pub struct SupportedKxGroup {
64    /// The IANA "TLS Supported Groups" name of the group
65    pub name: NamedGroup,
66
67    /// The corresponding ring agreement::Algorithm
68    agreement_algorithm: &'static ring::agreement::Algorithm,
69}
70
71impl fmt::Debug for SupportedKxGroup {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        self.name.fmt(f)
74    }
75}
76
77/// Ephemeral ECDH on curve25519 (see RFC7748)
78pub static X25519: SupportedKxGroup = SupportedKxGroup {
79    name: NamedGroup::X25519,
80    agreement_algorithm: &ring::agreement::X25519,
81};
82
83/// Ephemeral ECDH on secp256r1 (aka NIST-P256)
84pub static SECP256R1: SupportedKxGroup = SupportedKxGroup {
85    name: NamedGroup::secp256r1,
86    agreement_algorithm: &ring::agreement::ECDH_P256,
87};
88
89/// Ephemeral ECDH on secp384r1 (aka NIST-P384)
90pub static SECP384R1: SupportedKxGroup = SupportedKxGroup {
91    name: NamedGroup::secp384r1,
92    agreement_algorithm: &ring::agreement::ECDH_P384,
93};
94
95/// A list of all the key exchange groups supported by rustls.
96pub static ALL_KX_GROUPS: [&SupportedKxGroup; 3] = [&X25519, &SECP256R1, &SECP384R1];