Skip to main content

rsa/
pss.rs

1//! Support for the [Probabilistic Signature Scheme] (PSS) a.k.a. RSASSA-PSS.
2//!
3//! Designed by Mihir Bellare and Phillip Rogaway. Specified in [RFC8017 § 8.1].
4//!
5//! # Usage
6//!
7//! See [code example in the toplevel rustdoc](../index.html#pss-signatures).
8//!
9//! [Probabilistic Signature Scheme]: https://en.wikipedia.org/wiki/Probabilistic_signature_scheme
10//! [RFC8017 § 8.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1
11
12#[cfg(feature = "private-key")]
13mod blinded_signing_key;
14mod signature;
15#[cfg(feature = "private-key")]
16mod signing_key;
17mod verifying_key;
18
19#[cfg(feature = "private-key")]
20pub use self::{blinded_signing_key::BlindedSigningKey, signing_key::SigningKey};
21
22#[cfg(feature = "alloc")]
23pub use self::{signature::Signature, verifying_key::VerifyingKey};
24pub use self::{
25    signature::{GenericSignature, SignatureBytes},
26    verifying_key::GenericVerifyingKey,
27};
28
29#[cfg(feature = "alloc")]
30use alloc::{vec, vec::Vec};
31use core::fmt::{self, Debug};
32#[cfg(feature = "alloc")]
33use crypto_bigint::BoxedUint;
34
35use digest::{Digest, FixedOutputReset};
36use rand_core::TryCryptoRng;
37
38#[cfg(feature = "alloc")]
39use crate::algorithms::pad::{uint_to_be_pad, uint_to_be_pad_into, uint_to_zeroizing_be_pad};
40use crate::algorithms::pss::*;
41#[cfg(feature = "private-key")]
42use crate::algorithms::rsa::rsa_decrypt_and_check;
43#[cfg(feature = "alloc")]
44use crate::algorithms::rsa::rsa_encrypt;
45use crate::errors::{Error, Result};
46use crate::traits::{PublicKeyParts, SignatureScheme, UnsignedModularInt};
47#[cfg(feature = "private-key")]
48use crate::RsaPrivateKey;
49#[cfg(feature = "alloc")]
50use crate::RsaPublicKey;
51
52#[cfg(feature = "encoding")]
53use {
54    crate::encoding::ID_RSASSA_PSS,
55    const_oid::AssociatedOid,
56    pkcs1::RsaPssParams,
57    spki::{der::Any, AlgorithmIdentifierOwned},
58};
59
60/// Digital signatures using PSS padding.
61pub struct Pss<D> {
62    /// Create blinded signatures.
63    pub blinded: bool,
64
65    /// Digest type to use.
66    pub digest: D,
67
68    /// Salt length.
69    /// Required for signing, optional for verifying.
70    pub salt_len: Option<usize>,
71}
72
73impl<D> Default for Pss<D>
74where
75    D: Digest,
76{
77    fn default() -> Self {
78        Self::new()
79    }
80}
81
82impl<D> Pss<D>
83where
84    D: Digest,
85{
86    /// New PSS padding for the given digest.
87    /// Digest output size is used as a salt length.
88    pub fn new() -> Self {
89        Self::new_with_salt(<D as Digest>::output_size())
90    }
91
92    /// New PSS padding for the given digest with a salt value of the given length.
93    pub fn new_with_salt(len: usize) -> Self {
94        Self {
95            blinded: false,
96            digest: D::new(),
97            salt_len: Some(len),
98        }
99    }
100
101    /// New PSS padding for blinded signatures (RSA-BSSA) for the given digest.
102    /// Digest output size is used as a salt length.
103    pub fn new_blinded() -> Self {
104        Self::new_blinded_with_salt(<D as Digest>::output_size())
105    }
106
107    /// New PSS padding for blinded signatures (RSA-BSSA) for the given digest
108    /// with a salt value of the given length.
109    pub fn new_blinded_with_salt(len: usize) -> Self {
110        Self {
111            blinded: true,
112            digest: D::new(),
113            salt_len: Some(len),
114        }
115    }
116}
117
118#[cfg(feature = "alloc")]
119impl<D> SignatureScheme for Pss<D>
120where
121    D: Digest + FixedOutputReset,
122{
123    #[cfg(feature = "private-key")]
124    fn sign<Rng: TryCryptoRng + ?Sized>(
125        mut self,
126        rng: Option<&mut Rng>,
127        priv_key: &RsaPrivateKey,
128        hashed: &[u8],
129    ) -> Result<Vec<u8>> {
130        sign(
131            rng.ok_or(Error::InvalidPaddingScheme)?,
132            self.blinded,
133            priv_key,
134            hashed,
135            self.salt_len.expect("salt_len to be Some"),
136            &mut self.digest,
137        )
138    }
139
140    fn verify<K, T>(mut self, pub_key: &K, hashed: &[u8], sig: &[u8]) -> Result<()>
141    where
142        T: UnsignedModularInt,
143        K: PublicKeyParts<T>,
144    {
145        if sig.len() != pub_key.size() {
146            return Err(Error::Verification);
147        }
148        let sig = T::try_from_be_bytes_vartime(sig).map_err(|_| Error::Verification)?;
149        if sig >= *pub_key.n().as_ref() || sig.bits_precision() != pub_key.n_bits_precision() {
150            return Err(Error::Verification);
151        }
152
153        let mut em = vec![0u8; pub_key.size()];
154        let em_len =
155            uint_to_be_pad_into(rsa_encrypt(pub_key, &sig)?, pub_key.size(), &mut em)?.len();
156
157        emsa_pss_verify(
158            hashed,
159            &mut em[..em_len],
160            self.salt_len,
161            &mut self.digest,
162            pub_key.n().bits() as _,
163        )
164    }
165}
166
167impl<D> Debug for Pss<D> {
168    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169        f.debug_struct("PSS")
170            .field("blinded", &self.blinded)
171            .field("digest", &"...")
172            .field("salt_len", &self.salt_len)
173            .finish()
174    }
175}
176
177#[cfg(feature = "alloc")]
178#[allow(dead_code)]
179pub(crate) fn verify<D>(
180    pub_key: &RsaPublicKey,
181    hashed: &[u8],
182    sig: &BoxedUint,
183    sig_len: usize,
184    digest: &mut D,
185    salt_len: Option<usize>,
186) -> Result<()>
187where
188    D: Digest + FixedOutputReset,
189{
190    if sig_len != pub_key.size() {
191        return Err(Error::Verification);
192    }
193    let raw = rsa_encrypt(pub_key, sig)?;
194    let mut em = uint_to_be_pad(raw, pub_key.size())?;
195
196    emsa_pss_verify(hashed, &mut em, salt_len, digest, pub_key.n().bits() as _)
197}
198
199#[cfg(feature = "alloc")]
200#[allow(dead_code)]
201pub(crate) fn verify_digest<D>(
202    pub_key: &RsaPublicKey,
203    hashed: &[u8],
204    sig: &BoxedUint,
205    salt_len: Option<usize>,
206) -> Result<()>
207where
208    D: Digest + FixedOutputReset,
209{
210    let mut storage = vec![0u8; pub_key.size()];
211    verify_digest_into::<D, _, BoxedUint>(pub_key, hashed, sig, salt_len, &mut storage)
212}
213
214/// `storage` must be at least `pub_key.size()` bytes.
215pub fn verify_digest_into<D, K, T>(
216    pub_key: &K,
217    hashed: &[u8],
218    sig: &T,
219    salt_len: Option<usize>,
220    storage: &mut [u8],
221) -> crate::Result<()>
222where
223    D: digest::Digest + digest::FixedOutputReset,
224    K: crate::traits::PublicKeyParts<T>,
225    T: crate::traits::UnsignedModularInt,
226{
227    if sig >= pub_key.n().as_ref() || sig.bits_precision() != pub_key.n_bits_precision() {
228        return Err(crate::Error::Verification);
229    }
230    let padded_len = pub_key.size();
231    let em = crate::algorithms::pad::uint_to_be_pad_into(
232        crate::algorithms::rsa::rsa_encrypt(pub_key, sig)?,
233        padded_len,
234        storage,
235    )?;
236    // `uint_to_be_pad_into` returns an immutable slice into `storage`; PSS
237    // verify wants `&mut [u8]`. Drop the borrow and re-slice mutably.
238    let em_len = em.len();
239    emsa_pss_verify_digest::<D>(
240        hashed,
241        &mut storage[..em_len],
242        salt_len,
243        pub_key.n().bits() as _,
244    )
245}
246
247/// SignPSS calculates the signature of hashed using RSASSA-PSS.
248///
249/// Note that hashed must be the result of hashing the input message using the
250/// given hash function. The opts argument may be nil, in which case sensible
251/// defaults are used.
252#[cfg(feature = "private-key")]
253pub(crate) fn sign<T, D>(
254    rng: &mut T,
255    blind: bool,
256    priv_key: &RsaPrivateKey,
257    hashed: &[u8],
258    salt_len: usize,
259    digest: &mut D,
260) -> Result<Vec<u8>>
261where
262    T: TryCryptoRng + ?Sized,
263    D: Digest + FixedOutputReset,
264{
265    let mut salt = vec![0; salt_len];
266    rng.try_fill_bytes(&mut salt[..]).map_err(|_| Error::Rng)?;
267
268    sign_pss_with_salt(blind.then_some(rng), priv_key, hashed, &salt, digest)
269}
270
271#[cfg(feature = "private-key")]
272pub(crate) fn sign_digest<T, D>(
273    rng: &mut T,
274    blind: bool,
275    priv_key: &RsaPrivateKey,
276    hashed: &[u8],
277    salt_len: usize,
278) -> Result<Vec<u8>>
279where
280    T: TryCryptoRng + ?Sized,
281    D: Digest + FixedOutputReset,
282{
283    let mut salt = vec![0; salt_len];
284    rng.try_fill_bytes(&mut salt[..]).map_err(|_| Error::Rng)?;
285
286    sign_pss_with_salt_digest::<_, D>(blind.then_some(rng), priv_key, hashed, &salt)
287}
288
289/// signPSSWithSalt calculates the signature of hashed using PSS with specified salt.
290///
291/// Note that hashed must be the result of hashing the input message using the
292/// given hash function. salt is a random sequence of bytes whose length will be
293/// later used to verify the signature.
294#[cfg(feature = "private-key")]
295fn sign_pss_with_salt<T, D>(
296    blind_rng: Option<&mut T>,
297    priv_key: &RsaPrivateKey,
298    hashed: &[u8],
299    salt: &[u8],
300    digest: &mut D,
301) -> Result<Vec<u8>>
302where
303    T: TryCryptoRng + ?Sized,
304    D: Digest + FixedOutputReset,
305{
306    let em_bits = priv_key.n().bits() - 1;
307
308    let em = emsa_pss_encode(hashed, em_bits as _, salt, digest)?;
309
310    let em = BoxedUint::from_be_slice(&em, priv_key.n_bits_precision())?;
311    let raw = rsa_decrypt_and_check(priv_key, blind_rng, &em)?;
312    uint_to_zeroizing_be_pad(raw, priv_key.size())
313}
314
315#[cfg(feature = "private-key")]
316fn sign_pss_with_salt_digest<T, D>(
317    blind_rng: Option<&mut T>,
318    priv_key: &RsaPrivateKey,
319    hashed: &[u8],
320    salt: &[u8],
321) -> Result<Vec<u8>>
322where
323    T: TryCryptoRng + ?Sized,
324    D: Digest + FixedOutputReset,
325{
326    let em_bits = priv_key.n().bits() - 1;
327    let em = emsa_pss_encode_digest::<D>(hashed, em_bits as _, salt)?;
328
329    let em = BoxedUint::from_be_slice(&em, priv_key.n_bits_precision())?;
330    uint_to_zeroizing_be_pad(
331        rsa_decrypt_and_check(priv_key, blind_rng, &em)?,
332        priv_key.size(),
333    )
334}
335
336/// Returns the [`AlgorithmIdentifierOwned`] associated with PSS signature using a given digest.
337#[cfg(feature = "encoding")]
338pub fn get_default_pss_signature_algo_id<D>() -> spki::Result<AlgorithmIdentifierOwned>
339where
340    D: Digest + AssociatedOid,
341{
342    let salt_len: u8 = <D as Digest>::output_size() as u8;
343    get_pss_signature_algo_id::<D>(salt_len)
344}
345
346#[cfg(feature = "encoding")]
347fn get_pss_signature_algo_id<D>(salt_len: u8) -> spki::Result<AlgorithmIdentifierOwned>
348where
349    D: Digest + AssociatedOid,
350{
351    let pss_params = RsaPssParams::new::<D>(salt_len);
352
353    Ok(AlgorithmIdentifierOwned {
354        oid: ID_RSASSA_PSS,
355        parameters: Some(Any::encode_from(&pss_params)?),
356    })
357}
358
359#[cfg(all(test, feature = "encoding"))]
360mod test {
361    use crate::pss::{BlindedSigningKey, Pss, Signature, SigningKey, VerifyingKey};
362    use crate::{RsaPrivateKey, RsaPublicKey};
363
364    use crate::traits::PublicKeyParts;
365    use hex_literal::hex;
366    use pkcs1::DecodeRsaPrivateKey;
367    use rand::rngs::ChaCha8Rng;
368    use rand_core::SeedableRng;
369    use rstest::rstest;
370    use sha1::{Digest, Sha1};
371    use signature::hazmat::{PrehashVerifier, RandomizedPrehashSigner};
372    use signature::{DigestVerifier, Keypair, RandomizedDigestSigner, RandomizedSigner, Verifier};
373
374    fn get_private_key() -> RsaPrivateKey {
375        // In order to generate new test vectors you'll need the PEM form of this key:
376        // -----BEGIN RSA PRIVATE KEY-----
377        // MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
378        // fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
379        // /ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
380        // RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
381        // EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
382        // IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
383        // tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
384        // -----END RSA PRIVATE KEY-----
385
386        let pem = r#"
387-----BEGIN RSA PRIVATE KEY-----
388MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
389fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
390/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
391RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
392EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
393IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
394tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
395-----END RSA PRIVATE KEY-----"#;
396
397        RsaPrivateKey::from_pkcs1_pem(pem).unwrap()
398    }
399
400    #[rstest]
401    #[case(
402        "test\n",
403        hex!(
404            "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
405            "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
406        ),
407        true,
408    )]
409    #[case(
410        "test\n",
411        hex!(
412            "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
413            "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
414        ),
415        false,
416    )]
417    fn test_verify_pss(#[case] text: &str, #[case] sig: [u8; 64], #[case] expected: bool) {
418        let priv_key = get_private_key();
419        let pub_key: RsaPublicKey = priv_key.into();
420
421        let digest = Sha1::digest(text.as_bytes()).to_vec();
422        let result = pub_key.verify(Pss::<Sha1>::new(), &digest, &sig);
423
424        match expected {
425            true => result.expect("failed to verify"),
426            false => {
427                result.expect_err("expected verifying error");
428            }
429        }
430    }
431
432    #[rstest]
433    #[case(
434        "test\n",
435        hex!(
436            "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
437            "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
438        ),
439        true,
440    )]
441    #[case(
442        "test\n",
443        hex!(
444            "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
445            "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
446        ),
447        false,
448    )]
449    fn test_verify_pss_signer(#[case] text: &str, #[case] sig: [u8; 64], #[case] expected: bool) {
450        let priv_key = get_private_key();
451        let pub_key: RsaPublicKey = priv_key.into();
452        let verifying_key: VerifyingKey<Sha1> = VerifyingKey::new(pub_key);
453
454        let result = verifying_key.verify(
455            text.as_bytes(),
456            &Signature::try_from(sig.as_slice()).unwrap(),
457        );
458        match expected {
459            true => result.expect("failed to verify"),
460            false => {
461                result.expect_err("expected verifying error");
462            }
463        }
464    }
465
466    #[rstest]
467    #[case(
468        "test\n",
469        hex!(
470            "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
471            "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
472        ),
473        true,
474    )]
475    #[case(
476        "test\n",
477        hex!(
478            "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
479            "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
480        ),
481        false,
482    )]
483    fn test_verify_pss_digest_signer(
484        #[case] text: &str,
485        #[case] sig: [u8; 64],
486        #[case] expected: bool,
487    ) {
488        let priv_key = get_private_key();
489        let pub_key: RsaPublicKey = priv_key.into();
490        let verifying_key = VerifyingKey::new(pub_key);
491
492        let result = verifying_key.verify_digest(
493            |digest: &mut Sha1| {
494                digest.update(text.as_bytes());
495                Ok(())
496            },
497            &Signature::try_from(sig.as_slice()).unwrap(),
498        );
499        match expected {
500            true => result.expect("failed to verify"),
501            false => {
502                result.expect_err("expected verifying error");
503            }
504        }
505    }
506
507    #[rstest]
508    #[case("test\n")]
509    fn test_sign_and_verify_roundtrip(#[case] test: &str) {
510        let priv_key = get_private_key();
511
512        let mut rng = ChaCha8Rng::from_seed([42; 32]);
513
514        let digest = Sha1::digest(test.as_bytes()).to_vec();
515        let sig = priv_key
516            .sign_with_rng(&mut rng, Pss::<Sha1>::new(), &digest)
517            .expect("failed to sign");
518
519        priv_key
520            .to_public_key()
521            .verify(Pss::<Sha1>::new(), &digest, &sig)
522            .expect("failed to verify");
523    }
524
525    #[rstest]
526    #[case("test\n")]
527    fn test_sign_blinded_and_verify_roundtrip(#[case] test: &str) {
528        let priv_key = get_private_key();
529
530        let mut rng = ChaCha8Rng::from_seed([42; 32]);
531
532        let digest = Sha1::digest(test.as_bytes()).to_vec();
533        let sig = priv_key
534            .sign_with_rng(&mut rng, Pss::<Sha1>::new_blinded(), &digest)
535            .expect("failed to sign");
536
537        priv_key
538            .to_public_key()
539            .verify(Pss::<Sha1>::new(), &digest, &sig)
540            .expect("failed to verify");
541    }
542
543    #[rstest]
544    #[case("test\n")]
545    fn test_sign_and_verify_roundtrip_signer(#[case] test: &str) {
546        let priv_key = get_private_key();
547
548        let mut rng = ChaCha8Rng::from_seed([42; 32]);
549        let signing_key = SigningKey::<Sha1>::new(priv_key);
550        let verifying_key = signing_key.verifying_key();
551
552        let sig = signing_key.sign_with_rng(&mut rng, test.as_bytes());
553        verifying_key
554            .verify(test.as_bytes(), &sig)
555            .expect("failed to verify");
556    }
557
558    #[rstest]
559    #[case("test\n")]
560    fn test_sign_and_verify_roundtrip_blinded_signer(#[case] test: &str) {
561        let priv_key = get_private_key();
562
563        let mut rng = ChaCha8Rng::from_seed([42; 32]);
564        let signing_key = BlindedSigningKey::<Sha1>::new(priv_key);
565        let verifying_key = signing_key.verifying_key();
566
567        let sig = signing_key.sign_with_rng(&mut rng, test.as_bytes());
568        verifying_key
569            .verify(test.as_bytes(), &sig)
570            .expect("failed to verify");
571    }
572
573    #[rstest]
574    #[case("test\n")]
575    fn test_sign_and_verify_roundtrip_digest_signer(#[case] test: &str) {
576        let priv_key = get_private_key();
577
578        let mut rng = ChaCha8Rng::from_seed([42; 32]);
579        let signing_key = SigningKey::new(priv_key);
580        let verifying_key = signing_key.verifying_key();
581
582        let sig = signing_key
583            .sign_digest_with_rng(&mut rng, |digest: &mut Sha1| digest.update(test.as_bytes()));
584
585        verifying_key
586            .verify_digest(
587                |digest: &mut Sha1| {
588                    digest.update(test.as_bytes());
589                    Ok(())
590                },
591                &sig,
592            )
593            .expect("failed to verify");
594    }
595
596    #[rstest]
597    #[case("test\n")]
598    fn test_sign_and_verify_roundtrip_blinded_digest_signer(#[case] test: &str) {
599        let priv_key = get_private_key();
600
601        let mut rng = ChaCha8Rng::from_seed([42; 32]);
602        let signing_key = BlindedSigningKey::<Sha1>::new(priv_key);
603        let verifying_key = signing_key.verifying_key();
604
605        let sig = signing_key
606            .sign_digest_with_rng(&mut rng, |digest: &mut Sha1| digest.update(test.as_bytes()));
607
608        verifying_key
609            .verify_digest(
610                |digest: &mut Sha1| {
611                    digest.update(test.as_bytes());
612                    Ok(())
613                },
614                &sig,
615            )
616            .expect("failed to verify");
617    }
618
619    #[rstest]
620    #[case(
621        "test\n",
622        hex!(
623            "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
624            "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
625        ),
626        true
627    )]
628    #[case(
629        "test\n",
630        hex!(
631            "6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
632            "30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
633        ),
634        false
635    )]
636    fn test_verify_pss_hazmat(#[case] text: &str, #[case] sig: [u8; 64], #[case] expected: bool) {
637        let text = Sha1::digest(text);
638        let priv_key = get_private_key();
639
640        let pub_key: RsaPublicKey = priv_key.into();
641        let verifying_key = VerifyingKey::<Sha1>::new(pub_key);
642
643        let result = verifying_key
644            .verify_prehash(text.as_ref(), &Signature::try_from(sig.as_slice()).unwrap());
645        match expected {
646            true => result.expect("failed to verify"),
647            false => {
648                result.expect_err("expected verifying error");
649            }
650        }
651    }
652
653    #[rstest]
654    #[case("test\n")]
655    fn test_sign_and_verify_pss_hazmat(#[case] test: &str) {
656        let test = &Sha1::digest(test);
657        let priv_key = get_private_key();
658
659        let mut rng = ChaCha8Rng::from_seed([42; 32]);
660        let signing_key = SigningKey::<Sha1>::new(priv_key);
661        let verifying_key = signing_key.verifying_key();
662
663        let sig = signing_key
664            .sign_prehash_with_rng(&mut rng, test)
665            .expect("failed to sign");
666        verifying_key
667            .verify_prehash(test, &sig)
668            .expect("failed to verify");
669    }
670
671    #[rstest]
672    #[case("test\n")]
673    fn test_sign_and_verify_pss_blinded_hazmat(#[case] test: &str) {
674        let priv_key = get_private_key();
675
676        let test = &Sha1::digest(test);
677        let mut rng = ChaCha8Rng::from_seed([42; 32]);
678        let signing_key = BlindedSigningKey::<Sha1>::new(priv_key);
679        let verifying_key = signing_key.verifying_key();
680
681        let sig = signing_key
682            .sign_prehash_with_rng(&mut rng, test)
683            .expect("failed to sign");
684        verifying_key
685            .verify_prehash(test, &sig)
686            .expect("failed to verify");
687    }
688
689    #[test]
690    // Tests the corner case where the key is multiple of 8 + 1 bits long
691    fn test_sign_and_verify_2049bit_key() {
692        let plaintext = "Hello\n";
693        let mut rng = ChaCha8Rng::from_seed([42; 32]);
694        for i in 0..10 {
695            println!("round {i}");
696            let priv_key = RsaPrivateKey::new(&mut rng, 2049).unwrap();
697
698            let digest = Sha1::digest(plaintext.as_bytes()).to_vec();
699            let sig = priv_key
700                .sign_with_rng(&mut rng, Pss::<Sha1>::new(), &digest)
701                .expect("failed to sign");
702
703            priv_key
704                .to_public_key()
705                .verify(Pss::<Sha1>::new(), &digest, &sig)
706                .expect("failed to verify");
707        }
708    }
709
710    // Tests the case where the salt length used for signing differs from the default length
711    // while the verifier uses auto-detection.
712    #[rstest]
713    #[case("test\n")]
714    fn test_sign_and_verify_pss_differing_salt_len(#[case] test: &str) {
715        let priv_key = get_private_key();
716
717        let mut rng = ChaCha8Rng::from_seed([42; 32]);
718
719        // signing keys using different salt lengths
720        let signing_keys = [
721            // default salt length
722            SigningKey::<Sha1>::new(priv_key.clone()),
723            // maximum salt length
724            SigningKey::<Sha1>::new_with_salt_len(
725                priv_key.clone(),
726                priv_key.size() - Sha1::output_size() - 2,
727            ),
728            // unsalted
729            SigningKey::<Sha1>::new_with_salt_len(priv_key.clone(), 0),
730        ];
731
732        // verifying key uses default salt length strategy
733        let verifying_key = VerifyingKey::<Sha1>::new_with_auto_salt_len(priv_key.to_public_key());
734
735        for signing_key in &signing_keys {
736            let sig = signing_key.sign_with_rng(&mut rng, test.as_bytes());
737            verifying_key
738                .verify(test.as_bytes(), &sig)
739                .expect("verification to succeed");
740        }
741    }
742}