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