rustls/crypto/
signer.rs

1use alloc::boxed::Box;
2use alloc::vec::Vec;
3use core::fmt::Debug;
4
5use pki_types::{AlgorithmIdentifier, CertificateDer, PrivateKeyDer, SubjectPublicKeyInfoDer};
6
7use super::CryptoProvider;
8use crate::client::ResolvesClientCert;
9use crate::enums::{SignatureAlgorithm, SignatureScheme};
10use crate::error::{Error, InconsistentKeys};
11use crate::server::{ClientHello, ParsedCertificate, ResolvesServerCert};
12use crate::sync::Arc;
13use crate::x509;
14
15/// An abstract signing key.
16///
17/// This interface is used by rustls to use a private signing key
18/// for authentication.  This includes server and client authentication.
19///
20/// Objects of this type are always used within Rustls as
21/// `Arc<dyn SigningKey>`. There are no concrete public structs in Rustls
22/// that implement this trait.
23///
24/// There are two main ways to get a signing key:
25///
26///  - [`KeyProvider::load_private_key()`], or
27///  - some other method outside of the `KeyProvider` extension trait,
28///    for instance:
29///    - [`crypto::ring::sign::any_ecdsa_type()`]
30///    - [`crypto::ring::sign::any_eddsa_type()`]
31///    - [`crypto::ring::sign::any_supported_type()`]
32///    - [`crypto::aws_lc_rs::sign::any_ecdsa_type()`]
33///    - [`crypto::aws_lc_rs::sign::any_eddsa_type()`]
34///    - [`crypto::aws_lc_rs::sign::any_supported_type()`]
35///
36/// The `KeyProvider` method `load_private_key()` is called under the hood by
37/// [`ConfigBuilder::with_single_cert()`],
38/// [`ConfigBuilder::with_client_auth_cert()`], and
39/// [`ConfigBuilder::with_single_cert_with_ocsp()`].
40///
41/// A signing key created outside of the `KeyProvider` extension trait can be used
42/// to create a [`CertifiedKey`], which in turn can be used to create a
43/// [`ResolvesServerCertUsingSni`]. Alternately, a `CertifiedKey` can be returned from a
44/// custom implementation of the [`ResolvesServerCert`] or [`ResolvesClientCert`] traits.
45///
46/// [`KeyProvider::load_private_key()`]: crate::crypto::KeyProvider::load_private_key
47/// [`ConfigBuilder::with_single_cert()`]: crate::ConfigBuilder::with_single_cert
48/// [`ConfigBuilder::with_single_cert_with_ocsp()`]: crate::ConfigBuilder::with_single_cert_with_ocsp
49/// [`ConfigBuilder::with_client_auth_cert()`]: crate::ConfigBuilder::with_client_auth_cert
50/// [`crypto::ring::sign::any_ecdsa_type()`]: crate::crypto::ring::sign::any_ecdsa_type
51/// [`crypto::ring::sign::any_eddsa_type()`]: crate::crypto::ring::sign::any_eddsa_type
52/// [`crypto::ring::sign::any_supported_type()`]: crate::crypto::ring::sign::any_supported_type
53/// [`crypto::aws_lc_rs::sign::any_ecdsa_type()`]: crate::crypto::aws_lc_rs::sign::any_ecdsa_type
54/// [`crypto::aws_lc_rs::sign::any_eddsa_type()`]: crate::crypto::aws_lc_rs::sign::any_eddsa_type
55/// [`crypto::aws_lc_rs::sign::any_supported_type()`]: crate::crypto::aws_lc_rs::sign::any_supported_type
56/// [`ResolvesServerCertUsingSni`]: crate::server::ResolvesServerCertUsingSni
57/// [`ResolvesServerCert`]: crate::server::ResolvesServerCert
58/// [`ResolvesClientCert`]: crate::client::ResolvesClientCert
59pub trait SigningKey: Debug + Send + Sync {
60    /// Choose a `SignatureScheme` from those offered.
61    ///
62    /// Expresses the choice by returning something that implements `Signer`,
63    /// using the chosen scheme.
64    fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>>;
65
66    /// Get the RFC 5280-compliant SubjectPublicKeyInfo (SPKI) of this [`SigningKey`].
67    ///
68    /// If an implementation does not have the ability to derive this,
69    /// it can return `None`.
70    fn public_key(&self) -> Option<SubjectPublicKeyInfoDer<'_>>;
71
72    /// What kind of key we have.
73    fn algorithm(&self) -> SignatureAlgorithm;
74}
75
76/// A thing that can sign a message.
77pub trait Signer: Debug + Send + Sync {
78    /// Signs `message` using the selected scheme.
79    ///
80    /// `message` is not hashed; the implementer must hash it using the hash function
81    /// implicit in [`Self::scheme()`].
82    ///
83    /// The returned signature format is also defined by [`Self::scheme()`].
84    fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error>;
85
86    /// Reveals which scheme will be used when you call [`Self::sign()`].
87    fn scheme(&self) -> SignatureScheme;
88}
89
90/// Server certificate resolver which always resolves to the same certificate and key.
91///
92/// For use with [`ConfigBuilder::with_cert_resolver()`].
93///
94/// [`ConfigBuilder::with_cert_resolver()`]: crate::ConfigBuilder::with_cert_resolver
95#[derive(Debug)]
96pub struct SingleCertAndKey(Arc<CertifiedKey>);
97
98impl From<CertifiedKey> for SingleCertAndKey {
99    fn from(certified_key: CertifiedKey) -> Self {
100        Self(Arc::new(certified_key))
101    }
102}
103
104impl From<Arc<CertifiedKey>> for SingleCertAndKey {
105    fn from(certified_key: Arc<CertifiedKey>) -> Self {
106        Self(certified_key)
107    }
108}
109
110impl ResolvesClientCert for SingleCertAndKey {
111    fn resolve(
112        &self,
113        _root_hint_subjects: &[&[u8]],
114        _sigschemes: &[SignatureScheme],
115    ) -> Option<Arc<CertifiedKey>> {
116        Some(self.0.clone())
117    }
118
119    fn has_certs(&self) -> bool {
120        true
121    }
122}
123
124impl ResolvesServerCert for SingleCertAndKey {
125    fn resolve(&self, _client_hello: &ClientHello<'_>) -> Option<Arc<CertifiedKey>> {
126        Some(self.0.clone())
127    }
128}
129
130/// A packaged-together certificate chain, matching `SigningKey` and
131/// optional stapled OCSP response.
132///
133/// Note: this struct is also used to represent an [RFC 7250] raw public key,
134/// when the client/server is configured to use raw public keys instead of
135/// certificates.
136///
137/// [RFC 7250]: https://tools.ietf.org/html/rfc7250
138#[non_exhaustive]
139#[derive(Clone, Debug)]
140pub struct CertifiedKey {
141    /// The certificate chain or raw public key.
142    pub cert_chain: Vec<CertificateDer<'static>>,
143
144    /// The certified key.
145    pub key: Arc<dyn SigningKey>,
146
147    /// An optional OCSP response from the certificate issuer,
148    /// attesting to its continued validity.
149    pub ocsp: Option<Vec<u8>>,
150}
151
152impl CertifiedKey {
153    /// Create a new `CertifiedKey` from a certificate chain and DER-encoded private key.
154    ///
155    /// Attempt to parse the private key with the given [`CryptoProvider`]'s [`KeyProvider`] and
156    /// verify that it matches the public key in the first certificate of the `cert_chain`
157    /// if possible.
158    ///
159    /// [`KeyProvider`]: crate::crypto::KeyProvider
160    pub fn from_der(
161        cert_chain: Vec<CertificateDer<'static>>,
162        key: PrivateKeyDer<'static>,
163        provider: &CryptoProvider,
164    ) -> Result<Self, Error> {
165        Self::new(
166            cert_chain,
167            provider
168                .key_provider
169                .load_private_key(key)?,
170        )
171    }
172
173    /// Make a new CertifiedKey, with the given chain and key.
174    ///
175    /// The cert chain must not be empty. The first certificate in the chain
176    /// must be the end-entity certificate. The end-entity certificate's
177    /// subject public key info must match that of the `key`'s public key.
178    /// If the `key` does not have a public key, this will return an
179    /// `InconsistentKeys::Unknown` error.
180    ///
181    /// This constructor should be used with all [`SigningKey`] implementations
182    /// that can provide a public key, including those provided by rustls itself.
183    pub fn new(
184        cert_chain: Vec<CertificateDer<'static>>,
185        key: Arc<dyn SigningKey>,
186    ) -> Result<Self, Error> {
187        let parsed = ParsedCertificate::try_from(
188            cert_chain
189                .first()
190                .ok_or(Error::NoCertificatesPresented)?,
191        )?;
192
193        match (key.public_key(), parsed.subject_public_key_info()) {
194            (None, _) => Err(Error::InconsistentKeys(InconsistentKeys::Unknown)),
195            (Some(key_spki), cert_spki) if key_spki != cert_spki => {
196                Err(Error::InconsistentKeys(InconsistentKeys::KeyMismatch))
197            }
198            _ => Ok(Self {
199                cert_chain,
200                key,
201                ocsp: None,
202            }),
203        }
204    }
205
206    /// Make a new `CertifiedKey` from a raw private key.
207    ///
208    /// Unlike [`CertifiedKey::new()`], this does not check that the end-entity certificate's
209    /// subject key matches `key`'s public key.
210    ///
211    /// This avoids parsing the end-entity certificate, which is useful when using client
212    /// certificates that are not fully standards compliant, but known to usable by the peer.
213    pub fn new_unchecked(
214        cert_chain: Vec<CertificateDer<'static>>,
215        key: Arc<dyn SigningKey>,
216    ) -> Self {
217        Self {
218            cert_chain,
219            key,
220            ocsp: None,
221        }
222    }
223
224    /// Verify the consistency of this [`CertifiedKey`]'s public and private keys.
225    /// This is done by performing a comparison of SubjectPublicKeyInfo bytes.
226    pub fn keys_match(&self) -> Result<(), Error> {
227        let Some(key_spki) = self.key.public_key() else {
228            return Err(InconsistentKeys::Unknown.into());
229        };
230
231        let cert = ParsedCertificate::try_from(self.end_entity_cert()?)?;
232        match key_spki == cert.subject_public_key_info() {
233            true => Ok(()),
234            false => Err(InconsistentKeys::KeyMismatch.into()),
235        }
236    }
237
238    /// The end-entity certificate.
239    pub fn end_entity_cert(&self) -> Result<&CertificateDer<'_>, Error> {
240        self.cert_chain
241            .first()
242            .ok_or(Error::NoCertificatesPresented)
243    }
244}
245
246#[cfg_attr(not(any(feature = "aws-lc-rs", feature = "ring")), allow(dead_code))]
247pub(crate) fn public_key_to_spki(
248    alg_id: &AlgorithmIdentifier,
249    public_key: impl AsRef<[u8]>,
250) -> SubjectPublicKeyInfoDer<'static> {
251    // SubjectPublicKeyInfo  ::=  SEQUENCE  {
252    //    algorithm            AlgorithmIdentifier,
253    //    subjectPublicKey     BIT STRING  }
254    //
255    // AlgorithmIdentifier  ::=  SEQUENCE  {
256    //    algorithm               OBJECT IDENTIFIER,
257    //    parameters              ANY DEFINED BY algorithm OPTIONAL  }
258    //
259    // note that the `pki_types::AlgorithmIdentifier` type is the
260    // concatenation of `algorithm` and `parameters`, but misses the
261    // outer `Sequence`.
262
263    let mut spki_inner = x509::wrap_in_sequence(alg_id.as_ref());
264    spki_inner.extend(&x509::wrap_in_bit_string(public_key.as_ref()));
265
266    let spki = x509::wrap_in_sequence(&spki_inner);
267
268    SubjectPublicKeyInfoDer::from(spki)
269}