1use std::sync::Arc;
8
9use rustls::sign::{Signer, SigningKey};
10use rustls::{Error, SignatureAlgorithm, SignatureScheme};
11use tracing::{debug, error};
12
13use crate::HsmContext;
14use crate::key::KeyAlgorithm;
15
16#[derive(Debug)]
18pub struct Pkcs11SigningKey {
19 hsm: Arc<HsmContext>,
20 key_label: String,
21 algorithm: KeyAlgorithm,
22}
23
24impl Pkcs11SigningKey {
25 pub fn new(
26 hsm: Arc<HsmContext>,
27 key_label: impl Into<String>,
28 algorithm: KeyAlgorithm,
29 ) -> Self {
30 Self {
31 hsm,
32 key_label: key_label.into(),
33 algorithm,
34 }
35 }
36}
37
38impl SigningKey for Pkcs11SigningKey {
39 fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> {
40 let supported = match &self.algorithm {
42 KeyAlgorithm::Rsa(_) => &[
43 SignatureScheme::RSA_PSS_SHA512,
44 SignatureScheme::RSA_PSS_SHA384,
45 SignatureScheme::RSA_PSS_SHA256,
46 SignatureScheme::RSA_PKCS1_SHA512,
47 SignatureScheme::RSA_PKCS1_SHA384,
48 SignatureScheme::RSA_PKCS1_SHA256,
49 ][..],
50 KeyAlgorithm::Ecdsa(curve) => match curve {
51 crate::key::EcdsaCurve::P256 => &[SignatureScheme::ECDSA_NISTP256_SHA256][..],
52 crate::key::EcdsaCurve::P384 => &[SignatureScheme::ECDSA_NISTP384_SHA384][..],
53 _ => &[SignatureScheme::ECDSA_NISTP521_SHA512][..],
54 },
55 _ => {
56 error!(algorithm = ?self.algorithm, "unsupported key algorithm for PKCS#11 TLS");
57 return None;
58 }
59 };
60
61 for scheme in offered {
62 if supported.contains(scheme) {
63 debug!(
64 key_label = %self.key_label,
65 scheme = ?scheme,
66 "PKCS#11 signing key: chose scheme"
67 );
68 return Some(Box::new(Pkcs11Signer {
69 hsm: Arc::clone(&self.hsm),
70 key_label: self.key_label.clone(),
71 scheme: *scheme,
72 }));
73 }
74 }
75
76 None
77 }
78
79 fn algorithm(&self) -> SignatureAlgorithm {
80 match &self.algorithm {
81 KeyAlgorithm::Rsa(_) => SignatureAlgorithm::RSA,
82 KeyAlgorithm::Ecdsa(_) => SignatureAlgorithm::ECDSA,
83 other => {
84 error!(algorithm = ?other, "unsupported algorithm for PKCS#11 TLS SigningKey");
85 SignatureAlgorithm::RSA
86 }
87 }
88 }
89}
90
91#[derive(Debug)]
93struct Pkcs11Signer {
94 hsm: Arc<HsmContext>,
95 key_label: String,
96 scheme: SignatureScheme,
97}
98
99impl Signer for Pkcs11Signer {
100 fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
101 self.hsm
102 .sign_tls(&self.key_label, message, self.scheme)
103 .map_err(|e| {
104 error!(
105 key_label = %self.key_label,
106 error = %e,
107 "PKCS#11 TLS signing failed"
108 );
109 Error::General(format!("PKCS#11 sign failed: {e}"))
110 })
111 }
112
113 fn scheme(&self) -> SignatureScheme {
114 self.scheme
115 }
116}
117
118pub fn certificate_algorithm(der: &[u8]) -> crate::HsmResult<KeyAlgorithm> {
120 let cert = openssl::x509::X509::from_der(der)
121 .map_err(|e| crate::HsmError::KeyNotFound(e.to_string()))?;
122 let key = cert
123 .public_key()
124 .map_err(|e| crate::HsmError::KeyNotFound(e.to_string()))?;
125 if key.id() == openssl::pkey::Id::RSA {
126 return Ok(KeyAlgorithm::Rsa(key.bits()));
127 }
128 let ec = key.ec_key().map_err(|_| {
129 crate::HsmError::UnsupportedMechanism("TLS HSM key must be RSA or ECDSA".into())
130 })?;
131 let curve = match ec.group().curve_name() {
132 Some(openssl::nid::Nid::X9_62_PRIME256V1) => crate::key::EcdsaCurve::P256,
133 Some(openssl::nid::Nid::SECP384R1) => crate::key::EcdsaCurve::P384,
134 Some(openssl::nid::Nid::SECP521R1) => crate::key::EcdsaCurve::P521,
135 _ => {
136 return Err(crate::HsmError::UnsupportedMechanism(
137 "unsupported TLS EC curve".into(),
138 ));
139 }
140 };
141 Ok(KeyAlgorithm::Ecdsa(curve))
142}
143
144pub fn verify_tls_key(hsm: &HsmContext, label: &str, cert_der: &[u8]) -> crate::HsmResult<()> {
146 use openssl::{
147 hash::MessageDigest,
148 rsa::Padding,
149 sign::{RsaPssSaltlen, Verifier},
150 };
151 let algorithm = certificate_algorithm(cert_der)?;
152 let (scheme, digest) = match algorithm {
153 KeyAlgorithm::Rsa(_) => (SignatureScheme::RSA_PSS_SHA256, MessageDigest::sha256()),
154 KeyAlgorithm::Ecdsa(crate::key::EcdsaCurve::P256) => (
155 SignatureScheme::ECDSA_NISTP256_SHA256,
156 MessageDigest::sha256(),
157 ),
158 KeyAlgorithm::Ecdsa(crate::key::EcdsaCurve::P384) => (
159 SignatureScheme::ECDSA_NISTP384_SHA384,
160 MessageDigest::sha384(),
161 ),
162 KeyAlgorithm::Ecdsa(crate::key::EcdsaCurve::P521) => (
163 SignatureScheme::ECDSA_NISTP521_SHA512,
164 MessageDigest::sha512(),
165 ),
166 _ => {
167 return Err(crate::HsmError::UnsupportedMechanism(
168 "unsupported TLS key".into(),
169 ));
170 }
171 };
172 let map = |e: openssl::error::ErrorStack| crate::HsmError::SigningFailure(e.to_string());
173 let mut challenge = [0u8; 32];
174 openssl::rand::rand_bytes(&mut challenge).map_err(map)?;
175 let signature = hsm.sign_tls(label, &challenge, scheme)?;
176 let public = openssl::x509::X509::from_der(cert_der)
177 .map_err(map)?
178 .public_key()
179 .map_err(map)?;
180 let mut verifier = Verifier::new(digest, &public).map_err(map)?;
181 if matches!(algorithm, KeyAlgorithm::Rsa(_)) {
182 verifier.set_rsa_padding(Padding::PKCS1_PSS).map_err(map)?;
183 verifier.set_rsa_mgf1_md(digest).map_err(map)?;
184 verifier
185 .set_rsa_pss_saltlen(RsaPssSaltlen::DIGEST_LENGTH)
186 .map_err(map)?;
187 }
188 if !verifier
189 .verify_oneshot(&signature, &challenge)
190 .map_err(map)?
191 {
192 return Err(crate::HsmError::SigningFailure(
193 "HSM key does not match TLS certificate".into(),
194 ));
195 }
196 Ok(())
197}
198
199#[cfg(test)]
200mod review_regressions {
201 use super::*;
202 #[test]
203 fn tls13_rsa_pss_and_exact_ec_curve_schemes() {
204 let hsm = Arc::new(HsmContext::placeholder());
205 let rsa = Pkcs11SigningKey::new(hsm.clone(), "synthetic", KeyAlgorithm::Rsa(2048));
206 assert!(
207 rsa.choose_scheme(&[SignatureScheme::RSA_PSS_SHA256])
208 .is_some()
209 );
210 for (curve, scheme) in [
211 (
212 crate::key::EcdsaCurve::P256,
213 SignatureScheme::ECDSA_NISTP256_SHA256,
214 ),
215 (
216 crate::key::EcdsaCurve::P384,
217 SignatureScheme::ECDSA_NISTP384_SHA384,
218 ),
219 (
220 crate::key::EcdsaCurve::P521,
221 SignatureScheme::ECDSA_NISTP521_SHA512,
222 ),
223 ] {
224 let ec = Pkcs11SigningKey::new(hsm.clone(), "synthetic", KeyAlgorithm::Ecdsa(curve));
225 assert_eq!(ec.choose_scheme(&[scheme]).unwrap().scheme(), scheme);
226 assert!(
227 ec.choose_scheme(&[SignatureScheme::RSA_PSS_SHA256])
228 .is_none()
229 );
230 }
231 }
232}