use crate::{
Buf,
BufError::{self},
BufMut, BufResult, Codec, Cursor,
ietf::tls::{LengthPrefix, ProtocolVersion, TlsVec, u24},
ietf::tls1_3::Extension,
};
use ring::rand::{SecureRandom, SystemRandom};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum HandshakeType {
ClientHello = 1,
ServerHello = 2,
NewSessionTicket = 4,
EndOfEarlyData = 5,
EncryptedExtensions = 8,
Certificate = 11,
CertificateRequest = 13,
CertificateVerify = 15,
Finished = 20,
KeyUpdate = 24,
MessageHash = 254,
}
impl Codec for HandshakeType {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
(*self as u8).encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
match u8::decode(reader, ())? {
x if x == (Self::ClientHello as u8) => Ok(Self::ClientHello),
x if x == (Self::ServerHello as u8) => Ok(Self::ServerHello),
x if x == (Self::NewSessionTicket as u8) => Ok(Self::NewSessionTicket),
x if x == (Self::EndOfEarlyData as u8) => Ok(Self::EndOfEarlyData),
x if x == (Self::EncryptedExtensions as u8) => Ok(Self::EncryptedExtensions),
x if x == (Self::Certificate as u8) => Ok(Self::Certificate),
x if x == (Self::CertificateRequest as u8) => Ok(Self::CertificateRequest),
x if x == (Self::CertificateVerify as u8) => Ok(Self::CertificateVerify),
x if x == (Self::Finished as u8) => Ok(Self::Finished),
x if x == (Self::KeyUpdate as u8) => Ok(Self::KeyUpdate),
x if x == (Self::MessageHash as u8) => Ok(Self::MessageHash),
_ => Err(BufError::UnexpectedValue),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Handshake {
pub msg_type: HandshakeType,
pub msg: Vec<u8>,
}
impl Codec for Handshake {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.msg_type.encode(writer, ())?;
let len = u24::from_usize(self.msg.len())?;
len.encode(writer, ())?;
writer.write_slice(&self.msg)
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let msg_type = HandshakeType::decode(reader, ())?;
let length_u24 = u24::decode(reader, ())?;
let length = length_u24.as_usize();
if reader.remaining() < length {
return Err(BufError::UnexpectedEof);
}
let mut msg = vec![0u8; length];
reader.read_into(&mut msg)?;
Ok(Self { msg_type, msg })
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u16)]
pub enum CipherSuite {
TlsAes128GcmSha256 = 0x1301,
TlsAes256GcmSha384 = 0x1302,
TlsChacha20Poly1305Sha256 = 0x1303,
TlsAes128CcmSha256 = 0x1304,
TlsAes128Ccm8Sha256 = 0x1305,
TlsEmptyRenegotiationInfoScsv = 0x00FF,
}
impl Codec for CipherSuite {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
(*self as u16).encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
match u16::decode(reader, ())? {
x if x == (Self::TlsAes128GcmSha256 as u16) => Ok(Self::TlsAes128GcmSha256),
x if x == (Self::TlsAes256GcmSha384 as u16) => Ok(Self::TlsAes256GcmSha384),
x if x == (Self::TlsChacha20Poly1305Sha256 as u16) => {
Ok(Self::TlsChacha20Poly1305Sha256)
}
x if x == (Self::TlsAes128CcmSha256 as u16) => Ok(Self::TlsAes128CcmSha256),
x if x == (Self::TlsAes128Ccm8Sha256 as u16) => Ok(Self::TlsAes128Ccm8Sha256),
x if x == (Self::TlsEmptyRenegotiationInfoScsv as u16) => {
Ok(Self::TlsEmptyRenegotiationInfoScsv)
}
_ => Err(BufError::UnexpectedValue),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Random(pub [u8; 32]);
impl Random {
pub fn random() -> Self {
let mut random = [0u8; 32];
let rng = SystemRandom::new();
rng.fill(&mut random).unwrap();
Self(random)
}
}
impl Codec for Random {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
writer.write_array(&self.0)
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self(reader.read_array::<32>()?))
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ClientHello {
pub legacy_version: ProtocolVersion,
pub random: Random,
pub legacy_session_id: TlsVec<u8, u8>,
pub cipher_suites: TlsVec<CipherSuite, u16>,
pub legacy_compression_methods: TlsVec<u8, u8>,
pub extensions: TlsVec<Extension, u16>,
}
impl ClientHello {
pub fn default(extensions: TlsVec<Extension, u16>) -> Self {
Self {
legacy_version: ProtocolVersion::TLS12,
random: Random::random(),
legacy_session_id: TlsVec::new(vec![]),
cipher_suites: TlsVec::new(vec![
CipherSuite::TlsAes128GcmSha256,
CipherSuite::TlsChacha20Poly1305Sha256,
]),
legacy_compression_methods: TlsVec::new(vec![0x00]),
extensions,
}
}
}
impl Codec for ClientHello {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.legacy_version.encode(writer, ())?;
self.random.encode(writer, ())?;
self.legacy_session_id.encode(writer, ())?;
self.cipher_suites.encode(writer, ())?;
self.legacy_compression_methods.encode(writer, ())?;
self.extensions.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self {
legacy_version: ProtocolVersion::decode(reader, ())?,
random: Random::decode(reader, ())?,
legacy_session_id: TlsVec::<u8, u8>::decode(reader, ())?,
cipher_suites: TlsVec::<CipherSuite, u16>::decode(reader, ())?,
legacy_compression_methods: TlsVec::<u8, u8>::decode(reader, ())?,
extensions: TlsVec::<Extension, u16>::decode(reader, ())?,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ServerHello {
pub legacy_version: ProtocolVersion,
pub random: Random,
pub legacy_session_id_echo: TlsVec<u8, u8>,
pub cipher_suite: CipherSuite,
pub legacy_compression_method: u8,
pub extensions: TlsVec<Extension, u16>,
}
impl Codec for ServerHello {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.legacy_version.encode(writer, ())?;
self.random.encode(writer, ())?;
self.legacy_session_id_echo.encode(writer, ())?;
self.cipher_suite.encode(writer, ())?;
self.legacy_compression_method.encode(writer, ())?;
self.extensions.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self {
legacy_version: ProtocolVersion::decode(reader, ())?,
random: Random::decode(reader, ())?,
legacy_session_id_echo: TlsVec::<u8, u8>::decode(reader, ())?,
cipher_suite: CipherSuite::decode(reader, ())?,
legacy_compression_method: u8::decode(reader, ())?,
extensions: TlsVec::<Extension, u16>::decode(reader, ())?,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct NewSessionTicket {
pub ticket_lifetime: u32,
pub ticket_age_add: u32,
pub ticket_nonce: TlsVec<u8, u8>,
pub ticket: TlsVec<u8, u16>,
pub extensions: TlsVec<Extension, u16>,
}
impl Codec for NewSessionTicket {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.ticket_lifetime.encode(writer, ())?;
self.ticket_age_add.encode(writer, ())?;
self.ticket_nonce.encode(writer, ())?;
self.ticket.encode(writer, ())?;
self.extensions.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self {
ticket_lifetime: u32::decode(reader, ())?,
ticket_age_add: u32::decode(reader, ())?,
ticket_nonce: TlsVec::<u8, u8>::decode(reader, ())?,
ticket: TlsVec::<u8, u16>::decode(reader, ())?,
extensions: TlsVec::<Extension, u16>::decode(reader, ())?,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EndOfEarlyData;
impl Codec for EndOfEarlyData {
fn encode<W: BufMut>(&self, _writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Ok(())
}
fn decode<R: Buf>(_reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EncryptedExtensions {
pub extensions: TlsVec<Extension, u16>,
}
impl Codec for EncryptedExtensions {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.extensions.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self {
extensions: TlsVec::<Extension, u16>::decode(reader, ())?,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SignatureScheme(pub u16);
impl SignatureScheme {
pub const RSA_PKCS1_SHA256: Self = Self(0x0401);
pub const ECDSA_SECP256R1_SHA256: Self = Self(0x0403);
pub const ECDSA_SECP384R1_SHA384: Self = Self(0x0503);
pub const RSA_PSS_RSAE_SHA256: Self = Self(0x0804);
pub const RSA_PSS_RSAE_SHA384: Self = Self(0x0805);
pub const ED25519: Self = Self(0x0807);
}
impl Codec for SignatureScheme {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.0.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self(u16::decode(reader, ())?))
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CertificateEntry {
pub cert_data: TlsVec<u8, u24>,
pub extensions: TlsVec<Extension, u16>,
}
impl Codec for CertificateEntry {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.cert_data.encode(writer, ())?;
self.extensions.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self {
cert_data: TlsVec::<u8, u24>::decode(reader, ())?,
extensions: TlsVec::<Extension, u16>::decode(reader, ())?,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Certificate {
pub certificate_request_context: TlsVec<u8, u8>,
pub certificate_list: TlsVec<CertificateEntry, u24>,
}
impl Codec for Certificate {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.certificate_request_context.encode(writer, ())?;
self.certificate_list.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self {
certificate_request_context: TlsVec::<u8, u8>::decode(reader, ())?,
certificate_list: TlsVec::<CertificateEntry, u24>::decode(reader, ())?,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CertificateRequest {
pub certificate_request_context: TlsVec<u8, u8>,
pub extensions: TlsVec<Extension, u16>,
}
impl Codec for CertificateRequest {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.certificate_request_context.encode(writer, ())?;
self.extensions.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self {
certificate_request_context: TlsVec::<u8, u8>::decode(reader, ())?,
extensions: TlsVec::<Extension, u16>::decode(reader, ())?,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CertificateVerify {
pub algorithm: SignatureScheme,
pub signature: TlsVec<u8, u16>,
}
impl Codec for CertificateVerify {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.algorithm.encode(writer, ())?;
self.signature.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self {
algorithm: SignatureScheme::decode(reader, ())?,
signature: TlsVec::<u8, u16>::decode(reader, ())?,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Finished {
pub verify_data: Vec<u8>,
}
impl Codec for Finished {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.verify_data.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self {
verify_data: Vec::<u8>::decode(reader, ())?,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum KeyUpdateRequest {
UpdateNotRequested = 0,
UpdateRequested = 1,
}
impl Codec for KeyUpdateRequest {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
(*self as u8).encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
match u8::decode(reader, ())? {
x if x == (Self::UpdateNotRequested as u8) => Ok(Self::UpdateNotRequested),
x if x == (Self::UpdateRequested as u8) => Ok(Self::UpdateRequested),
_ => Err(BufError::UnexpectedValue),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct KeyUpdate {
pub request_update: KeyUpdateRequest,
}
impl Codec for KeyUpdate {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.request_update.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self {
request_update: KeyUpdateRequest::decode(reader, ())?,
})
}
}
#[cfg(test)]
mod tests {
use core::fmt::Debug;
use super::{CipherSuite, HandshakeType, KeyUpdateRequest};
use crate::{Codec, Cursor};
fn codec_roundtrip<T: Codec<C> + Debug + Eq, C: Copy>(
etalon_struct: T,
etalon_bytes: &[u8],
context: C,
) {
let mut encoded_bytes = vec![];
{
let writer = &mut Cursor::new(&mut encoded_bytes);
etalon_struct.encode(writer, context).unwrap();
}
assert_eq!(etalon_bytes, &encoded_bytes);
let decoded_struct = {
let reader = &mut Cursor::new(&mut encoded_bytes);
T::decode(reader, context).unwrap()
};
assert_eq!(etalon_struct, decoded_struct);
encoded_bytes.fill(0x00);
{
let writer = &mut Cursor::new(&mut encoded_bytes);
decoded_struct.encode(writer, context).unwrap();
}
assert_eq!(etalon_bytes, &encoded_bytes);
}
#[test]
fn handshake_type() {
let etalon_bytes = &[0x01];
let etalon_struct = HandshakeType::ClientHello;
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn cipher_suite() {
let etalon_bytes = &[0x13, 0x01];
let etalon_struct = CipherSuite::TlsAes128GcmSha256;
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn key_update_request() {
let etalon_bytes = &[0x01];
let etalon_struct = KeyUpdateRequest::UpdateRequested;
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
}