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