From 51134f38c40a79dcffb2de2466b899ba35842870 Mon Sep 17 00:00:00 2001 From: joalopez Date: Fri, 12 Jul 2024 13:58:52 -0400 Subject: [PATCH] fix/refactor: changed the logic flow of tsig (sign, process) and new functions digest --- src/tsig.rs | 253 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 146 insertions(+), 107 deletions(-) diff --git a/src/tsig.rs b/src/tsig.rs index 72d609f5..d2277bc1 100644 --- a/src/tsig.rs +++ b/src/tsig.rs @@ -66,86 +66,110 @@ fn set_tsig_rd(name: String, original_id: u16, result: MacResult, //TODO: crear una función para simplificar la extracción de bits paa simplificar código // This function extracts the digest #[doc = r"This function recives a DNS message and generate the digest da. Requested by RFC 8945 4.3.3 "] -fn get_digest_request(dns_msg: Vec, tsig_rr: ResourceRecord) -> Vec { - let mut res: Vec = dns_msg.clone(); - let tsig_rdata = tsig_rr.get_rdata(); - res.extend(tsig_rr.get_name().to_bytes()); - //processing TSIG RR - let rclass_bytes: u16 = class_rclass::Rclass::from_rclass_to_int(tsig_rr.get_rclass()); - let rclass_lbyte = rclass_bytes as u8; - let rclass_ubyte = (rclass_bytes >> 8) as u8; - res.push(rclass_ubyte); - res.push(rclass_lbyte); - - let rclass_ttl: u32 = tsig_rr.get_ttl(); - let r_ttl1 = (rclass_ttl >> 24) as u8; - let r_ttl2 = (rclass_ttl >> 16) as u8; - let r_ttl3 = (rclass_ttl >> 8) as u8; - let r_ttl4 = rclass_ttl as u8; - res.push(r_ttl1); - res.push(r_ttl2); - res.push(r_ttl3); - res.push(r_ttl4); - - //processing TSIG RDATA - let tsig_rd = match tsig_rdata { - Rdata::TSIG(tsig_rd) => tsig_rd, - _ => panic!() - }; - let a_name = tsig_rd.get_algorithm_name().to_bytes(); - let tsig_rd_time_signed: u64 = tsig_rd.get_time_signed(); - let tsig_rd_fudge: u16 = tsig_rd.get_fudge(); - let tsig_rd_error: u16= tsig_rd.get_error(); - let tsig_rd_other_len: u16 = tsig_rd.get_other_len(); - let tsig_rd_other_data = tsig_rd.get_other_data(); - - res.extend(a_name); - - let time_s6 = (tsig_rd_time_signed) as u8; - let time_s5 = (tsig_rd_time_signed >> 8) as u8; - let time_s4 = (tsig_rd_time_signed >> 16) as u8; - let time_s3 = (tsig_rd_time_signed >> 24) as u8; - let time_s2 = (tsig_rd_time_signed >> 32) as u8; - let time_s1 = (tsig_rd_time_signed >> 40) as u8; - res.push(time_s1); - res.push(time_s2); - res.push(time_s3); - res.push(time_s4); - res.push(time_s5); - res.push(time_s6); - - let fudge1 = (tsig_rd_fudge >> 8) as u8; - let fudge2 = (tsig_rd_fudge ) as u8; - res.push(fudge1); - res.push(fudge2); - - let error1 = (tsig_rd_error >> 8) as u8; - let error2 = (tsig_rd_error) as u8; - res.push(error1); - res.push(error2); - - let otherl1 = (tsig_rd_other_len >> 8) as u8; - let otherl2 = (tsig_rd_other_len) as u8; - res.push(otherl1); - res.push(otherl2); - - res.extend(tsig_rd_other_data); - - return res; +fn get_digest_request(mac: Vec ,dns_msg: Vec, tsig_rr: ResourceRecord) -> Vec { + let mut res: Vec = vec![]; + + if (mac.len() != 0) { + res.extend(mac.clone()); + } + res.extend(dns_msg.clone()); + let tsig_rdata = tsig_rr.get_rdata(); + res.extend(tsig_rr.get_name().to_bytes()); + //The below shifts are meant to correctly retreive theby + //processing TSIG RR + let rclass_bytes: u16 = class_rclass::Rclass::from_rclass_to_int(tsig_rr.get_rclass()); + let rclass_ubyte = (rclass_bytes >> 8) as u8; + let rclass_lbyte = rclass_bytes as u8; + res.push(rclass_ubyte); + res.push(rclass_lbyte); + + let rclass_ttl: u32 = tsig_rr.get_ttl(); + let r_ttl1 = (rclass_ttl >> 24) as u8; + let r_ttl2 = (rclass_ttl >> 16) as u8; + let r_ttl3 = (rclass_ttl >> 8) as u8; + let r_ttl4 = rclass_ttl as u8; + res.push(r_ttl1); + res.push(r_ttl2); + res.push(r_ttl3); + res.push(r_ttl4); + + //processing TSIG RDATA + let tsig_rd = match tsig_rdata { + Rdata::TSIG(tsig_rd) => tsig_rd, + _ => panic!() + }; + let a_name = tsig_rd.get_algorithm_name().to_bytes(); + // Remember that time_signed is u48 + let tsig_rd_time_signed: u64 = tsig_rd.get_time_signed(); + let tsig_rd_fudge: u16 = tsig_rd.get_fudge(); + let tsig_rd_error: u16= tsig_rd.get_error(); + let tsig_rd_other_len: u16 = tsig_rd.get_other_len(); + let tsig_rd_other_data = tsig_rd.get_other_data(); + + res.extend(a_name); + + let time_s1 = (tsig_rd_time_signed >> 40) as u8; + let time_s2 = (tsig_rd_time_signed >> 32) as u8; + let time_s3 = (tsig_rd_time_signed >> 24) as u8; + let time_s4 = (tsig_rd_time_signed >> 16) as u8; + let time_s5 = (tsig_rd_time_signed >> 8) as u8; + let time_s6 = (tsig_rd_time_signed) as u8; + res.push(time_s1); + res.push(time_s2); + res.push(time_s3); + res.push(time_s4); + res.push(time_s5); + res.push(time_s6); + + let fudge1 = (tsig_rd_fudge >> 8) as u8; + let fudge2 = (tsig_rd_fudge) as u8; + res.push(fudge1); + res.push(fudge2); + + let error1 = (tsig_rd_error >> 8) as u8; + let error2 = (tsig_rd_error) as u8; + res.push(error1); + res.push(error2); + + let otherl1 = (tsig_rd_other_len >> 8) as u8; + let otherl2 = (tsig_rd_other_len) as u8; + res.push(otherl1); + res.push(otherl2); + + res.extend(tsig_rd_other_data); + + return res; +} + +fn digest(bytes: Vec, tsig_algorithm: TsigAlgorithm, key: Vec) -> Vec{ + match tsig_algorithm { + TsigAlgorithm::HmacSha1 => { + + //new_query_message.push(); + let mut hasher = crypto_hmac::new(Sha1::new(), &key); + hasher.input(&bytes[..]); + hasher.result().code().to_vec() + }, + TsigAlgorithm::HmacSha256 => { + let mut hasher = crypto_hmac::new(Sha256::new(), &key); + hasher.input(&bytes[..]); + hasher.result().code().to_vec() + } + } } -//TODO: revisar que la creación del TSIG resourcerecord contenga efectivamente los campos del 8945, 4.3.3 //RFC 8945, section 5.1 #[doc = r"This function creates the signature of a DnsMessage with a key in bytes and the algName that will be used to encrypt the key."] pub fn sign_tsig(query_msg: &mut DnsMessage, key: &[u8], alg_name: TsigAlgorithm, - fudge: u16, time_signed: u64, key_name: String) -> Vec { + fudge: u16, time_signed: u64, key_name: String, mac_request: Vec) -> Vec { let mut tsig_rd: TSigRdata = TSigRdata::new(); let new_query_message = query_msg.clone(); let original_id = query_msg.get_query_id(); let alg_name_str = tsig_alg_to_string(&alg_name); - let tsig_rr= set_tsig_vars( alg_name_str.as_str(), key_name.as_str(), time_signed, fudge); - let digest_comp = get_digest_request(new_query_message.to_bytes(), tsig_rr); - + let tsig_rr= set_tsig_vars(alg_name_str.as_str(), key_name.as_str(), + time_signed, fudge); + let digest_comp = get_digest_request(mac_request, new_query_message.to_bytes(), + tsig_rr); match alg_name { TsigAlgorithm::HmacSha1 => { @@ -253,9 +277,9 @@ fn check_last_one_is_tsig(add_rec: &Vec) -> bool { filtered_tsig.len()>1 || islast } - #[doc = r"This function process a tsig message, checking for errors in the DNS message"] -pub fn process_tsig(msg: &DnsMessage,key:&[u8], key_name: String, time: u64, available_algorithm: Vec<(String, bool)>) -> (bool, TsigErrorCode) { +pub fn process_tsig(msg: &DnsMessage, key:&[u8], key_name: String, time: u64, + available_algorithm: Vec<(String, bool)>, mac_to_process: Vec) -> (bool, TsigErrorCode) { let mut retmsg = msg.clone(); let mut addit = retmsg.get_additional(); //RFC 8945 5.2 y 5.4 @@ -281,28 +305,29 @@ pub fn process_tsig(msg: &DnsMessage,key:&[u8], key_name: String, time: u64, av tsig_rr_copy = data; } _ => { - println!("error") + println!("error"); + unimplemented!("TODO: error code if last rr is not tsig; FORMERR") } } - let nuevo_len_arcount = addit.len() as u16; - let mut new_header = retmsg.get_header(); - new_header.set_arcount(nuevo_len_arcount); - retmsg.set_header(new_header); + //RFC 8945 5.2.1 - let name_alg = tsig_rr_copy.get_algorithm_name().get_name(); let key_in_rr = rr_copy.get_name().get_name(); - let flag = check_alg_name(&name_alg,available_algorithm); + let name_alg = tsig_rr_copy.get_algorithm_name().get_name(); + + let flag = check_alg_name(&name_alg, available_algorithm); if !flag { println!("RCODE 9: NOAUTH\n TSIG ERROR 17: BADKEY"); return (false, TsigErrorCode::BADKEY); } - let cond1 = check_key(key_in_rr,key_name); + + let cond1 = check_key(key_in_rr, key_name); if !cond1 { println!("RCODE 9: NOAUTH\n TSIG ERROR 17: BADKEY"); return (false, TsigErrorCode::BADKEY); } + //RFC 8945 5.2.2 - retmsg.set_additional(addit); + //retmsg.set_additional(addit); let fudge = tsig_rr_copy.get_fudge(); let time_signed = tsig_rr_copy.get_time_signed(); let mac_received = tsig_rr_copy.get_mac(); @@ -313,9 +338,21 @@ pub fn process_tsig(msg: &DnsMessage,key:&[u8], key_name: String, time: u64, av "hmac-sha256" => new_alg_name = TsigAlgorithm::HmacSha256, &_ => println!("not supported algorithm") } - let new_mac = sign_tsig(&mut retmsg, key, new_alg_name, fudge, time_signed, key_name); - + + //let nuevo_len_arcount = addit.len() as u16; + //let mut new_header = retmsg.get_header(); + //new_header.set_arcount(nuevo_len_arcount); + //retmsg.set_header(new_header); + retmsg.set_additional(addit); + retmsg.update_header_counters(); + + // This gets the bytes to use the function and generate the digest + let bytes_to_hash = get_digest_request(mac_to_process, retmsg.to_bytes(), rr_copy); + + let new_mac = digest(bytes_to_hash, new_alg_name, key.to_vec()); + let cond2 = check_mac(new_mac, mac_received); + if !cond2 { println!("RCODE 9: NOAUTH\n TSIG ERROR 16: BADSIG"); return (false, TsigErrorCode::BADSIG) @@ -360,7 +397,7 @@ fn check_process_tsig_exists() { let mut lista :Vec<(String, bool)> = vec![]; let server_key = b"1234567890"; lista.push((String::from("hmac-sha256"),true)); - let (answer, error) = process_tsig(& response, server_key, key_name, 21010, lista); + let (answer, error) = process_tsig(& response, server_key, key_name, 21010, lista, vec![]); assert!(!answer); assert_eq!(error,TsigErrorCode::FORMERR); } @@ -379,16 +416,16 @@ fn check_process_tsig_exists2() { // cloning response let mut response2 = response.clone(); - sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name.clone()); + sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name.clone(), vec![]); let mut response_capture = response.clone(); - sign_tsig(&mut response_capture, server_key, alg_name2, fudge, time_signed, key_name.clone()); + sign_tsig(&mut response_capture, server_key, alg_name2, fudge, time_signed, key_name.clone(), vec![]); //Client process let key_name:String = "".to_string(); let mut lista :Vec<(String, bool)> = vec![]; lista.push((String::from("hmac-sha256"),true)); - let (control_answer, _) = process_tsig(& response, server_key, key_name.clone(),21010, lista.clone()); + let (control_answer, _) = process_tsig(& response, server_key, key_name.clone(),21010, lista.clone(), vec![]); assert!(control_answer); - let (answer, error) = process_tsig(& response_capture, server_key, key_name, 21010, lista); + let (answer, error) = process_tsig(& response_capture, server_key, key_name, 21010, lista, vec![]); assert!(!answer); assert_eq!(error, TsigErrorCode::FORMERR); } @@ -404,7 +441,7 @@ fn check_process_tsig_exists3(){ let time_signed = 21000; let key_name = ""; //se crea un rr TSIG que se añadirá en adittionals - sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name.to_string()); + sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name.to_string(), vec![]); //se agrega otro resource record en el additional... let mut new_additional = Vec::::new(); @@ -418,7 +455,7 @@ fn check_process_tsig_exists3(){ let key_name:String = "".to_string(); let mut lista :Vec<(String, bool)> = vec![]; lista.push((String::from("hmac-sha256"),true)); - let (answer, error) = process_tsig(& response_capture, server_key, key_name, 21010, lista); + let (answer, error) = process_tsig(& response_capture, server_key, key_name, 21010, lista, vec![]); assert!(!answer); assert_eq!(error, TsigErrorCode::FORMERR); } @@ -431,14 +468,14 @@ fn check_process_tsig_alg_name() { let fudge = 300; let time_signed = 21000; let key_name = "".to_string(); - sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name); + sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name, vec![]); let mut response_capture = response.clone(); //Client process let key_name:String = "".to_string(); let mut lista :Vec<(String, bool)> = vec![]; //suponemos que hmacsha256 no está disponible lista.push((String::from("hmac-sha1"),true)); - let (answer, error) = process_tsig(& response_capture, server_key, key_name, 21010, lista); + let (answer, error) = process_tsig(& response_capture, server_key, key_name, 21010, lista, vec![]); assert!(!answer); assert_eq!(error,TsigErrorCode::BADKEY); } @@ -451,14 +488,14 @@ fn check_process_tsig_alg_name2() { let fudge = 300; let time_signed = 21000; let key_name = "".to_string(); - sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name); + sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name, vec![]); let mut response_capture = response.clone(); //Client process let key_name:String = "".to_string(); let mut lista :Vec<(String, bool)> = vec![]; //suponemos que reconocemos hmac-sha256, pero no está implementado lista.push((String::from("hmac-sha256"),false)); - let (answer, error) = process_tsig(& response_capture, server_key, key_name, 21010, lista); + let (answer, error) = process_tsig(& response_capture, server_key, key_name, 21010, lista, vec![]); assert!(!answer); assert_eq!(error,TsigErrorCode::BADKEY); } @@ -471,14 +508,14 @@ fn check_process_tsig_key(){ let fudge = 300; let time_signed = 21000; let key_name = "".to_string(); - sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name); + sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name, vec![]); let mut response_capture = response.clone(); //Client process let key_name:String = "different".to_string(); let mut lista :Vec<(String, bool)> = vec![]; //suponemos que reconocemos hmac-sha256, pero no está implementado lista.push((String::from("hmac-sha256"),false)); - let (answer, error) = process_tsig(& response_capture, server_key, key_name, 21010, lista); + let (answer, error) = process_tsig(& response_capture, server_key, key_name, 21010, lista, vec![]); assert!(!answer); assert_eq!(error,TsigErrorCode::BADKEY); } @@ -493,14 +530,14 @@ fn check_process_tsig_badsign(){ let time_signed = 210000000; let key_name = "".to_string(); // se firma el mensaje con algoritmo SHA-1 - sign_tsig(& mut msg1, key, alg_name, fudge, time_signed, key_name); + sign_tsig(& mut msg1, key, alg_name, fudge, time_signed, key_name, vec![]); let mut lista :Vec<(String, bool)> = vec![]; lista.push((String::from("hmac-sha1"),true)); lista.push((String::from("hmac-sha256"),true)); // se verifica que el mensaje está firmado, pero se usa otra key let key_name = "".to_string(); let key2 = b"12345678909"; - let (answer,error) = process_tsig(&mut msg1, key2, key_name, time_signed,lista); + let (answer,error) = process_tsig(&mut msg1, key2, key_name, time_signed,lista, vec![]); assert_eq!(error,TsigErrorCode::BADSIG); } #[test] @@ -512,33 +549,35 @@ fn check_proces_tsig_badtime(){ let fudge = 300; let time_signed = 21000; let key_name = "".to_string(); - sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name); + sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name, vec![]); let mut response_capture = response.clone(); //Client process let key_name:String = "".to_string(); let mut lista :Vec<(String, bool)> = vec![]; //suponemos que reconocemos hmac-sha256, pero no está implementado lista.push((String::from("hmac-sha256"),true)); - let (answer, error) = process_tsig(& response_capture, server_key, key_name, 22010, lista); + let (answer, error) = process_tsig(& response_capture, server_key, key_name, + 22010, lista, vec![]); assert!(!answer); assert_eq!(error,TsigErrorCode::BADTIME); } #[test] fn check_process_tsig() { - //Server process + //sender process let mut response = DnsMessage::new_response_message(String::from("test.com"), "NS", "IN", 1, true, 1); let server_key = b"1234567890"; let alg_name = TsigAlgorithm::HmacSha256; let fudge = 300; let time_signed = 21000; let key_name = "".to_string(); - sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name); + sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name, vec![]); let mut response_capture = response.clone(); - //Client process + //recv process let key_name:String = "".to_string(); let mut lista :Vec<(String, bool)> = vec![]; lista.push((String::from("hmac-sha256"),true)); - let (answer, error) = process_tsig(& response_capture, server_key, key_name, 21010, lista); + let (answer, error) = process_tsig(& response_capture, server_key, key_name, + 21010, lista, vec![]); assert!(answer); assert_eq!(error,TsigErrorCode::NOERR); } @@ -566,9 +605,9 @@ fn check_signed_tsig() { let tsig_rr = set_tsig_vars(tsig_alg_to_string(&alg_name).as_str(), &name, time_signed, fudge); let q_for_mac = q.clone(); //creation of the signature to compare - let firma_a_comparar = sign_tsig(&mut q, key, alg_name, fudge, time_signed, name); + let firma_a_comparar = sign_tsig(&mut q, key, alg_name, fudge, time_signed, name, vec![]); // creation of the signature digest - let dig_for_mac = get_digest_request(q_for_mac.to_bytes(), tsig_rr); + let dig_for_mac = get_digest_request(vec![],q_for_mac.to_bytes(), tsig_rr); let mut hasher = crypto_hmac::new(Sha1::new(), key); hasher.input(&dig_for_mac[..]);