diff --git a/apps/desktop/desktop_native/win_webauthn/src/plugin/crypto.rs b/apps/desktop/desktop_native/win_webauthn/src/plugin/crypto.rs index 727e8435ac5..51afbfda550 100644 --- a/apps/desktop/desktop_native/win_webauthn/src/plugin/crypto.rs +++ b/apps/desktop/desktop_native/win_webauthn/src/plugin/crypto.rs @@ -8,13 +8,13 @@ use windows::{ core::{GUID, HRESULT}, Win32::Security::Cryptography::{ BCryptCreateHash, BCryptDestroyHash, BCryptDestroyKey, BCryptFinishHash, BCryptGetProperty, - BCryptHashData, BCryptImportKeyPair, BCryptVerifySignature, - BCRYPT_ECDSA_P256_ALG_HANDLE, BCRYPT_ECDSA_P384_ALG_HANDLE, BCRYPT_ECDSA_P521_ALG_HANDLE, - BCRYPT_ECDSA_PUBLIC_P256_MAGIC, BCRYPT_ECDSA_PUBLIC_P384_MAGIC, - BCRYPT_ECDSA_PUBLIC_P521_MAGIC, BCRYPT_FLAGS, BCRYPT_HASH_HANDLE, BCRYPT_HASH_LENGTH, - BCRYPT_KEY_BLOB, BCRYPT_KEY_HANDLE, BCRYPT_OBJECT_LENGTH, BCRYPT_PAD_PKCS1, - BCRYPT_PKCS1_PADDING_INFO, BCRYPT_PUBLIC_KEY_BLOB, BCRYPT_RSA_ALG_HANDLE, - BCRYPT_RSAPUBLIC_MAGIC, BCRYPT_SHA256_ALGORITHM, BCRYPT_SHA256_ALG_HANDLE, + BCryptHashData, BCryptImportKeyPair, BCryptVerifySignature, BCRYPT_ECDSA_P256_ALG_HANDLE, + BCRYPT_ECDSA_P384_ALG_HANDLE, BCRYPT_ECDSA_P521_ALG_HANDLE, BCRYPT_ECDSA_PUBLIC_P256_MAGIC, + BCRYPT_ECDSA_PUBLIC_P384_MAGIC, BCRYPT_ECDSA_PUBLIC_P521_MAGIC, BCRYPT_FLAGS, + BCRYPT_HASH_HANDLE, BCRYPT_HASH_LENGTH, BCRYPT_KEY_BLOB, BCRYPT_KEY_HANDLE, + BCRYPT_OBJECT_LENGTH, BCRYPT_PAD_PKCS1, BCRYPT_PKCS1_PADDING_INFO, BCRYPT_PUBLIC_KEY_BLOB, + BCRYPT_RSAPUBLIC_MAGIC, BCRYPT_RSA_ALG_HANDLE, BCRYPT_SHA256_ALGORITHM, + BCRYPT_SHA256_ALG_HANDLE, }, }; @@ -150,7 +150,8 @@ fn verify_signature( // RSA, P-256, P-384 and P-512. let key_blob = public_key.pbPublicKey.as_ref(); tracing::debug!(" got key magic: {}", key_blob.Magic); - let (alg_handle, padding_info, bcrypt_flags) = if key_blob.Magic == BCRYPT_RSAPUBLIC_MAGIC.0 { + let (alg_handle, padding_info, bcrypt_flags) = if key_blob.Magic == BCRYPT_RSAPUBLIC_MAGIC.0 + { tracing::debug!("Detected RSA key, adding PKCS1 padding"); let padding_info = BCRYPT_PKCS1_PADDING_INFO { pszAlgId: BCRYPT_SHA256_ALGORITHM, @@ -168,7 +169,9 @@ fn verify_signature( } else { tracing::error!("Unsupported key type: magic={}", key_blob.Magic); // NTE_BAD_ALGID - return Err(windows::core::Error::from_hresult(HRESULT(0x80090008u32 as i32))); + return Err(windows::core::Error::from_hresult(HRESULT( + 0x80090008u32 as i32, + ))); }; tracing::debug!("Getting key handle"); @@ -367,8 +370,8 @@ mod tests { use std::ptr::NonNull; use windows::Win32::Security::Cryptography::{ - BCRYPT_ECCKEY_BLOB, BCRYPT_ECDSA_PUBLIC_P384_MAGIC, BCRYPT_RSAKEY_BLOB, - BCRYPT_RSAPUBLIC_MAGIC, + BCRYPT_ECCKEY_BLOB, BCRYPT_ECDSA_PUBLIC_P256_MAGIC, BCRYPT_ECDSA_PUBLIC_P384_MAGIC, + BCRYPT_RSAKEY_BLOB, BCRYPT_RSAPUBLIC_MAGIC, }; use crate::plugin::crypto::{verify_signature, VerifyingKey}; @@ -572,4 +575,71 @@ mod tests { ]; verify_signature(&verify_key, digest, signature).expect("a signature to verify properly"); } + + #[test] + fn test_p256_signature_verifies_properly() { + // SHA-256 hash of "abc" + let digest = &[ + 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, + 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, + 0xf2, 0x00, 0x15, 0xad, + ]; + /* + Test private key used to create expected signature, generated by OpenSSL + + -----BEGIN PRIVATE KEY----- + MIIBeQIBADCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAAB + AAAAAAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA + ///////////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMV + AMSdNgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg + 9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8A + AAAA//////////+85vqtpxeehPO5ysL8YyVRAgEBBG0wawIBAQQg/grBMmNCqKg1 + 8kAjQFqMsmuFf/l5MO/GP3zEEqzcR4yhRANCAASk4KnUT1k3ruE4fbAQm5HQQVb4 + JEeWo53xOgSlJm2/6arp39vcqZCNYL+39JaaauWAFlm7TD2jvrQQurvYl8Sk + -----END PRIVATE KEY----- + + Signature generated with: + openssl pkeyutl -sign -inkey p256.key.pem -in hash.bin -out sig_der.bin + Converted from DER to IEEE P1363 (r || s) format. + */ + // P-256 public key X coordinate (32 bytes, big-endian) + let x: &[u8] = &[ + 0xa4, 0xe0, 0xa9, 0xd4, 0x4f, 0x59, 0x37, 0xae, 0xe1, 0x38, 0x7d, 0xb0, 0x10, 0x9b, + 0x91, 0xd0, 0x41, 0x56, 0xf8, 0x24, 0x47, 0x96, 0xa3, 0x9d, 0xf1, 0x3a, 0x04, 0xa5, + 0x26, 0x6d, 0xbf, 0xe9, + ]; + // P-256 public key Y coordinate (32 bytes, big-endian) + let y: &[u8] = &[ + 0xaa, 0xe9, 0xdf, 0xdb, 0xdc, 0xa9, 0x90, 0x8d, 0x60, 0xbf, 0xb7, 0xf4, 0x96, 0x9a, + 0x6a, 0xe5, 0x80, 0x16, 0x59, 0xbb, 0x4c, 0x3d, 0xa3, 0xbe, 0xb4, 0x10, 0xba, 0xbb, + 0xd8, 0x97, 0xc4, 0xa4, + ]; + let key_header = BCRYPT_ECCKEY_BLOB { + dwMagic: BCRYPT_ECDSA_PUBLIC_P256_MAGIC, + cbKey: 32, // P-256: 256 bits / 8 = 32 bytes per coordinate + }; + let mut public_key_bytes: Vec = unsafe { + std::slice::from_raw_parts( + std::ptr::from_ref(&key_header).cast::(), + std::mem::size_of::(), + ) + } + .to_vec(); + public_key_bytes.extend_from_slice(x); + public_key_bytes.extend_from_slice(y); + println!("{:?}", public_key_bytes); + let verify_key = VerifyingKey { + cbPublicKey: public_key_bytes.len() as u32, + pbPublicKey: NonNull::new(public_key_bytes.as_mut_ptr().cast()).unwrap(), + }; + // ECDSA signature in IEEE P1363 format (r || s), each 32 bytes, big-endian + let signature: &[u8] = &[ + 0x55, 0x8d, 0x74, 0x5e, 0x35, 0x15, 0xbd, 0x56, 0x99, 0x0c, 0xf2, 0x09, 0x99, 0x00, + 0x2e, 0x92, 0x2b, 0x64, 0x3b, 0xf6, 0x07, 0x5f, 0xc4, 0xd1, 0x10, 0xbc, 0xb7, 0xf2, + 0xc4, 0x39, 0x0a, 0x84, 0x3e, 0xda, 0xc6, 0x5c, 0xc9, 0x9a, 0x7a, 0x94, 0x94, 0x08, + 0x7b, 0xac, 0xdd, 0x25, 0x08, 0x37, 0x33, 0xe4, 0xf5, 0xb6, 0xfd, 0xc2, 0x10, 0x7e, + 0xe9, 0xd0, 0xbf, 0xcd, 0x4c, 0xfe, 0xd0, 0x41, + ]; + verify_signature(&verify_key, digest, signature).expect("a signature to verify properly"); + } }