Skip to main content

hickory_proto/dnssec/
crypto.rs

1use alloc::{borrow::Cow, boxed::Box, sync::Arc, vec::Vec};
2
3use rustls_pki_types::{PrivateKeyDer, PrivatePkcs1KeyDer, PrivatePkcs8KeyDer};
4
5use super::{
6    Algorithm, DigestType, DnsSecError, DnsSecResult, PublicKey, PublicKeyBuf, SigningKey, TBS,
7    ec_public_key::ECPublicKey,
8    ring_like::{
9        ECDSA_P256_SHA256_FIXED_SIGNING, ECDSA_P384_SHA384_FIXED_SIGNING, ED25519_PUBLIC_KEY_LEN,
10        EcdsaKeyPair, Ed25519KeyPair, KeyPair, PublicKeyComponents, RSA_PKCS1_SHA256,
11        RSA_PKCS1_SHA512, RsaKeyPair, SystemRandom, digest, signature,
12    },
13    rsa_public_key::RSAPublicKey,
14};
15use crate::{ProtoError, error::ProtoResult, serialize::binary::DecodeError};
16
17/// Decode private key
18pub fn signing_key_from_der(
19    key_der: &PrivateKeyDer<'_>,
20    algorithm: Algorithm,
21) -> DnsSecResult<Box<dyn SigningKey>> {
22    #[allow(deprecated)]
23    match algorithm {
24        Algorithm::Unknown(v) => Err(format!("unknown algorithm: {v}").into()),
25        Algorithm::RSASHA256 | Algorithm::RSASHA512 => {
26            Ok(Box::new(RsaSigningKey::from_key_der(key_der, algorithm)?))
27        }
28        Algorithm::ECDSAP256SHA256 | Algorithm::ECDSAP384SHA384 => {
29            Ok(Box::new(EcdsaSigningKey::from_key_der(key_der, algorithm)?))
30        }
31        Algorithm::ED25519 => Ok(Box::new(Ed25519SigningKey::from_key_der(key_der)?)),
32        e => Err(format!("unsupported SigningKey algorithm for ring: {e:?}").into()),
33    }
34}
35
36pub(super) fn decode_public_key<'a>(
37    public_key: &'a [u8],
38    algorithm: Algorithm,
39) -> ProtoResult<Arc<dyn PublicKey + 'a>> {
40    // try to keep this and `Algorithm::is_supported` in sync
41    debug_assert!(algorithm.is_supported());
42
43    #[allow(deprecated)]
44    match algorithm {
45        Algorithm::ECDSAP256SHA256 | Algorithm::ECDSAP384SHA384 => Ok(Arc::new(
46            ECPublicKey::from_public_bytes(public_key, algorithm)?,
47        )),
48        Algorithm::ED25519 => Ok(Arc::new(Ed25519::from_public_bytes(public_key.into())?)),
49        Algorithm::RSASHA1
50        | Algorithm::RSASHA1NSEC3SHA1
51        | Algorithm::RSASHA256
52        | Algorithm::RSASHA512 => Ok(Arc::new(Rsa::from_public_bytes(public_key, algorithm)?)),
53        _ => Err("public key algorithm not supported".into()),
54    }
55}
56
57/// An ECDSA signing key pair (backed by ring).
58pub struct EcdsaSigningKey {
59    inner: EcdsaKeyPair,
60    algorithm: Algorithm,
61}
62
63impl EcdsaSigningKey {
64    /// Decode signing key pair from DER.
65    ///
66    /// Errors unless the given algorithm is one of the following:
67    ///
68    /// - [`Algorithm::ECDSAP256SHA256`]
69    /// - [`Algorithm::ECDSAP384SHA384`]
70    pub fn from_key_der(key: &PrivateKeyDer<'_>, algorithm: Algorithm) -> DnsSecResult<Self> {
71        match key {
72            PrivateKeyDer::Pkcs8(key) => Self::from_pkcs8(key, algorithm),
73            _ => Err("unsupported key format (only PKCS#8 supported)".into()),
74        }
75    }
76
77    /// Decode signing key pair from DER-encoded PKCS#8 bytes.
78    ///
79    /// Errors unless the given algorithm is one of the following:
80    ///
81    /// - [`Algorithm::ECDSAP256SHA256`]
82    /// - [`Algorithm::ECDSAP384SHA384`]
83    pub fn from_pkcs8(key: &PrivatePkcs8KeyDer<'_>, algorithm: Algorithm) -> DnsSecResult<Self> {
84        let ring_algorithm = if algorithm == Algorithm::ECDSAP256SHA256 {
85            &ECDSA_P256_SHA256_FIXED_SIGNING
86        } else if algorithm == Algorithm::ECDSAP384SHA384 {
87            &ECDSA_P384_SHA384_FIXED_SIGNING
88        } else {
89            return Err(DnsSecError::Message("unsupported algorithm"));
90        };
91
92        #[cfg(all(feature = "dnssec-aws-lc-rs", not(feature = "dnssec-ring")))]
93        let inner = EcdsaKeyPair::from_pkcs8(ring_algorithm, key.secret_pkcs8_der())?;
94
95        #[cfg(feature = "dnssec-ring")]
96        let inner =
97            EcdsaKeyPair::from_pkcs8(ring_algorithm, key.secret_pkcs8_der(), &SystemRandom::new())?;
98
99        Ok(Self { inner, algorithm })
100    }
101
102    /// Creates an ECDSA key pair with ring.
103    pub fn from_ecdsa(inner: EcdsaKeyPair, algorithm: Algorithm) -> Self {
104        Self { inner, algorithm }
105    }
106
107    /// Generate signing key pair and return the DER-encoded PKCS#8 bytes.
108    ///
109    /// Errors unless the given algorithm is one of the following:
110    ///
111    /// - [`Algorithm::ECDSAP256SHA256`]
112    /// - [`Algorithm::ECDSAP384SHA384`]
113    pub fn generate_pkcs8(algorithm: Algorithm) -> DnsSecResult<PrivatePkcs8KeyDer<'static>> {
114        let rng = SystemRandom::new();
115        let alg = if algorithm == Algorithm::ECDSAP256SHA256 {
116            &ECDSA_P256_SHA256_FIXED_SIGNING
117        } else if algorithm == Algorithm::ECDSAP384SHA384 {
118            &ECDSA_P384_SHA384_FIXED_SIGNING
119        } else {
120            return Err(DnsSecError::Message("unsupported algorithm"));
121        };
122
123        let pkcs8 = EcdsaKeyPair::generate_pkcs8(alg, &rng)?;
124        Ok(PrivatePkcs8KeyDer::from(pkcs8.as_ref().to_vec()))
125    }
126}
127
128impl SigningKey for EcdsaSigningKey {
129    fn sign(&self, tbs: &TBS) -> DnsSecResult<Vec<u8>> {
130        let rng = SystemRandom::new();
131        Ok(self.inner.sign(&rng, tbs.as_ref())?.as_ref().to_vec())
132    }
133
134    fn to_public_key(&self) -> DnsSecResult<PublicKeyBuf> {
135        let mut bytes = self.inner.public_key().as_ref().to_vec();
136        bytes.remove(0);
137        Ok(PublicKeyBuf::new(bytes, self.algorithm))
138    }
139
140    fn algorithm(&self) -> Algorithm {
141        self.algorithm
142    }
143}
144
145/// An Ed25519 signing key pair (backed by ring).
146pub struct Ed25519SigningKey {
147    inner: Ed25519KeyPair,
148}
149
150impl Ed25519SigningKey {
151    /// Decode signing key pair from DER.
152    pub fn from_key_der(key: &PrivateKeyDer<'_>) -> DnsSecResult<Self> {
153        match key {
154            PrivateKeyDer::Pkcs8(key) => Self::from_pkcs8(key),
155            _ => Err("unsupported key format (only PKCS#8 supported)".into()),
156        }
157    }
158
159    /// Decode signing key pair from DER-encoded PKCS#8 bytes.
160    pub fn from_pkcs8(key: &PrivatePkcs8KeyDer<'_>) -> DnsSecResult<Self> {
161        Ok(Self {
162            inner: Ed25519KeyPair::from_pkcs8(key.secret_pkcs8_der())?,
163        })
164    }
165
166    /// Creates an Ed25519 keypair.
167    pub fn from_ed25519(inner: Ed25519KeyPair) -> Self {
168        Self { inner }
169    }
170
171    /// Generate signing key pair and return the DER-encoded PKCS#8 bytes.
172    pub fn generate_pkcs8() -> DnsSecResult<PrivatePkcs8KeyDer<'static>> {
173        let rng = SystemRandom::new();
174        let pkcs8 = Ed25519KeyPair::generate_pkcs8(&rng)?;
175        Ok(PrivatePkcs8KeyDer::from(pkcs8.as_ref().to_vec()))
176    }
177}
178
179impl SigningKey for Ed25519SigningKey {
180    fn sign(&self, tbs: &TBS) -> DnsSecResult<Vec<u8>> {
181        Ok(self.inner.sign(tbs.as_ref()).as_ref().to_vec())
182    }
183
184    fn to_public_key(&self) -> DnsSecResult<PublicKeyBuf> {
185        Ok(PublicKeyBuf::new(
186            self.inner.public_key().as_ref().to_vec(),
187            Algorithm::ED25519,
188        ))
189    }
190
191    fn algorithm(&self) -> Algorithm {
192        Algorithm::ED25519
193    }
194}
195
196/// Ed25519 Public key
197pub struct Ed25519<'k> {
198    raw: Cow<'k, [u8]>,
199}
200
201impl<'k> Ed25519<'k> {
202    /// ```text
203    /// RFC 8080                    EdDSA for DNSSEC               February 2017
204    ///
205    ///  An Ed25519 public key consists of a 32-octet value, which is encoded
206    ///  into the Public Key field of a DNSKEY resource record as a simple bit
207    ///  string.  The generation of a public key is defined in Section 5.1.5
208    ///  of [RFC8032].
209    /// ```
210    pub fn from_public_bytes(public_key: Cow<'k, [u8]>) -> ProtoResult<Self> {
211        if public_key.len() != ED25519_PUBLIC_KEY_LEN {
212            return Err(format!(
213                "expected {} byte public_key: {}",
214                ED25519_PUBLIC_KEY_LEN,
215                public_key.len()
216            )
217            .into());
218        }
219
220        Ok(Self { raw: public_key })
221    }
222}
223
224impl PublicKey for Ed25519<'_> {
225    // TODO: just store reference to public key bytes in ctor...
226    fn public_bytes(&self) -> &[u8] {
227        self.raw.as_ref()
228    }
229
230    fn verify(&self, message: &[u8], signature: &[u8]) -> ProtoResult<()> {
231        let public_key = signature::UnparsedPublicKey::new(&signature::ED25519, self.raw.as_ref());
232        public_key
233            .verify(message, signature)
234            .map_err(|_| ProtoError::Crypto("ED25519 signature verification failed"))
235    }
236
237    fn algorithm(&self) -> Algorithm {
238        Algorithm::ED25519
239    }
240}
241
242/// Rsa public key
243pub struct Rsa<'k> {
244    raw: &'k [u8],
245    pkey: RSAPublicKey<'k>,
246    algorithm: Algorithm,
247}
248
249impl<'k> Rsa<'k> {
250    /// ```text
251    /// RFC 3110              RSA SIGs and KEYs in the DNS              May 2001
252    ///
253    ///       2. RSA Public KEY Resource Records
254    ///
255    ///  RSA public keys are stored in the DNS as KEY RRs using algorithm
256    ///  number 5 [RFC2535].  The structure of the algorithm specific portion
257    ///  of the RDATA part of such RRs is as shown below.
258    ///
259    ///        Field             Size
260    ///        -----             ----
261    ///        exponent length   1 or 3 octets (see text)
262    ///        exponent          as specified by length field
263    ///        modulus           remaining space
264    ///
265    ///  For interoperability, the exponent and modulus are each limited to
266    ///  4096 bits in length.  The public key exponent is a variable length
267    ///  unsigned integer.  Its length in octets is represented as one octet
268    ///  if it is in the range of 1 to 255 and by a zero octet followed by a
269    ///  two octet unsigned length if it is longer than 255 bytes.  The public
270    ///  key modulus field is a multiprecision unsigned integer.  The length
271    ///  of the modulus can be determined from the RDLENGTH and the preceding
272    ///  RDATA fields including the exponent.  Leading zero octets are
273    ///  prohibited in the exponent and modulus.
274    ///
275    ///  Note: KEY RRs for use with RSA/SHA1 DNS signatures MUST use this
276    ///  algorithm number (rather than the algorithm number specified in the
277    ///  obsoleted RFC 2537).
278    ///
279    ///  Note: This changes the algorithm number for RSA KEY RRs to be the
280    ///  same as the new algorithm number for RSA/SHA1 SIGs.
281    /// ```
282    pub fn from_public_bytes(raw: &'k [u8], algorithm: Algorithm) -> ProtoResult<Self> {
283        let pkey = RSAPublicKey::try_from(raw)?;
284        Ok(Self {
285            raw,
286            pkey,
287            algorithm,
288        })
289    }
290}
291
292impl PublicKey for Rsa<'_> {
293    fn public_bytes(&self) -> &[u8] {
294        self.raw
295    }
296
297    fn verify(&self, message: &[u8], signature: &[u8]) -> ProtoResult<()> {
298        #[allow(deprecated)]
299        let alg = match self.algorithm {
300            Algorithm::RSASHA256 => &signature::RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY,
301            Algorithm::RSASHA512 => &signature::RSA_PKCS1_1024_8192_SHA512_FOR_LEGACY_USE_ONLY,
302            // RFC 5155 §2: algorithm 7 uses the same RSA/SHA-1 signature scheme as algorithm 5;
303            // the distinct identifier only signals NSEC3 capability of the signer.
304            Algorithm::RSASHA1 | Algorithm::RSASHA1NSEC3SHA1 => {
305                &signature::RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY
306            }
307            _ => unreachable!("non-RSA algorithm passed to RSA verify()"),
308        };
309        let public_key = signature::RsaPublicKeyComponents {
310            n: self.pkey.n(),
311            e: self.pkey.e(),
312        };
313        public_key
314            .verify(alg, message, signature)
315            .map_err(|_| ProtoError::Crypto("RSA signature verification failed"))
316    }
317
318    fn algorithm(&self) -> Algorithm {
319        self.algorithm
320    }
321}
322
323/// An RSA signing key pair (backed by ring).
324pub struct RsaSigningKey {
325    inner: RsaKeyPair,
326    algorithm: Algorithm,
327}
328
329impl RsaSigningKey {
330    /// Decode signing key pair from DER.
331    pub fn from_key_der(key: &PrivateKeyDer<'_>, algorithm: Algorithm) -> DnsSecResult<Self> {
332        match key {
333            PrivateKeyDer::Pkcs8(key) => Self::from_pkcs8(key, algorithm),
334            PrivateKeyDer::Pkcs1(key) => Self::from_pkcs1(key, algorithm),
335            _ => Err("unsupported key format (only PKCS#8 supported)".into()),
336        }
337    }
338
339    /// Decode signing key pair from DER-encoded PKCS#8 bytes.
340    pub fn from_pkcs8(key: &PrivatePkcs8KeyDer<'_>, algorithm: Algorithm) -> DnsSecResult<Self> {
341        match algorithm {
342            #[allow(deprecated)]
343            Algorithm::RSASHA1 | Algorithm::RSASHA1NSEC3SHA1 => {
344                return Err("unsupported Algorithm (insecure): {algorithm:?}".into());
345            }
346            Algorithm::RSASHA256 | Algorithm::RSASHA512 => {}
347            _ => return Err("unsupported Algorithm: {algorithm:?}".into()),
348        }
349
350        Ok(Self {
351            inner: RsaKeyPair::from_pkcs8(key.secret_pkcs8_der())?,
352            algorithm,
353        })
354    }
355
356    /// Decode signing key pair from DER-encoded PKCS#1 bytes.
357    pub fn from_pkcs1(key: &PrivatePkcs1KeyDer<'_>, algorithm: Algorithm) -> DnsSecResult<Self> {
358        match algorithm {
359            #[allow(deprecated)]
360            Algorithm::RSASHA1 | Algorithm::RSASHA1NSEC3SHA1 => {
361                return Err("unsupported Algorithm (insecure): {algorithm:?}".into());
362            }
363            Algorithm::RSASHA256 | Algorithm::RSASHA512 => {}
364            _ => return Err("unsupported Algorithm: {algorithm:?}".into()),
365        }
366
367        Ok(Self {
368            inner: RsaKeyPair::from_der(key.secret_pkcs1_der())?,
369            algorithm,
370        })
371    }
372}
373
374impl SigningKey for RsaSigningKey {
375    fn sign(&self, tbs: &TBS) -> DnsSecResult<Vec<u8>> {
376        let encoding = match self.algorithm {
377            Algorithm::RSASHA256 => &RSA_PKCS1_SHA256,
378            Algorithm::RSASHA512 => &RSA_PKCS1_SHA512,
379            _ => unreachable!(),
380        };
381
382        let rng = SystemRandom::new();
383        let mut signature = vec![0; self.inner.public_key().modulus_len()];
384        self.inner
385            .sign(encoding, &rng, tbs.as_ref(), &mut signature)?;
386        Ok(signature)
387    }
388
389    fn to_public_key(&self) -> DnsSecResult<PublicKeyBuf> {
390        let components = PublicKeyComponents::<Vec<u8>>::from(self.inner.public_key());
391
392        let mut buf = Vec::with_capacity(components.e.len() + components.n.len());
393        if components.e.len() > 255 {
394            buf.push(0);
395            buf.push((components.e.len() >> 8) as u8);
396        }
397
398        buf.push(components.e.len() as u8);
399        buf.extend(&components.e);
400        buf.extend(&components.n);
401        Ok(PublicKeyBuf::new(buf, self.algorithm))
402    }
403
404    fn algorithm(&self) -> Algorithm {
405        self.algorithm
406    }
407}
408
409/// Hashing wrapper type.
410#[derive(Clone, Copy, Debug)]
411pub struct Digest(digest::Digest);
412
413impl Digest {
414    /// Hashes the given `data` `iterations` times with the given `salt` and `r#type`.
415    pub fn iterated(
416        salt: &[u8],
417        bytes: &[u8],
418        r#type: DigestType,
419        mut iterations: u16,
420    ) -> Result<Self, DecodeError> {
421        let alg = r#type.try_into()?;
422        let mut cur = hash_iter([bytes, salt], alg);
423        while iterations > 0 {
424            cur = hash_iter([cur.as_ref(), salt], alg);
425            iterations -= 1;
426        }
427        Ok(Self(cur))
428    }
429
430    /// Hashes the data from the `bytes` iterator with the given `r#type`.
431    pub fn from_iter<'a>(
432        bytes: impl IntoIterator<Item = &'a [u8]>,
433        r#type: DigestType,
434    ) -> Result<Self, DecodeError> {
435        Ok(Self(hash_iter(bytes, r#type.try_into()?)))
436    }
437
438    /// Hashes
439    pub fn new(bytes: &[u8], r#type: DigestType) -> Result<Self, DecodeError> {
440        Ok(Self(digest::digest(r#type.try_into()?, bytes)))
441    }
442}
443
444fn hash_iter<'a>(
445    iter: impl IntoIterator<Item = &'a [u8]>,
446    alg: &'static digest::Algorithm,
447) -> digest::Digest {
448    let mut ctx = digest::Context::new(alg);
449    for d in iter {
450        ctx.update(d);
451    }
452    ctx.finish()
453}
454
455impl AsRef<[u8]> for Digest {
456    fn as_ref(&self) -> &[u8] {
457        self.0.as_ref()
458    }
459}
460
461impl TryFrom<DigestType> for &'static digest::Algorithm {
462    type Error = DecodeError;
463
464    fn try_from(value: DigestType) -> Result<&'static digest::Algorithm, Self::Error> {
465        match value {
466            DigestType::SHA1 => Ok(&digest::SHA1_FOR_LEGACY_USE_ONLY),
467            DigestType::SHA256 => Ok(&digest::SHA256),
468            DigestType::SHA384 => Ok(&digest::SHA384),
469            DigestType::Unknown(other) => Err(DecodeError::UnknownDigestAlgorithm(other)),
470        }
471    }
472}
473
474#[cfg(test)]
475mod tests {
476    use rustls_pki_types::pem::PemObject;
477
478    use super::*;
479    use crate::dnssec::test_utils::{hash_test, public_key_test};
480
481    #[test]
482    fn test_ec_p256_pkcs8() {
483        let algorithm = Algorithm::ECDSAP256SHA256;
484        let pkcs8 = EcdsaSigningKey::generate_pkcs8(algorithm).unwrap();
485        let key = signing_key_from_der(&PrivateKeyDer::from(pkcs8), algorithm).unwrap();
486        public_key_test(&*key);
487
488        let neg_pkcs8 = EcdsaSigningKey::generate_pkcs8(algorithm).unwrap();
489        let neg = signing_key_from_der(&PrivateKeyDer::from(neg_pkcs8), algorithm).unwrap();
490        hash_test(&*key, &*neg);
491    }
492
493    #[test]
494    fn test_ec_p384_pkcs8() {
495        let algorithm = Algorithm::ECDSAP384SHA384;
496        let pkcs8 = EcdsaSigningKey::generate_pkcs8(algorithm).unwrap();
497        let key = signing_key_from_der(&PrivateKeyDer::from(pkcs8), algorithm).unwrap();
498        public_key_test(&*key);
499
500        let neg_pkcs8 = EcdsaSigningKey::generate_pkcs8(algorithm).unwrap();
501        let neg = signing_key_from_der(&PrivateKeyDer::from(neg_pkcs8), algorithm).unwrap();
502        hash_test(&*key, &*neg);
503    }
504
505    #[test]
506    fn test_ed25519() {
507        let algorithm = Algorithm::ED25519;
508        let pkcs8 = Ed25519SigningKey::generate_pkcs8().unwrap();
509        let key = signing_key_from_der(&PrivateKeyDer::from(pkcs8), algorithm).unwrap();
510        public_key_test(&*key);
511
512        let neg_pkcs8 = Ed25519SigningKey::generate_pkcs8().unwrap();
513        let neg = signing_key_from_der(&PrivateKeyDer::from(neg_pkcs8), algorithm).unwrap();
514        hash_test(&*key, &*neg);
515    }
516
517    #[test]
518    fn test_rsa() {
519        // ring currently does not support RSA key generation support.
520        // Generated per the documentation from https://docs.rs/ring/latest/ring/rsa/struct.KeyPair.html#method.from_pkcs8.
521        const KEY_1: &[u8] = include_bytes!("../../tests/test-data/rsa-2048-private-key-1.pk8");
522        const KEY_2: &[u8] = include_bytes!("../../tests/test-data/rsa-2048-private-key-2.pk8");
523
524        let algorithm = Algorithm::RSASHA256;
525        let key_der = PrivateKeyDer::try_from(KEY_1).unwrap();
526        let key = signing_key_from_der(&key_der, algorithm).unwrap();
527        public_key_test(&*key);
528
529        let key_der = PrivateKeyDer::try_from(KEY_2).unwrap();
530        let neg = signing_key_from_der(&key_der, algorithm).unwrap();
531        hash_test(&*key, &*neg);
532    }
533
534    #[test]
535    fn test_ec_encode_decode_pkcs8() {
536        let algorithm = Algorithm::ECDSAP256SHA256;
537        let pkcs8 = EcdsaSigningKey::generate_pkcs8(algorithm).unwrap();
538        signing_key_from_der(&PrivateKeyDer::from(pkcs8), algorithm).unwrap();
539    }
540
541    #[test]
542    fn test_ed25519_encode_decode_pkcs8() {
543        let pkcs8 = Ed25519SigningKey::generate_pkcs8().unwrap();
544        signing_key_from_der(&PrivateKeyDer::from(pkcs8), Algorithm::ED25519).unwrap();
545    }
546
547    #[test]
548    fn test_rsasha256_encode_decode_pkcs8() {
549        // ring currently does not support RSA key generation support.
550        // Generated per the documentation from https://docs.rs/ring/latest/ring/rsa/struct.KeyPair.html#method.from_pkcs8.
551        const KEY: &[u8] = include_bytes!("../../tests/test-data/rsa-2048-private-key-1.pk8");
552        let key_der = PrivateKeyDer::try_from(KEY).unwrap();
553        signing_key_from_der(&key_der, Algorithm::RSASHA256).unwrap();
554    }
555
556    #[test]
557    fn test_rsasha256_decode_pkcs1() {
558        const KEY: &[u8] = include_bytes!("../../tests/test-data/rsa-2048-pkcs1.pem");
559        let key_der = PrivateKeyDer::from_pem_slice(KEY).unwrap();
560        assert!(matches!(key_der, PrivateKeyDer::Pkcs1(_)));
561        signing_key_from_der(&key_der, Algorithm::RSASHA256).unwrap();
562    }
563
564    /// Regression test for https://github.com/hickory-dns/hickory-dns/issues/3690.
565    ///
566    /// Per RFC 5155 §2, DNSSEC algorithm 7 (RSASHA1NSEC3SHA1) uses the same RSA/SHA-1
567    /// signature scheme as algorithm 5 (RSASHA1); the distinct identifier only signals
568    /// that the signer understands NSEC3. `Algorithm::is_supported()` advertises both,
569    /// so `Rsa::verify` must accept them on equal footing instead of rejecting alg 7.
570    #[test]
571    #[allow(deprecated)]
572    fn test_rsasha1_nsec3sha1_uses_same_crypto_as_rsasha1() {
573        const KEY: &[u8] = include_bytes!("../../tests/test-data/rsa-2048-private-key-1.pk8");
574        let signing =
575            RsaSigningKey::from_pkcs8(&PrivatePkcs8KeyDer::from(KEY), Algorithm::RSASHA256)
576                .unwrap();
577        let key_bytes = signing.to_public_key().unwrap().into_inner();
578
579        // Both algorithms must take the same code path. A garbage signature must
580        // produce a verifier failure, not an algorithm-dispatch failure.
581        for algorithm in [Algorithm::RSASHA1, Algorithm::RSASHA1NSEC3SHA1] {
582            let key = Rsa::from_public_bytes(&key_bytes, algorithm).unwrap();
583            let err = key.verify(b"message", b"bogus signature").unwrap_err();
584            assert!(
585                matches!(err, ProtoError::Crypto("RSA signature verification failed")),
586                "unexpected error for {algorithm:?}: {err:?}",
587            );
588        }
589    }
590}