mirror of
https://github.com/ZeusWPI/ZNS.git
synced 2024-11-21 21:41:10 +01:00
check signature algorithm beforehand and add RSASHA256 support
This commit is contained in:
parent
1161d34194
commit
6ac9f2f36e
12 changed files with 196 additions and 134 deletions
47
Cargo.lock
generated
47
Cargo.lock
generated
|
@ -435,6 +435,19 @@ dependencies = [
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "int-enum"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a37a9c11c6ecfec8b9bed97337dfecff3686d02ba8f52e8addad2829d047128"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"proc-macro2-diagnostics",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.9.0"
|
version = "2.9.0"
|
||||||
|
@ -647,13 +660,26 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.78"
|
version = "1.0.85"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2-diagnostics"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check",
|
||||||
|
"yansi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.35"
|
version = "1.0.35"
|
||||||
|
@ -869,9 +895,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.49"
|
version = "2.0.66"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496"
|
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1079,6 +1105,12 @@ version = "0.2.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "want"
|
name = "want"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
@ -1312,6 +1344,12 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yansi"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zeusns"
|
name = "zeusns"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -1320,6 +1358,7 @@ dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"diesel",
|
"diesel",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
|
"int-enum",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"ring",
|
"ring",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|
|
@ -3,7 +3,6 @@ name = "zeusns"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
diesel = { version = "2.1.4", features = ["postgres"] }
|
diesel = { version = "2.1.4", features = ["postgres"] }
|
||||||
dotenvy = "0.15"
|
dotenvy = "0.15"
|
||||||
|
@ -12,3 +11,4 @@ ring = "0.17.8"
|
||||||
base64 = "0.22.0"
|
base64 = "0.22.0"
|
||||||
reqwest = {version = "0.12.4", features = ["json","default"]}
|
reqwest = {version = "0.12.4", features = ["json","default"]}
|
||||||
asn1 = "0.16.2"
|
asn1 = "0.16.2"
|
||||||
|
int-enum = "1.1"
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
|
|
||||||
use super::ResponseHandler;
|
use super::ResponseHandler;
|
||||||
|
|
||||||
pub(super) struct QueryHandler {}
|
pub struct QueryHandler {}
|
||||||
|
|
||||||
impl ResponseHandler for QueryHandler {
|
impl ResponseHandler for QueryHandler {
|
||||||
async fn handle(message: &Message, _raw: &[u8]) -> Result<Message, DNSError> {
|
async fn handle(message: &Message, _raw: &[u8]) -> Result<Message, DNSError> {
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use base64::prelude::*;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::Config,
|
config::Config,
|
||||||
db::models::get_from_database,
|
db::models::get_from_database,
|
||||||
|
@ -9,16 +7,9 @@ use crate::{
|
||||||
structs::{Class, RRClass, RRType, Type},
|
structs::{Class, RRClass, RRType, Type},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{dnskey::DNSKeyRData, pubkeys::PublicKeyError, sig::Sig};
|
||||||
dnskey::DNSKeyRData,
|
|
||||||
pubkeys::{Ed25519PublicKey, PublicKey, PublicKeyError, RsaPublicKey, SSH_ED25519, SSH_RSA},
|
|
||||||
sig::Sig,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub(super) async fn authenticate(
|
pub async fn authenticate(sig: &Sig, zone: &Vec<String>) -> Result<bool, AuthenticationError> {
|
||||||
sig: &Sig,
|
|
||||||
zone: &Vec<String>,
|
|
||||||
) -> Result<bool, AuthenticationError> {
|
|
||||||
if zone.len() >= 4 {
|
if zone.len() >= 4 {
|
||||||
let username = &zone[zone.len() - 4]; // Should match: username.users.zeus.gent
|
let username = &zone[zone.len() - 4]; // Should match: username.users.zeus.gent
|
||||||
|
|
||||||
|
@ -36,7 +27,7 @@ pub(super) async fn authenticate(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn validate_ssh(username: &String, sig: &Sig) -> Result<bool, PublicKeyError> {
|
async fn validate_ssh(username: &String, sig: &Sig) -> Result<bool, reqwest::Error> {
|
||||||
Ok(reqwest::get(format!(
|
Ok(reqwest::get(format!(
|
||||||
"{}/users/keys/{}",
|
"{}/users/keys/{}",
|
||||||
Config::get().zauth_url,
|
Config::get().zauth_url,
|
||||||
|
@ -46,18 +37,7 @@ async fn validate_ssh(username: &String, sig: &Sig) -> Result<bool, PublicKeyErr
|
||||||
.json::<Vec<String>>()
|
.json::<Vec<String>>()
|
||||||
.await?
|
.await?
|
||||||
.iter()
|
.iter()
|
||||||
.any(|key| {
|
.any(|key| sig.verify_ssh(&key).is_ok_and(|b| b)))
|
||||||
let key_split: Vec<&str> = key.split_ascii_whitespace().collect();
|
|
||||||
let bin = BASE64_STANDARD.decode(key_split[1]).unwrap();
|
|
||||||
match key_split[0] {
|
|
||||||
//TODO: do something with error, debugging?
|
|
||||||
SSH_ED25519 => {
|
|
||||||
Ed25519PublicKey::from_openssh(&bin).is_ok_and(|pubkey| sig.verify(pubkey))
|
|
||||||
}
|
|
||||||
SSH_RSA => RsaPublicKey::from_openssh(&bin).is_ok_and(|pubkey| sig.verify(pubkey)),
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn validate_dnskey(zone: &Vec<String>, sig: &Sig) -> Result<bool, DatabaseError> {
|
async fn validate_dnskey(zone: &Vec<String>, sig: &Sig) -> Result<bool, DatabaseError> {
|
||||||
|
@ -68,20 +48,11 @@ async fn validate_dnskey(zone: &Vec<String>, sig: &Sig) -> Result<bool, Database
|
||||||
.any(|rr| {
|
.any(|rr| {
|
||||||
let mut reader = Reader::new(&rr.rdata);
|
let mut reader = Reader::new(&rr.rdata);
|
||||||
DNSKeyRData::from_bytes(&mut reader)
|
DNSKeyRData::from_bytes(&mut reader)
|
||||||
.map(|key| key.verify(sig))
|
.is_ok_and(|dnskey| sig.verify_dnskey(dnskey).is_ok_and(|b| b))
|
||||||
.is_ok_and(|b| b)
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<reqwest::Error> for PublicKeyError {
|
|
||||||
fn from(value: reqwest::Error) -> Self {
|
|
||||||
PublicKeyError {
|
|
||||||
message: format!("Reqwest Error: {}", value.to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<PublicKeyError> for AuthenticationError {
|
impl From<PublicKeyError> for AuthenticationError {
|
||||||
fn from(value: PublicKeyError) -> Self {
|
fn from(value: PublicKeyError) -> Self {
|
||||||
AuthenticationError {
|
AuthenticationError {
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
use crate::{errors::ParseError, parser::FromBytes, reader::Reader};
|
use crate::{errors::ParseError, parser::FromBytes, reader::Reader};
|
||||||
|
|
||||||
use super::{
|
use super::sig::Algorithm;
|
||||||
pubkeys::{Ed25519PublicKey, PublicKey, RsaPublicKey},
|
|
||||||
sig::Sig,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// https://datatracker.ietf.org/doc/html/rfc4034#section-2
|
/// https://datatracker.ietf.org/doc/html/rfc4034#section-2
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct DNSKeyRData {
|
pub struct DNSKeyRData {
|
||||||
pub flags: u16,
|
pub flags: u16,
|
||||||
pub protocol: u8,
|
pub protocol: u8,
|
||||||
pub algorithm: u8,
|
pub algorithm: Algorithm,
|
||||||
pub public_key: Vec<u8>,
|
pub public_key: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,21 +17,8 @@ impl FromBytes for DNSKeyRData {
|
||||||
Ok(DNSKeyRData {
|
Ok(DNSKeyRData {
|
||||||
flags: reader.read_u16()?,
|
flags: reader.read_u16()?,
|
||||||
protocol: reader.read_u8()?,
|
protocol: reader.read_u8()?,
|
||||||
algorithm: reader.read_u8()?,
|
algorithm: Algorithm::from(reader.read_u8()?)?,
|
||||||
public_key: reader.read(reader.unread_bytes())?,
|
public_key: reader.read(reader.unread_bytes())?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DNSKeyRData {
|
|
||||||
pub fn verify(&self, sig: &Sig) -> bool {
|
|
||||||
match self.algorithm {
|
|
||||||
10 => {
|
|
||||||
RsaPublicKey::from_dnskey(&self.public_key).is_ok_and(|pubkey| sig.verify(pubkey))
|
|
||||||
}
|
|
||||||
15 => Ed25519PublicKey::from_dnskey(&self.public_key)
|
|
||||||
.is_ok_and(|pubkey| sig.verify(pubkey)),
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ mod dnskey;
|
||||||
mod pubkeys;
|
mod pubkeys;
|
||||||
mod sig;
|
mod sig;
|
||||||
|
|
||||||
pub(super) struct UpdateHandler {}
|
pub struct UpdateHandler {}
|
||||||
|
|
||||||
impl ResponseHandler for UpdateHandler {
|
impl ResponseHandler for UpdateHandler {
|
||||||
async fn handle(message: &Message, raw: &[u8]) -> Result<Message, crate::errors::DNSError> {
|
async fn handle(message: &Message, raw: &[u8]) -> Result<Message, crate::errors::DNSError> {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use ring::signature;
|
use ring::signature;
|
||||||
|
|
||||||
use crate::reader::Reader;
|
use crate::{handlers::update::sig::Algorithm, reader::Reader};
|
||||||
|
|
||||||
use super::{PublicKey, PublicKeyError, SSH_ED25519};
|
use super::{PublicKey, PublicKeyError, SSH_ED25519};
|
||||||
|
|
||||||
|
@ -28,7 +28,12 @@ impl PublicKey for Ed25519PublicKey {
|
||||||
Ok(Ed25519PublicKey { data: key.to_vec() })
|
Ok(Ed25519PublicKey { data: key.to_vec() })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify(&self, data: &[u8], signature: &[u8]) -> Result<bool, PublicKeyError> {
|
fn verify(
|
||||||
|
&self,
|
||||||
|
data: &[u8],
|
||||||
|
signature: &[u8],
|
||||||
|
_algorithm: &Algorithm,
|
||||||
|
) -> Result<bool, PublicKeyError> {
|
||||||
let pkey = ring::signature::UnparsedPublicKey::new(&signature::ED25519, &self.data);
|
let pkey = ring::signature::UnparsedPublicKey::new(&signature::ED25519, &self.data);
|
||||||
|
|
||||||
Ok(pkey.verify(data, signature).is_ok())
|
Ok(pkey.verify(data, signature).is_ok())
|
||||||
|
|
|
@ -3,13 +3,13 @@ mod rsa;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use std::str::from_utf8;
|
use std::str::from_utf8;
|
||||||
|
|
||||||
use base64::prelude::*;
|
|
||||||
|
|
||||||
use crate::{errors::ReaderError, reader::Reader};
|
use crate::{errors::ReaderError, reader::Reader};
|
||||||
|
|
||||||
pub use self::ed25519::Ed25519PublicKey;
|
pub use self::ed25519::Ed25519PublicKey;
|
||||||
pub use self::rsa::RsaPublicKey;
|
pub use self::rsa::RsaPublicKey;
|
||||||
|
|
||||||
|
use super::sig::Algorithm;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PublicKeyError {
|
pub struct PublicKeyError {
|
||||||
pub message: String,
|
pub message: String,
|
||||||
|
@ -60,5 +60,10 @@ pub trait PublicKey {
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
fn verify(&self, data: &[u8], signature: &[u8]) -> Result<bool, PublicKeyError>;
|
fn verify(
|
||||||
|
&self,
|
||||||
|
data: &[u8],
|
||||||
|
signature: &[u8],
|
||||||
|
algorithm: &Algorithm,
|
||||||
|
) -> Result<bool, PublicKeyError>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use ring::signature;
|
use ring::signature;
|
||||||
|
|
||||||
use crate::reader::Reader;
|
use crate::{handlers::update::sig::Algorithm, reader::Reader};
|
||||||
|
|
||||||
use super::{PublicKey, PublicKeyError, SSH_RSA};
|
use super::{PublicKey, PublicKeyError, SSH_RSA};
|
||||||
|
|
||||||
|
@ -29,7 +29,12 @@ impl PublicKey for RsaPublicKey {
|
||||||
Ok(RsaPublicKey { e, n })
|
Ok(RsaPublicKey { e, n })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify(&self, data: &[u8], signature: &[u8]) -> Result<bool, PublicKeyError> {
|
fn verify(
|
||||||
|
&self,
|
||||||
|
data: &[u8],
|
||||||
|
signature: &[u8],
|
||||||
|
algorithm: &Algorithm,
|
||||||
|
) -> Result<bool, PublicKeyError> {
|
||||||
let result = asn1::write_single(&RsaAsn1 {
|
let result = asn1::write_single(&RsaAsn1 {
|
||||||
n: asn1::BigInt::new(&self.n),
|
n: asn1::BigInt::new(&self.n),
|
||||||
e: asn1::BigInt::new(&self.e),
|
e: asn1::BigInt::new(&self.e),
|
||||||
|
@ -38,8 +43,15 @@ impl PublicKey for RsaPublicKey {
|
||||||
message: format!("Verify Error: {}", e),
|
message: format!("Verify Error: {}", e),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let pkey =
|
let signature_type = match algorithm {
|
||||||
ring::signature::UnparsedPublicKey::new(&signature::RSA_PKCS1_2048_8192_SHA512, result);
|
Algorithm::RSASHA512 => Ok(&signature::RSA_PKCS1_2048_8192_SHA512),
|
||||||
|
Algorithm::RSASHA256 => Ok(&signature::RSA_PKCS1_2048_8192_SHA256),
|
||||||
|
_ => Err(PublicKeyError {
|
||||||
|
message: format!("RsaPublicKey: invalid verify algorithm",),
|
||||||
|
}),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
let pkey = ring::signature::UnparsedPublicKey::new(signature_type, result);
|
||||||
|
|
||||||
Ok(pkey.verify(data, signature).is_ok())
|
Ok(pkey.verify(data, signature).is_ok())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,85 @@
|
||||||
|
use base64::prelude::*;
|
||||||
|
use int_enum::IntEnum;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::ParseError,
|
errors::ParseError,
|
||||||
parser::FromBytes,
|
parser::FromBytes,
|
||||||
reader::Reader,
|
reader::Reader,
|
||||||
structs::{KeyRData, RR},
|
structs::{LabelString, RR},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::pubkeys::PublicKey;
|
use super::{
|
||||||
|
dnskey::DNSKeyRData,
|
||||||
|
pubkeys::{Ed25519PublicKey, PublicKey, PublicKeyError, RsaPublicKey, SSH_ED25519, SSH_RSA},
|
||||||
|
};
|
||||||
|
|
||||||
pub(super) struct Sig {
|
pub struct Sig {
|
||||||
raw_data: Vec<u8>,
|
raw_data: Vec<u8>,
|
||||||
key_rdata: KeyRData,
|
key_rdata: SigRData,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct SigRData {
|
||||||
|
type_covered: u16,
|
||||||
|
algo: Algorithm,
|
||||||
|
labels: u8,
|
||||||
|
original_ttl: u32,
|
||||||
|
signature_expiration: u32,
|
||||||
|
signature_inception: u32,
|
||||||
|
key_tag: u16,
|
||||||
|
signer: LabelString,
|
||||||
|
signature: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(IntEnum, Debug, PartialEq)]
|
||||||
|
pub enum Algorithm {
|
||||||
|
ED25519 = 15,
|
||||||
|
RSASHA512 = 10,
|
||||||
|
RSASHA256 = 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Algorithm {
|
||||||
|
pub fn from(value: u8) -> Result<Self, ParseError> {
|
||||||
|
Algorithm::try_from(value).map_err(|a| ParseError {
|
||||||
|
// TODO: Should respond with error code refused or notimpl
|
||||||
|
object: String::from("Algorithm"),
|
||||||
|
message: format!("Usupported algorithm: {}", a),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromBytes for SigRData {
|
||||||
|
fn from_bytes(reader: &mut Reader) -> Result<Self, ParseError> {
|
||||||
|
if reader.unread_bytes() < 18 {
|
||||||
|
Err(ParseError {
|
||||||
|
object: String::from("KeyRData"),
|
||||||
|
message: String::from("invalid rdata"),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Ok(SigRData {
|
||||||
|
type_covered: reader.read_u16()?,
|
||||||
|
algo: Algorithm::from(reader.read_u8()?)?,
|
||||||
|
labels: reader.read_u8()?,
|
||||||
|
original_ttl: reader.read_u32()?,
|
||||||
|
signature_expiration: reader.read_u32()?,
|
||||||
|
signature_inception: reader.read_u32()?,
|
||||||
|
key_tag: reader.read_u16()?,
|
||||||
|
signer: LabelString::from_bytes(reader)?,
|
||||||
|
signature: reader.read(reader.unread_bytes())?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sig {
|
impl Sig {
|
||||||
pub fn new(rr: &RR, datagram: &[u8]) -> Result<Sig, ParseError> {
|
pub fn new(rr: &RR, datagram: &[u8]) -> Result<Self, ParseError> {
|
||||||
let mut request = datagram[0..datagram.len() - 11 - rr.rdlength as usize].to_vec();
|
let mut request = datagram[0..datagram.len() - 11 - rr.rdlength as usize].to_vec();
|
||||||
request[11] -= 1; // Decrease arcount
|
request[11] -= 1; // Decrease arcount
|
||||||
|
|
||||||
let mut reader = Reader::new(&rr.rdata);
|
let mut reader = Reader::new(&rr.rdata);
|
||||||
let key_rdata = KeyRData::from_bytes(&mut reader)?;
|
let key_rdata = SigRData::from_bytes(&mut reader)?;
|
||||||
|
|
||||||
let mut raw_data = rr.rdata[0..rr.rdata.len() - key_rdata.signature.len()].to_vec();
|
let mut raw_data = rr.rdata[0..rr.rdata.len() - key_rdata.signature.len()].to_vec();
|
||||||
raw_data.extend(request);
|
raw_data.extend(request);
|
||||||
|
@ -29,8 +90,37 @@ impl Sig {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify(&self, key: impl PublicKey) -> bool {
|
fn verify(&self, key: impl PublicKey) -> Result<bool, PublicKeyError> {
|
||||||
key.verify(&self.raw_data, &self.key_rdata.signature)
|
key.verify(
|
||||||
.is_ok_and(|b| b)
|
&self.raw_data,
|
||||||
|
&self.key_rdata.signature,
|
||||||
|
&self.key_rdata.algo,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify_ssh(&self, key: &str) -> Result<bool, PublicKeyError> {
|
||||||
|
let key_split: Vec<&str> = key.split_ascii_whitespace().collect();
|
||||||
|
let bin = BASE64_STANDARD.decode(key_split[1]).unwrap();
|
||||||
|
|
||||||
|
match (key_split[0], &self.key_rdata.algo) {
|
||||||
|
(SSH_ED25519, Algorithm::ED25519) => self.verify(Ed25519PublicKey::from_openssh(&bin)?),
|
||||||
|
(SSH_RSA, Algorithm::RSASHA512 | Algorithm::RSASHA256) => {
|
||||||
|
self.verify(RsaPublicKey::from_openssh(&bin)?)
|
||||||
|
}
|
||||||
|
_ => Ok(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify_dnskey(&self, key: DNSKeyRData) -> Result<bool, PublicKeyError> {
|
||||||
|
if self.key_rdata.algo != key.algorithm {
|
||||||
|
Ok(false)
|
||||||
|
} else {
|
||||||
|
match self.key_rdata.algo {
|
||||||
|
Algorithm::RSASHA512 | Algorithm::RSASHA256 => {
|
||||||
|
self.verify(RsaPublicKey::from_dnskey(&key.public_key)?)
|
||||||
|
}
|
||||||
|
Algorithm::ED25519 => self.verify(Ed25519PublicKey::from_dnskey(&key.public_key)?),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,7 @@ use std::{mem::size_of, vec};
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::ParseError,
|
errors::ParseError,
|
||||||
reader::Reader,
|
reader::Reader,
|
||||||
structs::{
|
structs::{Class, Header, LabelString, Message, Opcode, Question, RRClass, RRType, Type, RR},
|
||||||
Class, Header, KeyRData, LabelString, Message, Opcode, Question, RRClass, RRType, Type, RR,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type Result<T> = std::result::Result<T, ParseError>;
|
type Result<T> = std::result::Result<T, ParseError>;
|
||||||
|
@ -42,26 +40,18 @@ impl From<Class> for u16 {
|
||||||
|
|
||||||
impl From<u16> for Type {
|
impl From<u16> for Type {
|
||||||
fn from(value: u16) -> Self {
|
fn from(value: u16) -> Self {
|
||||||
//TODO: use macro
|
match RRType::try_from(value) {
|
||||||
match value {
|
Ok(rrtype) => Type::Type(rrtype),
|
||||||
x if x == RRType::A as u16 => Type::Type(RRType::A),
|
Err(x) => Type::Other(x),
|
||||||
x if x == RRType::OPT as u16 => Type::Type(RRType::OPT),
|
|
||||||
x if x == RRType::SOA as u16 => Type::Type(RRType::SOA),
|
|
||||||
x if x == RRType::ANY as u16 => Type::Type(RRType::SOA),
|
|
||||||
x if x == RRType::KEY as u16 => Type::Type(RRType::KEY),
|
|
||||||
x if x == RRType::DNSKEY as u16 => Type::Type(RRType::DNSKEY),
|
|
||||||
x => Type::Other(x),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u16> for Class {
|
impl From<u16> for Class {
|
||||||
fn from(value: u16) -> Self {
|
fn from(value: u16) -> Self {
|
||||||
match value {
|
match RRClass::try_from(value) {
|
||||||
x if x == RRClass::IN as u16 => Class::Class(RRClass::IN),
|
Ok(rrclass) => Class::Class(rrclass),
|
||||||
x if x == RRClass::ANY as u16 => Class::Class(RRClass::ANY),
|
Err(x) => Class::Other(x),
|
||||||
x if x == RRClass::NONE as u16 => Class::Class(RRClass::NONE),
|
|
||||||
x => Class::Other(x),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -305,26 +295,3 @@ impl ToBytes for Message {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromBytes for KeyRData {
|
|
||||||
fn from_bytes(reader: &mut Reader) -> Result<Self> {
|
|
||||||
if reader.unread_bytes() < 18 {
|
|
||||||
Err(ParseError {
|
|
||||||
object: String::from("KeyRData"),
|
|
||||||
message: String::from("invalid rdata"),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Ok(KeyRData {
|
|
||||||
type_covered: reader.read_u16()?,
|
|
||||||
algo: reader.read_u8()?,
|
|
||||||
labels: reader.read_u8()?,
|
|
||||||
original_ttl: reader.read_u32()?,
|
|
||||||
signature_expiration: reader.read_u32()?,
|
|
||||||
signature_inception: reader.read_u32()?,
|
|
||||||
key_tag: reader.read_u16()?,
|
|
||||||
signer: LabelString::from_bytes(reader)?,
|
|
||||||
signature: reader.read(reader.unread_bytes())?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use int_enum::IntEnum;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
Type(RRType),
|
Type(RRType),
|
||||||
|
@ -5,7 +7,7 @@ pub enum Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, IntEnum)]
|
||||||
pub enum RRType {
|
pub enum RRType {
|
||||||
A = 1,
|
A = 1,
|
||||||
SOA = 6,
|
SOA = 6,
|
||||||
|
@ -22,7 +24,7 @@ pub enum Class {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, IntEnum)]
|
||||||
pub enum RRClass {
|
pub enum RRClass {
|
||||||
IN = 1,
|
IN = 1,
|
||||||
NONE = 254,
|
NONE = 254,
|
||||||
|
@ -94,16 +96,3 @@ pub struct OptRR {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type LabelString = Vec<String>;
|
pub type LabelString = Vec<String>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct KeyRData {
|
|
||||||
pub type_covered: u16,
|
|
||||||
pub algo: u8,
|
|
||||||
pub labels: u8,
|
|
||||||
pub original_ttl: u32,
|
|
||||||
pub signature_expiration: u32,
|
|
||||||
pub signature_inception: u32,
|
|
||||||
pub key_tag: u16,
|
|
||||||
pub signer: LabelString,
|
|
||||||
pub signature: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue