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