1use std::sync::Arc;
4
5use rustls::{
6 sign::{Signer, SigningKey},
7 SignatureAlgorithm, SignatureScheme, {Error, OtherError},
8};
9use windows_sys::Win32::Security::Cryptography::{
10 BCryptHash, CryptEncodeObjectEx, BCRYPT_SHA256_ALG_HANDLE, BCRYPT_SHA384_ALG_HANDLE,
11 BCRYPT_SHA512_ALG_HANDLE, CERT_ECC_SIGNATURE, CRYPT_INTEGER_BLOB, X509_ASN_ENCODING,
12 X509_ECC_SIGNATURE,
13};
14
15use crate::key::{AlgorithmGroup, NCryptKey, SignaturePadding};
16
17fn p1363_to_der(data: &mut [u8]) -> Result<Vec<u8>, Error> {
21 if data.is_empty() || !data.len().is_multiple_of(2) {
22 return Err(Error::General("Invalid signature size".to_owned()));
23 }
24
25 let (r, s) = data.split_at_mut(data.len() / 2);
26
27 r.reverse();
29 s.reverse();
30
31 let sig = CERT_ECC_SIGNATURE {
32 r: CRYPT_INTEGER_BLOB {
33 cbData: r.len() as u32,
34 pbData: r.as_mut_ptr(),
35 },
36 s: CRYPT_INTEGER_BLOB {
37 cbData: s.len() as u32,
38 pbData: s.as_mut_ptr(),
39 },
40 };
41 let sig_ptr = std::ptr::from_ref(&sig).cast();
42
43 unsafe {
44 let mut len = 0u32;
46 let status = CryptEncodeObjectEx(
47 X509_ASN_ENCODING,
48 X509_ECC_SIGNATURE,
49 sig_ptr,
50 0,
51 std::ptr::null(),
52 std::ptr::null_mut(),
53 &mut len,
54 );
55 if status == 0 {
56 return Err(Error::General(
57 "CryptEncodeObjectEx failed to size the signature".to_owned(),
58 ));
59 }
60
61 let mut der = vec![0u8; len as usize];
62 let status = CryptEncodeObjectEx(
63 X509_ASN_ENCODING,
64 X509_ECC_SIGNATURE,
65 sig_ptr,
66 0,
67 std::ptr::null(),
68 der.as_mut_ptr().cast(),
69 &mut len,
70 );
71 if status == 0 {
72 return Err(Error::General(
73 "CryptEncodeObjectEx failed to encode the signature".to_owned(),
74 ));
75 }
76
77 der.truncate(len as usize);
78 Ok(der)
79 }
80}
81
82#[derive(Debug, Clone)]
84pub struct CngSigningKey {
85 key: NCryptKey,
86 algorithm_group: AlgorithmGroup,
87 bits: u32,
88}
89
90impl CngSigningKey {
91 pub fn new(key: NCryptKey) -> crate::Result<Self> {
93 let group = key.algorithm_group()?;
94 let bits = key.bits()?;
95 Ok(Self {
96 key,
97 algorithm_group: group,
98 bits,
99 })
100 }
101
102 pub fn key(&self) -> &NCryptKey {
104 &self.key
105 }
106
107 pub fn algorithm_group(&self) -> AlgorithmGroup {
109 self.algorithm_group
110 }
111
112 pub fn bits(&self) -> u32 {
114 self.bits
115 }
116
117 pub fn supported_schemes(&self) -> &[SignatureScheme] {
119 match self.algorithm_group {
120 AlgorithmGroup::Rsa => &[
121 SignatureScheme::RSA_PKCS1_SHA256,
122 SignatureScheme::RSA_PKCS1_SHA384,
123 SignatureScheme::RSA_PKCS1_SHA512,
124 SignatureScheme::RSA_PSS_SHA256,
125 SignatureScheme::RSA_PSS_SHA384,
126 SignatureScheme::RSA_PSS_SHA512,
127 ],
128 AlgorithmGroup::Ecdsa | AlgorithmGroup::Ecdh => match self.bits {
129 256 => &[SignatureScheme::ECDSA_NISTP256_SHA256],
130 384 => &[SignatureScheme::ECDSA_NISTP384_SHA384],
131 521 => &[SignatureScheme::ECDSA_NISTP521_SHA512],
132 _ => &[],
133 },
134 }
135 }
136}
137
138#[derive(Debug)]
139struct CngSigner {
140 key: NCryptKey,
141 scheme: SignatureScheme,
142}
143
144impl CngSigner {
145 fn hash(&self, message: &[u8]) -> Result<(Vec<u8>, SignaturePadding), Error> {
147 let (alg, padding) = match self.scheme {
148 SignatureScheme::RSA_PKCS1_SHA256 => {
149 (BCRYPT_SHA256_ALG_HANDLE, SignaturePadding::Pkcs1)
150 }
151 SignatureScheme::RSA_PKCS1_SHA384 => {
152 (BCRYPT_SHA384_ALG_HANDLE, SignaturePadding::Pkcs1)
153 }
154 SignatureScheme::RSA_PKCS1_SHA512 => {
155 (BCRYPT_SHA512_ALG_HANDLE, SignaturePadding::Pkcs1)
156 }
157 SignatureScheme::RSA_PSS_SHA256 => (BCRYPT_SHA256_ALG_HANDLE, SignaturePadding::Pss),
158 SignatureScheme::RSA_PSS_SHA384 => (BCRYPT_SHA384_ALG_HANDLE, SignaturePadding::Pss),
159 SignatureScheme::RSA_PSS_SHA512 => (BCRYPT_SHA512_ALG_HANDLE, SignaturePadding::Pss),
160 SignatureScheme::ECDSA_NISTP256_SHA256 => {
161 (BCRYPT_SHA256_ALG_HANDLE, SignaturePadding::None)
162 }
163 SignatureScheme::ECDSA_NISTP384_SHA384 => {
164 (BCRYPT_SHA384_ALG_HANDLE, SignaturePadding::None)
165 }
166 SignatureScheme::ECDSA_NISTP521_SHA512 => {
167 (BCRYPT_SHA512_ALG_HANDLE, SignaturePadding::None)
168 }
169 _ => return Err(Error::General("Unsupported signature scheme".to_owned())),
170 };
171
172 let hash_len = match alg {
173 BCRYPT_SHA256_ALG_HANDLE => 32,
174 BCRYPT_SHA384_ALG_HANDLE => 48,
175 BCRYPT_SHA512_ALG_HANDLE => 64,
176 _ => return Err(Error::General("Unsupported hash algorithm!".to_owned())),
177 };
178
179 let mut hash = vec![0u8; hash_len];
180
181 unsafe {
182 let status = BCryptHash(
183 alg,
184 std::ptr::null_mut(), 0, message.as_ptr().cast(),
187 message.len() as u32,
188 hash.as_mut_ptr(),
189 hash_len as u32,
190 );
191
192 if status != 0 {
193 return Err(Error::General(format!(
194 "BCryptHash failed with status: 0x{status:X}"
195 )));
196 }
197 }
198 Ok((hash, padding))
199 }
200}
201
202impl Signer for CngSigner {
203 fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
204 let (hash, padding) = self.hash(message)?;
205 let mut signature = self
206 .key
207 .sign(&hash, padding)
208 .map_err(|e| Error::Other(OtherError(Arc::new(e))))?;
209
210 if padding == SignaturePadding::None {
211 Ok(p1363_to_der(&mut signature)?)
213 } else {
214 Ok(signature)
215 }
216 }
217
218 fn scheme(&self) -> SignatureScheme {
219 self.scheme
220 }
221}
222
223impl SigningKey for CngSigningKey {
224 fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> {
225 let supported = self.supported_schemes();
226 for scheme in offered {
227 if supported.contains(scheme) {
228 return Some(Box::new(CngSigner {
229 key: self.key.clone(),
230 scheme: *scheme,
231 }));
232 }
233 }
234 None
235 }
236
237 fn algorithm(&self) -> SignatureAlgorithm {
238 match self.algorithm_group {
239 AlgorithmGroup::Rsa => SignatureAlgorithm::RSA,
240 AlgorithmGroup::Ecdsa | AlgorithmGroup::Ecdh => SignatureAlgorithm::ECDSA,
241 }
242 }
243}
244
245#[cfg(test)]
246mod tests {
247 use std::ptr;
248
249 use windows_sys::Win32::Security::Cryptography::{
250 CryptDecodeObjectEx, CERT_ECC_SIGNATURE, CRYPT_INTEGER_BLOB, X509_ASN_ENCODING,
251 X509_ECC_SIGNATURE,
252 };
253
254 unsafe fn blob_to_be(blob: &CRYPT_INTEGER_BLOB) -> Vec<u8> {
256 let le = unsafe { std::slice::from_raw_parts(blob.pbData, blob.cbData as usize) };
257 let mut be = le.iter().rev().copied().collect::<Vec<u8>>();
258 while be.len() > 1 && be[0] == 0 {
259 be.remove(0);
260 }
261 be
262 }
263
264 fn decode_der(data: &[u8]) -> (Vec<u8>, Vec<u8>) {
267 unsafe {
268 let mut len = 0u32;
270 let status = CryptDecodeObjectEx(
271 X509_ASN_ENCODING,
272 X509_ECC_SIGNATURE,
273 data.as_ptr(),
274 data.len() as u32,
275 0,
276 ptr::null(),
277 ptr::null_mut(),
278 &mut len,
279 );
280 assert_ne!(status, 0, "CryptDecodeObjectEx failed to size the output");
281
282 let mut buf = vec![0u8; len as usize];
283 let status = CryptDecodeObjectEx(
284 X509_ASN_ENCODING,
285 X509_ECC_SIGNATURE,
286 data.as_ptr(),
287 data.len() as u32,
288 0,
289 ptr::null(),
290 buf.as_mut_ptr().cast(),
291 &mut len,
292 );
293 assert_ne!(status, 0, "CryptDecodeObjectEx failed to decode");
294
295 let sig: &CERT_ECC_SIGNATURE = &*buf.as_ptr().cast();
296 (blob_to_be(&sig.r), blob_to_be(&sig.s))
297 }
298 }
299
300 fn validate_der(data: &[u8], r: &[u8], s: &[u8]) {
301 let (parsed_r, parsed_s) = decode_der(data);
302 assert_eq!(parsed_r, r);
303 assert_eq!(parsed_s, s);
304 }
305
306 #[test]
307 fn test_p1363_to_der() {
308 let mut p1363 = [1, 2, 3, 4, 5, 6, 7, 8];
309 let der = super::p1363_to_der(&mut p1363).unwrap();
310 validate_der(&der, &[1, 2, 3, 4], &[5, 6, 7, 8]);
311 }
312
313 #[test]
314 fn test_p1363_to_der_signed() {
315 let mut p1363 = [0x81, 2, 3, 4, 0x85, 6, 7, 8];
316 let der = super::p1363_to_der(&mut p1363).unwrap();
317 validate_der(&der, &[0x81, 2, 3, 4], &[0x85, 6, 7, 8]);
318 }
319
320 #[test]
321 fn test_p1363_to_der_zeroes_stripped() {
322 let mut p1363 = [0, 1, 2, 3, 4, 0, 5, 6, 7, 8];
323 let der = super::p1363_to_der(&mut p1363).unwrap();
324 validate_der(&der, &[1, 2, 3, 4], &[5, 6, 7, 8]);
325 }
326
327 #[test]
328 fn test_p1363_to_der_signed_zeroes_stripped() {
329 let mut p1363 = [0, 0x81, 2, 3, 4, 0, 0x85, 6, 7, 8];
330 let der = super::p1363_to_der(&mut p1363).unwrap();
331 validate_der(&der, &[0x81, 2, 3, 4], &[0x85, 6, 7, 8]);
332 }
333
334 #[test]
335 fn test_p1363_to_der_long() {
336 let r = (1..128).collect::<Vec<u8>>();
337 let s = (128..254).chain([0]).rev().collect::<Vec<u8>>();
338
339 let mut p1363 = r.clone().into_iter().chain(s.clone()).collect::<Vec<u8>>();
340 let der = super::p1363_to_der(&mut p1363).unwrap();
341
342 let expected_s = (128..254).rev().collect::<Vec<u8>>();
344 validate_der(&der, &r, &expected_s);
345 }
346}