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