diff --git a/src/dnssec.rs b/src/dnssec.rs index 1b7ce88f..9f6c7239 100644 --- a/src/dnssec.rs +++ b/src/dnssec.rs @@ -1,90 +1,4 @@ -pub mod dnssec; - - - -use std::str::FromStr; -use crate::domain_name::DomainName; -use crate::message::rclass::Rclass; -use crate::message::DnsMessage; -use crate::message::rdata::opt_rdata::OptRdata; -use crate::message::rdata::Rdata; -use crate::message::resource_record::{FromBytes, ResourceRecord, ToBytes}; -use crate::message::rcode; -use crate::message::rcode::Rcode; -use crate::message::rrtype::Rrtype; - -const EDNS_VERSION: u8 = 0; -const REQUESTED_UDP_LEN: u16 = 4096; -/* -The mechanism chosen for the explicit notification of the ability of -the client to accept (if not understand) DNSSEC security RRs is using -the most significant bit of the Z field on the EDNS0 OPT header in -the query. This bit is referred to as the "DNSSEC OK" (DO) bit. In -the context of the EDNS0 OPT meta-RR, the DO bit is the first bit of -the third and fourth bytes of the "extended RCODE and flags" portion -of the EDNS0 OPT meta-RR, structured as follows: - - +0 (MSB) +1 (LSB) - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - 0: | EXTENDED-RCODE | VERSION | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - 2: |DO| Z | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -*/ -fn create_opt_rr(capacity: u16 ,e_rcode :u8, version: u8, do_bit: bool) -> ResourceRecord { - let opt_rdata = OptRdata::new(); - let rdata = Rdata::OPT(opt_rdata); - let mut rr = ResourceRecord::new(rdata); - - let do_val: u16 = if do_bit {0x8000} else {0x0}; - let ttl: u32 = (e_rcode as u32) << 24 | (version as u32) << 16| (do_val as u32); - rr.set_ttl(ttl); - rr.set_rclass(Rclass::UNKNOWN(capacity)); - println!("EL ttl es: {:#05x?}", ttl); - rr -} - -fn read_opt_rr(opt_rr: ResourceRecord) -> String { - let requested_udp_len = Rclass::from_rclass_to_int(opt_rr.get_rclass()); - let data = opt_rr.get_ttl().to_be_bytes(); - let (e_rcode, version) = (data[0], data[1]); - let z = u16::from_be_bytes([data[2], data[3]]); - - let do_bit = ((z & 0x8000) > 0) as u8 ; - format!("OPT PSEUDO-RR\n\trequested_udp_len: {requested_udp_len}\n\terror code: {e_rcode}\n\tversion: EDNS{version}\n\tuse dnssec: {do_bit}") -} - -/* - A security-aware resolver MUST include an EDNS ([RFC2671]) OPT - pseudo-RR with the DO ([RFC3225]) bit set when sending queries. -*/ -fn create_dns_message_with_dnssec(mut msg: DnsMessage) -> DnsMessage { - // We create a opt rr with the do bit set to 1 - // with NOERR as rcode and EDNS0 - let rr = create_opt_rr(REQUESTED_UDP_LEN, - rcode::Rcode::from_rcode_to_int(Rcode::NOERROR), - EDNS_VERSION, - true); - - let vec = vec![rr]; - msg.add_additionals(vec); - msg -} - -#[test] -fn see_dnssec_message() { - let query = DnsMessage::new_query_message( - DomainName::new_from_str("example.com"), - Rrtype::A, - Rclass::UNKNOWN(4096), - 1, - true, - 2000 - ); - let query= create_dns_message_with_dnssec(query); - assert_eq!(String::from_str - ("OPT PSEUDO-RR\n\trequested_udp_len: 4096\n\terror code: 0\n\tversion: EDNS0\n\tuse dnssec: 1") - .expect("Not a utf8 str"), - read_opt_rr(query.get_additional().pop().expect("No OPT Record!")) - ) -} \ No newline at end of file +pub mod dnssec_message; +pub mod dnssec_message_processing; +pub mod dnssec_fetch; +pub mod rrset_signature; \ No newline at end of file diff --git a/src/dnssec/dnssec.rs b/src/dnssec/dnssec_fetch.rs similarity index 78% rename from src/dnssec/dnssec.rs rename to src/dnssec/dnssec_fetch.rs index 899bf857..24295daa 100644 --- a/src/dnssec/dnssec.rs +++ b/src/dnssec/dnssec_fetch.rs @@ -1,6 +1,6 @@ use crate::message::{DnsMessage, Rdata, ResourceRecord}; -use crate::dnssec_message_processing::extract_dnssec_records; -use crate::rrset_signature::{verify_rrsig, verify_ds}; +use crate::dnssec::dnssec_message_processing::extract_dnssec_records; +use crate::dnssec::rrset_signature::{verify_rrsig, verify_ds}; use crate::message::rdata::DnskeyRdata; use crate::client::client_error::ClientError; diff --git a/src/dnssec/dnssec_message.rs b/src/dnssec/dnssec_message.rs new file mode 100644 index 00000000..975cf6b8 --- /dev/null +++ b/src/dnssec/dnssec_message.rs @@ -0,0 +1,87 @@ + +use std::str::FromStr; +use crate::domain_name::DomainName; +use crate::message::rclass::Rclass; +use crate::message::DnsMessage; +use crate::message::rdata::opt_rdata::OptRdata; +use crate::message::rdata::Rdata; +use crate::message::resource_record::{FromBytes, ResourceRecord, ToBytes}; +use crate::message::rcode; +use crate::message::rcode::Rcode; +use crate::message::rrtype::Rrtype; + +const EDNS_VERSION: u8 = 0; +const REQUESTED_UDP_LEN: u16 = 4096; +/* +The mechanism chosen for the explicit notification of the ability of +the client to accept (if not understand) DNSSEC security RRs is using +the most significant bit of the Z field on the EDNS0 OPT header in +the query. This bit is referred to as the "DNSSEC OK" (DO) bit. In +the context of the EDNS0 OPT meta-RR, the DO bit is the first bit of +the third and fourth bytes of the "extended RCODE and flags" portion +of the EDNS0 OPT meta-RR, structured as follows: + + +0 (MSB) +1 (LSB) + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + 0: | EXTENDED-RCODE | VERSION | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + 2: |DO| Z | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +*/ +fn create_opt_rr(capacity: u16 ,e_rcode :u8, version: u8, do_bit: bool) -> ResourceRecord { + let opt_rdata = OptRdata::new(); + let rdata = Rdata::OPT(opt_rdata); + let mut rr = ResourceRecord::new(rdata); + + let do_val: u16 = if do_bit {0x8000} else {0x0}; + let ttl: u32 = (e_rcode as u32) << 24 | (version as u32) << 16| (do_val as u32); + rr.set_ttl(ttl); + rr.set_rclass(Rclass::UNKNOWN(capacity)); + println!("EL ttl es: {:#05x?}", ttl); + rr +} + +fn read_opt_rr(opt_rr: ResourceRecord) -> String { + let requested_udp_len = Rclass::from_rclass_to_int(opt_rr.get_rclass()); + let data = opt_rr.get_ttl().to_be_bytes(); + let (e_rcode, version) = (data[0], data[1]); + let z = u16::from_be_bytes([data[2], data[3]]); + + let do_bit = ((z & 0x8000) > 0) as u8 ; + format!("OPT PSEUDO-RR\n\trequested_udp_len: {requested_udp_len}\n\terror code: {e_rcode}\n\tversion: EDNS{version}\n\tuse dnssec: {do_bit}") +} + +/* + A security-aware resolver MUST include an EDNS ([RFC2671]) OPT + pseudo-RR with the DO ([RFC3225]) bit set when sending queries. +*/ +fn create_dns_message_with_dnssec(mut msg: DnsMessage) -> DnsMessage { + // We create a opt rr with the do bit set to 1 + // with NOERR as rcode and EDNS0 + let rr = create_opt_rr(REQUESTED_UDP_LEN, + rcode::Rcode::from_rcode_to_int(Rcode::NOERROR), + EDNS_VERSION, + true); + + let vec = vec![rr]; + msg.add_additionals(vec); + msg +} + +#[test] +fn see_dnssec_message() { + let query = DnsMessage::new_query_message( + DomainName::new_from_str("example.com"), + Rrtype::A, + Rclass::UNKNOWN(4096), + 1, + true, + 2000 + ); + let query= create_dns_message_with_dnssec(query); + assert_eq!(String::from_str + ("OPT PSEUDO-RR\n\trequested_udp_len: 4096\n\terror code: 0\n\tversion: EDNS0\n\tuse dnssec: 1") + .expect("Not a utf8 str"), + read_opt_rr(query.get_additional().pop().expect("No OPT Record!")) + ) +} \ No newline at end of file diff --git a/src/dnssec/rrset_signature.rs b/src/dnssec/rrset_signature.rs index 25cd1669..b0e9b1aa 100644 --- a/src/dnssec/rrset_signature.rs +++ b/src/dnssec/rrset_signature.rs @@ -1,16 +1,17 @@ use sha2::{Sha256, Digest}; -use rust_crypto::digest::Digest as RustDigest; -use rust_crypto::sha1::Sha1; +use crypto::digest::Digest as RustDigest; +use crypto::sha1::Sha1; use base64::encode; -use crate::message::rdata::{DnskeyRdata, RrsigRdata, Rdata}; +use crate::message::rdata::{DnskeyRdata, Rdata}; +use crate::message::rdata::rrsig_rdata::{RRSIGRdata}; use crate::message::resource_record::ResourceRecord; use crate::client::client_error::ClientError; -pub fn verify_rrsig(rrsig: &RrsigRdata, dnskey: &DnskeyRdata, rrset: &[ResourceRecord]) -> Result { +pub fn verify_rrsig(rrsig: &RRSIGRdata, dnskey: &DnskeyRdata, rrset: &[ResourceRecord]) -> Result { let mut rrsig_data = Vec::new(); - rrsig_data.extend_from_slice(&rrsig.type_covered.to_be_bytes()); - rrsig_data.push(rrsig.algorithm); - rrsig_data.push(rrsig.labels); + rrsig_data.extend_from_slice(&rrsig.get_type_covered().to_be_bytes()); + rrsig_data.push(rrsig.get_algorithm()); + rrsig_data.push(rrsig.get_labels()); rrsig_data.extend_from_slice(&rrsig.original_ttl.to_be_bytes()); rrsig_data.extend_from_slice(&rrsig.expiration.to_be_bytes()); rrsig_data.extend_from_slice(&rrsig.inception.to_be_bytes());