mirror of
https://github.com/ZeusWPI/ZNS.git
synced 2024-11-27 22:51:12 +01:00
Add rsa support
This commit is contained in:
parent
c6437e6901
commit
a166ec562b
9 changed files with 224 additions and 34 deletions
21
Cargo.lock
generated
21
Cargo.lock
generated
|
@ -17,6 +17,26 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "asn1"
|
||||
version = "0.16.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "532ceda058281b62096b2add4ab00ab3a453d30dee28b8890f62461a0109ebbd"
|
||||
dependencies = [
|
||||
"asn1_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "asn1_derive"
|
||||
version = "0.16.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56e6076d38cc17cc22b0f65f31170a2ee1975e6b07f0012893aefd86ce19c987"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
|
@ -1296,6 +1316,7 @@ dependencies = [
|
|||
name = "zeusns"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"asn1",
|
||||
"base64",
|
||||
"diesel",
|
||||
"dotenvy",
|
||||
|
|
|
@ -11,3 +11,4 @@ tokio = {version = "1.36.0", features = ["macros","rt-multi-thread","net"], defa
|
|||
ring = "0.17.8"
|
||||
base64 = "0.22.0"
|
||||
reqwest = {version = "0.12.4", features = ["json","default"]}
|
||||
asn1 = "0.16.2"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use reqwest::Error;
|
||||
use base64::prelude::*;
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
|
@ -9,7 +9,11 @@ use crate::{
|
|||
structs::{Class, RRClass, RRType, Type},
|
||||
};
|
||||
|
||||
use super::{dnskey::DNSKeyRData, sig::Sig};
|
||||
use super::{
|
||||
dnskey::DNSKeyRData,
|
||||
pubkeys::{Ed25519PublicKey, PublicKey, PublicKeyError, RsaPublicKey, SSH_ED25519, SSH_RSA},
|
||||
sig::Sig,
|
||||
};
|
||||
|
||||
pub(super) async fn authenticate(
|
||||
sig: &Sig,
|
||||
|
@ -32,7 +36,7 @@ pub(super) async fn authenticate(
|
|||
}
|
||||
}
|
||||
|
||||
async fn validate_ssh(username: &String, sig: &Sig) -> Result<bool, Error> {
|
||||
async fn validate_ssh(username: &String, sig: &Sig) -> Result<bool, PublicKeyError> {
|
||||
Ok(reqwest::get(format!(
|
||||
"{}/users/keys/{}",
|
||||
Config::get().zauth_url,
|
||||
|
@ -44,11 +48,13 @@ async fn validate_ssh(username: &String, sig: &Sig) -> Result<bool, Error> {
|
|||
.iter()
|
||||
.any(|key| {
|
||||
let key_split: Vec<&str> = key.split_ascii_whitespace().collect();
|
||||
match key_split.len() {
|
||||
3 => match key_split[0] {
|
||||
"ssh-ed25519" => sig.verify_ssh_ed25519(key_split[1]),
|
||||
_ => false,
|
||||
},
|
||||
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,
|
||||
}
|
||||
}))
|
||||
|
@ -67,3 +73,19 @@ async fn validate_dnskey(zone: &Vec<String>, sig: &Sig) -> Result<bool, Database
|
|||
}),
|
||||
)
|
||||
}
|
||||
|
||||
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 {
|
||||
fn from(value: PublicKeyError) -> Self {
|
||||
AuthenticationError {
|
||||
message: value.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use base64::prelude::*;
|
||||
|
||||
use crate::{errors::ParseError, parser::FromBytes, reader::Reader};
|
||||
|
||||
use super::sig::Sig;
|
||||
use super::{
|
||||
pubkeys::{Ed25519PublicKey, PublicKey, RsaPublicKey},
|
||||
sig::Sig,
|
||||
};
|
||||
|
||||
/// https://datatracker.ietf.org/doc/html/rfc4034#section-2
|
||||
#[derive(Debug)]
|
||||
|
@ -27,9 +28,12 @@ impl FromBytes for DNSKeyRData {
|
|||
|
||||
impl DNSKeyRData {
|
||||
pub fn verify(&self, sig: &Sig) -> bool {
|
||||
let encoded = BASE64_STANDARD.encode(&self.public_key);
|
||||
match self.algorithm {
|
||||
15 => sig.verify_ed25519(&encoded),
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ use super::ResponseHandler;
|
|||
|
||||
mod authenticate;
|
||||
mod dnskey;
|
||||
mod pubkeys;
|
||||
mod sig;
|
||||
|
||||
pub(super) struct UpdateHandler {}
|
||||
|
|
36
src/handlers/update/pubkeys/ed25519.rs
Normal file
36
src/handlers/update/pubkeys/ed25519.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use ring::signature;
|
||||
|
||||
use crate::reader::Reader;
|
||||
|
||||
use super::{PublicKey, PublicKeyError, SSH_ED25519};
|
||||
|
||||
pub struct Ed25519PublicKey {
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl PublicKey for Ed25519PublicKey {
|
||||
fn from_openssh(key: &[u8]) -> Result<Self, PublicKeyError>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let mut reader = Reader::new(key);
|
||||
Ed25519PublicKey::verify_ssh_type(&mut reader, SSH_ED25519)?;
|
||||
reader.read_i32()?;
|
||||
Ok(Ed25519PublicKey {
|
||||
data: reader.read(reader.unread_bytes())?,
|
||||
})
|
||||
}
|
||||
|
||||
fn from_dnskey(key: &[u8]) -> Result<Self, PublicKeyError>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Ok(Ed25519PublicKey { data: key.to_vec() })
|
||||
}
|
||||
|
||||
fn verify(&self, data: &[u8], signature: &[u8]) -> Result<bool, PublicKeyError> {
|
||||
let pkey = ring::signature::UnparsedPublicKey::new(&signature::ED25519, &self.data);
|
||||
|
||||
Ok(pkey.verify(data, signature).is_ok())
|
||||
}
|
||||
}
|
64
src/handlers/update/pubkeys/mod.rs
Normal file
64
src/handlers/update/pubkeys/mod.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
mod ed25519;
|
||||
mod rsa;
|
||||
use core::fmt;
|
||||
use std::str::from_utf8;
|
||||
|
||||
use base64::prelude::*;
|
||||
|
||||
use crate::{errors::ReaderError, reader::Reader};
|
||||
|
||||
pub use self::ed25519::Ed25519PublicKey;
|
||||
pub use self::rsa::RsaPublicKey;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PublicKeyError {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl fmt::Display for PublicKeyError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Public Key Error: {}", self.message)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ReaderError> for PublicKeyError {
|
||||
fn from(value: ReaderError) -> Self {
|
||||
PublicKeyError {
|
||||
message: value.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const SSH_ED25519: &str = "ssh-ed25519";
|
||||
pub const SSH_RSA: &str = "ssh-rsa";
|
||||
|
||||
pub trait PublicKey {
|
||||
fn verify_ssh_type(reader: &mut Reader, key_type: &str) -> Result<(), PublicKeyError> {
|
||||
let type_size = reader.read_i32()?;
|
||||
let read = reader.read(type_size as usize)?;
|
||||
let algo_type = from_utf8(&read).map_err(|e| PublicKeyError {
|
||||
message: format!(
|
||||
"Could not convert type name bytes to string: {}",
|
||||
e.to_string()
|
||||
),
|
||||
})?;
|
||||
|
||||
if algo_type == key_type {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(PublicKeyError {
|
||||
message: String::from("ssh key type does not match identifier"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn from_openssh(key: &[u8]) -> Result<Self, PublicKeyError>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn from_dnskey(key: &[u8]) -> Result<Self, PublicKeyError>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn verify(&self, data: &[u8], signature: &[u8]) -> Result<bool, PublicKeyError>;
|
||||
}
|
57
src/handlers/update/pubkeys/rsa.rs
Normal file
57
src/handlers/update/pubkeys/rsa.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
use ring::signature;
|
||||
|
||||
use crate::reader::Reader;
|
||||
|
||||
use super::{PublicKey, PublicKeyError, SSH_RSA};
|
||||
|
||||
pub struct RsaPublicKey {
|
||||
e: Vec<u8>,
|
||||
n: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(asn1::Asn1Write)]
|
||||
struct RsaAsn1<'a> {
|
||||
n: Option<asn1::BigInt<'a>>,
|
||||
e: Option<asn1::BigInt<'a>>,
|
||||
}
|
||||
|
||||
impl PublicKey for RsaPublicKey {
|
||||
fn from_openssh(key: &[u8]) -> Result<Self, PublicKeyError>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let mut reader = Reader::new(key);
|
||||
RsaPublicKey::verify_ssh_type(&mut reader, SSH_RSA)?;
|
||||
let e_size = reader.read_i32()?;
|
||||
let e = reader.read(e_size as usize)?;
|
||||
let n_size = reader.read_i32()?;
|
||||
let n = reader.read(n_size as usize)?;
|
||||
Ok(RsaPublicKey { e, n })
|
||||
}
|
||||
|
||||
fn verify(&self, data: &[u8], signature: &[u8]) -> Result<bool, PublicKeyError> {
|
||||
let result = asn1::write_single(&RsaAsn1 {
|
||||
n: asn1::BigInt::new(&self.n),
|
||||
e: asn1::BigInt::new(&self.e),
|
||||
})
|
||||
.map_err(|e| PublicKeyError {
|
||||
message: format!("Verify Error: {}", e),
|
||||
})?;
|
||||
|
||||
let pkey =
|
||||
ring::signature::UnparsedPublicKey::new(&signature::RSA_PKCS1_2048_8192_SHA512, result);
|
||||
|
||||
Ok(pkey.verify(data, signature).is_ok())
|
||||
}
|
||||
|
||||
fn from_dnskey(key: &[u8]) -> Result<Self, PublicKeyError>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let mut reader = Reader::new(key);
|
||||
let e_len = reader.read_u8()?;
|
||||
let e = reader.read(e_len as usize)?;
|
||||
let n = reader.read(reader.unread_bytes())?;
|
||||
Ok(RsaPublicKey { e, n })
|
||||
}
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
use base64::prelude::*;
|
||||
|
||||
use crate::{
|
||||
errors::ParseError,
|
||||
parser::FromBytes,
|
||||
|
@ -7,6 +5,8 @@ use crate::{
|
|||
structs::{KeyRData, RR},
|
||||
};
|
||||
|
||||
use super::pubkeys::PublicKey;
|
||||
|
||||
pub(super) struct Sig {
|
||||
raw_data: Vec<u8>,
|
||||
key_rdata: KeyRData,
|
||||
|
@ -29,24 +29,8 @@ impl Sig {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn verify_ed25519(&self, key: &str) -> bool {
|
||||
let blob = BASE64_STANDARD.decode(key).unwrap();
|
||||
|
||||
let pkey = ring::signature::UnparsedPublicKey::new(&ring::signature::ED25519, &blob);
|
||||
|
||||
pkey.verify(&self.raw_data, &self.key_rdata.signature)
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
pub fn verify_ssh_ed25519(&self, key: &str) -> bool {
|
||||
let blob = BASE64_STANDARD.decode(key).unwrap();
|
||||
|
||||
let pkey = ring::signature::UnparsedPublicKey::new(
|
||||
&ring::signature::ED25519,
|
||||
&blob.as_slice()[19..],
|
||||
);
|
||||
|
||||
pkey.verify(&self.raw_data, &self.key_rdata.signature)
|
||||
.is_ok()
|
||||
pub fn verify(&self, key: impl PublicKey) -> bool {
|
||||
key.verify(&self.raw_data, &self.key_rdata.signature)
|
||||
.is_ok_and(|b| b)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue