Skip to main content

xml_sec/xmldsig/
signature.rs

1//! Signature verification helpers for XMLDSig.
2//!
3//! This module covers RSA PKCS#1 v1.5, DSA-SHA1, and ECDSA verification,
4//! including donor P-521 interoperability under the XMLDSig `ecdsa-sha384` URI.
5//!
6//! Input public keys are accepted in SubjectPublicKeyInfo (SPKI) form because
7//! that is how the vendored PEM fixtures are stored.
8//! - RSA keys are parsed from full SPKI DER (`PUBLIC KEY`) and verified via
9//!   RustCrypto `rsa::pkcs1v15`.
10//! - ECDSA keys are validated as uncompressed SEC1 points from the SPKI bit
11//!   string and verified with RustCrypto curve crates (`p256`/`p384`/`p521`).
12
13use der::Decode as _;
14use p256::ecdsa::{Signature as P256Signature, VerifyingKey as P256VerifyingKey};
15use p384::ecdsa::{Signature as P384Signature, VerifyingKey as P384VerifyingKey};
16use p521::ecdsa::{Signature as P521Signature, VerifyingKey as P521VerifyingKey};
17use rsa::pkcs8::DecodePublicKey;
18use rsa::signature::hazmat::PrehashVerifier;
19use rsa::{
20    pkcs1v15::{Signature as RsaPkcs1v15Signature, VerifyingKey as RsaVerifyingKey},
21    traits::PublicKeyParts,
22};
23use sha1::Sha1;
24use sha2::{Digest, Sha224, Sha256, Sha384, Sha512};
25use signature::Verifier;
26use x509_parser::prelude::FromDer;
27use x509_parser::public_key::{ECPoint, PublicKey};
28use x509_parser::x509::SubjectPublicKeyInfo;
29
30use super::parse::SignatureAlgorithm;
31use crate::policy::EcdsaSignatureValueEncoding;
32
33pub(crate) fn signature_value_matches_algorithm(
34    algorithm: SignatureAlgorithm,
35    signature_value: &[u8],
36) -> bool {
37    signature_value_matches_algorithm_with_encoding(
38        algorithm,
39        signature_value,
40        EcdsaSignatureValueEncoding::XmlDsig,
41    )
42}
43
44pub(crate) fn signature_value_matches_algorithm_with_encoding(
45    algorithm: SignatureAlgorithm,
46    signature_value: &[u8],
47    encoding: EcdsaSignatureValueEncoding,
48) -> bool {
49    match algorithm {
50        SignatureAlgorithm::PostQuantum(algorithm) => {
51            signature_value.len() == algorithm.signature_len()
52        }
53        SignatureAlgorithm::Ed25519
54        | SignatureAlgorithm::Ed25519Ctx
55        | SignatureAlgorithm::Ed25519Ph => signature_value.len() == 64,
56        SignatureAlgorithm::Ed448 | SignatureAlgorithm::Ed448Ph => signature_value.len() == 114,
57        SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256 => algorithm
58            .dsa_component_len()
59            .is_some_and(|component_len| signature_value.len() == component_len * 2),
60        SignatureAlgorithm::HmacSha1
61        | SignatureAlgorithm::HmacSha224
62        | SignatureAlgorithm::HmacSha256
63        | SignatureAlgorithm::HmacSha384
64        | SignatureAlgorithm::HmacSha512 => algorithm
65            .hmac_output_bits()
66            .is_some_and(|bits| (1..=bits / 8).contains(&signature_value.len())),
67        // Opaque custom keys expose no modulus here, so the default can enforce
68        // only non-empty framing under the absolute ceiling. Built-in keys
69        // override this with the exact modulus width.
70        SignatureAlgorithm::RsaSha1
71        | SignatureAlgorithm::RsaSha224
72        | SignatureAlgorithm::RsaSha256
73        | SignatureAlgorithm::RsaSha384
74        | SignatureAlgorithm::RsaSha512 => {
75            (1..=crate::hard_limits::RSA_MODULUS_BIT_CEILING / 8).contains(&signature_value.len())
76        }
77        SignatureAlgorithm::EcdsaSha1
78        | SignatureAlgorithm::EcdsaSha224
79        | SignatureAlgorithm::EcdsaSha256
80        | SignatureAlgorithm::EcdsaSha384
81        | SignatureAlgorithm::EcdsaSha512
82        | SignatureAlgorithm::EcdsaSha3_224
83        | SignatureAlgorithm::EcdsaSha3_256
84        | SignatureAlgorithm::EcdsaSha3_384
85        | SignatureAlgorithm::EcdsaSha3_512 => {
86            [32, 48, 66]
87                .into_iter()
88                .any(|component_len| match encoding {
89                    EcdsaSignatureValueEncoding::XmlDsig => {
90                        signature_value.len() == component_len * 2
91                    }
92                    EcdsaSignatureValueEncoding::XmlSecAsn1Der => {
93                        inspect_der_encoded_ecdsa_signature(signature_value, component_len)
94                            .is_ok_and(|value| value.is_some())
95                    }
96                })
97        }
98    }
99}
100
101pub(crate) fn signature_value_matches_spki(
102    algorithm: SignatureAlgorithm,
103    public_key_spki_der: &[u8],
104    signature_value: &[u8],
105) -> Result<bool, SignatureVerificationError> {
106    signature_value_matches_spki_with_encoding(
107        algorithm,
108        public_key_spki_der,
109        signature_value,
110        EcdsaSignatureValueEncoding::XmlDsig,
111    )
112}
113
114pub(crate) fn signature_value_matches_spki_with_encoding(
115    algorithm: SignatureAlgorithm,
116    public_key_spki_der: &[u8],
117    signature_value: &[u8],
118    encoding: EcdsaSignatureValueEncoding,
119) -> Result<bool, SignatureVerificationError> {
120    if let Some(length) = algorithm.eddsa_signature_len() {
121        super::modern::validate_public_key(algorithm, public_key_spki_der)?;
122        return Ok(signature_value.len() == length);
123    }
124    if let SignatureAlgorithm::PostQuantum(algorithm) = algorithm {
125        #[cfg(feature = "experimental-pq")]
126        {
127            super::post_quantum::validate_public_key(algorithm, public_key_spki_der)?;
128            return Ok(signature_value.len() == algorithm.signature_len());
129        }
130        #[cfg(not(feature = "experimental-pq"))]
131        {
132            return Err(SignatureVerificationError::UnsupportedAlgorithm {
133                uri: algorithm.uri().to_owned(),
134            });
135        }
136    }
137    let (rest, spki) = SubjectPublicKeyInfo::from_der(public_key_spki_der)
138        .map_err(|_| SignatureVerificationError::InvalidKeyDer)?;
139    if !rest.is_empty() {
140        return Err(SignatureVerificationError::InvalidKeyDer);
141    }
142    let public_key = spki
143        .parsed()
144        .map_err(|_| SignatureVerificationError::InvalidKeyDer)?;
145
146    match (algorithm, public_key) {
147        (
148            algorithm @ (SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256),
149            PublicKey::DSA(_),
150        ) => {
151            let key = decode_dsa_verifying_key(public_key_spki_der)?;
152            let component_len = usize::try_from(key.components().q().bits_vartime())
153                .map_err(|_| SignatureVerificationError::InvalidKeyDer)?
154                .div_ceil(8);
155            Ok(algorithm.dsa_component_len() == Some(component_len)
156                && signature_value.len() == component_len * 2)
157        }
158        (
159            SignatureAlgorithm::RsaSha1
160            | SignatureAlgorithm::RsaSha224
161            | SignatureAlgorithm::RsaSha256
162            | SignatureAlgorithm::RsaSha384
163            | SignatureAlgorithm::RsaSha512,
164            PublicKey::RSA(_),
165        ) => {
166            let key = rsa::RsaPublicKey::from_public_key_der(public_key_spki_der)
167                .map_err(|_| SignatureVerificationError::InvalidKeyDer)?;
168            Ok(signature_value.len() == key.size())
169        }
170        (
171            SignatureAlgorithm::EcdsaSha1
172            | SignatureAlgorithm::EcdsaSha224
173            | SignatureAlgorithm::EcdsaSha256
174            | SignatureAlgorithm::EcdsaSha384
175            | SignatureAlgorithm::EcdsaSha512
176            | SignatureAlgorithm::EcdsaSha3_224
177            | SignatureAlgorithm::EcdsaSha3_256
178            | SignatureAlgorithm::EcdsaSha3_384
179            | SignatureAlgorithm::EcdsaSha3_512,
180            PublicKey::EC(ec),
181        ) => {
182            validate_ec_public_key_encoding(&ec, &spki.subject_public_key.data)?;
183            let (_, component_len) = ecdsa_curve_and_component_len(&spki, &ec)?;
184            match encoding {
185                EcdsaSignatureValueEncoding::XmlDsig
186                    if signature_value.len() == component_len * 2 => {}
187                EcdsaSignatureValueEncoding::XmlSecAsn1Der
188                    if inspect_der_encoded_ecdsa_signature(signature_value, component_len)?
189                        .is_some() => {}
190                _ => return Err(SignatureVerificationError::InvalidSignatureFormat),
191            }
192            Ok(true)
193        }
194        (
195            SignatureAlgorithm::HmacSha1
196            | SignatureAlgorithm::HmacSha224
197            | SignatureAlgorithm::HmacSha256
198            | SignatureAlgorithm::HmacSha384
199            | SignatureAlgorithm::HmacSha512,
200            _,
201        ) => Err(SignatureVerificationError::KeyAlgorithmMismatch {
202            uri: algorithm.uri().to_owned(),
203        }),
204        _ => Err(SignatureVerificationError::KeyAlgorithmMismatch {
205            uri: algorithm.uri().to_owned(),
206        }),
207    }
208}
209
210/// Errors while preparing or running XMLDSig signature verification.
211#[derive(Debug, thiserror::Error)]
212#[non_exhaustive]
213pub enum SignatureVerificationError {
214    /// The provided PEM block could not be parsed as PEM input.
215    #[error("invalid PEM public key")]
216    InvalidKeyPem,
217
218    /// The signature method is not an RSA PKCS#1 v1.5 algorithm.
219    #[error("unsupported signature algorithm: {uri}")]
220    UnsupportedAlgorithm {
221        /// XMLDSig algorithm URI used for diagnostics.
222        uri: String,
223    },
224
225    /// The provided PEM block was not a public key.
226    #[error("invalid key format: expected PUBLIC KEY PEM, got {label}")]
227    InvalidKeyFormat {
228        /// The PEM label that was actually supplied.
229        label: String,
230    },
231
232    /// The provided DER bytes were not a valid SPKI-encoded public key.
233    #[error("invalid SubjectPublicKeyInfo DER")]
234    InvalidKeyDer,
235
236    /// A structurally valid key violates the active key-strength policy.
237    #[error("verification key rejected by policy: {0}")]
238    KeyPolicy(#[from] crate::policy::PolicyViolation),
239
240    /// The provided public key does not match the signature algorithm.
241    #[error("public key does not match signature algorithm: {uri}")]
242    KeyAlgorithmMismatch {
243        /// XMLDSig algorithm URI used for diagnostics.
244        uri: String,
245    },
246
247    /// The provided ECDSA signature bytes do not use the encoding selected by
248    /// the active verification policy.
249    #[error("invalid ECDSA signature encoding")]
250    InvalidSignatureFormat,
251}
252
253/// Verify an RSA XMLDSig signature using a PEM-encoded SPKI public key.
254///
255/// The PEM must contain a `PUBLIC KEY` block. Returns `Ok(false)` for signature
256/// mismatch and `Err` for algorithm/key preparation errors.
257#[must_use = "discarding the verification result skips signature validation"]
258pub fn verify_rsa_signature_pem(
259    algorithm: SignatureAlgorithm,
260    public_key_pem: &str,
261    signed_data: &[u8],
262    signature_value: &[u8],
263) -> Result<bool, SignatureVerificationError> {
264    let public_key_spki_der = parse_public_key_pem(public_key_pem)?;
265    verify_rsa_signature_spki(
266        algorithm,
267        &public_key_spki_der,
268        signed_data,
269        signature_value,
270    )
271}
272
273/// Verify an ECDSA XMLDSig signature using a PEM-encoded SPKI public key.
274///
275/// The PEM must contain a `PUBLIC KEY` block. The signature value is expected
276/// to use the XMLDSig fixed-width `r || s` format required by
277/// [RFC 9231 section 2.3.6](https://www.rfc-editor.org/rfc/rfc9231.html#section-2.3.6)
278/// (which replaces RFC 6931) and XMLDSig 1.1. Use [`verify_ecdsa_signature_pem_with_encoding`] to opt into
279/// libxmlsec1's ASN.1 compatibility representation. Returns `Ok(false)` for a
280/// signature mismatch and `Err` for key or signature-format errors.
281#[must_use = "discarding the verification result skips signature validation"]
282pub fn verify_ecdsa_signature_pem(
283    algorithm: SignatureAlgorithm,
284    public_key_pem: &str,
285    signed_data: &[u8],
286    signature_value: &[u8],
287) -> Result<bool, SignatureVerificationError> {
288    verify_ecdsa_signature_pem_with_encoding(
289        algorithm,
290        public_key_pem,
291        signed_data,
292        signature_value,
293        EcdsaSignatureValueEncoding::XmlDsig,
294    )
295}
296
297/// Verify an ECDSA signature using an explicit XMLDSig compatibility encoding.
298#[must_use = "discarding the verification result skips signature validation"]
299pub fn verify_ecdsa_signature_pem_with_encoding(
300    algorithm: SignatureAlgorithm,
301    public_key_pem: &str,
302    signed_data: &[u8],
303    signature_value: &[u8],
304    encoding: EcdsaSignatureValueEncoding,
305) -> Result<bool, SignatureVerificationError> {
306    let public_key_spki_der = parse_public_key_pem(public_key_pem)?;
307    verify_ecdsa_signature_spki_with_encoding(
308        algorithm,
309        &public_key_spki_der,
310        signed_data,
311        signature_value,
312        encoding,
313    )
314}
315
316fn parse_public_key_pem(public_key_pem: &str) -> Result<Vec<u8>, SignatureVerificationError> {
317    let (rest, pem) = x509_parser::pem::parse_x509_pem(public_key_pem.as_bytes())
318        .map_err(|_| SignatureVerificationError::InvalidKeyPem)?;
319    if !rest.iter().all(|byte| byte.is_ascii_whitespace()) {
320        return Err(SignatureVerificationError::InvalidKeyPem);
321    }
322    if pem.label != "PUBLIC KEY" {
323        return Err(SignatureVerificationError::InvalidKeyFormat { label: pem.label });
324    }
325
326    Ok(pem.contents)
327}
328
329/// Verify an RSA XMLDSig signature using DER-encoded SPKI public key bytes.
330///
331/// The input must be an X.509 `SubjectPublicKeyInfo` wrapping an RSA key.
332/// Returns `Ok(false)` for signature mismatch and `Err` for algorithm/key
333/// preparation errors.
334#[must_use = "discarding the verification result skips signature validation"]
335pub fn verify_rsa_signature_spki(
336    algorithm: SignatureAlgorithm,
337    public_key_spki_der: &[u8],
338    signed_data: &[u8],
339    signature_value: &[u8],
340) -> Result<bool, SignatureVerificationError> {
341    verify_rsa_signature_spki_with_minimum(
342        algorithm,
343        public_key_spki_der,
344        signed_data,
345        signature_value,
346        2048,
347    )
348}
349
350pub(crate) fn verify_rsa_signature_spki_with_minimum(
351    algorithm: SignatureAlgorithm,
352    public_key_spki_der: &[u8],
353    signed_data: &[u8],
354    signature_value: &[u8],
355    minimum_modulus_bits: usize,
356) -> Result<bool, SignatureVerificationError> {
357    validate_rsa_signature_spki_with_minimum(algorithm, public_key_spki_der, minimum_modulus_bits)?;
358    verify_rsa_signature_spki_primitive(
359        algorithm,
360        public_key_spki_der,
361        signed_data,
362        signature_value,
363    )
364}
365
366pub(crate) fn validate_rsa_signature_spki_with_minimum(
367    algorithm: SignatureAlgorithm,
368    public_key_spki_der: &[u8],
369    minimum_modulus_bits: usize,
370) -> Result<(), SignatureVerificationError> {
371    let (rest, spki) = SubjectPublicKeyInfo::from_der(public_key_spki_der)
372        .map_err(|_| SignatureVerificationError::InvalidKeyDer)?;
373    if !rest.is_empty() {
374        return Err(SignatureVerificationError::InvalidKeyDer);
375    }
376    match spki
377        .parsed()
378        .map_err(|_| SignatureVerificationError::InvalidKeyDer)?
379    {
380        PublicKey::RSA(rsa) => validate_rsa_public_key(&rsa, algorithm, minimum_modulus_bits),
381        _ => Err(SignatureVerificationError::KeyAlgorithmMismatch {
382            uri: algorithm.uri().to_string(),
383        }),
384    }
385}
386
387pub(crate) fn verify_rsa_signature_spki_primitive(
388    algorithm: SignatureAlgorithm,
389    public_key_spki_der: &[u8],
390    signed_data: &[u8],
391    signature_value: &[u8],
392) -> Result<bool, SignatureVerificationError> {
393    ensure_rsa_signature_algorithm(algorithm)?;
394    let key = rsa::RsaPublicKey::from_public_key_der(public_key_spki_der)
395        .map_err(|_| SignatureVerificationError::InvalidKeyDer)?;
396    let Ok(signature) = RsaPkcs1v15Signature::try_from(signature_value) else {
397        return Ok(false);
398    };
399    let verified = match algorithm {
400        SignatureAlgorithm::RsaSha1 => RsaVerifyingKey::<Sha1>::new(key)
401            .verify(signed_data, &signature)
402            .is_ok(),
403        SignatureAlgorithm::RsaSha224 => RsaVerifyingKey::<Sha224>::new(key)
404            .verify(signed_data, &signature)
405            .is_ok(),
406        SignatureAlgorithm::RsaSha256 => RsaVerifyingKey::<Sha256>::new(key)
407            .verify(signed_data, &signature)
408            .is_ok(),
409        SignatureAlgorithm::RsaSha384 => RsaVerifyingKey::<Sha384>::new(key)
410            .verify(signed_data, &signature)
411            .is_ok(),
412        SignatureAlgorithm::RsaSha512 => RsaVerifyingKey::<Sha512>::new(key)
413            .verify(signed_data, &signature)
414            .is_ok(),
415        _ => unreachable!("RSA algorithm checked above"),
416    };
417    Ok(verified)
418}
419
420/// Verify an XMLDSig DSA-SHA1 signature using a DER SPKI public key.
421///
422/// XMLDSig 1.0 encodes the signature as the fixed-width 20-byte `r` followed
423/// by the fixed-width 20-byte `s`, rather than ASN.1 DER.
424#[must_use = "discarding the verification result skips signature validation"]
425pub fn verify_dsa_signature_spki(
426    algorithm: SignatureAlgorithm,
427    public_key_spki_der: &[u8],
428    signed_data: &[u8],
429    signature_value: &[u8],
430) -> Result<bool, SignatureVerificationError> {
431    verify_dsa_signature_spki_with_minimum(
432        algorithm,
433        public_key_spki_der,
434        signed_data,
435        signature_value,
436        crate::policy::DsaKeyPolicy::default().minimum_modulus_bits,
437    )
438}
439
440pub(crate) fn verify_dsa_signature_spki_with_minimum(
441    algorithm: SignatureAlgorithm,
442    public_key_spki_der: &[u8],
443    signed_data: &[u8],
444    signature_value: &[u8],
445    minimum_modulus_bits: usize,
446) -> Result<bool, SignatureVerificationError> {
447    validate_dsa_signature_spki_with_minimum(public_key_spki_der, minimum_modulus_bits)?;
448    verify_dsa_signature_spki_primitive(
449        algorithm,
450        public_key_spki_der,
451        signed_data,
452        signature_value,
453    )
454}
455
456pub(crate) fn validate_dsa_signature_spki_with_minimum(
457    public_key_spki_der: &[u8],
458    minimum_modulus_bits: usize,
459) -> Result<(), SignatureVerificationError> {
460    let key = decode_dsa_verifying_key(public_key_spki_der)?;
461    let modulus_bits = usize::try_from(key.components().p().bits_vartime())
462        .map_err(|_| SignatureVerificationError::InvalidKeyDer)?;
463    crate::policy::DsaKeyPolicy {
464        minimum_modulus_bits,
465    }
466    .validate_modulus_bits(modulus_bits)
467    .map_err(SignatureVerificationError::KeyPolicy)
468}
469
470#[derive(der::Sequence)]
471pub(crate) struct BorrowedDsaPublicParameters<'a> {
472    pub(crate) p: der::asn1::UintRef<'a>,
473    pub(crate) q: der::asn1::UintRef<'a>,
474    pub(crate) g: der::asn1::UintRef<'a>,
475}
476
477pub(crate) fn decode_dsa_verifying_key(
478    bytes: &[u8],
479) -> Result<dsa::VerifyingKey, SignatureVerificationError> {
480    // Component size is a process-safety bound, not a DSA conformance rule.
481    // Inspect borrowed DER integers before any allocating bigint conversion,
482    // including certificate signatures and signature-framing checks.
483    let spki = rsa::pkcs8::SubjectPublicKeyInfoRef::from_der(bytes)
484        .map_err(|_| SignatureVerificationError::InvalidKeyDer)?;
485    let parameters = spki
486        .algorithm
487        .parameters
488        .as_ref()
489        .ok_or(SignatureVerificationError::InvalidKeyDer)?
490        .decode_as::<BorrowedDsaPublicParameters<'_>>()
491        .map_err(|_| SignatureVerificationError::InvalidKeyDer)?;
492    let y = der::asn1::UintRef::from_der(spki.subject_public_key.raw_bytes())
493        .map_err(|_| SignatureVerificationError::InvalidKeyDer)?;
494    for component in [parameters.p, parameters.q, parameters.g, y] {
495        if component.as_bytes().len() > crate::hard_limits::DSA_KEY_COMPONENT_BYTE_CEILING {
496            return Err(SignatureVerificationError::InvalidKeyDer);
497        }
498    }
499    dsa::VerifyingKey::from_public_key_der(bytes)
500        .map_err(|_| SignatureVerificationError::InvalidKeyDer)
501}
502
503pub(crate) fn verify_dsa_signature_spki_primitive(
504    algorithm: SignatureAlgorithm,
505    public_key_spki_der: &[u8],
506    signed_data: &[u8],
507    signature_value: &[u8],
508) -> Result<bool, SignatureVerificationError> {
509    if !matches!(
510        algorithm,
511        SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256
512    ) {
513        return Err(SignatureVerificationError::UnsupportedAlgorithm {
514            uri: algorithm.uri().to_string(),
515        });
516    }
517    let key = decode_dsa_verifying_key(public_key_spki_der)?;
518    let component_len = usize::try_from(key.components().q().bits_vartime())
519        .map_err(|_| SignatureVerificationError::InvalidKeyDer)?
520        .div_ceil(8);
521    if algorithm.dsa_component_len() != Some(component_len) {
522        return Ok(false);
523    }
524    if signature_value.len() != component_len.saturating_mul(2) {
525        return Ok(false);
526    }
527    let Some(signature) = dsa::Signature::from_components(
528        crypto_bigint::BoxedUint::from_be_slice_vartime(&signature_value[..component_len]),
529        crypto_bigint::BoxedUint::from_be_slice_vartime(&signature_value[component_len..]),
530    ) else {
531        return Ok(false);
532    };
533    let verified = match algorithm {
534        SignatureAlgorithm::DsaSha1 => key.verify_prehash(&Sha1::digest(signed_data), &signature),
535        SignatureAlgorithm::DsaSha256 => {
536            key.verify_prehash(&Sha256::digest(signed_data), &signature)
537        }
538        _ => unreachable!("DSA algorithm checked above"),
539    };
540    Ok(verified.is_ok())
541}
542
543/// Verify an ECDSA XMLDSig signature using DER-encoded SPKI public key bytes.
544///
545/// The input must be an X.509 `SubjectPublicKeyInfo` wrapping an EC key. The
546/// signature value must use XMLDSig fixed-width `r || s` bytes. Use
547/// [`verify_ecdsa_signature_spki_with_encoding`] to select libxmlsec1's ASN.1
548/// compatibility representation explicitly.
549#[must_use = "discarding the verification result skips signature validation"]
550pub fn verify_ecdsa_signature_spki(
551    algorithm: SignatureAlgorithm,
552    public_key_spki_der: &[u8],
553    signed_data: &[u8],
554    signature_value: &[u8],
555) -> Result<bool, SignatureVerificationError> {
556    verify_ecdsa_signature_spki_with_encoding(
557        algorithm,
558        public_key_spki_der,
559        signed_data,
560        signature_value,
561        EcdsaSignatureValueEncoding::XmlDsig,
562    )
563}
564
565/// Verify an ECDSA signature using an explicit XMLDSig compatibility encoding.
566#[must_use = "discarding the verification result skips signature validation"]
567pub fn verify_ecdsa_signature_spki_with_encoding(
568    algorithm: SignatureAlgorithm,
569    public_key_spki_der: &[u8],
570    signed_data: &[u8],
571    signature_value: &[u8],
572    encoding: EcdsaSignatureValueEncoding,
573) -> Result<bool, SignatureVerificationError> {
574    let digest_algorithm = algorithm.ecdsa_digest().ok_or_else(|| {
575        SignatureVerificationError::UnsupportedAlgorithm {
576            uri: algorithm.uri().to_string(),
577        }
578    })?;
579
580    let (rest, spki) = SubjectPublicKeyInfo::from_der(public_key_spki_der)
581        .map_err(|_| SignatureVerificationError::InvalidKeyDer)?;
582    if !rest.is_empty() {
583        return Err(SignatureVerificationError::InvalidKeyDer);
584    }
585    let public_key = spki
586        .parsed()
587        .map_err(|_| SignatureVerificationError::InvalidKeyDer)?;
588
589    match public_key {
590        PublicKey::EC(ec) => {
591            validate_ec_public_key_encoding(&ec, &spki.subject_public_key.data)?;
592            let (curve, component_len) = ecdsa_curve_and_component_len(&spki, &ec)?;
593            let signature_encoding = match encoding {
594                EcdsaSignatureValueEncoding::XmlDsig => {
595                    if signature_value.len() != component_len * 2 {
596                        return Err(SignatureVerificationError::InvalidSignatureFormat);
597                    }
598                    EcdsaSignatureEncoding::XmlDsigFixed
599                }
600                EcdsaSignatureValueEncoding::XmlSecAsn1Der => {
601                    if inspect_der_encoded_ecdsa_signature(signature_value, component_len)?
602                        .is_none()
603                    {
604                        return Err(SignatureVerificationError::InvalidSignatureFormat);
605                    }
606                    EcdsaSignatureEncoding::Asn1Der
607                }
608            };
609            let prehash = super::compute_digest(digest_algorithm, signed_data);
610            match curve {
611                EcCurve::P256 => verify_ecdsa_p256(
612                    &spki.subject_public_key.data,
613                    &prehash,
614                    signature_value,
615                    signature_encoding,
616                ),
617                EcCurve::P384 => verify_ecdsa_p384(
618                    &spki.subject_public_key.data,
619                    &prehash,
620                    signature_value,
621                    signature_encoding,
622                ),
623                EcCurve::P521 => verify_ecdsa_p521(
624                    &spki.subject_public_key.data,
625                    &prehash,
626                    signature_value,
627                    signature_encoding,
628                ),
629            }
630        }
631        _ => Err(SignatureVerificationError::KeyAlgorithmMismatch {
632            uri: algorithm.uri().to_string(),
633        }),
634    }
635}
636
637/// Verify the ASN.1 DER ECDSA representation required by X.509 signatures.
638///
639/// This is intentionally separate from the XMLDSig policy-aware entry point:
640/// certificate signature framing is fixed by X.509 and must not inherit the
641/// document's `SignatureValue` compatibility mode.
642pub(crate) fn verify_ecdsa_signature_spki_asn1_der(
643    algorithm: SignatureAlgorithm,
644    public_key_spki_der: &[u8],
645    signed_data: &[u8],
646    signature_value: &[u8],
647) -> Result<bool, SignatureVerificationError> {
648    verify_ecdsa_signature_spki_with_encoding(
649        algorithm,
650        public_key_spki_der,
651        signed_data,
652        signature_value,
653        EcdsaSignatureValueEncoding::XmlSecAsn1Der,
654    )
655}
656
657fn validate_rsa_public_key(
658    rsa: &x509_parser::public_key::RSAPublicKey<'_>,
659    algorithm: SignatureAlgorithm,
660    minimum_modulus_bits: usize,
661) -> Result<(), SignatureVerificationError> {
662    ensure_rsa_signature_algorithm(algorithm)?;
663    validate_rsa_key_components(rsa.modulus, rsa.exponent, minimum_modulus_bits)
664}
665
666/// Apply the RSA key-strength invariant shared by XMLDSig and X.509 algorithms.
667pub(crate) fn validate_rsa_key_components(
668    modulus: &[u8],
669    exponent: &[u8],
670    minimum_modulus_bits: usize,
671) -> Result<(), SignatureVerificationError> {
672    crate::policy::RsaKeyPolicy {
673        minimum_modulus_bits,
674    }
675    .validate_components("verification", modulus, exponent)
676    .map(|_| ())
677    .map_err(SignatureVerificationError::KeyPolicy)
678}
679
680fn ensure_rsa_signature_algorithm(
681    algorithm: SignatureAlgorithm,
682) -> Result<(), SignatureVerificationError> {
683    match algorithm {
684        SignatureAlgorithm::RsaSha1
685        | SignatureAlgorithm::RsaSha224
686        | SignatureAlgorithm::RsaSha256
687        | SignatureAlgorithm::RsaSha384
688        | SignatureAlgorithm::RsaSha512 => Ok(()),
689        _ => Err(SignatureVerificationError::UnsupportedAlgorithm {
690            uri: algorithm.uri().to_string(),
691        }),
692    }
693}
694
695#[derive(Clone, Copy, Debug, Eq, PartialEq)]
696enum EcCurve {
697    P256,
698    P384,
699    P521,
700}
701
702fn ecdsa_curve_and_component_len(
703    spki: &SubjectPublicKeyInfo<'_>,
704    ec: &ECPoint<'_>,
705) -> Result<(EcCurve, usize), SignatureVerificationError> {
706    let curve_oid = spki
707        .algorithm
708        .parameters
709        .as_ref()
710        .and_then(|params| params.as_oid().ok())
711        .ok_or(SignatureVerificationError::InvalidKeyDer)?;
712    let point_len = ec.key_size();
713
714    let curve_oid = curve_oid.to_id_string();
715    match (curve_oid.as_str(), point_len) {
716        ("1.2.840.10045.3.1.7", 256) => Ok((EcCurve::P256, 32)),
717        ("1.3.132.0.34", 384) => Ok((EcCurve::P384, 48)),
718        // x509-parser reports the byte-aligned SEC1 point size for P-521.
719        ("1.3.132.0.35", 528) => Ok((EcCurve::P521, 66)),
720        _ => Err(SignatureVerificationError::InvalidKeyDer),
721    }
722}
723
724fn verify_ecdsa_p256(
725    public_key: &[u8],
726    prehash: &[u8],
727    signature_value: &[u8],
728    signature_encoding: EcdsaSignatureEncoding,
729) -> Result<bool, SignatureVerificationError> {
730    let key = P256VerifyingKey::from_sec1_bytes(public_key)
731        .map_err(|_| SignatureVerificationError::InvalidKeyDer)?;
732    verify_p256_signature(&key, signature_value, signature_encoding, prehash)
733}
734
735fn verify_ecdsa_p384(
736    public_key: &[u8],
737    prehash: &[u8],
738    signature_value: &[u8],
739    signature_encoding: EcdsaSignatureEncoding,
740) -> Result<bool, SignatureVerificationError> {
741    let key = P384VerifyingKey::from_sec1_bytes(public_key)
742        .map_err(|_| SignatureVerificationError::InvalidKeyDer)?;
743    verify_p384_signature(&key, signature_value, signature_encoding, prehash)
744}
745
746fn verify_ecdsa_p521(
747    public_key: &[u8],
748    prehash: &[u8],
749    signature_value: &[u8],
750    signature_encoding: EcdsaSignatureEncoding,
751) -> Result<bool, SignatureVerificationError> {
752    let key = P521VerifyingKey::from_sec1_bytes(public_key)
753        .map_err(|_| SignatureVerificationError::InvalidKeyDer)?;
754    verify_p521_signature(&key, signature_value, signature_encoding, prehash)
755}
756
757trait DecodeEcdsaSignature: Sized {
758    fn decode_fixed_width(bytes: &[u8]) -> Result<Self, SignatureVerificationError>;
759    fn decode_der(bytes: &[u8]) -> Result<Self, SignatureVerificationError>;
760}
761
762macro_rules! impl_ecdsa_signature_decoder {
763    ($signature:ty) => {
764        impl DecodeEcdsaSignature for $signature {
765            fn decode_fixed_width(bytes: &[u8]) -> Result<Self, SignatureVerificationError> {
766                Self::from_slice(bytes)
767                    .map_err(|_| SignatureVerificationError::InvalidSignatureFormat)
768            }
769
770            fn decode_der(bytes: &[u8]) -> Result<Self, SignatureVerificationError> {
771                Self::from_der(bytes)
772                    .map_err(|_| SignatureVerificationError::InvalidSignatureFormat)
773            }
774        }
775    };
776}
777
778impl_ecdsa_signature_decoder!(P256Signature);
779impl_ecdsa_signature_decoder!(P384Signature);
780impl_ecdsa_signature_decoder!(P521Signature);
781
782fn verify_ecdsa_signature<K, S>(
783    key: &K,
784    signature_value: &[u8],
785    signature_encoding: EcdsaSignatureEncoding,
786    prehash: &[u8],
787) -> Result<bool, SignatureVerificationError>
788where
789    K: PrehashVerifier<S>,
790    S: DecodeEcdsaSignature,
791{
792    let signature = match signature_encoding {
793        EcdsaSignatureEncoding::XmlDsigFixed => S::decode_fixed_width(signature_value)?,
794        EcdsaSignatureEncoding::Asn1Der => S::decode_der(signature_value)?,
795    };
796    Ok(key.verify_prehash(prehash, &signature).is_ok())
797}
798
799fn verify_p256_signature(
800    key: &P256VerifyingKey,
801    signature_value: &[u8],
802    signature_encoding: EcdsaSignatureEncoding,
803    prehash: &[u8],
804) -> Result<bool, SignatureVerificationError> {
805    verify_ecdsa_signature::<_, P256Signature>(key, signature_value, signature_encoding, prehash)
806}
807
808fn verify_p384_signature(
809    key: &P384VerifyingKey,
810    signature_value: &[u8],
811    signature_encoding: EcdsaSignatureEncoding,
812    prehash: &[u8],
813) -> Result<bool, SignatureVerificationError> {
814    verify_ecdsa_signature::<_, P384Signature>(key, signature_value, signature_encoding, prehash)
815}
816
817fn verify_p521_signature(
818    key: &P521VerifyingKey,
819    signature_value: &[u8],
820    signature_encoding: EcdsaSignatureEncoding,
821    prehash: &[u8],
822) -> Result<bool, SignatureVerificationError> {
823    verify_ecdsa_signature::<_, P521Signature>(key, signature_value, signature_encoding, prehash)
824}
825
826#[derive(Clone, Copy, Debug, Eq, PartialEq)]
827enum EcdsaSignatureEncoding {
828    XmlDsigFixed,
829    Asn1Der,
830}
831
832pub(crate) fn encode_ecdsa_signature_as_der(signature: &[u8]) -> Option<Vec<u8>> {
833    if signature.is_empty() || !signature.len().is_multiple_of(2) {
834        return None;
835    }
836    let component_len = signature.len() / 2;
837    let mut content = Vec::with_capacity(signature.len() + 8);
838    encode_der_integer(&signature[..component_len], &mut content);
839    encode_der_integer(&signature[component_len..], &mut content);
840
841    let mut encoded = Vec::with_capacity(content.len() + 3);
842    encoded.push(0x30);
843    encode_der_length(content.len(), &mut encoded);
844    encoded.extend_from_slice(&content);
845    Some(encoded)
846}
847
848pub(crate) fn maximum_ecdsa_der_signature_len(raw_signature_len: usize) -> Option<usize> {
849    if raw_signature_len == 0 || !raw_signature_len.is_multiple_of(2) {
850        return None;
851    }
852    let component_len = raw_signature_len / 2;
853    let integer_content_len = component_len.checked_add(1)?;
854    let integer_len = 1_usize
855        .checked_add(der_length_octets(integer_content_len)?)?
856        .checked_add(integer_content_len)?;
857    let sequence_content_len = integer_len.checked_mul(2)?;
858    1_usize
859        .checked_add(der_length_octets(sequence_content_len)?)?
860        .checked_add(sequence_content_len)
861}
862
863fn encode_der_integer(component: &[u8], output: &mut Vec<u8>) {
864    let first_nonzero = component
865        .iter()
866        .position(|byte| *byte != 0)
867        .unwrap_or(component.len() - 1);
868    let magnitude = &component[first_nonzero..];
869    let needs_sign_octet = magnitude[0] & 0x80 != 0;
870    output.push(0x02);
871    encode_der_length(magnitude.len() + usize::from(needs_sign_octet), output);
872    if needs_sign_octet {
873        output.push(0);
874    }
875    output.extend_from_slice(magnitude);
876}
877
878fn encode_der_length(len: usize, output: &mut Vec<u8>) {
879    if len < 128 {
880        output.push(len as u8);
881        return;
882    }
883
884    let bytes = len.to_be_bytes();
885    let first_nonzero = bytes
886        .iter()
887        .position(|byte| *byte != 0)
888        .expect("non-short DER lengths are nonzero");
889    let encoded = &bytes[first_nonzero..];
890    output.push(0x80 | encoded.len() as u8);
891    output.extend_from_slice(encoded);
892}
893
894fn der_length_octets(len: usize) -> Option<usize> {
895    if len < 128 {
896        return Some(1);
897    }
898    let significant_bytes = (usize::BITS - len.leading_zeros()).div_ceil(8) as usize;
899    significant_bytes.checked_add(1)
900}
901
902fn inspect_der_encoded_ecdsa_signature(
903    signature_value: &[u8],
904    component_len: usize,
905) -> Result<Option<()>, SignatureVerificationError> {
906    let Some((&tag, rest)) = signature_value.split_first() else {
907        return Ok(None);
908    };
909    if tag != 0x30 {
910        return Ok(None);
911    }
912
913    let sequence = parse_der_length(rest)
914        .ok_or(SignatureVerificationError::InvalidSignatureFormat)?
915        .map_err(|_| SignatureVerificationError::InvalidSignatureFormat)?;
916    let (sequence_len, sequence_rest) = sequence;
917    let (sequence_content, trailing) = sequence_rest
918        .split_at_checked(sequence_len)
919        .ok_or(SignatureVerificationError::InvalidSignatureFormat)?;
920    if !trailing.is_empty() {
921        return Err(SignatureVerificationError::InvalidSignatureFormat);
922    }
923
924    let after_r = parse_der_integer(sequence_content, component_len)?;
925    let after_s = parse_der_integer(after_r, component_len)?;
926    if !after_s.is_empty() {
927        return Err(SignatureVerificationError::InvalidSignatureFormat);
928    }
929
930    Ok(Some(()))
931}
932
933fn parse_der_integer(
934    input: &[u8],
935    component_len: usize,
936) -> Result<&[u8], SignatureVerificationError> {
937    let Some((&tag, rest)) = input.split_first() else {
938        return Err(SignatureVerificationError::InvalidSignatureFormat);
939    };
940    if tag != 0x02 {
941        return Err(SignatureVerificationError::InvalidSignatureFormat);
942    }
943
944    let (len, rest) = parse_der_length(rest)
945        .ok_or(SignatureVerificationError::InvalidSignatureFormat)?
946        .map_err(|_| SignatureVerificationError::InvalidSignatureFormat)?;
947    let (integer_bytes, remainder) = rest
948        .split_at_checked(len)
949        .ok_or(SignatureVerificationError::InvalidSignatureFormat)?;
950
951    if integer_bytes.is_empty() {
952        return Err(SignatureVerificationError::InvalidSignatureFormat);
953    }
954    if integer_bytes.len() > component_len + 1 {
955        return Err(SignatureVerificationError::InvalidSignatureFormat);
956    }
957    if integer_bytes.len() == component_len + 1 && integer_bytes[0] != 0 {
958        return Err(SignatureVerificationError::InvalidSignatureFormat);
959    }
960    if integer_bytes[0] & 0x80 != 0 {
961        return Err(SignatureVerificationError::InvalidSignatureFormat);
962    }
963    if integer_bytes.len() > 1 && integer_bytes[0] == 0 && integer_bytes[1] & 0x80 == 0 {
964        return Err(SignatureVerificationError::InvalidSignatureFormat);
965    }
966
967    Ok(remainder)
968}
969
970fn parse_der_length(input: &[u8]) -> Option<Result<(usize, &[u8]), ()>> {
971    let (&len_byte, rest) = input.split_first()?;
972
973    if len_byte & 0x80 == 0 {
974        return Some(Ok((usize::from(len_byte), rest)));
975    }
976
977    let len_len = usize::from(len_byte & 0x7f);
978    if len_len == 0 || len_len > std::mem::size_of::<usize>() || rest.len() < len_len {
979        return Some(Err(()));
980    }
981
982    let (len_bytes, remainder) = rest.split_at(len_len);
983    if len_bytes[0] == 0 {
984        return Some(Err(()));
985    }
986
987    let mut declared_len = 0_usize;
988    for &byte in len_bytes {
989        declared_len = match declared_len.checked_mul(256) {
990            Some(len) => len,
991            None => return Some(Err(())),
992        };
993        declared_len = match declared_len.checked_add(usize::from(byte)) {
994            Some(len) => len,
995            None => return Some(Err(())),
996        };
997    }
998
999    if declared_len < 128 {
1000        return Some(Err(()));
1001    }
1002
1003    Some(Ok((declared_len, remainder)))
1004}
1005
1006pub(crate) fn validate_ec_public_key_encoding(
1007    ec: &ECPoint<'_>,
1008    public_key_bytes: &[u8],
1009) -> Result<(), SignatureVerificationError> {
1010    let coordinate_len = ec_coordinate_len_bytes(ec.key_size())?;
1011    let expected_len = coordinate_len
1012        .checked_mul(2)
1013        .and_then(|len| len.checked_add(1))
1014        .ok_or(SignatureVerificationError::InvalidKeyDer)?;
1015
1016    // RFC 5480 ยง2.2 permits, but does not require, compressed points:
1017    // https://www.rfc-editor.org/rfc/rfc5480.html#section-2.2 . This implementation
1018    // uses the uncompressed profile consistently for import and verification.
1019    let is_uncompressed_sec1 =
1020        public_key_bytes.len() == expected_len && public_key_bytes.first() == Some(&0x04);
1021    if !is_uncompressed_sec1 {
1022        return Err(SignatureVerificationError::InvalidKeyDer);
1023    }
1024
1025    Ok(())
1026}
1027
1028fn ec_coordinate_len_bytes(key_bits: usize) -> Result<usize, SignatureVerificationError> {
1029    key_bits
1030        .checked_add(7)
1031        .and_then(|bits| bits.checked_div(8))
1032        .ok_or(SignatureVerificationError::InvalidKeyDer)
1033}
1034
1035#[cfg(test)]
1036#[expect(clippy::unwrap_used, reason = "unit tests use fixed fixture data")]
1037mod tests {
1038    use super::*;
1039
1040    #[test]
1041    fn ecdsa_algorithms_are_rejected_for_rsa_verification() {
1042        for algorithm in [
1043            SignatureAlgorithm::EcdsaSha256,
1044            SignatureAlgorithm::EcdsaSha384,
1045        ] {
1046            let err = ensure_rsa_signature_algorithm(algorithm).unwrap_err();
1047            assert!(matches!(
1048                err,
1049                SignatureVerificationError::UnsupportedAlgorithm { .. }
1050            ));
1051        }
1052    }
1053
1054    #[test]
1055    fn malformed_dsa_components_are_verification_misses() {
1056        let public_key = include_bytes!(
1057            "../../tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/lugh.der"
1058        );
1059        let signature = [0_u8; 40];
1060
1061        assert!(matches!(
1062            verify_dsa_signature_spki_with_minimum(
1063                SignatureAlgorithm::DsaSha1,
1064                public_key,
1065                b"signed",
1066                &signature,
1067                1024,
1068            ),
1069            Ok(false)
1070        ));
1071    }
1072
1073    #[test]
1074    fn spki_signature_framing_uses_the_resolved_key_width() {
1075        let rsa = parse_public_key_pem(include_str!(
1076            "../../tests/fixtures/keys/rsa/rsa-2048-pubkey.pem"
1077        ))
1078        .expect("RSA fixture must parse");
1079        assert!(
1080            signature_value_matches_spki(SignatureAlgorithm::RsaSha256, &rsa, &[0; 256]).unwrap()
1081        );
1082        assert!(
1083            !signature_value_matches_spki(SignatureAlgorithm::RsaSha256, &rsa, &[0; 255]).unwrap()
1084        );
1085
1086        let p256 = parse_public_key_pem(include_str!(
1087            "../../tests/fixtures/keys/ec/ec-prime256v1-pubkey.pem"
1088        ))
1089        .expect("P-256 fixture must parse");
1090        assert!(
1091            signature_value_matches_spki(SignatureAlgorithm::EcdsaSha256, &p256, &[0xAA; 64])
1092                .unwrap()
1093        );
1094        assert!(matches!(
1095            signature_value_matches_spki(SignatureAlgorithm::EcdsaSha256, &p256, &[0xAA; 96]),
1096            Err(SignatureVerificationError::InvalidSignatureFormat)
1097        ));
1098    }
1099
1100    #[test]
1101    fn der_like_prefix_with_fixed_width_len_is_not_valid_der() {
1102        let mut signature = vec![0xAA_u8; 96];
1103        signature[0] = 0x30;
1104        signature[1] = 0x20;
1105
1106        assert!(inspect_der_encoded_ecdsa_signature(&signature, 48).is_err());
1107    }
1108
1109    #[test]
1110    fn overlong_der_length_below_128_is_rejected() {
1111        let bad = [0x81_u8, 0x7f];
1112        let parsed = parse_der_length(&bad).expect("length bytes should be present");
1113        assert!(
1114            matches!(parsed, Err(())),
1115            "DER must reject long-form lengths below 128"
1116        );
1117    }
1118
1119    #[test]
1120    fn ec_coordinate_length_rounds_up_for_non_byte_aligned_curves() {
1121        assert_eq!(
1122            ec_coordinate_len_bytes(521).expect("521-bit curves require rounded byte length"),
1123            66
1124        );
1125    }
1126
1127    #[test]
1128    fn same_width_valid_der_is_recognized_in_explicit_mode() {
1129        let mut signature = Vec::with_capacity(64);
1130        signature.extend_from_slice(&[0x30, 0x3e, 0x02, 0x1d]);
1131        signature.extend(std::iter::repeat_n(0x11_u8, 29));
1132        signature.extend_from_slice(&[0x02, 0x1d]);
1133        signature.extend(std::iter::repeat_n(0x22_u8, 29));
1134
1135        assert_eq!(
1136            inspect_der_encoded_ecdsa_signature(&signature, 32).unwrap(),
1137            Some(())
1138        );
1139    }
1140
1141    #[test]
1142    fn der_integer_longer_than_component_requires_sign_byte() {
1143        let mut signature = Vec::with_capacity(72);
1144        signature.extend_from_slice(&[0x30, 0x46, 0x02, 0x21, 0x01]);
1145        signature.extend(std::iter::repeat_n(0x11_u8, 32));
1146        signature.extend_from_slice(&[0x02, 0x21, 0x01]);
1147        signature.extend(std::iter::repeat_n(0x22_u8, 32));
1148
1149        let encoding = inspect_der_encoded_ecdsa_signature(&signature, 32);
1150        assert!(matches!(
1151            encoding,
1152            Err(SignatureVerificationError::InvalidSignatureFormat)
1153        ));
1154    }
1155
1156    #[test]
1157    fn fixed_width_ecdsa_is_encoded_as_canonical_der() {
1158        // Leading zeroes are stripped, while a high-bit magnitude receives the
1159        // sign-protecting zero octet required by DER INTEGER canonicalization.
1160        let mut raw = vec![0_u8; 64];
1161        raw[31] = 1;
1162        raw[32] = 0x80;
1163
1164        let encoded = encode_ecdsa_signature_as_der(&raw).unwrap();
1165        assert_eq!(
1166            encoded,
1167            [
1168                &[0x30, 0x26, 0x02, 0x01, 0x01, 0x02, 0x21, 0x00][..],
1169                &[0x80],
1170                &[0; 31],
1171            ]
1172            .concat()
1173        );
1174        assert_eq!(
1175            inspect_der_encoded_ecdsa_signature(&encoded, 32).unwrap(),
1176            Some(())
1177        );
1178    }
1179
1180    #[test]
1181    fn maximum_der_length_covers_supported_curve_widths() {
1182        // Signing preflight must reserve the worst-case canonical DER framing
1183        // for every supported curve and reject impossible raw widths.
1184        assert_eq!(maximum_ecdsa_der_signature_len(64), Some(72));
1185        assert_eq!(maximum_ecdsa_der_signature_len(96), Some(104));
1186        assert_eq!(maximum_ecdsa_der_signature_len(132), Some(141));
1187        assert_eq!(maximum_ecdsa_der_signature_len(0), None);
1188        assert_eq!(maximum_ecdsa_der_signature_len(65), None);
1189    }
1190}