Skip to main content

xml_sec/
provider.rs

1//! Provider-neutral cryptographic operations.
2//!
3//! XML parsing and protocol orchestration depend on this contract rather than
4//! concrete cryptographic crates. Secret-bearing keys remain opaque behind
5//! operation-specific handles; this provider owns primitive dispatch and
6//! randomness.
7
8#[cfg(feature = "aws-lc-fips")]
9mod aws_lc;
10#[cfg(all(feature = "aws-lc-fips", feature = "xmlenc"))]
11pub use aws_lc::AwsLcRsaPrivateKey;
12#[cfg(feature = "aws-lc-fips")]
13pub use aws_lc::{AwsLcFipsProvider, AwsLcSigningKey};
14
15#[cfg(feature = "xmlenc")]
16use std::borrow::Cow;
17
18#[cfg(any(feature = "xmldsig", feature = "xmlenc"))]
19use getrandom::rand_core::TryCryptoRng;
20use getrandom::{SysRng, rand_core::TryRng};
21
22#[cfg(feature = "xmldsig")]
23use crate::xmldsig::DigestAlgorithm;
24#[cfg(feature = "xmlenc")]
25use crate::xmlenc::{DataEncryptionAlgorithm, KeyWrapAlgorithm, RsaOaepParameters};
26
27/// A cryptographic operation advertised by a provider.
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
29#[non_exhaustive]
30pub enum ProviderOperation {
31    /// Message digest computation.
32    Digest,
33    /// Public-key signature generation.
34    Sign,
35    /// Public-key signature verification.
36    Verify,
37    /// X.509 certificate or CRL signature verification.
38    VerifyCertificate,
39    /// Authenticated or padded symmetric encryption.
40    Encrypt,
41    /// Authenticated or padded symmetric decryption.
42    Decrypt,
43    /// Symmetric key wrapping.
44    KeyWrap,
45    /// Symmetric key unwrapping.
46    KeyUnwrap,
47    /// Public-key key transport.
48    KeyTransport,
49    /// Private-key recovery of transported key bytes.
50    KeyRecovery,
51    /// Key agreement.
52    KeyAgreement,
53    /// Key derivation.
54    Kdf,
55    /// Cryptographically secure random bytes.
56    Random,
57}
58
59/// One exact provider capability, including operation-specific parameters.
60///
61/// Capability discovery describes mechanisms, not policy permission. Callers
62/// must still apply the immutable operation policy before provider dispatch.
63#[derive(Debug, Clone, Copy)]
64#[non_exhaustive]
65pub enum ProviderCapability<'a> {
66    /// Message digest computation for an XMLDSig digest method.
67    #[cfg(feature = "xmldsig")]
68    Digest(DigestAlgorithm),
69    /// Provider dispatch for an XMLDSig signing method.
70    ///
71    /// The opaque signing key remains responsible for accepting the method and
72    /// implementing its primitive.
73    #[cfg(feature = "xmldsig")]
74    Sign(crate::xmldsig::SignatureAlgorithm),
75    /// Provider dispatch for an XMLDSig verification method.
76    ///
77    /// The opaque verification key remains responsible for accepting the
78    /// method and implementing its primitive.
79    #[cfg(feature = "xmldsig")]
80    Verify(crate::xmldsig::SignatureAlgorithm),
81    /// X.509 signature verification with complete algorithm parameters.
82    #[cfg(feature = "xmldsig")]
83    VerifyCertificate(X509SignatureAlgorithm),
84    /// XMLEnc content encryption.
85    #[cfg(feature = "xmlenc")]
86    Encrypt(DataEncryptionAlgorithm),
87    /// XMLEnc content decryption.
88    #[cfg(feature = "xmlenc")]
89    Decrypt(DataEncryptionAlgorithm),
90    /// RFC 3394 key wrapping.
91    #[cfg(feature = "xmlenc")]
92    KeyWrap(KeyWrapAlgorithm),
93    /// RFC 3394 key unwrapping.
94    #[cfg(feature = "xmlenc")]
95    KeyUnwrap(KeyWrapAlgorithm),
96    /// RSA-OAEP key transport with complete digest, MGF, and label parameters.
97    #[cfg(feature = "xmlenc")]
98    KeyTransport(&'a RsaOaepParameters),
99    /// RSA-OAEP key recovery with complete digest, MGF, and label parameters.
100    #[cfg(feature = "xmlenc")]
101    KeyRecovery(&'a RsaOaepParameters),
102    /// Provider-defined key agreement identified by its standard URI.
103    KeyAgreement(&'a KeyAgreementParameters<'a>),
104    /// Provider-defined key derivation identified by its standard URI.
105    Kdf(&'a KdfParameters<'a>),
106    /// Cryptographically secure random byte generation.
107    Random,
108}
109
110impl ProviderCapability<'_> {
111    /// Operation category used in diagnostics.
112    #[must_use]
113    pub const fn operation(&self) -> ProviderOperation {
114        match self {
115            #[cfg(feature = "xmldsig")]
116            Self::Digest(_) => ProviderOperation::Digest,
117            #[cfg(feature = "xmldsig")]
118            Self::Sign(_) => ProviderOperation::Sign,
119            #[cfg(feature = "xmldsig")]
120            Self::Verify(_) => ProviderOperation::Verify,
121            #[cfg(feature = "xmldsig")]
122            Self::VerifyCertificate(_) => ProviderOperation::VerifyCertificate,
123            #[cfg(feature = "xmlenc")]
124            Self::Encrypt(_) => ProviderOperation::Encrypt,
125            #[cfg(feature = "xmlenc")]
126            Self::Decrypt(_) => ProviderOperation::Decrypt,
127            #[cfg(feature = "xmlenc")]
128            Self::KeyWrap(_) => ProviderOperation::KeyWrap,
129            #[cfg(feature = "xmlenc")]
130            Self::KeyUnwrap(_) => ProviderOperation::KeyUnwrap,
131            #[cfg(feature = "xmlenc")]
132            Self::KeyTransport(_) => ProviderOperation::KeyTransport,
133            #[cfg(feature = "xmlenc")]
134            Self::KeyRecovery(_) => ProviderOperation::KeyRecovery,
135            Self::KeyAgreement(_) => ProviderOperation::KeyAgreement,
136            Self::Kdf(_) => ProviderOperation::Kdf,
137            Self::Random => ProviderOperation::Random,
138        }
139    }
140
141    /// Standard algorithm identifier used in unsupported-operation errors.
142    #[must_use]
143    pub fn algorithm(&self) -> Option<&str> {
144        match self {
145            #[cfg(feature = "xmldsig")]
146            Self::Digest(algorithm) => Some(algorithm.uri()),
147            #[cfg(feature = "xmldsig")]
148            Self::Sign(algorithm) | Self::Verify(algorithm) => Some(algorithm.uri()),
149            #[cfg(feature = "xmldsig")]
150            Self::VerifyCertificate(algorithm) => Some(algorithm.oid()),
151            #[cfg(feature = "xmlenc")]
152            Self::Encrypt(algorithm) | Self::Decrypt(algorithm) => Some(algorithm.uri()),
153            #[cfg(feature = "xmlenc")]
154            Self::KeyWrap(algorithm) | Self::KeyUnwrap(algorithm) => Some(algorithm.uri()),
155            #[cfg(feature = "xmlenc")]
156            Self::KeyTransport(parameters) | Self::KeyRecovery(parameters) => {
157                Some(parameters.algorithm.uri())
158            }
159            Self::KeyAgreement(parameters) => Some(parameters.algorithm),
160            Self::Kdf(parameters) => Some(parameters.algorithm),
161            Self::Random => None,
162        }
163    }
164}
165
166/// Provider-neutral parameters for an asymmetric key-agreement operation.
167#[derive(Debug, Clone, Copy, PartialEq, Eq)]
168pub struct KeyAgreementParameters<'a> {
169    /// Standard key-agreement algorithm URI.
170    pub algorithm: &'a str,
171    /// Encoded peer public key in the algorithm's standard wire format.
172    pub peer_public_key: &'a [u8],
173}
174
175/// Provider-neutral parameters for a key-derivation operation.
176#[derive(Debug, Clone, Copy, PartialEq, Eq)]
177pub struct KdfParameters<'a> {
178    /// Standard KDF algorithm URI.
179    pub algorithm: &'a str,
180    /// Optional digest or PRF URI selected by the KDF parameters.
181    pub digest: Option<&'a str>,
182    /// Caller-provided salt, when the KDF defines one.
183    pub salt: &'a [u8],
184    /// Algorithm-specific context bytes such as ConcatKDF OtherInfo or HKDF info.
185    pub info: &'a [u8],
186    /// Policy-validated iteration count for iterative KDFs; zero when not applicable.
187    pub iterations: u64,
188    /// Policy-validated requested output length in bytes.
189    pub output_len: usize,
190}
191
192/// Provider-neutral X.509 certificate and CRL signature parameters.
193#[cfg(feature = "xmldsig")]
194#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
195#[non_exhaustive]
196pub enum X509SignatureAlgorithm {
197    /// DSA with the selected message digest.
198    Dsa(DigestAlgorithm),
199    /// RSASSA-PKCS1-v1_5 with the selected message digest.
200    RsaPkcs1v15(DigestAlgorithm),
201    /// RSASSA-PSS with explicit RFC 4055 parameters.
202    RsaPss {
203        /// Message digest applied to the signed certificate data.
204        digest: DigestAlgorithm,
205        /// Digest used by MGF1.
206        mgf_digest: DigestAlgorithm,
207        /// Salt length in octets.
208        salt_len: usize,
209    },
210    /// ECDSA with the selected message digest; SPKI selects the curve.
211    Ecdsa(DigestAlgorithm),
212    /// Pure Ed25519 as specified by RFC 8410.
213    Ed25519,
214    /// Pure Ed448 as specified by RFC 8410.
215    Ed448,
216    /// Pure ML-DSA or SLH-DSA with the PKIX-mandated empty context.
217    PostQuantum(crate::xmldsig::PqAlgorithm),
218}
219
220#[cfg(feature = "xmldsig")]
221impl X509SignatureAlgorithm {
222    /// Return the standard AlgorithmIdentifier OID used for capability queries.
223    #[must_use]
224    pub const fn oid(self) -> &'static str {
225        match self {
226            Self::Dsa(DigestAlgorithm::Sha1) => "1.2.840.10040.4.3",
227            Self::Dsa(DigestAlgorithm::Sha224) => "2.16.840.1.101.3.4.3.1",
228            Self::Dsa(DigestAlgorithm::Sha256) => "2.16.840.1.101.3.4.3.2",
229            Self::Dsa(DigestAlgorithm::Sha384) => "2.16.840.1.101.3.4.3.3",
230            Self::Dsa(DigestAlgorithm::Sha512) => "2.16.840.1.101.3.4.3.4",
231            Self::Dsa(DigestAlgorithm::Sha3_224) => "2.16.840.1.101.3.4.3.5",
232            Self::Dsa(DigestAlgorithm::Sha3_256) => "2.16.840.1.101.3.4.3.6",
233            Self::Dsa(DigestAlgorithm::Sha3_384) => "2.16.840.1.101.3.4.3.7",
234            Self::Dsa(DigestAlgorithm::Sha3_512) => "2.16.840.1.101.3.4.3.8",
235            Self::RsaPkcs1v15(DigestAlgorithm::Sha1) => "1.2.840.113549.1.1.5",
236            Self::RsaPkcs1v15(DigestAlgorithm::Sha224) => "1.2.840.113549.1.1.14",
237            Self::RsaPkcs1v15(DigestAlgorithm::Sha256) => "1.2.840.113549.1.1.11",
238            Self::RsaPkcs1v15(DigestAlgorithm::Sha384) => "1.2.840.113549.1.1.12",
239            Self::RsaPkcs1v15(DigestAlgorithm::Sha512) => "1.2.840.113549.1.1.13",
240            Self::RsaPkcs1v15(DigestAlgorithm::Sha3_224) => "2.16.840.1.101.3.4.3.13",
241            Self::RsaPkcs1v15(DigestAlgorithm::Sha3_256) => "2.16.840.1.101.3.4.3.14",
242            Self::RsaPkcs1v15(DigestAlgorithm::Sha3_384) => "2.16.840.1.101.3.4.3.15",
243            Self::RsaPkcs1v15(DigestAlgorithm::Sha3_512) => "2.16.840.1.101.3.4.3.16",
244            Self::RsaPss { .. } => "1.2.840.113549.1.1.10",
245            Self::Ecdsa(DigestAlgorithm::Sha1) => "1.2.840.10045.4.1",
246            Self::Ecdsa(DigestAlgorithm::Sha224) => "1.2.840.10045.4.3.1",
247            Self::Ecdsa(DigestAlgorithm::Sha256) => "1.2.840.10045.4.3.2",
248            Self::Ecdsa(DigestAlgorithm::Sha384) => "1.2.840.10045.4.3.3",
249            Self::Ecdsa(DigestAlgorithm::Sha512) => "1.2.840.10045.4.3.4",
250            Self::Ecdsa(DigestAlgorithm::Sha3_224) => "2.16.840.1.101.3.4.3.9",
251            Self::Ecdsa(DigestAlgorithm::Sha3_256) => "2.16.840.1.101.3.4.3.10",
252            Self::Ecdsa(DigestAlgorithm::Sha3_384) => "2.16.840.1.101.3.4.3.11",
253            Self::Ecdsa(DigestAlgorithm::Sha3_512) => "2.16.840.1.101.3.4.3.12",
254            Self::Ed25519 => "1.3.101.112",
255            Self::Ed448 => "1.3.101.113",
256            Self::PostQuantum(algorithm) => algorithm.oid(),
257        }
258    }
259}
260
261/// Structured invalid-input reasons returned by cryptographic providers.
262#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
263#[non_exhaustive]
264pub enum ProviderInputError {
265    /// A primitive rejected a key or IV after its public preconditions were checked.
266    #[error("failed to initialize {0}")]
267    PrimitiveInitialization(&'static str),
268    /// AES-CBC input does not contain an IV followed by complete blocks.
269    #[error("invalid AES-CBC framing")]
270    AesCbcFraming,
271    /// AES-CBC block decryption failed.
272    #[error("invalid AES-CBC ciphertext")]
273    AesCbcCiphertext,
274    /// AES-GCM input does not contain a nonce and authentication tag.
275    #[error("invalid AES-GCM framing")]
276    AesGcmFraming,
277    /// AES key-wrap input or output framing is invalid.
278    #[error("invalid AES key-wrap framing")]
279    AesKeyWrapFraming,
280    /// Legacy compatibility variant retained for downstream construction and matching.
281    ///
282    /// Explicit MGF parameters are valid for both RSA-OAEP URIs, so current providers never
283    /// return this reason.
284    #[deprecated(note = "explicit MGF parameters are supported for both RSA-OAEP URIs")]
285    #[error("legacy RSA-OAEP requires MGF1-SHA1")]
286    LegacyRsaOaepMgf,
287}
288
289/// Failure returned by a cryptographic provider.
290#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
291#[non_exhaustive]
292pub enum ProviderError {
293    /// The selected provider does not implement the operation/parameters.
294    #[error("provider does not support {operation:?} with algorithm {algorithm:?}")]
295    Unsupported {
296        /// Requested operation.
297        operation: ProviderOperation,
298        /// Requested algorithm URI or name.
299        algorithm: Option<String>,
300    },
301    /// A key has the wrong size for the selected algorithm.
302    #[error("invalid key size: expected {expected} bytes, got {actual}")]
303    InvalidKeySize {
304        /// Required key length.
305        expected: usize,
306        /// Supplied key length.
307        actual: usize,
308    },
309    /// A provider reported success but returned bytes that violate the selected
310    /// operation's fixed-size output contract.
311    #[error(
312        "invalid provider output size for {operation:?}: expected {expected} bytes, got {actual}"
313    )]
314    InvalidOutputSize {
315        /// Operation whose output contract was violated.
316        operation: ProviderOperation,
317        /// Exact output length required by the algorithm.
318        expected: usize,
319        /// Actual provider output length.
320        actual: usize,
321    },
322    /// A provider reported success but returned bytes outside the selected
323    /// operation's variable-size output contract.
324    #[error(
325        "invalid provider output size for {operation:?}: expected {minimum}..={maximum} bytes, got {actual}"
326    )]
327    InvalidOutputSizeRange {
328        /// Operation whose output contract was violated.
329        operation: ProviderOperation,
330        /// Smallest output length permitted by the algorithm.
331        minimum: usize,
332        /// Largest output length permitted by the algorithm.
333        maximum: usize,
334        /// Actual provider output length.
335        actual: usize,
336    },
337    /// Input framing, padding, or primitive initialization is invalid.
338    #[error("invalid cryptographic input: {0}")]
339    InvalidInput(ProviderInputError),
340    /// Authenticated decryption or key-wrap integrity validation failed.
341    #[error("cryptographic authentication failed")]
342    AuthenticationFailed,
343    /// Operating-system randomness was unavailable.
344    #[error("operating-system random number generation failed: {0}")]
345    Random(String),
346}
347
348/// Opaque public-key handle used for asymmetric key transport.
349///
350/// Implementations own their key material and operation. The orchestration
351/// layer can inspect only public RSA components needed for policy validation
352/// and output framing; it cannot recover a backend-specific key object.
353#[cfg(feature = "xmlenc")]
354pub trait KeyTransportKey: Send + Sync {
355    /// RSA modulus bytes without redundant leading zero octets.
356    ///
357    /// These components must identify the exact key used by
358    /// [`Self::transport_with_provider`]; returning metadata for another key
359    /// would violate the policy boundary.
360    fn rsa_modulus(&self) -> Cow<'_, [u8]>;
361
362    /// RSA public exponent bytes without redundant leading zero octets.
363    fn rsa_exponent(&self) -> Cow<'_, [u8]>;
364
365    /// Execute OAEP key transport using the selected provider's randomness.
366    fn transport_with_provider(
367        &self,
368        provider: &dyn CryptoProvider,
369        parameters: &RsaOaepParameters,
370        plaintext: &[u8],
371    ) -> Result<Vec<u8>, ProviderError>;
372}
373
374/// Opaque private-key handle used to recover transported key bytes.
375///
376/// Private key material never crosses this boundary. The ciphertext size is
377/// public metadata required to reject malformed RSA inputs before dispatch.
378#[cfg(feature = "xmlenc")]
379pub trait KeyRecoveryKey: Send + Sync {
380    /// Native engine binding; an incompatible provider must reject this handle.
381    fn provider_name(&self) -> Option<&'static str> {
382        None
383    }
384    /// Borrow the matching public SPKI when available for certificate binding.
385    fn public_spki(&self) -> Option<&[u8]> {
386        None
387    }
388    /// Exact mathematical bit length of the recovery key's public modulus,
389    /// excluding leading zero padding. Not the rounded ciphertext width.
390    fn rsa_modulus_bits(&self) -> usize;
391
392    /// Public exponent of that same key, or `None` if wider than 64 bits.
393    /// Opaque providers expose public metadata without copying private material.
394    fn rsa_public_exponent(&self) -> Option<u64>;
395
396    /// Exact RSA ciphertext width in bytes for the key used by
397    /// [`Self::recover_with_provider`].
398    fn ciphertext_len(&self) -> usize;
399
400    /// Execute OAEP recovery using the selected provider's randomness.
401    fn recover_with_provider(
402        &self,
403        provider: &dyn CryptoProvider,
404        parameters: &RsaOaepParameters,
405        ciphertext: &[u8],
406    ) -> Result<Vec<u8>, ProviderError>;
407}
408
409/// Opaque private-key handle used for provider-defined key agreement.
410pub trait KeyAgreementKey: Send + Sync {
411    /// Derive the raw shared secret for the supplied peer and parameters.
412    fn agree(&self, parameters: &KeyAgreementParameters<'_>) -> Result<Vec<u8>, ProviderError>;
413}
414
415/// Stateless provider operations used by the XML Security pipelines.
416pub trait CryptoProvider: Send + Sync {
417    /// Stable provider name for diagnostics and capability reporting.
418    fn name(&self) -> &'static str;
419
420    /// Import original PKCS#8 input into this engine without exporting another
421    /// provider's private handle. Policy and input budgets are enforced by the caller.
422    #[cfg(feature = "xmldsig")]
423    fn import_signing_key(
424        &self,
425        algorithm: crate::xmldsig::SignatureAlgorithm,
426        _pkcs8: &[u8],
427    ) -> Result<Box<dyn crate::xmldsig::SigningKey>, crate::xmldsig::SigningKeyError> {
428        Err(ProviderError::Unsupported {
429            operation: ProviderOperation::Sign,
430            algorithm: Some(algorithm.uri().into()),
431        }
432        .into())
433    }
434
435    /// Import original PKCS#8 input into a provider-owned RSA recovery handle.
436    #[cfg(feature = "xmlenc")]
437    fn import_recovery_key(
438        &self,
439        _pkcs8: &[u8],
440    ) -> Result<std::sync::Arc<dyn KeyRecoveryKey>, ProviderError> {
441        Err(ProviderError::Unsupported {
442            operation: ProviderOperation::KeyRecovery,
443            algorithm: None,
444        })
445    }
446
447    /// Return whether this build can dispatch the requested capability.
448    ///
449    /// [`ProviderCapability::Sign`] and [`ProviderCapability::Verify`] describe
450    /// provider dispatch only: the supplied opaque key performs the executable
451    /// algorithm-support check when the operation runs.
452    fn supports(&self, capability: ProviderCapability<'_>) -> bool;
453
454    /// Fill caller-owned output with cryptographically secure random bytes.
455    fn fill_random(&self, output: &mut [u8]) -> Result<(), ProviderError>;
456
457    /// Compute a message digest.
458    #[cfg(feature = "xmldsig")]
459    fn digest(&self, algorithm: DigestAlgorithm, data: &[u8]) -> Result<Vec<u8>, ProviderError>;
460
461    /// Sign bytes with an opaque key handle.
462    ///
463    /// Providers that delegate primitive signing to the supplied key must call
464    /// [`crate::xmldsig::SigningKey::sign_with_provider`] so randomized
465    /// primitives consume this provider's randomness.
466    #[cfg(feature = "xmldsig")]
467    fn sign(
468        &self,
469        key: &dyn crate::xmldsig::SigningKey,
470        algorithm: crate::xmldsig::SignatureAlgorithm,
471        data: &[u8],
472    ) -> Result<Vec<u8>, crate::xmldsig::SigningKeyError>;
473
474    /// Verify bytes with an opaque key handle.
475    ///
476    /// The XMLDSig facade validates algorithm- and key-specific signature
477    /// framing before this provider boundary.
478    #[cfg(feature = "xmldsig")]
479    fn verify(
480        &self,
481        key: &dyn crate::xmldsig::VerifyingKey,
482        algorithm: crate::xmldsig::SignatureAlgorithm,
483        data: &[u8],
484        signature: &[u8],
485    ) -> Result<bool, crate::xmldsig::DsigError>;
486
487    /// Sign with explicit domain separation; unsupported contexts must not be discarded.
488    #[cfg(feature = "xmldsig")]
489    fn sign_with_context(
490        &self,
491        key: &dyn crate::xmldsig::SigningKey,
492        algorithm: crate::xmldsig::SignatureAlgorithm,
493        context: &crate::xmldsig::SignatureContext,
494        data: &[u8],
495    ) -> Result<Vec<u8>, crate::xmldsig::SigningKeyError> {
496        if !context.as_bytes().is_empty() {
497            return Err(crate::xmldsig::SigningKeyError::UnsupportedAlgorithm {
498                uri: algorithm.uri().to_owned(),
499            });
500        }
501        self.sign(key, algorithm, data)
502    }
503
504    /// Verify with explicit domain separation; unsupported contexts fail closed.
505    #[cfg(feature = "xmldsig")]
506    fn verify_with_context(
507        &self,
508        key: &dyn crate::xmldsig::VerifyingKey,
509        algorithm: crate::xmldsig::SignatureAlgorithm,
510        context: &crate::xmldsig::SignatureContext,
511        data: &[u8],
512        signature: &[u8],
513    ) -> Result<bool, crate::xmldsig::DsigError> {
514        if !context.as_bytes().is_empty() {
515            return Err(
516                crate::xmldsig::SignatureVerificationError::UnsupportedAlgorithm {
517                    uri: algorithm.uri().to_owned(),
518                }
519                .into(),
520            );
521        }
522        self.verify(key, algorithm, data, signature)
523    }
524
525    /// Verify an X.509 certificate or CRL signature under its issuer SPKI.
526    #[cfg(feature = "xmldsig")]
527    fn verify_x509_signature(
528        &self,
529        algorithm: X509SignatureAlgorithm,
530        signed_data: &[u8],
531        signature: &[u8],
532        issuer_spki_der: &[u8],
533    ) -> Result<bool, ProviderError> {
534        let _ = (signed_data, signature, issuer_spki_der);
535        Err(ProviderError::Unsupported {
536            operation: ProviderOperation::VerifyCertificate,
537            algorithm: Some(algorithm.oid().to_owned()),
538        })
539    }
540
541    /// Encrypt XMLEnc content bytes, including standard framing.
542    #[cfg(feature = "xmlenc")]
543    fn encrypt_data(
544        &self,
545        algorithm: DataEncryptionAlgorithm,
546        key: &[u8],
547        plaintext: &[u8],
548    ) -> Result<Vec<u8>, ProviderError>;
549
550    /// Decrypt XMLEnc content bytes, including framing validation.
551    #[cfg(feature = "xmlenc")]
552    fn decrypt_data(
553        &self,
554        algorithm: DataEncryptionAlgorithm,
555        key: &[u8],
556        ciphertext: &[u8],
557    ) -> Result<Vec<u8>, ProviderError>;
558
559    /// Wrap a content key with RFC 3394 AES Key Wrap.
560    ///
561    /// Successful output contains the complete RFC 3394 value and is exactly
562    /// eight bytes longer than `key`. The XMLEnc facade validates that framing
563    /// before serializing provider output.
564    #[cfg(feature = "xmlenc")]
565    fn wrap_key(
566        &self,
567        algorithm: KeyWrapAlgorithm,
568        kek: &[u8],
569        key: &[u8],
570    ) -> Result<Vec<u8>, ProviderError>;
571
572    /// Unwrap a content key with RFC 3394 AES Key Wrap.
573    #[cfg(feature = "xmlenc")]
574    fn unwrap_key(
575        &self,
576        algorithm: KeyWrapAlgorithm,
577        kek: &[u8],
578        wrapped: &[u8],
579    ) -> Result<Vec<u8>, ProviderError>;
580
581    /// Wrap key bytes using an opaque RSA public-key operation.
582    #[cfg(feature = "xmlenc")]
583    fn transport_key(
584        &self,
585        key: &dyn KeyTransportKey,
586        parameters: &RsaOaepParameters,
587        plaintext: &[u8],
588    ) -> Result<Vec<u8>, ProviderError>;
589
590    /// Recover key bytes using an opaque RSA private-key operation.
591    #[cfg(feature = "xmlenc")]
592    fn recover_key(
593        &self,
594        key: &dyn KeyRecoveryKey,
595        parameters: &RsaOaepParameters,
596        ciphertext: &[u8],
597    ) -> Result<Vec<u8>, ProviderError>;
598
599    /// Perform key agreement with an opaque provider-owned private key.
600    fn agree_key(
601        &self,
602        key: &dyn KeyAgreementKey,
603        parameters: &KeyAgreementParameters<'_>,
604    ) -> Result<Vec<u8>, ProviderError> {
605        self.require_capability(ProviderCapability::KeyAgreement(parameters))?;
606        key.agree(parameters)
607    }
608
609    /// Derive key bytes from caller-owned secret material.
610    ///
611    /// Implementations that advertise [`ProviderCapability::Kdf`] must perform
612    /// the advertised derivation here. This method is required so capability
613    /// discovery cannot silently inherit a contradictory unsupported default.
614    fn derive_key(
615        &self,
616        parameters: &KdfParameters<'_>,
617        secret: &[u8],
618    ) -> Result<Vec<u8>, ProviderError>;
619
620    /// Reject an unavailable exact capability without falling back.
621    fn require_capability(&self, capability: ProviderCapability<'_>) -> Result<(), ProviderError> {
622        if self.supports(capability) {
623            Ok(())
624        } else {
625            Err(ProviderError::Unsupported {
626                operation: capability.operation(),
627                algorithm: capability.algorithm().map(str::to_owned),
628            })
629        }
630    }
631}
632
633/// Pure-Rust provider backed by RustCrypto crates.
634#[derive(Debug, Clone, Copy, Default)]
635pub struct RustCryptoProvider;
636
637/// Opaque RSA public-key handle for the built-in RustCrypto provider.
638#[cfg(feature = "xmlenc")]
639#[derive(Clone)]
640pub struct RustCryptoRsaPublicKey {
641    key: rsa::RsaPublicKey,
642    modulus: Vec<u8>,
643    exponent: Vec<u8>,
644}
645
646#[cfg(feature = "xmlenc")]
647impl RustCryptoRsaPublicKey {
648    /// Wrap an already parsed RustCrypto RSA public key.
649    #[must_use]
650    pub fn new(key: rsa::RsaPublicKey) -> Self {
651        use rsa::traits::PublicKeyParts as _;
652        let modulus = key.n().to_be_bytes_trimmed_vartime().into_vec();
653        let exponent = key.e().to_be_bytes_trimmed_vartime().into_vec();
654        Self {
655            key,
656            modulus,
657            exponent,
658        }
659    }
660}
661
662#[cfg(feature = "xmlenc")]
663impl From<rsa::RsaPublicKey> for RustCryptoRsaPublicKey {
664    fn from(key: rsa::RsaPublicKey) -> Self {
665        Self::new(key)
666    }
667}
668
669#[cfg(feature = "xmlenc")]
670impl KeyTransportKey for RustCryptoRsaPublicKey {
671    fn rsa_modulus(&self) -> Cow<'_, [u8]> {
672        Cow::Borrowed(&self.modulus)
673    }
674
675    fn rsa_exponent(&self) -> Cow<'_, [u8]> {
676        Cow::Borrowed(&self.exponent)
677    }
678
679    fn transport_with_provider(
680        &self,
681        provider: &dyn CryptoProvider,
682        parameters: &RsaOaepParameters,
683        plaintext: &[u8],
684    ) -> Result<Vec<u8>, ProviderError> {
685        rustcrypto::transport_key(provider, &self.key, parameters, plaintext)
686    }
687}
688
689#[cfg(feature = "xmlenc")]
690impl KeyTransportKey for rsa::RsaPublicKey {
691    fn rsa_modulus(&self) -> Cow<'_, [u8]> {
692        use rsa::traits::PublicKeyParts as _;
693        Cow::Owned(self.n().to_be_bytes_trimmed_vartime().into_vec())
694    }
695
696    fn rsa_exponent(&self) -> Cow<'_, [u8]> {
697        use rsa::traits::PublicKeyParts as _;
698        Cow::Owned(self.e().to_be_bytes_trimmed_vartime().into_vec())
699    }
700
701    fn transport_with_provider(
702        &self,
703        provider: &dyn CryptoProvider,
704        parameters: &RsaOaepParameters,
705        plaintext: &[u8],
706    ) -> Result<Vec<u8>, ProviderError> {
707        rustcrypto::transport_key(provider, self, parameters, plaintext)
708    }
709}
710
711/// Opaque RSA private-key handle for the built-in RustCrypto provider.
712#[cfg(feature = "xmlenc")]
713#[derive(Clone)]
714pub struct RustCryptoRsaPrivateKey {
715    key: rsa::RsaPrivateKey,
716    ciphertext_len: usize,
717}
718
719#[cfg(feature = "xmlenc")]
720impl RustCryptoRsaPrivateKey {
721    /// Wrap an already parsed RustCrypto RSA private key.
722    #[must_use]
723    pub fn new(key: rsa::RsaPrivateKey) -> Self {
724        use rsa::traits::PublicKeyParts as _;
725        let ciphertext_len = key.size();
726        Self {
727            key,
728            ciphertext_len,
729        }
730    }
731}
732
733#[cfg(feature = "xmlenc")]
734impl From<rsa::RsaPrivateKey> for RustCryptoRsaPrivateKey {
735    fn from(key: rsa::RsaPrivateKey) -> Self {
736        Self::new(key)
737    }
738}
739
740#[cfg(feature = "xmlenc")]
741impl KeyRecoveryKey for RustCryptoRsaPrivateKey {
742    fn rsa_modulus_bits(&self) -> usize {
743        KeyRecoveryKey::rsa_modulus_bits(&self.key)
744    }
745    fn rsa_public_exponent(&self) -> Option<u64> {
746        KeyRecoveryKey::rsa_public_exponent(&self.key)
747    }
748    fn ciphertext_len(&self) -> usize {
749        self.ciphertext_len
750    }
751
752    fn recover_with_provider(
753        &self,
754        provider: &dyn CryptoProvider,
755        parameters: &RsaOaepParameters,
756        ciphertext: &[u8],
757    ) -> Result<Vec<u8>, ProviderError> {
758        rustcrypto::recover_key(provider, &self.key, parameters, ciphertext)
759    }
760}
761
762#[cfg(feature = "xmlenc")]
763impl KeyRecoveryKey for rsa::RsaPrivateKey {
764    fn rsa_modulus_bits(&self) -> usize {
765        use rsa::traits::PublicKeyParts as _;
766        self.n().bits_vartime() as usize
767    }
768    fn rsa_public_exponent(&self) -> Option<u64> {
769        use rsa::traits::PublicKeyParts as _;
770        if self.e().bits_vartime() > 64 {
771            return None;
772        }
773        let mut exponent = 0_u64;
774        let word_bits = crypto_bigint::Word::BITS as usize;
775        for (index, word) in self.e().as_words().iter().take(64 / word_bits).enumerate() {
776            #[cfg(target_pointer_width = "64")]
777            let word = *word;
778            #[cfg(target_pointer_width = "32")]
779            let word = u64::from(*word);
780            exponent |= word << (index * word_bits);
781        }
782        Some(exponent)
783    }
784    fn ciphertext_len(&self) -> usize {
785        use rsa::traits::PublicKeyParts as _;
786        self.size()
787    }
788
789    fn recover_with_provider(
790        &self,
791        provider: &dyn CryptoProvider,
792        parameters: &RsaOaepParameters,
793        ciphertext: &[u8],
794    ) -> Result<Vec<u8>, ProviderError> {
795        rustcrypto::recover_key(provider, self, parameters, ciphertext)
796    }
797}
798
799/// Process-wide immutable default provider. It contains no mutable state or keys.
800pub static RUST_CRYPTO_PROVIDER: RustCryptoProvider = RustCryptoProvider;
801
802/// Borrow the pure-Rust default provider.
803#[must_use]
804pub fn default_provider() -> &'static dyn CryptoProvider {
805    &RUST_CRYPTO_PROVIDER
806}
807
808/// Adapter used when a RustCrypto primitive requires a fallible RNG object.
809#[cfg(any(feature = "xmldsig", feature = "xmlenc"))]
810pub(crate) struct ProviderRng<'a>(pub(crate) &'a dyn CryptoProvider);
811
812#[cfg(any(feature = "xmldsig", feature = "xmlenc"))]
813impl TryRng for ProviderRng<'_> {
814    type Error = ProviderError;
815
816    fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
817        let mut bytes = [0_u8; 4];
818        self.try_fill_bytes(&mut bytes)?;
819        Ok(u32::from_le_bytes(bytes))
820    }
821
822    fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
823        let mut bytes = [0_u8; 8];
824        self.try_fill_bytes(&mut bytes)?;
825        Ok(u64::from_le_bytes(bytes))
826    }
827
828    fn try_fill_bytes(&mut self, output: &mut [u8]) -> Result<(), Self::Error> {
829        self.0.fill_random(output)
830    }
831}
832
833#[cfg(any(feature = "xmldsig", feature = "xmlenc"))]
834impl TryCryptoRng for ProviderRng<'_> {}
835
836impl CryptoProvider for RustCryptoProvider {
837    fn name(&self) -> &'static str {
838        "rustcrypto"
839    }
840
841    #[cfg(feature = "xmlenc")]
842    fn import_recovery_key(
843        &self,
844        pkcs8: &[u8],
845    ) -> Result<std::sync::Arc<dyn KeyRecoveryKey>, ProviderError> {
846        use rsa::pkcs8::DecodePrivateKey as _;
847        let key = rsa::RsaPrivateKey::from_pkcs8_der(pkcs8).map_err(|_| {
848            ProviderError::InvalidInput(ProviderInputError::PrimitiveInitialization(
849                "RSA recovery key",
850            ))
851        })?;
852        Ok(std::sync::Arc::new(RustCryptoRsaPrivateKey::new(key)))
853    }
854
855    #[cfg(feature = "xmldsig")]
856    fn import_signing_key(
857        &self,
858        algorithm: crate::xmldsig::SignatureAlgorithm,
859        der: &[u8],
860    ) -> Result<Box<dyn crate::xmldsig::SigningKey>, crate::xmldsig::SigningKeyError> {
861        use crate::xmldsig::{SignatureAlgorithm as A, *};
862        Ok(match algorithm {
863            #[cfg(feature = "experimental-pq")]
864            A::PostQuantum(parameter) => {
865                Box::new(PostQuantumSigningKey::from_pkcs8_der(parameter, der)?)
866            }
867            A::Ed25519 | A::Ed25519Ctx | A::Ed25519Ph | A::Ed448 | A::Ed448Ph => {
868                Box::new(EdDsaSigningKey::from_pkcs8_der(algorithm, der)?)
869            }
870            A::RsaSha1 | A::RsaSha224 | A::RsaSha256 | A::RsaSha384 | A::RsaSha512 => {
871                Box::new(RsaSigningKey::from_pkcs8_der(der)?)
872            }
873            A::DsaSha1 | A::DsaSha256 => Box::new(DsaSigningKey::from_pkcs8_der(der)?),
874            A::EcdsaSha1
875            | A::EcdsaSha224
876            | A::EcdsaSha256
877            | A::EcdsaSha384
878            | A::EcdsaSha512
879            | A::EcdsaSha3_224
880            | A::EcdsaSha3_256
881            | A::EcdsaSha3_384
882            | A::EcdsaSha3_512 => {
883                if let Ok(key) = EcdsaP256SigningKey::from_pkcs8_der(der) {
884                    Box::new(key)
885                } else if let Ok(key) = EcdsaP384SigningKey::from_pkcs8_der(der) {
886                    Box::new(key)
887                } else {
888                    Box::new(EcdsaP521SigningKey::from_pkcs8_der(der)?)
889                }
890            }
891            _ => {
892                return Err(SigningKeyError::UnsupportedAlgorithm {
893                    uri: algorithm.uri().into(),
894                });
895            }
896        })
897    }
898
899    fn supports(&self, capability: ProviderCapability<'_>) -> bool {
900        match capability {
901            #[cfg(feature = "xmldsig")]
902            ProviderCapability::Digest(_) => true,
903            #[cfg(feature = "xmldsig")]
904            // Opaque keys own these primitives and reject unsupported methods
905            // during dispatch; the provider advertises its dispatch surface.
906            ProviderCapability::Sign(algorithm) | ProviderCapability::Verify(algorithm) => {
907                !matches!(
908                    algorithm,
909                    crate::xmldsig::SignatureAlgorithm::PostQuantum(_)
910                ) || cfg!(feature = "experimental-pq")
911            }
912            #[cfg(feature = "xmldsig")]
913            ProviderCapability::VerifyCertificate(algorithm) => {
914                is_supported_x509_signature(algorithm)
915            }
916            #[cfg(feature = "xmlenc")]
917            ProviderCapability::Encrypt(_) | ProviderCapability::Decrypt(_) => true,
918            #[cfg(feature = "xmlenc")]
919            ProviderCapability::KeyWrap(_) | ProviderCapability::KeyUnwrap(_) => true,
920            #[cfg(feature = "xmlenc")]
921            ProviderCapability::KeyTransport(_) | ProviderCapability::KeyRecovery(_) => true,
922            ProviderCapability::Random => true,
923            ProviderCapability::KeyAgreement(_) | ProviderCapability::Kdf(_) => false,
924        }
925    }
926
927    fn fill_random(&self, output: &mut [u8]) -> Result<(), ProviderError> {
928        SysRng
929            .try_fill_bytes(output)
930            .map_err(|error| ProviderError::Random(error.to_string()))
931    }
932
933    fn derive_key(
934        &self,
935        parameters: &KdfParameters<'_>,
936        _secret: &[u8],
937    ) -> Result<Vec<u8>, ProviderError> {
938        self.require_capability(ProviderCapability::Kdf(parameters))?;
939        Err(ProviderError::Unsupported {
940            operation: ProviderOperation::Kdf,
941            algorithm: Some(parameters.algorithm.to_owned()),
942        })
943    }
944
945    #[cfg(feature = "xmldsig")]
946    fn digest(&self, algorithm: DigestAlgorithm, data: &[u8]) -> Result<Vec<u8>, ProviderError> {
947        use sha1::Sha1;
948        use sha2::{Digest, Sha224, Sha256, Sha384, Sha512};
949        use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512};
950        Ok(match algorithm {
951            DigestAlgorithm::Sha1 => Sha1::digest(data).to_vec(),
952            DigestAlgorithm::Sha224 => Sha224::digest(data).to_vec(),
953            DigestAlgorithm::Sha256 => Sha256::digest(data).to_vec(),
954            DigestAlgorithm::Sha384 => Sha384::digest(data).to_vec(),
955            DigestAlgorithm::Sha512 => Sha512::digest(data).to_vec(),
956            DigestAlgorithm::Sha3_224 => Sha3_224::digest(data).to_vec(),
957            DigestAlgorithm::Sha3_256 => Sha3_256::digest(data).to_vec(),
958            DigestAlgorithm::Sha3_384 => Sha3_384::digest(data).to_vec(),
959            DigestAlgorithm::Sha3_512 => Sha3_512::digest(data).to_vec(),
960        })
961    }
962
963    #[cfg(feature = "xmldsig")]
964    fn sign(
965        &self,
966        key: &dyn crate::xmldsig::SigningKey,
967        algorithm: crate::xmldsig::SignatureAlgorithm,
968        data: &[u8],
969    ) -> Result<Vec<u8>, crate::xmldsig::SigningKeyError> {
970        self.require_capability(ProviderCapability::Sign(algorithm))?;
971        key.sign_with_provider(self, algorithm, data)
972    }
973
974    #[cfg(feature = "xmldsig")]
975    fn sign_with_context(
976        &self,
977        key: &dyn crate::xmldsig::SigningKey,
978        algorithm: crate::xmldsig::SignatureAlgorithm,
979        context: &crate::xmldsig::SignatureContext,
980        data: &[u8],
981    ) -> Result<Vec<u8>, crate::xmldsig::SigningKeyError> {
982        self.require_capability(ProviderCapability::Sign(algorithm))?;
983        key.sign_with_provider_context(self, algorithm, context, data)
984    }
985
986    #[cfg(feature = "xmldsig")]
987    fn verify_with_context(
988        &self,
989        key: &dyn crate::xmldsig::VerifyingKey,
990        algorithm: crate::xmldsig::SignatureAlgorithm,
991        context: &crate::xmldsig::SignatureContext,
992        data: &[u8],
993        signature: &[u8],
994    ) -> Result<bool, crate::xmldsig::DsigError> {
995        self.require_capability(ProviderCapability::Verify(algorithm))?;
996        key.verify_with_context(algorithm, context, data, signature)
997    }
998
999    #[cfg(feature = "xmldsig")]
1000    fn verify(
1001        &self,
1002        key: &dyn crate::xmldsig::VerifyingKey,
1003        algorithm: crate::xmldsig::SignatureAlgorithm,
1004        data: &[u8],
1005        signature: &[u8],
1006    ) -> Result<bool, crate::xmldsig::DsigError> {
1007        self.require_capability(ProviderCapability::Verify(algorithm))?;
1008        key.verify(algorithm, data, signature)
1009    }
1010
1011    #[cfg(feature = "xmldsig")]
1012    fn verify_x509_signature(
1013        &self,
1014        algorithm: X509SignatureAlgorithm,
1015        signed_data: &[u8],
1016        signature: &[u8],
1017        issuer_spki_der: &[u8],
1018    ) -> Result<bool, ProviderError> {
1019        rustcrypto_x509::verify_signature(algorithm, signed_data, signature, issuer_spki_der)
1020    }
1021
1022    #[cfg(feature = "xmlenc")]
1023    fn encrypt_data(
1024        &self,
1025        algorithm: DataEncryptionAlgorithm,
1026        key: &[u8],
1027        plaintext: &[u8],
1028    ) -> Result<Vec<u8>, ProviderError> {
1029        rustcrypto::encrypt_data(self, algorithm, key, plaintext)
1030    }
1031
1032    #[cfg(feature = "xmlenc")]
1033    fn decrypt_data(
1034        &self,
1035        algorithm: DataEncryptionAlgorithm,
1036        key: &[u8],
1037        ciphertext: &[u8],
1038    ) -> Result<Vec<u8>, ProviderError> {
1039        rustcrypto::decrypt_data(algorithm, key, ciphertext)
1040    }
1041
1042    #[cfg(feature = "xmlenc")]
1043    fn wrap_key(
1044        &self,
1045        algorithm: KeyWrapAlgorithm,
1046        kek: &[u8],
1047        key: &[u8],
1048    ) -> Result<Vec<u8>, ProviderError> {
1049        rustcrypto::wrap_key(algorithm, kek, key)
1050    }
1051
1052    #[cfg(feature = "xmlenc")]
1053    fn unwrap_key(
1054        &self,
1055        algorithm: KeyWrapAlgorithm,
1056        kek: &[u8],
1057        wrapped: &[u8],
1058    ) -> Result<Vec<u8>, ProviderError> {
1059        rustcrypto::unwrap_key(algorithm, kek, wrapped)
1060    }
1061
1062    #[cfg(feature = "xmlenc")]
1063    fn transport_key(
1064        &self,
1065        key: &dyn KeyTransportKey,
1066        parameters: &RsaOaepParameters,
1067        plaintext: &[u8],
1068    ) -> Result<Vec<u8>, ProviderError> {
1069        self.require_capability(ProviderCapability::KeyTransport(parameters))?;
1070        key.transport_with_provider(self, parameters, plaintext)
1071    }
1072
1073    #[cfg(feature = "xmlenc")]
1074    fn recover_key(
1075        &self,
1076        key: &dyn KeyRecoveryKey,
1077        parameters: &RsaOaepParameters,
1078        ciphertext: &[u8],
1079    ) -> Result<Vec<u8>, ProviderError> {
1080        self.require_capability(ProviderCapability::KeyRecovery(parameters))?;
1081        key.recover_with_provider(self, parameters, ciphertext)
1082    }
1083}
1084
1085#[cfg(feature = "xmldsig")]
1086fn is_supported_x509_signature(algorithm: X509SignatureAlgorithm) -> bool {
1087    match algorithm {
1088        X509SignatureAlgorithm::Dsa(DigestAlgorithm::Sha1)
1089        | X509SignatureAlgorithm::Ed25519
1090        | X509SignatureAlgorithm::Ed448 => true,
1091        X509SignatureAlgorithm::Ecdsa(_) => true,
1092        X509SignatureAlgorithm::PostQuantum(_) => cfg!(feature = "experimental-pq"),
1093        X509SignatureAlgorithm::RsaPkcs1v15(digest) => matches!(
1094            digest,
1095            DigestAlgorithm::Sha1
1096                | DigestAlgorithm::Sha224
1097                | DigestAlgorithm::Sha256
1098                | DigestAlgorithm::Sha384
1099                | DigestAlgorithm::Sha512
1100        ),
1101        X509SignatureAlgorithm::RsaPss {
1102            digest, mgf_digest, ..
1103        } => {
1104            matches!(
1105                digest,
1106                DigestAlgorithm::Sha256 | DigestAlgorithm::Sha384 | DigestAlgorithm::Sha512
1107            ) && digest == mgf_digest
1108        }
1109        X509SignatureAlgorithm::Dsa(_) => false,
1110    }
1111}
1112
1113#[cfg(feature = "xmldsig")]
1114mod rustcrypto_x509 {
1115    use der::Decode as _;
1116    use dsa::pkcs8::DecodePublicKey as _;
1117    use rsa::{
1118        RsaPublicKey,
1119        pkcs1::DecodeRsaPublicKey as _,
1120        pss::{Signature as RsaPssSignature, VerifyingKey as RsaPssVerifyingKey},
1121        traits::PublicKeyParts as _,
1122    };
1123    use sha1::Digest as _;
1124    use sha2::{Sha256, Sha384, Sha512};
1125    use signature::{Verifier as _, hazmat::PrehashVerifier as _};
1126    use x509_parser::prelude::FromDer as _;
1127
1128    use super::{ProviderError, X509SignatureAlgorithm};
1129    use crate::xmldsig::signature::verify_ecdsa_signature_spki_asn1_der;
1130    use crate::xmldsig::{
1131        DigestAlgorithm, DsigError, SignatureAlgorithm, VerificationKey, VerifyingKey as _,
1132    };
1133
1134    pub(super) fn verify_signature(
1135        algorithm: X509SignatureAlgorithm,
1136        signed_data: &[u8],
1137        signature: &[u8],
1138        issuer_spki_der: &[u8],
1139    ) -> Result<bool, ProviderError> {
1140        match algorithm {
1141            X509SignatureAlgorithm::Dsa(DigestAlgorithm::Sha1) => {
1142                // Certificate signatures are ASN.1 DER integers sized by the
1143                // issuer's q parameter. XMLDSig's fixed 20-byte r||s framing
1144                // applies only to SignatureValue, never to X.509 signatures.
1145                let Ok(key) = crate::xmldsig::signature::decode_dsa_verifying_key(issuer_spki_der)
1146                else {
1147                    return Ok(false);
1148                };
1149                let Ok(signature) = dsa::Signature::from_der(signature) else {
1150                    return Ok(false);
1151                };
1152                let digest = sha1::Sha1::digest(signed_data);
1153                Ok(key.verify_prehash(&digest, &signature).is_ok())
1154            }
1155            X509SignatureAlgorithm::RsaPkcs1v15(digest) => {
1156                let Some(algorithm) = rsa_pkcs1_algorithm(digest) else {
1157                    return unsupported(X509SignatureAlgorithm::RsaPkcs1v15(digest));
1158                };
1159                verify_xml_signature(algorithm, signed_data, signature, issuer_spki_der)
1160            }
1161            X509SignatureAlgorithm::Ecdsa(digest) => {
1162                let Some(algorithm) = ecdsa_algorithm(digest) else {
1163                    return unsupported(X509SignatureAlgorithm::Ecdsa(digest));
1164                };
1165                // RFC 5280 ECDSA certificate signatures are always ASN.1 DER;
1166                // XMLDSig's SignatureValue framing policy is irrelevant here.
1167                match verify_ecdsa_signature_spki_asn1_der(
1168                    algorithm,
1169                    issuer_spki_der,
1170                    signed_data,
1171                    signature,
1172                ) {
1173                    Ok(verified) => Ok(verified),
1174                    Err(_) => Ok(false),
1175                }
1176            }
1177            X509SignatureAlgorithm::RsaPss {
1178                digest,
1179                mgf_digest,
1180                salt_len,
1181            } => {
1182                // RFC 4055 key restrictions are part of signature validity. Check
1183                // them before provider capability so an incompatible key is a
1184                // deterministic non-match even when the requested MGF is unsupported.
1185                let Some(key) = compatible_rsa_pss_public_key_from_spki(issuer_spki_der, algorithm)
1186                else {
1187                    return Ok(false);
1188                };
1189                if digest != mgf_digest {
1190                    return unsupported(algorithm);
1191                }
1192                verify_rsa_pss(digest, salt_len, signed_data, signature, key)
1193            }
1194            X509SignatureAlgorithm::Ed25519 => {
1195                let Ok(key) = ed25519_dalek::VerifyingKey::from_public_key_der(issuer_spki_der)
1196                else {
1197                    return Ok(false);
1198                };
1199                let Ok(signature) = ed25519_dalek::Signature::try_from(signature) else {
1200                    return Ok(false);
1201                };
1202                Ok(key.verify_strict(signed_data, &signature).is_ok())
1203            }
1204            X509SignatureAlgorithm::Ed448 => {
1205                // RFC 8410 sections 3 and 6 select pure Ed448 without context
1206                // or external prehash: https://www.rfc-editor.org/rfc/rfc8410.html#section-6
1207                let Ok(key) = ed448_goldilocks::VerifyingKey::from_public_key_der(issuer_spki_der)
1208                else {
1209                    return Ok(false);
1210                };
1211                let Ok(signature) = ed448_goldilocks::Signature::try_from(signature) else {
1212                    return Ok(false);
1213                };
1214                Ok(key.verify_raw(&signature, signed_data).is_ok())
1215            }
1216            #[cfg(feature = "experimental-pq")]
1217            X509SignatureAlgorithm::PostQuantum(algorithm) => {
1218                // RFC 9881 §3 and RFC 9909 §§1, 4 require pure signatures
1219                // over the DER object with an empty context, not an XML context.
1220                // https://www.rfc-editor.org/rfc/rfc9881.html#section-3
1221                // https://www.rfc-editor.org/rfc/rfc9909.html#section-4
1222                Ok(crate::xmldsig::post_quantum::verify(
1223                    algorithm,
1224                    issuer_spki_der,
1225                    &crate::xmldsig::SignatureContext::default(),
1226                    signed_data,
1227                    signature,
1228                )
1229                .unwrap_or(false))
1230            }
1231            _ => unsupported(algorithm),
1232        }
1233    }
1234
1235    fn verify_xml_signature(
1236        algorithm: SignatureAlgorithm,
1237        signed_data: &[u8],
1238        signature: &[u8],
1239        issuer_spki_der: &[u8],
1240    ) -> Result<bool, ProviderError> {
1241        let key = VerificationKey {
1242            algorithm,
1243            public_key_bytes: issuer_spki_der.to_vec(),
1244            certificate_der: None,
1245            name: None,
1246        };
1247        match key.verify(algorithm, signed_data, signature) {
1248            Ok(verified) => Ok(verified),
1249            Err(DsigError::Provider(error)) => Err(error),
1250            Err(_) => Ok(false),
1251        }
1252    }
1253
1254    fn verify_rsa_pss(
1255        digest: DigestAlgorithm,
1256        salt_len: usize,
1257        signed_data: &[u8],
1258        signature: &[u8],
1259        key: RsaPublicKey,
1260    ) -> Result<bool, ProviderError> {
1261        if !rsa_pss_salt_fits_key(&key, digest, salt_len) {
1262            return Ok(false);
1263        }
1264        let Ok(signature) = RsaPssSignature::try_from(signature) else {
1265            return Ok(false);
1266        };
1267        let verified = match digest {
1268            DigestAlgorithm::Sha256 => {
1269                RsaPssVerifyingKey::<Sha256>::new_with_salt_len(key, salt_len)
1270                    .verify(signed_data, &signature)
1271            }
1272            DigestAlgorithm::Sha384 => {
1273                RsaPssVerifyingKey::<Sha384>::new_with_salt_len(key, salt_len)
1274                    .verify(signed_data, &signature)
1275            }
1276            DigestAlgorithm::Sha512 => {
1277                RsaPssVerifyingKey::<Sha512>::new_with_salt_len(key, salt_len)
1278                    .verify(signed_data, &signature)
1279            }
1280            _ => {
1281                return unsupported(X509SignatureAlgorithm::RsaPss {
1282                    digest,
1283                    mgf_digest: digest,
1284                    salt_len,
1285                });
1286            }
1287        };
1288        Ok(verified.is_ok())
1289    }
1290
1291    pub(super) fn rsa_pss_salt_fits_key(
1292        key: &RsaPublicKey,
1293        digest: DigestAlgorithm,
1294        salt_len: usize,
1295    ) -> bool {
1296        let Some(em_bits) = key.n().bits().checked_sub(1) else {
1297            return false;
1298        };
1299        let Ok(em_len) = usize::try_from(em_bits.div_ceil(8)) else {
1300            return false;
1301        };
1302        digest
1303            .output_len()
1304            .checked_add(salt_len)
1305            .and_then(|length| length.checked_add(2))
1306            .is_some_and(|required| required <= em_len)
1307    }
1308
1309    fn compatible_rsa_pss_public_key_from_spki(
1310        spki_der: &[u8],
1311        signature_algorithm: X509SignatureAlgorithm,
1312    ) -> Option<RsaPublicKey> {
1313        let (_, spki) = x509_parser::x509::SubjectPublicKeyInfo::from_der(spki_der).ok()?;
1314        match spki.algorithm.algorithm.to_id_string().as_str() {
1315            "1.2.840.113549.1.1.1" => RsaPublicKey::from_public_key_der(spki_der).ok(),
1316            "1.2.840.113549.1.1.10" => {
1317                // RFC 4055 section 3.3 applies key restrictions only when
1318                // RSASSA-PSS-params is present in SubjectPublicKeyInfo.
1319                if spki
1320                    .algorithm
1321                    .parameters
1322                    .as_ref()
1323                    .is_some_and(|parameters| {
1324                        !rsa_pss_key_parameters_allow(parameters, signature_algorithm)
1325                    })
1326                {
1327                    return None;
1328                }
1329                RsaPublicKey::from_pkcs1_der(&spki.subject_public_key.data).ok()
1330            }
1331            _ => None,
1332        }
1333    }
1334
1335    fn rsa_pss_key_parameters_allow(
1336        parameters: &x509_parser::asn1_rs::Any<'_>,
1337        signature_algorithm: X509SignatureAlgorithm,
1338    ) -> bool {
1339        let X509SignatureAlgorithm::RsaPss {
1340            digest,
1341            mgf_digest,
1342            salt_len,
1343        } = signature_algorithm
1344        else {
1345            return false;
1346        };
1347        let Ok(parameters) =
1348            x509_parser::signature_algorithm::RsaSsaPssParams::try_from(parameters)
1349        else {
1350            return false;
1351        };
1352        let Ok(mask) = parameters.mask_gen_algorithm() else {
1353            return false;
1354        };
1355        parameters.trailer_field() == 1
1356            && x509_digest_from_oid(&parameters.hash_algorithm_oid().to_id_string()) == Some(digest)
1357            && mask.mgf.to_id_string() == "1.2.840.113549.1.1.8"
1358            && x509_digest_from_oid(&mask.hash.to_id_string()) == Some(mgf_digest)
1359            && usize::try_from(parameters.salt_length()).is_ok_and(|minimum| salt_len >= minimum)
1360    }
1361
1362    fn x509_digest_from_oid(oid: &str) -> Option<DigestAlgorithm> {
1363        match oid {
1364            "1.3.14.3.2.26" => Some(DigestAlgorithm::Sha1),
1365            "2.16.840.1.101.3.4.2.4" => Some(DigestAlgorithm::Sha224),
1366            "2.16.840.1.101.3.4.2.1" => Some(DigestAlgorithm::Sha256),
1367            "2.16.840.1.101.3.4.2.2" => Some(DigestAlgorithm::Sha384),
1368            "2.16.840.1.101.3.4.2.3" => Some(DigestAlgorithm::Sha512),
1369            _ => None,
1370        }
1371    }
1372
1373    const fn rsa_pkcs1_algorithm(digest: DigestAlgorithm) -> Option<SignatureAlgorithm> {
1374        match digest {
1375            DigestAlgorithm::Sha1 => Some(SignatureAlgorithm::RsaSha1),
1376            DigestAlgorithm::Sha224 => Some(SignatureAlgorithm::RsaSha224),
1377            DigestAlgorithm::Sha256 => Some(SignatureAlgorithm::RsaSha256),
1378            DigestAlgorithm::Sha384 => Some(SignatureAlgorithm::RsaSha384),
1379            DigestAlgorithm::Sha512 => Some(SignatureAlgorithm::RsaSha512),
1380            _ => None,
1381        }
1382    }
1383
1384    const fn ecdsa_algorithm(digest: DigestAlgorithm) -> Option<SignatureAlgorithm> {
1385        match digest {
1386            DigestAlgorithm::Sha1 => Some(SignatureAlgorithm::EcdsaSha1),
1387            DigestAlgorithm::Sha224 => Some(SignatureAlgorithm::EcdsaSha224),
1388            DigestAlgorithm::Sha256 => Some(SignatureAlgorithm::EcdsaSha256),
1389            DigestAlgorithm::Sha384 => Some(SignatureAlgorithm::EcdsaSha384),
1390            DigestAlgorithm::Sha512 => Some(SignatureAlgorithm::EcdsaSha512),
1391            DigestAlgorithm::Sha3_224 => Some(SignatureAlgorithm::EcdsaSha3_224),
1392            DigestAlgorithm::Sha3_256 => Some(SignatureAlgorithm::EcdsaSha3_256),
1393            DigestAlgorithm::Sha3_384 => Some(SignatureAlgorithm::EcdsaSha3_384),
1394            DigestAlgorithm::Sha3_512 => Some(SignatureAlgorithm::EcdsaSha3_512),
1395        }
1396    }
1397
1398    fn unsupported<T>(algorithm: X509SignatureAlgorithm) -> Result<T, ProviderError> {
1399        Err(ProviderError::Unsupported {
1400            operation: super::ProviderOperation::VerifyCertificate,
1401            algorithm: Some(algorithm.oid().to_owned()),
1402        })
1403    }
1404}
1405
1406#[cfg(feature = "xmlenc")]
1407mod rustcrypto {
1408    use aes::{
1409        Aes128, Aes256,
1410        cipher::{BlockModeDecrypt, BlockModeEncrypt, KeyIvInit, block_padding::NoPadding},
1411    };
1412    use aes_gcm::{
1413        Aes128Gcm, Aes256Gcm, Nonce,
1414        aead::{AeadInOut, KeyInit},
1415    };
1416    use aes_kw::{KwAes128, KwAes256};
1417    use cbc::{Decryptor, Encryptor};
1418    use rsa::{Oaep, traits::PaddingScheme};
1419    use sha1::Sha1;
1420    use sha2::{Sha256, Sha384, Sha512};
1421
1422    use super::{CryptoProvider, ProviderError, ProviderInputError};
1423    use crate::xmlenc::{
1424        DataEncryptionAlgorithm, KeyWrapAlgorithm, OaepDigestAlgorithm, RsaOaepParameters,
1425    };
1426
1427    pub(super) fn encrypt_data(
1428        provider: &dyn CryptoProvider,
1429        algorithm: DataEncryptionAlgorithm,
1430        key: &[u8],
1431        plaintext: &[u8],
1432    ) -> Result<Vec<u8>, ProviderError> {
1433        check_key(algorithm.key_len(), key)?;
1434        match algorithm {
1435            DataEncryptionAlgorithm::Aes128Cbc => encrypt_cbc::<Aes128>(provider, key, plaintext),
1436            DataEncryptionAlgorithm::Aes256Cbc => encrypt_cbc::<Aes256>(provider, key, plaintext),
1437            DataEncryptionAlgorithm::Aes128Gcm => {
1438                encrypt_gcm::<Aes128Gcm>(provider, key, plaintext)
1439            }
1440            DataEncryptionAlgorithm::Aes256Gcm => {
1441                encrypt_gcm::<Aes256Gcm>(provider, key, plaintext)
1442            }
1443        }
1444    }
1445
1446    pub(super) fn decrypt_data(
1447        algorithm: DataEncryptionAlgorithm,
1448        key: &[u8],
1449        ciphertext: &[u8],
1450    ) -> Result<Vec<u8>, ProviderError> {
1451        check_key(algorithm.key_len(), key)?;
1452        match algorithm {
1453            DataEncryptionAlgorithm::Aes128Cbc => decrypt_cbc::<Aes128>(key, ciphertext),
1454            DataEncryptionAlgorithm::Aes256Cbc => decrypt_cbc::<Aes256>(key, ciphertext),
1455            DataEncryptionAlgorithm::Aes128Gcm => decrypt_gcm::<Aes128Gcm>(key, ciphertext),
1456            DataEncryptionAlgorithm::Aes256Gcm => decrypt_gcm::<Aes256Gcm>(key, ciphertext),
1457        }
1458    }
1459
1460    fn check_key(expected: usize, key: &[u8]) -> Result<(), ProviderError> {
1461        if key.len() == expected {
1462            Ok(())
1463        } else {
1464            Err(ProviderError::InvalidKeySize {
1465                expected,
1466                actual: key.len(),
1467            })
1468        }
1469    }
1470
1471    fn encrypt_cbc<C>(
1472        provider: &dyn CryptoProvider,
1473        key: &[u8],
1474        plaintext: &[u8],
1475    ) -> Result<Vec<u8>, ProviderError>
1476    where
1477        C: aes::cipher::BlockCipherEncrypt + aes::cipher::KeyInit,
1478    {
1479        let mut iv = [0_u8; 16];
1480        provider.fill_random(&mut iv)?;
1481        let pad_len = 16 - (plaintext.len() % 16);
1482        let mut padded = vec![0_u8; plaintext.len() + pad_len];
1483        padded[..plaintext.len()].copy_from_slice(plaintext);
1484        if pad_len > 1 {
1485            let last = padded.len() - 1;
1486            provider.fill_random(&mut padded[plaintext.len()..last])?;
1487        }
1488        *padded.last_mut().expect("padding is non-empty") = pad_len as u8;
1489        Encryptor::<C>::new_from_slices(key, &iv)
1490            .map_err(|_| {
1491                ProviderError::InvalidInput(ProviderInputError::PrimitiveInitialization("AES-CBC"))
1492            })?
1493            .encrypt_padded::<NoPadding>(&mut padded, plaintext.len() + pad_len)
1494            .map_err(|_| {
1495                ProviderError::InvalidInput(ProviderInputError::PrimitiveInitialization(
1496                    "AES-CBC padding",
1497                ))
1498            })?;
1499        let mut output = Vec::with_capacity(16 + padded.len());
1500        output.extend_from_slice(&iv);
1501        output.extend_from_slice(&padded);
1502        Ok(output)
1503    }
1504
1505    fn decrypt_cbc<C>(key: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>, ProviderError>
1506    where
1507        C: aes::cipher::BlockCipherDecrypt + aes::cipher::KeyInit,
1508    {
1509        if ciphertext.len() < 32 || !(ciphertext.len() - 16).is_multiple_of(16) {
1510            return Err(ProviderError::InvalidInput(
1511                ProviderInputError::AesCbcFraming,
1512            ));
1513        }
1514        let (iv, body) = ciphertext.split_at(16);
1515        let mut plaintext = body.to_vec();
1516        Decryptor::<C>::new_from_slices(key, iv)
1517            .map_err(|_| {
1518                ProviderError::InvalidInput(ProviderInputError::PrimitiveInitialization("AES-CBC"))
1519            })?
1520            .decrypt_padded::<NoPadding>(&mut plaintext)
1521            .map_err(|_| ProviderError::InvalidInput(ProviderInputError::AesCbcCiphertext))?;
1522        let pad_len = *plaintext.last().ok_or(ProviderError::InvalidInput(
1523            ProviderInputError::AesCbcCiphertext,
1524        ))?;
1525        let padding_bytes = usize::from(pad_len);
1526        if !(1..=16).contains(&padding_bytes) || padding_bytes > plaintext.len() {
1527            return Err(ProviderError::InvalidInput(
1528                ProviderInputError::AesCbcCiphertext,
1529            ));
1530        }
1531        plaintext.truncate(plaintext.len() - padding_bytes);
1532        Ok(plaintext)
1533    }
1534
1535    fn encrypt_gcm<C>(
1536        provider: &dyn CryptoProvider,
1537        key: &[u8],
1538        plaintext: &[u8],
1539    ) -> Result<Vec<u8>, ProviderError>
1540    where
1541        C: AeadInOut + KeyInit,
1542    {
1543        let mut nonce = [0_u8; 12];
1544        provider.fill_random(&mut nonce)?;
1545        let cipher = C::new_from_slice(key).map_err(|_| {
1546            ProviderError::InvalidInput(ProviderInputError::PrimitiveInitialization("AES-GCM"))
1547        })?;
1548        let mut output = plaintext.to_vec();
1549        let nonce = Nonce::try_from(nonce.as_slice()).map_err(|_| {
1550            ProviderError::InvalidInput(ProviderInputError::PrimitiveInitialization(
1551                "AES-GCM nonce",
1552            ))
1553        })?;
1554        cipher
1555            .encrypt_in_place(&nonce, &[], &mut output)
1556            .map_err(|_| ProviderError::AuthenticationFailed)?;
1557        let mut framed = Vec::with_capacity(12 + output.len());
1558        framed.extend_from_slice(&nonce);
1559        framed.extend_from_slice(&output);
1560        Ok(framed)
1561    }
1562
1563    fn decrypt_gcm<C>(key: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>, ProviderError>
1564    where
1565        C: AeadInOut + KeyInit,
1566    {
1567        if ciphertext.len() < 28 {
1568            return Err(ProviderError::InvalidInput(
1569                ProviderInputError::AesGcmFraming,
1570            ));
1571        }
1572        let (nonce, body) = ciphertext.split_at(12);
1573        let cipher = C::new_from_slice(key).map_err(|_| {
1574            ProviderError::InvalidInput(ProviderInputError::PrimitiveInitialization("AES-GCM"))
1575        })?;
1576        let mut plaintext = body.to_vec();
1577        let nonce = Nonce::try_from(nonce).map_err(|_| {
1578            ProviderError::InvalidInput(ProviderInputError::PrimitiveInitialization(
1579                "AES-GCM nonce",
1580            ))
1581        })?;
1582        cipher
1583            .decrypt_in_place(&nonce, &[], &mut plaintext)
1584            .map_err(|_| ProviderError::AuthenticationFailed)?;
1585        Ok(plaintext)
1586    }
1587
1588    pub(super) fn wrap_key(
1589        algorithm: KeyWrapAlgorithm,
1590        kek: &[u8],
1591        key: &[u8],
1592    ) -> Result<Vec<u8>, ProviderError> {
1593        check_key(algorithm.key_len(), kek)?;
1594        let mut output = vec![0_u8; key.len() + 8];
1595        match algorithm {
1596            KeyWrapAlgorithm::AesKw128 => KwAes128::new_from_slice(kek)
1597                .map_err(|_| ProviderError::InvalidKeySize {
1598                    expected: 16,
1599                    actual: kek.len(),
1600                })?
1601                .wrap_key(key, &mut output),
1602            KeyWrapAlgorithm::AesKw256 => KwAes256::new_from_slice(kek)
1603                .map_err(|_| ProviderError::InvalidKeySize {
1604                    expected: 32,
1605                    actual: kek.len(),
1606                })?
1607                .wrap_key(key, &mut output),
1608        }
1609        .map_err(|_| ProviderError::InvalidInput(ProviderInputError::AesKeyWrapFraming))?;
1610        Ok(output)
1611    }
1612
1613    pub(super) fn unwrap_key(
1614        algorithm: KeyWrapAlgorithm,
1615        kek: &[u8],
1616        wrapped: &[u8],
1617    ) -> Result<Vec<u8>, ProviderError> {
1618        check_key(algorithm.key_len(), kek)?;
1619        if wrapped.len() < 16 || !wrapped.len().is_multiple_of(8) {
1620            return Err(ProviderError::InvalidInput(
1621                ProviderInputError::AesKeyWrapFraming,
1622            ));
1623        }
1624        let mut output = vec![0_u8; wrapped.len() - 8];
1625        let key = match algorithm {
1626            KeyWrapAlgorithm::AesKw128 => KwAes128::new_from_slice(kek)
1627                .map_err(|_| ProviderError::InvalidKeySize {
1628                    expected: 16,
1629                    actual: kek.len(),
1630                })?
1631                .unwrap_key(wrapped, &mut output),
1632            KeyWrapAlgorithm::AesKw256 => KwAes256::new_from_slice(kek)
1633                .map_err(|_| ProviderError::InvalidKeySize {
1634                    expected: 32,
1635                    actual: kek.len(),
1636                })?
1637                .unwrap_key(wrapped, &mut output),
1638        }
1639        .map_err(|_| ProviderError::AuthenticationFailed)?;
1640        Ok(key.to_vec())
1641    }
1642
1643    pub(super) fn transport_key(
1644        provider: &dyn CryptoProvider,
1645        key: &rsa::RsaPublicKey,
1646        parameters: &RsaOaepParameters,
1647        plaintext: &[u8],
1648    ) -> Result<Vec<u8>, ProviderError> {
1649        let mut rng = super::ProviderRng(provider);
1650        macro_rules! encrypt_with {
1651            ($digest:ty, $mgf:ty) => {
1652                Oaep::<$digest, $mgf>::new_with_mgf_hash_and_label(parameters.label.clone())
1653                    .encrypt(&mut rng, key, plaintext)
1654            };
1655        }
1656        let result = match (parameters.digest, parameters.mgf_digest) {
1657            (OaepDigestAlgorithm::Sha1, OaepDigestAlgorithm::Sha1) => {
1658                encrypt_with!(Sha1, Sha1)
1659            }
1660            (OaepDigestAlgorithm::Sha1, OaepDigestAlgorithm::Sha256) => {
1661                encrypt_with!(Sha1, Sha256)
1662            }
1663            (OaepDigestAlgorithm::Sha1, OaepDigestAlgorithm::Sha384) => {
1664                encrypt_with!(Sha1, Sha384)
1665            }
1666            (OaepDigestAlgorithm::Sha1, OaepDigestAlgorithm::Sha512) => {
1667                encrypt_with!(Sha1, Sha512)
1668            }
1669            (OaepDigestAlgorithm::Sha256, OaepDigestAlgorithm::Sha1) => {
1670                encrypt_with!(Sha256, Sha1)
1671            }
1672            (OaepDigestAlgorithm::Sha256, OaepDigestAlgorithm::Sha256) => {
1673                encrypt_with!(Sha256, Sha256)
1674            }
1675            (OaepDigestAlgorithm::Sha256, OaepDigestAlgorithm::Sha384) => {
1676                encrypt_with!(Sha256, Sha384)
1677            }
1678            (OaepDigestAlgorithm::Sha256, OaepDigestAlgorithm::Sha512) => {
1679                encrypt_with!(Sha256, Sha512)
1680            }
1681            (OaepDigestAlgorithm::Sha384, OaepDigestAlgorithm::Sha1) => {
1682                encrypt_with!(Sha384, Sha1)
1683            }
1684            (OaepDigestAlgorithm::Sha384, OaepDigestAlgorithm::Sha256) => {
1685                encrypt_with!(Sha384, Sha256)
1686            }
1687            (OaepDigestAlgorithm::Sha384, OaepDigestAlgorithm::Sha384) => {
1688                encrypt_with!(Sha384, Sha384)
1689            }
1690            (OaepDigestAlgorithm::Sha384, OaepDigestAlgorithm::Sha512) => {
1691                encrypt_with!(Sha384, Sha512)
1692            }
1693            (OaepDigestAlgorithm::Sha512, OaepDigestAlgorithm::Sha1) => {
1694                encrypt_with!(Sha512, Sha1)
1695            }
1696            (OaepDigestAlgorithm::Sha512, OaepDigestAlgorithm::Sha256) => {
1697                encrypt_with!(Sha512, Sha256)
1698            }
1699            (OaepDigestAlgorithm::Sha512, OaepDigestAlgorithm::Sha384) => {
1700                encrypt_with!(Sha512, Sha384)
1701            }
1702            (OaepDigestAlgorithm::Sha512, OaepDigestAlgorithm::Sha512) => {
1703                encrypt_with!(Sha512, Sha512)
1704            }
1705        };
1706        result.map_err(map_rsa_error)
1707    }
1708
1709    pub(super) fn recover_key(
1710        provider: &dyn CryptoProvider,
1711        key: &rsa::RsaPrivateKey,
1712        parameters: &RsaOaepParameters,
1713        ciphertext: &[u8],
1714    ) -> Result<Vec<u8>, ProviderError> {
1715        let mut rng = super::ProviderRng(provider);
1716        macro_rules! decrypt_with {
1717            ($digest:ty, $mgf:ty) => {
1718                Oaep::<$digest, $mgf>::new_with_mgf_hash_and_label(parameters.label.clone())
1719                    .decrypt(Some(&mut rng), key, ciphertext)
1720            };
1721        }
1722        let result = match (parameters.digest, parameters.mgf_digest) {
1723            (OaepDigestAlgorithm::Sha1, OaepDigestAlgorithm::Sha1) => {
1724                decrypt_with!(Sha1, Sha1)
1725            }
1726            (OaepDigestAlgorithm::Sha1, OaepDigestAlgorithm::Sha256) => {
1727                decrypt_with!(Sha1, Sha256)
1728            }
1729            (OaepDigestAlgorithm::Sha1, OaepDigestAlgorithm::Sha384) => {
1730                decrypt_with!(Sha1, Sha384)
1731            }
1732            (OaepDigestAlgorithm::Sha1, OaepDigestAlgorithm::Sha512) => {
1733                decrypt_with!(Sha1, Sha512)
1734            }
1735            (OaepDigestAlgorithm::Sha256, OaepDigestAlgorithm::Sha1) => {
1736                decrypt_with!(Sha256, Sha1)
1737            }
1738            (OaepDigestAlgorithm::Sha256, OaepDigestAlgorithm::Sha256) => {
1739                decrypt_with!(Sha256, Sha256)
1740            }
1741            (OaepDigestAlgorithm::Sha256, OaepDigestAlgorithm::Sha384) => {
1742                decrypt_with!(Sha256, Sha384)
1743            }
1744            (OaepDigestAlgorithm::Sha256, OaepDigestAlgorithm::Sha512) => {
1745                decrypt_with!(Sha256, Sha512)
1746            }
1747            (OaepDigestAlgorithm::Sha384, OaepDigestAlgorithm::Sha1) => {
1748                decrypt_with!(Sha384, Sha1)
1749            }
1750            (OaepDigestAlgorithm::Sha384, OaepDigestAlgorithm::Sha256) => {
1751                decrypt_with!(Sha384, Sha256)
1752            }
1753            (OaepDigestAlgorithm::Sha384, OaepDigestAlgorithm::Sha384) => {
1754                decrypt_with!(Sha384, Sha384)
1755            }
1756            (OaepDigestAlgorithm::Sha384, OaepDigestAlgorithm::Sha512) => {
1757                decrypt_with!(Sha384, Sha512)
1758            }
1759            (OaepDigestAlgorithm::Sha512, OaepDigestAlgorithm::Sha1) => {
1760                decrypt_with!(Sha512, Sha1)
1761            }
1762            (OaepDigestAlgorithm::Sha512, OaepDigestAlgorithm::Sha256) => {
1763                decrypt_with!(Sha512, Sha256)
1764            }
1765            (OaepDigestAlgorithm::Sha512, OaepDigestAlgorithm::Sha384) => {
1766                decrypt_with!(Sha512, Sha384)
1767            }
1768            (OaepDigestAlgorithm::Sha512, OaepDigestAlgorithm::Sha512) => {
1769                decrypt_with!(Sha512, Sha512)
1770            }
1771        };
1772        result.map_err(map_rsa_error)
1773    }
1774
1775    fn map_rsa_error(error: rsa::Error) -> ProviderError {
1776        match error {
1777            rsa::Error::Rng => ProviderError::Random("RSA-OAEP randomness failed".into()),
1778            _ => ProviderError::AuthenticationFailed,
1779        }
1780    }
1781}
1782
1783#[cfg(test)]
1784mod tests {
1785    #[cfg(feature = "xmldsig")]
1786    use std::sync::atomic::AtomicUsize;
1787    use std::sync::atomic::{AtomicBool, Ordering};
1788
1789    use super::*;
1790
1791    #[cfg(feature = "xmldsig")]
1792    struct CountingRandomProvider {
1793        random_calls: AtomicUsize,
1794        reject_digest: Option<DigestAlgorithm>,
1795        extra_digest_byte: bool,
1796        accept_signatures: bool,
1797    }
1798
1799    #[cfg(feature = "xmldsig")]
1800    impl CryptoProvider for CountingRandomProvider {
1801        fn name(&self) -> &'static str {
1802            "counting-random"
1803        }
1804
1805        fn supports(&self, capability: ProviderCapability<'_>) -> bool {
1806            RUST_CRYPTO_PROVIDER.supports(capability)
1807        }
1808
1809        fn fill_random(&self, output: &mut [u8]) -> Result<(), ProviderError> {
1810            self.random_calls.fetch_add(1, Ordering::Relaxed);
1811            RUST_CRYPTO_PROVIDER.fill_random(output)
1812        }
1813
1814        fn derive_key(
1815            &self,
1816            parameters: &KdfParameters<'_>,
1817            secret: &[u8],
1818        ) -> Result<Vec<u8>, ProviderError> {
1819            RUST_CRYPTO_PROVIDER.derive_key(parameters, secret)
1820        }
1821
1822        fn digest(
1823            &self,
1824            algorithm: DigestAlgorithm,
1825            data: &[u8],
1826        ) -> Result<Vec<u8>, ProviderError> {
1827            if self.reject_digest == Some(algorithm) {
1828                return Err(ProviderError::Unsupported {
1829                    operation: ProviderOperation::Digest,
1830                    algorithm: Some(algorithm.uri().to_owned()),
1831                });
1832            }
1833            let mut digest = RUST_CRYPTO_PROVIDER.digest(algorithm, data)?;
1834            if self.extra_digest_byte {
1835                digest.push(0);
1836            }
1837            Ok(digest)
1838        }
1839
1840        fn sign(
1841            &self,
1842            key: &dyn crate::xmldsig::SigningKey,
1843            algorithm: crate::xmldsig::SignatureAlgorithm,
1844            data: &[u8],
1845        ) -> Result<Vec<u8>, crate::xmldsig::SigningKeyError> {
1846            key.sign_with_provider(self, algorithm, data)
1847        }
1848
1849        fn verify(
1850            &self,
1851            key: &dyn crate::xmldsig::VerifyingKey,
1852            algorithm: crate::xmldsig::SignatureAlgorithm,
1853            data: &[u8],
1854            signature: &[u8],
1855        ) -> Result<bool, crate::xmldsig::DsigError> {
1856            if self.accept_signatures {
1857                return Ok(true);
1858            }
1859            RUST_CRYPTO_PROVIDER.verify(key, algorithm, data, signature)
1860        }
1861
1862        #[cfg(feature = "xmlenc")]
1863        fn encrypt_data(
1864            &self,
1865            algorithm: DataEncryptionAlgorithm,
1866            key: &[u8],
1867            plaintext: &[u8],
1868        ) -> Result<Vec<u8>, ProviderError> {
1869            RUST_CRYPTO_PROVIDER.encrypt_data(algorithm, key, plaintext)
1870        }
1871
1872        #[cfg(feature = "xmlenc")]
1873        fn decrypt_data(
1874            &self,
1875            algorithm: DataEncryptionAlgorithm,
1876            key: &[u8],
1877            ciphertext: &[u8],
1878        ) -> Result<Vec<u8>, ProviderError> {
1879            RUST_CRYPTO_PROVIDER.decrypt_data(algorithm, key, ciphertext)
1880        }
1881
1882        #[cfg(feature = "xmlenc")]
1883        fn wrap_key(
1884            &self,
1885            algorithm: KeyWrapAlgorithm,
1886            kek: &[u8],
1887            key: &[u8],
1888        ) -> Result<Vec<u8>, ProviderError> {
1889            RUST_CRYPTO_PROVIDER.wrap_key(algorithm, kek, key)
1890        }
1891
1892        #[cfg(feature = "xmlenc")]
1893        fn unwrap_key(
1894            &self,
1895            algorithm: KeyWrapAlgorithm,
1896            kek: &[u8],
1897            wrapped: &[u8],
1898        ) -> Result<Vec<u8>, ProviderError> {
1899            RUST_CRYPTO_PROVIDER.unwrap_key(algorithm, kek, wrapped)
1900        }
1901
1902        #[cfg(feature = "xmlenc")]
1903        fn transport_key(
1904            &self,
1905            key: &dyn KeyTransportKey,
1906            parameters: &RsaOaepParameters,
1907            plaintext: &[u8],
1908        ) -> Result<Vec<u8>, ProviderError> {
1909            RUST_CRYPTO_PROVIDER.transport_key(key, parameters, plaintext)
1910        }
1911
1912        #[cfg(feature = "xmlenc")]
1913        fn recover_key(
1914            &self,
1915            key: &dyn KeyRecoveryKey,
1916            parameters: &RsaOaepParameters,
1917            ciphertext: &[u8],
1918        ) -> Result<Vec<u8>, ProviderError> {
1919            RUST_CRYPTO_PROVIDER.recover_key(key, parameters, ciphertext)
1920        }
1921    }
1922
1923    #[cfg(feature = "xmldsig")]
1924    #[test]
1925    fn capability_query_is_explicit_about_unimplemented_operations() {
1926        assert!(RUST_CRYPTO_PROVIDER.supports(ProviderCapability::Digest(DigestAlgorithm::Sha256)));
1927        let agreement = KeyAgreementParameters {
1928            algorithm: "urn:unsupported:agreement",
1929            peer_public_key: &[],
1930        };
1931        assert!(!RUST_CRYPTO_PROVIDER.supports(ProviderCapability::KeyAgreement(&agreement)));
1932        assert!(RUST_CRYPTO_PROVIDER.supports(ProviderCapability::Sign(
1933            crate::xmldsig::SignatureAlgorithm::RsaSha1
1934        )));
1935        assert!(RUST_CRYPTO_PROVIDER.supports(ProviderCapability::Verify(
1936            crate::xmldsig::SignatureAlgorithm::RsaSha1
1937        )));
1938        for digest in [DigestAlgorithm::Sha1, DigestAlgorithm::Sha512] {
1939            assert!(
1940                RUST_CRYPTO_PROVIDER.supports(ProviderCapability::VerifyCertificate(
1941                    X509SignatureAlgorithm::Ecdsa(digest)
1942                ))
1943            );
1944        }
1945    }
1946
1947    #[cfg(feature = "xmldsig")]
1948    #[test]
1949    fn x509_digest_key_info_uses_the_selected_provider() {
1950        use crate::xmldsig::{
1951            DigestAlgorithm, KeyInfoWriteError, KeyInfoWriter, RsaSigningKey,
1952            X509DigestKeyInfoWriter,
1953        };
1954
1955        // KeyInfo generation is part of the signing operation's provider
1956        // boundary; a writer must not silently fall back to RustCrypto.
1957        let key = RsaSigningKey::from_pkcs8_pem(include_str!(
1958            "../tests/fixtures/keys/rsa/rsa-2048-key.pem"
1959        ))
1960        .expect("RSA fixture must parse");
1961        let writer = X509DigestKeyInfoWriter::from_pem(
1962            include_str!("../tests/fixtures/keys/rsa/rsa-2048-cert.pem"),
1963            DigestAlgorithm::Sha224,
1964        )
1965        .expect("certificate fixture must parse");
1966        let provider = CountingRandomProvider {
1967            random_calls: AtomicUsize::new(0),
1968            reject_digest: Some(DigestAlgorithm::Sha224),
1969            extra_digest_byte: false,
1970            accept_signatures: false,
1971        };
1972
1973        let error = writer
1974            .write_key_info_with_provider(&key, &provider)
1975            .expect_err("the selected provider must control X509Digest");
1976        assert!(matches!(
1977            error,
1978            KeyInfoWriteError::Provider(ProviderError::Unsupported {
1979                operation: ProviderOperation::Digest,
1980                ..
1981            })
1982        ));
1983    }
1984
1985    #[cfg(feature = "xmldsig")]
1986    #[test]
1987    fn x509_digest_writer_rejects_trailing_certificate_der() {
1988        use crate::xmldsig::{DigestAlgorithm, KeyInfoWriteError, X509DigestKeyInfoWriter};
1989
1990        // The writer retains both digest bytes and the validated signing-key
1991        // identity, so construction must accept exactly one DER certificate.
1992        let (_, certificate) = x509_parser::pem::parse_x509_pem(include_bytes!(
1993            "../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
1994        ))
1995        .expect("certificate fixture must parse");
1996        let mut certificate_der = certificate.contents;
1997        certificate_der.push(0);
1998
1999        assert!(matches!(
2000            X509DigestKeyInfoWriter::from_der(&certificate_der, DigestAlgorithm::Sha256),
2001            Err(KeyInfoWriteError::InvalidCertificateDer)
2002        ));
2003    }
2004
2005    #[cfg(all(feature = "xmldsig", feature = "xmlenc"))]
2006    #[test]
2007    fn capability_queries_include_oaep_and_pss_parameters() {
2008        use crate::xmlenc::{KeyTransportAlgorithm, OaepDigestAlgorithm};
2009
2010        let explicit_legacy = RsaOaepParameters {
2011            algorithm: KeyTransportAlgorithm::RsaOaepMgf1p,
2012            digest: OaepDigestAlgorithm::Sha256,
2013            mgf_digest: OaepDigestAlgorithm::Sha256,
2014            label: Vec::new(),
2015        };
2016        assert!(RUST_CRYPTO_PROVIDER.supports(ProviderCapability::KeyTransport(&explicit_legacy)));
2017        let modern =
2018            RsaOaepParameters::xmlenc11(OaepDigestAlgorithm::Sha256, OaepDigestAlgorithm::Sha512)
2019                .label(b"label".to_vec());
2020        assert!(RUST_CRYPTO_PROVIDER.supports(ProviderCapability::KeyTransport(&modern)));
2021
2022        let supported_pss = X509SignatureAlgorithm::RsaPss {
2023            digest: DigestAlgorithm::Sha256,
2024            mgf_digest: DigestAlgorithm::Sha256,
2025            salt_len: 32,
2026        };
2027        assert!(
2028            RUST_CRYPTO_PROVIDER.supports(ProviderCapability::VerifyCertificate(supported_pss))
2029        );
2030        let unsupported_pss = X509SignatureAlgorithm::RsaPss {
2031            digest: DigestAlgorithm::Sha256,
2032            mgf_digest: DigestAlgorithm::Sha384,
2033            salt_len: 32,
2034        };
2035        assert!(
2036            !RUST_CRYPTO_PROVIDER.supports(ProviderCapability::VerifyCertificate(unsupported_pss))
2037        );
2038    }
2039
2040    struct RecordingAgreementKey(AtomicBool);
2041
2042    impl KeyAgreementKey for RecordingAgreementKey {
2043        fn agree(
2044            &self,
2045            _parameters: &KeyAgreementParameters<'_>,
2046        ) -> Result<Vec<u8>, ProviderError> {
2047            self.0.store(true, Ordering::Relaxed);
2048            Ok(vec![0x42])
2049        }
2050    }
2051
2052    #[test]
2053    fn unsupported_agreement_and_kdf_fail_without_dispatch_or_fallback() {
2054        let agreement = KeyAgreementParameters {
2055            algorithm: "urn:example:agreement",
2056            peer_public_key: b"peer",
2057        };
2058        let key = RecordingAgreementKey(AtomicBool::new(false));
2059        let error = RUST_CRYPTO_PROVIDER
2060            .agree_key(&key, &agreement)
2061            .expect_err("unsupported agreement must fail closed");
2062        assert!(matches!(
2063            error,
2064            ProviderError::Unsupported {
2065                operation: ProviderOperation::KeyAgreement,
2066                algorithm: Some(ref algorithm),
2067            } if algorithm == agreement.algorithm
2068        ));
2069        assert!(!key.0.load(Ordering::Relaxed));
2070
2071        let kdf = KdfParameters {
2072            algorithm: "urn:example:kdf",
2073            digest: Some("urn:example:digest"),
2074            salt: b"salt",
2075            info: b"info",
2076            iterations: 1,
2077            output_len: 32,
2078        };
2079        assert!(matches!(
2080            RUST_CRYPTO_PROVIDER.derive_key(&kdf, b"secret"),
2081            Err(ProviderError::Unsupported {
2082                operation: ProviderOperation::Kdf,
2083                algorithm: Some(ref algorithm),
2084            }) if algorithm == kdf.algorithm
2085        ));
2086    }
2087
2088    #[cfg(feature = "xmldsig")]
2089    #[test]
2090    fn rsa_signing_uses_the_selected_providers_randomness() {
2091        use crate::xmldsig::{RsaSigningKey, SignatureAlgorithm};
2092
2093        // RSA PKCS#1 v1.5 uses randomness for blinding even though its wire
2094        // signature is deterministic; the selected provider owns that source.
2095        let key = RsaSigningKey::from_pkcs8_pem(include_str!(
2096            "../tests/fixtures/keys/rsa/rsa-2048-key.pem"
2097        ))
2098        .expect("RSA fixture must parse");
2099        let provider = CountingRandomProvider {
2100            random_calls: AtomicUsize::new(0),
2101            reject_digest: None,
2102            extra_digest_byte: false,
2103            accept_signatures: false,
2104        };
2105
2106        let signature = provider
2107            .sign(&key, SignatureAlgorithm::RsaSha256, b"signed info")
2108            .expect("RSA signing must succeed");
2109
2110        assert!(!signature.is_empty());
2111        assert!(provider.random_calls.load(Ordering::Relaxed) > 0);
2112    }
2113
2114    #[cfg(feature = "xmldsig")]
2115    #[test]
2116    fn ecdsa_signing_uses_the_selected_providers_digest() {
2117        use crate::xmldsig::{
2118            EcdsaP256SigningKey, EcdsaP384SigningKey, SignatureAlgorithm, SigningKeyError,
2119        };
2120
2121        // SignatureMethod chooses the hash independently of the EC key curve.
2122        // Both built-in ECDSA keys must therefore ask the selected provider for
2123        // that digest instead of hashing behind the provider boundary.
2124        let cases: [(
2125            Box<dyn crate::xmldsig::SigningKey>,
2126            SignatureAlgorithm,
2127            DigestAlgorithm,
2128        ); 2] = [
2129            (
2130                Box::new(
2131                    EcdsaP256SigningKey::from_pkcs8_pem(include_str!(
2132                        "../tests/fixtures/keys/ec/ec-prime256v1-key.pem"
2133                    ))
2134                    .expect("P-256 fixture must parse"),
2135                ),
2136                SignatureAlgorithm::EcdsaSha384,
2137                DigestAlgorithm::Sha384,
2138            ),
2139            (
2140                Box::new(
2141                    EcdsaP384SigningKey::from_pkcs8_pem(include_str!(
2142                        "../tests/fixtures/keys/ec/ec-prime384v1-key.pem"
2143                    ))
2144                    .expect("P-384 fixture must parse"),
2145                ),
2146                SignatureAlgorithm::EcdsaSha256,
2147                DigestAlgorithm::Sha256,
2148            ),
2149        ];
2150
2151        for (key, signature_algorithm, digest_algorithm) in cases {
2152            let provider = CountingRandomProvider {
2153                random_calls: AtomicUsize::new(0),
2154                reject_digest: Some(digest_algorithm),
2155                extra_digest_byte: false,
2156                accept_signatures: false,
2157            };
2158            let error = provider
2159                .sign(key.as_ref(), signature_algorithm, b"signed info")
2160                .expect_err("provider digest rejection must stop ECDSA signing");
2161
2162            assert!(matches!(
2163                error,
2164                SigningKeyError::Provider(ProviderError::Unsupported {
2165                    operation: ProviderOperation::Digest,
2166                    algorithm: Some(ref uri),
2167                }) if uri == digest_algorithm.uri()
2168            ));
2169        }
2170    }
2171
2172    #[cfg(feature = "xmldsig")]
2173    #[test]
2174    fn ecdsa_signing_rejects_provider_digests_with_the_wrong_length() {
2175        use crate::xmldsig::{
2176            EcdsaP256SigningKey, EcdsaP384SigningKey, SignatureAlgorithm, SigningKeyError,
2177        };
2178
2179        // Prehash signers may truncate oversized input, so the provider
2180        // boundary must reject it before either curve receives the digest.
2181        let cases: [(
2182            Box<dyn crate::xmldsig::SigningKey>,
2183            SignatureAlgorithm,
2184            usize,
2185        ); 2] = [
2186            (
2187                Box::new(
2188                    EcdsaP256SigningKey::from_pkcs8_pem(include_str!(
2189                        "../tests/fixtures/keys/ec/ec-prime256v1-key.pem"
2190                    ))
2191                    .expect("P-256 fixture must parse"),
2192                ),
2193                SignatureAlgorithm::EcdsaSha256,
2194                32,
2195            ),
2196            (
2197                Box::new(
2198                    EcdsaP384SigningKey::from_pkcs8_pem(include_str!(
2199                        "../tests/fixtures/keys/ec/ec-prime384v1-key.pem"
2200                    ))
2201                    .expect("P-384 fixture must parse"),
2202                ),
2203                SignatureAlgorithm::EcdsaSha384,
2204                48,
2205            ),
2206        ];
2207
2208        for (key, algorithm, expected) in cases {
2209            let provider = CountingRandomProvider {
2210                random_calls: AtomicUsize::new(0),
2211                reject_digest: None,
2212                extra_digest_byte: true,
2213                accept_signatures: false,
2214            };
2215            let error = provider
2216                .sign(key.as_ref(), algorithm, b"signed info")
2217                .expect_err("an oversized provider digest must not reach ECDSA prehash signing");
2218
2219            assert!(matches!(
2220                error,
2221                SigningKeyError::Provider(ProviderError::InvalidOutputSize {
2222                    operation: ProviderOperation::Digest,
2223                    expected: actual_expected,
2224                    actual,
2225                }) if actual_expected == expected && actual == expected + 1
2226            ));
2227        }
2228    }
2229
2230    #[cfg(feature = "xmldsig")]
2231    #[test]
2232    fn verification_facade_rejects_malformed_dsa_before_provider_dispatch() {
2233        use crate::xmldsig::{
2234            DefaultKeyResolver, DsigStatus, FailureReason, SignatureAlgorithm, VerifyContext,
2235        };
2236
2237        let original = include_str!(
2238            "../tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-dsa.xml"
2239        );
2240        let value_start = original
2241            .find("<SignatureValue>")
2242            .expect("Merlin fixture must contain SignatureValue")
2243            + "<SignatureValue>".len();
2244        let value_end = original[value_start..]
2245            .find("</SignatureValue>")
2246            .map(|offset| value_start + offset)
2247            .expect("Merlin fixture must close SignatureValue");
2248        let mut malformed = original.to_owned();
2249        malformed.replace_range(value_start..value_end, "AQ==");
2250        let provider = CountingRandomProvider {
2251            random_calls: AtomicUsize::new(0),
2252            reject_digest: None,
2253            extra_digest_byte: false,
2254            accept_signatures: true,
2255        };
2256
2257        let mut policy = crate::policy::VerificationPolicy::default();
2258        policy
2259            .key_trust
2260            .allowed_legacy_signature_algorithms
2261            .insert(SignatureAlgorithm::DsaSha1);
2262        policy.key_trust.dsa_keys.minimum_modulus_bits = 1024;
2263        policy.key_trust.mode = crate::policy::VerificationTrustMode::CryptographicOnly;
2264        let result = VerifyContext::new()
2265            .policy(policy)
2266            .provider(&provider)
2267            .key_resolver(&DefaultKeyResolver::default())
2268            .verify(&malformed)
2269            .expect("malformed framing must be a verification miss");
2270
2271        assert_eq!(
2272            result.status,
2273            DsigStatus::Invalid(FailureReason::SignatureMismatch)
2274        );
2275    }
2276
2277    #[cfg(feature = "xmldsig")]
2278    #[test]
2279    fn rustcrypto_provider_verifies_parameterized_rsa_pss_certificates() {
2280        use der::{Decode as _, Encode as _};
2281        use rand_chacha::{ChaCha20Rng, rand_core::SeedableRng};
2282        use rsa::{RsaPrivateKey, pkcs8::EncodePublicKey, pss::SigningKey as RsaPssSigningKey};
2283        use sha2::Sha256;
2284        use signature::{RandomizedSigner, SignatureEncoding};
2285        use x509_cert::spki::{AlgorithmIdentifierOwned, ObjectIdentifier};
2286
2287        // X.509 RSASSA-PSS carries salt and MGF parameters that cannot be
2288        // represented by the XMLDSig SignatureAlgorithm enum.
2289        let mut rng = ChaCha20Rng::from_seed([0x5a; 32]);
2290        let private_key =
2291            RsaPrivateKey::new(&mut rng, 2048).expect("deterministic RSA key generation");
2292        let public_key = private_key
2293            .to_public_key()
2294            .to_public_key_der()
2295            .expect("RSA public key must encode as SPKI");
2296        let signing_key = RsaPssSigningKey::<Sha256>::new_with_salt_len(private_key, 32);
2297        let signed_data = b"certificate tbs bytes";
2298        let signature = signing_key
2299            .try_sign_with_rng(&mut rng, signed_data)
2300            .expect("RSA-PSS signing must succeed")
2301            .to_vec();
2302
2303        assert!(
2304            RUST_CRYPTO_PROVIDER
2305                .verify_x509_signature(
2306                    X509SignatureAlgorithm::RsaPss {
2307                        digest: DigestAlgorithm::Sha256,
2308                        mgf_digest: DigestAlgorithm::Sha256,
2309                        salt_len: 32,
2310                    },
2311                    signed_data,
2312                    &signature,
2313                    public_key.as_bytes(),
2314                )
2315                .expect("standard RSA-PSS parameters must be supported")
2316        );
2317
2318        let mut parameterless_pss_spki =
2319            x509_cert::SubjectPublicKeyInfo::from_der(public_key.as_bytes())
2320                .expect("RSA SPKI must decode");
2321        parameterless_pss_spki.algorithm = AlgorithmIdentifierOwned {
2322            oid: ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.10"),
2323            parameters: None,
2324        };
2325        let parameterless_pss_spki = parameterless_pss_spki
2326            .to_der()
2327            .expect("parameterless PSS SPKI must encode");
2328        assert!(
2329            RUST_CRYPTO_PROVIDER
2330                .verify_x509_signature(
2331                    X509SignatureAlgorithm::RsaPss {
2332                        digest: DigestAlgorithm::Sha256,
2333                        mgf_digest: DigestAlgorithm::Sha256,
2334                        salt_len: 32,
2335                    },
2336                    signed_data,
2337                    &signature,
2338                    &parameterless_pss_spki,
2339                )
2340                .expect("parameterless PSS keys impose no signature restrictions")
2341        );
2342
2343        let mut pss_spki = x509_cert::SubjectPublicKeyInfo::from_der(public_key.as_bytes())
2344            .expect("RSA SPKI must decode");
2345        let pss_parameters = der::asn1::Any::from_der(&[
2346            0x30, 0x34, 0xa0, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
2347            0x04, 0x02, 0x01, 0x05, 0x00, 0xa1, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48,
2348            0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
2349            0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0xa2, 0x03, 0x02, 0x01, 0x20,
2350        ])
2351        .expect("standard SHA-256 PSS parameters must decode");
2352        pss_spki.algorithm = AlgorithmIdentifierOwned {
2353            oid: ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.10"),
2354            parameters: Some(pss_parameters),
2355        };
2356        let pss_spki = pss_spki.to_der().expect("PSS SPKI must encode");
2357
2358        assert!(
2359            RUST_CRYPTO_PROVIDER
2360                .verify_x509_signature(
2361                    X509SignatureAlgorithm::RsaPss {
2362                        digest: DigestAlgorithm::Sha256,
2363                        mgf_digest: DigestAlgorithm::Sha256,
2364                        salt_len: 32,
2365                    },
2366                    signed_data,
2367                    &signature,
2368                    &pss_spki,
2369                )
2370                .expect("RFC 4055 PSS SubjectPublicKeyInfo must be supported")
2371        );
2372
2373        for incompatible in [
2374            X509SignatureAlgorithm::RsaPss {
2375                digest: DigestAlgorithm::Sha384,
2376                mgf_digest: DigestAlgorithm::Sha256,
2377                salt_len: 32,
2378            },
2379            X509SignatureAlgorithm::RsaPss {
2380                digest: DigestAlgorithm::Sha256,
2381                mgf_digest: DigestAlgorithm::Sha384,
2382                salt_len: 32,
2383            },
2384            X509SignatureAlgorithm::RsaPss {
2385                digest: DigestAlgorithm::Sha256,
2386                mgf_digest: DigestAlgorithm::Sha256,
2387                salt_len: 16,
2388            },
2389        ] {
2390            assert!(
2391                !RUST_CRYPTO_PROVIDER
2392                    .verify_x509_signature(incompatible, signed_data, &signature, &pss_spki,)
2393                    .expect("incompatible PSS key restrictions are invalid, not unsupported")
2394            );
2395        }
2396    }
2397
2398    #[cfg(feature = "xmldsig")]
2399    #[test]
2400    fn rustcrypto_provider_verifies_dsa_certificate_signature_at_q_width() {
2401        use base64::Engine as _;
2402
2403        // OpenSSL-generated L=2048/N=224 DSA material. X.509 carries DER r/s
2404        // integers at q width, not XMLDSig's legacy fixed 20-byte components.
2405        let spki = base64::engine::general_purpose::STANDARD
2406            .decode("MIIDQzCCAjYGByqGSM44BAEwggIpAoIBAQDEkm7mUEj1dizQRRrcU6ehyhpQ1NAkcKi9XyNcBJDZlyTdVH09XZ04UZNuXAWRL1hEDvDAvFimuwmW7k099j0PRM+WypsfOOgZPJhIVNZu9poTPGINKpbMTXFmR+qhrYM4z+NSKxuUBWZwX5HibBIG5INbx8IDHWAxZqxgHQsebDej1+yZyCTTpmDS9nKGkBRVaxsJgZt958UPNlIz1ECf4n4P4mPLAl7W5xV8VSWMqlXdkOAPbLC/mChjFoCj0jmCQpbcOvd7a6cWhcyhw/yikoVoKEPNWr9xLtdJV37f1/4q/xTvoPKWhMmgMQ/DigUnYgPzmexyS82m5HLZ/vOJAh0A/ckrg9g9PsZesUsH/4bEijeNwWGXB5e+/LCt0QKCAQEAuBGFzyjZEmvbDKbb+8tz+zqw4lK7RGwOjVM3v9xPS6LuG5L1OwCNQcUcVIsU9VxBnEx9oMnl8eVX1nq3kfdiZB2F9ESxwX5FzBt+KLjMOzBa8rPlzVcyCZ3sT3orAQ2D/q7ffDhTCUt+v8UNiAhVbaNnR/vI7AkVoP9crRjpOSV/7b5MGa0BcjIyEzTtqM58wppfSQt8jkj7WT3+Bww/Y9rOtshDE2QosaX/7xoDnzyeZ3amLjTe3/MjBcsKlbK2z4QuaI6xoQBVd/QjP8FjXpZBhXWFIAsOL/sz6uR2Er0ovdX8DBA0EJpuzlTX94Lvf+Eh+5/83ESAm97fk4pnhQOCAQUAAoIBAEwSwKuLFPeR7UJGXkWM9egyYewhqHpIXPBEWOVPqwTw3xLc3EkufpYY9wkhJS08KD+J92jMjm//0bYeVf7fXisc6PHtGY4wx5XBm1g9HKw9lwRjbk7nH495dlZdl0BXHa14TJ8myE2zOM1jsaFyz6jAFTaRnKYIj6WlKOj59d2iAXtLZRme9r+7U4G6zDUkphyIEcIGH4vhb6gm3URr1zAV5kJjTlsPAiqgeH/PgxU52tmvLphJgv/xPxsuX5W0/s7iKbphIb2YWh/gtTWXvRQHiQQ2fCncI3TAMnZ75dBY0gPOVLQJhUyffeRbk9UULux/jc8QBPgKBS7GM5DnNSw=")
2407            .expect("DSA SPKI fixture must decode");
2408        let signature = base64::engine::general_purpose::STANDARD
2409            .decode("MD0CHQChtB1c+f5BmTJCtT7Gi4cyQiR2igj0znRQYCJ3Ahw4NGg4pL5jgA8Ri07ESV9Yr90WfUmRrbRcnjsY")
2410            .expect("DSA signature fixture must decode");
2411        let message = b"certificate tbs bytes for dsa q-width regression";
2412
2413        assert!(
2414            rustcrypto_x509::verify_signature(
2415                X509SignatureAlgorithm::Dsa(DigestAlgorithm::Sha1),
2416                message,
2417                &signature,
2418                &spki,
2419            )
2420            .expect("supported DSA-SHA1 certificate signature")
2421        );
2422
2423        let mut tampered = signature;
2424        *tampered.last_mut().expect("DER signature is non-empty") ^= 1;
2425        assert!(
2426            !rustcrypto_x509::verify_signature(
2427                X509SignatureAlgorithm::Dsa(DigestAlgorithm::Sha1),
2428                message,
2429                &tampered,
2430                &spki,
2431            )
2432            .expect("tampered DSA-SHA1 certificate signature is a verification miss")
2433        );
2434    }
2435
2436    #[cfg(feature = "xmldsig")]
2437    #[test]
2438    fn primitive_provider_does_not_embed_rsa_strength_policy() {
2439        use rand_chacha::{ChaCha20Rng, rand_core::SeedableRng};
2440        use rsa::{RsaPrivateKey, pkcs8::EncodePublicKey, pss::SigningKey as RsaPssSigningKey};
2441        use sha2::Sha256;
2442        use signature::{RandomizedSigner, SignatureEncoding};
2443
2444        let mut rng = ChaCha20Rng::from_seed([0x3c; 32]);
2445        let private_key =
2446            RsaPrivateKey::new(&mut rng, 1024).expect("deterministic weak RSA key generation");
2447        let public_key = private_key
2448            .to_public_key()
2449            .to_public_key_der()
2450            .expect("weak RSA public key must encode as SPKI");
2451        let signed_data = b"certificate tbs bytes";
2452        let signature = RsaPssSigningKey::<Sha256>::new_with_salt_len(private_key, 32)
2453            .try_sign_with_rng(&mut rng, signed_data)
2454            .expect("weak RSA-PSS key can still produce a cryptographic signature")
2455            .to_vec();
2456
2457        assert!(
2458            RUST_CRYPTO_PROVIDER
2459                .verify_x509_signature(
2460                    X509SignatureAlgorithm::RsaPss {
2461                        digest: DigestAlgorithm::Sha256,
2462                        mgf_digest: DigestAlgorithm::Sha256,
2463                        salt_len: 32,
2464                    },
2465                    signed_data,
2466                    &signature,
2467                    public_key.as_bytes(),
2468                )
2469                .expect(
2470                    "provider must evaluate structurally valid RSA-PSS independently of policy"
2471                )
2472        );
2473    }
2474
2475    #[cfg(feature = "xmldsig")]
2476    #[test]
2477    fn oversized_rsa_pss_salt_is_a_verification_miss() {
2478        use rand_chacha::{ChaCha20Rng, rand_core::SeedableRng};
2479        use rsa::{RsaPrivateKey, pkcs8::EncodePublicKey as _, traits::PublicKeyParts as _};
2480
2481        // ASN.1 saltLength is attacker-controlled. It must not reach the
2482        // dependency's unchecked hLen + saltLen + 2 arithmetic.
2483        let mut rng = ChaCha20Rng::from_seed([0x55; 32]);
2484        let public_key = RsaPrivateKey::new(&mut rng, 1024)
2485            .expect("deterministic RSA key generation")
2486            .to_public_key();
2487        let spki = public_key
2488            .to_public_key_der()
2489            .expect("RSA public key must encode as SPKI");
2490
2491        assert!(rustcrypto_x509::rsa_pss_salt_fits_key(
2492            &public_key,
2493            DigestAlgorithm::Sha256,
2494            0,
2495        ));
2496        assert!(rustcrypto_x509::rsa_pss_salt_fits_key(
2497            &public_key,
2498            DigestAlgorithm::Sha256,
2499            94,
2500        ));
2501        assert!(!rustcrypto_x509::rsa_pss_salt_fits_key(
2502            &public_key,
2503            DigestAlgorithm::Sha256,
2504            95,
2505        ));
2506
2507        assert!(
2508            !RUST_CRYPTO_PROVIDER
2509                .verify_x509_signature(
2510                    X509SignatureAlgorithm::RsaPss {
2511                        digest: DigestAlgorithm::Sha256,
2512                        mgf_digest: DigestAlgorithm::Sha256,
2513                        salt_len: usize::MAX,
2514                    },
2515                    b"certificate tbs bytes",
2516                    &vec![0_u8; public_key.size()],
2517                    spki.as_bytes(),
2518                )
2519                .expect("oversized PSS salt must fail without panicking")
2520        );
2521    }
2522}