Coverage Report

Created: 2025-12-31 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rustls-0.23.35/src/crypto/signer.rs
Line
Count
Source
1
use alloc::boxed::Box;
2
use alloc::vec::Vec;
3
use core::fmt::Debug;
4
5
use pki_types::{AlgorithmIdentifier, CertificateDer, PrivateKeyDer, SubjectPublicKeyInfoDer};
6
7
use super::CryptoProvider;
8
use crate::client::ResolvesClientCert;
9
use crate::enums::{SignatureAlgorithm, SignatureScheme};
10
use crate::error::{Error, InconsistentKeys};
11
use crate::server::{ClientHello, ParsedCertificate, ResolvesServerCert};
12
use crate::sync::Arc;
13
use 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
59
pub 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`] if available.
67
0
    fn public_key(&self) -> Option<SubjectPublicKeyInfoDer<'_>> {
68
        // Opt-out by default
69
0
        None
70
0
    }
71
72
    /// What kind of key we have.
73
    fn algorithm(&self) -> SignatureAlgorithm;
74
}
75
76
/// A thing that can sign a message.
77
pub 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)]
96
pub struct SingleCertAndKey(Arc<CertifiedKey>);
97
98
impl From<CertifiedKey> for SingleCertAndKey {
99
0
    fn from(certified_key: CertifiedKey) -> Self {
100
0
        Self(Arc::new(certified_key))
101
0
    }
102
}
103
104
impl From<Arc<CertifiedKey>> for SingleCertAndKey {
105
0
    fn from(certified_key: Arc<CertifiedKey>) -> Self {
106
0
        Self(certified_key)
107
0
    }
108
}
109
110
impl ResolvesClientCert for SingleCertAndKey {
111
0
    fn resolve(
112
0
        &self,
113
0
        _root_hint_subjects: &[&[u8]],
114
0
        _sigschemes: &[SignatureScheme],
115
0
    ) -> Option<Arc<CertifiedKey>> {
116
0
        Some(self.0.clone())
117
0
    }
118
119
0
    fn has_certs(&self) -> bool {
120
0
        true
121
0
    }
122
}
123
124
impl ResolvesServerCert for SingleCertAndKey {
125
0
    fn resolve(&self, _client_hello: ClientHello<'_>) -> Option<Arc<CertifiedKey>> {
126
0
        Some(self.0.clone())
127
0
    }
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
#[derive(Clone, Debug)]
139
pub struct CertifiedKey {
140
    /// The certificate chain or raw public key.
141
    pub cert: Vec<CertificateDer<'static>>,
142
143
    /// The certified key.
144
    pub key: Arc<dyn SigningKey>,
145
146
    /// An optional OCSP response from the certificate issuer,
147
    /// attesting to its continued validity.
148
    pub ocsp: Option<Vec<u8>>,
149
}
150
151
impl CertifiedKey {
152
    /// Create a new `CertifiedKey` from a certificate chain and DER-encoded private key.
153
    ///
154
    /// Attempt to parse the private key with the given [`CryptoProvider`]'s [`KeyProvider`] and
155
    /// verify that it matches the public key in the first certificate of the `cert_chain`
156
    /// if possible.
157
    ///
158
    /// [`KeyProvider`]: crate::crypto::KeyProvider
159
0
    pub fn from_der(
160
0
        cert_chain: Vec<CertificateDer<'static>>,
161
0
        key: PrivateKeyDer<'static>,
162
0
        provider: &CryptoProvider,
163
0
    ) -> Result<Self, Error> {
164
0
        let private_key = provider
165
0
            .key_provider
166
0
            .load_private_key(key)?;
167
168
0
        let certified_key = Self::new(cert_chain, private_key);
169
0
        match certified_key.keys_match() {
170
            // Don't treat unknown consistency as an error
171
0
            Ok(()) | Err(Error::InconsistentKeys(InconsistentKeys::Unknown)) => Ok(certified_key),
172
0
            Err(err) => Err(err),
173
        }
174
0
    }
175
176
    /// Make a new CertifiedKey, with the given chain and key.
177
    ///
178
    /// The cert chain must not be empty. The first certificate in the chain
179
    /// must be the end-entity certificate.
180
0
    pub fn new(cert: Vec<CertificateDer<'static>>, key: Arc<dyn SigningKey>) -> Self {
181
0
        Self {
182
0
            cert,
183
0
            key,
184
0
            ocsp: None,
185
0
        }
186
0
    }
187
188
    /// Verify the consistency of this [`CertifiedKey`]'s public and private keys.
189
    /// This is done by performing a comparison of SubjectPublicKeyInfo bytes.
190
0
    pub fn keys_match(&self) -> Result<(), Error> {
191
0
        let Some(key_spki) = self.key.public_key() else {
192
0
            return Err(InconsistentKeys::Unknown.into());
193
        };
194
195
0
        let cert = ParsedCertificate::try_from(self.end_entity_cert()?)?;
196
0
        match key_spki == cert.subject_public_key_info() {
197
0
            true => Ok(()),
198
0
            false => Err(InconsistentKeys::KeyMismatch.into()),
199
        }
200
0
    }
201
202
    /// The end-entity certificate.
203
0
    pub fn end_entity_cert(&self) -> Result<&CertificateDer<'_>, Error> {
204
0
        self.cert
205
0
            .first()
206
0
            .ok_or(Error::NoCertificatesPresented)
207
0
    }
208
}
209
210
/// Convert a public key and algorithm identifier into [`SubjectPublicKeyInfoDer`].
211
0
pub fn public_key_to_spki(
212
0
    alg_id: &AlgorithmIdentifier,
213
0
    public_key: impl AsRef<[u8]>,
214
0
) -> SubjectPublicKeyInfoDer<'static> {
215
    // SubjectPublicKeyInfo  ::=  SEQUENCE  {
216
    //    algorithm            AlgorithmIdentifier,
217
    //    subjectPublicKey     BIT STRING  }
218
    //
219
    // AlgorithmIdentifier  ::=  SEQUENCE  {
220
    //    algorithm               OBJECT IDENTIFIER,
221
    //    parameters              ANY DEFINED BY algorithm OPTIONAL  }
222
    //
223
    // note that the `pki_types::AlgorithmIdentifier` type is the
224
    // concatenation of `algorithm` and `parameters`, but misses the
225
    // outer `Sequence`.
226
227
0
    let mut spki_inner = x509::wrap_in_sequence(alg_id.as_ref());
228
0
    spki_inner.extend(&x509::wrap_in_bit_string(public_key.as_ref()));
229
230
0
    let spki = x509::wrap_in_sequence(&spki_inner);
231
232
0
    SubjectPublicKeyInfoDer::from(spki)
233
0
}
Unexecuted instantiation: rustls::crypto::signer::public_key_to_spki::<&ring::rsa::public_key::PublicKey>
Unexecuted instantiation: rustls::crypto::signer::public_key_to_spki::<&ring::ec::curve25519::ed25519::signing::PublicKey>
Unexecuted instantiation: rustls::crypto::signer::public_key_to_spki::<&ring::ec::suite_b::ecdsa::signing::PublicKey>