Skip to main content

xml_sec/
provider.rs

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