1use std::fmt;
6#[cfg(not(windows))]
7use std::sync::Arc;
8
9use super::{Certificate, Error, KeyType};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum HashAlg {
14 Sha256,
16 Sha384,
18 Sha512,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum SignScheme {
25 RsaPkcs1(HashAlg),
27 RsaPss(HashAlg),
29 Ecdsa(HashAlg),
31}
32
33#[derive(Clone)]
35pub struct PrivateKey {
36 cert: Certificate,
37 #[cfg(not(windows))]
38 pub(super) der: Arc<zeroize::Zeroizing<Vec<u8>>>,
39 #[cfg(all(not(windows), feature = "rustls"))]
40 pub(crate) signing_key: Arc<dyn tls_rustls::sign::SigningKey>,
41 #[cfg(all(not(windows), not(feature = "rustls"), feature = "openssl"))]
42 key: tls_openssl::pkey::PKey<tls_openssl::pkey::Private>,
43 #[cfg(windows)]
44 pub(crate) native: super::cng::CngKey,
45}
46
47impl PrivateKey {
48 pub(crate) fn from_pkcs8(cert: &Certificate, der: &[u8]) -> Result<Self, Error> {
50 #[cfg(windows)]
51 {
52 let native = super::cng::from_pkcs8(cert, der)?;
53 Ok(Self::from_native(cert.clone(), native))
54 }
55 #[cfg(all(not(windows), feature = "rustls"))]
56 {
57 use tls_rustls::pki_types::{CertificateDer, PrivatePkcs8KeyDer};
58 let provider = super::crypto::provider()?;
59 let key = provider
60 .key_provider
61 .load_private_key(PrivatePkcs8KeyDer::from(der.to_vec()).into())
62 .map_err(|e| Error::InvalidIdentity(e.to_string()))?;
63 let certified = tls_rustls::sign::CertifiedKey::new(
64 vec![CertificateDer::from(cert.der().to_vec())],
65 key.clone(),
66 );
67 certified
68 .keys_match()
69 .map_err(|e| Error::InvalidIdentity(e.to_string()))?;
70 Ok(Self {
71 cert: cert.clone(),
72 der: Arc::new(zeroize::Zeroizing::new(der.to_vec())),
73 signing_key: key,
74 })
75 }
76 #[cfg(all(not(windows), not(feature = "rustls"), feature = "openssl"))]
77 {
78 let invalid = |e: tls_openssl::error::ErrorStack| Error::InvalidIdentity(e.to_string());
79 let key = tls_openssl::pkey::PKey::private_key_from_pkcs8(der).map_err(invalid)?;
80 let public = tls_openssl::pkey::PKey::public_key_from_der(cert.public_key_der())
81 .map_err(invalid)?;
82 if !key.public_eq(&public) {
83 return Err(Error::InvalidIdentity(
84 "certificate/private key mismatch".into(),
85 ));
86 }
87 Ok(Self {
88 cert: cert.clone(),
89 der: Arc::new(zeroize::Zeroizing::new(der.to_vec())),
90 key,
91 })
92 }
93 }
94
95 #[cfg(windows)]
96 pub(crate) fn from_native(cert: Certificate, native: super::cng::CngKey) -> Self {
97 Self { cert, native }
98 }
99
100 #[must_use]
102 pub fn key_type(&self) -> Option<KeyType> {
103 self.cert.key_type()
104 }
105
106 #[must_use]
108 pub fn public_key_der(&self) -> &[u8] {
109 self.cert.public_key_der()
110 }
111
112 pub fn export_pkcs8_der(&self) -> Result<&[u8], Error> {
117 #[cfg(not(windows))]
118 {
119 Ok(&self.der)
120 }
121 #[cfg(windows)]
122 {
123 Err(Error::Unsupported(
124 "native private keys cannot be exported".into(),
125 ))
126 }
127 }
128
129 pub fn sign(&self, scheme: SignScheme, message: &[u8]) -> Result<Vec<u8>, Error> {
135 #[cfg(windows)]
136 {
137 self.native.sign(scheme, message)
138 }
139 #[cfg(all(not(windows), feature = "rustls"))]
140 {
141 self.signing_key
142 .choose_scheme(&[scheme.rustls()])
143 .ok_or_else(|| Error::Unsupported(format!("signature scheme {scheme:?}")))?
144 .sign(message)
145 .map_err(|e| Error::Backend(e.to_string()))
146 }
147 #[cfg(all(not(windows), not(feature = "rustls"), feature = "openssl"))]
148 {
149 use tls_openssl::hash::MessageDigest;
150 use tls_openssl::rsa::Padding;
151 use tls_openssl::sign::{RsaPssSaltlen, Signer};
152
153 let rsa = self.key_type() == Some(KeyType::Rsa);
154 let hash = match scheme {
155 SignScheme::RsaPkcs1(h) | SignScheme::RsaPss(h) if rsa => h,
156 SignScheme::Ecdsa(h)
157 if matches!(
158 self.key_type(),
159 Some(KeyType::EcP256 | KeyType::EcP384 | KeyType::EcP521)
160 ) =>
161 {
162 h
163 }
164 _ => return Err(Error::Unsupported(format!("signature scheme {scheme:?}"))),
165 };
166 let digest = match hash {
167 HashAlg::Sha256 => MessageDigest::sha256(),
168 HashAlg::Sha384 => MessageDigest::sha384(),
169 HashAlg::Sha512 => MessageDigest::sha512(),
170 };
171 let error = |e: tls_openssl::error::ErrorStack| Error::Backend(e.to_string());
172 let mut signer = Signer::new(digest, &self.key).map_err(error)?;
173 if matches!(scheme, SignScheme::RsaPss(_)) {
174 signer.set_rsa_padding(Padding::PKCS1_PSS).map_err(error)?;
175 signer.set_rsa_mgf1_md(digest).map_err(error)?;
176 signer
177 .set_rsa_pss_saltlen(RsaPssSaltlen::DIGEST_LENGTH)
178 .map_err(error)?;
179 }
180 signer.sign_oneshot_to_vec(message).map_err(error)
181 }
182 }
183}
184
185#[cfg(feature = "rustls")]
186impl SignScheme {
187 pub(crate) fn rustls(self) -> tls_rustls::SignatureScheme {
188 use tls_rustls::SignatureScheme as S;
189 match self {
190 Self::RsaPkcs1(HashAlg::Sha256) => S::RSA_PKCS1_SHA256,
191 Self::RsaPkcs1(HashAlg::Sha384) => S::RSA_PKCS1_SHA384,
192 Self::RsaPkcs1(HashAlg::Sha512) => S::RSA_PKCS1_SHA512,
193 Self::RsaPss(HashAlg::Sha256) => S::RSA_PSS_SHA256,
194 Self::RsaPss(HashAlg::Sha384) => S::RSA_PSS_SHA384,
195 Self::RsaPss(HashAlg::Sha512) => S::RSA_PSS_SHA512,
196 Self::Ecdsa(HashAlg::Sha256) => S::ECDSA_NISTP256_SHA256,
197 Self::Ecdsa(HashAlg::Sha384) => S::ECDSA_NISTP384_SHA384,
198 Self::Ecdsa(HashAlg::Sha512) => S::ECDSA_NISTP521_SHA512,
199 }
200 }
201}
202
203impl fmt::Debug for PrivateKey {
204 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205 f.debug_struct("PrivateKey")
206 .field("key_type", &self.key_type())
207 .field("material", &"<redacted>")
208 .finish()
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215 use crate::x509::Identity;
216 use tls_rustls::SignatureScheme as S;
217
218 fn verify(cert: &Certificate, scheme: S, message: &[u8], signature: &[u8]) -> bool {
219 use x509_parser::prelude::{FromDer, X509Certificate};
220 let (_, cert) = X509Certificate::from_der(cert.der()).unwrap();
221 let provider = tls_rustls::crypto::ring::default_provider();
222 provider
223 .signature_verification_algorithms
224 .mapping
225 .iter()
226 .find(|(candidate, _)| *candidate == scheme)
227 .unwrap()
228 .1
229 .iter()
230 .any(|algorithm| {
231 algorithm
232 .verify_signature(
233 &cert.public_key().subject_public_key.data,
234 message,
235 signature,
236 )
237 .is_ok()
238 })
239 }
240
241 #[test]
248 fn rsa_signature_schemes() {
249 crate::x509::test_provider();
250 let identity = Identity::from_pem(
251 include_bytes!("../../examples/cert.pem"),
252 include_bytes!("../../examples/key.pem"),
253 )
254 .unwrap();
255 for (hash, pkcs1, pss) in [
256 (HashAlg::Sha256, S::RSA_PKCS1_SHA256, S::RSA_PSS_SHA256),
257 (HashAlg::Sha384, S::RSA_PKCS1_SHA384, S::RSA_PSS_SHA384),
258 (HashAlg::Sha512, S::RSA_PKCS1_SHA512, S::RSA_PSS_SHA512),
259 ] {
260 for (scheme, expected, other) in [
261 (SignScheme::RsaPkcs1(hash), pkcs1, pss),
262 (SignScheme::RsaPss(hash), pss, pkcs1),
263 ] {
264 let signature = identity.private_key().sign(scheme, b"message").unwrap();
265 assert!(verify(identity.cert(), expected, b"message", &signature));
266 assert!(!verify(identity.cert(), expected, b"modified", &signature));
267 assert!(!verify(identity.cert(), other, b"message", &signature));
268 }
269 }
270 }
271
272 #[cfg(not(windows))]
279 #[test]
280 fn ec_identity_signatures() {
281 crate::x509::test_provider();
282 for (algorithm, hash, scheme) in [
283 (
284 &rcgen::PKCS_ECDSA_P256_SHA256,
285 HashAlg::Sha256,
286 S::ECDSA_NISTP256_SHA256,
287 ),
288 (
289 &rcgen::PKCS_ECDSA_P384_SHA384,
290 HashAlg::Sha384,
291 S::ECDSA_NISTP384_SHA384,
292 ),
293 ] {
294 let key = rcgen::KeyPair::generate_for(algorithm).unwrap();
295 let cert = rcgen::CertificateParams::default()
296 .self_signed(&key)
297 .unwrap();
298 let other = rcgen::KeyPair::generate_for(algorithm).unwrap();
299 assert!(matches!(
300 Identity::from_der(&[cert.der()], other.serialized_der()),
301 Err(Error::InvalidIdentity(_))
302 ));
303 let identity = Identity::from_der(&[cert.der()], key.serialized_der()).unwrap();
304 let key = PrivateKey::from_pkcs8(
305 identity.cert(),
306 identity.private_key().export_pkcs8_der().unwrap(),
307 )
308 .unwrap();
309 let signature = key.sign(SignScheme::Ecdsa(hash), b"message").unwrap();
310 assert!(verify(identity.cert(), scheme, b"message", &signature));
311 assert!(!verify(identity.cert(), scheme, b"modified", &signature));
312 assert!(matches!(
313 key.sign(SignScheme::RsaPss(hash), b"message"),
314 Err(Error::Unsupported(_))
315 ));
316 #[cfg(feature = "rustls")]
317 {
318 let certified = crate::rustls::certified_key(&identity).unwrap();
319 assert!(certified.key.choose_scheme(&[S::RSA_PSS_SHA256]).is_none());
320 let signer = certified.key.choose_scheme(&[scheme]).unwrap();
321 assert_eq!(signer.scheme(), scheme);
322 assert!(verify(
323 identity.cert(),
324 scheme,
325 b"message",
326 &signer.sign(b"message").unwrap()
327 ));
328 }
329 }
330 }
331}