/
githubmirror
/
deno
Обзор
Документация
Войти
/
githubmirror
/
deno
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
ext/node_crypto/sign.rs
684 строки
26 KB
em
fix(ext/node): enable test-crypto.js node compat test (#33822)
09 май 2026, 10:08
Не верифицирован
09 май 2026, 10:08
d7b5c73
Код
Авторство
О чём код?
// Copyright 2018-2026 the Deno authors. MIT license. use core::ops::Add; use ecdsa::der::MaxOverhead; use ecdsa::der::MaxSize; use elliptic_curve::FieldBytesSize; use elliptic_curve::generic_array::ArrayLength; use rand::rngs::OsRng; use rsa::signature::hazmat::PrehashSigner as _; use rsa::signature::hazmat::PrehashVerifier as _; use rsa::traits::PublicKeyParts as _; use rsa::traits::SignatureScheme as _; use spki::der::Decode; use super::keys::AsymmetricPrivateKey; use super::keys::AsymmetricPublicKey; use super::keys::EcPrivateKey; use super::keys::EcPublicKey; use super::keys::KeyObjectHandle; use super::keys::RsaPssHashAlgorithm; use crate::digest::match_fixed_digest; use crate::digest::match_fixed_digest_with_oid; /// OpenSSL RSA_PKCS1_PADDING constant value. const RSA_PKCS1_PADDING: u32 = 1; /// OpenSSL RSA_PKCS1_PSS_PADDING constant value. const RSA_PKCS1_PSS_PADDING: u32 = 6; /// OpenSSL RSA_PKCS1_OAEP_PADDING constant value. const RSA_PKCS1_OAEP_PADDING: u32 = 4; fn dsa_signature<C: elliptic_curve::PrimeCurve>( encoding: u32, signature: ecdsa::Signature<C>, ) -> Result<Box<[u8]>, KeyObjectHandlePrehashedSignAndVerifyError> where MaxSize<C>: ArrayLength<u8>, <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, { match encoding { // DER 0 => Ok(signature.to_der().to_bytes().to_vec().into_boxed_slice()), // IEEE P1363 1 => Ok(signature.to_bytes().to_vec().into_boxed_slice()), _ => Err( KeyObjectHandlePrehashedSignAndVerifyError::InvalidDsaSignatureEncoding, ), } } /// Encode a DSA signature to IEEE P1363 format: r || s, each zero-padded to /// q_len bytes. Spec: https://www.w3.org/TR/WebCryptoAPI/#convert-an-ecdsa-signature fn dsa_sig_to_p1363(sig: &dsa::Signature, q_len: usize) -> Box<[u8]> { let mut result = vec![0u8; q_len * 2]; let r_bytes = sig.r().to_bytes_be(); let s_bytes = sig.s().to_bytes_be(); if r_bytes.len() <= q_len { result[q_len - r_bytes.len()..q_len].copy_from_slice(&r_bytes); } if s_bytes.len() <= q_len { result[2 * q_len - s_bytes.len()..2 * q_len].copy_from_slice(&s_bytes); } result.into_boxed_slice() } /// Decode a DSA signature from IEEE P1363 format: r || s, each of q_len bytes. /// Spec: https://www.w3.org/TR/WebCryptoAPI/#convert-an-ecdsa-signature fn dsa_sig_from_p1363(bytes: &[u8], q_len: usize) -> Option<dsa::Signature> { if bytes.len() != 2 * q_len { return None; } let r = dsa::BigUint::from_bytes_be(&bytes[..q_len]); let s = dsa::BigUint::from_bytes_be(&bytes[q_len..]); dsa::Signature::from_components(r, s).ok() } #[derive(Debug, thiserror::Error, deno_error::JsError)] #[class(type)] pub enum KeyObjectHandlePrehashedSignAndVerifyError { #[error("invalid DSA signature encoding")] InvalidDsaSignatureEncoding, #[error("key is not a private key")] KeyIsNotPrivate, #[error("digest not allowed for RSA signature: {0}")] DigestNotAllowedForRsaSignature(String), #[class(generic)] #[error("failed to sign digest with RSA")] FailedToSignDigestWithRsa, #[class(generic)] #[property("code" = "ERR_OSSL_RSA_DIGEST_TOO_BIG_FOR_RSA_KEY")] #[error("error:02000070:rsa routines::digest too big for rsa key")] DigestTooBigForRsaKey, #[error("digest not allowed for RSA-PSS signature: {0}")] DigestNotAllowedForRsaPssSignature(String), #[class(generic)] #[error("failed to sign digest with RSA-PSS")] FailedToSignDigestWithRsaPss, #[error("failed to sign digest with DSA")] FailedToSignDigestWithDsa, #[error( "rsa-pss with different mf1 hash algorithm and hash algorithm is not supported" )] RsaPssHashAlgorithmUnsupported, #[class(generic)] #[error("{actual} digest not allowed")] PrivateKeyDisallowsUsage { actual: String, expected: String }, #[class(generic)] #[error("pss saltlen too small")] PssSaltLenTooSmall, #[error("failed to sign digest")] FailedToSignDigest, #[class(generic)] #[error("operation not supported for this keytype")] #[property("code" = "ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE")] X25519KeyCannotBeUsedForSigning, #[class(generic)] #[error("Unsupported crypto operation")] #[property("code" = "ERR_CRYPTO_UNSUPPORTED_OPERATION")] Ed25519KeyCannotBeUsedForPrehashedSigning, #[class(generic)] #[error("operation not supported for this keytype")] #[property("code" = "ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE")] DhKeyCannotBeUsedForSigning, #[error("key is not a public or private key")] KeyIsNotPublicOrPrivate, #[error("Invalid DSA signature")] InvalidDsaSignature, #[class(generic)] #[error("operation not supported for this keytype")] #[property("code" = "ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE")] X25519KeyCannotBeUsedForVerification, #[class(generic)] #[error("Unsupported crypto operation")] #[property("code" = "ERR_CRYPTO_UNSUPPORTED_OPERATION")] Ed25519KeyCannotBeUsedForPrehashedVerification, #[class(generic)] #[error("operation not supported for this keytype")] #[property("code" = "ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE")] DhKeyCannotBeUsedForVerification, #[class(generic)] #[error( "error:1C8000A5:Provider routines::illegal or unsupported padding mode" )] #[property("code" = "ERR_OSSL_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE")] IllegalOrUnsupportedPaddingMode, } /// Constructs a PSS scheme for the given digest type and optional salt length. /// Used by both sign and verify operations on RSA keys with PSS padding. /// /// When `key_size_bits` is provided and `pss_salt_length` is `None`, /// the default salt length is max (key_bytes - hash_len - 2), matching /// Node.js's documented default of `RSA_PSS_SALTLEN_MAX_SIGN`. /// When `key_size_bits` is `None` (verify path), the default salt length /// is the digest length. /// OpenSSL RSA_PSS_SALTLEN_DIGEST: use digest length as salt length. const RSA_PSS_SALTLEN_DIGEST: i32 = -1; /// OpenSSL RSA_PSS_SALTLEN_MAX_SIGN: use maximum possible salt length. const RSA_PSS_SALTLEN_MAX_SIGN: i32 = -2; /// Resolves the effective salt length for PSS operations. /// /// Handles Node.js special constants: /// - `-1` (RSA_PSS_SALTLEN_DIGEST): use the digest output size /// - `-2` (RSA_PSS_SALTLEN_MAX_SIGN / RSA_PSS_SALTLEN_AUTO): use maximum /// possible salt length (key_bytes - hash_len - 2) /// - `None`: defaults to max salt when `key_size_bits` is provided (sign), /// or digest length otherwise (verify) /// - Positive values: use as-is fn resolve_pss_salt_length<D: digest::Digest>( pss_salt_length: Option<i32>, key_size_bits: Option<usize>, ) -> usize { match pss_salt_length { Some(RSA_PSS_SALTLEN_DIGEST) => <D as digest::Digest>::output_size(), Some(RSA_PSS_SALTLEN_MAX_SIGN) => { let hash_len = <D as digest::Digest>::output_size(); if let Some(key_bits) = key_size_bits { let key_bytes = key_bits / 8; key_bytes.saturating_sub(hash_len + 2) } else { hash_len } } Some(len) if len >= 0 => len as usize, Some(_) => <D as digest::Digest>::output_size(), // Unknown negative, fallback to digest length None => { if let Some(key_bits) = key_size_bits { // Default to max salt length for signing (RSA_PSS_SALTLEN_MAX_SIGN) let key_bytes = key_bits / 8; let hash_len = <D as digest::Digest>::output_size(); key_bytes.saturating_sub(hash_len + 2) } else { <D as digest::Digest>::output_size() } } } } fn new_pss_scheme( digest_type: &str, pss_salt_length: Option<i32>, key_size_bits: Option<usize>, ) -> Result<rsa::pss::Pss, KeyObjectHandlePrehashedSignAndVerifyError> { let pss = match_fixed_digest_with_oid!( digest_type, fn <D>(algorithm: Option<RsaPssHashAlgorithm>) { let _: Option<RsaPssHashAlgorithm> = algorithm; let salt_len = resolve_pss_salt_length::<D>(pss_salt_length, key_size_bits); rsa::pss::Pss::new_with_salt::<D>(salt_len) }, _ => { return Err(KeyObjectHandlePrehashedSignAndVerifyError::DigestNotAllowedForRsaPssSignature(digest_type.to_string())); } ); Ok(pss) } /// Recover the PSS salt length from a signature using AUTO detection. /// Performs the RSA raw operation (sig^e mod n) to get the encoded message, /// then parses the PSS structure to find the salt length. fn recover_pss_salt_len<D>(key: &rsa::RsaPublicKey, sig: &[u8]) -> Option<usize> where D: digest::Digest, { use rsa::traits::PublicKeyParts; let h_len = <D as digest::Digest>::output_size(); let key_bits = key.n().bits(); let em_bits = key_bits - 1; let em_len = em_bits.div_ceil(8); let key_len = key_bits.div_ceil(8); // Compute em = sig^e mod n (raw RSA public key operation) let sig_bn = rsa::BigUint::from_bytes_be(sig); let em_bn = rsa::hazmat::rsa_encrypt(key, &sig_bn).ok()?; let em_be = em_bn.to_bytes_be(); // Pad em to key_len bytes (big-endian, left-pad with zeros) if em_be.len() > key_len { return None; } let mut em_padded = vec![0u8; key_len]; em_padded[key_len - em_be.len()..].copy_from_slice(&em_be); // Take the relevant em_len bytes from the right let em = &mut em_padded[key_len - em_len..]; // Check 0xBC trailer if em[em_len - 1] != 0xBC { return None; } if em_len < h_len + 2 { return None; } let db_len = em_len - h_len - 1; // H is at em[db_len..db_len+h_len] let h = em[db_len..db_len + h_len].to_vec(); // Unmask maskedDB using MGF1(H, db_len) let masked_db = &mut em[..db_len]; let mut counter: u32 = 0; let mut pos = 0; while pos < db_len { let mut hasher = D::new(); hasher.update(h.as_slice()); hasher.update(counter.to_be_bytes()); let hash_out = hasher.finalize(); let hash_bytes: &[u8] = hash_out.as_ref(); let end = (pos + h_len).min(db_len); for j in pos..end { masked_db[j] ^= hash_bytes[j - pos]; } pos += h_len; counter += 1; } // Clear top bits: db[0] &= 0xFF >> (8*em_len - em_bits) let db = masked_db; let top_bits_to_clear = 8 * em_len - em_bits; if top_bits_to_clear < 8 { db[0] &= 0xFF_u8 >> top_bits_to_clear; } // Find the 0x01 separator byte: DB = PS (zeros) || 0x01 || salt let mut salt_start = None; for (i, &b) in db.iter().enumerate() { if b == 0x01 { salt_start = Some(i + 1); break; } else if b != 0x00 { return None; // Invalid DB structure } } let salt_start = salt_start?; Some(db_len - salt_start) } impl KeyObjectHandle { pub fn sign_prehashed( &self, digest_type: &str, digest: &[u8], pss_salt_length: Option<i32>, padding: Option<u32>, dsa_signature_encoding: u32, ) -> Result<Box<[u8]>, KeyObjectHandlePrehashedSignAndVerifyError> { let private_key = self .as_private_key() .ok_or(KeyObjectHandlePrehashedSignAndVerifyError::KeyIsNotPrivate)?; match private_key { AsymmetricPrivateKey::Rsa(key) => { if padding == Some(RSA_PKCS1_OAEP_PADDING) { return Err(KeyObjectHandlePrehashedSignAndVerifyError::IllegalOrUnsupportedPaddingMode); } if padding == Some(RSA_PKCS1_PSS_PADDING) { let pss = new_pss_scheme( digest_type, pss_salt_length, Some(key.n().bits()), )?; let signature = pss .sign(Some(&mut OsRng), key, digest) .map_err(|_| KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigestWithRsaPss)?; return Ok(signature.into()); } let signer = if digest_type == "md5-sha1" { rsa::pkcs1v15::Pkcs1v15Sign::new_unprefixed() } else { match_fixed_digest_with_oid!( digest_type, fn <D>() { rsa::pkcs1v15::Pkcs1v15Sign::new::<D>() }, _ => { return Err(KeyObjectHandlePrehashedSignAndVerifyError::DigestNotAllowedForRsaSignature(digest_type.to_string())) } ) }; let signature = signer.sign(Some(&mut OsRng), key, digest).map_err( |e| { if e == rsa::Error::MessageTooLong { KeyObjectHandlePrehashedSignAndVerifyError::DigestTooBigForRsaKey } else { KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigestWithRsa } }, )?; Ok(signature.into()) } AsymmetricPrivateKey::RsaPss(key) => { if padding == Some(RSA_PKCS1_PADDING) { return Err(KeyObjectHandlePrehashedSignAndVerifyError::IllegalOrUnsupportedPaddingMode); } let mut hash_algorithm = None; let mut salt_length = None; if let Some(details) = &key.details { // Note: the rsa crate's PSS uses the same hash for the message and // for MGF1. We honor the key's enforced message hash but fall back // to using it for MGF1 too, even if the key specifies a distinct // mgf1 hash. RFC 4055 / PKCS#1 v2.1 permits this combination but // signatures produced here will not be byte-compatible with those // produced by OpenSSL when mgf1 hash != message hash. hash_algorithm = Some(details.hash_algorithm); salt_length = Some(details.salt_length as usize); } // Match Node.js / OpenSSL ordering for RSA-PSS signing: validate // the requested salt length against the key's enforced minimum // before validating the digest itself. if let Some(min_salt) = salt_length && let Some(requested) = pss_salt_length && requested >= 0 && (requested as usize) < min_salt { return Err( KeyObjectHandlePrehashedSignAndVerifyError::PssSaltLenTooSmall, ); } let pss = match_fixed_digest_with_oid!( digest_type, fn <D>(algorithm: Option<RsaPssHashAlgorithm>) { if let Some(hash_algorithm) = hash_algorithm.take() && Some(hash_algorithm) != algorithm { return Err(KeyObjectHandlePrehashedSignAndVerifyError::PrivateKeyDisallowsUsage { actual: digest_type.to_string(), expected: hash_algorithm.as_str().to_string(), }); } // Resolve salt length: explicit pss_salt_length takes priority, // then key details, then default (digest length) let resolved = if pss_salt_length.is_some() { let r = resolve_pss_salt_length::<D>(pss_salt_length, Some(key.key.n().bits())); // Enforce key's minimum salt length if let Some(min_salt) = salt_length && r < min_salt { return Err(KeyObjectHandlePrehashedSignAndVerifyError::PssSaltLenTooSmall); } r } else if let Some(sl) = salt_length { sl } else { <D as digest::Digest>::output_size() }; rsa::pss::Pss::new_with_salt::<D>(resolved) }, _ => { return Err(KeyObjectHandlePrehashedSignAndVerifyError::DigestNotAllowedForRsaPssSignature(digest_type.to_string())); } ); let signature = pss .sign(Some(&mut OsRng), &key.key, digest) .map_err(|_| KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigestWithRsaPss)?; Ok(signature.into()) } AsymmetricPrivateKey::Dsa(key) => { let res = match_fixed_digest!( digest_type, fn <D>() { key.sign_prehashed_rfc6979::<D>(digest) }, _ => { return Err(KeyObjectHandlePrehashedSignAndVerifyError::DigestNotAllowedForRsaSignature(digest_type.to_string())) } ); let signature = res.map_err(|_| KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigestWithDsa)?; if dsa_signature_encoding == 0 { Ok(signature.into()) } else { let q_len = key.verifying_key().components().q().bits().div_ceil(8); Ok(dsa_sig_to_p1363(&signature, q_len)) } } AsymmetricPrivateKey::Ec(key) => match key { EcPrivateKey::P224(key) => { let signing_key = p224::ecdsa::SigningKey::from(key); let signature: p224::ecdsa::Signature = signing_key .sign_prehash(digest) .map_err(|_| KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigest)?; dsa_signature(dsa_signature_encoding, signature) } EcPrivateKey::P256(key) => { let signing_key = p256::ecdsa::SigningKey::from(key); let signature: p256::ecdsa::Signature = signing_key .sign_prehash(digest) .map_err(|_| KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigest)?; dsa_signature(dsa_signature_encoding, signature) } EcPrivateKey::P384(key) => { let signing_key = p384::ecdsa::SigningKey::from(key); let signature: p384::ecdsa::Signature = signing_key .sign_prehash(digest) .map_err(|_| KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigest)?; dsa_signature(dsa_signature_encoding, signature) } EcPrivateKey::P521(key) => { let signing_key = p521::ecdsa::SigningKey::from_bytes(&key.to_bytes()) .map_err(|_| KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigest)?; let signature: p521::ecdsa::Signature = signing_key .sign_prehash(digest) .map_err(|_| KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigest)?; dsa_signature(dsa_signature_encoding, signature) } EcPrivateKey::Secp256k1(key) => { let signing_key = k256::ecdsa::SigningKey::from(key); let signature: k256::ecdsa::Signature = signing_key .sign_prehash(digest) .map_err(|_| KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigest)?; dsa_signature(dsa_signature_encoding, signature) } }, AsymmetricPrivateKey::X25519(_) | AsymmetricPrivateKey::X448(_) => { Err(KeyObjectHandlePrehashedSignAndVerifyError::X25519KeyCannotBeUsedForSigning) } AsymmetricPrivateKey::Ed25519(_) | AsymmetricPrivateKey::Ed448(_) => Err(KeyObjectHandlePrehashedSignAndVerifyError::Ed25519KeyCannotBeUsedForPrehashedSigning), AsymmetricPrivateKey::Dh(_) => { Err(KeyObjectHandlePrehashedSignAndVerifyError::DhKeyCannotBeUsedForSigning) } } } pub fn verify_prehashed( &self, digest_type: &str, digest: &[u8], signature: &[u8], pss_salt_length: Option<i32>, padding: Option<u32>, dsa_signature_encoding: u32, ) -> Result<bool, KeyObjectHandlePrehashedSignAndVerifyError> { let public_key = self.as_public_key().ok_or( KeyObjectHandlePrehashedSignAndVerifyError::KeyIsNotPublicOrPrivate, )?; match &*public_key { AsymmetricPublicKey::Rsa(key) => { if padding == Some(RSA_PKCS1_PSS_PADDING) { // AUTO mode: when pss_salt_length == -2 (RSA_PSS_SALTLEN_AUTO), // recover the actual salt length from the signature structure. let effective_salt_length = if pss_salt_length == Some(RSA_PSS_SALTLEN_MAX_SIGN) { let recovered = match_fixed_digest_with_oid!( digest_type, fn <D>(algorithm: Option<RsaPssHashAlgorithm>) { let _: Option<RsaPssHashAlgorithm> = algorithm; recover_pss_salt_len::<D>(key, signature) }, _ => { return Err(KeyObjectHandlePrehashedSignAndVerifyError::DigestNotAllowedForRsaPssSignature(digest_type.to_string())); } ); match recovered { Some(s) => Some(s as i32), None => return Ok(false), } } else { pss_salt_length }; let pss = new_pss_scheme( digest_type, effective_salt_length, Some(key.n().bits()), )?; return Ok(pss.verify(key, digest, signature).is_ok()); } let signer = if digest_type == "md5-sha1" { rsa::pkcs1v15::Pkcs1v15Sign::new_unprefixed() } else { match_fixed_digest_with_oid!( digest_type, fn <D>() { rsa::pkcs1v15::Pkcs1v15Sign::new::<D>() }, _ => { return Err(KeyObjectHandlePrehashedSignAndVerifyError::DigestNotAllowedForRsaSignature(digest_type.to_string())) } ) }; Ok(signer.verify(key, digest, signature).is_ok()) } AsymmetricPublicKey::RsaPss(key) => { if padding == Some(RSA_PKCS1_PADDING) { return Err(KeyObjectHandlePrehashedSignAndVerifyError::IllegalOrUnsupportedPaddingMode); } let mut hash_algorithm = None; let mut salt_length = None; if let Some(details) = &key.details { // Mirror the sign path: when mgf1 hash != message hash, fall back // to using the message hash for MGF1 too. Round-trips with our own // sign implementation but is not byte-compatible with OpenSSL. hash_algorithm = Some(details.hash_algorithm); salt_length = Some(details.salt_length as usize); } let pss = match_fixed_digest_with_oid!( digest_type, fn <D>(algorithm: Option<RsaPssHashAlgorithm>) { if let Some(hash_algorithm) = hash_algorithm.take() && Some(hash_algorithm) != algorithm { return Err(KeyObjectHandlePrehashedSignAndVerifyError::PrivateKeyDisallowsUsage { actual: digest_type.to_string(), expected: hash_algorithm.as_str().to_string(), }); } let resolved = if pss_salt_length.is_some() { resolve_pss_salt_length::<D>(pss_salt_length, Some(key.key.n().bits())) } else if let Some(sl) = salt_length { sl } else { <D as digest::Digest>::output_size() }; rsa::pss::Pss::new_with_salt::<D>(resolved) }, _ => { return Err(KeyObjectHandlePrehashedSignAndVerifyError::DigestNotAllowedForRsaPssSignature(digest_type.to_string())); } ); Ok(pss.verify(&key.key, digest, signature).is_ok()) } AsymmetricPublicKey::Dsa(key) => { let sig = if dsa_signature_encoding == 0 { // DER encoding let Ok(sig) = dsa::Signature::from_der(signature) else { return Ok(false); }; sig } else { let q_len = key.components().q().bits().div_ceil(8); let Some(sig) = dsa_sig_from_p1363(signature, q_len) else { return Ok(false); }; sig }; Ok(key.verify_prehash(digest, &sig).is_ok()) } AsymmetricPublicKey::Ec(key) => match key { EcPublicKey::P224(key) => { let verifying_key = p224::ecdsa::VerifyingKey::from(key); let signature = if dsa_signature_encoding == 0 { p224::ecdsa::Signature::from_der(signature) } else { p224::ecdsa::Signature::try_from(signature) }; let Ok(signature) = signature else { return Ok(false); }; Ok(verifying_key.verify_prehash(digest, &signature).is_ok()) } EcPublicKey::P256(key) => { let verifying_key = p256::ecdsa::VerifyingKey::from(key); let signature = if dsa_signature_encoding == 0 { p256::ecdsa::Signature::from_der(signature) } else { p256::ecdsa::Signature::try_from(signature) }; let Ok(signature) = signature else { return Ok(false); }; Ok(verifying_key.verify_prehash(digest, &signature).is_ok()) } EcPublicKey::P384(key) => { let verifying_key = p384::ecdsa::VerifyingKey::from(key); let signature = if dsa_signature_encoding == 0 { p384::ecdsa::Signature::from_der(signature) } else { p384::ecdsa::Signature::try_from(signature) }; let Ok(signature) = signature else { return Ok(false); }; Ok(verifying_key.verify_prehash(digest, &signature).is_ok()) } EcPublicKey::P521(key) => { let Ok(verifying_key) = p521::ecdsa::VerifyingKey::from_affine(*key.as_affine()) else { return Ok(false); }; let signature = if dsa_signature_encoding == 0 { p521::ecdsa::Signature::from_der(signature) } else { p521::ecdsa::Signature::try_from(signature) }; let Ok(signature) = signature else { return Ok(false); }; Ok(verifying_key.verify_prehash(digest, &signature).is_ok()) } EcPublicKey::Secp256k1(key) => { let verifying_key = k256::ecdsa::VerifyingKey::from(key); let signature = if dsa_signature_encoding == 0 { k256::ecdsa::Signature::from_der(signature) } else { k256::ecdsa::Signature::try_from(signature) }; let Ok(signature) = signature else { return Ok(false); }; Ok(verifying_key.verify_prehash(digest, &signature).is_ok()) } }, AsymmetricPublicKey::X25519(_) | AsymmetricPublicKey::X448(_) => { Err(KeyObjectHandlePrehashedSignAndVerifyError::X25519KeyCannotBeUsedForVerification) } AsymmetricPublicKey::Ed25519(_) | AsymmetricPublicKey::Ed448(_) => Err(KeyObjectHandlePrehashedSignAndVerifyError::Ed25519KeyCannotBeUsedForPrehashedVerification), AsymmetricPublicKey::Dh(_) => { Err(KeyObjectHandlePrehashedSignAndVerifyError::DhKeyCannotBeUsedForVerification) } } } }