Skip to main content

xml_sec/
provider.rs

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