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 as *mut core::ffi::c_void,
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{:X}",
154 status
155 )));
156 }
157 }
158 Ok((hash, padding))
159 }
160}
161
162impl Signer for CngSigner {
163 fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
164 let (hash, padding) = self.hash(message)?;
165 let signature = self
166 .key
167 .sign(&hash, padding)
168 .map_err(|e| Error::Other(OtherError(Arc::new(e))))?;
169
170 if padding == SignaturePadding::None {
171 Ok(p1363_to_der(&signature))
173 } else {
174 Ok(signature)
175 }
176 }
177
178 fn scheme(&self) -> SignatureScheme {
179 self.scheme
180 }
181}
182
183impl SigningKey for CngSigningKey {
184 fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> {
185 let supported = self.supported_schemes();
186 for scheme in offered {
187 if supported.contains(scheme) {
188 return Some(Box::new(CngSigner {
189 key: self.key.clone(),
190 scheme: *scheme,
191 }));
192 }
193 }
194 None
195 }
196
197 fn algorithm(&self) -> SignatureAlgorithm {
198 match self.algorithm_group {
199 AlgorithmGroup::Rsa => SignatureAlgorithm::RSA,
200 AlgorithmGroup::Ecdsa | AlgorithmGroup::Ecdh => SignatureAlgorithm::ECDSA,
201 }
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 #[test]
208 fn test_p1363_to_der() {
209 let p1363 = [1, 2, 3, 4, 5, 6, 7, 8];
210 let der = super::p1363_to_der(&p1363);
211 assert_eq!(
212 der,
213 [0x30, 0x0c, 0x02, 0x04, 1, 2, 3, 4, 0x02, 0x04, 5, 6, 7, 8]
214 )
215 }
216
217 #[test]
218 fn test_p1363_to_der_signed() {
219 let p1363 = [0x81, 2, 3, 4, 0x85, 6, 7, 8];
220 let der = super::p1363_to_der(&p1363);
221 assert_eq!(
222 der,
223 [0x30, 0x0e, 0x02, 0x05, 0, 0x81, 2, 3, 4, 0x02, 0x05, 0, 0x85, 6, 7, 8]
224 )
225 }
226}