1use std::sync::Arc;
4
5use rustls::{
6 sign::{Signer, SigningKey},
7 Error, OtherError, SignatureAlgorithm, SignatureScheme,
8};
9
10use crate::key::{AlgorithmGroup, NCryptKey, SignaturePadding};
11
12use windows_sys::Win32::Security::Cryptography::BCryptHash;
13use windows_sys::Win32::Security::Cryptography::{
14 BCRYPT_SHA256_ALG_HANDLE, BCRYPT_SHA384_ALG_HANDLE, BCRYPT_SHA512_ALG_HANDLE,
15};
16
17fn p1363_to_der(data: &[u8]) -> Vec<u8> {
20 let (r, s) = data.split_at(data.len() / 2);
21
22 let r_sign: &[u8] = if r[0] >= 0x80 { &[0] } else { &[] };
23 let s_sign: &[u8] = if s[0] >= 0x80 { &[0] } else { &[] };
24
25 let length = data.len() + 2 + 4 + r_sign.len() + s_sign.len();
26
27 let mut buf = Vec::with_capacity(length);
28
29 buf.push(0x30); buf.push((length - 2) as u8);
31
32 buf.push(0x02); buf.push((r.len() + r_sign.len()) as u8);
34 buf.extend(r_sign);
35 buf.extend(r);
36
37 buf.push(0x02); buf.push((s.len() + s_sign.len()) as u8);
39 buf.extend(s_sign);
40 buf.extend(s);
41
42 buf
43}
44
45#[derive(Debug)]
47pub struct CngSigningKey {
48 key: NCryptKey,
49 algorithm_group: AlgorithmGroup,
50 bits: u32,
51}
52
53impl CngSigningKey {
54 pub fn new(key: NCryptKey) -> crate::Result<Self> {
56 let group = key.algorithm_group()?;
57 let bits = key.bits()?;
58 Ok(Self {
59 key,
60 algorithm_group: group,
61 bits,
62 })
63 }
64
65 pub fn key(&self) -> &NCryptKey {
67 &self.key
68 }
69
70 pub fn algorithm_group(&self) -> &AlgorithmGroup {
72 &self.algorithm_group
73 }
74
75 pub fn bits(&self) -> u32 {
77 self.bits
78 }
79
80 pub fn supported_schemes(&self) -> &[SignatureScheme] {
82 match self.algorithm_group {
83 AlgorithmGroup::Rsa => &[
84 SignatureScheme::RSA_PKCS1_SHA256,
85 SignatureScheme::RSA_PKCS1_SHA384,
86 SignatureScheme::RSA_PKCS1_SHA512,
87 SignatureScheme::RSA_PSS_SHA256,
88 SignatureScheme::RSA_PSS_SHA384,
89 SignatureScheme::RSA_PSS_SHA512,
90 ],
91 AlgorithmGroup::Ecdsa | AlgorithmGroup::Ecdh => match self.bits {
92 256 => &[SignatureScheme::ECDSA_NISTP256_SHA256],
93 384 => &[SignatureScheme::ECDSA_NISTP384_SHA384],
94 _ => &[],
95 },
96 }
97 }
98}
99
100#[derive(Debug)]
101struct CngSigner {
102 key: NCryptKey,
103 scheme: SignatureScheme,
104}
105
106impl CngSigner {
107 fn hash(&self, message: &[u8]) -> Result<(Vec<u8>, SignaturePadding), Error> {
109 let (alg, padding) = match self.scheme {
110 SignatureScheme::RSA_PKCS1_SHA256 => {
111 (BCRYPT_SHA256_ALG_HANDLE, SignaturePadding::Pkcs1)
112 }
113 SignatureScheme::RSA_PKCS1_SHA384 => {
114 (BCRYPT_SHA384_ALG_HANDLE, SignaturePadding::Pkcs1)
115 }
116 SignatureScheme::RSA_PKCS1_SHA512 => {
117 (BCRYPT_SHA512_ALG_HANDLE, SignaturePadding::Pkcs1)
118 }
119 SignatureScheme::RSA_PSS_SHA256 => (BCRYPT_SHA256_ALG_HANDLE, SignaturePadding::Pss),
120 SignatureScheme::RSA_PSS_SHA384 => (BCRYPT_SHA384_ALG_HANDLE, SignaturePadding::Pss),
121 SignatureScheme::RSA_PSS_SHA512 => (BCRYPT_SHA512_ALG_HANDLE, SignaturePadding::Pss),
122 SignatureScheme::ECDSA_NISTP256_SHA256 => {
123 (BCRYPT_SHA256_ALG_HANDLE, SignaturePadding::None)
124 }
125 SignatureScheme::ECDSA_NISTP384_SHA384 => {
126 (BCRYPT_SHA384_ALG_HANDLE, SignaturePadding::None)
127 }
128 _ => return Err(Error::General("Unsupported signature scheme".to_owned())),
129 };
130
131 let hash_len = match alg {
132 BCRYPT_SHA256_ALG_HANDLE => 32,
133 BCRYPT_SHA384_ALG_HANDLE => 48,
134 BCRYPT_SHA512_ALG_HANDLE => 64,
135 _ => return Err(Error::General("Unsupported hash algorithm!".to_owned())),
136 };
137
138 let mut hash = vec![0u8; hash_len];
139
140 unsafe {
141 let status = BCryptHash(
142 alg,
143 std::ptr::null_mut(), 0, message.as_ptr() as *mut u8,
146 message.len() as u32,
147 hash.as_mut_ptr(),
148 hash_len as u32,
149 );
150
151 if status != 0 {
152 return Err(Error::General(format!(
153 "BCryptHash failed with status: 0x{status:X}"
154 )));
155 }
156 }
157 Ok((hash, padding))
158 }
159}
160
161impl Signer for CngSigner {
162 fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
163 let (hash, padding) = self.hash(message)?;
164 let signature = self
165 .key
166 .sign(&hash, padding)
167 .map_err(|e| Error::Other(OtherError(Arc::new(e))))?;
168
169 if padding == SignaturePadding::None {
170 Ok(p1363_to_der(&signature))
172 } else {
173 Ok(signature)
174 }
175 }
176
177 fn scheme(&self) -> SignatureScheme {
178 self.scheme
179 }
180}
181
182impl SigningKey for CngSigningKey {
183 fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> {
184 let supported = self.supported_schemes();
185 for scheme in offered {
186 if supported.contains(scheme) {
187 return Some(Box::new(CngSigner {
188 key: self.key.clone(),
189 scheme: *scheme,
190 }));
191 }
192 }
193 None
194 }
195
196 fn algorithm(&self) -> SignatureAlgorithm {
197 match self.algorithm_group {
198 AlgorithmGroup::Rsa => SignatureAlgorithm::RSA,
199 AlgorithmGroup::Ecdsa | AlgorithmGroup::Ecdh => SignatureAlgorithm::ECDSA,
200 }
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 #[test]
207 fn test_p1363_to_der() {
208 let p1363 = [1, 2, 3, 4, 5, 6, 7, 8];
209 let der = super::p1363_to_der(&p1363);
210 assert_eq!(
211 der,
212 [0x30, 0x0c, 0x02, 0x04, 1, 2, 3, 4, 0x02, 0x04, 5, 6, 7, 8]
213 )
214 }
215
216 #[test]
217 fn test_p1363_to_der_signed() {
218 let p1363 = [0x81, 2, 3, 4, 0x85, 6, 7, 8];
219 let der = super::p1363_to_der(&p1363);
220 assert_eq!(
221 der,
222 [0x30, 0x0e, 0x02, 0x05, 0, 0x81, 2, 3, 4, 0x02, 0x05, 0, 0x85, 6, 7, 8]
223 )
224 }
225}