Skip to content

Commit

Permalink
handling key submission from client and responding with server public…
Browse files Browse the repository at this point in the history
… key
  • Loading branch information
Sarsoo committed Feb 10, 2024
1 parent 328c011 commit 6e954a9
Show file tree
Hide file tree
Showing 12 changed files with 372 additions and 23 deletions.
43 changes: 43 additions & 0 deletions dnstp/src/clients.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use std::collections::HashMap;
use std::time::SystemTime;
use aes_gcm_siv::Aes256GcmSiv;

pub struct Client {
pub first_seen: SystemTime,
pub shared_key: Aes256GcmSiv
}

impl Client {

pub fn new(shared_key: Aes256GcmSiv) -> Client
{
Client {
first_seen: SystemTime::now(),
shared_key
}
}
}

pub struct Clients {
client_map: HashMap<String, Client>
}

impl Clients {

pub fn new() -> Clients
{
Clients {
client_map: HashMap::new()
}
}

// pub fn add_from(&mut self, client_id: String, shared_key: Aes256GcmSiv)
// {
// self.client_map.insert(client_id, Client::new(shared_key));
// }

pub fn add(&mut self, client_id: String, client:Client)
{
self.client_map.insert(client_id, client);
}
}
2 changes: 1 addition & 1 deletion dnstp/src/crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
mod tests;

use std::str::FromStr;
use p256::{EncodedPoint, PublicKey, ecdh::EphemeralSecret, NistP256};
use p256::{PublicKey, ecdh::EphemeralSecret, NistP256};
use p256::elliptic_curve::ecdh::SharedSecret;
use aes_gcm_siv::{aead::{Aead, KeyInit}, AeadCore, Aes256GcmSiv, Nonce};

Expand Down
3 changes: 2 additions & 1 deletion dnstp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ mod byte;
pub mod processor;
pub mod message;
pub mod net;
mod string;
pub mod string;
pub mod config;
pub mod crypto;
mod clients;

pub use config::DomainConfig;
34 changes: 29 additions & 5 deletions dnstp/src/message/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,18 @@ impl DNSMessage {
}
}

pub fn a_resp_from_request(request: &DNSMessage, ip: impl Fn(&DNSQuestion) -> Ipv4Addr) -> DNSMessage
pub fn a_resp_from_request(&self, ip: impl Fn(&DNSQuestion) -> Ipv4Addr) -> DNSMessage
{
let mut response = DNSMessage{
header: request.header.clone(),
questions: request.questions.clone(),
header: self.header.clone(),
questions: self.questions.clone(),
answer_records: vec![],
authority_records: vec![],
additional_records: vec![],
peer: request.peer
peer: self.peer
};

response.answer_records = request.questions
response.answer_records = self.questions
.iter()
.map(|x|
ResourceRecord::from_query(x,
Expand All @@ -107,4 +107,28 @@ impl DNSMessage {

response
}

pub fn empty_resp_from_request(&self) -> DNSMessage
{
let mut response = DNSMessage{
header: self.header.clone(),
questions: self.questions.clone(),
answer_records: vec![],
authority_records: vec![],
additional_records: vec![],
peer: self.peer
};

response.header.direction = Direction::Response;
response.header.response = ResponseCode::NoError;
response.header.answer_record_count = 0;
response.header.authority_record_count = 0;
response.header.additional_record_count = 0;

if response.header.recursion_desired {
response.header.recursion_available = true;
}

response
}
}
23 changes: 23 additions & 0 deletions dnstp/src/message/question/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#[cfg(test)]
mod tests;

use std::fmt;
use urlencoding::decode;
use crate::byte::{push_split_bytes, two_byte_combine};
use crate::string::encode_domain_name;
Expand All @@ -25,6 +26,28 @@ pub enum QType {
ANY = 255,
}

impl fmt::Display for QType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
QType::A => write!(f, "A"),
QType::NS => write!(f, "NS"),
QType::CNAME => write!(f, "CNAME"),
QType::SOA => write!(f, "SOA"),
QType::WKS => write!(f, "WKS"),
QType::PTR => write!(f, "PTR"),
QType::HINFO => write!(f, "HINFO"),
QType::MINFO => write!(f, "MINFO"),
QType::MX => write!(f, "MX"),
QType::TXT => write!(f, "TXT"),
QType::RP => write!(f, "RP"),
QType::AAAA => write!(f, "AAAA"),
QType::SRV => write!(f, "SRV"),
QType::OPT => write!(f, "OPT"),
QType::ANY => write!(f, "ANY"),
}
}
}

impl TryFrom<u16> for QType {
type Error = u16;

Expand Down
30 changes: 30 additions & 0 deletions dnstp/src/message/record/cname_rdata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use std::fmt::{Debug, Formatter};
use crate::message::record::RData;
use crate::string::encode_domain_name;

pub struct CnameRdata {
pub rdata: String
}

impl Debug for CnameRdata {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CNAME")
.field("Host", &self.rdata)
.finish()
}
}

impl RData for CnameRdata {
fn to_bytes(&self) -> Vec<u8> {
encode_domain_name(&self.rdata)
}
}

impl CnameRdata {
pub fn from(rdata: String) -> CnameRdata
{
CnameRdata {
rdata
}
}
}
2 changes: 2 additions & 0 deletions dnstp/src/message/record/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ pub use aaaa_rdata::AAAARdata;
mod txt_rdata;
pub use txt_rdata::TXTRdata;

mod cname_rdata;
pub use cname_rdata::CnameRdata;

#[cfg(test)]
mod tests;
Expand Down
108 changes: 102 additions & 6 deletions dnstp/src/processor/request/encryption.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,112 @@
use std::net::Ipv4Addr;
use p256::ecdh::EphemeralSecret;
use crate::crypto::{get_random_asym_pair, trim_public_key};
use crate::message::DNSMessage;
use crate::clients::Client;
use crate::crypto::{asym_to_sym_key, fatten_public_key, get_random_asym_pair, get_shared_asym_secret, trim_public_key};
use crate::message::{ARdata, DNSMessage, DNSQuestion, QClass, QType, ResourceRecord};
use crate::message::record::CnameRdata;
use crate::string::{append_base_domain_to_key, strip_base_domain_from_key};

pub fn get_key_response(request: DNSMessage) -> DNSMessage
{
DNSMessage::a_resp_from_request(&request, |_| Ipv4Addr::from([127, 0, 0, 1]))
pub struct KeySwapContext {
pub new_client: Client,
pub response: DNSMessage,
pub server_public: String,
pub client_public: String
}

pub fn get_key_request_with_base_domain(base_domain: String) -> (EphemeralSecret, String)
{
let (private, public) = get_random_asym_pair();

(private, vec![trim_public_key(&public), base_domain].join("."))
(private, append_base_domain_to_key(trim_public_key(&public), &base_domain))
}

pub fn get_fattened_public_key(key_question: &DNSQuestion) -> (String, String)
{
let public_key = &key_question.qname;
let (trimmed_public_key, base_domain) = strip_base_domain_from_key(public_key);

(fatten_public_key(&trimmed_public_key), base_domain)
}

#[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Copy, Clone)]
pub enum KeyDecodeError {
QuestionCount(usize),
FirstQuestionNotA(QType),
SecondQuestionNotA(QType),
SharedSecretDerivation,
}

pub fn decode_key_request(message: DNSMessage) -> Result<KeySwapContext, KeyDecodeError>
{
if message.questions.len() == 2 {

if message.questions[0].qtype != QType::A
{
return Err(KeyDecodeError::FirstQuestionNotA(message.questions[0].qtype));
}

let key_question = &message.questions[1];

if key_question.qtype != QType::A
{
return Err(KeyDecodeError::SecondQuestionNotA(key_question.qtype));
}

let (fattened_public_key, base_domain) = get_fattened_public_key(&key_question);
let (server_private, server_public) = get_random_asym_pair();

let shared_secret = get_shared_asym_secret(server_private, fattened_public_key);

match shared_secret {
Ok(secret) => {

let sym_key = asym_to_sym_key(&secret);
let new_client = Client::new(sym_key);
let mut response = message.empty_resp_from_request();

let first_record = ResourceRecord {
name_offset: 12,
answer_type: QType::A,
class: QClass::Internet,
ttl: 0,
rd_length: 4,
r_data: Box::new(ARdata::from(Ipv4Addr::from([127,0,0,1])))
};

let second_record = ResourceRecord {
name_offset: 12 + (&message.questions[0]).to_bytes().len() as u16,
answer_type: QType::CNAME,
class: QClass::Internet,
ttl: 0,
rd_length: 4,
r_data: Box::new(
CnameRdata::from(
append_base_domain_to_key(
trim_public_key(&server_public),
&base_domain
)
)
)
};

response.answer_records = vec![
first_record, second_record
];

return Ok(KeySwapContext {
new_client,
response,
server_public,
client_public: key_question.qname.to_string()
});
}
Err(_) => {
return Err(KeyDecodeError::SharedSecretDerivation);
}
}
}
else
{
return Err(KeyDecodeError::QuestionCount(message.questions.len()));
}
}
Loading

0 comments on commit 6e954a9

Please sign in to comment.