1use ring::digest;
8use ring::rand::{SecureRandom, SystemRandom};
9use ring::signature::{self, UnparsedPublicKey};
10
11use crate::credential::Challenge;
12pub use crate::der::rsa_components_to_der;
13use crate::error::{Result, WebAuthnError};
14
15pub fn sha256(data: &[u8]) -> [u8; 32] {
20 let digest = digest::digest(&digest::SHA256, data);
21 digest
23 .as_ref()
24 .try_into()
25 .expect("SHA-256 digest is always 32 bytes")
26}
27
28pub fn random_bytes(len: usize) -> Result<Vec<u8>> {
34 let rng = SystemRandom::new();
35 let mut bytes = vec![0u8; len];
36 rng.fill(&mut bytes).map_err(|_| {
37 WebAuthnError::InvalidClientData(
38 "system random number generator failed to produce bytes".to_string(),
39 )
40 })?;
41 Ok(bytes)
42}
43
44pub fn verify_es256(
56 public_key_uncompressed: &[u8],
57 message: &[u8],
58 signature: &[u8],
59) -> Result<()> {
60 let key = UnparsedPublicKey::new(&signature::ECDSA_P256_SHA256_ASN1, public_key_uncompressed);
61 key.verify(message, signature)
62 .map_err(|_| WebAuthnError::SignatureVerificationFailed)
63}
64
65pub fn verify_es384(
77 public_key_uncompressed: &[u8],
78 message: &[u8],
79 signature: &[u8],
80) -> Result<()> {
81 let key = UnparsedPublicKey::new(&signature::ECDSA_P384_SHA384_ASN1, public_key_uncompressed);
82 key.verify(message, signature)
83 .map_err(|_| WebAuthnError::SignatureVerificationFailed)
84}
85
86pub fn verify_eddsa(public_key: &[u8], message: &[u8], signature: &[u8]) -> Result<()> {
100 let key = UnparsedPublicKey::new(&signature::ED25519, public_key);
101 key.verify(message, signature)
102 .map_err(|_| WebAuthnError::SignatureVerificationFailed)
103}
104
105pub fn verify_rs256(public_key_der: &[u8], message: &[u8], signature: &[u8]) -> Result<()> {
118 let key = UnparsedPublicKey::new(&signature::RSA_PKCS1_2048_8192_SHA256, public_key_der);
119 key.verify(message, signature)
120 .map_err(|_| WebAuthnError::SignatureVerificationFailed)
121}
122
123pub fn generate_challenge() -> Result<Challenge> {
127 Challenge::new()
128}
129
130#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
139 fn sha256_known_answer_empty_input() {
140 let digest = sha256(b"");
142 let expected = hex_to_bytes(
143 "e3b0c44298fc1c149afbf4c8996fb924\
144 27ae41e4649b934ca495991b7852b855",
145 );
146 assert_eq!(digest, expected.as_slice());
147 }
148
149 #[test]
150 fn sha256_returns_32_bytes() {
151 assert_eq!(sha256(b"anything").len(), 32);
152 }
153
154 #[test]
155 fn sha256_is_deterministic() {
156 assert_eq!(sha256(b"abc"), sha256(b"abc"));
157 }
158
159 #[test]
160 fn sha256_different_inputs_differ() {
161 assert_ne!(sha256(b"abc"), sha256(b"abd"));
162 assert_ne!(sha256(b"abc"), sha256(b""));
163 }
164
165 #[test]
168 fn random_bytes_zero_len_returns_empty() {
169 let result = random_bytes(0).expect("test setup");
170 assert!(result.is_empty());
171 }
172
173 #[test]
174 fn random_bytes_returns_exact_len() {
175 let result = random_bytes(32).expect("test setup");
176 assert_eq!(result.len(), 32);
177 }
178
179 #[test]
180 fn random_bytes_two_calls_differ() {
181 let a = random_bytes(32).expect("test setup");
182 let b = random_bytes(32).expect("test setup");
183 assert_ne!(a, b, "two random 32-byte draws should not match");
184 }
185
186 #[test]
189 fn verify_es256_rejects_key_missing_prefix() {
190 let key_64 = vec![0x01u8; 64];
192 let err = verify_es256(&key_64, b"msg", b"sig").expect_err("expected error");
193 assert!(matches!(err, WebAuthnError::SignatureVerificationFailed));
194 }
195
196 #[test]
197 fn verify_es256_rejects_empty_key() {
198 let err = verify_es256(&[], b"msg", b"sig").expect_err("expected error");
199 assert!(matches!(err, WebAuthnError::SignatureVerificationFailed));
200 }
201
202 #[test]
203 fn verify_es256_rejects_empty_signature() {
204 let key = vec![0x04u8; 65];
205 let err = verify_es256(&key, b"hello", &[]).expect_err("expected error");
206 assert!(matches!(err, WebAuthnError::SignatureVerificationFailed));
207 }
208
209 #[test]
210 fn verify_es256_rejects_wrong_signature() {
211 use ring::rand::SystemRandom;
212 use ring::signature::{EcdsaKeyPair, KeyPair, ECDSA_P256_SHA256_ASN1_SIGNING};
213
214 let rng = SystemRandom::new();
215 let pkcs8 = EcdsaKeyPair::generate_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING, &rng)
216 .expect("test setup");
217 let kp = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING, pkcs8.as_ref(), &rng)
218 .expect("test setup");
219 let pk = kp.public_key().as_ref();
220
221 let sig = kp.sign(&rng, b"message A").expect("test setup");
223 let err = verify_es256(pk, b"message B", sig.as_ref()).expect_err("expected error");
224 assert!(matches!(err, WebAuthnError::SignatureVerificationFailed));
225 }
226
227 #[test]
228 fn verify_es256_rejects_garbage_der_signature() {
229 use ring::rand::SystemRandom;
230 use ring::signature::{EcdsaKeyPair, KeyPair, ECDSA_P256_SHA256_ASN1_SIGNING};
231
232 let rng = SystemRandom::new();
233 let pkcs8 = EcdsaKeyPair::generate_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING, &rng)
234 .expect("test setup");
235 let kp = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING, pkcs8.as_ref(), &rng)
236 .expect("test setup");
237 let pk = kp.public_key().as_ref();
238
239 let err =
240 verify_es256(pk, b"hello", &[0xDE, 0xAD, 0xBE, 0xEF]).expect_err("expected error");
241 assert!(matches!(err, WebAuthnError::SignatureVerificationFailed));
242 }
243
244 #[test]
247 fn verify_eddsa_accepts_valid_signature() {
248 use ring::signature::{Ed25519KeyPair, KeyPair};
249
250 let rng = SystemRandom::new();
251 let pkcs8 = Ed25519KeyPair::generate_pkcs8(&rng).expect("test setup");
252 let kp = Ed25519KeyPair::from_pkcs8(pkcs8.as_ref()).expect("test setup");
253 let pk = kp.public_key().as_ref();
254
255 let msg = b"test message for EdDSA verification";
256 let sig = kp.sign(msg);
257 verify_eddsa(pk, msg, sig.as_ref()).expect("valid EdDSA signature should verify");
258 }
259
260 #[test]
261 fn verify_eddsa_rejects_wrong_message() {
262 use ring::signature::{Ed25519KeyPair, KeyPair};
263
264 let rng = SystemRandom::new();
265 let pkcs8 = Ed25519KeyPair::generate_pkcs8(&rng).expect("test setup");
266 let kp = Ed25519KeyPair::from_pkcs8(pkcs8.as_ref()).expect("test setup");
267 let pk = kp.public_key().as_ref();
268
269 let sig = kp.sign(b"message A");
270 let err = verify_eddsa(pk, b"message B", sig.as_ref()).expect_err("expected error");
271 assert!(matches!(err, WebAuthnError::SignatureVerificationFailed));
272 }
273
274 #[test]
275 fn verify_eddsa_rejects_empty_key() {
276 let err = verify_eddsa(&[], b"msg", &[0u8; 64]).expect_err("expected error");
277 assert!(matches!(err, WebAuthnError::SignatureVerificationFailed));
278 }
279
280 #[test]
281 fn verify_eddsa_rejects_tampered_signature() {
282 use ring::signature::{Ed25519KeyPair, KeyPair};
283
284 let rng = SystemRandom::new();
285 let pkcs8 = Ed25519KeyPair::generate_pkcs8(&rng).expect("test setup");
286 let kp = Ed25519KeyPair::from_pkcs8(pkcs8.as_ref()).expect("test setup");
287 let pk = kp.public_key().as_ref();
288
289 let msg = b"test message";
290 let sig = kp.sign(msg);
291 let mut sig_bytes = sig.as_ref().to_vec();
292 sig_bytes[10] ^= 0xFF;
293 let err = verify_eddsa(pk, msg, &sig_bytes).expect_err("expected error");
294 assert!(matches!(err, WebAuthnError::SignatureVerificationFailed));
295 }
296
297 const TEST_RSA_PKCS8_DER: &[u8] = &[
302 0x30, 0x82, 0x04, 0xbc, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
303 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x04, 0xa6, 0x30, 0x82, 0x04, 0xa2,
304 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb7, 0xe0, 0x0f, 0xc9, 0xdb, 0xfa, 0xce,
305 0x64, 0xa6, 0xe2, 0xb7, 0xfb, 0xa2, 0x1c, 0x09, 0x14, 0xfb, 0xd6, 0x26, 0xe5, 0x17, 0xcc,
306 0xf6, 0x6b, 0xf5, 0x8e, 0xbb, 0x69, 0x07, 0x50, 0xc0, 0xbb, 0x4c, 0xe7, 0x6e, 0xd8, 0xa4,
307 0x6a, 0x69, 0x29, 0xfc, 0xc9, 0x52, 0x0c, 0xdb, 0x04, 0xec, 0xa2, 0xef, 0x27, 0x7d, 0x8f,
308 0xfa, 0x9d, 0xaa, 0x10, 0x59, 0x54, 0x7b, 0x42, 0x78, 0xdb, 0xae, 0xd4, 0x24, 0x0a, 0xd4,
309 0x06, 0x69, 0xb0, 0xe2, 0xa5, 0x68, 0xca, 0x2d, 0x41, 0x34, 0xb0, 0x64, 0xaf, 0x61, 0x13,
310 0xc9, 0x32, 0xfc, 0x93, 0x56, 0x4f, 0x82, 0x7b, 0xea, 0xff, 0x20, 0xe5, 0x1c, 0x56, 0xb6,
311 0xe0, 0xf4, 0xaa, 0x6a, 0x20, 0xd2, 0x1c, 0x46, 0x71, 0xe6, 0x05, 0x9a, 0x96, 0x99, 0xad,
312 0x5a, 0x6f, 0x78, 0xfd, 0xa7, 0x06, 0xf8, 0xfd, 0x2d, 0xea, 0x91, 0xf2, 0x9e, 0xac, 0xc0,
313 0x43, 0x45, 0x2d, 0x79, 0xb0, 0xf2, 0x24, 0x5a, 0x8c, 0x91, 0xe6, 0xc6, 0xc2, 0xfe, 0x50,
314 0x8d, 0x64, 0x82, 0x06, 0x77, 0x6e, 0xef, 0x7d, 0x61, 0x6e, 0x80, 0xd1, 0x87, 0xfb, 0x25,
315 0x35, 0xc6, 0xe8, 0x3a, 0xec, 0x38, 0xce, 0x45, 0x70, 0xf8, 0x56, 0xc7, 0x6e, 0xb7, 0x20,
316 0xdb, 0x72, 0x51, 0x82, 0xd0, 0xd2, 0xd2, 0xbd, 0xc9, 0xe0, 0x3c, 0xef, 0xbb, 0x93, 0x70,
317 0xdd, 0xfb, 0xd4, 0xda, 0x6e, 0xf6, 0x73, 0xb3, 0x79, 0xf7, 0xe8, 0x49, 0x72, 0x22, 0x44,
318 0x92, 0xd8, 0xe4, 0x3e, 0x04, 0xbc, 0x83, 0xb2, 0x6c, 0x59, 0x4a, 0x79, 0x11, 0x1e, 0x33,
319 0xd6, 0x4b, 0xe6, 0x24, 0x7b, 0xdf, 0x93, 0x18, 0x1d, 0xb3, 0x27, 0x0b, 0x73, 0xbb, 0xff,
320 0xa8, 0xe2, 0x13, 0xa0, 0x8f, 0x39, 0x2c, 0x21, 0xc1, 0x5e, 0xf1, 0xa8, 0x82, 0x25, 0x28,
321 0x19, 0xae, 0xc9, 0x3f, 0x09, 0x2d, 0x8c, 0x81, 0xa5, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
322 0x82, 0x01, 0x00, 0x1b, 0x31, 0xd5, 0x8b, 0xf4, 0x8f, 0xbb, 0xca, 0x49, 0x9f, 0x62, 0xf8,
323 0x21, 0xb1, 0xf5, 0x4a, 0xe7, 0xf3, 0x34, 0x95, 0xf1, 0xe6, 0xf3, 0xb4, 0x24, 0x61, 0x7b,
324 0x88, 0xcd, 0x56, 0xed, 0x66, 0x56, 0x39, 0xad, 0x5c, 0x77, 0xb6, 0xb0, 0x3e, 0x90, 0x3f,
325 0x43, 0x36, 0x19, 0x07, 0x79, 0xab, 0x20, 0x65, 0x4e, 0x0e, 0x07, 0x12, 0x1d, 0xf6, 0xa4,
326 0x8b, 0x98, 0xde, 0x4c, 0x2b, 0x2b, 0x88, 0x7f, 0x1b, 0x25, 0xe0, 0x1b, 0xee, 0x18, 0x1b,
327 0x40, 0x2c, 0x14, 0xb4, 0xdd, 0xe2, 0xcf, 0xc5, 0x5b, 0x7d, 0x76, 0x66, 0xa6, 0xd1, 0xf0,
328 0xb4, 0x3a, 0x37, 0x73, 0x1a, 0x50, 0x26, 0x6a, 0x82, 0x4d, 0xb2, 0x68, 0x25, 0x33, 0x24,
329 0x8f, 0x06, 0xb5, 0x09, 0x7f, 0xec, 0x68, 0xc0, 0x68, 0xd2, 0xa9, 0x7b, 0x2e, 0xa1, 0x0f,
330 0x3c, 0xba, 0x03, 0x11, 0xf1, 0x2d, 0x2c, 0x3d, 0xb9, 0x0d, 0x87, 0x34, 0x84, 0x62, 0x65,
331 0xe4, 0xe3, 0x32, 0x0d, 0xbd, 0x90, 0xad, 0x2c, 0x57, 0x74, 0x39, 0xd8, 0x25, 0x42, 0x46,
332 0x3c, 0xc9, 0x0b, 0x26, 0xc9, 0x99, 0x75, 0xc2, 0x6e, 0x56, 0x82, 0x41, 0xfb, 0xeb, 0xd9,
333 0x80, 0x3d, 0x6e, 0x0e, 0x8b, 0x0b, 0xa3, 0xaf, 0x6c, 0x1d, 0x39, 0x79, 0xf8, 0xa5, 0xae,
334 0x6c, 0x9e, 0xdf, 0x1b, 0xd3, 0x7a, 0x16, 0x35, 0xf4, 0x14, 0x6d, 0x1e, 0x4d, 0x7b, 0x6f,
335 0xbb, 0xfb, 0xe9, 0x2c, 0x9e, 0xad, 0xf9, 0x0a, 0x53, 0x29, 0x2a, 0xd8, 0xff, 0x9d, 0xb3,
336 0xac, 0x9e, 0x2d, 0x86, 0x77, 0x67, 0x4c, 0xa8, 0x74, 0xe3, 0xb2, 0x94, 0xf8, 0xfb, 0xe8,
337 0x33, 0xf2, 0x3c, 0x5d, 0x57, 0x79, 0x89, 0x87, 0xd0, 0x9b, 0x52, 0x4b, 0xc9, 0xbc, 0x48,
338 0x68, 0xbe, 0x85, 0x1f, 0x25, 0x61, 0x44, 0x7e, 0xa6, 0x40, 0x54, 0x70, 0xaf, 0x65, 0x11,
339 0x3a, 0x58, 0xd1, 0x81, 0x02, 0x81, 0x81, 0x00, 0xfd, 0x9e, 0x1a, 0x50, 0x85, 0xd7, 0xa8,
340 0x9c, 0x36, 0x6a, 0x8f, 0x1c, 0x9f, 0x2d, 0x6d, 0xdf, 0xb4, 0xe6, 0xc4, 0xd2, 0xcf, 0x99,
341 0x6f, 0x5d, 0xc5, 0x71, 0x01, 0xe6, 0x1d, 0x5f, 0xd5, 0x6d, 0x52, 0x86, 0x7c, 0xb6, 0xc2,
342 0xc2, 0x1b, 0xcd, 0x4a, 0xd1, 0x0c, 0x79, 0x15, 0x2d, 0x4e, 0x93, 0xe2, 0xc0, 0x7d, 0xe6,
343 0xa4, 0xc4, 0x71, 0x41, 0xa3, 0x49, 0x93, 0x2c, 0xf9, 0xe7, 0xc8, 0xe6, 0x79, 0x52, 0x19,
344 0xf7, 0xe0, 0x2a, 0xd9, 0xc0, 0x0f, 0x3e, 0xad, 0xdf, 0xf4, 0x96, 0xbd, 0xb9, 0x54, 0x5a,
345 0x5a, 0xe8, 0x70, 0x2d, 0xad, 0xf0, 0x5d, 0x63, 0x80, 0xb4, 0x8f, 0x3c, 0x1b, 0xad, 0xd9,
346 0x2b, 0x63, 0x16, 0x80, 0xe1, 0x52, 0x8d, 0xd7, 0x8e, 0x2c, 0x37, 0x99, 0x6e, 0x1e, 0x8e,
347 0x64, 0xcf, 0x0e, 0x79, 0x32, 0xdd, 0x1a, 0xc1, 0x43, 0x7e, 0x4c, 0x0c, 0xab, 0x29, 0x5b,
348 0x25, 0x02, 0x81, 0x81, 0x00, 0xb9, 0x9a, 0x3e, 0x3e, 0x20, 0x74, 0xe5, 0x19, 0x82, 0x8b,
349 0x1d, 0x20, 0x2b, 0xe5, 0xa9, 0x8c, 0x71, 0xd5, 0xa8, 0xe6, 0xed, 0x7e, 0x0a, 0x91, 0x8f,
350 0x87, 0xf5, 0x80, 0xc8, 0xd4, 0x1d, 0x4e, 0x25, 0x0b, 0xfe, 0x22, 0xb6, 0xdd, 0xc3, 0xfd,
351 0x46, 0x78, 0x7f, 0x6c, 0x27, 0x9d, 0xfe, 0xbf, 0xea, 0x66, 0x27, 0x57, 0x2e, 0xc2, 0x7c,
352 0xca, 0x63, 0x1a, 0xc8, 0xb8, 0xda, 0x2f, 0xf3, 0x03, 0xfc, 0x03, 0xcb, 0xf4, 0x0c, 0x8a,
353 0x00, 0x2f, 0x5d, 0x78, 0x7a, 0xff, 0x9e, 0x84, 0xc5, 0x0b, 0xd6, 0xae, 0xf6, 0xf8, 0xc7,
354 0x6f, 0x5f, 0x77, 0x8c, 0x4f, 0xe6, 0x4f, 0x58, 0x67, 0xbf, 0xde, 0x8e, 0x39, 0xa5, 0xd8,
355 0x82, 0x59, 0x40, 0xf8, 0xd4, 0x46, 0xbe, 0x5b, 0xaa, 0x2b, 0x74, 0xf4, 0x29, 0x72, 0xfd,
356 0x2b, 0xa0, 0xa2, 0xb4, 0x1a, 0x3d, 0x4d, 0x2f, 0xfe, 0x61, 0x55, 0x04, 0x81, 0x02, 0x81,
357 0x80, 0x58, 0x92, 0xa6, 0xce, 0x08, 0x70, 0x50, 0xca, 0x7d, 0x96, 0xa9, 0x74, 0x6d, 0x83,
358 0x08, 0x24, 0x60, 0xa1, 0x57, 0x8b, 0xe8, 0x44, 0xc5, 0xc8, 0x11, 0xf4, 0x6d, 0x9d, 0x58,
359 0x14, 0xe8, 0x0c, 0xce, 0x0d, 0x79, 0xf0, 0xba, 0x03, 0xe0, 0x81, 0xc9, 0xe7, 0x48, 0x5b,
360 0xe1, 0x31, 0x79, 0x87, 0xdc, 0x61, 0x2d, 0x97, 0x27, 0x64, 0x13, 0xc9, 0xc0, 0xa5, 0x29,
361 0x69, 0x43, 0xbd, 0xd7, 0x43, 0xe6, 0x8a, 0xed, 0xd6, 0xcb, 0xcb, 0x2b, 0x51, 0x10, 0x01,
362 0xeb, 0xe7, 0x93, 0x1c, 0x32, 0x16, 0x4f, 0x87, 0x5e, 0xc8, 0x5e, 0xa5, 0x15, 0x62, 0x24,
363 0xbb, 0x63, 0x6f, 0xab, 0xb6, 0x6a, 0x54, 0x44, 0xcc, 0x0a, 0x47, 0x09, 0xab, 0xa7, 0x91,
364 0x31, 0xfe, 0xcd, 0x22, 0x7d, 0xcb, 0x1f, 0x90, 0xcb, 0x54, 0x24, 0xd1, 0xdf, 0x19, 0xa9,
365 0x06, 0x65, 0xf3, 0xed, 0xcb, 0x5e, 0xdb, 0x8a, 0xa1, 0x02, 0x81, 0x80, 0x0b, 0x53, 0x45,
366 0x1f, 0x07, 0x5d, 0xfa, 0xa8, 0xce, 0xd5, 0x6c, 0x46, 0x8d, 0x47, 0x2b, 0x4c, 0x5d, 0x99,
367 0xda, 0xff, 0x94, 0x58, 0x4f, 0x8e, 0xc8, 0x42, 0x54, 0x91, 0xb2, 0x2f, 0x77, 0x46, 0x50,
368 0x6e, 0x65, 0xe8, 0x7a, 0x5e, 0x17, 0xda, 0x79, 0x95, 0x5a, 0xb9, 0x1f, 0xc5, 0xbd, 0x48,
369 0xba, 0xa5, 0xd7, 0x1a, 0xb3, 0xc8, 0xbc, 0x52, 0xa1, 0x2f, 0x7e, 0x36, 0x01, 0x62, 0x51,
370 0xa2, 0xd9, 0x9a, 0xe5, 0xb4, 0x13, 0x9b, 0xcc, 0x1d, 0x17, 0xc8, 0x05, 0x41, 0x59, 0xcb,
371 0xe2, 0x36, 0x31, 0xb8, 0x65, 0x6b, 0x92, 0xc7, 0xd1, 0xfc, 0x7a, 0x7c, 0x59, 0xa2, 0x57,
372 0xd3, 0xa4, 0xda, 0x90, 0xb5, 0x25, 0xd0, 0x8b, 0x4b, 0xa4, 0xf2, 0x4a, 0x09, 0xb3, 0x0d,
373 0xe6, 0xd9, 0x55, 0xfe, 0x9c, 0x14, 0xdf, 0x2b, 0xed, 0x56, 0x60, 0x45, 0x05, 0x9e, 0x93,
374 0x22, 0x23, 0x90, 0x4b, 0x81, 0x02, 0x81, 0x80, 0x71, 0x49, 0x07, 0xff, 0x86, 0xc5, 0xf7,
375 0xe4, 0xbd, 0xa8, 0xbc, 0xa4, 0xbe, 0x1f, 0x8e, 0x73, 0xb0, 0xea, 0x71, 0x85, 0x61, 0xb1,
376 0x8d, 0x30, 0xe3, 0xac, 0x67, 0xfc, 0x2c, 0x5a, 0x36, 0xcc, 0x66, 0xe7, 0x2f, 0x32, 0x97,
377 0x54, 0x97, 0xe9, 0xd6, 0x5d, 0xd9, 0xe5, 0xbb, 0x1a, 0x06, 0x15, 0x95, 0x2d, 0x8e, 0xca,
378 0x27, 0x8e, 0x2e, 0x39, 0xab, 0x45, 0x2d, 0x94, 0x26, 0x93, 0xd0, 0x7b, 0xda, 0x62, 0x02,
379 0xba, 0xe6, 0xd9, 0x87, 0xad, 0xf7, 0x2a, 0x33, 0x1d, 0x5a, 0xd9, 0xa8, 0xf3, 0x38, 0x0e,
380 0x0f, 0xd1, 0x24, 0x25, 0x69, 0x2a, 0x2c, 0x99, 0xf7, 0xea, 0x0d, 0x3b, 0x51, 0x8b, 0x2a,
381 0x72, 0xb0, 0x51, 0xd3, 0x07, 0x63, 0x9e, 0x9d, 0x15, 0xe6, 0xa8, 0xf5, 0xce, 0x69, 0x74,
382 0x53, 0xd3, 0xb1, 0x26, 0x77, 0xfa, 0x0e, 0x8f, 0xdd, 0x1f, 0x0e, 0x76, 0x51, 0x56, 0x85,
383 0xb7,
384 ];
385
386 const TEST_RSA_N: &[u8] = &[
387 0xb7, 0xe0, 0x0f, 0xc9, 0xdb, 0xfa, 0xce, 0x64, 0xa6, 0xe2, 0xb7, 0xfb, 0xa2, 0x1c, 0x09,
388 0x14, 0xfb, 0xd6, 0x26, 0xe5, 0x17, 0xcc, 0xf6, 0x6b, 0xf5, 0x8e, 0xbb, 0x69, 0x07, 0x50,
389 0xc0, 0xbb, 0x4c, 0xe7, 0x6e, 0xd8, 0xa4, 0x6a, 0x69, 0x29, 0xfc, 0xc9, 0x52, 0x0c, 0xdb,
390 0x04, 0xec, 0xa2, 0xef, 0x27, 0x7d, 0x8f, 0xfa, 0x9d, 0xaa, 0x10, 0x59, 0x54, 0x7b, 0x42,
391 0x78, 0xdb, 0xae, 0xd4, 0x24, 0x0a, 0xd4, 0x06, 0x69, 0xb0, 0xe2, 0xa5, 0x68, 0xca, 0x2d,
392 0x41, 0x34, 0xb0, 0x64, 0xaf, 0x61, 0x13, 0xc9, 0x32, 0xfc, 0x93, 0x56, 0x4f, 0x82, 0x7b,
393 0xea, 0xff, 0x20, 0xe5, 0x1c, 0x56, 0xb6, 0xe0, 0xf4, 0xaa, 0x6a, 0x20, 0xd2, 0x1c, 0x46,
394 0x71, 0xe6, 0x05, 0x9a, 0x96, 0x99, 0xad, 0x5a, 0x6f, 0x78, 0xfd, 0xa7, 0x06, 0xf8, 0xfd,
395 0x2d, 0xea, 0x91, 0xf2, 0x9e, 0xac, 0xc0, 0x43, 0x45, 0x2d, 0x79, 0xb0, 0xf2, 0x24, 0x5a,
396 0x8c, 0x91, 0xe6, 0xc6, 0xc2, 0xfe, 0x50, 0x8d, 0x64, 0x82, 0x06, 0x77, 0x6e, 0xef, 0x7d,
397 0x61, 0x6e, 0x80, 0xd1, 0x87, 0xfb, 0x25, 0x35, 0xc6, 0xe8, 0x3a, 0xec, 0x38, 0xce, 0x45,
398 0x70, 0xf8, 0x56, 0xc7, 0x6e, 0xb7, 0x20, 0xdb, 0x72, 0x51, 0x82, 0xd0, 0xd2, 0xd2, 0xbd,
399 0xc9, 0xe0, 0x3c, 0xef, 0xbb, 0x93, 0x70, 0xdd, 0xfb, 0xd4, 0xda, 0x6e, 0xf6, 0x73, 0xb3,
400 0x79, 0xf7, 0xe8, 0x49, 0x72, 0x22, 0x44, 0x92, 0xd8, 0xe4, 0x3e, 0x04, 0xbc, 0x83, 0xb2,
401 0x6c, 0x59, 0x4a, 0x79, 0x11, 0x1e, 0x33, 0xd6, 0x4b, 0xe6, 0x24, 0x7b, 0xdf, 0x93, 0x18,
402 0x1d, 0xb3, 0x27, 0x0b, 0x73, 0xbb, 0xff, 0xa8, 0xe2, 0x13, 0xa0, 0x8f, 0x39, 0x2c, 0x21,
403 0xc1, 0x5e, 0xf1, 0xa8, 0x82, 0x25, 0x28, 0x19, 0xae, 0xc9, 0x3f, 0x09, 0x2d, 0x8c, 0x81,
404 0xa5,
405 ];
406
407 const TEST_RSA_E: &[u8] = &[0x01, 0x00, 0x01]; fn rsa_sign(message: &[u8]) -> Vec<u8> {
410 use ring::rand::SystemRandom;
411 use ring::rsa::KeyPair as RsaKeyPair;
412 use ring::signature::RSA_PKCS1_SHA256;
413
414 let rng = SystemRandom::new();
415 let key_pair = RsaKeyPair::from_pkcs8(TEST_RSA_PKCS8_DER).expect("test setup");
416 let mut sig = vec![0u8; key_pair.public().modulus_len()];
417 key_pair
418 .sign(&RSA_PKCS1_SHA256, &rng, message, &mut sig)
419 .expect("test setup");
420 sig
421 }
422
423 fn rsa_public_key_der() -> Vec<u8> {
424 crate::der::rsa_components_to_der(TEST_RSA_N, TEST_RSA_E).expect("test setup")
425 }
426
427 #[test]
428 fn verify_rs256_accepts_valid_signature() {
429 let message = b"test message for RS256 verification";
430 let sig = rsa_sign(message);
431 let der = rsa_public_key_der();
432 verify_rs256(&der, message, &sig).expect("valid RS256 signature should verify");
433 }
434
435 #[test]
436 fn verify_rs256_rejects_tampered_signature() {
437 let message = b"test message";
438 let mut sig = rsa_sign(message);
439 sig[10] ^= 0xFF;
440 let der = rsa_public_key_der();
441 let err = verify_rs256(&der, message, &sig).expect_err("expected error");
442 assert!(matches!(err, WebAuthnError::SignatureVerificationFailed));
443 }
444
445 #[test]
446 fn verify_rs256_rejects_wrong_message() {
447 let sig = rsa_sign(b"message A");
448 let der = rsa_public_key_der();
449 let err = verify_rs256(&der, b"message B", &sig).expect_err("expected error");
450 assert!(matches!(err, WebAuthnError::SignatureVerificationFailed));
451 }
452
453 #[test]
454 fn verify_rs256_rejects_empty_public_key() {
455 let err = verify_rs256(&[], b"msg", &[0u8; 256]).expect_err("expected error");
456 assert!(matches!(err, WebAuthnError::SignatureVerificationFailed));
457 }
458
459 #[test]
460 fn verify_rs256_rejects_garbage_signature() {
461 let der = rsa_public_key_der();
462 let err =
463 verify_rs256(&der, b"hello", &[0xDE, 0xAD, 0xBE, 0xEF]).expect_err("expected error");
464 assert!(matches!(err, WebAuthnError::SignatureVerificationFailed));
465 }
466
467 fn hex_to_bytes(s: &str) -> Vec<u8> {
470 (0..s.len())
471 .step_by(2)
472 .map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("test setup"))
473 .collect()
474 }
475}