1#[cfg(not(feature = "openssl"))]
9use std::marker::PhantomData;
10
11#[cfg(feature = "openssl")]
12use openssl::bn::BigNumContext;
13#[cfg(feature = "openssl")]
14use openssl::ec::{EcGroup, EcKey, PointConversionForm};
15#[cfg(feature = "openssl")]
16use openssl::nid::Nid;
17#[cfg(feature = "openssl")]
18use openssl::pkey::PKey;
19#[cfg(feature = "openssl")]
20use openssl::rsa::Rsa as OpenSslRsa;
21#[cfg(feature = "openssl")]
22use openssl::sign::Signer;
23
24#[allow(deprecated)]
25use crate::rr::dnssec::rdata::key::{KeyTrust, Protocol, UpdateScope};
26#[cfg(feature = "ring")]
27use ring::{
28 rand,
29 signature::{
30 EcdsaKeyPair, Ed25519KeyPair, KeyPair as RingKeyPair, ECDSA_P256_SHA256_FIXED_SIGNING,
31 ECDSA_P384_SHA384_FIXED_SIGNING,
32 },
33};
34
35use crate::error::*;
36use crate::rr::dnssec::rdata::key::KeyUsage;
37#[cfg(any(feature = "openssl", feature = "ring"))]
38use crate::rr::dnssec::rdata::DS;
39use crate::rr::dnssec::rdata::{DNSKEY, KEY};
40#[cfg(any(feature = "openssl", feature = "ring"))]
41use crate::rr::dnssec::DigestType;
42use crate::rr::dnssec::{Algorithm, PublicKeyBuf};
43use crate::rr::dnssec::{HasPrivate, HasPublic, Private, TBS};
44#[cfg(any(feature = "openssl", feature = "ring"))]
45use crate::rr::Name;
46
47#[allow(clippy::large_enum_variant)]
53pub enum KeyPair<K> {
54 #[cfg(feature = "openssl")]
56 #[cfg_attr(docsrs, doc(cfg(feature = "openssl")))]
57 RSA(PKey<K>),
58 #[cfg(feature = "openssl")]
60 #[cfg_attr(docsrs, doc(cfg(feature = "openssl")))]
61 EC(PKey<K>),
62 #[cfg(not(feature = "openssl"))]
63 #[doc(hidden)]
64 Phantom(PhantomData<K>),
65 #[cfg(feature = "ring")]
67 #[cfg_attr(docsrs, doc(cfg(feature = "ring")))]
68 ECDSA(EcdsaKeyPair),
69 #[cfg(feature = "ring")]
71 #[cfg_attr(docsrs, doc(cfg(feature = "ring")))]
72 ED25519(Ed25519KeyPair),
73}
74
75impl<K> KeyPair<K> {
76 #[cfg(feature = "openssl")]
78 #[cfg_attr(docsrs, doc(cfg(feature = "openssl")))]
79 pub fn from_rsa(rsa: OpenSslRsa<K>) -> DnsSecResult<Self> {
80 PKey::from_rsa(rsa).map(Self::RSA).map_err(Into::into)
81 }
82
83 #[cfg(feature = "openssl")]
85 #[cfg_attr(docsrs, doc(cfg(feature = "openssl")))]
86 pub fn from_rsa_pkey(pkey: PKey<K>) -> Self {
87 Self::RSA(pkey)
88 }
89
90 #[cfg(feature = "openssl")]
92 #[cfg_attr(docsrs, doc(cfg(feature = "openssl")))]
93 pub fn from_ec_key(ec_key: EcKey<K>) -> DnsSecResult<Self> {
94 PKey::from_ec_key(ec_key).map(Self::EC).map_err(Into::into)
95 }
96
97 #[cfg(feature = "openssl")]
99 #[cfg_attr(docsrs, doc(cfg(feature = "openssl")))]
100 pub fn from_ec_pkey(pkey: PKey<K>) -> Self {
101 Self::EC(pkey)
102 }
103
104 #[cfg(feature = "ring")]
106 #[cfg_attr(docsrs, doc(cfg(feature = "ring")))]
107 pub fn from_ecdsa(ec_key: EcdsaKeyPair) -> Self {
108 Self::ECDSA(ec_key)
109 }
110
111 #[cfg(feature = "ring")]
113 #[cfg_attr(docsrs, doc(cfg(feature = "ring")))]
114 pub fn from_ed25519(ed_key: Ed25519KeyPair) -> Self {
115 Self::ED25519(ed_key)
116 }
117}
118
119impl<K: HasPublic> KeyPair<K> {
120 pub fn to_public_bytes(&self) -> DnsSecResult<Vec<u8>> {
125 #[allow(unreachable_patterns)]
126 match *self {
127 #[cfg(feature = "openssl")]
129 Self::RSA(ref pkey) => {
130 let mut bytes: Vec<u8> = Vec::new();
131 let rsa: OpenSslRsa<K> = pkey
133 .rsa()
134 .expect("pkey should have been initialized with RSA");
135
136 let e: Vec<u8> = rsa.e().to_vec();
138 let n: Vec<u8> = rsa.n().to_vec();
139
140 if e.len() > 255 {
141 bytes.push(0);
142 bytes.push((e.len() >> 8) as u8);
143 }
144
145 bytes.push(e.len() as u8);
146 bytes.extend_from_slice(&e);
147 bytes.extend_from_slice(&n);
148
149 Ok(bytes)
150 }
151 #[cfg(feature = "openssl")]
153 Self::EC(ref pkey) => {
154 let ec_key: EcKey<K> = pkey
156 .ec_key()
157 .expect("pkey should have been initialized with EC");
158 let group = ec_key.group();
159 let point = ec_key.public_key();
160
161 let mut bytes = BigNumContext::new()
162 .and_then(|mut ctx| {
163 point.to_bytes(group, PointConversionForm::UNCOMPRESSED, &mut ctx)
164 })
165 .map_err(DnsSecError::from)?;
166
167 bytes.remove(0);
169 Ok(bytes)
170 }
171 #[cfg(feature = "ring")]
172 Self::ECDSA(ref ec_key) => {
173 let mut bytes: Vec<u8> = ec_key.public_key().as_ref().to_vec();
174 bytes.remove(0);
175 Ok(bytes)
176 }
177 #[cfg(feature = "ring")]
178 Self::ED25519(ref ed_key) => Ok(ed_key.public_key().as_ref().to_vec()),
179 #[cfg(not(feature = "openssl"))]
180 Self::Phantom(..) => panic!("Phantom disallowed"),
181 #[cfg(not(any(feature = "openssl", feature = "ring")))]
182 _ => Err(DnsSecErrorKind::Message("openssl or ring feature(s) not enabled").into()),
183 }
184 }
185
186 pub fn to_public_key(&self) -> DnsSecResult<PublicKeyBuf> {
188 Ok(PublicKeyBuf::new(self.to_public_bytes()?))
189 }
190
191 pub fn key_tag(&self) -> DnsSecResult<u16> {
245 let mut ac: usize = 0;
246
247 for (i, k) in self.to_public_bytes()?.iter().enumerate() {
248 ac += if i & 0x0001 == 0x0001 {
249 *k as usize
250 } else {
251 (*k as usize) << 8
252 };
253 }
254
255 ac += (ac >> 16) & 0xFFFF;
256 Ok((ac & 0xFFFF) as u16) }
258
259 pub fn to_dnskey(&self, algorithm: Algorithm) -> DnsSecResult<DNSKEY> {
269 self.to_public_bytes()
270 .map(|bytes| DNSKEY::new(true, true, false, algorithm, bytes))
271 }
272
273 pub fn to_sig0key(&self, algorithm: Algorithm) -> DnsSecResult<KEY> {
284 self.to_sig0key_with_usage(algorithm, KeyUsage::default())
285 }
286
287 pub fn to_sig0key_with_usage(
299 &self,
300 algorithm: Algorithm,
301 usage: KeyUsage,
302 ) -> DnsSecResult<KEY> {
303 self.to_public_bytes().map(|bytes| {
304 KEY::new(
305 KeyTrust::default(),
306 usage,
307 #[allow(deprecated)]
308 UpdateScope::default(),
309 Protocol::default(),
310 algorithm,
311 bytes,
312 )
313 })
314 }
315
316 #[cfg(any(feature = "openssl", feature = "ring"))]
324 #[cfg_attr(docsrs, doc(cfg(any(feature = "openssl", feature = "ring"))))]
325 pub fn to_ds(
326 &self,
327 name: &Name,
328 algorithm: Algorithm,
329 digest_type: DigestType,
330 ) -> DnsSecResult<DS> {
331 self.to_dnskey(algorithm)
332 .and_then(|dnskey| self.key_tag().map(|key_tag| (key_tag, dnskey)))
333 .and_then(|(key_tag, dnskey)| {
334 dnskey
335 .to_digest(name, digest_type)
336 .map(|digest| (key_tag, digest))
337 .map_err(Into::into)
338 })
339 .map(|(key_tag, digest)| {
340 DS::new(key_tag, algorithm, digest_type, digest.as_ref().to_owned())
341 })
342 }
343}
344
345impl<K: HasPrivate> KeyPair<K> {
346 #[allow(unused)]
358 pub fn sign(&self, algorithm: Algorithm, tbs: &TBS) -> DnsSecResult<Vec<u8>> {
359 use std::iter;
360
361 match *self {
362 #[cfg(feature = "openssl")]
363 Self::RSA(ref pkey) | Self::EC(ref pkey) => {
364 let digest_type = DigestType::from(algorithm).to_openssl_digest()?;
365 let mut signer = Signer::new(digest_type, pkey)?;
366 signer.update(tbs.as_ref())?;
367 signer.sign_to_vec().map_err(Into::into).and_then(|bytes| {
368 if let Self::RSA(_) = *self {
369 return Ok(bytes);
370 }
371
372 if bytes.len() < 8 {
374 return Err("unexpected signature format (length too short)".into());
375 }
376 let expect = |pos: usize, expected: u8| -> DnsSecResult<()> {
377 if bytes[pos] != expected {
378 return Err(format!(
379 "unexpected signature format ({pos}, {expected}))"
380 )
381 .into());
382 }
383 Ok(())
384 };
385 expect(0, 0x30)?;
387 expect(1, (bytes.len() - 2) as u8)?;
388 expect(2, 0x02)?;
389 let p1_len = bytes[3] as usize;
390 let p2_pos = 4 + p1_len;
391 expect(p2_pos, 0x02)?;
392 let p2_len = bytes[p2_pos + 1] as usize;
393 if p2_pos + 2 + p2_len > bytes.len() {
394 return Err("unexpected signature format (invalid length)".into());
395 }
396
397 let p1 = &bytes[4..p2_pos];
398 let p2 = &bytes[p2_pos + 2..p2_pos + 2 + p2_len];
399
400 let part_len = match algorithm {
403 Algorithm::ECDSAP256SHA256 => 32,
404 Algorithm::ECDSAP384SHA384 => 48,
405 _ => return Err("unexpected algorithm".into()),
406 };
407 let mut ret = Vec::<u8>::new();
408 {
409 let mut write_part = |mut part: &[u8]| -> DnsSecResult<()> {
410 if part.len() > part_len + 1 {
412 return Err("invalid signature data".into());
413 }
414 if part.len() == part_len + 1 {
415 if part[0] != 0x00 {
417 return Err("invalid signature data".into());
418 }
419 part = &part[1..];
420 }
421
422 ret.extend(iter::repeat(0x00).take(part_len - part.len()));
424 ret.extend(part);
425 Ok(())
426 };
427 write_part(p1)?;
428 write_part(p2)?;
429 }
430 assert_eq!(ret.len(), part_len * 2);
431 Ok(ret)
432 })
433 }
434 #[cfg(feature = "ring")]
435 Self::ECDSA(ref ec_key) => {
436 let rng = rand::SystemRandom::new();
437 Ok(ec_key.sign(&rng, tbs.as_ref())?.as_ref().to_vec())
438 }
439 #[cfg(feature = "ring")]
440 Self::ED25519(ref ed_key) => Ok(ed_key.sign(tbs.as_ref()).as_ref().to_vec()),
441 #[cfg(not(feature = "openssl"))]
442 Self::Phantom(..) => panic!("Phantom disallowed"),
443 #[cfg(not(any(feature = "openssl", feature = "ring")))]
444 _ => Err(DnsSecErrorKind::Message("openssl nor ring feature(s) not enabled").into()),
445 }
446 }
447}
448
449impl KeyPair<Private> {
450 pub fn generate(algorithm: Algorithm) -> DnsSecResult<Self> {
454 #[allow(deprecated)]
455 match algorithm {
456 Algorithm::Unknown(_) => Err(DnsSecErrorKind::Message("unknown algorithm").into()),
457 #[cfg(feature = "openssl")]
458 Algorithm::RSASHA1
459 | Algorithm::RSASHA1NSEC3SHA1
460 | Algorithm::RSASHA256
461 | Algorithm::RSASHA512 => {
462 OpenSslRsa::generate(2048)
464 .map_err(Into::into)
465 .and_then(Self::from_rsa)
466 }
467 #[cfg(feature = "openssl")]
468 Algorithm::ECDSAP256SHA256 => EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)
469 .and_then(|group| EcKey::generate(&group))
470 .map_err(Into::into)
471 .and_then(Self::from_ec_key),
472 #[cfg(feature = "openssl")]
473 Algorithm::ECDSAP384SHA384 => EcGroup::from_curve_name(Nid::SECP384R1)
474 .and_then(|group| EcKey::generate(&group))
475 .map_err(Into::into)
476 .and_then(Self::from_ec_key),
477 #[cfg(feature = "ring")]
478 Algorithm::ED25519 => Err(DnsSecErrorKind::Message(
479 "use generate_pkcs8 for generating private key and encoding",
480 )
481 .into()),
482 _ => Err(DnsSecErrorKind::Message("openssl nor ring feature(s) not enabled").into()),
483 }
484 }
485
486 #[cfg(feature = "ring")]
488 #[cfg_attr(docsrs, doc(cfg(feature = "ring")))]
489 pub fn generate_pkcs8(algorithm: Algorithm) -> DnsSecResult<Vec<u8>> {
490 #[allow(deprecated)]
491 match algorithm {
492 Algorithm::Unknown(_) => Err(DnsSecErrorKind::Message("unknown algorithm").into()),
493 #[cfg(feature = "openssl")]
494 Algorithm::RSASHA1
495 | Algorithm::RSASHA1NSEC3SHA1
496 | Algorithm::RSASHA256
497 | Algorithm::RSASHA512 => {
498 Err(DnsSecErrorKind::Message("openssl does not yet support pkcs8").into())
499 }
500 #[cfg(feature = "ring")]
501 Algorithm::ECDSAP256SHA256 => {
502 let rng = rand::SystemRandom::new();
503 EcdsaKeyPair::generate_pkcs8(&ECDSA_P256_SHA256_FIXED_SIGNING, &rng)
504 .map_err(Into::into)
505 .map(|pkcs8_bytes| pkcs8_bytes.as_ref().to_vec())
506 }
507 #[cfg(feature = "ring")]
508 Algorithm::ECDSAP384SHA384 => {
509 let rng = rand::SystemRandom::new();
510 EcdsaKeyPair::generate_pkcs8(&ECDSA_P384_SHA384_FIXED_SIGNING, &rng)
511 .map_err(Into::into)
512 .map(|pkcs8_bytes| pkcs8_bytes.as_ref().to_vec())
513 }
514 #[cfg(feature = "ring")]
515 Algorithm::ED25519 => {
516 let rng = rand::SystemRandom::new();
517 Ed25519KeyPair::generate_pkcs8(&rng)
518 .map_err(Into::into)
519 .map(|pkcs8_bytes| pkcs8_bytes.as_ref().to_vec())
520 }
521 _ => Err(DnsSecErrorKind::Message("openssl nor ring feature(s) not enabled").into()),
522 }
523 }
524}
525
526#[cfg(any(feature = "openssl", feature = "ring"))]
527#[cfg(test)]
528mod tests {
529 use crate::rr::dnssec::TBS;
530 use crate::rr::dnssec::*;
531
532 #[cfg(feature = "openssl")]
533 #[test]
534 fn test_rsa() {
535 public_key_test(Algorithm::RSASHA256, KeyFormat::Der);
536 hash_test(Algorithm::RSASHA256, KeyFormat::Der);
537 }
538
539 #[cfg(feature = "openssl")]
540 #[test]
541 fn test_ec_p256() {
542 public_key_test(Algorithm::ECDSAP256SHA256, KeyFormat::Der);
543 hash_test(Algorithm::ECDSAP256SHA256, KeyFormat::Der);
544 }
545
546 #[cfg(feature = "ring")]
547 #[test]
548 fn test_ec_p256_pkcs8() {
549 public_key_test(Algorithm::ECDSAP256SHA256, KeyFormat::Pkcs8);
550 hash_test(Algorithm::ECDSAP256SHA256, KeyFormat::Pkcs8);
551 }
552
553 #[cfg(feature = "openssl")]
554 #[test]
555 fn test_ec_p384() {
556 public_key_test(Algorithm::ECDSAP384SHA384, KeyFormat::Der);
557 hash_test(Algorithm::ECDSAP384SHA384, KeyFormat::Der);
558 }
559
560 #[cfg(feature = "ring")]
561 #[test]
562 fn test_ec_p384_pkcs8() {
563 public_key_test(Algorithm::ECDSAP384SHA384, KeyFormat::Pkcs8);
564 hash_test(Algorithm::ECDSAP384SHA384, KeyFormat::Pkcs8);
565 }
566
567 #[cfg(feature = "ring")]
568 #[test]
569 fn test_ed25519() {
570 public_key_test(Algorithm::ED25519, KeyFormat::Pkcs8);
571 hash_test(Algorithm::ED25519, KeyFormat::Pkcs8);
572 }
573
574 #[allow(clippy::uninlined_format_args)]
575 fn public_key_test(algorithm: Algorithm, key_format: KeyFormat) {
576 let key = key_format
577 .decode_key(
578 &key_format.generate_and_encode(algorithm, None).unwrap(),
579 None,
580 algorithm,
581 )
582 .unwrap();
583 let pk = key.to_public_key().unwrap();
584
585 let tbs = TBS::from(&b"www.example.com"[..]);
586 let mut sig = key.sign(algorithm, &tbs).unwrap();
587 assert!(
588 pk.verify(algorithm, tbs.as_ref(), &sig).is_ok(),
589 "algorithm: {:?} (public key)",
590 algorithm
591 );
592 sig[10] = !sig[10];
593 assert!(
594 pk.verify(algorithm, tbs.as_ref(), &sig).is_err(),
595 "algorithm: {:?} (public key, neg)",
596 algorithm
597 );
598 }
599
600 #[allow(clippy::uninlined_format_args)]
601 fn hash_test(algorithm: Algorithm, key_format: KeyFormat) {
602 let tbs = TBS::from(&b"www.example.com"[..]);
603
604 let key = key_format
606 .decode_key(
607 &key_format.generate_and_encode(algorithm, None).unwrap(),
608 None,
609 algorithm,
610 )
611 .unwrap();
612 let pub_key = key.to_public_key().unwrap();
613
614 let neg = key_format
615 .decode_key(
616 &key_format.generate_and_encode(algorithm, None).unwrap(),
617 None,
618 algorithm,
619 )
620 .unwrap();
621 let neg_pub_key = neg.to_public_key().unwrap();
622
623 let sig = key.sign(algorithm, &tbs).unwrap();
624 assert!(
625 pub_key.verify(algorithm, tbs.as_ref(), &sig).is_ok(),
626 "algorithm: {:?}",
627 algorithm
628 );
629 assert!(
630 key.to_dnskey(algorithm)
631 .unwrap()
632 .verify(tbs.as_ref(), &sig)
633 .is_ok(),
634 "algorithm: {:?} (dnskey)",
635 algorithm
636 );
637 assert!(
638 neg_pub_key.verify(algorithm, tbs.as_ref(), &sig).is_err(),
639 "algorithm: {:?} (neg)",
640 algorithm
641 );
642 assert!(
643 neg.to_dnskey(algorithm)
644 .unwrap()
645 .verify(tbs.as_ref(), &sig)
646 .is_err(),
647 "algorithm: {:?} (dnskey, neg)",
648 algorithm
649 );
650 }
651}