1use alloc::string::String;
11use alloc::vec::Vec;
12use core::fmt;
13
14#[cfg(feature = "backtrace")]
15use backtrace::Backtrace;
16use rdata::tsig::TsigAlgorithm;
17#[cfg(feature = "serde")]
18use serde::{Deserialize, Serialize};
19use thiserror::Error;
20
21use crate::error::{ProtoError, ProtoErrorKind};
22#[cfg(feature = "backtrace")]
23use crate::trace;
24
25mod algorithm;
26mod dnssec_dns_handle;
27pub use dnssec_dns_handle::DnssecDnsHandle;
28#[doc(hidden)]
29pub use dnssec_dns_handle::verify_nsec;
30pub mod crypto;
32mod ec_public_key;
33mod nsec3;
34pub mod proof;
35pub mod public_key;
36pub mod rdata;
37mod rsa_public_key;
38mod signer;
39mod supported_algorithm;
40pub mod tbs;
41mod trust_anchor;
42pub mod tsig;
43mod verifier;
44
45pub use self::algorithm::Algorithm;
46pub use self::nsec3::Nsec3HashAlgorithm;
47pub use self::proof::{Proof, ProofError, ProofErrorKind, ProofFlags, Proven};
48pub use self::public_key::{PublicKey, PublicKeyBuf};
49pub use self::signer::SigSigner;
50pub use self::supported_algorithm::SupportedAlgorithms;
51pub use self::tbs::TBS;
52pub use self::trust_anchor::TrustAnchors;
53pub use self::verifier::Verifier;
54
55#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
71#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
72#[non_exhaustive]
73pub enum DigestType {
74 #[cfg_attr(feature = "serde", serde(rename = "SHA-1"))]
76 SHA1,
77 #[cfg_attr(feature = "serde", serde(rename = "SHA-256"))]
79 SHA256,
80 #[cfg_attr(feature = "serde", serde(rename = "SHA-384"))]
82 SHA384,
83 Unknown(u8),
85}
86
87impl DigestType {
88 fn is_supported(&self) -> bool {
89 !matches!(self, Self::Unknown(_))
90 }
91}
92
93impl From<u8> for DigestType {
94 fn from(value: u8) -> Self {
95 match value {
96 1 => Self::SHA1,
97 2 => Self::SHA256,
98 4 => Self::SHA384,
99 _ => Self::Unknown(value),
100 }
101 }
102}
103
104impl From<DigestType> for u8 {
105 fn from(a: DigestType) -> Self {
106 match a {
107 DigestType::SHA1 => 1,
108 DigestType::SHA256 => 2,
109 DigestType::SHA384 => 4,
110 DigestType::Unknown(other) => other,
111 }
112 }
113}
114
115pub trait SigningKey: Send + Sync + 'static {
117 fn sign(&self, tbs: &TBS) -> DnsSecResult<Vec<u8>>;
123
124 fn to_public_key(&self) -> DnsSecResult<PublicKeyBuf>;
126
127 fn algorithm(&self) -> Algorithm;
129}
130
131#[derive(Clone, Copy, Debug, Eq, PartialEq)]
133pub enum KeyFormat {
134 Der,
136 Pem,
138 Pkcs8,
140}
141
142pub type DnsSecResult<T> = ::core::result::Result<T, DnsSecError>;
144
145#[derive(Debug, Clone, Error)]
147pub struct DnsSecError {
148 kind: DnsSecErrorKind,
149 #[cfg(feature = "backtrace")]
150 backtrack: Option<Backtrace>,
151}
152
153impl DnsSecError {
154 pub fn kind(&self) -> &DnsSecErrorKind {
156 &self.kind
157 }
158}
159
160impl fmt::Display for DnsSecError {
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 cfg_if::cfg_if! {
163 if #[cfg(feature = "backtrace")] {
164 if let Some(backtrace) = &self.backtrack {
165 fmt::Display::fmt(&self.kind, f)?;
166 fmt::Debug::fmt(backtrace, f)
167 } else {
168 fmt::Display::fmt(&self.kind, f)
169 }
170 } else {
171 fmt::Display::fmt(&self.kind, f)
172 }
173 }
174 }
175}
176
177impl From<DnsSecErrorKind> for DnsSecError {
178 fn from(kind: DnsSecErrorKind) -> Self {
179 Self {
180 kind,
181 #[cfg(feature = "backtrace")]
182 backtrack: trace!(),
183 }
184 }
185}
186
187impl From<&'static str> for DnsSecError {
188 fn from(msg: &'static str) -> Self {
189 DnsSecErrorKind::Message(msg).into()
190 }
191}
192
193impl From<String> for DnsSecError {
194 fn from(msg: String) -> Self {
195 DnsSecErrorKind::Msg(msg).into()
196 }
197}
198
199impl From<ProtoError> for DnsSecError {
200 fn from(e: ProtoError) -> Self {
201 match e.kind() {
202 ProtoErrorKind::Timeout => DnsSecErrorKind::Timeout.into(),
203 _ => DnsSecErrorKind::from(e).into(),
204 }
205 }
206}
207
208impl From<ring_like::KeyRejected> for DnsSecError {
209 fn from(e: ring_like::KeyRejected) -> Self {
210 DnsSecErrorKind::from(e).into()
211 }
212}
213
214impl From<ring_like::Unspecified> for DnsSecError {
215 fn from(e: ring_like::Unspecified) -> Self {
216 DnsSecErrorKind::from(e).into()
217 }
218}
219
220#[derive(Debug, Error)]
222#[non_exhaustive]
223pub enum DnsSecErrorKind {
224 #[error("hmac validation failure")]
226 HmacInvalid,
227
228 #[error("{0}")]
230 Message(&'static str),
231
232 #[error("{0}")]
234 Msg(String),
235
236 #[error("proto error: {0}")]
239 Proto(#[from] ProtoError),
240
241 #[error("ring error: {0}")]
243 RingKeyRejected(#[from] ring_like::KeyRejected),
244
245 #[error("ring error: {0}")]
247 RingUnspecified(#[from] ring_like::Unspecified),
248
249 #[error("request timed out")]
251 Timeout,
252
253 #[error("Tsig unsupported mac algorithm")]
256 TsigUnsupportedMacAlgorithm(TsigAlgorithm),
257
258 #[error("Tsig key wrong key error")]
260 TsigWrongKey,
261}
262
263impl Clone for DnsSecErrorKind {
264 fn clone(&self) -> Self {
265 use DnsSecErrorKind::*;
266 match self {
267 HmacInvalid => HmacInvalid,
268 Message(msg) => Message(msg),
269 Msg(msg) => Msg(msg.clone()),
270 Proto(proto) => Proto(proto.clone()),
272 RingKeyRejected(r) => Msg(format!("Ring rejected key: {r}")),
273 RingUnspecified(_r) => RingUnspecified(ring_like::Unspecified),
274 Timeout => Timeout,
275 TsigUnsupportedMacAlgorithm(ref alg) => TsigUnsupportedMacAlgorithm(alg.clone()),
276 TsigWrongKey => TsigWrongKey,
277 }
278 }
279}
280
281#[cfg(all(feature = "dnssec-aws-lc-rs", not(feature = "dnssec-ring")))]
282pub(crate) use aws_lc_rs_impl as ring_like;
283#[cfg(feature = "dnssec-ring")]
284pub(crate) use ring_impl as ring_like;
285
286#[cfg(feature = "dnssec-aws-lc-rs")]
287#[cfg_attr(feature = "dnssec-ring", allow(unused_imports))]
288pub(crate) mod aws_lc_rs_impl {
289 pub(crate) use aws_lc_rs::{
290 digest,
291 error::{KeyRejected, Unspecified},
292 hmac,
293 rand::SystemRandom,
294 rsa::PublicKeyComponents,
295 signature::{
296 self, ECDSA_P256_SHA256_FIXED_SIGNING, ECDSA_P384_SHA384_FIXED_SIGNING,
297 ED25519_PUBLIC_KEY_LEN, EcdsaKeyPair, Ed25519KeyPair, KeyPair, RSA_PKCS1_SHA256,
298 RSA_PKCS1_SHA512, RsaKeyPair,
299 },
300 };
301}
302
303#[cfg(feature = "dnssec-ring")]
304pub(crate) mod ring_impl {
305 pub(crate) use ring::{
306 digest,
307 error::{KeyRejected, Unspecified},
308 hmac,
309 rand::SystemRandom,
310 rsa::PublicKeyComponents,
311 signature::{
312 self, ECDSA_P256_SHA256_FIXED_SIGNING, ECDSA_P384_SHA384_FIXED_SIGNING,
313 ED25519_PUBLIC_KEY_LEN, EcdsaKeyPair, Ed25519KeyPair, KeyPair, RSA_PKCS1_SHA256,
314 RSA_PKCS1_SHA512, RsaKeyPair,
315 },
316 };
317}
318
319#[cfg(test)]
320mod test_utils {
321 use rdata::DNSKEY;
322
323 use super::*;
324
325 pub(super) fn public_key_test(key: &dyn SigningKey) {
326 let pk = key.to_public_key().unwrap();
327
328 let tbs = TBS::from(&b"www.example.com"[..]);
329 let mut sig = key.sign(&tbs).unwrap();
330 assert!(
331 pk.verify(tbs.as_ref(), &sig).is_ok(),
332 "public_key_test() failed to verify (algorithm: {:?})",
333 key.algorithm(),
334 );
335 sig[10] = !sig[10];
336 assert!(
337 pk.verify(tbs.as_ref(), &sig).is_err(),
338 "algorithm: {:?} (public key, neg)",
339 key.algorithm(),
340 );
341 }
342
343 pub(super) fn hash_test(key: &dyn SigningKey, neg: &dyn SigningKey) {
344 let tbs = TBS::from(&b"www.example.com"[..]);
345
346 let pub_key = key.to_public_key().unwrap();
348 let neg_pub_key = neg.to_public_key().unwrap();
349
350 let sig = key.sign(&tbs).unwrap();
351 assert!(
352 pub_key.verify(tbs.as_ref(), &sig).is_ok(),
353 "algorithm: {:?}",
354 key.algorithm(),
355 );
356
357 let pub_key = key.to_public_key().unwrap();
358 let dns_key = DNSKEY::from_key(&pub_key);
359 assert!(
360 dns_key.verify(tbs.as_ref(), &sig).is_ok(),
361 "algorithm: {:?} (dnskey)",
362 pub_key.algorithm(),
363 );
364 assert!(
365 neg_pub_key.verify(tbs.as_ref(), &sig).is_err(),
366 "algorithm: {:?} (neg)",
367 neg_pub_key.algorithm(),
368 );
369
370 let neg_pub_key = neg.to_public_key().unwrap();
371 let neg_dns_key = DNSKEY::from_key(&neg_pub_key);
372 assert!(
373 neg_dns_key.verify(tbs.as_ref(), &sig).is_err(),
374 "algorithm: {:?} (dnskey, neg)",
375 neg_pub_key.algorithm(),
376 );
377 }
378}