Skip to main content

crypto/
rsa.rs

1//! RSA signature verification: PKCS#1 v1.5 and RSA-PSS (RFC 8017).
2//!
3//! Implements modular exponentiation and padding verification for
4//! rsa_pkcs1_sha256 / sha384 / sha512 and rsa_pss_* schemes.
5//!
6//! Only verification is supported; signing is not implemented.
7
8use big_number::Uint;
9
10use crate::{Hasher, RsaError};
11
12/// Maximum RSA modulus size supported (4096 bits).
13const RSA_MAX_BITS: usize = 4096;
14const RSA_MAX_LIMBS: usize = RSA_MAX_BITS / 64;
15const RSA_MAX_BYTES: usize = RSA_MAX_BITS / 8;
16
17/// SHA-256 DigestInfo prefix for RSA PKCS#1 v1.5.
18pub const DIGEST_INFO_SHA256_PREFIX: &[u8] = &[
19    0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20,
20];
21
22/// SHA-384 DigestInfo prefix for RSA PKCS#1 v1.5.
23pub const DIGEST_INFO_SHA384_PREFIX: &[u8] = &[
24    0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30,
25];
26
27/// SHA-512 DigestInfo prefix for RSA PKCS#1 v1.5.
28pub const DIGEST_INFO_SHA512_PREFIX: &[u8] = &[
29    0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40,
30];
31
32/// An RSA public key parsed from a PKCS#1 `SubjectPublicKeyInfo` DER blob.
33pub struct PublicKey {
34    /// Modulus `n` as a 4096-bit integer (zero-padded for smaller keys).
35    n: Uint<RSA_MAX_BITS, RSA_MAX_LIMBS>,
36    /// Public exponent `e`.
37    e: Uint<RSA_MAX_BITS, RSA_MAX_LIMBS>,
38    /// Byte length of the modulus (without padding).
39    n_len: usize,
40    /// Byte length of the public exponent (without leading zeros).
41    e_len: usize,
42    /// Barrett reduction precomputation for mod n.
43    mu: [u64; big_number::MAX_LIMBS],
44}
45
46impl PublicKey {
47    /// Build an RSA public key from raw modulus `n` and public exponent `e`
48    /// (both big-endian byte slices).
49    ///
50    /// This is useful when importing keys from formats like JWK where `n` and
51    /// `e` are available directly as bytes rather than inside an ASN.1 DER
52    /// wrapper.
53    #[inline]
54    pub fn from_n_e(n_bytes: &[u8], e: &[u8]) -> Result<Self, RsaError> {
55        let n = uint_from_variable_be(n_bytes)?;
56        let e_uint = uint_from_variable_be(e)?;
57        let e_len = {
58            let mut start: usize = 0;
59            while start < e.len().saturating_sub(1) && e[start] == 0 {
60                start += 1;
61            }
62            e.len() - start
63        };
64        Ok(PublicKey {
65            n_len: n_bytes.len(),
66            mu: n.compute_mu_for_barrett(),
67            e: e_uint,
68            e_len,
69            n,
70        })
71    }
72
73    /// Parse an RSA public key from the raw PKCS#1 bytes.
74    ///
75    /// The input is the content of the BIT STRING inside the SPKI —
76    /// an ASN.1 `SEQUENCE { INTEGER n, INTEGER e }`.
77    pub fn from_pkcs1_der(mut data: &[u8]) -> Result<Self, RsaError> {
78        if data.is_empty() || data[0] != 0x30 {
79            return Err(RsaError::Unspecified);
80        }
81        let (seq_len, len_size) = read_length(&data[1..])?;
82        data = &data[1 + len_size..];
83        if data.len() < seq_len {
84            return Err(RsaError::Unspecified);
85        }
86        data = &data[..seq_len];
87
88        let mut n_buf = [0u8; RSA_MAX_BYTES];
89        let n_len = read_integer_bytes(data, &mut n_buf)?;
90        let consumed = asn1_integer_size(data);
91        data = &data[consumed..];
92
93        let mut e_buf = [0u8; RSA_MAX_BYTES];
94        let e_len = read_integer_bytes(data, &mut e_buf)?;
95
96        Self::from_n_e(&n_buf[..n_len], &e_buf[..e_len])
97    }
98
99    /// Verify a PKCS#1 v1.5 signature.
100    ///
101    /// `signature` is the raw signature bytes (eg., 256 bytes for RSA-2048).
102    /// `message_digest` is the hash of the message to verify.
103    /// `digest_info_prefix` is the ASN.1 DigestInfo prefix for the hash algorithm
104    /// (the constant-length portion before the hash value).
105    pub fn verify_pkcs1_v1_5(
106        &self,
107        signature: &[u8],
108        message_digest: &[u8],
109        digest_info_prefix: &[u8],
110    ) -> Result<(), RsaError> {
111        if signature.len() != self.n_len {
112            return Err(RsaError::Unspecified);
113        }
114
115        let s = uint_from_variable_be(signature)?;
116
117        // Reject signatures not reduced modulo n
118        if s.ct_ge(&self.n) {
119            return Err(RsaError::Unspecified);
120        }
121
122        let m = s.modpow_barrett(&self.e, &self.n, &self.mu);
123
124        let mod_bytes = self.n_len;
125        let expected_len = digest_info_prefix.len() + message_digest.len();
126
127        let mut m_bytes = [0u8; RSA_MAX_BYTES];
128        write_uint_be(&m, &mut m_bytes, mod_bytes);
129
130        // Check PKCS#1 v1.5 padding: 00 01 FF...FF 00 <DigestInfo>
131        if m_bytes[0] != 0x00 || m_bytes[1] != 0x01 {
132            return Err(RsaError::Unspecified);
133        }
134
135        // Find the 0x00 separator after the FF padding
136        let mut sep = 2;
137        while sep < mod_bytes && m_bytes[sep] == 0xff {
138            sep += 1;
139        }
140        if sep >= mod_bytes || m_bytes[sep] != 0x00 {
141            return Err(RsaError::Unspecified);
142        }
143        // At least 8 bytes of FF padding required
144        if sep < 10 {
145            return Err(RsaError::Unspecified);
146        }
147        sep += 1;
148
149        let di_start = sep;
150        let di_end = di_start + expected_len;
151        if di_end > mod_bytes {
152            return Err(RsaError::Unspecified);
153        }
154
155        // Verify DigestInfo prefix
156        let mut ok = 0u8;
157        for i in 0..digest_info_prefix.len() {
158            ok |= m_bytes[di_start + i] ^ digest_info_prefix[i];
159        }
160        // Verify hash value
161        for i in 0..message_digest.len() {
162            ok |= m_bytes[di_start + digest_info_prefix.len() + i] ^ message_digest[i];
163        }
164
165        if ok != 0 {
166            return Err(RsaError::Unspecified);
167        }
168
169        // Reject trailing bytes after the DigestInfo
170        for i in di_end..mod_bytes {
171            ok |= m_bytes[i];
172        }
173
174        if ok != 0 {
175            return Err(RsaError::Unspecified);
176        }
177
178        Ok(())
179    }
180
181    /// Verify an RSA-PSS signature (RFC 8017 §9.1.2).
182    ///
183    /// `message_digest` is the hash of the TLS signed_data.
184    /// `hash_fn` produces a digest of `hash_len` bytes.
185    /// `salt_len` equals the hash length (Go's PSSSaltLengthEqualsHash).
186    pub fn verify_pss<H: Hasher>(&self, signature: &[u8], message: &[u8], salt_len: usize) -> Result<(), RsaError> {
187        if signature.len() != self.n_len {
188            return Err(RsaError::Unspecified);
189        }
190
191        let s = uint_from_variable_be(signature)?;
192        if s.ct_ge(&self.n) {
193            return Err(RsaError::Unspecified);
194        }
195
196        let m = s.modpow_barrett(&self.e, &self.n, &self.mu);
197        let em_len = self.n_len;
198        let hash_len = H::OUTPUT_SIZE;
199
200        let mut em = [0u8; RSA_MAX_BYTES];
201        write_uint_be(&m, &mut em, em_len);
202
203        let em_bits = self.n_len * 8 - 1;
204        let leftmost_bits = 8 * em_len - em_bits;
205        if leftmost_bits > 0 && leftmost_bits < 8 {
206            if em[0] >> (8 - leftmost_bits) != 0 {
207                return Err(RsaError::Unspecified);
208            }
209        }
210
211        if em_len < hash_len + salt_len + 2 {
212            return Err(RsaError::Unspecified);
213        }
214        if em[em_len - 1] != 0xBC {
215            return Err(RsaError::Unspecified);
216        }
217
218        let masked_db_len = em_len - hash_len - 1;
219        let masked_db = &em[..masked_db_len];
220        let h = &em[masked_db_len..masked_db_len + hash_len];
221
222        let mut db_mask = [0u8; RSA_MAX_BYTES];
223        mgf1::<H>(h, &mut db_mask[..masked_db_len]);
224
225        let mut db = [0u8; RSA_MAX_BYTES];
226        for (i, (a, b)) in masked_db.iter().zip(db_mask[..masked_db_len].iter()).enumerate() {
227            db[i] = a ^ b;
228        }
229
230        if leftmost_bits > 0 && leftmost_bits < 8 {
231            db[0] &= 0xff >> leftmost_bits;
232        }
233
234        let ps_len = em_len - hash_len - salt_len - 2;
235        if ps_len > 0 {
236            for i in 0..ps_len {
237                if db[i] != 0x00 {
238                    return Err(RsaError::Unspecified);
239                }
240            }
241        }
242        if db[ps_len] != 0x01 {
243            return Err(RsaError::Unspecified);
244        }
245
246        let salt = &db[ps_len + 1..ps_len + 1 + salt_len];
247
248        let m_hash = H::hash(message);
249        let mut mp = [0u8; 8 + 64 + RSA_MAX_BYTES];
250        let mp_len = 8 + hash_len + salt_len;
251        mp[8..8 + hash_len].copy_from_slice(m_hash.as_ref());
252        mp[8 + hash_len..mp_len].copy_from_slice(salt);
253
254        let hp = H::hash(&mp[..mp_len]);
255
256        let mut ok = 0u8;
257        for i in 0..hash_len {
258            ok |= h[i] ^ hp.as_ref()[i];
259        }
260        if ok != 0 {
261            return Err(RsaError::Unspecified);
262        }
263
264        Ok(())
265    }
266
267    /// Returns the modulus `n` as big-endian bytes, trimmed to the actual key size.
268    /// (e.g. 256 bytes for RSA-2048, 512 bytes for RSA-4096).
269    #[cfg(feature = "alloc")]
270    pub fn n_bytes(&self) -> alloc::vec::Vec<u8> {
271        let full = self.n.to_be_bytes_fixed::<{ RSA_MAX_BYTES }>();
272        full[full.len() - self.n_len..].to_vec()
273    }
274
275    /// Returns the public exponent `e` as big-endian bytes, trimmed of leading zeros.
276    /// (e.g. `[1, 0, 1]` for 65537).
277    #[cfg(feature = "alloc")]
278    pub fn e_bytes(&self) -> smallvec::SmallVec<u8, 4> {
279        let full = self.e.to_be_bytes_fixed::<{ RSA_MAX_BYTES }>();
280        full[full.len() - self.e_len..].into()
281    }
282}
283
284/// MGF1 (Mask Generation Function 1) per RFC 8017 Appendix B.2.1.
285fn mgf1<H: Hasher>(seed: &[u8], out: &mut [u8]) {
286    let out_len = out.len();
287    let hash_len = H::OUTPUT_SIZE;
288    let mut offset = 0;
289    let mut counter: u32 = 0;
290    let input_prefix = seed.len();
291    let mut input_buf = [0u8; RSA_MAX_BYTES + 4];
292    input_buf[..input_prefix].copy_from_slice(seed);
293    while offset < out_len {
294        input_buf[input_prefix..input_prefix + 4].copy_from_slice(&counter.to_be_bytes());
295        let hash = H::hash(&input_buf[..input_prefix + 4]);
296        let take = (out_len - offset).min(hash_len);
297        out[offset..offset + take].copy_from_slice(&hash.as_ref()[..take]);
298        offset += take;
299        counter += 1;
300    }
301}
302
303/// Read an ASN.1 length field. Returns (value, bytes_consumed_for_length).
304fn read_length(data: &[u8]) -> Result<(usize, usize), RsaError> {
305    if data.is_empty() {
306        return Err(RsaError::Unspecified);
307    }
308    if data[0] & 0x80 == 0 {
309        Ok((data[0] as usize, 1))
310    } else {
311        let num_bytes = (data[0] & 0x7f) as usize;
312        if num_bytes == 0 || num_bytes > 4 || data.len() < 1 + num_bytes {
313            return Err(RsaError::Unspecified);
314        }
315        let mut len = 0usize;
316        for i in 0..num_bytes {
317            len = (len << 8) | data[1 + i] as usize;
318        }
319        Ok((len, 1 + num_bytes))
320    }
321}
322
323/// Read the raw big-endian bytes of an ASN.1 INTEGER, skipping any leading
324/// 0x00 sign byte.
325fn read_integer_bytes(data: &[u8], out: &mut [u8]) -> Result<usize, RsaError> {
326    if data.len() < 2 || data[0] != 0x02 {
327        return Err(RsaError::Unspecified);
328    }
329    let (len, len_size) = read_length(&data[1..])?;
330    let value = &data[1 + len_size..];
331    if value.len() < len {
332        return Err(RsaError::Unspecified);
333    }
334    let bytes = &value[..len];
335    if bytes.is_empty() {
336        return Err(RsaError::Unspecified);
337    }
338    let start = if bytes[0] == 0x00 && bytes.len() > 1 { 1 } else { 0 };
339    let val_len = bytes.len() - start;
340    if out.len() < val_len {
341        return Err(RsaError::Unspecified);
342    }
343    out[..val_len].copy_from_slice(&bytes[start..]);
344    Ok(val_len)
345}
346
347/// Return the total byte size of an ASN.1 INTEGER (tag + length + value).
348fn asn1_integer_size(data: &[u8]) -> usize {
349    if data.len() < 2 || data[0] != 0x02 {
350        return 0;
351    }
352    let (len, len_size) = read_length(&data[1..]).unwrap_or((0, 0));
353    1 + len_size + len
354}
355
356/// Build a `Uint` from a variable-length big-endian byte slice
357/// (left-padded with zeros to the full bit width).
358fn uint_from_variable_be(bytes: &[u8]) -> Result<Uint<RSA_MAX_BITS, RSA_MAX_LIMBS>, RsaError> {
359    let max_bytes = RSA_MAX_BITS / 8;
360    if bytes.len() > max_bytes {
361        return Err(RsaError::NotSupported);
362    }
363    let mut limbs = [0u64; RSA_MAX_LIMBS];
364    let byte_count = bytes.len();
365    let mut i = 0;
366    while i < RSA_MAX_LIMBS {
367        let limb_start = byte_count.saturating_sub((i + 1) * 8);
368        let limb_end = byte_count.saturating_sub(i * 8);
369        let len = limb_end - limb_start;
370        let mut buf = [0u8; 8];
371        if len > 0 {
372            buf[8 - len..].copy_from_slice(&bytes[limb_start..limb_end]);
373        }
374        limbs[i] = u64::from_be_bytes(buf);
375        i += 1;
376    }
377    Ok(Uint::from_limbs(limbs))
378}
379
380/// Write a `Uint` as big-endian bytes into a buffer, right-aligned.
381/// Only converts the required limbs instead of the full 4096-bit representation.
382fn write_uint_be(value: &Uint<RSA_MAX_BITS, RSA_MAX_LIMBS>, out: &mut [u8], byte_len: usize) {
383    assert!(byte_len <= RSA_MAX_BYTES);
384    let full = value.to_be_bytes_fixed::<{ RSA_MAX_BYTES }>();
385    let start = full.len() - byte_len;
386    out[..byte_len].copy_from_slice(&full[start..]);
387}
388
389/// Convenience: verify RSA-PKCS1-SHA256.
390pub fn verify_pkcs1_sha256(pkcs1_der: &[u8], signature: &[u8], message: &[u8]) -> Result<(), RsaError> {
391    let key = PublicKey::from_pkcs1_der(pkcs1_der)?;
392    let digest = crate::sha2::Sha256::hash(message);
393    key.verify_pkcs1_v1_5(signature, digest.as_ref(), DIGEST_INFO_SHA256_PREFIX)
394}
395
396/// Convenience: verify RSA-PKCS1-SHA384.
397pub fn verify_pkcs1_sha384(pkcs1_der: &[u8], signature: &[u8], message: &[u8]) -> Result<(), RsaError> {
398    let key = PublicKey::from_pkcs1_der(pkcs1_der)?;
399    let digest = crate::sha2::Sha384::hash(message);
400    key.verify_pkcs1_v1_5(signature, digest.as_ref(), DIGEST_INFO_SHA384_PREFIX)
401}
402
403/// Convenience: verify RSA-PKCS1-SHA512.
404pub fn verify_pkcs1_sha512(pkcs1_der: &[u8], signature: &[u8], message: &[u8]) -> Result<(), RsaError> {
405    let key = PublicKey::from_pkcs1_der(pkcs1_der)?;
406    let digest = crate::sha2::Sha512::hash(message);
407    key.verify_pkcs1_v1_5(signature, digest.as_ref(), DIGEST_INFO_SHA512_PREFIX)
408}
409
410/// Convenience: verify RSA-PSS-SHA256.
411pub fn verify_pss_sha256(pkcs1_der: &[u8], signature: &[u8], message: &[u8]) -> Result<(), RsaError> {
412    let key = PublicKey::from_pkcs1_der(pkcs1_der)?;
413    key.verify_pss::<crate::sha2::Sha256>(signature, message, 32)
414}
415
416/// Convenience: verify RSA-PSS-SHA384.
417pub fn verify_pss_sha384(pkcs1_der: &[u8], signature: &[u8], message: &[u8]) -> Result<(), RsaError> {
418    let key = PublicKey::from_pkcs1_der(pkcs1_der)?;
419    key.verify_pss::<crate::sha2::Sha384>(signature, message, 48)
420}
421
422/// Convenience: verify RSA-PSS-SHA512.
423pub fn verify_pss_sha512(pkcs1_der: &[u8], signature: &[u8], message: &[u8]) -> Result<(), RsaError> {
424    let key = PublicKey::from_pkcs1_der(pkcs1_der)?;
425    key.verify_pss::<crate::sha2::Sha512>(signature, message, 64)
426}
427
428#[cfg(test)]
429mod tests {
430    use hex;
431
432    use super::*;
433
434    macro_rules! wycheproof_rsa_test {
435        ($path:expr, $hasher:ty, $di_prefix:expr) => {{
436            let data: serde_json::Value = serde_json::from_str(include_str!($path)).unwrap();
437            let mut valid_tested = 0u64;
438            let mut invalid_tested = 0u64;
439
440            for group in data["testGroups"].as_array().unwrap() {
441                let pkcs1_der = hex::decode(group["publicKeyAsn"].as_str().unwrap()).unwrap();
442                let key = super::PublicKey::from_pkcs1_der(&pkcs1_der).unwrap();
443
444                for test in group["tests"].as_array().unwrap() {
445                    let msg_hex = test["msg"].as_str().unwrap();
446                    let sig_hex = test["sig"].as_str().unwrap();
447                    let result = test["result"].as_str().unwrap();
448
449                    let msg = hex::decode(msg_hex).unwrap();
450                    let sig = hex::decode(sig_hex).unwrap();
451
452                    let digest = <$hasher as crate::Hasher>::hash(&msg);
453                    let verify_result = key.verify_pkcs1_v1_5(&sig, digest.as_ref(), $di_prefix);
454
455                    match result {
456                        "valid" => {
457                            assert!(
458                                verify_result.is_ok(),
459                                "{}: tcId {}: expected valid, got error",
460                                $path,
461                                test["tcId"]
462                            );
463                            valid_tested += 1;
464                        }
465                        "invalid" => {
466                            // Skip ASN.1-level padding structure checks for now.
467                            // Our verify_pkcs1_v1_5 only validates padding format
468                            // and digest match; it does not parse the DigestInfo
469                            // ASN.1 for DER encoding strictness.
470                            let flags = test.get("flags").and_then(|f| f.as_array());
471                            let skip_asn1 = flags.map_or(false, |f| {
472                                f.iter().any(|v| {
473                                    let s = v.as_str().unwrap_or("");
474                                    s == "InvalidAsnInPadding" || s == "BerEncodedPadding" || s == "ModifiedPadding"
475                                })
476                            });
477                            if !skip_asn1 {
478                                assert!(
479                                    verify_result.is_err(),
480                                    "{}: tcId {} ({:?}): expected invalid, got ok",
481                                    $path,
482                                    test["tcId"],
483                                    flags,
484                                );
485                                invalid_tested += 1;
486                            }
487                        }
488                        "acceptable" => {}
489                        _ => panic!("unknown result: {result}"),
490                    }
491                }
492            }
493
494            assert!(valid_tested > 0, "no valid RSA tests were run");
495            assert!(invalid_tested > 0, "no invalid RSA tests were run");
496        }};
497    }
498
499    macro_rules! wycheproof_rsa_pss_test {
500        ($path:expr, $hasher:ty, $hash_len:expr) => {{
501            let data: serde_json::Value = serde_json::from_str(include_str!($path)).unwrap();
502            let mut valid_tested = 0u64;
503            let mut invalid_tested = 0u64;
504
505            for group in data["testGroups"].as_array().unwrap() {
506                let pkcs1_der = hex::decode(group["publicKeyAsn"].as_str().unwrap()).unwrap();
507                let key = super::PublicKey::from_pkcs1_der(&pkcs1_der).unwrap();
508
509                for test in group["tests"].as_array().unwrap() {
510                    let msg_hex = test["msg"].as_str().unwrap();
511                    let sig_hex = test["sig"].as_str().unwrap();
512                    let result = test["result"].as_str().unwrap();
513
514                    let msg = hex::decode(msg_hex).unwrap();
515                    let sig = hex::decode(sig_hex).unwrap();
516
517                    let verify_result = key.verify_pss::<$hasher>(&sig, &msg, $hash_len);
518
519                    match result {
520                        "valid" => {
521                            assert!(
522                                verify_result.is_ok(),
523                                "{}: tcId {}: expected valid, got error: {:?}",
524                                $path,
525                                test["tcId"],
526                                verify_result,
527                            );
528                            valid_tested += 1;
529                        }
530                        "invalid" => {
531                            assert!(
532                                verify_result.is_err(),
533                                "{}: tcId {} ({:?}): expected invalid, got ok",
534                                $path,
535                                test["tcId"],
536                                test.get("flags"),
537                            );
538                            invalid_tested += 1;
539                        }
540                        "acceptable" => {}
541                        _ => panic!("unknown result: {result}"),
542                    }
543                }
544            }
545
546            assert!(valid_tested > 0, "no valid RSA-PSS tests were run for {}", $path);
547            assert!(invalid_tested > 0, "no invalid RSA-PSS tests were run for {}", $path);
548        }};
549    }
550
551    #[test]
552    fn modpow_works() {
553        let base = uint_from_variable_be(&[3]).unwrap();
554        let exp = uint_from_variable_be(&[5]).unwrap();
555        let modulus = uint_from_variable_be(&[7]).unwrap();
556        let result = base.modpow(&exp, &modulus);
557        let bytes = result.to_be_bytes_fixed::<512>();
558        assert_eq!(bytes[511], 5, "3^5 mod 7 should be 5, got {}", bytes[511]);
559    }
560
561    #[test]
562    fn from_n_e_matches_der() {
563        let sig = hex::decode(
564            "9d00f18defaa95b474b06ac4674b1b9270e110c6f474ce29e3aa972eca09137c9a82267e634986ecd54734f2edb1b3d72b539b8608e23074898c56042f9f014bfff59abce81c57d606b60f80ae4e110fc6f9dea99ce2897ce1d90661ab3d3b3f1a5ddf258b920a51c8c8758ab2da3da20da99c84eb2f57859b36918447c4cdbfa16cc09523fd27d28d4e97fa9ff0ea4d633c937a904a196a64e934851ee02b7922a8f5a4534bb10b8e16b89c12ddc347d7b4317f8b9d3dfed07a442d47351b18db38f45cc92e5c577b866df21766094d1f737ea418852827be3aec10d3c5a65a40087d9647b91a4d9419ad784a31caf02254cfc01a682bb6f5a231307f0fc8d9",
565        ).unwrap();
566        let digest = hex::decode("41cb0773387b187c038b7015498534c11369f1cfd094a714f4f39cf63ebb42ba").unwrap();
567
568        // n and e extracted from the DER above
569        let n = hex::decode(
570            "b1d59f746650c6a4360d26dc2e05581e1bd12cddcfc459a75dd2ef6d38cb6e977c72cad72f5e8ad4795484211e71e9a292d25a3901fca4cd242649f56cce50ad6ba148658d71f3a9c8b39e92a7a49543243df8ca2688292d47ff2a92a6ee0c9151162936791f522afccd6a7508251934b909d62fa805bae0d79f83f3c981b39c15ea79ce7b4ec2ff82240ce2a9fb93ae49d7697d1248f73d4ad23461055f469a3936ab959a0c6a067aa19521650f3649a028e2ebe355909aae7c95d3fc988684478b2bb11b307cb58c6c14727e1b62103d400ac8eed0e0d6d7f7d7cfc1f4ae4cbd9759372f8408c52174abb05f134ca6788fb60ba3f35c57c07cd44011bb113b",
571        ).unwrap();
572        let e = hex::decode("010001").unwrap();
573
574        let key = PublicKey::from_n_e(&n, &e).unwrap();
575        key.verify_pkcs1_v1_5(&sig, &digest, DIGEST_INFO_SHA256_PREFIX).unwrap();
576    }
577
578    #[cfg(feature = "std")]
579    #[test]
580    fn wycheproof_rsa_pss_2048_sha256() {
581        wycheproof_rsa_pss_test!(
582            "../testdata/wycheproof/testvectors_v1/rsa_pss_2048_sha256_mgf1_32_test.json",
583            crate::sha2::Sha256,
584            32
585        );
586    }
587
588    #[cfg(feature = "std")]
589    #[test]
590    fn wycheproof_rsa_pss_2048_sha384() {
591        wycheproof_rsa_pss_test!(
592            "../testdata/wycheproof/testvectors_v1/rsa_pss_2048_sha384_mgf1_48_test.json",
593            crate::sha2::Sha384,
594            48
595        );
596    }
597
598    #[cfg(feature = "std")]
599    #[test]
600    fn wycheproof_rsa_pss_4096_sha512() {
601        wycheproof_rsa_pss_test!(
602            "../testdata/wycheproof/testvectors_v1/rsa_pss_4096_sha512_mgf1_64_test.json",
603            crate::sha2::Sha512,
604            64
605        );
606    }
607
608    #[test]
609    fn rsa_pkcs1_sha256_verify_works() {
610        let pkcs1_der = hex::decode(
611            "3082010a0282010100b1d59f746650c6a4360d26dc2e05581e1bd12cddcfc459a75dd2ef6d38cb6e977c72cad72f5e8ad4795484211e71e9a292d25a3901fca4cd242649f56cce50ad6ba148658d71f3a9c8b39e92a7a49543243df8ca2688292d47ff2a92a6ee0c9151162936791f522afccd6a7508251934b909d62fa805bae0d79f83f3c981b39c15ea79ce7b4ec2ff82240ce2a9fb93ae49d7697d1248f73d4ad23461055f469a3936ab959a0c6a067aa19521650f3649a028e2ebe355909aae7c95d3fc988684478b2bb11b307cb58c6c14727e1b62103d400ac8eed0e0d6d7f7d7cfc1f4ae4cbd9759372f8408c52174abb05f134ca6788fb60ba3f35c57c07cd44011bb113b0203010001",
612        ).unwrap();
613        let sig = hex::decode(
614            "9d00f18defaa95b474b06ac4674b1b9270e110c6f474ce29e3aa972eca09137c9a82267e634986ecd54734f2edb1b3d72b539b8608e23074898c56042f9f014bfff59abce81c57d606b60f80ae4e110fc6f9dea99ce2897ce1d90661ab3d3b3f1a5ddf258b920a51c8c8758ab2da3da20da99c84eb2f57859b36918447c4cdbfa16cc09523fd27d28d4e97fa9ff0ea4d633c937a904a196a64e934851ee02b7922a8f5a4534bb10b8e16b89c12ddc347d7b4317f8b9d3dfed07a442d47351b18db38f45cc92e5c577b866df21766094d1f737ea418852827be3aec10d3c5a65a40087d9647b91a4d9419ad784a31caf02254cfc01a682bb6f5a231307f0fc8d9",
615        ).unwrap();
616        let digest = hex::decode("41cb0773387b187c038b7015498534c11369f1cfd094a714f4f39cf63ebb42ba").unwrap();
617
618        let key = PublicKey::from_pkcs1_der(&pkcs1_der).unwrap();
619        key.verify_pkcs1_v1_5(&sig, &digest, DIGEST_INFO_SHA256_PREFIX).unwrap();
620    }
621
622    #[cfg(feature = "std")]
623    #[test]
624    fn wycheproof_rsa_pkcs1_2048_sha256() {
625        use crate::sha2::Sha256;
626        wycheproof_rsa_test!(
627            "../testdata/wycheproof/testvectors_v1/rsa_signature_2048_sha256_test.json",
628            Sha256,
629            DIGEST_INFO_SHA256_PREFIX
630        );
631    }
632
633    #[cfg(feature = "std")]
634    #[test]
635    fn wycheproof_rsa_pkcs1_2048_sha384() {
636        use crate::sha2::Sha384;
637        wycheproof_rsa_test!(
638            "../testdata/wycheproof/testvectors_v1/rsa_signature_2048_sha384_test.json",
639            Sha384,
640            DIGEST_INFO_SHA384_PREFIX
641        );
642    }
643
644    #[cfg(feature = "std")]
645    #[test]
646    fn wycheproof_rsa_pkcs1_2048_sha512() {
647        use crate::sha2::Sha512;
648        wycheproof_rsa_test!(
649            "../testdata/wycheproof/testvectors_v1/rsa_signature_2048_sha512_test.json",
650            Sha512,
651            DIGEST_INFO_SHA512_PREFIX
652        );
653    }
654}