hickory_proto/rr/dnssec/
public_key.rs

1// Copyright 2015-2016 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// https://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! Public Key implementations for supported key types
9#[cfg(not(any(feature = "openssl", feature = "ring")))]
10use std::marker::PhantomData;
11
12#[cfg(all(not(feature = "ring"), feature = "openssl"))]
13use openssl::bn::BigNum;
14#[cfg(all(not(feature = "ring"), feature = "openssl"))]
15use openssl::bn::BigNumContext;
16#[cfg(all(not(feature = "ring"), feature = "openssl"))]
17use openssl::ec::{EcGroup, EcKey, EcPoint};
18#[cfg(all(not(feature = "ring"), feature = "openssl"))]
19use openssl::nid::Nid;
20#[cfg(all(not(feature = "ring"), feature = "openssl"))]
21use openssl::pkey::{PKey, Public};
22#[cfg(all(not(feature = "ring"), feature = "openssl"))]
23use openssl::rsa::Rsa as OpenSslRsa;
24#[cfg(all(not(feature = "ring"), feature = "openssl"))]
25use openssl::sign::Verifier;
26#[cfg(feature = "ring")]
27use ring::signature::{self, ED25519_PUBLIC_KEY_LEN};
28
29use crate::error::*;
30use crate::rr::dnssec::Algorithm;
31#[cfg(all(not(feature = "ring"), feature = "openssl"))]
32use crate::rr::dnssec::DigestType;
33
34#[cfg(any(feature = "openssl", feature = "ring"))]
35use crate::rr::dnssec::ec_public_key::ECPublicKey;
36#[cfg(any(feature = "openssl", feature = "ring"))]
37use crate::rr::dnssec::rsa_public_key::RSAPublicKey;
38
39/// PublicKeys implement the ability to ideally be zero copy abstractions over public keys for verifying signed content.
40///
41/// In DNS the KEY and DNSKEY types are generally the RData types which store public key material.
42pub trait PublicKey {
43    /// Returns the public bytes of the public key, in DNS format
44    fn public_bytes(&self) -> &[u8];
45
46    /// Verifies the hash matches the signature with the current `key`.
47    ///
48    /// # Arguments
49    ///
50    /// * `message` - the message to be validated, see `hash_rrset`
51    /// * `signature` - the signature to use to verify the hash, extracted from an `RData::RRSIG`
52    ///                 for example.
53    ///
54    /// # Return value
55    ///
56    /// True if and only if the signature is valid for the hash. This will always return
57    /// false if the `key`.
58    #[allow(unused)]
59    fn verify(&self, algorithm: Algorithm, message: &[u8], signature: &[u8]) -> ProtoResult<()>;
60}
61
62#[cfg(all(not(feature = "ring"), feature = "openssl"))]
63fn verify_with_pkey(
64    pkey: &PKey<Public>,
65    algorithm: Algorithm,
66    message: &[u8],
67    signature: &[u8],
68) -> ProtoResult<()> {
69    let digest_type = DigestType::from(algorithm).to_openssl_digest()?;
70    let mut verifier = Verifier::new(digest_type, pkey)?;
71    verifier.update(message)?;
72    verifier
73        .verify(signature)
74        .map_err(Into::into)
75        .and_then(|b| {
76            if b {
77                Ok(())
78            } else {
79                Err("could not verify".into())
80            }
81        })
82}
83
84/// Elyptic Curve public key type
85#[cfg(all(not(feature = "ring"), feature = "openssl"))]
86#[cfg_attr(docsrs, doc(cfg(all(not(feature = "ring"), feature = "openssl"))))]
87pub struct Ec<'k> {
88    raw: &'k [u8],
89    pkey: PKey<Public>,
90}
91
92#[cfg(all(not(feature = "ring"), feature = "openssl"))]
93#[cfg_attr(docsrs, doc(cfg(all(not(feature = "ring"), feature = "openssl"))))]
94impl<'k> Ec<'k> {
95    /// ```text
96    /// RFC 6605                    ECDSA for DNSSEC                  April 2012
97    ///
98    ///   4.  DNSKEY and RRSIG Resource Records for ECDSA
99    ///
100    ///   ECDSA public keys consist of a single value, called "Q" in FIPS
101    ///   186-3.  In DNSSEC keys, Q is a simple bit string that represents the
102    ///   uncompressed form of a curve point, "x | y".
103    ///
104    ///   The ECDSA signature is the combination of two non-negative integers,
105    ///   called "r" and "s" in FIPS 186-3.  The two integers, each of which is
106    ///   formatted as a simple octet string, are combined into a single longer
107    ///   octet string for DNSSEC as the concatenation "r | s".  (Conversion of
108    ///   the integers to bit strings is described in Section C.2 of FIPS
109    ///   186-3.)  For P-256, each integer MUST be encoded as 32 octets; for
110    ///   P-384, each integer MUST be encoded as 48 octets.
111    ///
112    ///   The algorithm numbers associated with the DNSKEY and RRSIG resource
113    ///   records are fully defined in the IANA Considerations section.  They
114    ///   are:
115    ///
116    ///   o  DNSKEY and RRSIG RRs signifying ECDSA with the P-256 curve and
117    ///      SHA-256 use the algorithm number 13.
118    ///
119    ///   o  DNSKEY and RRSIG RRs signifying ECDSA with the P-384 curve and
120    ///      SHA-384 use the algorithm number 14.
121    ///
122    ///   Conformant implementations that create records to be put into the DNS
123    ///   MUST implement signing and verification for both of the above
124    ///   algorithms.  Conformant DNSSEC verifiers MUST implement verification
125    ///   for both of the above algorithms.
126    /// ```
127    pub fn from_public_bytes(public_key: &'k [u8], algorithm: Algorithm) -> ProtoResult<Self> {
128        let curve = match algorithm {
129            Algorithm::ECDSAP256SHA256 => Nid::X9_62_PRIME256V1,
130            Algorithm::ECDSAP384SHA384 => Nid::SECP384R1,
131            _ => return Err("only ECDSAP256SHA256 and ECDSAP384SHA384 are supported by Ec".into()),
132        };
133        // Key needs to be converted to OpenSSL format
134        let k = ECPublicKey::from_unprefixed(public_key, algorithm)?;
135        EcGroup::from_curve_name(curve)
136            .and_then(|group| BigNumContext::new().map(|ctx| (group, ctx)))
137            // FYI: BigNum slices treat all slices as BigEndian, i.e NetworkByteOrder
138            .and_then(|(group, mut ctx)| {
139                EcPoint::from_bytes(&group, k.prefixed_bytes(), &mut ctx)
140                    .map(|point| (group, point))
141            })
142            .and_then(|(group, point)| EcKey::from_public_key(&group, &point))
143            .and_then(PKey::from_ec_key)
144            .map_err(Into::into)
145            .map(|pkey| Ec {
146                raw: public_key,
147                pkey,
148            })
149    }
150}
151
152#[cfg(all(not(feature = "ring"), feature = "openssl"))]
153fn asn1_emit_integer(output: &mut Vec<u8>, int: &[u8]) {
154    assert!(!int.is_empty());
155    output.push(0x02); // INTEGER
156    if int[0] > 0x7f {
157        output.push((int.len() + 1) as u8);
158        output.push(0x00); // MSB must be zero
159        output.extend(int);
160        return;
161    }
162    // Trim leading zeros
163    let mut pos = 0;
164    while pos < int.len() {
165        if int[pos] == 0 {
166            if pos == int.len() - 1 {
167                break;
168            }
169            pos += 1;
170            continue;
171        }
172        if int[pos] > 0x7f {
173            // We need to leave one 0x00 to make MSB zero
174            pos -= 1;
175        }
176        break;
177    }
178    let int_output = &int[pos..];
179    output.push(int_output.len() as u8);
180    output.extend(int_output);
181}
182
183/// Convert raw DNSSEC ECDSA signature to ASN.1 DER format
184#[cfg(all(not(feature = "ring"), feature = "openssl"))]
185#[cfg_attr(docsrs, doc(cfg(all(not(feature = "ring"), feature = "openssl"))))]
186pub fn dnssec_ecdsa_signature_to_der(signature: &[u8]) -> ProtoResult<Vec<u8>> {
187    if signature.is_empty() || signature.len() & 1 != 0 || signature.len() > 127 {
188        return Err("invalid signature length".into());
189    }
190    let part_len = signature.len() / 2;
191    // ASN.1 SEQUENCE: 0x30 [LENGTH]
192    let mut signature_asn1 = vec![0x30, 0x00];
193    asn1_emit_integer(&mut signature_asn1, &signature[..part_len]);
194    asn1_emit_integer(&mut signature_asn1, &signature[part_len..]);
195    signature_asn1[1] = (signature_asn1.len() - 2) as u8;
196    Ok(signature_asn1)
197}
198
199#[cfg(all(not(feature = "ring"), feature = "openssl"))]
200#[cfg_attr(docsrs, doc(cfg(all(not(feature = "ring"), feature = "openssl"))))]
201impl PublicKey for Ec<'_> {
202    fn public_bytes(&self) -> &[u8] {
203        self.raw
204    }
205
206    fn verify(&self, algorithm: Algorithm, message: &[u8], signature: &[u8]) -> ProtoResult<()> {
207        let signature_asn1 = dnssec_ecdsa_signature_to_der(signature)?;
208        verify_with_pkey(&self.pkey, algorithm, message, &signature_asn1)
209    }
210}
211
212/// Elyptic Curve public key type
213#[cfg(feature = "ring")]
214#[cfg_attr(docsrs, doc(cfg(feature = "ring")))]
215pub type Ec = ECPublicKey;
216
217#[cfg(feature = "ring")]
218impl Ec {
219    /// ```text
220    /// RFC 6605                    ECDSA for DNSSEC                  April 2012
221    ///
222    ///   4.  DNSKEY and RRSIG Resource Records for ECDSA
223    ///
224    ///   ECDSA public keys consist of a single value, called "Q" in FIPS
225    ///   186-3.  In DNSSEC keys, Q is a simple bit string that represents the
226    ///   uncompressed form of a curve point, "x | y".
227    ///
228    ///   The ECDSA signature is the combination of two non-negative integers,
229    ///   called "r" and "s" in FIPS 186-3.  The two integers, each of which is
230    ///   formatted as a simple octet string, are combined into a single longer
231    ///   octet string for DNSSEC as the concatenation "r | s".  (Conversion of
232    ///   the integers to bit strings is described in Section C.2 of FIPS
233    ///   186-3.)  For P-256, each integer MUST be encoded as 32 octets; for
234    ///   P-384, each integer MUST be encoded as 48 octets.
235    ///
236    ///   The algorithm numbers associated with the DNSKEY and RRSIG resource
237    ///   records are fully defined in the IANA Considerations section.  They
238    ///   are:
239    ///
240    ///   o  DNSKEY and RRSIG RRs signifying ECDSA with the P-256 curve and
241    ///      SHA-256 use the algorithm number 13.
242    ///
243    ///   o  DNSKEY and RRSIG RRs signifying ECDSA with the P-384 curve and
244    ///      SHA-384 use the algorithm number 14.
245    ///
246    ///   Conformant implementations that create records to be put into the DNS
247    ///   MUST implement signing and verification for both of the above
248    ///   algorithms.  Conformant DNSSEC verifiers MUST implement verification
249    ///   for both of the above algorithms.
250    /// ```
251    pub fn from_public_bytes(public_key: &[u8], algorithm: Algorithm) -> ProtoResult<Self> {
252        Self::from_unprefixed(public_key, algorithm)
253    }
254}
255
256#[cfg(feature = "ring")]
257#[cfg_attr(docsrs, doc(cfg(feature = "ring")))]
258impl PublicKey for Ec {
259    fn public_bytes(&self) -> &[u8] {
260        self.unprefixed_bytes()
261    }
262
263    fn verify(&self, algorithm: Algorithm, message: &[u8], signature: &[u8]) -> ProtoResult<()> {
264        // TODO: assert_eq!(algorithm, self.algorithm); once *ring* allows this.
265        let alg = match algorithm {
266            Algorithm::ECDSAP256SHA256 => &signature::ECDSA_P256_SHA256_FIXED,
267            Algorithm::ECDSAP384SHA384 => &signature::ECDSA_P384_SHA384_FIXED,
268            _ => return Err("only ECDSAP256SHA256 and ECDSAP384SHA384 are supported by Ec".into()),
269        };
270        let public_key = signature::UnparsedPublicKey::new(alg, self.prefixed_bytes());
271        public_key.verify(message, signature).map_err(Into::into)
272    }
273}
274
275/// Ed25519 Public key
276#[cfg(feature = "ring")]
277#[cfg_attr(docsrs, doc(cfg(feature = "ring")))]
278pub struct Ed25519<'k> {
279    raw: &'k [u8],
280}
281
282#[cfg(feature = "ring")]
283#[cfg_attr(docsrs, doc(cfg(feature = "ring")))]
284impl<'k> Ed25519<'k> {
285    /// ```text
286    ///  Internet-Draft              EdDSA for DNSSEC               December 2016
287    ///
288    ///  An Ed25519 public key consists of a 32-octet value, which is encoded
289    ///  into the Public Key field of a DNSKEY resource record as a simple bit
290    ///  string.  The generation of a public key is defined in Section 5.1.5
291    ///  in [RFC 8032]. Breaking tradition, the keys are encoded in little-
292    ///  endian byte order.
293    /// ```
294    pub fn from_public_bytes(public_key: &'k [u8]) -> ProtoResult<Self> {
295        if public_key.len() != ED25519_PUBLIC_KEY_LEN {
296            return Err(format!(
297                "expected {} byte public_key: {}",
298                ED25519_PUBLIC_KEY_LEN,
299                public_key.len()
300            )
301            .into());
302        }
303
304        Ok(Ed25519 { raw: public_key })
305    }
306}
307
308#[cfg(feature = "ring")]
309impl PublicKey for Ed25519<'_> {
310    // TODO: just store reference to public key bytes in ctor...
311    fn public_bytes(&self) -> &[u8] {
312        self.raw
313    }
314
315    fn verify(&self, _: Algorithm, message: &[u8], signature: &[u8]) -> ProtoResult<()> {
316        let public_key = signature::UnparsedPublicKey::new(&signature::ED25519, self.raw);
317        public_key.verify(message, signature).map_err(Into::into)
318    }
319}
320
321/// Rsa public key
322#[cfg(any(feature = "openssl", feature = "ring"))]
323#[cfg_attr(docsrs, doc(cfg(any(feature = "openssl", feature = "ring"))))]
324pub struct Rsa<'k> {
325    raw: &'k [u8],
326
327    #[cfg(all(not(feature = "ring"), feature = "openssl"))]
328    pkey: PKey<Public>,
329
330    #[cfg(feature = "ring")]
331    pkey: RSAPublicKey<'k>,
332}
333
334#[cfg(any(feature = "openssl", feature = "ring"))]
335#[cfg_attr(docsrs, doc(cfg(any(feature = "openssl", feature = "ring"))))]
336impl<'k> Rsa<'k> {
337    /// ```text
338    /// RFC 3110              RSA SIGs and KEYs in the DNS              May 2001
339    ///
340    ///       2. RSA Public KEY Resource Records
341    ///
342    ///  RSA public keys are stored in the DNS as KEY RRs using algorithm
343    ///  number 5 [RFC2535].  The structure of the algorithm specific portion
344    ///  of the RDATA part of such RRs is as shown below.
345    ///
346    ///        Field             Size
347    ///        -----             ----
348    ///        exponent length   1 or 3 octets (see text)
349    ///        exponent          as specified by length field
350    ///        modulus           remaining space
351    ///
352    ///  For interoperability, the exponent and modulus are each limited to
353    ///  4096 bits in length.  The public key exponent is a variable length
354    ///  unsigned integer.  Its length in octets is represented as one octet
355    ///  if it is in the range of 1 to 255 and by a zero octet followed by a
356    ///  two octet unsigned length if it is longer than 255 bytes.  The public
357    ///  key modulus field is a multiprecision unsigned integer.  The length
358    ///  of the modulus can be determined from the RDLENGTH and the preceding
359    ///  RDATA fields including the exponent.  Leading zero octets are
360    ///  prohibited in the exponent and modulus.
361    ///
362    ///  Note: KEY RRs for use with RSA/SHA1 DNS signatures MUST use this
363    ///  algorithm number (rather than the algorithm number specified in the
364    ///  obsoleted RFC 2537).
365    ///
366    ///  Note: This changes the algorithm number for RSA KEY RRs to be the
367    ///  same as the new algorithm number for RSA/SHA1 SIGs.
368    /// ```
369    pub fn from_public_bytes(raw: &'k [u8]) -> ProtoResult<Self> {
370        let parsed = RSAPublicKey::try_from(raw)?;
371        let pkey = into_pkey(parsed)?;
372        Ok(Rsa { raw, pkey })
373    }
374}
375
376#[cfg(all(not(feature = "ring"), feature = "openssl"))]
377fn into_pkey(parsed: RSAPublicKey<'_>) -> ProtoResult<PKey<Public>> {
378    // FYI: BigNum slices treat all slices as BigEndian, i.e NetworkByteOrder
379    let e = BigNum::from_slice(parsed.e())?;
380    let n = BigNum::from_slice(parsed.n())?;
381
382    OpenSslRsa::from_public_components(n, e)
383        .and_then(PKey::from_rsa)
384        .map_err(Into::into)
385}
386
387#[cfg(feature = "ring")]
388#[allow(clippy::unnecessary_wraps)]
389fn into_pkey(parsed: RSAPublicKey<'_>) -> ProtoResult<RSAPublicKey<'_>> {
390    Ok(parsed)
391}
392
393#[cfg(any(feature = "openssl", feature = "ring"))]
394impl PublicKey for Rsa<'_> {
395    fn public_bytes(&self) -> &[u8] {
396        self.raw
397    }
398
399    #[cfg(all(not(feature = "ring"), feature = "openssl"))]
400    fn verify(&self, algorithm: Algorithm, message: &[u8], signature: &[u8]) -> ProtoResult<()> {
401        verify_with_pkey(&self.pkey, algorithm, message, signature)
402    }
403
404    #[cfg(feature = "ring")]
405    fn verify(&self, algorithm: Algorithm, message: &[u8], signature: &[u8]) -> ProtoResult<()> {
406        #[allow(deprecated)]
407        let alg = match algorithm {
408            Algorithm::RSASHA256 => &signature::RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY,
409            Algorithm::RSASHA512 => &signature::RSA_PKCS1_1024_8192_SHA512_FOR_LEGACY_USE_ONLY,
410            Algorithm::RSASHA1 => &signature::RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY,
411            Algorithm::RSASHA1NSEC3SHA1 => {
412                return Err("*ring* doesn't support RSASHA1NSEC3SHA1 yet".into())
413            }
414            _ => unreachable!("non-RSA algorithm passed to RSA verify()"),
415        };
416        let public_key = signature::RsaPublicKeyComponents {
417            n: self.pkey.n(),
418            e: self.pkey.e(),
419        };
420        public_key
421            .verify(alg, message, signature)
422            .map_err(Into::into)
423    }
424}
425
426/// Variants of all know public keys
427#[non_exhaustive]
428pub enum PublicKeyEnum<'k> {
429    /// RSA keypair, supported by OpenSSL
430    #[cfg(any(feature = "openssl", feature = "ring"))]
431    #[cfg_attr(docsrs, doc(cfg(any(feature = "openssl", feature = "ring"))))]
432    Rsa(Rsa<'k>),
433    /// Elliptic curve keypair
434    #[cfg(all(not(feature = "ring"), feature = "openssl"))]
435    #[cfg_attr(docsrs, doc(cfg(any(all(not(feature = "ring"), feature = "openssl")))))]
436    Ec(Ec<'k>),
437    /// Elliptic curve keypair
438    #[cfg(feature = "ring")]
439    #[cfg_attr(docsrs, doc(cfg(feature = "ring")))]
440    Ec(Ec),
441    /// Ed25519 public key for the Algorithm::ED25519
442    #[cfg(feature = "ring")]
443    #[cfg_attr(docsrs, doc(cfg(feature = "ring")))]
444    Ed25519(Ed25519<'k>),
445    /// PhatomData for compiler when ring and or openssl not defined, do not use...
446    #[cfg(not(any(feature = "ring", feature = "openssl")))]
447    #[cfg_attr(docsrs, doc(cfg(not(any(feature = "ring", feature = "openssl")))))]
448    Phantom(&'k PhantomData<()>),
449}
450
451impl<'k> PublicKeyEnum<'k> {
452    /// Converts the bytes into a PulbicKey of the specified algorithm
453    #[allow(unused_variables, clippy::match_single_binding)]
454    pub fn from_public_bytes(public_key: &'k [u8], algorithm: Algorithm) -> ProtoResult<Self> {
455        #[allow(deprecated)]
456        match algorithm {
457            #[cfg(any(feature = "openssl", feature = "ring"))]
458            Algorithm::ECDSAP256SHA256 | Algorithm::ECDSAP384SHA384 => Ok(PublicKeyEnum::Ec(
459                Ec::from_public_bytes(public_key, algorithm)?,
460            )),
461            #[cfg(feature = "ring")]
462            Algorithm::ED25519 => Ok(PublicKeyEnum::Ed25519(Ed25519::from_public_bytes(
463                public_key,
464            )?)),
465            #[cfg(any(feature = "openssl", feature = "ring"))]
466            Algorithm::RSASHA1
467            | Algorithm::RSASHA1NSEC3SHA1
468            | Algorithm::RSASHA256
469            | Algorithm::RSASHA512 => Ok(PublicKeyEnum::Rsa(Rsa::from_public_bytes(public_key)?)),
470            _ => Err("public key algorithm not supported".into()),
471        }
472    }
473}
474
475impl PublicKey for PublicKeyEnum<'_> {
476    #[allow(clippy::match_single_binding, clippy::match_single_binding)]
477    fn public_bytes(&self) -> &[u8] {
478        match *self {
479            #[cfg(any(feature = "openssl", feature = "ring"))]
480            PublicKeyEnum::Ec(ref ec) => ec.public_bytes(),
481            #[cfg(feature = "ring")]
482            PublicKeyEnum::Ed25519(ref ed) => ed.public_bytes(),
483            #[cfg(any(feature = "openssl", feature = "ring"))]
484            PublicKeyEnum::Rsa(ref rsa) => rsa.public_bytes(),
485            #[cfg(not(any(feature = "ring", feature = "openssl")))]
486            _ => panic!("no public keys registered, enable ring or openssl features"),
487        }
488    }
489
490    #[allow(unused_variables, clippy::match_single_binding)]
491    fn verify(&self, algorithm: Algorithm, message: &[u8], signature: &[u8]) -> ProtoResult<()> {
492        match *self {
493            #[cfg(any(feature = "openssl", feature = "ring"))]
494            PublicKeyEnum::Ec(ref ec) => ec.verify(algorithm, message, signature),
495            #[cfg(feature = "ring")]
496            PublicKeyEnum::Ed25519(ref ed) => ed.verify(algorithm, message, signature),
497            #[cfg(any(feature = "openssl", feature = "ring"))]
498            PublicKeyEnum::Rsa(ref rsa) => rsa.verify(algorithm, message, signature),
499            #[cfg(not(any(feature = "ring", feature = "openssl")))]
500            _ => panic!("no public keys registered, enable ring or openssl features"),
501        }
502    }
503}
504
505/// An owned variant of PublicKey
506pub struct PublicKeyBuf {
507    key_buf: Vec<u8>,
508}
509
510impl PublicKeyBuf {
511    /// Constructs a new PublicKey from the specified bytes, these should be in DNSKEY form.
512    pub fn new(key_buf: Vec<u8>) -> Self {
513        Self { key_buf }
514    }
515}
516
517impl PublicKey for PublicKeyBuf {
518    fn public_bytes(&self) -> &[u8] {
519        &self.key_buf
520    }
521
522    fn verify(&self, algorithm: Algorithm, message: &[u8], signature: &[u8]) -> ProtoResult<()> {
523        let public_key = PublicKeyEnum::from_public_bytes(&self.key_buf, algorithm)?;
524
525        public_key.verify(algorithm, message, signature)
526    }
527}
528
529#[cfg(all(not(feature = "ring"), feature = "openssl"))]
530#[cfg(test)]
531mod tests {
532    #[cfg(feature = "openssl")]
533    #[test]
534    fn test_asn1_emit_integer() {
535        fn test_case(source: &[u8], expected_data: &[u8]) {
536            use crate::rr::dnssec::public_key::asn1_emit_integer;
537
538            let mut output = Vec::<u8>::new();
539            asn1_emit_integer(&mut output, source);
540            assert_eq!(output[0], 0x02);
541            assert_eq!(output[1], expected_data.len() as u8);
542            assert_eq!(&output[2..], expected_data);
543        }
544        test_case(&[0x00], &[0x00]);
545        test_case(&[0x00, 0x00], &[0x00]);
546        test_case(&[0x7f], &[0x7f]);
547        test_case(&[0x80], &[0x00, 0x80]);
548        test_case(&[0x00, 0x80], &[0x00, 0x80]);
549        test_case(&[0x00, 0x00, 0x80], &[0x00, 0x80]);
550        test_case(&[0x7f, 0x00, 0x80], &[0x7f, 0x00, 0x80]);
551        test_case(&[0x00, 0x7f, 0x00, 0x80], &[0x7f, 0x00, 0x80]);
552        test_case(&[0x80, 0x00, 0x80], &[0x00, 0x80, 0x00, 0x80]);
553        test_case(&[0xff, 0x00, 0x80], &[0x00, 0xff, 0x00, 0x80]);
554    }
555}