This commit is contained in:
2026-02-21 08:05:44 +00:00
commit af63ad4870
75 changed files with 11874 additions and 0 deletions

39
src/handshake/binder.rs Normal file
View File

@@ -0,0 +1,39 @@
use crate::ProtocolError;
use crate::buffer::CryptoBuffer;
use core::fmt::{Debug, Formatter};
//use digest::generic_array::{ArrayLength, GenericArray};
use generic_array::{ArrayLength, GenericArray};
// use heapless::Vec;
pub struct PskBinder<N: ArrayLength<u8>> {
pub verify: GenericArray<u8, N>,
}
#[cfg(feature = "defmt")]
impl<N: ArrayLength<u8>> defmt::Format for PskBinder<N> {
fn format(&self, f: defmt::Formatter<'_>) {
defmt::write!(f, "verify length:{}", &self.verify.len());
}
}
impl<N: ArrayLength<u8>> Debug for PskBinder<N> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("PskBinder").finish()
}
}
impl<N: ArrayLength<u8>> PskBinder<N> {
pub(crate) fn encode(&self, buf: &mut CryptoBuffer<'_>) -> Result<(), ProtocolError> {
let len = self.verify.len() as u8;
//buf.extend_from_slice(&[len[1], len[2], len[3]]);
buf.push(len).map_err(|_| ProtocolError::EncodeError)?;
buf.extend_from_slice(&self.verify[..self.verify.len()])
.map_err(|_| ProtocolError::EncodeError)?;
Ok(())
}
#[allow(dead_code)]
pub fn len() -> usize {
N::to_usize()
}
}

View File

@@ -0,0 +1,174 @@
use crate::ProtocolError;
use crate::buffer::CryptoBuffer;
use crate::extensions::messages::CertificateExtension;
use crate::parse_buffer::ParseBuffer;
use heapless::Vec;
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CertificateRef<'a> {
raw_entries: &'a [u8],
request_context: &'a [u8],
pub entries: Vec<CertificateEntryRef<'a>, 16>,
}
impl<'a> CertificateRef<'a> {
pub fn with_context(request_context: &'a [u8]) -> Self {
Self {
raw_entries: &[],
request_context,
entries: Vec::new(),
}
}
pub fn add(&mut self, entry: CertificateEntryRef<'a>) -> Result<(), ProtocolError> {
self.entries.push(entry).map_err(|_| {
error!("CertificateRef: InsufficientSpace");
ProtocolError::InsufficientSpace
})
}
pub fn parse(buf: &mut ParseBuffer<'a>) -> Result<Self, ProtocolError> {
let request_context_len = buf.read_u8().map_err(|_| ProtocolError::InvalidCertificate)?;
let request_context = buf
.slice(request_context_len as usize)
.map_err(|_| ProtocolError::InvalidCertificate)?;
let entries_len = buf.read_u24().map_err(|_| ProtocolError::InvalidCertificate)?;
let mut raw_entries = buf
.slice(entries_len as usize)
.map_err(|_| ProtocolError::InvalidCertificate)?;
let entries = CertificateEntryRef::parse_vector(&mut raw_entries)?;
Ok(Self {
raw_entries: raw_entries.as_slice(),
request_context: request_context.as_slice(),
entries,
})
}
pub(crate) fn encode(&self, buf: &mut CryptoBuffer<'_>) -> Result<(), ProtocolError> {
buf.with_u8_length(|buf| buf.extend_from_slice(self.request_context))?;
buf.with_u24_length(|buf| {
for entry in &self.entries {
entry.encode(buf)?;
}
Ok(())
})?;
Ok(())
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CertificateEntryRef<'a> {
X509(&'a [u8]),
RawPublicKey(&'a [u8]),
}
impl<'a> CertificateEntryRef<'a> {
pub fn parse(buf: &mut ParseBuffer<'a>) -> Result<Self, ProtocolError> {
let entry_len = buf
.read_u24()
.map_err(|_| ProtocolError::InvalidCertificateEntry)?;
let cert = buf
.slice(entry_len as usize)
.map_err(|_| ProtocolError::InvalidCertificateEntry)?;
let entry = CertificateEntryRef::X509(cert.as_slice());
// Validate extensions
CertificateExtension::parse_vector::<2>(buf)?;
Ok(entry)
}
pub fn parse_vector<const N: usize>(
buf: &mut ParseBuffer<'a>,
) -> Result<Vec<Self, N>, ProtocolError> {
let mut result = Vec::new();
while !buf.is_empty() {
result
.push(Self::parse(buf)?)
.map_err(|_| ProtocolError::DecodeError)?;
}
Ok(result)
}
pub(crate) fn encode(&self, buf: &mut CryptoBuffer<'_>) -> Result<(), ProtocolError> {
match *self {
CertificateEntryRef::RawPublicKey(_key) => {
todo!("ASN1_subjectPublicKeyInfo encoding?");
// buf.with_u24_length(|buf| buf.extend_from_slice(key))?;
}
CertificateEntryRef::X509(cert) => {
buf.with_u24_length(|buf| buf.extend_from_slice(cert))?;
}
}
// Zero extensions for now
buf.push_u16(0)?;
Ok(())
}
}
impl<'a, D: AsRef<[u8]>> From<&'a crate::config::Certificate<D>> for CertificateEntryRef<'a> {
fn from(cert: &'a crate::config::Certificate<D>) -> Self {
match cert {
crate::config::Certificate::X509(data) => CertificateEntryRef::X509(data.as_ref()),
crate::config::Certificate::RawPublicKey(data) => {
CertificateEntryRef::RawPublicKey(data.as_ref())
}
}
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Certificate<const N: usize> {
request_context: Vec<u8, 256>,
entries_data: Vec<u8, N>,
}
impl<const N: usize> Certificate<N> {
pub fn request_context(&self) -> &[u8] {
&self.request_context[..]
}
}
impl<'a, const N: usize> TryFrom<CertificateRef<'a>> for Certificate<N> {
type Error = ProtocolError;
fn try_from(cert: CertificateRef<'a>) -> Result<Self, Self::Error> {
let mut request_context = Vec::new();
request_context
.extend_from_slice(cert.request_context)
.map_err(|_| ProtocolError::OutOfMemory)?;
let mut entries_data = Vec::new();
entries_data
.extend_from_slice(cert.raw_entries)
.map_err(|_| ProtocolError::OutOfMemory)?;
Ok(Self {
request_context,
entries_data,
})
}
}
impl<'a, const N: usize> TryFrom<&'a Certificate<N>> for CertificateRef<'a> {
type Error = ProtocolError;
fn try_from(cert: &'a Certificate<N>) -> Result<Self, Self::Error> {
let request_context = cert.request_context();
let entries =
CertificateEntryRef::parse_vector(&mut ParseBuffer::from(&cert.entries_data[..]))?;
Ok(Self {
raw_entries: &cert.entries_data[..],
request_context,
entries,
})
}
}

View File

@@ -0,0 +1,50 @@
use crate::extensions::messages::CertificateRequestExtension;
use crate::parse_buffer::ParseBuffer;
use crate::{ProtocolError, unused};
use heapless::Vec;
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CertificateRequestRef<'a> {
pub(crate) request_context: &'a [u8],
}
impl<'a> CertificateRequestRef<'a> {
pub fn parse(buf: &mut ParseBuffer<'a>) -> Result<CertificateRequestRef<'a>, ProtocolError> {
let request_context_len = buf
.read_u8()
.map_err(|_| ProtocolError::InvalidCertificateRequest)?;
let request_context = buf
.slice(request_context_len as usize)
.map_err(|_| ProtocolError::InvalidCertificateRequest)?;
// Validate extensions
let extensions = CertificateRequestExtension::parse_vector::<6>(buf)?;
unused(extensions);
Ok(Self {
request_context: request_context.as_slice(),
})
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CertificateRequest {
pub(crate) request_context: Vec<u8, 256>,
}
impl<'a> TryFrom<CertificateRequestRef<'a>> for CertificateRequest {
type Error = ProtocolError;
fn try_from(cert: CertificateRequestRef<'a>) -> Result<Self, Self::Error> {
let mut request_context = Vec::new();
request_context
.extend_from_slice(cert.request_context)
.map_err(|_| {
error!("CertificateRequest: InsufficientSpace");
ProtocolError::InsufficientSpace
})?;
Ok(Self { request_context })
}
}

View File

@@ -0,0 +1,56 @@
use crate::ProtocolError;
use crate::extensions::extension_data::signature_algorithms::SignatureScheme;
use crate::parse_buffer::ParseBuffer;
use super::CryptoBuffer;
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct HandshakeVerifyRef<'a> {
pub signature_scheme: SignatureScheme,
pub signature: &'a [u8],
}
impl<'a> HandshakeVerifyRef<'a> {
pub fn parse(buf: &mut ParseBuffer<'a>) -> Result<HandshakeVerifyRef<'a>, ProtocolError> {
let signature_scheme =
SignatureScheme::parse(buf).map_err(|_| ProtocolError::InvalidSignatureScheme)?;
let len = buf.read_u16().map_err(|_| ProtocolError::InvalidSignature)?;
let signature = buf
.slice(len as usize)
.map_err(|_| ProtocolError::InvalidSignature)?;
Ok(Self {
signature_scheme,
signature: signature.as_slice(),
})
}
}
// Calculations for max. signature sizes:
// ecdsaSHA256 -> 6 bytes (ASN.1 structure) + 32-33 bytes (r) + 32-33 bytes (s) = 70..72 bytes
// ecdsaSHA384 -> 6 bytes (ASN.1 structure) + 48-49 bytes (r) + 48-49 bytes (s) = 102..104 bytes
// Ed25519 -> 6 bytes (ASN.1 structure) + 32-33 bytes (r) + 32-33 bytes (s) = 70..72 bytes
// RSA2048 -> 256 bytes
// RSA3072 -> 384 bytee
// RSA4096 -> 512 bytes
#[cfg(feature = "rsa")]
const SIGNATURE_SIZE: usize = 512;
#[cfg(not(feature = "rsa"))]
const SIGNATURE_SIZE: usize = 104;
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct HandshakeVerify {
pub(crate) signature_scheme: SignatureScheme,
pub(crate) signature: heapless::Vec<u8, SIGNATURE_SIZE>,
}
impl HandshakeVerify {
pub(crate) fn encode(&self, buf: &mut CryptoBuffer<'_>) -> Result<(), ProtocolError> {
buf.push_u16(self.signature_scheme.as_u16())?;
buf.with_u16_length(|buf| buf.extend_from_slice(self.signature.as_slice()))?;
Ok(())
}
}

View File

@@ -0,0 +1,188 @@
use core::marker::PhantomData;
use digest::{Digest, OutputSizeUser};
use heapless::Vec;
use p256::EncodedPoint;
use p256::ecdh::EphemeralSecret;
use p256::elliptic_curve::rand_core::RngCore;
use typenum::Unsigned;
use crate::ProtocolError;
use crate::config::{TlsCipherSuite, ConnectConfig};
use crate::extensions::extension_data::alpn::AlpnProtocolNameList;
use crate::extensions::extension_data::key_share::{KeyShareClientHello, KeyShareEntry};
use crate::extensions::extension_data::pre_shared_key::PreSharedKeyClientHello;
use crate::extensions::extension_data::psk_key_exchange_modes::{
PskKeyExchangeMode, PskKeyExchangeModes,
};
use crate::extensions::extension_data::server_name::ServerNameList;
use crate::extensions::extension_data::signature_algorithms::SignatureAlgorithms;
use crate::extensions::extension_data::supported_groups::{NamedGroup, SupportedGroups};
use crate::extensions::extension_data::supported_versions::{SupportedVersionsClientHello, TLS13};
use crate::extensions::messages::ClientHelloExtension;
use crate::handshake::{LEGACY_VERSION, Random};
use crate::key_schedule::{HashOutputSize, WriteKeySchedule};
use crate::{CryptoBackend, buffer::CryptoBuffer};
pub struct ClientHello<'config, CipherSuite>
where
CipherSuite: TlsCipherSuite,
{
pub(crate) config: &'config ConnectConfig<'config>,
random: Random,
cipher_suite: PhantomData<CipherSuite>,
pub(crate) secret: EphemeralSecret,
}
impl<'config, CipherSuite> ClientHello<'config, CipherSuite>
where
CipherSuite: TlsCipherSuite,
{
pub fn new<CP>(config: &'config ConnectConfig<'config>, mut provider: CP) -> Self
where
CP: CryptoBackend,
{
let mut random = [0; 32];
provider.rng().fill_bytes(&mut random);
Self {
config,
random,
cipher_suite: PhantomData,
secret: EphemeralSecret::random(&mut provider.rng()),
}
}
pub(crate) fn encode(&self, buf: &mut CryptoBuffer<'_>) -> Result<(), ProtocolError> {
let public_key = EncodedPoint::from(&self.secret.public_key());
let public_key = public_key.as_ref();
buf.push_u16(LEGACY_VERSION)
.map_err(|_| ProtocolError::EncodeError)?;
buf.extend_from_slice(&self.random)
.map_err(|_| ProtocolError::EncodeError)?;
// session id (empty)
buf.push(0).map_err(|_| ProtocolError::EncodeError)?;
// cipher suites (2+)
//buf.extend_from_slice(&((self.config.cipher_suites.len() * 2) as u16).to_be_bytes());
//for c in self.config.cipher_suites.iter() {
//buf.extend_from_slice(&(*c as u16).to_be_bytes());
//}
buf.push_u16(2).map_err(|_| ProtocolError::EncodeError)?;
buf.push_u16(CipherSuite::CODE_POINT)
.map_err(|_| ProtocolError::EncodeError)?;
// compression methods, 1 byte of 0
buf.push(1).map_err(|_| ProtocolError::EncodeError)?;
buf.push(0).map_err(|_| ProtocolError::EncodeError)?;
// extensions (1+)
buf.with_u16_length(|buf| {
// Section 4.2.1. Supported Versions
// Implementations of this specification MUST send this extension in the
// ClientHello containing all versions of TLS which they are prepared to
// negotiate
ClientHelloExtension::SupportedVersions(SupportedVersionsClientHello {
versions: Vec::from_slice(&[TLS13]).unwrap(),
})
.encode(buf)?;
ClientHelloExtension::SignatureAlgorithms(SignatureAlgorithms {
supported_signature_algorithms: self.config.signature_schemes.clone(),
})
.encode(buf)?;
if let Some(max_fragment_length) = self.config.max_fragment_length {
ClientHelloExtension::MaxFragmentLength(max_fragment_length).encode(buf)?;
}
ClientHelloExtension::SupportedGroups(SupportedGroups {
supported_groups: self.config.named_groups.clone(),
})
.encode(buf)?;
ClientHelloExtension::PskKeyExchangeModes(PskKeyExchangeModes {
modes: Vec::from_slice(&[PskKeyExchangeMode::PskDheKe]).unwrap(),
})
.encode(buf)?;
ClientHelloExtension::KeyShare(KeyShareClientHello {
client_shares: Vec::from_slice(&[KeyShareEntry {
group: NamedGroup::Secp256r1,
opaque: public_key,
}])
.unwrap(),
})
.encode(buf)?;
if let Some(server_name) = self.config.server_name {
ClientHelloExtension::ServerName(ServerNameList::single(server_name))
.encode(buf)?;
}
if let Some(alpn_protocols) = self.config.alpn_protocols {
ClientHelloExtension::ApplicationLayerProtocolNegotiation(AlpnProtocolNameList {
protocols: alpn_protocols,
})
.encode(buf)?;
}
// Section 4.2
// When multiple extensions of different types are present, the
// extensions MAY appear in any order, with the exception of
// "pre_shared_key" which MUST be the last extension in
// the ClientHello.
if let Some((_, identities)) = &self.config.psk {
ClientHelloExtension::PreSharedKey(PreSharedKeyClientHello {
identities: identities.clone(),
hash_size: <CipherSuite::Hash as OutputSizeUser>::output_size(),
})
.encode(buf)?;
}
Ok(())
})?;
Ok(())
}
pub fn finalize(
&self,
enc_buf: &mut [u8],
transcript: &mut CipherSuite::Hash,
write_key_schedule: &mut WriteKeySchedule<CipherSuite>,
) -> Result<(), ProtocolError> {
// Special case for PSK which needs to:
//
// 1. Add the client hello without the binders to the transcript
// 2. Create the binders for each identity using the transcript
// 3. Add the rest of the client hello.
//
// This causes a few issues since lengths must be correctly inside the payload,
// but won't actually be added to the record buffer until the end.
if let Some((_, identities)) = &self.config.psk {
let binders_len = identities.len() * (1 + HashOutputSize::<CipherSuite>::to_usize());
let binders_pos = enc_buf.len() - binders_len;
// NOTE: Exclude the binders_len itself from the digest
transcript.update(&enc_buf[0..binders_pos - 2]);
// Append after the client hello data. Sizes have already been set.
let mut buf = CryptoBuffer::wrap(&mut enc_buf[binders_pos..]);
// Create a binder and encode for each identity
for _id in identities {
let binder = write_key_schedule.create_psk_binder(transcript)?;
binder.encode(&mut buf)?;
}
transcript.update(&enc_buf[binders_pos - 2..]);
} else {
transcript.update(enc_buf);
}
Ok(())
}
}

View File

@@ -0,0 +1,19 @@
use core::marker::PhantomData;
use crate::extensions::messages::EncryptedExtensionsExtension;
use crate::ProtocolError;
use crate::parse_buffer::ParseBuffer;
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct EncryptedExtensions<'a> {
_todo: PhantomData<&'a ()>,
}
impl<'a> EncryptedExtensions<'a> {
pub fn parse(buf: &mut ParseBuffer<'a>) -> Result<EncryptedExtensions<'a>, ProtocolError> {
EncryptedExtensionsExtension::parse_vector::<16>(buf)?;
Ok(EncryptedExtensions { _todo: PhantomData })
}
}

52
src/handshake/finished.rs Normal file
View File

@@ -0,0 +1,52 @@
use crate::ProtocolError;
use crate::buffer::CryptoBuffer;
use crate::parse_buffer::ParseBuffer;
use core::fmt::{Debug, Formatter};
//use digest::generic_array::{ArrayLength, GenericArray};
use generic_array::{ArrayLength, GenericArray};
// use heapless::Vec;
pub struct Finished<N: ArrayLength<u8>> {
pub verify: GenericArray<u8, N>,
pub hash: Option<GenericArray<u8, N>>,
}
#[cfg(feature = "defmt")]
impl<N: ArrayLength<u8>> defmt::Format for Finished<N> {
fn format(&self, f: defmt::Formatter<'_>) {
defmt::write!(f, "verify length:{}", &self.verify.len());
}
}
impl<N: ArrayLength<u8>> Debug for Finished<N> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Finished")
.field("verify", &self.hash)
.finish()
}
}
impl<N: ArrayLength<u8>> Finished<N> {
pub fn parse(buf: &mut ParseBuffer, _len: u32) -> Result<Self, ProtocolError> {
// info!("finished len: {}", len);
let mut verify = GenericArray::default();
buf.fill(&mut verify)?;
//let hash = GenericArray::from_slice()
//let hash: Result<Vec<u8, _>, ()> = buf
//.slice(len as usize)
//.map_err(|_| ProtocolError::InvalidHandshake)?
//.into();
// info!("hash {:?}", verify);
//let hash = hash.map_err(|_| ProtocolError::InvalidHandshake)?;
// info!("hash ng {:?}", verify);
Ok(Self { verify, hash: None })
}
pub(crate) fn encode(&self, buf: &mut CryptoBuffer<'_>) -> Result<(), ProtocolError> {
//let len = self.verify.len().to_be_bytes();
//buf.extend_from_slice(&[len[1], len[2], len[3]]);
buf.extend_from_slice(&self.verify[..self.verify.len()])
.map_err(|_| ProtocolError::EncodeError)?;
Ok(())
}
}

241
src/handshake/mod.rs Normal file
View File

@@ -0,0 +1,241 @@
//use p256::elliptic_curve::AffinePoint;
use crate::ProtocolError;
use crate::config::TlsCipherSuite;
use crate::handshake::certificate::CertificateRef;
use crate::handshake::certificate_request::CertificateRequestRef;
use crate::handshake::certificate_verify::{HandshakeVerify, HandshakeVerifyRef};
use crate::handshake::client_hello::ClientHello;
use crate::handshake::encrypted_extensions::EncryptedExtensions;
use crate::handshake::finished::Finished;
use crate::handshake::new_session_ticket::NewSessionTicket;
use crate::handshake::server_hello::ServerHello;
use crate::key_schedule::HashOutputSize;
use crate::parse_buffer::{ParseBuffer, ParseError};
use crate::{buffer::CryptoBuffer, key_schedule::WriteKeySchedule};
use core::fmt::{Debug, Formatter};
use sha2::Digest;
pub mod binder;
pub mod certificate;
pub mod certificate_request;
pub mod certificate_verify;
pub mod client_hello;
pub mod encrypted_extensions;
pub mod finished;
pub mod new_session_ticket;
pub mod server_hello;
const LEGACY_VERSION: u16 = 0x0303;
type Random = [u8; 32];
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum HandshakeType {
ClientHello = 1,
ServerHello = 2,
NewSessionTicket = 4,
EndOfEarlyData = 5,
EncryptedExtensions = 8,
Certificate = 11,
CertificateRequest = 13,
HandshakeVerify = 15,
Finished = 20,
KeyUpdate = 24,
MessageHash = 254,
}
impl HandshakeType {
pub fn parse(buf: &mut ParseBuffer) -> Result<Self, ParseError> {
match buf.read_u8()? {
1 => Ok(HandshakeType::ClientHello),
2 => Ok(HandshakeType::ServerHello),
4 => Ok(HandshakeType::NewSessionTicket),
5 => Ok(HandshakeType::EndOfEarlyData),
8 => Ok(HandshakeType::EncryptedExtensions),
11 => Ok(HandshakeType::Certificate),
13 => Ok(HandshakeType::CertificateRequest),
15 => Ok(HandshakeType::HandshakeVerify),
20 => Ok(HandshakeType::Finished),
24 => Ok(HandshakeType::KeyUpdate),
254 => Ok(HandshakeType::MessageHash),
_ => Err(ParseError::InvalidData),
}
}
}
#[allow(clippy::large_enum_variant)]
pub enum ClientHandshake<'config, 'a, CipherSuite>
where
CipherSuite: TlsCipherSuite,
{
ClientCert(CertificateRef<'a>),
ClientCertVerify(HandshakeVerify),
ClientHello(ClientHello<'config, CipherSuite>),
Finished(Finished<HashOutputSize<CipherSuite>>),
}
impl<CipherSuite> ClientHandshake<'_, '_, CipherSuite>
where
CipherSuite: TlsCipherSuite,
{
fn handshake_type(&self) -> HandshakeType {
match self {
ClientHandshake::ClientHello(_) => HandshakeType::ClientHello,
ClientHandshake::Finished(_) => HandshakeType::Finished,
ClientHandshake::ClientCert(_) => HandshakeType::Certificate,
ClientHandshake::ClientCertVerify(_) => HandshakeType::HandshakeVerify,
}
}
fn encode_inner(&self, buf: &mut CryptoBuffer<'_>) -> Result<(), ProtocolError> {
match self {
ClientHandshake::ClientHello(inner) => inner.encode(buf),
ClientHandshake::Finished(inner) => inner.encode(buf),
ClientHandshake::ClientCert(inner) => inner.encode(buf),
ClientHandshake::ClientCertVerify(inner) => inner.encode(buf),
}
}
pub(crate) fn encode(&self, buf: &mut CryptoBuffer<'_>) -> Result<(), ProtocolError> {
buf.push(self.handshake_type() as u8)
.map_err(|_| ProtocolError::EncodeError)?;
buf.with_u24_length(|buf| self.encode_inner(buf))
}
pub fn finalize(
&self,
buf: &mut CryptoBuffer,
transcript: &mut CipherSuite::Hash,
write_key_schedule: &mut WriteKeySchedule<CipherSuite>,
) -> Result<(), ProtocolError> {
let enc_buf = buf.as_mut_slice();
if let ClientHandshake::ClientHello(hello) = self {
hello.finalize(enc_buf, transcript, write_key_schedule)
} else {
transcript.update(enc_buf);
Ok(())
}
}
pub fn finalize_encrypted(buf: &mut CryptoBuffer, transcript: &mut CipherSuite::Hash) {
let enc_buf = buf.as_slice();
let end = enc_buf.len();
transcript.update(&enc_buf[0..end]);
}
}
#[allow(clippy::large_enum_variant)]
pub enum ServerHandshake<'a, CipherSuite: TlsCipherSuite> {
ServerHello(ServerHello<'a>),
EncryptedExtensions(EncryptedExtensions<'a>),
NewSessionTicket(NewSessionTicket<'a>),
Certificate(CertificateRef<'a>),
CertificateRequest(CertificateRequestRef<'a>),
HandshakeVerify(HandshakeVerifyRef<'a>),
Finished(Finished<HashOutputSize<CipherSuite>>),
}
impl<CipherSuite: TlsCipherSuite> ServerHandshake<'_, CipherSuite> {
#[allow(dead_code)]
pub fn handshake_type(&self) -> HandshakeType {
match self {
ServerHandshake::ServerHello(_) => HandshakeType::ServerHello,
ServerHandshake::EncryptedExtensions(_) => HandshakeType::EncryptedExtensions,
ServerHandshake::NewSessionTicket(_) => HandshakeType::NewSessionTicket,
ServerHandshake::Certificate(_) => HandshakeType::Certificate,
ServerHandshake::CertificateRequest(_) => HandshakeType::CertificateRequest,
ServerHandshake::HandshakeVerify(_) => HandshakeType::HandshakeVerify,
ServerHandshake::Finished(_) => HandshakeType::Finished,
}
}
}
impl<CipherSuite: TlsCipherSuite> Debug for ServerHandshake<'_, CipherSuite> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
ServerHandshake::ServerHello(inner) => Debug::fmt(inner, f),
ServerHandshake::EncryptedExtensions(inner) => Debug::fmt(inner, f),
ServerHandshake::Certificate(inner) => Debug::fmt(inner, f),
ServerHandshake::CertificateRequest(inner) => Debug::fmt(inner, f),
ServerHandshake::HandshakeVerify(inner) => Debug::fmt(inner, f),
ServerHandshake::Finished(inner) => Debug::fmt(inner, f),
ServerHandshake::NewSessionTicket(inner) => Debug::fmt(inner, f),
}
}
}
#[cfg(feature = "defmt")]
impl<'a, CipherSuite: TlsCipherSuite> defmt::Format for ServerHandshake<'a, CipherSuite> {
fn format(&self, f: defmt::Formatter<'_>) {
match self {
ServerHandshake::ServerHello(inner) => defmt::write!(f, "{}", inner),
ServerHandshake::EncryptedExtensions(inner) => defmt::write!(f, "{}", inner),
ServerHandshake::Certificate(inner) => defmt::write!(f, "{}", inner),
ServerHandshake::CertificateRequest(inner) => defmt::write!(f, "{}", inner),
ServerHandshake::HandshakeVerify(inner) => defmt::write!(f, "{}", inner),
ServerHandshake::Finished(inner) => defmt::write!(f, "{}", inner),
ServerHandshake::NewSessionTicket(inner) => defmt::write!(f, "{}", inner),
}
}
}
impl<'a, CipherSuite: TlsCipherSuite> ServerHandshake<'a, CipherSuite> {
pub fn read(
buf: &mut ParseBuffer<'a>,
digest: &mut CipherSuite::Hash,
) -> Result<Self, ProtocolError> {
let handshake_start = buf.offset();
let mut handshake = Self::parse(buf)?;
let handshake_end = buf.offset();
if let ServerHandshake::Finished(finished) = &mut handshake {
finished.hash.replace(digest.clone().finalize());
}
digest.update(&buf.as_slice()[handshake_start..handshake_end]);
Ok(handshake)
}
fn parse(buf: &mut ParseBuffer<'a>) -> Result<Self, ProtocolError> {
let handshake_type = HandshakeType::parse(buf).map_err(|_| ProtocolError::InvalidHandshake)?;
trace!("handshake = {:?}", handshake_type);
let content_len = buf.read_u24().map_err(|_| ProtocolError::InvalidHandshake)?;
let handshake = match handshake_type {
//HandshakeType::ClientHello => {}
HandshakeType::ServerHello => ServerHandshake::ServerHello(ServerHello::parse(buf)?),
HandshakeType::NewSessionTicket => {
ServerHandshake::NewSessionTicket(NewSessionTicket::parse(buf)?)
}
//HandshakeType::EndOfEarlyData => {}
HandshakeType::EncryptedExtensions => {
ServerHandshake::EncryptedExtensions(EncryptedExtensions::parse(buf)?)
}
HandshakeType::Certificate => ServerHandshake::Certificate(CertificateRef::parse(buf)?),
HandshakeType::CertificateRequest => {
ServerHandshake::CertificateRequest(CertificateRequestRef::parse(buf)?)
}
HandshakeType::HandshakeVerify => {
ServerHandshake::HandshakeVerify(HandshakeVerifyRef::parse(buf)?)
}
HandshakeType::Finished => {
ServerHandshake::Finished(Finished::parse(buf, content_len)?)
}
//HandshakeType::KeyUpdate => {}
//HandshakeType::MessageHash => {}
t => {
warn!("Unimplemented handshake type: {:?}", t);
return Err(ProtocolError::Unimplemented);
}
};
Ok(handshake)
}
}

View File

@@ -0,0 +1,33 @@
use core::marker::PhantomData;
use crate::extensions::messages::NewSessionTicketExtension;
use crate::parse_buffer::ParseBuffer;
use crate::{ProtocolError, unused};
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct NewSessionTicket<'a> {
_todo: PhantomData<&'a ()>,
}
impl<'a> NewSessionTicket<'a> {
pub fn parse(buf: &mut ParseBuffer<'a>) -> Result<NewSessionTicket<'a>, ProtocolError> {
let lifetime = buf.read_u32()?;
let age_add = buf.read_u32()?;
let nonce_length = buf.read_u8()?;
let nonce = buf
.slice(nonce_length as usize)
.map_err(|_| ProtocolError::InvalidNonceLength)?;
let ticket_length = buf.read_u16()?;
let ticket = buf
.slice(ticket_length as usize)
.map_err(|_| ProtocolError::InvalidTicketLength)?;
let extensions = NewSessionTicketExtension::parse_vector::<1>(buf)?;
unused((lifetime, age_add, nonce, ticket, extensions));
Ok(Self { _todo: PhantomData })
}
}

View File

@@ -0,0 +1,83 @@
use heapless::Vec;
use crate::cipher_suites::CipherSuite;
use crate::cipher::CryptoEngine;
use crate::extensions::extension_data::key_share::KeyShareEntry;
use crate::extensions::messages::ServerHelloExtension;
use crate::parse_buffer::ParseBuffer;
use crate::{ProtocolError, unused};
use p256::PublicKey;
use p256::ecdh::{EphemeralSecret, SharedSecret};
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ServerHello<'a> {
extensions: Vec<ServerHelloExtension<'a>, 4>,
}
impl<'a> ServerHello<'a> {
pub fn parse(buf: &mut ParseBuffer<'a>) -> Result<ServerHello<'a>, ProtocolError> {
//let mut buf = ParseBuffer::new(&buf[0..content_length]);
//let mut buf = ParseBuffer::new(&buf);
let _version = buf.read_u16().map_err(|_| ProtocolError::InvalidHandshake)?;
let mut random = [0; 32];
buf.fill(&mut random)?;
let session_id_length = buf
.read_u8()
.map_err(|_| ProtocolError::InvalidSessionIdLength)?;
//info!("sh 1");
let session_id = buf
.slice(session_id_length as usize)
.map_err(|_| ProtocolError::InvalidSessionIdLength)?;
//info!("sh 2");
let cipher_suite = CipherSuite::parse(buf).map_err(|_| ProtocolError::InvalidCipherSuite)?;
////info!("sh 3");
// skip compression method, it's 0.
buf.read_u8()?;
let extensions = ServerHelloExtension::parse_vector(buf)?;
// debug!("server random {:x}", random);
// debug!("server session-id {:x}", session_id.as_slice());
debug!("server cipher_suite {:?}", cipher_suite);
debug!("server extensions {:?}", extensions);
unused(session_id);
Ok(Self { extensions })
}
pub fn key_share(&self) -> Option<&KeyShareEntry<'_>> {
self.extensions.iter().find_map(|e| {
if let ServerHelloExtension::KeyShare(entry) = e {
Some(&entry.0)
} else {
None
}
})
}
pub fn calculate_shared_secret(&self, secret: &EphemeralSecret) -> Option<SharedSecret> {
let server_key_share = self.key_share()?;
let server_public_key = PublicKey::from_sec1_bytes(server_key_share.opaque).ok()?;
Some(secret.diffie_hellman(&server_public_key))
}
#[allow(dead_code)]
pub fn initialize_crypto_engine(&self, secret: &EphemeralSecret) -> Option<CryptoEngine> {
let server_key_share = self.key_share()?;
let group = server_key_share.group;
let server_public_key = PublicKey::from_sec1_bytes(server_key_share.opaque).ok()?;
let shared = secret.diffie_hellman(&server_public_key);
Some(CryptoEngine::new(group, shared))
}
}