Add comments and LICENSE

This commit is contained in:
2026-02-21 08:20:02 +00:00
parent af63ad4870
commit 526d9f7458
37 changed files with 266 additions and 447 deletions

View File

@@ -1,9 +1,7 @@
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>,
@@ -25,7 +23,6 @@ impl<N: ArrayLength<u8>> Debug for PskBinder<N> {
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)?;

View File

@@ -79,7 +79,6 @@ impl<'a> CertificateEntryRef<'a> {
let entry = CertificateEntryRef::X509(cert.as_slice());
// Validate extensions
CertificateExtension::parse_vector::<2>(buf)?;
Ok(entry)
@@ -103,14 +102,12 @@ impl<'a> CertificateEntryRef<'a> {
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(())
}

View File

@@ -18,7 +18,6 @@ impl<'a> CertificateRequestRef<'a> {
.slice(request_context_len as usize)
.map_err(|_| ProtocolError::InvalidCertificateRequest)?;
// Validate extensions
let extensions = CertificateRequestExtension::parse_vector::<6>(buf)?;
unused(extensions);

View File

@@ -28,13 +28,6 @@ impl<'a> HandshakeVerifyRef<'a> {
}
}
// 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"))]

View File

@@ -62,28 +62,19 @@ where
buf.extend_from_slice(&self.random)
.map_err(|_| ProtocolError::EncodeError)?;
// session id (empty)
// Empty legacy session ID — TLS 1.3 doesn't use it, but the field must be present
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());
//}
// Exactly one cipher suite entry (2-byte length prefix + 2-byte code point)
buf.push_u16(2).map_err(|_| ProtocolError::EncodeError)?;
buf.push_u16(CipherSuite::CODE_POINT)
.map_err(|_| ProtocolError::EncodeError)?;
// compression methods, 1 byte of 0
// Legacy compression methods: one entry, 0x00 = no compression
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(),
})
@@ -129,11 +120,6 @@ where
.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(),
@@ -154,25 +140,16 @@ where
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 {
// PSK binders depend on the transcript up to (but not including) the binder values,
// so we hash the partial message, compute binders, then hash the remainder (RFC 8446 §4.2.11.2)
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)?;

View File

@@ -2,10 +2,12 @@ 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;
/// TLS Finished message: contains an HMAC over the handshake transcript (RFC 8446 §4.4.4).
///
/// `hash` holds the transcript hash snapshot taken just before this message was received;
/// it is `None` when the struct is used for a locally-generated Finished message.
pub struct Finished<N: ArrayLength<u8>> {
pub verify: GenericArray<u8, N>,
pub hash: Option<GenericArray<u8, N>>,
@@ -28,23 +30,12 @@ impl<N: ArrayLength<u8>> Debug for Finished<N> {
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(())

View File

@@ -1,4 +1,3 @@
//use p256::elliptic_curve::AffinePoint;
use crate::ProtocolError;
use crate::config::TlsCipherSuite;
use crate::handshake::certificate::CertificateRef;
@@ -25,6 +24,7 @@ pub mod finished;
pub mod new_session_ticket;
pub mod server_hello;
// TLS legacy_record_version field — always 0x0303 for TLS 1.3 compatibility (RFC 8446 §5.1)
const LEGACY_VERSION: u16 = 0x0303;
type Random = [u8; 32];
@@ -101,6 +101,7 @@ where
buf.push(self.handshake_type() as u8)
.map_err(|_| ProtocolError::EncodeError)?;
// Handshake message body is preceded by a 3-byte (u24) length (RFC 8446 §4)
buf.with_u24_length(|buf| self.encode_inner(buf))
}
@@ -190,6 +191,7 @@ impl<'a, CipherSuite: TlsCipherSuite> ServerHandshake<'a, CipherSuite> {
let mut handshake = Self::parse(buf)?;
let handshake_end = buf.offset();
// Capture the current transcript hash into Finished before we update it with this message
if let ServerHandshake::Finished(finished) = &mut handshake {
finished.hash.replace(digest.clone().finalize());
}
@@ -207,12 +209,10 @@ impl<'a, CipherSuite: TlsCipherSuite> ServerHandshake<'a, CipherSuite> {
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)?)
}
@@ -228,8 +228,6 @@ impl<'a, CipherSuite: TlsCipherSuite> ServerHandshake<'a, CipherSuite> {
HandshakeType::Finished => {
ServerHandshake::Finished(Finished::parse(buf, content_len)?)
}
//HandshakeType::KeyUpdate => {}
//HandshakeType::MessageHash => {}
t => {
warn!("Unimplemented handshake type: {:?}", t);
return Err(ProtocolError::Unimplemented);

View File

@@ -17,9 +17,7 @@ pub struct ServerHello<'a> {
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);
// legacy_version is always 0x0303 in TLS 1.3; actual version is negotiated via extensions
let _version = buf.read_u16().map_err(|_| ProtocolError::InvalidHandshake)?;
let mut random = [0; 32];
@@ -29,23 +27,18 @@ impl<'a> ServerHello<'a> {
.read_u8()
.map_err(|_| ProtocolError::InvalidSessionIdLength)?;
//info!("sh 1");
// Legacy session ID echo: TLS 1.3 servers echo the client's session ID for middlebox compatibility
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.
// compression_method: always 0x00 in TLS 1.3
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);
@@ -63,6 +56,7 @@ impl<'a> ServerHello<'a> {
})
}
/// Performs ECDH with the server's key share to derive the shared secret used in the handshake.
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()?;