| // Copyright 2026 The BoringSSL Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| //! Supported key exchange groups |
| //! |
| //! We support the following standard groups. |
| //! |
| //! - [ECDH_P256] for elliptic curve based Diffie-Hellman ECDH-P256 |
| //! - [ECDH_P384] for elliptic curve based Diffie-Hellman ECDH-P384 |
| //! - [X25519] for X25519 |
| //! |
| //! If `mlalgs` feature is enabled, we also support the following post-quantum hybrid key exchange |
| //! groups, for TLS 1.3. |
| //! |
| //! - [X25519MLKEM768] for X25519MLKEM768 |
| |
| use alloc::{ |
| boxed::Box, |
| fmt::{Debug, Formatter, Result as FmtResult}, |
| vec::Vec, |
| }; |
| use core::marker::PhantomData; |
| |
| use bssl_crypto::{ec, ecdh, x25519}; |
| use rustls::{ |
| Error, NamedGroup, PeerMisbehaved, |
| crypto::{ActiveKeyExchange, SharedSecret, SupportedKxGroup}, |
| }; |
| |
| #[cfg(feature = "mlalgs")] |
| mod mlkem; |
| #[cfg(feature = "mlalgs")] |
| pub use mlkem::X25519MLKEM768; |
| |
| /// Elliptic Curve Diffie-Hellman key exchange group |
| struct EcGroup<C: ec::Curve>(PhantomData<fn() -> C>); |
| /// Elliptic Curve Diffie-Hellman key exchange group `ECDH-P256` |
| pub const ECDH_P256: &'static dyn SupportedKxGroup = &EcGroup::<ec::P256>(PhantomData); |
| /// Elliptic Curve Diffie-Hellman key exchange group `ECDH-P384` |
| pub const ECDH_P384: &'static dyn SupportedKxGroup = &EcGroup::<ec::P384>(PhantomData); |
| |
| impl<C: ec::Curve> Debug for EcGroup<C> { |
| fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { |
| f.debug_struct("EcGroup").finish() |
| } |
| } |
| |
| impl<C: ec::Curve + 'static> SupportedKxGroup for EcGroup<C> { |
| fn start(&self) -> Result<Box<dyn ActiveKeyExchange>, Error> { |
| let priv_key = ecdh::PrivateKey::<C>::generate(); |
| let pub_key = priv_key.to_public_key(); |
| let pub_key_x962_uncompressed = pub_key.to_x962_uncompressed().as_ref().into(); |
| Ok(Box::new(EcActiveKeyExchange { |
| priv_key, |
| pub_key_x962_uncompressed, |
| })) |
| } |
| |
| fn name(&self) -> NamedGroup { |
| match C::group() { |
| ec::Group::P256 => NamedGroup::secp256r1, |
| ec::Group::P384 => NamedGroup::secp384r1, |
| } |
| } |
| } |
| |
| /// This type encodes the Diffie-Hellman key exchange state during TLS. |
| struct EcActiveKeyExchange<C: ec::Curve> { |
| priv_key: ecdh::PrivateKey<C>, |
| pub_key_x962_uncompressed: Vec<u8>, |
| } |
| impl<C: ec::Curve> ActiveKeyExchange for EcActiveKeyExchange<C> { |
| fn complete(self: Box<Self>, peer_pub_key: &[u8]) -> Result<SharedSecret, Error> { |
| let peer_pub_key = ecdh::PublicKey::from_x962_uncompressed(peer_pub_key) |
| .ok_or(Error::PeerMisbehaved(PeerMisbehaved::InvalidKeyShare))?; |
| let shared_secret = self.priv_key.compute_shared_key(&peer_pub_key); |
| Ok(shared_secret.into()) |
| } |
| |
| fn pub_key(&self) -> &[u8] { |
| &self.pub_key_x962_uncompressed |
| } |
| |
| fn group(&self) -> NamedGroup { |
| match C::group() { |
| ec::Group::P256 => NamedGroup::secp256r1, |
| ec::Group::P384 => NamedGroup::secp384r1, |
| } |
| } |
| } |
| |
| /// X25519 Key exchange group |
| #[derive(Debug)] |
| struct X25519Group; |
| /// X25519 key exchange group |
| pub const X25519: &'static dyn SupportedKxGroup = &X25519Group; |
| |
| impl SupportedKxGroup for X25519Group { |
| fn start(&self) -> Result<Box<dyn ActiveKeyExchange>, Error> { |
| let (pub_key, priv_key) = x25519::PrivateKey::generate(); |
| Ok(Box::new(X25519ActiveKeyExchange { pub_key, priv_key })) |
| } |
| |
| fn name(&self) -> NamedGroup { |
| NamedGroup::X25519 |
| } |
| } |
| |
| struct X25519ActiveKeyExchange { |
| pub_key: x25519::PublicKey, |
| priv_key: x25519::PrivateKey, |
| } |
| |
| impl ActiveKeyExchange for X25519ActiveKeyExchange { |
| fn complete(self: Box<Self>, peer_pub_key: &[u8]) -> Result<SharedSecret, Error> { |
| let secret = self |
| .priv_key |
| .compute_shared_key( |
| peer_pub_key |
| .try_into() |
| .map_err(|_| Error::PeerMisbehaved(PeerMisbehaved::InvalidKeyShare))?, |
| ) |
| .ok_or(Error::PeerMisbehaved(PeerMisbehaved::InvalidKeyShare))? |
| .to_vec(); |
| Ok(secret.into()) |
| } |
| |
| fn pub_key(&self) -> &[u8] { |
| &self.pub_key |
| } |
| |
| fn group(&self) -> NamedGroup { |
| NamedGroup::X25519 |
| } |
| } |