Test request serialization
Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
parent
55e10a60c6
commit
5625bd95a4
|
@ -5,7 +5,7 @@ use ::zeroize::Zeroize;
|
||||||
|
|
||||||
/// User identifier. 16 bytes for easy uuid conversion
|
/// User identifier. 16 bytes for easy uuid conversion
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct UserID([u8; 16]);
|
pub struct UserID(pub [u8; 16]);
|
||||||
|
|
||||||
impl From<[u8; 16]> for UserID {
|
impl From<[u8; 16]> for UserID {
|
||||||
fn from(raw: [u8; 16]) -> Self {
|
fn from(raw: [u8; 16]) -> Self {
|
||||||
|
@ -36,7 +36,7 @@ impl UserID {
|
||||||
/// Authentication Token, basically just 32 random bytes
|
/// Authentication Token, basically just 32 random bytes
|
||||||
#[derive(Clone, Zeroize)]
|
#[derive(Clone, Zeroize)]
|
||||||
#[zeroize(drop)]
|
#[zeroize(drop)]
|
||||||
pub struct Token([u8; 32]);
|
pub struct Token(pub [u8; 32]);
|
||||||
|
|
||||||
impl Token {
|
impl Token {
|
||||||
/// New random token, anonymous should not check this anyway
|
/// New random token, anonymous should not check this anyway
|
||||||
|
@ -110,7 +110,7 @@ impl Domain {
|
||||||
pub const SERVICEID_AUTH: ServiceID = ServiceID([0; 16]);
|
pub const SERVICEID_AUTH: ServiceID = ServiceID([0; 16]);
|
||||||
/// The Service ID is a UUID associated with the service.
|
/// The Service ID is a UUID associated with the service.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct ServiceID([u8; 16]);
|
pub struct ServiceID(pub [u8; 16]);
|
||||||
|
|
||||||
impl From<[u8; 16]> for ServiceID {
|
impl From<[u8; 16]> for ServiceID {
|
||||||
fn from(raw: [u8; 16]) -> Self {
|
fn from(raw: [u8; 16]) -> Self {
|
||||||
|
|
|
@ -97,7 +97,9 @@ pub struct Req {
|
||||||
pub exchange_key: ExchangePubKey,
|
pub exchange_key: ExchangePubKey,
|
||||||
/// encrypted data
|
/// encrypted data
|
||||||
pub data: ReqInner,
|
pub data: ReqInner,
|
||||||
// Security: Add padding to min: 1200 bytes to avoid amplification attaks
|
// SECURITY: TODO: Add padding to min: 1200 bytes
|
||||||
|
// to avoid amplification attaks
|
||||||
|
// also: 1200 < 1280 to allow better vpn compatibility
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Req {
|
impl Req {
|
||||||
|
@ -125,7 +127,9 @@ impl Req {
|
||||||
+ HkdfKind::len()
|
+ HkdfKind::len()
|
||||||
+ CipherKind::len()
|
+ CipherKind::len()
|
||||||
+ self.exchange_key.kind().pub_len()
|
+ self.exchange_key.kind().pub_len()
|
||||||
|
+ self.cipher.nonce_len().0
|
||||||
+ self.data.len()
|
+ self.data.len()
|
||||||
|
+ self.cipher.tag_len().0
|
||||||
}
|
}
|
||||||
/// Serialize into raw bytes
|
/// Serialize into raw bytes
|
||||||
/// NOTE: assumes that there is exactly as much buffer as needed
|
/// NOTE: assumes that there is exactly as much buffer as needed
|
||||||
|
@ -135,8 +139,21 @@ impl Req {
|
||||||
tag_len: TagLen,
|
tag_len: TagLen,
|
||||||
out: &mut [u8],
|
out: &mut [u8],
|
||||||
) {
|
) {
|
||||||
//assert!(out.len() > , ": not enough buffer to serialize");
|
out[0..2].copy_from_slice(&self.key_id.0.to_le_bytes());
|
||||||
todo!()
|
out[2] = self.exchange as u8;
|
||||||
|
out[3] = self.hkdf as u8;
|
||||||
|
out[4] = self.cipher as u8;
|
||||||
|
let key_len = self.exchange_key.len();
|
||||||
|
let written_next = 5 + key_len;
|
||||||
|
self.exchange_key.serialize_into(&mut out[5..written_next]);
|
||||||
|
let written = written_next;
|
||||||
|
if let ReqInner::ClearText(data) = &self.data {
|
||||||
|
let from = written + head_len.0;
|
||||||
|
let to = out.len() - tag_len.0;
|
||||||
|
data.serialize(&mut out[from..to]);
|
||||||
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +164,7 @@ impl super::HandshakeParsing for Req {
|
||||||
return Err(Error::NotEnoughData);
|
return Err(Error::NotEnoughData);
|
||||||
}
|
}
|
||||||
let key_id: KeyID =
|
let key_id: KeyID =
|
||||||
KeyID(u16::from_le_bytes(raw[0..1].try_into().unwrap()));
|
KeyID(u16::from_le_bytes(raw[0..2].try_into().unwrap()));
|
||||||
use ::num_traits::FromPrimitive;
|
use ::num_traits::FromPrimitive;
|
||||||
let exchange: KeyExchangeKind = match KeyExchangeKind::from_u8(raw[2]) {
|
let exchange: KeyExchangeKind = match KeyExchangeKind::from_u8(raw[2]) {
|
||||||
Some(exchange) => exchange,
|
Some(exchange) => exchange,
|
||||||
|
@ -161,7 +178,7 @@ impl super::HandshakeParsing for Req {
|
||||||
Some(cipher) => cipher,
|
Some(cipher) => cipher,
|
||||||
None => return Err(Error::Parsing),
|
None => return Err(Error::Parsing),
|
||||||
};
|
};
|
||||||
let (exchange_key, len) = match ExchangePubKey::from_slice(&raw[5..]) {
|
let (exchange_key, len) = match ExchangePubKey::deserialize(&raw[5..]) {
|
||||||
Ok(exchange_key) => exchange_key,
|
Ok(exchange_key) => exchange_key,
|
||||||
Err(e) => return Err(e.into()),
|
Err(e) => return Err(e.into()),
|
||||||
};
|
};
|
||||||
|
@ -235,6 +252,21 @@ impl AuthInfo {
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
Self::MIN_PKT_LEN + self.domain.len()
|
Self::MIN_PKT_LEN + self.domain.len()
|
||||||
}
|
}
|
||||||
|
/// serialize into a buffer
|
||||||
|
/// Note: assumes there is enough space
|
||||||
|
pub fn serialize(&self, out: &mut [u8]) {
|
||||||
|
out[..auth::UserID::len()].copy_from_slice(&self.user.0);
|
||||||
|
const WRITTEN_TOKEN: usize = auth::UserID::len() + auth::Token::len();
|
||||||
|
out[auth::UserID::len()..WRITTEN_TOKEN].copy_from_slice(&self.token.0);
|
||||||
|
const WRITTEN_SERVICE_ID: usize =
|
||||||
|
WRITTEN_TOKEN + auth::ServiceID::len();
|
||||||
|
out[WRITTEN_TOKEN..WRITTEN_SERVICE_ID]
|
||||||
|
.copy_from_slice(&self.service_id.0);
|
||||||
|
let domain_len = self.domain.0.as_bytes().len() as u8;
|
||||||
|
out[WRITTEN_SERVICE_ID] = domain_len;
|
||||||
|
const WRITTEN_DOMAIN_LEN: usize = WRITTEN_SERVICE_ID + 1;
|
||||||
|
out[WRITTEN_DOMAIN_LEN..].copy_from_slice(&self.domain.0.as_bytes());
|
||||||
|
}
|
||||||
/// deserialize from raw bytes
|
/// deserialize from raw bytes
|
||||||
pub fn deserialize(raw: &[u8]) -> Result<Self, Error> {
|
pub fn deserialize(raw: &[u8]) -> Result<Self, Error> {
|
||||||
if raw.len() < Self::MIN_PKT_LEN {
|
if raw.len() < Self::MIN_PKT_LEN {
|
||||||
|
@ -295,6 +327,19 @@ impl ReqData {
|
||||||
/// Minimum byte length of the request data
|
/// Minimum byte length of the request data
|
||||||
pub const MIN_PKT_LEN: usize =
|
pub const MIN_PKT_LEN: usize =
|
||||||
16 + KeyID::len() + ID::len() + AuthInfo::MIN_PKT_LEN;
|
16 + KeyID::len() + ID::len() + AuthInfo::MIN_PKT_LEN;
|
||||||
|
/// serialize into a buffer
|
||||||
|
/// Note: assumes there is enough space
|
||||||
|
pub fn serialize(&self, out: &mut [u8]) {
|
||||||
|
out[..Nonce::len()].copy_from_slice(&self.nonce.0);
|
||||||
|
const WRITTEN_KEY: usize = Nonce::len() + KeyID::len();
|
||||||
|
out[Nonce::len()..WRITTEN_KEY]
|
||||||
|
.copy_from_slice(&self.client_key_id.0.to_le_bytes());
|
||||||
|
const WRITTEN: usize = WRITTEN_KEY;
|
||||||
|
const WRITTEN_ID: usize = WRITTEN + 8;
|
||||||
|
out[WRITTEN..WRITTEN_ID]
|
||||||
|
.copy_from_slice(&self.id.as_u64().to_le_bytes());
|
||||||
|
self.auth.serialize(&mut out[WRITTEN_ID..]);
|
||||||
|
}
|
||||||
/// Parse the cleartext raw data
|
/// Parse the cleartext raw data
|
||||||
pub fn deserialize(raw: &[u8]) -> Result<Self, Error> {
|
pub fn deserialize(raw: &[u8]) -> Result<Self, Error> {
|
||||||
if raw.len() < Self::MIN_PKT_LEN {
|
if raw.len() < Self::MIN_PKT_LEN {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
//! Handhsake handling
|
//! Handhsake handling
|
||||||
|
|
||||||
pub mod dirsync;
|
pub mod dirsync;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
auth::ServiceID,
|
auth::ServiceID,
|
||||||
|
@ -194,7 +196,7 @@ impl HandshakeData {
|
||||||
/// Kind of handshake
|
/// Kind of handshake
|
||||||
#[derive(::num_derive::FromPrimitive, Debug, Clone, Copy)]
|
#[derive(::num_derive::FromPrimitive, Debug, Clone, Copy)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum Kind {
|
pub enum HandshakeKind {
|
||||||
/// 1-RTT, Directory synchronized handshake
|
/// 1-RTT, Directory synchronized handshake
|
||||||
/// Request
|
/// Request
|
||||||
DirSyncReq = 0,
|
DirSyncReq = 0,
|
||||||
|
@ -210,6 +212,12 @@ pub enum Kind {
|
||||||
....
|
....
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
impl HandshakeKind {
|
||||||
|
/// Length of the serialized field
|
||||||
|
pub const fn len() -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parsed handshake
|
/// Parsed handshake
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -230,7 +238,7 @@ impl Handshake {
|
||||||
}
|
}
|
||||||
/// return the total length of the handshake
|
/// return the total length of the handshake
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
ProtocolVersion::len() + self.data.len()
|
ProtocolVersion::len() + HandshakeKind::len() + self.data.len()
|
||||||
}
|
}
|
||||||
const MIN_PKT_LEN: usize = 8;
|
const MIN_PKT_LEN: usize = 8;
|
||||||
/// Parse the packet and return the parsed handshake
|
/// Parse the packet and return the parsed handshake
|
||||||
|
@ -242,13 +250,15 @@ impl Handshake {
|
||||||
Some(fenrir_version) => fenrir_version,
|
Some(fenrir_version) => fenrir_version,
|
||||||
None => return Err(Error::Parsing),
|
None => return Err(Error::Parsing),
|
||||||
};
|
};
|
||||||
let handshake_kind = match Kind::from_u8(raw[1]) {
|
let handshake_kind = match HandshakeKind::from_u8(raw[1]) {
|
||||||
Some(handshake_kind) => handshake_kind,
|
Some(handshake_kind) => handshake_kind,
|
||||||
None => return Err(Error::Parsing),
|
None => return Err(Error::Parsing),
|
||||||
};
|
};
|
||||||
let data = match handshake_kind {
|
let data = match handshake_kind {
|
||||||
Kind::DirSyncReq => dirsync::Req::deserialize(&raw[2..])?,
|
HandshakeKind::DirSyncReq => dirsync::Req::deserialize(&raw[2..])?,
|
||||||
Kind::DirSyncResp => dirsync::Resp::deserialize(&raw[2..])?,
|
HandshakeKind::DirSyncResp => {
|
||||||
|
dirsync::Resp::deserialize(&raw[2..])?
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
fenrir_version,
|
fenrir_version,
|
||||||
|
@ -263,9 +273,14 @@ impl Handshake {
|
||||||
tag_len: TagLen,
|
tag_len: TagLen,
|
||||||
out: &mut [u8],
|
out: &mut [u8],
|
||||||
) {
|
) {
|
||||||
assert!(out.len() > 1, "Handshake: not enough buffer to serialize");
|
out[0] = self.fenrir_version as u8;
|
||||||
self.fenrir_version.serialize(&mut out[0]);
|
out[1] = match &self.data {
|
||||||
self.data.serialize(head_len, tag_len, &mut out[1..]);
|
HandshakeData::DirSync(d) => match d {
|
||||||
|
dirsync::DirSync::Req(_) => HandshakeKind::DirSyncReq,
|
||||||
|
dirsync::DirSync::Resp(_) => HandshakeKind::DirSyncResp,
|
||||||
|
},
|
||||||
|
} as u8;
|
||||||
|
self.data.serialize(head_len, tag_len, &mut out[2..]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
use crate::{
|
||||||
|
auth,
|
||||||
|
connection::{handshake::*, ID},
|
||||||
|
enc,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_handshake_dirsync_req() {
|
||||||
|
let rand = enc::Random::new();
|
||||||
|
let secret = enc::Secret::new_rand(&rand);
|
||||||
|
let cipher_send = enc::sym::CipherSend::new(
|
||||||
|
enc::sym::CipherKind::XChaCha20Poly1305,
|
||||||
|
secret,
|
||||||
|
&rand,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (_, exchange_key) =
|
||||||
|
match enc::asym::KeyExchangeKind::X25519DiffieHellman.new_keypair(&rand)
|
||||||
|
{
|
||||||
|
Ok(pair) => pair,
|
||||||
|
Err(_) => {
|
||||||
|
assert!(false, "Can't generate random keypair");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let data = dirsync::ReqInner::ClearText(dirsync::ReqData {
|
||||||
|
nonce: dirsync::Nonce::new(&rand),
|
||||||
|
client_key_id: KeyID(2424),
|
||||||
|
id: ID::ID(::core::num::NonZeroU64::new(424242).unwrap()),
|
||||||
|
auth: dirsync::AuthInfo {
|
||||||
|
user: auth::UserID::new(&rand),
|
||||||
|
token: auth::Token::new_anonymous(&rand),
|
||||||
|
service_id: auth::SERVICEID_AUTH,
|
||||||
|
domain: auth::Domain("example.com".to_owned()),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let h_req = Handshake::new(HandshakeData::DirSync(dirsync::DirSync::Req(
|
||||||
|
dirsync::Req {
|
||||||
|
key_id: KeyID(4224),
|
||||||
|
exchange: enc::asym::KeyExchangeKind::X25519DiffieHellman,
|
||||||
|
hkdf: enc::hkdf::HkdfKind::Sha3,
|
||||||
|
cipher: enc::sym::CipherKind::XChaCha20Poly1305,
|
||||||
|
exchange_key,
|
||||||
|
data,
|
||||||
|
},
|
||||||
|
)));
|
||||||
|
|
||||||
|
let mut bytes = Vec::<u8>::with_capacity(h_req.len());
|
||||||
|
bytes.resize(h_req.len(), 0);
|
||||||
|
h_req.serialize(
|
||||||
|
cipher_send.kind().nonce_len(),
|
||||||
|
cipher_send.kind().tag_len(),
|
||||||
|
&mut bytes,
|
||||||
|
);
|
||||||
|
|
||||||
|
let deserialized = match Handshake::deserialize(&bytes) {
|
||||||
|
Ok(deserialized) => deserialized,
|
||||||
|
Err(e) => {
|
||||||
|
assert!(false, "{}", e.to_string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -152,34 +152,56 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialization() {
|
fn test_serialization() {
|
||||||
// The record was generated with:
|
let rand = enc::Random::new();
|
||||||
// f-dnssec generate dnssec \
|
let (_, exchange_key) =
|
||||||
// -a 1 2 42 directory_synchronized 127.0.0.1 31337 \
|
match enc::asym::KeyExchangeKind::X25519DiffieHellman
|
||||||
// -p 42 x25519 x25519.pub \
|
.new_keypair(&rand)
|
||||||
// -x x25519diffiehellman \
|
{
|
||||||
// -c xchacha20poly1305
|
Ok(pair) => pair,
|
||||||
const TXT_RECORD: &'static str = "v=Fenrir1 \
|
Err(_) => {
|
||||||
5fBgo5ovk=0Dk}g0V)6>0cKP8KO-Vna846zp@MaLF|nim_XH&nQvT-I|B9HfJpcd";
|
assert!(false, "Can't generate random keypair");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
use crate::enc;
|
||||||
|
let record = Record {
|
||||||
|
public_keys : [(enc::asym::KeyID(42),
|
||||||
|
enc::asym::PubKey::Exchange(exchange_key))].to_vec(),
|
||||||
|
addresses: [record::Address {
|
||||||
|
ip: ::std::net::IpAddr::V4(::std::net::Ipv4Addr::new(127,0,0,1)),
|
||||||
|
port: Some(::core::num::NonZeroU16::new(31337).unwrap()),
|
||||||
|
priority: record::AddressPriority::P1,
|
||||||
|
weight: record::AddressWeight::W1,
|
||||||
|
handshake_ids: [crate::connection::handshake::HandshakeID::DirectorySynchronized].to_vec(),
|
||||||
|
public_key_idx : [record::PubKeyIdx(0)].to_vec(),
|
||||||
|
|
||||||
let record = match Dnssec::parse_txt_record(TXT_RECORD) {
|
}].to_vec(),
|
||||||
|
key_exchanges: [enc::asym::KeyExchangeKind::X25519DiffieHellman].to_vec(),
|
||||||
|
hkdfs: [enc::hkdf::HkdfKind::Sha3].to_vec(),
|
||||||
|
ciphers: [enc::sym::CipherKind::XChaCha20Poly1305].to_vec(),
|
||||||
|
|
||||||
|
};
|
||||||
|
let encoded = match record.encode() {
|
||||||
|
Ok(encoded) => encoded,
|
||||||
|
Err(e) => {
|
||||||
|
assert!(false, "{}", e.to_string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let full_record = "v=Fenrir1 ".to_string() + &encoded;
|
||||||
|
let record = match Dnssec::parse_txt_record(&full_record) {
|
||||||
Ok(record) => record,
|
Ok(record) => record,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
assert!(false, "{}", e.to_string());
|
assert!(false, "{}", e.to_string());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let re_encoded = match record.encode() {
|
let _re_encoded = match record.encode() {
|
||||||
Ok(re_encoded) => re_encoded,
|
Ok(re_encoded) => re_encoded,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
assert!(false, "{}", e.to_string());
|
assert!(false, "{}", e.to_string());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
assert!(
|
|
||||||
TXT_RECORD[10..] == re_encoded,
|
|
||||||
"DNSSEC record decoding->encoding failed:\n{}\n{}",
|
|
||||||
TXT_RECORD,
|
|
||||||
re_encoded
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -429,7 +429,7 @@ impl Record {
|
||||||
+ self
|
+ self
|
||||||
.public_keys
|
.public_keys
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(_, key)| 4 + key.kind().pub_len())
|
.map(|(_, key)| 3 + key.kind().pub_len())
|
||||||
.sum::<usize>()
|
.sum::<usize>()
|
||||||
+ self.key_exchanges.len()
|
+ self.key_exchanges.len()
|
||||||
+ self.hkdfs.len()
|
+ self.hkdfs.len()
|
||||||
|
@ -463,7 +463,7 @@ impl Record {
|
||||||
let written_next = written + KeyID::len();
|
let written_next = written + KeyID::len();
|
||||||
raw[written..written_next].copy_from_slice(&key_id_bytes);
|
raw[written..written_next].copy_from_slice(&key_id_bytes);
|
||||||
written = written_next;
|
written = written_next;
|
||||||
raw[written] = public_key.kind().pub_len() as u8;
|
raw[written] = public_key.len() as u8;
|
||||||
written = written + 1;
|
written = written + 1;
|
||||||
let written_next = written + public_key.len();
|
let written_next = written + public_key.len();
|
||||||
public_key.serialize_into(&mut raw[written..written_next]);
|
public_key.serialize_into(&mut raw[written..written_next]);
|
||||||
|
@ -531,10 +531,10 @@ impl Record {
|
||||||
let raw_key_id =
|
let raw_key_id =
|
||||||
u16::from_le_bytes([raw[bytes_parsed], raw[bytes_parsed + 1]]);
|
u16::from_le_bytes([raw[bytes_parsed], raw[bytes_parsed + 1]]);
|
||||||
let id = KeyID(raw_key_id);
|
let id = KeyID(raw_key_id);
|
||||||
bytes_parsed = bytes_parsed + 2;
|
bytes_parsed = bytes_parsed + KeyID::len();
|
||||||
let pubkey_length = raw[bytes_parsed] as usize;
|
let pubkey_length = raw[bytes_parsed] as usize;
|
||||||
bytes_parsed = bytes_parsed + 1;
|
bytes_parsed = bytes_parsed + 1;
|
||||||
let bytes_next_key = bytes_parsed + 1 + pubkey_length;
|
let bytes_next_key = bytes_parsed + pubkey_length;
|
||||||
if bytes_next_key > raw.len() {
|
if bytes_next_key > raw.len() {
|
||||||
return Err(Error::NotEnoughData(bytes_parsed));
|
return Err(Error::NotEnoughData(bytes_parsed));
|
||||||
}
|
}
|
||||||
|
@ -551,7 +551,7 @@ impl Record {
|
||||||
return Err(Error::UnsupportedData(bytes_parsed));
|
return Err(Error::UnsupportedData(bytes_parsed));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if bytes != 1 + pubkey_length {
|
if bytes != pubkey_length {
|
||||||
return Err(Error::UnsupportedData(bytes_parsed));
|
return Err(Error::UnsupportedData(bytes_parsed));
|
||||||
}
|
}
|
||||||
bytes_parsed = bytes_parsed + bytes;
|
bytes_parsed = bytes_parsed + bytes;
|
||||||
|
|
|
@ -93,16 +93,19 @@ pub enum KeyKind {
|
||||||
#[strum(serialize = "x25519")]
|
#[strum(serialize = "x25519")]
|
||||||
X25519,
|
X25519,
|
||||||
}
|
}
|
||||||
// FIXME: actually check this
|
|
||||||
const MIN_KEY_SIZE: usize = 32;
|
|
||||||
impl KeyKind {
|
impl KeyKind {
|
||||||
|
/// Length of the serialized field
|
||||||
|
pub const fn len() -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
/// return the expected length of the public key
|
/// return the expected length of the public key
|
||||||
pub fn pub_len(&self) -> usize {
|
pub fn pub_len(&self) -> usize {
|
||||||
match self {
|
KeyKind::len()
|
||||||
// FIXME: 99% wrong size
|
+ match self {
|
||||||
KeyKind::Ed25519 => ::ring::signature::ED25519_PUBLIC_KEY_LEN,
|
// FIXME: 99% wrong size
|
||||||
KeyKind::X25519 => 32,
|
KeyKind::Ed25519 => ::ring::signature::ED25519_PUBLIC_KEY_LEN,
|
||||||
}
|
KeyKind::X25519 => 32,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/// Get the capabilities of this key type
|
/// Get the capabilities of this key type
|
||||||
pub fn capabilities(&self) -> KeyCapabilities {
|
pub fn capabilities(&self) -> KeyCapabilities {
|
||||||
|
@ -185,7 +188,7 @@ pub enum PubKey {
|
||||||
impl PubKey {
|
impl PubKey {
|
||||||
/// Get the serialized key length
|
/// Get the serialized key length
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
1 + match self {
|
match self {
|
||||||
PubKey::Exchange(ex) => ex.len(),
|
PubKey::Exchange(ex) => ex.len(),
|
||||||
PubKey::Signing => todo!(),
|
PubKey::Signing => todo!(),
|
||||||
}
|
}
|
||||||
|
@ -215,17 +218,12 @@ impl PubKey {
|
||||||
/// serialize the key into the buffer
|
/// serialize the key into the buffer
|
||||||
/// NOTE: Assumes there is enough space
|
/// NOTE: Assumes there is enough space
|
||||||
pub fn serialize_into(&self, out: &mut [u8]) {
|
pub fn serialize_into(&self, out: &mut [u8]) {
|
||||||
assert!(
|
|
||||||
out.len() >= 1 + self.kind().pub_len(),
|
|
||||||
"Not enough out buffer",
|
|
||||||
);
|
|
||||||
out[0] = self.kind() as u8;
|
|
||||||
match self {
|
match self {
|
||||||
PubKey::Signing => {
|
PubKey::Signing => {
|
||||||
::tracing::error!("serializing ed25519 not supported");
|
::tracing::error!("serializing ed25519 not supported");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PubKey::Exchange(ex) => ex.serialize_into(&mut out[1..]),
|
PubKey::Exchange(ex) => ex.serialize_into(out),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Try to deserialize the pubkey from raw bytes
|
/// Try to deserialize the pubkey from raw bytes
|
||||||
|
@ -238,7 +236,7 @@ impl PubKey {
|
||||||
Some(kind) => kind,
|
Some(kind) => kind,
|
||||||
None => return Err(Error::UnsupportedKey(1)),
|
None => return Err(Error::UnsupportedKey(1)),
|
||||||
};
|
};
|
||||||
if raw.len() < 1 + kind.pub_len() {
|
if raw.len() < kind.pub_len() {
|
||||||
return Err(Error::NotEnoughData(1));
|
return Err(Error::NotEnoughData(1));
|
||||||
}
|
}
|
||||||
match kind {
|
match kind {
|
||||||
|
@ -259,7 +257,7 @@ impl PubKey {
|
||||||
};
|
};
|
||||||
Ok((
|
Ok((
|
||||||
PubKey::Exchange(ExchangePubKey::X25519(pub_key)),
|
PubKey::Exchange(ExchangePubKey::X25519(pub_key)),
|
||||||
1 + kind.pub_len(),
|
kind.pub_len(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -281,7 +279,7 @@ pub enum PrivKey {
|
||||||
impl PrivKey {
|
impl PrivKey {
|
||||||
/// Get the serialized key length
|
/// Get the serialized key length
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
1 + match self {
|
match self {
|
||||||
PrivKey::Exchange(ex) => ex.len(),
|
PrivKey::Exchange(ex) => ex.len(),
|
||||||
PrivKey::Signing => todo!(),
|
PrivKey::Signing => todo!(),
|
||||||
}
|
}
|
||||||
|
@ -296,9 +294,8 @@ impl PrivKey {
|
||||||
/// serialize the key into the buffer
|
/// serialize the key into the buffer
|
||||||
/// NOTE: Assumes there is enough space
|
/// NOTE: Assumes there is enough space
|
||||||
pub fn serialize_into(&self, out: &mut [u8]) {
|
pub fn serialize_into(&self, out: &mut [u8]) {
|
||||||
out[0] = self.kind() as u8;
|
|
||||||
match self {
|
match self {
|
||||||
PrivKey::Exchange(ex) => ex.serialize_into(&mut out[1..]),
|
PrivKey::Exchange(ex) => ex.serialize_into(out),
|
||||||
PrivKey::Signing => todo!(),
|
PrivKey::Signing => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -346,9 +343,10 @@ impl ExchangePrivKey {
|
||||||
/// serialize the key into the buffer
|
/// serialize the key into the buffer
|
||||||
/// NOTE: Assumes there is enough space
|
/// NOTE: Assumes there is enough space
|
||||||
pub fn serialize_into(&self, out: &mut [u8]) {
|
pub fn serialize_into(&self, out: &mut [u8]) {
|
||||||
|
out[0] = self.kind() as u8;
|
||||||
match self {
|
match self {
|
||||||
ExchangePrivKey::X25519(key) => {
|
ExchangePrivKey::X25519(key) => {
|
||||||
out[0..32].copy_from_slice(&key.to_bytes());
|
out[1..33].copy_from_slice(&key.to_bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -378,21 +376,18 @@ impl ExchangePubKey {
|
||||||
/// serialize the key into the buffer
|
/// serialize the key into the buffer
|
||||||
/// NOTE: Assumes there is enough space
|
/// NOTE: Assumes there is enough space
|
||||||
pub fn serialize_into(&self, out: &mut [u8]) {
|
pub fn serialize_into(&self, out: &mut [u8]) {
|
||||||
|
out[0] = self.kind() as u8;
|
||||||
match self {
|
match self {
|
||||||
ExchangePubKey::X25519(pk) => {
|
ExchangePubKey::X25519(pk) => {
|
||||||
let bytes = pk.as_bytes();
|
let bytes = pk.as_bytes();
|
||||||
assert!(bytes.len() == 32, "x25519 should have been 32 bytes");
|
out[1..33].copy_from_slice(bytes);
|
||||||
out[..32].copy_from_slice(bytes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Load public key used for key exchange from it raw bytes
|
/// Load public key used for key exchange from it raw bytes
|
||||||
/// The riesult is "unparsed" since we don't verify
|
/// The riesult is "unparsed" since we don't verify
|
||||||
/// the actual key
|
/// the actual key
|
||||||
pub fn from_slice(raw: &[u8]) -> Result<(Self, usize), Error> {
|
pub fn deserialize(raw: &[u8]) -> Result<(Self, usize), Error> {
|
||||||
if raw.len() < 1 + MIN_KEY_SIZE {
|
|
||||||
return Err(Error::NotEnoughData(0));
|
|
||||||
}
|
|
||||||
match KeyKind::from_u8(raw[0]) {
|
match KeyKind::from_u8(raw[0]) {
|
||||||
Some(kind) => match kind {
|
Some(kind) => match kind {
|
||||||
KeyKind::Ed25519 => {
|
KeyKind::Ed25519 => {
|
||||||
|
|
Loading…
Reference in New Issue