Add comments and LICENSE
This commit is contained in:
@@ -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)?;
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"))]
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()?;
|
||||
|
||||
Reference in New Issue
Block a user