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