From f0aac34aabdd35b123b8369451c351a47d6fe905 Mon Sep 17 00:00:00 2001 From: Mathias Date: Tue, 6 Feb 2024 08:55:26 +0100 Subject: [PATCH 01/19] Started work on implementing the missing state of ClientCertVerify described in TLS1.3 RFC8446 section 4.4.3 --- src/config.rs | 1 + src/connection.rs | 61 ++++++++++++++++++++++++++++ src/handshake/certificate_request.rs | 6 ++- src/handshake/certificate_verify.rs | 9 ++++ src/handshake/mod.rs | 3 ++ 5 files changed, 79 insertions(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index 97c48495..f049bc45 100644 --- a/src/config.rs +++ b/src/config.rs @@ -134,6 +134,7 @@ where pub(crate) max_fragment_length: Option, pub(crate) ca: Option>, pub(crate) cert: Option>, + // TODO: priv_key: Option<&'a [u8]>? } pub trait TlsClock { diff --git a/src/connection.rs b/src/connection.rs index 419ffcd2..defceb11 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -1,4 +1,5 @@ use crate::config::{TlsCipherSuite, TlsConfig, TlsVerifier}; +use crate::handshake::certificate_verify::CertificateVerify; use crate::handshake::{ClientHandshake, ServerHandshake}; use crate::key_schedule::{KeySchedule, ReadKeySchedule, WriteKeySchedule}; use crate::record::{ClientRecord, ServerRecord}; @@ -171,6 +172,7 @@ pub enum State { ServerHello, ServerVerify, ClientCert, + ClientCertVerify, ClientFinished, ApplicationData, } @@ -226,6 +228,13 @@ impl<'a> State { Ok(state) } + State::ClientCertVerify => { + let (state, tx) = client_cert_verify(handshake, key_schedule, config, tx_buf)?; + + respond(tx, transport, key_schedule).await?; + + Ok(state) + } State::ClientFinished => { let tx = client_finished(key_schedule, tx_buf)?; @@ -283,6 +292,13 @@ impl<'a> State { Ok(state) } + State::ClientCertVerify => { + let (state, tx) = client_cert_verify(handshake, key_schedule, config, tx_buf)?; + + respond_blocking(tx, transport, key_schedule)?; + + Ok(state) + } State::ClientFinished => { let tx = client_finished(key_schedule, tx_buf)?; @@ -526,6 +542,51 @@ where write_key_schedule, Some(read_key_schedule), ) + .map(|slice| (State::ClientCertVerify, slice)) +} + +fn client_cert_verify<'r, CipherSuite, Verifier>( + handshake: &mut Handshake, + key_schedule: &mut KeySchedule, + config: &TlsConfig, + buffer: &'r mut WriteBuffer, +) -> Result<(State, &'r [u8]), TlsError> +where + CipherSuite: TlsCipherSuite, +{ + // TODO: + // + // handshake + // .traffic_hash + // .replace(key_schedule.transcript_hash().clone()); + + // let extensions = &handshake + // .certificate_request + // .as_ref() + // .ok_or(TlsError::InvalidHandshake)? + // .extensions; + + // let ctx_str = b"TLS 1.3, client CertificateVerify\x00"; + // let mut msg: heapless::Vec = heapless::Vec::new(); + // msg.resize(64, 0x20).map_err(|_| TlsError::EncodeError)?; + // msg.extend_from_slice(ctx_str) + // .map_err(|_| TlsError::EncodeError)?; + // msg.extend_from_slice(&handshake_hash.finalize()) + // .map_err(|_| TlsError::EncodeError)?; + + let mut certificate_verify = CertificateVerify { + signature_scheme: todo!(), + signature: todo!(), + }; + + let (write_key_schedule, read_key_schedule) = key_schedule.as_split(); + + buffer + .write_record( + &ClientRecord::Handshake(ClientHandshake::ClientCertVerify(certificate_verify), true), + write_key_schedule, + Some(read_key_schedule), + ) .map(|slice| (State::ClientFinished, slice)) } diff --git a/src/handshake/certificate_request.rs b/src/handshake/certificate_request.rs index 1f9fef1b..cbda76ce 100644 --- a/src/handshake/certificate_request.rs +++ b/src/handshake/certificate_request.rs @@ -7,6 +7,7 @@ use heapless::Vec; #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CertificateRequestRef<'a> { pub(crate) request_context: &'a [u8], + pub(crate) extensions: Vec, 6>, } impl<'a> CertificateRequestRef<'a> { @@ -19,10 +20,11 @@ impl<'a> CertificateRequestRef<'a> { .map_err(|_| TlsError::InvalidCertificateRequest)?; // Validate extensions - CertificateRequestExtension::parse_vector::<6>(buf)?; + let extensions = CertificateRequestExtension::parse_vector::<6>(buf)?; Ok(Self { request_context: request_context.as_slice(), + extensions, }) } } @@ -31,6 +33,8 @@ impl<'a> CertificateRequestRef<'a> { #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CertificateRequest { pub(crate) request_context: Vec, + // TODO: Owned version of the `Vec`? Or + // extract the potential `SignatureAlgorithms<4>`? } impl<'a> TryFrom> for CertificateRequest { diff --git a/src/handshake/certificate_verify.rs b/src/handshake/certificate_verify.rs index 4d176d9e..e470b599 100644 --- a/src/handshake/certificate_verify.rs +++ b/src/handshake/certificate_verify.rs @@ -2,6 +2,8 @@ use crate::extensions::extension_data::signature_algorithms::SignatureScheme; use crate::parse_buffer::ParseBuffer; use crate::TlsError; +use super::CryptoBuffer; + #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CertificateVerify<'a> { @@ -24,4 +26,11 @@ impl<'a> CertificateVerify<'a> { signature: signature.as_slice(), }) } + + pub(crate) fn encode(&self, buf: &mut CryptoBuffer<'_>) -> Result<(), TlsError> { + buf.push_u16(self.signature_scheme as _)?; + buf.push_u16(self.signature.len() as _)?; + buf.extend_from_slice(self.signature)?; + Ok(()) + } } diff --git a/src/handshake/mod.rs b/src/handshake/mod.rs index 733356fb..0b966d3d 100644 --- a/src/handshake/mod.rs +++ b/src/handshake/mod.rs @@ -70,6 +70,7 @@ where CipherSuite: TlsCipherSuite, { ClientCert(CertificateRef<'a>), + ClientCertVerify(CertificateVerify<'a>), ClientHello(ClientHello<'config, CipherSuite>), Finished(Finished>), } @@ -83,6 +84,7 @@ where ClientHandshake::ClientHello(_) => HandshakeType::ClientHello, ClientHandshake::Finished(_) => HandshakeType::Finished, ClientHandshake::ClientCert(_) => HandshakeType::Certificate, + ClientHandshake::ClientCertVerify(_) => HandshakeType::CertificateVerify, } } @@ -91,6 +93,7 @@ where ClientHandshake::ClientHello(inner) => inner.encode(buf), ClientHandshake::Finished(inner) => inner.encode(buf), ClientHandshake::ClientCert(inner) => inner.encode(buf), + ClientHandshake::ClientCertVerify(inner) => inner.encode(buf), } } From e00929963e5a0c864b3504a9ca76654d04b03aae Mon Sep 17 00:00:00 2001 From: Mathias Date: Tue, 6 Feb 2024 12:43:32 +0100 Subject: [PATCH 02/19] Add signature algorithms to CertificateRequest, and add priv_key to Config --- src/config.rs | 8 +++++++- src/handshake/certificate_request.rs | 18 +++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/config.rs b/src/config.rs index f049bc45..3e7106f5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -134,7 +134,7 @@ where pub(crate) max_fragment_length: Option, pub(crate) ca: Option>, pub(crate) cert: Option>, - // TODO: priv_key: Option<&'a [u8]>? + pub(crate) priv_key: Option<&'a [u8]>, } pub trait TlsClock { @@ -185,6 +185,7 @@ where server_name: None, ca: None, cert: None, + priv_key: None, }; //config.cipher_suites.push(CipherSuite::TlsAes128GcmSha256); @@ -281,6 +282,11 @@ where self } + pub fn with_priv_key(mut self, priv_key: &'a [u8]) -> Self { + self.priv_key = Some(priv_key); + self + } + pub fn with_psk(mut self, psk: &'a [u8], identities: &[&'a [u8]]) -> Self { // TODO: Remove potential panic self.psk = Some((psk, unwrap!(Vec::from_slice(identities).ok()))); diff --git a/src/handshake/certificate_request.rs b/src/handshake/certificate_request.rs index cbda76ce..c17993e9 100644 --- a/src/handshake/certificate_request.rs +++ b/src/handshake/certificate_request.rs @@ -1,3 +1,4 @@ +use crate::extensions::extension_data::signature_algorithms::SignatureAlgorithms; use crate::extensions::messages::CertificateRequestExtension; use crate::parse_buffer::ParseBuffer; use crate::TlsError; @@ -33,8 +34,7 @@ impl<'a> CertificateRequestRef<'a> { #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CertificateRequest { pub(crate) request_context: Vec, - // TODO: Owned version of the `Vec`? Or - // extract the potential `SignatureAlgorithms<4>`? + pub(crate) signature_algorithms: Option>, } impl<'a> TryFrom> for CertificateRequest { @@ -47,6 +47,18 @@ impl<'a> TryFrom> for CertificateRequest { error!("CertificateRequest: InsufficientSpace"); TlsError::InsufficientSpace })?; - Ok(Self { request_context }) + + let mut signature_algorithms = None; + + for ext in cert.extensions { + if let CertificateRequestExtension::SignatureAlgorithms(algos) = ext { + signature_algorithms = Some(algos) + } + } + + Ok(Self { + request_context, + signature_algorithms, + }) } } From b95e3e7b9d11438ee078c05acbfbdd84f7d9977f Mon Sep 17 00:00:00 2001 From: Mathias Date: Tue, 6 Feb 2024 21:10:15 +0100 Subject: [PATCH 03/19] Add client_cert_verify signature emit function --- src/connection.rs | 44 ++++++++++++-------------- tests/client_test.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 24 deletions(-) diff --git a/src/connection.rs b/src/connection.rs index defceb11..06d3c369 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -11,6 +11,7 @@ use crate::{ handshake::{certificate::CertificateRef, certificate_request::CertificateRequest}, }; use core::fmt::Debug; +use digest::Digest; use embedded_io::Error as _; use embedded_io::{Read as BlockingRead, Write as BlockingWrite}; use embedded_io_async::{Read as AsyncRead, Write as AsyncWrite}; @@ -531,9 +532,12 @@ where .request_context; let mut certificate = CertificateRef::with_context(request_context); - if let Some(cert) = &config.cert { + let next_state = if let Some(cert) = &config.cert { certificate.add(cert.into())?; - } + State::ClientCertVerify + } else { + State::ClientFinished + }; let (write_key_schedule, read_key_schedule) = key_schedule.as_split(); buffer @@ -542,7 +546,7 @@ where write_key_schedule, Some(read_key_schedule), ) - .map(|slice| (State::ClientCertVerify, slice)) + .map(|slice| (next_state, slice)) } fn client_cert_verify<'r, CipherSuite, Verifier>( @@ -554,29 +558,21 @@ fn client_cert_verify<'r, CipherSuite, Verifier>( where CipherSuite: TlsCipherSuite, { - // TODO: - // - // handshake - // .traffic_hash - // .replace(key_schedule.transcript_hash().clone()); - - // let extensions = &handshake - // .certificate_request - // .as_ref() - // .ok_or(TlsError::InvalidHandshake)? - // .extensions; - - // let ctx_str = b"TLS 1.3, client CertificateVerify\x00"; - // let mut msg: heapless::Vec = heapless::Vec::new(); - // msg.resize(64, 0x20).map_err(|_| TlsError::EncodeError)?; - // msg.extend_from_slice(ctx_str) - // .map_err(|_| TlsError::EncodeError)?; - // msg.extend_from_slice(&handshake_hash.finalize()) - // .map_err(|_| TlsError::EncodeError)?; + let ctx_str = b"TLS 1.3, client CertificateVerify\x00"; + let mut msg: heapless::Vec = heapless::Vec::new(); + msg.resize(64, 0x20).map_err(|_| TlsError::EncodeError)?; + msg.extend_from_slice(ctx_str) + .map_err(|_| TlsError::EncodeError)?; + msg.extend_from_slice(&key_schedule.transcript_hash().clone().finalize()) + .map_err(|_| TlsError::EncodeError)?; + + // TODO: How to get a hold of something that can sign here? + let scheme = signer.scheme(); + let sig = signer.sign(&msg)?; let mut certificate_verify = CertificateVerify { - signature_scheme: todo!(), - signature: todo!(), + signature_scheme: scheme, + signature: sig, }; let (write_key_schedule, read_key_schedule) = key_schedule.as_split(); diff --git a/tests/client_test.rs b/tests/client_test.rs index 63483559..d2d45197 100644 --- a/tests/client_test.rs +++ b/tests/client_test.rs @@ -266,6 +266,81 @@ async fn test_ping_nocopy_bufread() { .expect("error closing session"); } +#[tokio::test] +async fn test_client_certificate_auth() { + use embedded_tls::*; + use tokio::net::TcpStream; + let addr = setup(); + let ca_pem = include_str!("data/ca-cert.pem"); + let ca_der = pem_parser::pem_to_der(ca_pem); + + let client_cert_pem = include_str!("data/client-cert.pem"); + let client_cert_der = pem_parser::pem_to_der(client_cert_pem); + + let private_key_pem = include_str!("data/private_key.pem"); + let private_key_der = pem_parser::pem_to_der(private_key_pem); + + let stream = TcpStream::connect(addr) + .await + .expect("error connecting to server"); + + log::info!("Connected"); + let mut read_record_buffer = [0; 16384]; + let mut write_record_buffer = [0; 16384]; + let config = TlsConfig::new() + .with_ca(Certificate::X509(&ca_der)) + .with_cert(Certificate::X509(&client_cert_der)) + .with_priv_key(&private_key_der) + .with_server_name("localhost"); + + let mut tls: TlsConnection, Aes128GcmSha256> = TlsConnection::new( + FromTokio::new(stream), + &mut read_record_buffer, + &mut write_record_buffer, + ); + + log::info!("SIZE of connection is {}", core::mem::size_of_val(&tls)); + + let mut rng = OsRng; + let open_fut = tls.open::(TlsContext::new(&config, &mut rng)); + log::info!("SIZE of open fut is {}", core::mem::size_of_val(&open_fut)); + open_fut.await.expect("error establishing TLS connection"); + log::info!("Established"); + + let write_fut = tls.write(b"ping"); + log::info!( + "SIZE of write fut is {}", + core::mem::size_of_val(&write_fut) + ); + write_fut.await.expect("error writing data"); + tls.flush().await.expect("error flushing data"); + + // Make sure reading into a 0 length buffer doesn't loop + let mut rx_buf = [0; 0]; + let read_fut = tls.read(&mut rx_buf); + log::info!("SIZE of read fut is {}", core::mem::size_of_val(&read_fut)); + let sz = read_fut.await.expect("error reading data"); + assert_eq!(sz, 0); + + let mut rx_buf = [0; 4096]; + let read_fut = tls.read(&mut rx_buf); + log::info!("SIZE of read fut is {}", core::mem::size_of_val(&read_fut)); + let sz = read_fut.await.expect("error reading data"); + assert_eq!(4, sz); + assert_eq!(b"ping", &rx_buf[..sz]); + log::info!("Read {} bytes: {:?}", sz, &rx_buf[..sz]); + + // Test that embedded-tls doesn't block if the buffer is empty. + let mut rx_buf = [0; 0]; + let sz = tls.read(&mut rx_buf).await.expect("error reading data"); + assert_eq!(sz, 0); + + tls.close() + .await + .map_err(|(_, e)| e) + .expect("error closing session"); +} + #[test] fn test_blocking_ping() { use embedded_tls::blocking::*; From 98230553741b0d93f95558faa349651a5505e44f Mon Sep 17 00:00:00 2001 From: Mathias Date: Fri, 9 Feb 2024 13:16:38 +0100 Subject: [PATCH 04/19] Fix client cert authentication test, and fix encoding issues derived from running it --- src/connection.rs | 15 ++- src/extensions/messages.rs | 2 +- src/handshake/certificate.rs | 34 +++---- src/handshake/certificate_request.rs | 2 +- src/handshake/certificate_verify.rs | 3 +- tests/client_cert_test.rs | 137 +++++++++++++++++++++++++++ tests/client_test.rs | 76 --------------- tests/data/client-cert.pem | 12 +++ tests/data/client-key.pem | 5 + 9 files changed, 184 insertions(+), 102 deletions(-) create mode 100644 tests/client_cert_test.rs create mode 100644 tests/data/client-cert.pem create mode 100644 tests/data/client-key.pem diff --git a/src/connection.rs b/src/connection.rs index 06d3c369..2c31c684 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -223,13 +223,17 @@ impl<'a> State { handle_processing_error(result, transport, key_schedule, tx_buf).await } State::ClientCert => { + debug!("State::ClientCert"); let (state, tx) = client_cert(handshake, key_schedule, config, tx_buf)?; + debug!("State::ClientCert respond"); respond(tx, transport, key_schedule).await?; Ok(state) } State::ClientCertVerify => { + debug!("State::ClientCertVerify"); + let (state, tx) = client_cert_verify(handshake, key_schedule, config, tx_buf)?; respond(tx, transport, key_schedule).await?; @@ -566,13 +570,14 @@ where msg.extend_from_slice(&key_schedule.transcript_hash().clone().finalize()) .map_err(|_| TlsError::EncodeError)?; + debug!("Generating signature"); // TODO: How to get a hold of something that can sign here? - let scheme = signer.scheme(); - let sig = signer.sign(&msg)?; + // let scheme = signer.scheme(); + // let sig = signer.sign(&msg)?; - let mut certificate_verify = CertificateVerify { - signature_scheme: scheme, - signature: sig, + let certificate_verify = CertificateVerify { + signature_scheme: crate::extensions::extension_data::signature_algorithms::SignatureScheme::EcdsaSecp256r1Sha256, + signature: b"abcd", }; let (write_key_schedule, read_key_schedule) = key_schedule.as_split(); diff --git a/src/extensions/messages.rs b/src/extensions/messages.rs index 8fa025d8..c5e4e98b 100644 --- a/src/extensions/messages.rs +++ b/src/extensions/messages.rs @@ -71,7 +71,7 @@ extension_group! { extension_group! { pub enum CertificateRequestExtension<'a> { StatusRequest(Unimplemented<'a>), - SignatureAlgorithms(SignatureAlgorithms<4>), + SignatureAlgorithms(SignatureAlgorithms<16>), SignedCertificateTimestamp(Unimplemented<'a>), CertificateAuthorities(Unimplemented<'a>), OidFilters(Unimplemented<'a>), diff --git a/src/handshake/certificate.rs b/src/handshake/certificate.rs index 862fab11..e3bd9e0c 100644 --- a/src/handshake/certificate.rs +++ b/src/handshake/certificate.rs @@ -49,15 +49,14 @@ impl<'a> CertificateRef<'a> { } pub(crate) fn encode(&self, buf: &mut CryptoBuffer<'_>) -> Result<(), TlsError> { - buf.push(self.request_context.len() as u8) - .map_err(|_| TlsError::EncodeError)?; - buf.extend_from_slice(self.request_context) - .map_err(|_| TlsError::EncodeError)?; - - buf.push_u24(self.entries.len() as u32)?; - for entry in self.entries.iter() { - entry.encode(buf)?; - } + buf.with_u8_length(|buf| buf.extend_from_slice(self.request_context))?; + buf.with_u24_length(|buf| { + for entry in self.entries.iter() { + entry.encode(buf)?; + } + Ok(()) + })?; + Ok(()) } } @@ -100,19 +99,20 @@ impl<'a> CertificateEntryRef<'a> { Ok(result) } - pub(crate) fn encode(&self, _buf: &mut CryptoBuffer<'_>) -> Result<(), TlsError> { - todo!("not implemented"); - /* + pub(crate) fn encode(&self, buf: &mut CryptoBuffer<'_>) -> Result<(), TlsError> { match self { - CertificateEntry::RawPublicKey(key) => { - let entry_len = (key.len() as u32).to_be_bytes(); + &CertificateEntryRef::RawPublicKey(_key) => { + todo!("ASN1_subjectPublicKeyInfo encoding?"); + // buf.with_u24_length(|buf| buf.extend_from_slice(key))?; } - CertificateEntry::X509(cert) => { - let entry_len = (cert.len() as u32).to_be_bytes(); + &CertificateEntryRef::X509(cert) => { + buf.with_u24_length(|buf| buf.extend_from_slice(cert))?; } } + + // Zero extensions for now + buf.push_u16(0)?; Ok(()) - */ } } diff --git a/src/handshake/certificate_request.rs b/src/handshake/certificate_request.rs index c17993e9..1c78e485 100644 --- a/src/handshake/certificate_request.rs +++ b/src/handshake/certificate_request.rs @@ -34,7 +34,7 @@ impl<'a> CertificateRequestRef<'a> { #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CertificateRequest { pub(crate) request_context: Vec, - pub(crate) signature_algorithms: Option>, + pub(crate) signature_algorithms: Option>, } impl<'a> TryFrom> for CertificateRequest { diff --git a/src/handshake/certificate_verify.rs b/src/handshake/certificate_verify.rs index e470b599..13020d6f 100644 --- a/src/handshake/certificate_verify.rs +++ b/src/handshake/certificate_verify.rs @@ -29,8 +29,7 @@ impl<'a> CertificateVerify<'a> { pub(crate) fn encode(&self, buf: &mut CryptoBuffer<'_>) -> Result<(), TlsError> { buf.push_u16(self.signature_scheme as _)?; - buf.push_u16(self.signature.len() as _)?; - buf.extend_from_slice(self.signature)?; + buf.with_u16_length(|buf| buf.extend_from_slice(self.signature))?; Ok(()) } } diff --git a/tests/client_cert_test.rs b/tests/client_cert_test.rs new file mode 100644 index 00000000..1905baff --- /dev/null +++ b/tests/client_cert_test.rs @@ -0,0 +1,137 @@ +#![macro_use] +use embedded_io_adapters::tokio_1::FromTokio; +use rand::rngs::OsRng; +use rustls::server::AllowAnyAuthenticatedClient; +use std::net::SocketAddr; +use std::sync::Once; + +mod tlsserver; + +static LOG_INIT: Once = Once::new(); +static INIT: Once = Once::new(); +static mut ADDR: Option = None; + +fn init_log() { + LOG_INIT.call_once(|| { + env_logger::init(); + }); +} + +fn setup() -> SocketAddr { + use mio::net::TcpListener; + init_log(); + INIT.call_once(|| { + let addr: SocketAddr = "127.0.0.1:12345".parse().unwrap(); + + let listener = TcpListener::bind(addr).expect("cannot listen on port"); + let addr = listener + .local_addr() + .expect("error retrieving socket address"); + + std::thread::spawn(move || { + use tlsserver::*; + + let versions = &[&rustls::version::TLS13]; + + let test_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests"); + + let certs = load_certs(&test_dir.join("data").join("server-cert.pem")); + let privkey = load_private_key(&test_dir.join("data").join("server-key.pem")); + + let mut client_auth_roots = rustls::RootCertStore::empty(); + for root in certs.iter() { + client_auth_roots.add(root).unwrap() + } + + let client_cert_verifier = AllowAnyAuthenticatedClient::new(client_auth_roots); + + let config = rustls::ServerConfig::builder() + .with_cipher_suites(rustls::ALL_CIPHER_SUITES) + .with_kx_groups(&rustls::ALL_KX_GROUPS) + .with_protocol_versions(versions) + .unwrap() + .with_client_cert_verifier(client_cert_verifier.boxed()) + .with_single_cert(certs, privkey) + .unwrap(); + + run_with_config(listener, config); + }); + unsafe { ADDR.replace(addr) }; + }); + unsafe { ADDR.unwrap() } +} + +#[tokio::test] +async fn test_client_certificate_auth() { + use embedded_tls::*; + use tokio::net::TcpStream; + let addr = setup(); + let ca_pem = include_str!("data/ca-cert.pem"); + let ca_der = pem_parser::pem_to_der(ca_pem); + + let client_cert_pem = include_str!("data/client-cert.pem"); + let client_cert_der = pem_parser::pem_to_der(client_cert_pem); + + let private_key_pem = include_str!("data/client-key.pem"); + let private_key_der = pem_parser::pem_to_der(private_key_pem); + + let stream = TcpStream::connect(addr) + .await + .expect("error connecting to server"); + + log::info!("Connected"); + let mut read_record_buffer = [0; 16384]; + let mut write_record_buffer = [0; 16384]; + let config = TlsConfig::new() + .with_ca(Certificate::X509(&ca_der)) + .with_cert(Certificate::X509(&client_cert_der)) + .with_priv_key(&private_key_der) + .with_server_name("localhost"); + + let mut tls: TlsConnection, Aes128GcmSha256> = TlsConnection::new( + FromTokio::new(stream), + &mut read_record_buffer, + &mut write_record_buffer, + ); + + log::info!("SIZE of connection is {}", core::mem::size_of_val(&tls)); + + let mut rng = OsRng; + let open_fut = tls.open::(TlsContext::new(&config, &mut rng)); + log::info!("SIZE of open fut is {}", core::mem::size_of_val(&open_fut)); + open_fut.await.expect("error establishing TLS connection"); + log::info!("Established"); + + let write_fut = tls.write(b"ping"); + log::info!( + "SIZE of write fut is {}", + core::mem::size_of_val(&write_fut) + ); + write_fut.await.expect("error writing data"); + tls.flush().await.expect("error flushing data"); + + // Make sure reading into a 0 length buffer doesn't loop + let mut rx_buf = [0; 0]; + let read_fut = tls.read(&mut rx_buf); + log::info!("SIZE of read fut is {}", core::mem::size_of_val(&read_fut)); + let sz = read_fut.await.expect("error reading data"); + assert_eq!(sz, 0); + + let mut rx_buf = [0; 4096]; + let read_fut = tls.read(&mut rx_buf); + log::info!("SIZE of read fut is {}", core::mem::size_of_val(&read_fut)); + let sz = read_fut.await.expect("error reading data"); + assert_eq!(4, sz); + assert_eq!(b"ping", &rx_buf[..sz]); + log::info!("Read {} bytes: {:?}", sz, &rx_buf[..sz]); + + // Test that embedded-tls doesn't block if the buffer is empty. + let mut rx_buf = [0; 0]; + let sz = tls.read(&mut rx_buf).await.expect("error reading data"); + assert_eq!(sz, 0); + + tls.close() + .await + .map_err(|(_, e)| e) + .expect("error closing session"); +} diff --git a/tests/client_test.rs b/tests/client_test.rs index d2d45197..d27fa1b9 100644 --- a/tests/client_test.rs +++ b/tests/client_test.rs @@ -38,7 +38,6 @@ fn setup() -> SocketAddr { unsafe { ADDR.unwrap() } } -#[ignore] #[tokio::test] async fn test_google() { use embedded_tls::*; @@ -266,81 +265,6 @@ async fn test_ping_nocopy_bufread() { .expect("error closing session"); } -#[tokio::test] -async fn test_client_certificate_auth() { - use embedded_tls::*; - use tokio::net::TcpStream; - let addr = setup(); - let ca_pem = include_str!("data/ca-cert.pem"); - let ca_der = pem_parser::pem_to_der(ca_pem); - - let client_cert_pem = include_str!("data/client-cert.pem"); - let client_cert_der = pem_parser::pem_to_der(client_cert_pem); - - let private_key_pem = include_str!("data/private_key.pem"); - let private_key_der = pem_parser::pem_to_der(private_key_pem); - - let stream = TcpStream::connect(addr) - .await - .expect("error connecting to server"); - - log::info!("Connected"); - let mut read_record_buffer = [0; 16384]; - let mut write_record_buffer = [0; 16384]; - let config = TlsConfig::new() - .with_ca(Certificate::X509(&ca_der)) - .with_cert(Certificate::X509(&client_cert_der)) - .with_priv_key(&private_key_der) - .with_server_name("localhost"); - - let mut tls: TlsConnection, Aes128GcmSha256> = TlsConnection::new( - FromTokio::new(stream), - &mut read_record_buffer, - &mut write_record_buffer, - ); - - log::info!("SIZE of connection is {}", core::mem::size_of_val(&tls)); - - let mut rng = OsRng; - let open_fut = tls.open::(TlsContext::new(&config, &mut rng)); - log::info!("SIZE of open fut is {}", core::mem::size_of_val(&open_fut)); - open_fut.await.expect("error establishing TLS connection"); - log::info!("Established"); - - let write_fut = tls.write(b"ping"); - log::info!( - "SIZE of write fut is {}", - core::mem::size_of_val(&write_fut) - ); - write_fut.await.expect("error writing data"); - tls.flush().await.expect("error flushing data"); - - // Make sure reading into a 0 length buffer doesn't loop - let mut rx_buf = [0; 0]; - let read_fut = tls.read(&mut rx_buf); - log::info!("SIZE of read fut is {}", core::mem::size_of_val(&read_fut)); - let sz = read_fut.await.expect("error reading data"); - assert_eq!(sz, 0); - - let mut rx_buf = [0; 4096]; - let read_fut = tls.read(&mut rx_buf); - log::info!("SIZE of read fut is {}", core::mem::size_of_val(&read_fut)); - let sz = read_fut.await.expect("error reading data"); - assert_eq!(4, sz); - assert_eq!(b"ping", &rx_buf[..sz]); - log::info!("Read {} bytes: {:?}", sz, &rx_buf[..sz]); - - // Test that embedded-tls doesn't block if the buffer is empty. - let mut rx_buf = [0; 0]; - let sz = tls.read(&mut rx_buf).await.expect("error reading data"); - assert_eq!(sz, 0); - - tls.close() - .await - .map_err(|(_, e)| e) - .expect("error closing session"); -} - #[test] fn test_blocking_ping() { use embedded_tls::blocking::*; diff --git a/tests/data/client-cert.pem b/tests/data/client-cert.pem new file mode 100644 index 00000000..cb04a1a3 --- /dev/null +++ b/tests/data/client-cert.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBzDCCAXGgAwIBAgIUVB+wKMT9vfrrgAOVt5qON8J8onMwCgYIKoZIzj0EAwIw +QjELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UECgwT +RGVmYXVsdCBDb21wYW55IEx0ZDAeFw0yNDAyMDkwOTI3NDlaFw0yNDAzMTAwOTI3 +NDlaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQK +DBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwWTATBgcqhkjOPQIBBggqhkjOPQMB +BwNCAAQzXKrX05qlw3NP1k6+kSiTnmI6Mo3ffT6VY71oPQIcqYiD1+hY7tIkk9kV +ke11ZNdGZR0r/o+4TzYJcxcgkNhLo0IwQDAdBgNVHQ4EFgQUBH7ViSdnDzmkYtsO +/f+BpHjeJHcwHwYDVR0jBBgwFoAU7HQ64pisg1MasN9wSLE/LC6PcjowCgYIKoZI +zj0EAwIDSQAwRgIhAONbHGkd+/wpgELOk/az5ELfrB7YO2o4a6Uix5KQOnARAiEA +tDGyTnCEmHjB/GGsLwLa8DRplNXFESDH2erfhutw8ME= +-----END CERTIFICATE----- diff --git a/tests/data/client-key.pem b/tests/data/client-key.pem new file mode 100644 index 00000000..3f0ba5af --- /dev/null +++ b/tests/data/client-key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIIMoxSnX9BbbgLSGk2rVi0o+NLwzisbbfce/pLGkHwvooAoGCCqGSM49 +AwEHoUQDQgAEM1yq19OapcNzT9ZOvpEok55iOjKN330+lWO9aD0CHKmIg9foWO7S +JJPZFZHtdWTXRmUdK/6PuE82CXMXIJDYSw== +-----END EC PRIVATE KEY----- From 03ab5975eed6182459e1ee3ceb0d2440a1c096f9 Mon Sep 17 00:00:00 2001 From: Mathias Date: Wed, 14 Feb 2024 19:28:50 +0100 Subject: [PATCH 05/19] Add new CryptoProvider trait, and implement signing capabilities for certificateVerify state. Also add a temporary rustls to rustls test to verify and compare client certificate authentication --- Cargo.toml | 21 ++- src/asynch.rs | 25 ++-- src/blocking.rs | 23 ++-- src/config.rs | 167 ++++++++++++++++++------ src/connection.rs | 191 ++++++++++++++-------------- src/handshake/certificate_verify.rs | 17 ++- src/handshake/client_hello.rs | 18 ++- src/handshake/mod.rs | 8 +- src/lib.rs | 5 + src/record.rs | 13 +- src/webpki.rs | 34 +++-- tests/client_cert_test.rs | 95 ++++++++++++-- tests/client_test.rs | 60 +++++---- tests/data/new/ca.crt | 12 ++ tests/data/new/ca.key | 5 + tests/data/new/ca.srl | 1 + tests/data/new/cert.conf | 9 ++ tests/data/new/client.conf | 24 ++++ tests/data/new/client.crt | 14 ++ tests/data/new/client.csr | 11 ++ tests/data/new/client.key | 5 + tests/data/new/server.conf | 24 ++++ tests/data/new/server.crt | 14 ++ tests/data/new/server.csr | 11 ++ tests/data/new/server.key | 5 + tests/data/new/ssl.sh | 115 +++++++++++++++++ tests/early_data_test.rs | 9 +- tests/psk_test.rs | 8 +- tests/split_test.rs | 18 ++- tests/tlsserver.rs | 1 + 30 files changed, 734 insertions(+), 229 deletions(-) create mode 100644 tests/data/new/ca.crt create mode 100644 tests/data/new/ca.key create mode 100644 tests/data/new/ca.srl create mode 100644 tests/data/new/cert.conf create mode 100644 tests/data/new/client.conf create mode 100644 tests/data/new/client.crt create mode 100644 tests/data/new/client.csr create mode 100644 tests/data/new/client.key create mode 100644 tests/data/new/server.conf create mode 100644 tests/data/new/server.crt create mode 100644 tests/data/new/server.csr create mode 100644 tests/data/new/server.key create mode 100755 tests/data/new/ssl.sh diff --git a/Cargo.toml b/Cargo.toml index 344fd729..03de3440 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,13 +13,20 @@ exclude = [".github"] [dependencies] atomic-polyfill = "1" -p256 = { version = "0.13.2", default-features = false, features = [ "ecdh", "arithmetic" ] } +p256 = { version = "0.13.2", default-features = false, features = [ + "ecdh", + "ecdsa", + "arithmetic", + "sha256", +] } rand_core = { version = "0.6.3", default-features = false } hkdf = "0.12.3" hmac = "0.12.1" sha2 = { version = "0.10.2", default-features = false } aes-gcm = { version = "0.10.1", default-features = false, features = ["aes"] } -digest = { version = "0.10.3", default-features = false, features = ["core-api"] } +digest = { version = "0.10.3", default-features = false, features = [ + "core-api", +] } typenum = { version = "1.15.0", default-features = false } heapless = { version = "0.8", default-features = false } heapless_typenum = { package = "heapless", version = "0.6", default-features = false } @@ -28,13 +35,14 @@ embedded-io-async = "0.6" embedded-io-adapters = { version = "0.6", optional = true } generic-array = { version = "0.14", default-features = false } webpki = { package = "rustls-webpki", version = "0.101.7", default-features = false, optional = true } +ecdsa = { version = "0.16.9", default-features = false } # Logging alternatives log = { version = "0.4", optional = true } defmt = { version = "0.3", optional = true } [dev-dependencies] -env_logger = "0.10" +env_logger = "0.11" tokio = { version = "1", features = ["full"] } mio = { version = "0.8.3", features = ["os-poll", "net"] } rustls = "0.21.6" @@ -44,10 +52,15 @@ rand = "0.8" log = "0.4" pem-parser = "0.1.1" openssl = "0.10.44" +tokio-rustls = "0.24" [features] -default = ["std", "log", "tokio"] +default = ["std", "log", "tokio", "webpki"] defmt = ["dep:defmt", "embedded-io/defmt-03", "heapless/defmt-03"] std = ["embedded-io/std", "embedded-io-async/std"] tokio = ["embedded-io-adapters/tokio-1"] alloc = [] + + +[patch.crates-io] +rustls = { path = "../rustls/rustls" } \ No newline at end of file diff --git a/src/asynch.rs b/src/asynch.rs index 92b344b6..bc15957f 100644 --- a/src/asynch.rs +++ b/src/asynch.rs @@ -9,10 +9,13 @@ use crate::record_reader::RecordReader; use crate::split::{SplitState, SplitStateContainer}; use crate::write_buffer::WriteBuffer; use crate::TlsError; +use ecdsa::elliptic_curve::CurveArithmetic; +use ecdsa::hazmat::SignPrimitive; +use ecdsa::SignatureSize; use embedded_io::Error as _; use embedded_io::ErrorType; use embedded_io_async::{BufRead, Read as AsyncRead, Write as AsyncWrite}; -use rand_core::{CryptoRng, RngCore}; +use generic_array::ArrayLength; pub use crate::config::*; #[cfg(feature = "std")] @@ -71,16 +74,22 @@ where /// /// Returns an error if the handshake does not proceed. If an error occurs, the connection /// instance must be recreated. - pub async fn open<'v, RNG, Verifier>( + pub async fn open<'v, Provider>( &mut self, - context: TlsContext<'v, CipherSuite, RNG>, + mut context: TlsContext<'v, Provider>, ) -> Result<(), TlsError> where - RNG: CryptoRng + RngCore, - Verifier: TlsVerifier<'v, CipherSuite>, + Provider: CryptoProvider, + SignatureSize: + core::ops::Add + ArrayLength, + ecdsa::der::MaxSize: ArrayLength, + ::Scalar: + SignPrimitive, { - let mut handshake: Handshake = - Handshake::new(Verifier::new(context.config.server_name)); + let mut handshake: Handshake = Handshake::new(); + if let Ok(verifier) = context.crypto_provider.verifier() { + verifier.set_hostname_verification(context.config.server_name)?; + } let mut state = State::ClientHello; while state != State::ApplicationData { @@ -92,7 +101,7 @@ where &mut self.record_write_buf, &mut self.key_schedule, context.config, - context.rng, + &mut context.crypto_provider, ) .await?; trace!("State {:?} -> {:?}", state, next_state); diff --git a/src/blocking.rs b/src/blocking.rs index 42c7326d..3de0927b 100644 --- a/src/blocking.rs +++ b/src/blocking.rs @@ -8,9 +8,10 @@ use crate::record::{ClientRecord, ClientRecordHeader}; use crate::record_reader::RecordReader; use crate::split::{SplitState, SplitStateContainer}; use crate::write_buffer::WriteBuffer; +use ecdsa::{elliptic_curve::CurveArithmetic, hazmat::SignPrimitive, SignatureSize}; use embedded_io::Error as _; use embedded_io::{BufRead, ErrorType, Read, Write}; -use rand_core::{CryptoRng, RngCore}; +use generic_array::ArrayLength; pub use crate::config::*; #[cfg(feature = "std")] @@ -70,16 +71,22 @@ where /// /// Returns an error if the handshake does not proceed. If an error occurs, the connection /// instance must be recreated. - pub fn open<'v, RNG, Verifier>( + pub fn open<'v, Provider>( &mut self, - context: TlsContext<'v, CipherSuite, RNG>, + mut context: TlsContext<'v, Provider>, ) -> Result<(), TlsError> where - RNG: CryptoRng + RngCore, - Verifier: TlsVerifier<'v, CipherSuite>, + Provider: CryptoProvider, + SignatureSize: + core::ops::Add + ArrayLength, + ecdsa::der::MaxSize: ArrayLength, + ::Scalar: + SignPrimitive, { - let mut handshake: Handshake = - Handshake::new(Verifier::new(context.config.server_name)); + let mut handshake: Handshake = Handshake::new(); + if let Ok(verifier) = context.crypto_provider.verifier() { + verifier.set_hostname_verification(context.config.server_name)?; + } let mut state = State::ClientHello; while state != State::ApplicationData { @@ -90,7 +97,7 @@ where &mut self.record_write_buf, &mut self.key_schedule, context.config, - context.rng, + &mut context.crypto_provider, )?; trace!("State {:?} -> {:?}", state, next_state); state = next_state; diff --git a/src/config.rs b/src/config.rs index 3e7106f5..afd16e81 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,20 +1,29 @@ +use core::marker::PhantomData; + use crate::cipher_suites::CipherSuite; use crate::extensions::extension_data::signature_algorithms::SignatureScheme; use crate::extensions::extension_data::supported_groups::NamedGroup; use crate::handshake::certificate::CertificateRef; -use crate::handshake::certificate_verify::CertificateVerify; +use crate::handshake::certificate_verify::CertificateVerifyRef; use crate::TlsError; use aes_gcm::{AeadInPlace, Aes128Gcm, Aes256Gcm, KeyInit}; -use core::marker::PhantomData; use digest::core_api::BlockSizeUser; use digest::{Digest, FixedOutput, OutputSizeUser, Reset}; +use ecdsa::signature::RandomizedSigner; use generic_array::ArrayLength; use heapless::Vec; -use rand_core::{CryptoRng, RngCore}; +use p256::NistP256; +use rand_core::CryptoRngCore; pub use sha2::Sha256; pub use sha2::Sha384; use typenum::{Sum, U10, U12, U16, U32}; +use ecdsa::{ + elliptic_curve::{CurveArithmetic, SecretKey}, + hazmat::{DigestPrimitive, SignPrimitive}, + PrimeCurve, SignatureSize, SigningKey, +}; + pub use crate::extensions::extension_data::max_fragment_length::MaxFragmentLength; pub(crate) const TLS_RECORD_MAX: usize = 16384; @@ -70,12 +79,11 @@ pub trait TlsVerifier<'a, CipherSuite> where CipherSuite: TlsCipherSuite, { - /// Create a new verification instance. - /// - /// This method is called for every TLS handshake. - /// /// Host verification is enabled by passing a server hostname. - fn new(host: Option<&'a str>) -> Self; + fn set_hostname_verification( + &mut self, + hostname: Option<&'a str>, + ) -> Result<(), crate::TlsError>; /// Verify a certificate. /// @@ -92,7 +100,7 @@ where /// Verify the certificate signature. /// /// The signature verification uses the transcript and certificate provided earlier to decode the provided signature. - fn verify_signature(&mut self, verify: CertificateVerify) -> Result<(), crate::TlsError>; + fn verify_signature(&mut self, verify: CertificateVerifyRef) -> Result<(), crate::TlsError>; } pub struct NoVerify; @@ -101,8 +109,11 @@ impl<'a, CipherSuite> TlsVerifier<'a, CipherSuite> for NoVerify where CipherSuite: TlsCipherSuite, { - fn new(_host: Option<&str>) -> Self { - Self + fn set_hostname_verification( + &mut self, + _hostname: Option<&'a str>, + ) -> Result<(), crate::TlsError> { + Ok(()) } fn verify_certificate( @@ -114,21 +125,16 @@ where Ok(()) } - fn verify_signature(&mut self, _verify: CertificateVerify) -> Result<(), crate::TlsError> { + fn verify_signature(&mut self, _verify: CertificateVerifyRef) -> Result<(), crate::TlsError> { Ok(()) } } #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct TlsConfig<'a, CipherSuite> -where - CipherSuite: TlsCipherSuite, -{ - //pub(crate) cipher_suites: Vec, +pub struct TlsConfig<'a> { pub(crate) server_name: Option<&'a str>, pub(crate) psk: Option<(&'a [u8], Vec<&'a [u8], 4>)>, - pub(crate) cipher_suite: PhantomData, pub(crate) signature_schemes: Vec, pub(crate) named_groups: Vec, pub(crate) max_fragment_length: Option, @@ -150,34 +156,122 @@ impl TlsClock for NoClock { } #[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct TlsContext<'a, CipherSuite, RNG> +pub struct Signature where - CipherSuite: TlsCipherSuite, - RNG: CryptoRng + RngCore + 'a, + SignatureSize: core::ops::Add + ArrayLength, + ecdsa::der::MaxSize: ArrayLength, { - pub(crate) config: &'a TlsConfig<'a, CipherSuite>, - pub(crate) rng: &'a mut RNG, + signature: ecdsa::der::Signature, +} +impl Signature +where + SignatureSize: core::ops::Add + ArrayLength, + ecdsa::der::MaxSize: ArrayLength, +{ + pub fn to_vec(&self) -> heapless::Vec { + heapless::Vec::from_slice(self.signature.as_bytes()).unwrap() + } } -impl<'a, CipherSuite, RNG> TlsContext<'a, CipherSuite, RNG> +pub struct Signer<'a, T: PrimeCurve, RNG: CryptoRngCore> { + pub secret_key: SecretKey, + pub scheme: SignatureScheme, + pub rng: &'a mut RNG, +} + +impl<'a, T: PrimeCurve, RNG: CryptoRngCore> Signer<'a, T, RNG> where - CipherSuite: TlsCipherSuite, - RNG: CryptoRng + RngCore + 'a, + SignatureSize: core::ops::Add + ArrayLength, + ecdsa::der::MaxSize: ArrayLength, +{ + pub fn sign(&mut self, message: &[u8]) -> Signature + where + T: CurveArithmetic + DigestPrimitive, + ::Scalar: SignPrimitive, + { + let signing_key = SigningKey::from(&self.secret_key); + let signature = signing_key.try_sign_with_rng(self.rng, &message).unwrap(); + + Signature { signature } + } + + pub fn signature_scheme(&self) -> SignatureScheme { + self.scheme + } +} + +pub trait CryptoProvider { + type CipherSuite: TlsCipherSuite; + type SecureRandom: CryptoRngCore; + type SignatureCurve: CurveArithmetic + DigestPrimitive; + + fn rng(&mut self) -> &mut Self::SecureRandom; + + fn verifier(&mut self) -> Result<&mut impl TlsVerifier, crate::TlsError> { + Err::<&mut NoVerify, _>(crate::TlsError::Unimplemented) + } + + /// Decode and validate a private signing key from `key_der`. + fn signer( + &mut self, + _key_der: &[u8], + ) -> Result, crate::TlsError> { + Err::, _>(crate::TlsError::Unimplemented) + } +} + +pub struct SimpleProvider { + rng: RNG, + _marker: PhantomData, +} + +impl SimpleProvider<(), RNG> { + pub fn new(rng: RNG) -> SimpleProvider { + SimpleProvider { + rng, + _marker: PhantomData, + } + } +} + +impl CryptoProvider + for SimpleProvider { - /// Create a new context with a given config and random number generator reference. - pub fn new(config: &'a TlsConfig<'a, CipherSuite>, rng: &'a mut RNG) -> Self { - Self { config, rng } + type CipherSuite = CipherSuite; + type SecureRandom = RNG; + type SignatureCurve = NistP256; + + fn rng(&mut self) -> &mut Self::SecureRandom { + &mut self.rng } } -impl<'a, CipherSuite> TlsConfig<'a, CipherSuite> +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct TlsContext<'a, Provider> where - CipherSuite: TlsCipherSuite, + Provider: CryptoProvider, +{ + pub(crate) config: &'a TlsConfig<'a>, + pub(crate) crypto_provider: Provider, +} + +impl<'a, Provider> TlsContext<'a, Provider> +where + Provider: CryptoProvider, { + /// Create a new context with a given config and a crypto provider. + pub fn new(config: &'a TlsConfig<'a>, crypto_provider: Provider) -> Self { + Self { + config, + crypto_provider, + } + } +} + +impl<'a> TlsConfig<'a> { pub fn new() -> Self { let mut config = Self { - cipher_suite: PhantomData, signature_schemes: Vec::new(), named_groups: Vec::new(), max_fragment_length: None, @@ -188,8 +282,6 @@ where priv_key: None, }; - //config.cipher_suites.push(CipherSuite::TlsAes128GcmSha256); - // if cfg!(feature = "alloc") { config = config.enable_rsa_signatures(); } @@ -294,10 +386,7 @@ where } } -impl<'a, CipherSuite> Default for TlsConfig<'a, CipherSuite> -where - CipherSuite: TlsCipherSuite, -{ +impl<'a> Default for TlsConfig<'a> { fn default() -> Self { TlsConfig::new() } diff --git a/src/connection.rs b/src/connection.rs index 2c31c684..a0d79e7c 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -1,40 +1,28 @@ -use crate::config::{TlsCipherSuite, TlsConfig, TlsVerifier}; -use crate::handshake::certificate_verify::CertificateVerify; +use crate::config::{TlsCipherSuite, TlsConfig}; use crate::handshake::{ClientHandshake, ServerHandshake}; use crate::key_schedule::{KeySchedule, ReadKeySchedule, WriteKeySchedule}; use crate::record::{ClientRecord, ServerRecord}; use crate::record_reader::RecordReader; use crate::write_buffer::WriteBuffer; -use crate::TlsError; use crate::{ alert::*, handshake::{certificate::CertificateRef, certificate_request::CertificateRequest}, }; +use crate::{CertificateVerify, CryptoProvider, TlsError, TlsVerifier}; use core::fmt::Debug; use digest::Digest; +use ecdsa::{elliptic_curve::CurveArithmetic, hazmat::SignPrimitive, SignatureSize}; use embedded_io::Error as _; use embedded_io::{Read as BlockingRead, Write as BlockingWrite}; use embedded_io_async::{Read as AsyncRead, Write as AsyncWrite}; -use rand_core::{CryptoRng, RngCore}; +use generic_array::ArrayLength; use crate::application_data::ApplicationData; -// use crate::handshake::certificate_request::CertificateRequest; -// use crate::handshake::certificate_verify::CertificateVerify; -// 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::buffer::CryptoBuffer; use digest::generic_array::typenum::Unsigned; use p256::ecdh::EphemeralSecret; use crate::content_types::ContentType; -// use crate::handshake::certificate_request::CertificateRequest; -// use crate::handshake::certificate_verify::CertificateVerify; -// 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::parse_buffer::ParseBuffer; use aes_gcm::aead::{AeadCore, AeadInPlace, KeyInit}; @@ -141,27 +129,24 @@ where .map_err(|_| TlsError::InvalidApplicationData) } -pub struct Handshake +pub struct Handshake where CipherSuite: TlsCipherSuite, { traffic_hash: Option, secret: Option, certificate_request: Option, - verifier: Verifier, } -impl<'v, CipherSuite, Verifier> Handshake +impl<'v, CipherSuite> Handshake where CipherSuite: TlsCipherSuite, - Verifier: TlsVerifier<'v, CipherSuite>, { - pub fn new(verifier: Verifier) -> Handshake { + pub fn new() -> Handshake { Handshake { traffic_hash: None, secret: None, certificate_request: None, - verifier, } } } @@ -180,25 +165,29 @@ pub enum State { impl<'a> State { #[allow(clippy::too_many_arguments)] - pub async fn process<'v, Transport, CipherSuite, RNG, Verifier>( + pub async fn process<'v, Transport, Provider>( self, transport: &mut Transport, - handshake: &mut Handshake, - record_reader: &mut RecordReader<'_, CipherSuite>, + handshake: &mut Handshake, + record_reader: &mut RecordReader<'_, Provider::CipherSuite>, tx_buf: &mut WriteBuffer<'_>, - key_schedule: &mut KeySchedule, - config: &TlsConfig<'a, CipherSuite>, - rng: &mut RNG, + key_schedule: &mut KeySchedule, + config: &TlsConfig<'a>, + crypto_provider: &mut Provider, ) -> Result where Transport: AsyncRead + AsyncWrite + 'a, - RNG: CryptoRng + RngCore + 'a, - CipherSuite: TlsCipherSuite, - Verifier: TlsVerifier<'v, CipherSuite>, + Provider: CryptoProvider, + SignatureSize: + core::ops::Add + ArrayLength, + ecdsa::der::MaxSize: ArrayLength, + ::Scalar: + SignPrimitive, { match self { State::ClientHello => { - let (state, tx) = client_hello(key_schedule, config, rng, tx_buf, handshake)?; + let (state, tx) = + client_hello(key_schedule, config, crypto_provider, tx_buf, handshake)?; respond(tx, transport, key_schedule).await?; @@ -218,23 +207,21 @@ impl<'a> State { .read(transport, key_schedule.read_state()) .await?; - let result = process_server_verify(handshake, key_schedule, config, record); + let result = + process_server_verify(handshake, key_schedule, config, crypto_provider, record); handle_processing_error(result, transport, key_schedule, tx_buf).await } State::ClientCert => { - debug!("State::ClientCert"); let (state, tx) = client_cert(handshake, key_schedule, config, tx_buf)?; - debug!("State::ClientCert respond"); respond(tx, transport, key_schedule).await?; Ok(state) } State::ClientCertVerify => { - debug!("State::ClientCertVerify"); - - let (state, tx) = client_cert_verify(handshake, key_schedule, config, tx_buf)?; + let (state, tx) = + client_cert_verify(key_schedule, config, crypto_provider, tx_buf)?; respond(tx, transport, key_schedule).await?; @@ -252,25 +239,29 @@ impl<'a> State { } #[allow(clippy::too_many_arguments)] - pub fn process_blocking<'v, Transport, CipherSuite, RNG, Verifier>( + pub fn process_blocking<'v, Transport, Provider>( self, transport: &mut Transport, - handshake: &mut Handshake, - record_reader: &mut RecordReader<'_, CipherSuite>, + handshake: &mut Handshake, + record_reader: &mut RecordReader<'_, Provider::CipherSuite>, tx_buf: &mut WriteBuffer, - key_schedule: &mut KeySchedule, - config: &TlsConfig<'a, CipherSuite>, - rng: &mut RNG, + key_schedule: &mut KeySchedule, + config: &TlsConfig<'a>, + crypto_provider: &mut Provider, ) -> Result where Transport: BlockingRead + BlockingWrite + 'a, - RNG: CryptoRng + RngCore, - CipherSuite: TlsCipherSuite + 'static, - Verifier: TlsVerifier<'v, CipherSuite>, + Provider: CryptoProvider, + SignatureSize: + core::ops::Add + ArrayLength, + ecdsa::der::MaxSize: ArrayLength, + ::Scalar: + SignPrimitive, { match self { State::ClientHello => { - let (state, tx) = client_hello(key_schedule, config, rng, tx_buf, handshake)?; + let (state, tx) = + client_hello(key_schedule, config, crypto_provider, tx_buf, handshake)?; respond_blocking(tx, transport, key_schedule)?; @@ -286,7 +277,8 @@ impl<'a> State { State::ServerVerify => { let record = record_reader.read_blocking(transport, key_schedule.read_state())?; - let result = process_server_verify(handshake, key_schedule, config, record); + let result = + process_server_verify(handshake, key_schedule, config, crypto_provider, record); handle_processing_error_blocking(result, transport, key_schedule, tx_buf) } @@ -298,7 +290,8 @@ impl<'a> State { Ok(state) } State::ClientCertVerify => { - let (state, tx) = client_cert_verify(handshake, key_schedule, config, tx_buf)?; + let (state, tx) = + client_cert_verify(key_schedule, config, crypto_provider, tx_buf)?; respond_blocking(tx, transport, key_schedule)?; @@ -404,20 +397,19 @@ where Ok(()) } -fn client_hello<'r, CipherSuite, RNG, Verifier>( - key_schedule: &mut KeySchedule, - config: &TlsConfig, - rng: &mut RNG, +fn client_hello<'r, Provider>( + key_schedule: &mut KeySchedule, + config: &TlsConfig, + crypto_provider: &mut Provider, tx_buf: &'r mut WriteBuffer, - handshake: &mut Handshake, + handshake: &mut Handshake, ) -> Result<(State, &'r [u8]), TlsError> where - RNG: CryptoRng + RngCore, - CipherSuite: TlsCipherSuite, + Provider: CryptoProvider, { key_schedule.initialize_early_secret(config.psk.as_ref().map(|p| p.0))?; let (write_key_schedule, read_key_schedule) = key_schedule.as_split(); - let client_hello = ClientRecord::client_hello(config, rng); + let client_hello = ClientRecord::client_hello(config, crypto_provider); let slice = tx_buf.write_record(&client_hello, write_key_schedule, Some(read_key_schedule))?; if let ClientRecord::Handshake(ClientHandshake::ClientHello(client_hello), _) = client_hello { @@ -428,8 +420,8 @@ where } } -fn process_server_hello( - handshake: &mut Handshake, +fn process_server_hello( + handshake: &mut Handshake, key_schedule: &mut KeySchedule, record: ServerRecord<'_, CipherSuite>, ) -> Result @@ -456,15 +448,15 @@ where } } -fn process_server_verify<'a, 'v, CipherSuite, Verifier>( - handshake: &mut Handshake, - key_schedule: &mut KeySchedule, - config: &TlsConfig<'a, CipherSuite>, - record: ServerRecord<'_, CipherSuite>, +fn process_server_verify<'a, 'v, Provider>( + handshake: &mut Handshake, + key_schedule: &mut KeySchedule, + config: &TlsConfig<'a>, + crypto_provider: &mut Provider, + record: ServerRecord<'_, Provider::CipherSuite>, ) -> Result where - CipherSuite: TlsCipherSuite, - Verifier: TlsVerifier<'v, CipherSuite>, + Provider: CryptoProvider, { let mut state = State::ServerVerify; decrypt_record(key_schedule.read_state(), record, |key_schedule, record| { @@ -474,16 +466,20 @@ where ServerHandshake::EncryptedExtensions(_) => {} ServerHandshake::Certificate(certificate) => { let transcript = key_schedule.transcript_hash(); - handshake.verifier.verify_certificate( - transcript, - &config.ca, - certificate, - )?; - debug!("Certificate verified!"); + if let Ok(verifier) = crypto_provider.verifier() { + verifier.verify_certificate(transcript, &config.ca, certificate)?; + debug!("Certificate verified!"); + } else { + debug!("Certificate verification skipped due to no verifier!"); + } } ServerHandshake::CertificateVerify(verify) => { - handshake.verifier.verify_signature(verify)?; - debug!("Signature verified!"); + if let Ok(verifier) = crypto_provider.verifier() { + verifier.verify_signature(verify)?; + debug!("Signature verified!"); + } else { + debug!("Signature verification skipped due to no verifier!"); + } } ServerHandshake::CertificateRequest(request) => { handshake.certificate_request.replace(request.try_into()?); @@ -516,10 +512,10 @@ where Ok(state) } -fn client_cert<'r, CipherSuite, Verifier>( - handshake: &mut Handshake, +fn client_cert<'r, CipherSuite>( + handshake: &mut Handshake, key_schedule: &mut KeySchedule, - config: &TlsConfig, + config: &TlsConfig, buffer: &'r mut WriteBuffer, ) -> Result<(State, &'r [u8]), TlsError> where @@ -553,31 +549,42 @@ where .map(|slice| (next_state, slice)) } -fn client_cert_verify<'r, CipherSuite, Verifier>( - handshake: &mut Handshake, - key_schedule: &mut KeySchedule, - config: &TlsConfig, +fn client_cert_verify<'r, Provider>( + key_schedule: &mut KeySchedule, + config: &TlsConfig, + crypto_provider: &mut Provider, buffer: &'r mut WriteBuffer, ) -> Result<(State, &'r [u8]), TlsError> where - CipherSuite: TlsCipherSuite, + Provider: CryptoProvider, + SignatureSize: + core::ops::Add + ArrayLength, + ecdsa::der::MaxSize: ArrayLength, + ::Scalar: SignPrimitive, { + let hash = key_schedule.transcript_hash().clone().finalize(); + + info!("{:?}", &hash); + let ctx_str = b"TLS 1.3, client CertificateVerify\x00"; let mut msg: heapless::Vec = heapless::Vec::new(); msg.resize(64, 0x20).map_err(|_| TlsError::EncodeError)?; msg.extend_from_slice(ctx_str) .map_err(|_| TlsError::EncodeError)?; - msg.extend_from_slice(&key_schedule.transcript_hash().clone().finalize()) + msg.extend_from_slice(&hash) .map_err(|_| TlsError::EncodeError)?; - debug!("Generating signature"); - // TODO: How to get a hold of something that can sign here? - // let scheme = signer.scheme(); - // let sig = signer.sign(&msg)?; + // FIXME: Remove unwraps! + let mut signing_key = crypto_provider.signer(config.priv_key.unwrap()).unwrap(); + let signature = signing_key.sign(&msg); + + let signature = signature.to_vec(); + + info!("Signature: {:x?}, len: {}", signature, signature.len()); let certificate_verify = CertificateVerify { - signature_scheme: crate::extensions::extension_data::signature_algorithms::SignatureScheme::EcdsaSecp256r1Sha256, - signature: b"abcd", + signature_scheme: signing_key.signature_scheme(), + signature, }; let (write_key_schedule, read_key_schedule) = key_schedule.as_split(); @@ -611,9 +618,9 @@ where ) } -fn client_finished_finalize( +fn client_finished_finalize( key_schedule: &mut KeySchedule, - handshake: &mut Handshake, + handshake: &mut Handshake, ) -> Result where CipherSuite: TlsCipherSuite, diff --git a/src/handshake/certificate_verify.rs b/src/handshake/certificate_verify.rs index 13020d6f..0ffed4c4 100644 --- a/src/handshake/certificate_verify.rs +++ b/src/handshake/certificate_verify.rs @@ -6,13 +6,13 @@ use super::CryptoBuffer; #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CertificateVerify<'a> { +pub struct CertificateVerifyRef<'a> { pub(crate) signature_scheme: SignatureScheme, pub(crate) signature: &'a [u8], } -impl<'a> CertificateVerify<'a> { - pub fn parse(buf: &mut ParseBuffer<'a>) -> Result, TlsError> { +impl<'a> CertificateVerifyRef<'a> { + pub fn parse(buf: &mut ParseBuffer<'a>) -> Result, TlsError> { let signature_scheme = SignatureScheme::parse(buf).map_err(|_| TlsError::InvalidSignatureScheme)?; @@ -26,10 +26,19 @@ impl<'a> CertificateVerify<'a> { signature: signature.as_slice(), }) } +} + +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct CertificateVerify { + pub(crate) signature_scheme: SignatureScheme, + pub(crate) signature: heapless::Vec, +} +impl CertificateVerify { pub(crate) fn encode(&self, buf: &mut CryptoBuffer<'_>) -> Result<(), TlsError> { buf.push_u16(self.signature_scheme as _)?; - buf.with_u16_length(|buf| buf.extend_from_slice(self.signature))?; + buf.with_u16_length(|buf| buf.extend_from_slice(self.signature.as_slice()))?; Ok(()) } } diff --git a/src/handshake/client_hello.rs b/src/handshake/client_hello.rs index 7a0c96b5..c0e4cb68 100644 --- a/src/handshake/client_hello.rs +++ b/src/handshake/client_hello.rs @@ -1,11 +1,12 @@ +use core::marker::PhantomData; + use digest::{Digest, OutputSizeUser}; use heapless::Vec; use p256::ecdh::EphemeralSecret; -use p256::elliptic_curve::rand_core::{CryptoRng, RngCore}; +use p256::elliptic_curve::rand_core::RngCore; use p256::EncodedPoint; use typenum::Unsigned; -use crate::buffer::*; use crate::config::{TlsCipherSuite, TlsConfig}; use crate::extensions::extension_data::key_share::{KeyShareClientHello, KeyShareEntry}; use crate::extensions::extension_data::pre_shared_key::PreSharedKeyClientHello; @@ -20,13 +21,15 @@ use crate::extensions::messages::ClientHelloExtension; use crate::handshake::{Random, LEGACY_VERSION}; use crate::key_schedule::{HashOutputSize, WriteKeySchedule}; use crate::TlsError; +use crate::{buffer::*, CryptoProvider}; pub struct ClientHello<'config, CipherSuite> where CipherSuite: TlsCipherSuite, { - pub(crate) config: &'config TlsConfig<'config, CipherSuite>, + pub(crate) config: &'config TlsConfig<'config>, random: Random, + cipher_suite: PhantomData, pub(crate) secret: EphemeralSecret, } @@ -34,17 +37,18 @@ impl<'config, CipherSuite> ClientHello<'config, CipherSuite> where CipherSuite: TlsCipherSuite, { - pub fn new(config: &'config TlsConfig<'config, CipherSuite>, rng: &mut RNG) -> Self + pub fn new(config: &'config TlsConfig<'config>, provider: &mut Provider) -> Self where - RNG: CryptoRng + RngCore, + Provider: CryptoProvider, { let mut random = [0; 32]; - rng.fill_bytes(&mut random); + provider.rng().fill_bytes(&mut random); Self { config, random, - secret: EphemeralSecret::random(rng), + cipher_suite: PhantomData, + secret: EphemeralSecret::random(provider.rng()), } } diff --git a/src/handshake/mod.rs b/src/handshake/mod.rs index 0b966d3d..5520121d 100644 --- a/src/handshake/mod.rs +++ b/src/handshake/mod.rs @@ -2,7 +2,7 @@ use crate::config::TlsCipherSuite; use crate::handshake::certificate::CertificateRef; use crate::handshake::certificate_request::CertificateRequestRef; -use crate::handshake::certificate_verify::CertificateVerify; +use crate::handshake::certificate_verify::{CertificateVerify, CertificateVerifyRef}; use crate::handshake::client_hello::ClientHello; use crate::handshake::encrypted_extensions::EncryptedExtensions; use crate::handshake::finished::Finished; @@ -70,7 +70,7 @@ where CipherSuite: TlsCipherSuite, { ClientCert(CertificateRef<'a>), - ClientCertVerify(CertificateVerify<'a>), + ClientCertVerify(CertificateVerify), ClientHello(ClientHello<'config, CipherSuite>), Finished(Finished>), } @@ -138,7 +138,7 @@ pub enum ServerHandshake<'a, CipherSuite: TlsCipherSuite> { NewSessionTicket(NewSessionTicket<'a>), Certificate(CertificateRef<'a>), CertificateRequest(CertificateRequestRef<'a>), - CertificateVerify(CertificateVerify<'a>), + CertificateVerify(CertificateVerifyRef<'a>), Finished(Finished>), } @@ -227,7 +227,7 @@ impl<'a, CipherSuite: TlsCipherSuite> ServerHandshake<'a, CipherSuite> { } HandshakeType::CertificateVerify => { - ServerHandshake::CertificateVerify(CertificateVerify::parse(buf)?) + ServerHandshake::CertificateVerify(CertificateVerifyRef::parse(buf)?) } HandshakeType::Finished => { ServerHandshake::Finished(Finished::parse(buf, content_len)?) diff --git a/src/lib.rs b/src/lib.rs index c4eb405b..3c088f98 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,6 +57,10 @@ mod record_reader; mod split; mod write_buffer; +pub use config::{Signature, SimpleProvider}; +pub use extensions::extension_data::signature_algorithms::SignatureScheme; +pub use handshake::certificate_verify::CertificateVerify; + #[cfg(feature = "webpki")] pub mod webpki; @@ -91,6 +95,7 @@ pub enum TlsError { InvalidCertificate, InvalidCertificateEntry, InvalidCertificateRequest, + InvalidPrivateKey, UnableToInitializeCryptoEngine, ParseError(ParseError), OutOfMemory, diff --git a/src/record.rs b/src/record.rs index 24e6fee6..aa12a179 100644 --- a/src/record.rs +++ b/src/record.rs @@ -1,5 +1,4 @@ use crate::application_data::ApplicationData; -use crate::buffer::*; use crate::change_cipher_spec::ChangeCipherSpec; use crate::config::{TlsCipherSuite, TlsConfig}; use crate::content_types::ContentType; @@ -8,8 +7,8 @@ use crate::handshake::{ClientHandshake, ServerHandshake}; use crate::key_schedule::WriteKeySchedule; use crate::TlsError; use crate::{alert::*, parse_buffer::ParseBuffer}; +use crate::{buffer::*, CryptoProvider}; use core::fmt::Debug; -use rand_core::{CryptoRng, RngCore}; pub type Encrypted = bool; @@ -103,15 +102,15 @@ where } } - pub fn client_hello( - config: &'config TlsConfig<'config, CipherSuite>, - rng: &mut RNG, + pub fn client_hello( + config: &'config TlsConfig<'config>, + provider: &mut Provider, ) -> Self where - RNG: CryptoRng + RngCore, + Provider: CryptoProvider, { ClientRecord::Handshake( - ClientHandshake::ClientHello(ClientHello::new(config, rng)), + ClientHandshake::ClientHello(ClientHello::new(config, provider)), false, ) } diff --git a/src/webpki.rs b/src/webpki.rs index 9079cee7..4a1d9159 100644 --- a/src/webpki.rs +++ b/src/webpki.rs @@ -4,7 +4,7 @@ use crate::handshake::{ certificate::{ Certificate as OwnedCertificate, CertificateEntryRef, CertificateRef as ServerCertificate, }, - certificate_verify::CertificateVerify, + certificate_verify::CertificateVerifyRef, }; use crate::TlsError; use core::marker::PhantomData; @@ -100,20 +100,34 @@ where _clock: PhantomData, } -impl<'a, CipherSuite, Clock, const CERT_SIZE: usize> TlsVerifier<'a, CipherSuite> - for CertVerifier<'a, CipherSuite, Clock, CERT_SIZE> +impl<'a, CipherSuite, Clock, const CERT_SIZE: usize> CertVerifier<'a, CipherSuite, Clock, CERT_SIZE> where - CipherSuite: TlsCipherSuite, Clock: TlsClock, + CipherSuite: TlsCipherSuite, { - fn new(host: Option<&'a str>) -> Self { + fn new() -> Self { Self { - host, + host: None, certificate_transcript: None, certificate: None, _clock: PhantomData, } } +} + +impl<'a, CipherSuite, Clock, const CERT_SIZE: usize> TlsVerifier<'a, CipherSuite> + for CertVerifier<'a, CipherSuite, Clock, CERT_SIZE> +where + CipherSuite: TlsCipherSuite, + Clock: TlsClock, +{ + fn set_hostname_verification( + &mut self, + hostname: Option<&'a str>, + ) -> Result<(), crate::TlsError> { + self.host = hostname; + Ok(()) + } fn verify_certificate( &mut self, @@ -127,7 +141,7 @@ where Ok(()) } - fn verify_signature(&mut self, verify: CertificateVerify) -> Result<(), TlsError> { + fn verify_signature(&mut self, verify: CertificateVerifyRef) -> Result<(), TlsError> { let handshake_hash = unwrap!(self.certificate_transcript.take()); let ctx_str = b"TLS 1.3, server CertificateVerify\x00"; let mut msg: Vec = Vec::new(); @@ -143,10 +157,10 @@ where } } -fn verify_signature( +pub fn verify_signature( message: &[u8], certificate: ServerCertificate, - verify: CertificateVerify, + verify: CertificateVerifyRef, ) -> Result<(), TlsError> { let mut verified = false; if !certificate.entries.is_empty() { @@ -179,7 +193,7 @@ fn verify_signature( Ok(()) } -fn verify_certificate( +pub fn verify_certificate( verify_host: Option<&str>, ca: &Option, certificate: &ServerCertificate, diff --git a/tests/client_cert_test.rs b/tests/client_cert_test.rs index 1905baff..b9b4dffe 100644 --- a/tests/client_cert_test.rs +++ b/tests/client_cert_test.rs @@ -1,9 +1,12 @@ -#![macro_use] +use ecdsa::elliptic_curve::SecretKey; use embedded_io_adapters::tokio_1::FromTokio; +use embedded_tls::{CryptoProvider, SignatureScheme, Signer}; use rand::rngs::OsRng; use rustls::server::AllowAnyAuthenticatedClient; +use rustls::ClientConfig; use std::net::SocketAddr; use std::sync::Once; +use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _}; mod tlsserver; @@ -35,11 +38,12 @@ fn setup() -> SocketAddr { let test_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests"); - let certs = load_certs(&test_dir.join("data").join("server-cert.pem")); - let privkey = load_private_key(&test_dir.join("data").join("server-key.pem")); + let ca = load_certs(&test_dir.join("data").join("new").join("ca.crt")); + let certs = load_certs(&test_dir.join("data").join("new").join("server.crt")); + let privkey = load_private_key(&test_dir.join("data").join("new").join("server.key")); let mut client_auth_roots = rustls::RootCertStore::empty(); - for root in certs.iter() { + for root in ca.iter() { client_auth_roots.add(root).unwrap() } @@ -61,18 +65,46 @@ fn setup() -> SocketAddr { unsafe { ADDR.unwrap() } } +#[derive(Default)] +struct Provider { + rng: OsRng, +} + +impl CryptoProvider for Provider { + type CipherSuite = embedded_tls::Aes128GcmSha256; + type SecureRandom = OsRng; + type SignatureCurve = p256::NistP256; + + fn rng(&mut self) -> &mut Self::SecureRandom { + &mut self.rng + } + + fn signer( + &mut self, + key_der: &[u8], + ) -> Result, embedded_tls::TlsError> { + Ok(Signer { + secret_key: SecretKey::from_sec1_der(key_der) + .map_err(|_| embedded_tls::TlsError::InvalidPrivateKey)?, + scheme: SignatureScheme::EcdsaSecp256r1Sha256, + rng: &mut self.rng, + }) + } +} + #[tokio::test] async fn test_client_certificate_auth() { use embedded_tls::*; use tokio::net::TcpStream; let addr = setup(); - let ca_pem = include_str!("data/ca-cert.pem"); + + let ca_pem = include_str!("data/new/ca.crt"); let ca_der = pem_parser::pem_to_der(ca_pem); - let client_cert_pem = include_str!("data/client-cert.pem"); + let client_cert_pem = include_str!("data/new/client.crt"); let client_cert_der = pem_parser::pem_to_der(client_cert_pem); - let private_key_pem = include_str!("data/client-key.pem"); + let private_key_pem = include_str!("data/new/client.key"); let private_key_der = pem_parser::pem_to_der(private_key_pem); let stream = TcpStream::connect(addr) @@ -86,9 +118,9 @@ async fn test_client_certificate_auth() { .with_ca(Certificate::X509(&ca_der)) .with_cert(Certificate::X509(&client_cert_der)) .with_priv_key(&private_key_der) - .with_server_name("localhost"); + .with_server_name("factbird.com"); - let mut tls: TlsConnection, Aes128GcmSha256> = TlsConnection::new( + let mut tls = TlsConnection::new( FromTokio::new(stream), &mut read_record_buffer, &mut write_record_buffer, @@ -96,8 +128,7 @@ async fn test_client_certificate_auth() { log::info!("SIZE of connection is {}", core::mem::size_of_val(&tls)); - let mut rng = OsRng; - let open_fut = tls.open::(TlsContext::new(&config, &mut rng)); + let open_fut = tls.open(TlsContext::new(&config, Provider::default())); log::info!("SIZE of open fut is {}", core::mem::size_of_val(&open_fut)); open_fut.await.expect("error establishing TLS connection"); log::info!("Established"); @@ -135,3 +166,45 @@ async fn test_client_certificate_auth() { .map_err(|(_, e)| e) .expect("error closing session"); } + +#[tokio::test] +async fn test_client_certificate_auth_rustls() { + let addr = setup(); + + let test_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests"); + + let ca = tlsserver::load_certs(&test_dir.join("data").join("new").join("ca.crt")); + let certs = tlsserver::load_certs(&test_dir.join("data").join("new").join("client.crt")); + let privkey = + tlsserver::load_private_key(&test_dir.join("data").join("new").join("client.key")); + + let mut root_store = rustls::RootCertStore::empty(); + for root in ca.iter() { + root_store.add(root).unwrap() + } + + let config = ClientConfig::builder() + .with_cipher_suites(&[rustls::cipher_suite::TLS13_AES_128_GCM_SHA256]) + .with_kx_groups(&rustls::ALL_KX_GROUPS) + .with_protocol_versions(&[&rustls::version::TLS13]) + .unwrap() + .with_root_certificates(root_store) + .with_client_auth_cert(certs, privkey) + .unwrap(); + + let connector = tokio_rustls::TlsConnector::from(std::sync::Arc::new(config)); + let dnsname = rustls::ServerName::try_from("factbird.com").unwrap(); + + let stream = tokio::net::TcpStream::connect(&addr).await.unwrap(); + let mut tls = connector.connect(dnsname, stream).await.unwrap(); + + tls.write(b"ping").await.expect("error writing data"); + tls.flush().await.expect("error flushing data"); + + // Make sure reading into a 0 length buffer doesn't loop + let mut rx_buf = [0; 4096]; + let sz = tls.read(&mut rx_buf).await.expect("error reading data"); + assert_eq!(sz, 4); + assert_eq!(b"ping", &rx_buf[..sz]); + log::info!("Read {} bytes: {:?}", sz, &rx_buf[..sz]); +} diff --git a/tests/client_test.rs b/tests/client_test.rs index d27fa1b9..2ed116a0 100644 --- a/tests/client_test.rs +++ b/tests/client_test.rs @@ -54,14 +54,16 @@ async fn test_google() { let mut write_record_buffer = [0; 16384]; let config = TlsConfig::new().with_server_name("google.com"); - let mut tls: TlsConnection, Aes128GcmSha256> = TlsConnection::new( + let mut tls = TlsConnection::new( FromTokio::new(stream), &mut read_record_buffer, &mut write_record_buffer, ); - let mut rng = OsRng; - let open_fut = tls.open::(TlsContext::new(&config, &mut rng)); + let open_fut = tls.open(TlsContext::new( + &config, + SimpleProvider::new::(OsRng), + )); log::info!("SIZE of open fut is {}", core::mem::size_of_val(&open_fut)); open_fut.await.expect("error establishing TLS connection"); log::info!("Established"); @@ -100,7 +102,7 @@ async fn test_ping() { .with_ca(Certificate::X509(&der[..])) .with_server_name("localhost"); - let mut tls: TlsConnection, Aes128GcmSha256> = TlsConnection::new( + let mut tls = TlsConnection::new( FromTokio::new(stream), &mut read_record_buffer, &mut write_record_buffer, @@ -108,8 +110,10 @@ async fn test_ping() { log::info!("SIZE of connection is {}", core::mem::size_of_val(&tls)); - let mut rng = OsRng; - let open_fut = tls.open::(TlsContext::new(&config, &mut rng)); + let open_fut = tls.open(TlsContext::new( + &config, + SimpleProvider::new::(OsRng), + )); log::info!("SIZE of open fut is {}", core::mem::size_of_val(&open_fut)); open_fut.await.expect("error establishing TLS connection"); log::info!("Established"); @@ -167,7 +171,7 @@ async fn test_ping_nocopy() { .with_ca(Certificate::X509(&der[..])) .with_server_name("localhost"); - let mut tls: TlsConnection, Aes128GcmSha256> = TlsConnection::new( + let mut tls = TlsConnection::new( FromTokio::new(stream), &mut read_record_buffer, &mut write_record_buffer, @@ -175,8 +179,10 @@ async fn test_ping_nocopy() { log::info!("SIZE of connection is {}", core::mem::size_of_val(&tls)); - let mut rng = OsRng; - let open_fut = tls.open::(TlsContext::new(&config, &mut rng)); + let open_fut = tls.open(TlsContext::new( + &config, + SimpleProvider::new::(OsRng), + )); log::info!("SIZE of open fut is {}", core::mem::size_of_val(&open_fut)); open_fut.await.expect("error establishing TLS connection"); log::info!("Established"); @@ -237,15 +243,17 @@ async fn test_ping_nocopy_bufread() { .with_ca(Certificate::X509(&der[..])) .with_server_name("localhost"); - let mut tls: TlsConnection, Aes128GcmSha256> = TlsConnection::new( + let mut tls = TlsConnection::new( FromTokio::new(stream), &mut read_record_buffer, &mut write_record_buffer, ); - - tls.open::(TlsContext::new(&config, &mut OsRng)) - .await - .expect("error establishing TLS connection"); + tls.open(TlsContext::new( + &config, + SimpleProvider::new::(OsRng), + )) + .await + .expect("error establishing TLS connection"); log::info!("Established"); tls.write(b"ping").await.expect("error writing data"); @@ -287,9 +295,11 @@ fn test_blocking_ping() { &mut read_record_buffer, &mut write_record_buffer, ); - - tls.open::(TlsContext::new(&config, &mut OsRng)) - .expect("error establishing TLS connection"); + tls.open(TlsContext::new( + &config, + SimpleProvider::new::(OsRng), + )) + .expect("error establishing TLS connection"); log::info!("Established"); tls.write(b"ping").expect("error writing data"); @@ -338,9 +348,11 @@ fn test_blocking_ping_nocopy() { &mut read_record_buffer, &mut write_record_buffer, ); - - tls.open::(TlsContext::new(&config, &mut OsRng)) - .expect("error establishing TLS connection"); + tls.open(TlsContext::new( + &config, + SimpleProvider::new::(OsRng), + )) + .expect("error establishing TLS connection"); log::info!("Established"); tls.write(b"ping").expect("error writing data"); @@ -383,9 +395,11 @@ fn test_blocking_ping_nocopy_bufread() { &mut read_record_buffer, &mut write_record_buffer, ); - - tls.open::(TlsContext::new(&config, &mut OsRng)) - .expect("error establishing TLS connection"); + tls.open(TlsContext::new( + &config, + SimpleProvider::new::(OsRng), + )) + .expect("error establishing TLS connection"); log::info!("Established"); tls.write(b"ping").expect("error writing data"); diff --git a/tests/data/new/ca.crt b/tests/data/new/ca.crt new file mode 100644 index 00000000..816e604e --- /dev/null +++ b/tests/data/new/ca.crt @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBzTCCAXOgAwIBAgIUPD9fJNyOJr+zjxiNWW6KnMPQiMIwCgYIKoZIzj0EAwIw +PDEVMBMGA1UEAwwMZmFjdGJpcmQuY29tMQswCQYDVQQGEwJVUzEWMBQGA1UEBwwN +U2FuIEZyYW5zaXNjbzAeFw0yNDAyMTQxMTE1MTZaFw0yNDAzMTUxMTE1MTZaMDwx +FTATBgNVBAMMDGZhY3RiaXJkLmNvbTELMAkGA1UEBhMCVVMxFjAUBgNVBAcMDVNh +biBGcmFuc2lzY28wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARb2+jh+8VHAJJi +ElVVxwpJJbvoEiLEaR2v9A8Tr2lIP25D2XgCD+bRU6VeU5CyvagS+z5xPxXWWJxI +0taaLTXlo1MwUTAdBgNVHQ4EFgQUmNoB7B3c/jr2Z1iPW/5AT8lW4BowHwYDVR0j +BBgwFoAUmNoB7B3c/jr2Z1iPW/5AT8lW4BowDwYDVR0TAQH/BAUwAwEB/zAKBggq +hkjOPQQDAgNIADBFAiAYl7Yr02WNeOIKu9rozt559KynFm4kQdiFFlZTvjIfQQIh +AL6XLLwRd+Dz254VMv487DU5jKFGDMOF75K7KW6rsfxx +-----END CERTIFICATE----- diff --git a/tests/data/new/ca.key b/tests/data/new/ca.key new file mode 100644 index 00000000..ceeb71c4 --- /dev/null +++ b/tests/data/new/ca.key @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIJoJGgohVbLxsbmRlgYNKvTuTpyXMXsei76CdcBzj296oAoGCCqGSM49 +AwEHoUQDQgAEW9vo4fvFRwCSYhJVVccKSSW76BIixGkdr/QPE69pSD9uQ9l4Ag/m +0VOlXlOQsr2oEvs+cT8V1licSNLWmi015Q== +-----END EC PRIVATE KEY----- diff --git a/tests/data/new/ca.srl b/tests/data/new/ca.srl new file mode 100644 index 00000000..bcac8d38 --- /dev/null +++ b/tests/data/new/ca.srl @@ -0,0 +1 @@ +12C91A34CFE606D84185DA612B3BD751A670F9E5 diff --git a/tests/data/new/cert.conf b/tests/data/new/cert.conf new file mode 100644 index 00000000..c1bfdcd3 --- /dev/null +++ b/tests/data/new/cert.conf @@ -0,0 +1,9 @@ + +authorityKeyIdentifier=keyid,issuer +basicConstraints=CA:FALSE +keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment +subjectAltName = @alt_names + +[alt_names] +DNS.1 = factbird.com + diff --git a/tests/data/new/client.conf b/tests/data/new/client.conf new file mode 100644 index 00000000..690ff5e7 --- /dev/null +++ b/tests/data/new/client.conf @@ -0,0 +1,24 @@ +[ req ] +default_bits = 2048 +prompt = no +default_md = sha256 +req_extensions = req_ext +distinguished_name = dn + +[ dn ] +C = US +ST = California +L = San Fransisco +O = MLopsHub +OU = MlopsHub Dev +CN = factbird.com + +[ req_ext ] +subjectAltName = @alt_names + +[ alt_names ] +DNS.1 = factbird.com +DNS.2 = www.factbird.com +IP.1 = 192.168.1.5 +IP.2 = 192.168.1.6 + diff --git a/tests/data/new/client.crt b/tests/data/new/client.crt new file mode 100644 index 00000000..7359f274 --- /dev/null +++ b/tests/data/new/client.crt @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICLDCCAdKgAwIBAgIUEskaNM/mBthBhdphKzvXUaZw+eUwCgYIKoZIzj0EAwIw +PDEVMBMGA1UEAwwMZmFjdGJpcmQuY29tMQswCQYDVQQGEwJVUzEWMBQGA1UEBwwN +U2FuIEZyYW5zaXNjbzAeFw0yNDAyMTQxMTE1MTZaFw0yNjExMTAxMTE1MTZaMHsx +CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4g +RnJhbnNpc2NvMREwDwYDVQQKDAhNTG9wc0h1YjEVMBMGA1UECwwMTWxvcHNIdWIg +RGV2MRUwEwYDVQQDDAxmYWN0YmlyZC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMB +BwNCAARfzUjGqE5M1GuecOOeUlccNkWmPSMJc7vfCtw76KutDQKdZZRJrWwK3+9E +C+AgK0IqNxULozZvTHD5x7EFPpRRo3MwcTAfBgNVHSMEGDAWgBSY2gHsHdz+OvZn +WI9b/kBPyVbgGjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DAXBgNVHREEEDAOggxm +YWN0YmlyZC5jb20wHQYDVR0OBBYEFKobp1jvdFe7LtSrjEfaNrw0+6CaMAoGCCqG +SM49BAMCA0gAMEUCIQD4JCTjQrpfuo42EJlA5Ty3RE8w/GLPHJGISDZOn7Tu+QIg +XDbaXgII/elrXGt7WbX1bcd4UwGVdtjVDbAxR37JkWI= +-----END CERTIFICATE----- diff --git a/tests/data/new/client.csr b/tests/data/new/client.csr new file mode 100644 index 00000000..d0fe2bcd --- /dev/null +++ b/tests/data/new/client.csr @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBfjCCASUCAQAwezELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx +FjAUBgNVBAcMDVNhbiBGcmFuc2lzY28xETAPBgNVBAoMCE1Mb3BzSHViMRUwEwYD +VQQLDAxNbG9wc0h1YiBEZXYxFTATBgNVBAMMDGZhY3RiaXJkLmNvbTBZMBMGByqG +SM49AgEGCCqGSM49AwEHA0IABF/NSMaoTkzUa55w455SVxw2RaY9Iwlzu98K3Dvo +q60NAp1llEmtbArf70QL4CArQio3FQujNm9McPnHsQU+lFGgSDBGBgkqhkiG9w0B +CQ4xOTA3MDUGA1UdEQQuMCyCDGZhY3RiaXJkLmNvbYIQd3d3LmZhY3RiaXJkLmNv +bYcEwKgBBYcEwKgBBjAKBggqhkjOPQQDAgNHADBEAiBWJQ+l6qkKISss7U/hH2Nj +DHGKXUZUMnAFGzwAlJZQsAIgD+hkJjpig4SgpQrpt+PbktCAfZaoJGSAr0NzqMMM ++9M= +-----END CERTIFICATE REQUEST----- diff --git a/tests/data/new/client.key b/tests/data/new/client.key new file mode 100644 index 00000000..03324af9 --- /dev/null +++ b/tests/data/new/client.key @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEINLKEwvN7SYoo8s4ZQuYnNfnph7cSZJIWvPryHH4Mz96oAoGCCqGSM49 +AwEHoUQDQgAEX81IxqhOTNRrnnDjnlJXHDZFpj0jCXO73wrcO+irrQ0CnWWUSa1s +Ct/vRAvgICtCKjcVC6M2b0xw+cexBT6UUQ== +-----END EC PRIVATE KEY----- diff --git a/tests/data/new/server.conf b/tests/data/new/server.conf new file mode 100644 index 00000000..690ff5e7 --- /dev/null +++ b/tests/data/new/server.conf @@ -0,0 +1,24 @@ +[ req ] +default_bits = 2048 +prompt = no +default_md = sha256 +req_extensions = req_ext +distinguished_name = dn + +[ dn ] +C = US +ST = California +L = San Fransisco +O = MLopsHub +OU = MlopsHub Dev +CN = factbird.com + +[ req_ext ] +subjectAltName = @alt_names + +[ alt_names ] +DNS.1 = factbird.com +DNS.2 = www.factbird.com +IP.1 = 192.168.1.5 +IP.2 = 192.168.1.6 + diff --git a/tests/data/new/server.crt b/tests/data/new/server.crt new file mode 100644 index 00000000..7ee58f05 --- /dev/null +++ b/tests/data/new/server.crt @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICLDCCAdKgAwIBAgIUEskaNM/mBthBhdphKzvXUaZw+eQwCgYIKoZIzj0EAwIw +PDEVMBMGA1UEAwwMZmFjdGJpcmQuY29tMQswCQYDVQQGEwJVUzEWMBQGA1UEBwwN +U2FuIEZyYW5zaXNjbzAeFw0yNDAyMTQxMTE1MTZaFw0yNjExMTAxMTE1MTZaMHsx +CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4g +RnJhbnNpc2NvMREwDwYDVQQKDAhNTG9wc0h1YjEVMBMGA1UECwwMTWxvcHNIdWIg +RGV2MRUwEwYDVQQDDAxmYWN0YmlyZC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMB +BwNCAAQcVSNxt0Va0eGP5ZuAdO+nsL3D0NvkNAYlOKY+fAIdYfSGBrgo7U3evWcj ++k9UM0R+9qKWro9pNqBdSYbOxKTlo3MwcTAfBgNVHSMEGDAWgBSY2gHsHdz+OvZn +WI9b/kBPyVbgGjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DAXBgNVHREEEDAOggxm +YWN0YmlyZC5jb20wHQYDVR0OBBYEFIo1QWMzUtrGi8BxiHRjZsAygkpRMAoGCCqG +SM49BAMCA0gAMEUCIDgDqeBlzzQ+uTBhFUhzSpfiG5eWuh9n5p7nIumf8mAaAiEA +sxGDXrSL2na7h07sWi2h+xB92KyGIyCtDtrT2AhIzEk= +-----END CERTIFICATE----- diff --git a/tests/data/new/server.csr b/tests/data/new/server.csr new file mode 100644 index 00000000..8979c448 --- /dev/null +++ b/tests/data/new/server.csr @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBgDCCASUCAQAwezELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx +FjAUBgNVBAcMDVNhbiBGcmFuc2lzY28xETAPBgNVBAoMCE1Mb3BzSHViMRUwEwYD +VQQLDAxNbG9wc0h1YiBEZXYxFTATBgNVBAMMDGZhY3RiaXJkLmNvbTBZMBMGByqG +SM49AgEGCCqGSM49AwEHA0IABBxVI3G3RVrR4Y/lm4B076ewvcPQ2+Q0BiU4pj58 +Ah1h9IYGuCjtTd69ZyP6T1QzRH72opauj2k2oF1Jhs7EpOWgSDBGBgkqhkiG9w0B +CQ4xOTA3MDUGA1UdEQQuMCyCDGZhY3RiaXJkLmNvbYIQd3d3LmZhY3RiaXJkLmNv +bYcEwKgBBYcEwKgBBjAKBggqhkjOPQQDAgNJADBGAiEAoUNDV90xYiQG8oeOXF8L +gm0LJPVEnFieNTFcWXHpoI8CIQD/B2D9m437FbMapCO1dy8FvkqH00gLhqRbNGYY +16U6jA== +-----END CERTIFICATE REQUEST----- diff --git a/tests/data/new/server.key b/tests/data/new/server.key new file mode 100644 index 00000000..fdaea5bf --- /dev/null +++ b/tests/data/new/server.key @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIFumcDr3XLOin21fWEG4BeOONG2k1W1PrUAGMMCaDIyWoAoGCCqGSM49 +AwEHoUQDQgAEHFUjcbdFWtHhj+WbgHTvp7C9w9Db5DQGJTimPnwCHWH0hga4KO1N +3r1nI/pPVDNEfvailq6PaTagXUmGzsSk5Q== +-----END EC PRIVATE KEY----- diff --git a/tests/data/new/ssl.sh b/tests/data/new/ssl.sh new file mode 100755 index 00000000..b892c07f --- /dev/null +++ b/tests/data/new/ssl.sh @@ -0,0 +1,115 @@ +#! /bin/bash + +if [ "$#" -ne 1 ] +then + echo "Error: No domain name argument provided" + echo "Usage: Provide a domain name as an argument" + exit 1 +fi + +DOMAIN=$1 + +# Create root CA & Private key +openssl ecparam -name prime256v1 -genkey -noout -out ca.key +openssl req -new -x509 -sha256 -key ca.key -out ca.crt -subj "/CN=${DOMAIN}/C=US/L=San Fransisco" + +# Create server csr conf + +cat > server.conf < cert.conf < client.conf < cert.conf <, Aes128GcmSha256> = TlsConnection::new( + let mut tls = TlsConnection::new( FromStd::new(stream), &mut read_record_buffer, &mut write_record_buffer, ); - tls.open::(TlsContext::new(&config, &mut OsRng)) - .expect("error establishing TLS connection"); + tls.open(TlsContext::new( + &config, + SimpleProvider::new::(OsRng), + )) + .expect("error establishing TLS connection"); tls.write_all(b"ping").expect("Failed to write data"); tls.flush().expect("Failed to flush"); diff --git a/tests/psk_test.rs b/tests/psk_test.rs index 74510aec..c56a3288 100644 --- a/tests/psk_test.rs +++ b/tests/psk_test.rs @@ -75,15 +75,17 @@ async fn test_psk_open() { .with_psk(&[0xaa, 0xbb, 0xcc, 0xdd], &[b"vader"]) .with_server_name("localhost"); - let mut tls: TlsConnection, Aes128GcmSha256> = TlsConnection::new( + let mut tls = TlsConnection::new( FromTokio::new(stream), &mut read_record_buffer, &mut write_record_buffer, ); - let mut rng = OsRng; assert!(tls - .open::(TlsContext::new(&config, &mut rng)) + .open(TlsContext::new( + &config, + SimpleProvider::new::(OsRng) + )) .await .is_ok()); println!("TLS session opened"); diff --git a/tests/split_test.rs b/tests/split_test.rs index 69d8d4a3..daf3b9c0 100644 --- a/tests/split_test.rs +++ b/tests/split_test.rs @@ -78,14 +78,17 @@ fn test_blocking_borrowed() { .with_ca(Certificate::X509(&der[..])) .with_server_name("localhost"); - let mut tls: TlsConnection, Aes128GcmSha256> = TlsConnection::new( + let mut tls = TlsConnection::new( Clonable(Arc::new(stream)), &mut read_record_buffer, &mut write_record_buffer, ); - tls.open::(TlsContext::new(&config, &mut OsRng)) - .expect("error establishing TLS connection"); + tls.open(TlsContext::new( + &config, + SimpleProvider::new::(OsRng), + )) + .expect("error establishing TLS connection"); let mut state = SplitConnectionState::default(); let (mut reader, mut writer) = tls.split_with(&mut state); @@ -126,14 +129,17 @@ fn test_blocking_managed() { .with_ca(Certificate::X509(&der[..])) .with_server_name("localhost"); - let mut tls: TlsConnection, Aes128GcmSha256> = TlsConnection::new( + let mut tls = TlsConnection::new( Clonable(Arc::new(stream)), &mut read_record_buffer, &mut write_record_buffer, ); - tls.open::(TlsContext::new(&config, &mut OsRng)) - .expect("error establishing TLS connection"); + tls.open(TlsContext::new( + &config, + SimpleProvider::new::(OsRng), + )) + .expect("error establishing TLS connection"); let (mut reader, mut writer) = tls.split(); diff --git a/tests/tlsserver.rs b/tests/tlsserver.rs index ad6f4973..46510fb0 100644 --- a/tests/tlsserver.rs +++ b/tests/tlsserver.rs @@ -342,6 +342,7 @@ pub fn load_private_key(filename: &PathBuf) -> rustls::PrivateKey { match rustls_pemfile::read_one(&mut reader).expect("cannot parse private key .pem file") { Some(rustls_pemfile::Item::RSAKey(key)) => return rustls::PrivateKey(key), Some(rustls_pemfile::Item::PKCS8Key(key)) => return rustls::PrivateKey(key), + Some(rustls_pemfile::Item::ECKey(key)) => return rustls::PrivateKey(key), None => break, _ => {} } From f3c82f0bf4a37074c261e9ee8b266c99f28508b5 Mon Sep 17 00:00:00 2001 From: Mathias Date: Wed, 14 Feb 2024 19:36:38 +0100 Subject: [PATCH 06/19] Remove webpki as default feature again --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 03de3440..5b7c51f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,7 @@ openssl = "0.10.44" tokio-rustls = "0.24" [features] -default = ["std", "log", "tokio", "webpki"] +default = ["std", "log", "tokio"] defmt = ["dep:defmt", "embedded-io/defmt-03", "heapless/defmt-03"] std = ["embedded-io/std", "embedded-io-async/std"] tokio = ["embedded-io-adapters/tokio-1"] From c8d634dd9b190ca68f6fa00b7c3a6deb1fa7344f Mon Sep 17 00:00:00 2001 From: Mathias Date: Wed, 14 Feb 2024 19:58:18 +0100 Subject: [PATCH 07/19] Use full buffer to update transcript on finalize_encrypted --- src/handshake/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/handshake/mod.rs b/src/handshake/mod.rs index 5520121d..9cf7f0a5 100644 --- a/src/handshake/mod.rs +++ b/src/handshake/mod.rs @@ -126,8 +126,7 @@ where ) -> Result<(), TlsError> { let enc_buf = buf.as_slice(); let end = enc_buf.len(); - // Don't include the content type in the slice - transcript.update(&enc_buf[0..end - 1]); + transcript.update(&enc_buf[0..end]); Ok(()) } } From 1718c0a134436937689130892f355bae962d0a57 Mon Sep 17 00:00:00 2001 From: Mathias Date: Wed, 14 Feb 2024 20:04:03 +0100 Subject: [PATCH 08/19] Revert to old test certificates and remove rustls client test --- Cargo.toml | 5 -- tests/client_cert_test.rs | 56 ++---------------- tests/data/new/ca.crt | 12 ---- tests/data/new/ca.key | 5 -- tests/data/new/ca.srl | 1 - tests/data/new/cert.conf | 9 --- tests/data/new/client.conf | 24 -------- tests/data/new/client.crt | 14 ----- tests/data/new/client.csr | 11 ---- tests/data/new/client.key | 5 -- tests/data/new/server.conf | 24 -------- tests/data/new/server.crt | 14 ----- tests/data/new/server.csr | 11 ---- tests/data/new/server.key | 5 -- tests/data/new/ssl.sh | 115 ------------------------------------- 15 files changed, 6 insertions(+), 305 deletions(-) delete mode 100644 tests/data/new/ca.crt delete mode 100644 tests/data/new/ca.key delete mode 100644 tests/data/new/ca.srl delete mode 100644 tests/data/new/cert.conf delete mode 100644 tests/data/new/client.conf delete mode 100644 tests/data/new/client.crt delete mode 100644 tests/data/new/client.csr delete mode 100644 tests/data/new/client.key delete mode 100644 tests/data/new/server.conf delete mode 100644 tests/data/new/server.crt delete mode 100644 tests/data/new/server.csr delete mode 100644 tests/data/new/server.key delete mode 100755 tests/data/new/ssl.sh diff --git a/Cargo.toml b/Cargo.toml index 5b7c51f2..175471a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,6 @@ rand = "0.8" log = "0.4" pem-parser = "0.1.1" openssl = "0.10.44" -tokio-rustls = "0.24" [features] default = ["std", "log", "tokio"] @@ -60,7 +59,3 @@ defmt = ["dep:defmt", "embedded-io/defmt-03", "heapless/defmt-03"] std = ["embedded-io/std", "embedded-io-async/std"] tokio = ["embedded-io-adapters/tokio-1"] alloc = [] - - -[patch.crates-io] -rustls = { path = "../rustls/rustls" } \ No newline at end of file diff --git a/tests/client_cert_test.rs b/tests/client_cert_test.rs index b9b4dffe..4d094c13 100644 --- a/tests/client_cert_test.rs +++ b/tests/client_cert_test.rs @@ -3,10 +3,8 @@ use embedded_io_adapters::tokio_1::FromTokio; use embedded_tls::{CryptoProvider, SignatureScheme, Signer}; use rand::rngs::OsRng; use rustls::server::AllowAnyAuthenticatedClient; -use rustls::ClientConfig; use std::net::SocketAddr; use std::sync::Once; -use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _}; mod tlsserver; @@ -38,9 +36,9 @@ fn setup() -> SocketAddr { let test_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests"); - let ca = load_certs(&test_dir.join("data").join("new").join("ca.crt")); - let certs = load_certs(&test_dir.join("data").join("new").join("server.crt")); - let privkey = load_private_key(&test_dir.join("data").join("new").join("server.key")); + let ca = load_certs(&test_dir.join("data").join("ca-cert.pem")); + let certs = load_certs(&test_dir.join("data").join("server-cert.pem")); + let privkey = load_private_key(&test_dir.join("data").join("server-key.pem")); let mut client_auth_roots = rustls::RootCertStore::empty(); for root in ca.iter() { @@ -98,13 +96,13 @@ async fn test_client_certificate_auth() { use tokio::net::TcpStream; let addr = setup(); - let ca_pem = include_str!("data/new/ca.crt"); + let ca_pem = include_str!("data/ca-cert.pem"); let ca_der = pem_parser::pem_to_der(ca_pem); - let client_cert_pem = include_str!("data/new/client.crt"); + let client_cert_pem = include_str!("data/client-cert.pem"); let client_cert_der = pem_parser::pem_to_der(client_cert_pem); - let private_key_pem = include_str!("data/new/client.key"); + let private_key_pem = include_str!("data/client-key.pem"); let private_key_der = pem_parser::pem_to_der(private_key_pem); let stream = TcpStream::connect(addr) @@ -166,45 +164,3 @@ async fn test_client_certificate_auth() { .map_err(|(_, e)| e) .expect("error closing session"); } - -#[tokio::test] -async fn test_client_certificate_auth_rustls() { - let addr = setup(); - - let test_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests"); - - let ca = tlsserver::load_certs(&test_dir.join("data").join("new").join("ca.crt")); - let certs = tlsserver::load_certs(&test_dir.join("data").join("new").join("client.crt")); - let privkey = - tlsserver::load_private_key(&test_dir.join("data").join("new").join("client.key")); - - let mut root_store = rustls::RootCertStore::empty(); - for root in ca.iter() { - root_store.add(root).unwrap() - } - - let config = ClientConfig::builder() - .with_cipher_suites(&[rustls::cipher_suite::TLS13_AES_128_GCM_SHA256]) - .with_kx_groups(&rustls::ALL_KX_GROUPS) - .with_protocol_versions(&[&rustls::version::TLS13]) - .unwrap() - .with_root_certificates(root_store) - .with_client_auth_cert(certs, privkey) - .unwrap(); - - let connector = tokio_rustls::TlsConnector::from(std::sync::Arc::new(config)); - let dnsname = rustls::ServerName::try_from("factbird.com").unwrap(); - - let stream = tokio::net::TcpStream::connect(&addr).await.unwrap(); - let mut tls = connector.connect(dnsname, stream).await.unwrap(); - - tls.write(b"ping").await.expect("error writing data"); - tls.flush().await.expect("error flushing data"); - - // Make sure reading into a 0 length buffer doesn't loop - let mut rx_buf = [0; 4096]; - let sz = tls.read(&mut rx_buf).await.expect("error reading data"); - assert_eq!(sz, 4); - assert_eq!(b"ping", &rx_buf[..sz]); - log::info!("Read {} bytes: {:?}", sz, &rx_buf[..sz]); -} diff --git a/tests/data/new/ca.crt b/tests/data/new/ca.crt deleted file mode 100644 index 816e604e..00000000 --- a/tests/data/new/ca.crt +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBzTCCAXOgAwIBAgIUPD9fJNyOJr+zjxiNWW6KnMPQiMIwCgYIKoZIzj0EAwIw -PDEVMBMGA1UEAwwMZmFjdGJpcmQuY29tMQswCQYDVQQGEwJVUzEWMBQGA1UEBwwN -U2FuIEZyYW5zaXNjbzAeFw0yNDAyMTQxMTE1MTZaFw0yNDAzMTUxMTE1MTZaMDwx -FTATBgNVBAMMDGZhY3RiaXJkLmNvbTELMAkGA1UEBhMCVVMxFjAUBgNVBAcMDVNh -biBGcmFuc2lzY28wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARb2+jh+8VHAJJi -ElVVxwpJJbvoEiLEaR2v9A8Tr2lIP25D2XgCD+bRU6VeU5CyvagS+z5xPxXWWJxI -0taaLTXlo1MwUTAdBgNVHQ4EFgQUmNoB7B3c/jr2Z1iPW/5AT8lW4BowHwYDVR0j -BBgwFoAUmNoB7B3c/jr2Z1iPW/5AT8lW4BowDwYDVR0TAQH/BAUwAwEB/zAKBggq -hkjOPQQDAgNIADBFAiAYl7Yr02WNeOIKu9rozt559KynFm4kQdiFFlZTvjIfQQIh -AL6XLLwRd+Dz254VMv487DU5jKFGDMOF75K7KW6rsfxx ------END CERTIFICATE----- diff --git a/tests/data/new/ca.key b/tests/data/new/ca.key deleted file mode 100644 index ceeb71c4..00000000 --- a/tests/data/new/ca.key +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MHcCAQEEIJoJGgohVbLxsbmRlgYNKvTuTpyXMXsei76CdcBzj296oAoGCCqGSM49 -AwEHoUQDQgAEW9vo4fvFRwCSYhJVVccKSSW76BIixGkdr/QPE69pSD9uQ9l4Ag/m -0VOlXlOQsr2oEvs+cT8V1licSNLWmi015Q== ------END EC PRIVATE KEY----- diff --git a/tests/data/new/ca.srl b/tests/data/new/ca.srl deleted file mode 100644 index bcac8d38..00000000 --- a/tests/data/new/ca.srl +++ /dev/null @@ -1 +0,0 @@ -12C91A34CFE606D84185DA612B3BD751A670F9E5 diff --git a/tests/data/new/cert.conf b/tests/data/new/cert.conf deleted file mode 100644 index c1bfdcd3..00000000 --- a/tests/data/new/cert.conf +++ /dev/null @@ -1,9 +0,0 @@ - -authorityKeyIdentifier=keyid,issuer -basicConstraints=CA:FALSE -keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment -subjectAltName = @alt_names - -[alt_names] -DNS.1 = factbird.com - diff --git a/tests/data/new/client.conf b/tests/data/new/client.conf deleted file mode 100644 index 690ff5e7..00000000 --- a/tests/data/new/client.conf +++ /dev/null @@ -1,24 +0,0 @@ -[ req ] -default_bits = 2048 -prompt = no -default_md = sha256 -req_extensions = req_ext -distinguished_name = dn - -[ dn ] -C = US -ST = California -L = San Fransisco -O = MLopsHub -OU = MlopsHub Dev -CN = factbird.com - -[ req_ext ] -subjectAltName = @alt_names - -[ alt_names ] -DNS.1 = factbird.com -DNS.2 = www.factbird.com -IP.1 = 192.168.1.5 -IP.2 = 192.168.1.6 - diff --git a/tests/data/new/client.crt b/tests/data/new/client.crt deleted file mode 100644 index 7359f274..00000000 --- a/tests/data/new/client.crt +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICLDCCAdKgAwIBAgIUEskaNM/mBthBhdphKzvXUaZw+eUwCgYIKoZIzj0EAwIw -PDEVMBMGA1UEAwwMZmFjdGJpcmQuY29tMQswCQYDVQQGEwJVUzEWMBQGA1UEBwwN -U2FuIEZyYW5zaXNjbzAeFw0yNDAyMTQxMTE1MTZaFw0yNjExMTAxMTE1MTZaMHsx -CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4g -RnJhbnNpc2NvMREwDwYDVQQKDAhNTG9wc0h1YjEVMBMGA1UECwwMTWxvcHNIdWIg -RGV2MRUwEwYDVQQDDAxmYWN0YmlyZC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMB -BwNCAARfzUjGqE5M1GuecOOeUlccNkWmPSMJc7vfCtw76KutDQKdZZRJrWwK3+9E -C+AgK0IqNxULozZvTHD5x7EFPpRRo3MwcTAfBgNVHSMEGDAWgBSY2gHsHdz+OvZn -WI9b/kBPyVbgGjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DAXBgNVHREEEDAOggxm -YWN0YmlyZC5jb20wHQYDVR0OBBYEFKobp1jvdFe7LtSrjEfaNrw0+6CaMAoGCCqG -SM49BAMCA0gAMEUCIQD4JCTjQrpfuo42EJlA5Ty3RE8w/GLPHJGISDZOn7Tu+QIg -XDbaXgII/elrXGt7WbX1bcd4UwGVdtjVDbAxR37JkWI= ------END CERTIFICATE----- diff --git a/tests/data/new/client.csr b/tests/data/new/client.csr deleted file mode 100644 index d0fe2bcd..00000000 --- a/tests/data/new/client.csr +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIIBfjCCASUCAQAwezELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx -FjAUBgNVBAcMDVNhbiBGcmFuc2lzY28xETAPBgNVBAoMCE1Mb3BzSHViMRUwEwYD -VQQLDAxNbG9wc0h1YiBEZXYxFTATBgNVBAMMDGZhY3RiaXJkLmNvbTBZMBMGByqG -SM49AgEGCCqGSM49AwEHA0IABF/NSMaoTkzUa55w455SVxw2RaY9Iwlzu98K3Dvo -q60NAp1llEmtbArf70QL4CArQio3FQujNm9McPnHsQU+lFGgSDBGBgkqhkiG9w0B -CQ4xOTA3MDUGA1UdEQQuMCyCDGZhY3RiaXJkLmNvbYIQd3d3LmZhY3RiaXJkLmNv -bYcEwKgBBYcEwKgBBjAKBggqhkjOPQQDAgNHADBEAiBWJQ+l6qkKISss7U/hH2Nj -DHGKXUZUMnAFGzwAlJZQsAIgD+hkJjpig4SgpQrpt+PbktCAfZaoJGSAr0NzqMMM -+9M= ------END CERTIFICATE REQUEST----- diff --git a/tests/data/new/client.key b/tests/data/new/client.key deleted file mode 100644 index 03324af9..00000000 --- a/tests/data/new/client.key +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MHcCAQEEINLKEwvN7SYoo8s4ZQuYnNfnph7cSZJIWvPryHH4Mz96oAoGCCqGSM49 -AwEHoUQDQgAEX81IxqhOTNRrnnDjnlJXHDZFpj0jCXO73wrcO+irrQ0CnWWUSa1s -Ct/vRAvgICtCKjcVC6M2b0xw+cexBT6UUQ== ------END EC PRIVATE KEY----- diff --git a/tests/data/new/server.conf b/tests/data/new/server.conf deleted file mode 100644 index 690ff5e7..00000000 --- a/tests/data/new/server.conf +++ /dev/null @@ -1,24 +0,0 @@ -[ req ] -default_bits = 2048 -prompt = no -default_md = sha256 -req_extensions = req_ext -distinguished_name = dn - -[ dn ] -C = US -ST = California -L = San Fransisco -O = MLopsHub -OU = MlopsHub Dev -CN = factbird.com - -[ req_ext ] -subjectAltName = @alt_names - -[ alt_names ] -DNS.1 = factbird.com -DNS.2 = www.factbird.com -IP.1 = 192.168.1.5 -IP.2 = 192.168.1.6 - diff --git a/tests/data/new/server.crt b/tests/data/new/server.crt deleted file mode 100644 index 7ee58f05..00000000 --- a/tests/data/new/server.crt +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICLDCCAdKgAwIBAgIUEskaNM/mBthBhdphKzvXUaZw+eQwCgYIKoZIzj0EAwIw -PDEVMBMGA1UEAwwMZmFjdGJpcmQuY29tMQswCQYDVQQGEwJVUzEWMBQGA1UEBwwN -U2FuIEZyYW5zaXNjbzAeFw0yNDAyMTQxMTE1MTZaFw0yNjExMTAxMTE1MTZaMHsx -CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4g -RnJhbnNpc2NvMREwDwYDVQQKDAhNTG9wc0h1YjEVMBMGA1UECwwMTWxvcHNIdWIg -RGV2MRUwEwYDVQQDDAxmYWN0YmlyZC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMB -BwNCAAQcVSNxt0Va0eGP5ZuAdO+nsL3D0NvkNAYlOKY+fAIdYfSGBrgo7U3evWcj -+k9UM0R+9qKWro9pNqBdSYbOxKTlo3MwcTAfBgNVHSMEGDAWgBSY2gHsHdz+OvZn -WI9b/kBPyVbgGjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DAXBgNVHREEEDAOggxm -YWN0YmlyZC5jb20wHQYDVR0OBBYEFIo1QWMzUtrGi8BxiHRjZsAygkpRMAoGCCqG -SM49BAMCA0gAMEUCIDgDqeBlzzQ+uTBhFUhzSpfiG5eWuh9n5p7nIumf8mAaAiEA -sxGDXrSL2na7h07sWi2h+xB92KyGIyCtDtrT2AhIzEk= ------END CERTIFICATE----- diff --git a/tests/data/new/server.csr b/tests/data/new/server.csr deleted file mode 100644 index 8979c448..00000000 --- a/tests/data/new/server.csr +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIIBgDCCASUCAQAwezELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx -FjAUBgNVBAcMDVNhbiBGcmFuc2lzY28xETAPBgNVBAoMCE1Mb3BzSHViMRUwEwYD -VQQLDAxNbG9wc0h1YiBEZXYxFTATBgNVBAMMDGZhY3RiaXJkLmNvbTBZMBMGByqG -SM49AgEGCCqGSM49AwEHA0IABBxVI3G3RVrR4Y/lm4B076ewvcPQ2+Q0BiU4pj58 -Ah1h9IYGuCjtTd69ZyP6T1QzRH72opauj2k2oF1Jhs7EpOWgSDBGBgkqhkiG9w0B -CQ4xOTA3MDUGA1UdEQQuMCyCDGZhY3RiaXJkLmNvbYIQd3d3LmZhY3RiaXJkLmNv -bYcEwKgBBYcEwKgBBjAKBggqhkjOPQQDAgNJADBGAiEAoUNDV90xYiQG8oeOXF8L -gm0LJPVEnFieNTFcWXHpoI8CIQD/B2D9m437FbMapCO1dy8FvkqH00gLhqRbNGYY -16U6jA== ------END CERTIFICATE REQUEST----- diff --git a/tests/data/new/server.key b/tests/data/new/server.key deleted file mode 100644 index fdaea5bf..00000000 --- a/tests/data/new/server.key +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MHcCAQEEIFumcDr3XLOin21fWEG4BeOONG2k1W1PrUAGMMCaDIyWoAoGCCqGSM49 -AwEHoUQDQgAEHFUjcbdFWtHhj+WbgHTvp7C9w9Db5DQGJTimPnwCHWH0hga4KO1N -3r1nI/pPVDNEfvailq6PaTagXUmGzsSk5Q== ------END EC PRIVATE KEY----- diff --git a/tests/data/new/ssl.sh b/tests/data/new/ssl.sh deleted file mode 100755 index b892c07f..00000000 --- a/tests/data/new/ssl.sh +++ /dev/null @@ -1,115 +0,0 @@ -#! /bin/bash - -if [ "$#" -ne 1 ] -then - echo "Error: No domain name argument provided" - echo "Usage: Provide a domain name as an argument" - exit 1 -fi - -DOMAIN=$1 - -# Create root CA & Private key -openssl ecparam -name prime256v1 -genkey -noout -out ca.key -openssl req -new -x509 -sha256 -key ca.key -out ca.crt -subj "/CN=${DOMAIN}/C=US/L=San Fransisco" - -# Create server csr conf - -cat > server.conf < cert.conf < client.conf < cert.conf < Date: Wed, 14 Feb 2024 20:08:11 +0100 Subject: [PATCH 09/19] Cleanup signature struct slightly --- src/config.rs | 12 ++++++++---- src/connection.rs | 12 ++---------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/config.rs b/src/config.rs index afd16e81..ea652f50 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,5 @@ use core::marker::PhantomData; +use core::ops::Deref; use crate::cipher_suites::CipherSuite; use crate::extensions::extension_data::signature_algorithms::SignatureScheme; @@ -163,13 +164,16 @@ where { signature: ecdsa::der::Signature, } -impl Signature + +impl Deref for Signature where SignatureSize: core::ops::Add + ArrayLength, ecdsa::der::MaxSize: ArrayLength, { - pub fn to_vec(&self) -> heapless::Vec { - heapless::Vec::from_slice(self.signature.as_bytes()).unwrap() + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + self.signature.as_bytes() } } @@ -190,7 +194,7 @@ where ::Scalar: SignPrimitive, { let signing_key = SigningKey::from(&self.secret_key); - let signature = signing_key.try_sign_with_rng(self.rng, &message).unwrap(); + let signature = signing_key.sign_with_rng(self.rng, &message); Signature { signature } } diff --git a/src/connection.rs b/src/connection.rs index a0d79e7c..e206025f 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -562,29 +562,21 @@ where ecdsa::der::MaxSize: ArrayLength, ::Scalar: SignPrimitive, { - let hash = key_schedule.transcript_hash().clone().finalize(); - - info!("{:?}", &hash); - let ctx_str = b"TLS 1.3, client CertificateVerify\x00"; let mut msg: heapless::Vec = heapless::Vec::new(); msg.resize(64, 0x20).map_err(|_| TlsError::EncodeError)?; msg.extend_from_slice(ctx_str) .map_err(|_| TlsError::EncodeError)?; - msg.extend_from_slice(&hash) + msg.extend_from_slice(&key_schedule.transcript_hash().clone().finalize()) .map_err(|_| TlsError::EncodeError)?; // FIXME: Remove unwraps! let mut signing_key = crypto_provider.signer(config.priv_key.unwrap()).unwrap(); let signature = signing_key.sign(&msg); - let signature = signature.to_vec(); - - info!("Signature: {:x?}, len: {}", signature, signature.len()); - let certificate_verify = CertificateVerify { signature_scheme: signing_key.signature_scheme(), - signature, + signature: heapless::Vec::from_slice(&*signature).unwrap(), }; let (write_key_schedule, read_key_schedule) = key_schedule.as_split(); From 8b5d9d7513ceddbf4d99c4bb6335cd1a2188d334 Mon Sep 17 00:00:00 2001 From: Mathias Date: Wed, 14 Feb 2024 20:19:21 +0100 Subject: [PATCH 10/19] Revert public api in webpki impl --- src/webpki.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/webpki.rs b/src/webpki.rs index 4a1d9159..95307f4f 100644 --- a/src/webpki.rs +++ b/src/webpki.rs @@ -157,7 +157,7 @@ where } } -pub fn verify_signature( +fn verify_signature( message: &[u8], certificate: ServerCertificate, verify: CertificateVerifyRef, @@ -193,7 +193,7 @@ pub fn verify_signature( Ok(()) } -pub fn verify_certificate( +fn verify_certificate( verify_host: Option<&str>, ca: &Option, certificate: &ServerCertificate, From 2c8bd0f9978fd08902f6000d3b8e24ebe2599f57 Mon Sep 17 00:00:00 2001 From: Mathias Date: Thu, 15 Feb 2024 11:21:37 +0100 Subject: [PATCH 11/19] Fix doctest --- src/config.rs | 2 +- src/lib.rs | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/config.rs b/src/config.rs index ea652f50..3e66db99 100644 --- a/src/config.rs +++ b/src/config.rs @@ -165,7 +165,7 @@ where signature: ecdsa::der::Signature, } -impl Deref for Signature +impl Deref for Signature where SignatureSize: core::ops::Add + ArrayLength, ecdsa::der::MaxSize: ArrayLength, diff --git a/src/lib.rs b/src/lib.rs index 3c088f98..caab4427 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,19 +13,28 @@ use tokio::net::TcpStream; #[tokio::main] async fn main() { - let stream = TcpStream::connect("http.sandbox.drogue.cloud:443").await.expect("error creating TCP connection"); + let stream = TcpStream::connect("http.sandbox.drogue.cloud:443") + .await + .expect("error creating TCP connection"); println!("TCP connection opened"); let mut read_record_buffer = [0; 16384]; let mut write_record_buffer = [0; 16384]; - let config = TlsConfig::new() - .with_server_name("http.sandbox.drogue.cloud"); - let mut tls: TlsConnection, Aes128GcmSha256> = - TlsConnection::new(FromTokio::new(stream), &mut read_record_buffer, &mut write_record_buffer); + let config = TlsConfig::new().with_server_name("http.sandbox.drogue.cloud"); + let mut tls = TlsConnection::new( + FromTokio::new(stream), + &mut read_record_buffer, + &mut write_record_buffer, + ); // Allows disabling cert verification, in case you are using PSK and don't need it, or are just testing. // otherwise, use embedded_tls::webpki::CertVerifier, which only works on std for now. - tls.open::(TlsContext::new(&config, &mut OsRng)).await.expect("error establishing TLS connection"); + tls.open(TlsContext::new( + &config, + SimpleProvider::new::(OsRng), + )) + .await + .expect("error establishing TLS connection"); println!("TLS session opened"); } From c86644e23a908c972f17b31ca453c9138857b9b9 Mon Sep 17 00:00:00 2001 From: Mathias Date: Thu, 15 Feb 2024 13:43:13 +0100 Subject: [PATCH 12/19] Rename SimpleProvider to UnsecureProvider --- src/config.rs | 12 ++++++------ src/lib.rs | 4 ++-- src/webpki.rs | 2 +- tests/client_test.rs | 14 +++++++------- tests/early_data_test.rs | 2 +- tests/psk_test.rs | 2 +- tests/split_test.rs | 4 ++-- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/config.rs b/src/config.rs index 3e66db99..a93edb82 100644 --- a/src/config.rs +++ b/src/config.rs @@ -211,7 +211,7 @@ pub trait CryptoProvider { fn rng(&mut self) -> &mut Self::SecureRandom; - fn verifier(&mut self) -> Result<&mut impl TlsVerifier, crate::TlsError> { + fn verifier(&mut self) -> Result<&mut impl TlsVerifier<'_, Self::CipherSuite>, crate::TlsError> { Err::<&mut NoVerify, _>(crate::TlsError::Unimplemented) } @@ -224,14 +224,14 @@ pub trait CryptoProvider { } } -pub struct SimpleProvider { +pub struct UnsecureProvider { rng: RNG, _marker: PhantomData, } -impl SimpleProvider<(), RNG> { - pub fn new(rng: RNG) -> SimpleProvider { - SimpleProvider { +impl UnsecureProvider<(), RNG> { + pub fn new(rng: RNG) -> UnsecureProvider { + UnsecureProvider { rng, _marker: PhantomData, } @@ -239,7 +239,7 @@ impl SimpleProvider<(), RNG> { } impl CryptoProvider - for SimpleProvider + for UnsecureProvider { type CipherSuite = CipherSuite; type SecureRandom = RNG; diff --git a/src/lib.rs b/src/lib.rs index caab4427..1ca5c7cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,7 +31,7 @@ async fn main() { // otherwise, use embedded_tls::webpki::CertVerifier, which only works on std for now. tls.open(TlsContext::new( &config, - SimpleProvider::new::(OsRng), + UnsecureProvider::new::(OsRng), )) .await .expect("error establishing TLS connection"); @@ -66,7 +66,7 @@ mod record_reader; mod split; mod write_buffer; -pub use config::{Signature, SimpleProvider}; +pub use config::{Signature, UnsecureProvider}; pub use extensions::extension_data::signature_algorithms::SignatureScheme; pub use handshake::certificate_verify::CertificateVerify; diff --git a/src/webpki.rs b/src/webpki.rs index 95307f4f..ea7b02ea 100644 --- a/src/webpki.rs +++ b/src/webpki.rs @@ -105,7 +105,7 @@ where Clock: TlsClock, CipherSuite: TlsCipherSuite, { - fn new() -> Self { + pub fn new() -> Self { Self { host: None, certificate_transcript: None, diff --git a/tests/client_test.rs b/tests/client_test.rs index 2ed116a0..6c33b6b1 100644 --- a/tests/client_test.rs +++ b/tests/client_test.rs @@ -62,7 +62,7 @@ async fn test_google() { let open_fut = tls.open(TlsContext::new( &config, - SimpleProvider::new::(OsRng), + UnsecureProvider::new::(OsRng), )); log::info!("SIZE of open fut is {}", core::mem::size_of_val(&open_fut)); open_fut.await.expect("error establishing TLS connection"); @@ -112,7 +112,7 @@ async fn test_ping() { let open_fut = tls.open(TlsContext::new( &config, - SimpleProvider::new::(OsRng), + UnsecureProvider::new::(OsRng), )); log::info!("SIZE of open fut is {}", core::mem::size_of_val(&open_fut)); open_fut.await.expect("error establishing TLS connection"); @@ -181,7 +181,7 @@ async fn test_ping_nocopy() { let open_fut = tls.open(TlsContext::new( &config, - SimpleProvider::new::(OsRng), + UnsecureProvider::new::(OsRng), )); log::info!("SIZE of open fut is {}", core::mem::size_of_val(&open_fut)); open_fut.await.expect("error establishing TLS connection"); @@ -250,7 +250,7 @@ async fn test_ping_nocopy_bufread() { ); tls.open(TlsContext::new( &config, - SimpleProvider::new::(OsRng), + UnsecureProvider::new::(OsRng), )) .await .expect("error establishing TLS connection"); @@ -297,7 +297,7 @@ fn test_blocking_ping() { ); tls.open(TlsContext::new( &config, - SimpleProvider::new::(OsRng), + UnsecureProvider::new::(OsRng), )) .expect("error establishing TLS connection"); log::info!("Established"); @@ -350,7 +350,7 @@ fn test_blocking_ping_nocopy() { ); tls.open(TlsContext::new( &config, - SimpleProvider::new::(OsRng), + UnsecureProvider::new::(OsRng), )) .expect("error establishing TLS connection"); log::info!("Established"); @@ -397,7 +397,7 @@ fn test_blocking_ping_nocopy_bufread() { ); tls.open(TlsContext::new( &config, - SimpleProvider::new::(OsRng), + UnsecureProvider::new::(OsRng), )) .expect("error establishing TLS connection"); log::info!("Established"); diff --git a/tests/early_data_test.rs b/tests/early_data_test.rs index ae7409a7..647f5627 100644 --- a/tests/early_data_test.rs +++ b/tests/early_data_test.rs @@ -76,7 +76,7 @@ fn early_data_ignored() { tls.open(TlsContext::new( &config, - SimpleProvider::new::(OsRng), + UnsecureProvider::new::(OsRng), )) .expect("error establishing TLS connection"); diff --git a/tests/psk_test.rs b/tests/psk_test.rs index c56a3288..d82bd462 100644 --- a/tests/psk_test.rs +++ b/tests/psk_test.rs @@ -84,7 +84,7 @@ async fn test_psk_open() { assert!(tls .open(TlsContext::new( &config, - SimpleProvider::new::(OsRng) + UnsecureProvider::new::(OsRng) )) .await .is_ok()); diff --git a/tests/split_test.rs b/tests/split_test.rs index daf3b9c0..866442e5 100644 --- a/tests/split_test.rs +++ b/tests/split_test.rs @@ -86,7 +86,7 @@ fn test_blocking_borrowed() { tls.open(TlsContext::new( &config, - SimpleProvider::new::(OsRng), + UnsecureProvider::new::(OsRng), )) .expect("error establishing TLS connection"); @@ -137,7 +137,7 @@ fn test_blocking_managed() { tls.open(TlsContext::new( &config, - SimpleProvider::new::(OsRng), + UnsecureProvider::new::(OsRng), )) .expect("error establishing TLS connection"); From 67cbb0d41ef4fc733a9c6fa697b4cbd49d2921ed Mon Sep 17 00:00:00 2001 From: Mathias Date: Thu, 15 Feb 2024 13:43:45 +0100 Subject: [PATCH 13/19] Fix 4/5 examples building --- examples/embassy/src/main.rs | 16 +++++++++------- examples/nrf52/src/main.rs | 12 +++++++----- examples/tokio-psk/src/main.rs | 12 +++++++----- examples/tokio/src/main.rs | 12 +++++++----- 4 files changed, 30 insertions(+), 22 deletions(-) diff --git a/examples/embassy/src/main.rs b/examples/embassy/src/main.rs index 535efd77..51904541 100644 --- a/examples/embassy/src/main.rs +++ b/examples/embassy/src/main.rs @@ -57,7 +57,7 @@ async fn main_task(spawner: Spawner) { device, config, RESOURCES.init(StackResources::<3>::new()), - seed + seed, )); // Launch network task @@ -83,12 +83,14 @@ async fn main_task(spawner: Spawner) { let mut write_record_buffer = [0; 16384]; let mut rng = OsRng; let config = TlsConfig::new().with_server_name("example.com"); - let mut tls: TlsConnection = - TlsConnection::new(socket, &mut read_record_buffer, &mut write_record_buffer); - - tls.open::(TlsContext::new(&config, &mut rng)) - .await - .expect("error establishing TLS connection"); + let mut tls = TlsConnection::new(socket, &mut read_record_buffer, &mut write_record_buffer); + + tls.open(TlsContext::new( + &config, + UnsecureProvider::new::(OsRng), + )) + .await + .expect("error establishing TLS connection"); tls.write_all(b"ping").await.expect("error writing data"); tls.flush().await.expect("error flushing data"); diff --git a/examples/nrf52/src/main.rs b/examples/nrf52/src/main.rs index b46de457..742c06b4 100644 --- a/examples/nrf52/src/main.rs +++ b/examples/nrf52/src/main.rs @@ -17,16 +17,18 @@ use hal::rng::Rng; #[entry] fn main() -> ! { let p = hal::pac::Peripherals::take().unwrap(); - let mut rng = Rng::new(p.RNG); + let rng = Rng::new(p.RNG); defmt::info!("Connected"); let mut read_record_buffer = [0; 16384]; let mut write_record_buffer = [0; 16384]; let config = TlsConfig::new().with_server_name("example.com"); - let mut tls: TlsConnection = - TlsConnection::new(Dummy {}, &mut read_record_buffer, &mut write_record_buffer); + let mut tls = TlsConnection::new(Dummy {}, &mut read_record_buffer, &mut write_record_buffer); - tls.open::(TlsContext::new(&config, &mut rng)) - .expect("error establishing TLS connection"); + tls.open(TlsContext::new( + &config, + UnsecureProvider::new::(rng), + )) + .expect("error establishing TLS connection"); tls.write_all(b"ping").expect("error writing data"); tls.flush().expect("error flushing data"); diff --git a/examples/tokio-psk/src/main.rs b/examples/tokio-psk/src/main.rs index e188cf95..20d97222 100644 --- a/examples/tokio-psk/src/main.rs +++ b/examples/tokio-psk/src/main.rs @@ -19,16 +19,18 @@ async fn main() -> Result<(), Box> { let config = TlsConfig::new() .with_server_name("localhost") .with_psk(&[0xaa, 0xbb, 0xcc, 0xdd], &[b"vader"]); - let mut rng = OsRng; - let mut tls: TlsConnection, Aes128GcmSha256> = TlsConnection::new( + let mut tls = TlsConnection::new( FromTokio::new(stream), &mut read_record_buffer, &mut write_record_buffer, ); - tls.open::(TlsContext::new(&config, &mut rng)) - .await - .expect("error establishing TLS connection"); + tls.open(TlsContext::new( + &config, + UnsecureProvider::new::(OsRng), + )) + .await + .expect("error establishing TLS connection"); tls.write_all(b"ping").await.expect("error writing data"); tls.flush().await.expect("error flushing data"); diff --git a/examples/tokio/src/main.rs b/examples/tokio/src/main.rs index 46bb68fc..1f101dfe 100644 --- a/examples/tokio/src/main.rs +++ b/examples/tokio/src/main.rs @@ -17,16 +17,18 @@ async fn main() -> Result<(), Box> { let mut read_record_buffer = [0; 16384]; let mut write_record_buffer = [0; 16384]; let config = TlsConfig::new().with_server_name("localhost"); - let mut rng = OsRng; - let mut tls: TlsConnection, Aes128GcmSha256> = TlsConnection::new( + let mut tls = TlsConnection::new( FromTokio::new(stream), &mut read_record_buffer, &mut write_record_buffer, ); - tls.open::(TlsContext::new(&config, &mut rng)) - .await - .expect("error establishing TLS connection"); + tls.open(TlsContext::new( + &config, + UnsecureProvider::new::(OsRng), + )) + .await + .expect("error establishing TLS connection"); tls.write_all(b"ping").await.expect("error writing data"); tls.flush().await.expect("error flushing data"); From c511ea7128afd42c113bcefd4a70f469f2f0c583 Mon Sep 17 00:00:00 2001 From: Mathias Date: Thu, 15 Feb 2024 13:55:17 +0100 Subject: [PATCH 14/19] Send ClientRecord::Alert if signer operation fails due to invalid private key --- src/config.rs | 10 ++++--- src/connection.rs | 68 +++++++++++++++++++++++++++++------------------ 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/config.rs b/src/config.rs index a93edb82..21e59f55 100644 --- a/src/config.rs +++ b/src/config.rs @@ -141,7 +141,7 @@ pub struct TlsConfig<'a> { pub(crate) max_fragment_length: Option, pub(crate) ca: Option>, pub(crate) cert: Option>, - pub(crate) priv_key: Option<&'a [u8]>, + pub(crate) priv_key: &'a [u8], } pub trait TlsClock { @@ -211,7 +211,9 @@ pub trait CryptoProvider { fn rng(&mut self) -> &mut Self::SecureRandom; - fn verifier(&mut self) -> Result<&mut impl TlsVerifier<'_, Self::CipherSuite>, crate::TlsError> { + fn verifier( + &mut self, + ) -> Result<&mut impl TlsVerifier<'_, Self::CipherSuite>, crate::TlsError> { Err::<&mut NoVerify, _>(crate::TlsError::Unimplemented) } @@ -283,7 +285,7 @@ impl<'a> TlsConfig<'a> { server_name: None, ca: None, cert: None, - priv_key: None, + priv_key: &[], }; if cfg!(feature = "alloc") { @@ -379,7 +381,7 @@ impl<'a> TlsConfig<'a> { } pub fn with_priv_key(mut self, priv_key: &'a [u8]) -> Self { - self.priv_key = Some(priv_key); + self.priv_key = priv_key; self } diff --git a/src/connection.rs b/src/connection.rs index e206025f..f1f1903a 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -220,12 +220,12 @@ impl<'a> State { Ok(state) } State::ClientCertVerify => { - let (state, tx) = + let (result, tx) = client_cert_verify(key_schedule, config, crypto_provider, tx_buf)?; respond(tx, transport, key_schedule).await?; - Ok(state) + result } State::ClientFinished => { let tx = client_finished(key_schedule, tx_buf)?; @@ -290,12 +290,12 @@ impl<'a> State { Ok(state) } State::ClientCertVerify => { - let (state, tx) = + let (result, tx) = client_cert_verify(key_schedule, config, crypto_provider, tx_buf)?; respond_blocking(tx, transport, key_schedule)?; - Ok(state) + result } State::ClientFinished => { let tx = client_finished(key_schedule, tx_buf)?; @@ -554,7 +554,7 @@ fn client_cert_verify<'r, Provider>( config: &TlsConfig, crypto_provider: &mut Provider, buffer: &'r mut WriteBuffer, -) -> Result<(State, &'r [u8]), TlsError> +) -> Result<(Result, &'r [u8]), TlsError> where Provider: CryptoProvider, SignatureSize: @@ -562,32 +562,48 @@ where ecdsa::der::MaxSize: ArrayLength, ::Scalar: SignPrimitive, { - let ctx_str = b"TLS 1.3, client CertificateVerify\x00"; - let mut msg: heapless::Vec = heapless::Vec::new(); - msg.resize(64, 0x20).map_err(|_| TlsError::EncodeError)?; - msg.extend_from_slice(ctx_str) - .map_err(|_| TlsError::EncodeError)?; - msg.extend_from_slice(&key_schedule.transcript_hash().clone().finalize()) - .map_err(|_| TlsError::EncodeError)?; - - // FIXME: Remove unwraps! - let mut signing_key = crypto_provider.signer(config.priv_key.unwrap()).unwrap(); - let signature = signing_key.sign(&msg); - - let certificate_verify = CertificateVerify { - signature_scheme: signing_key.signature_scheme(), - signature: heapless::Vec::from_slice(&*signature).unwrap(), + let (result, record) = match crypto_provider.signer(config.priv_key) { + Ok(mut signing_key) => { + let ctx_str = b"TLS 1.3, client CertificateVerify\x00"; + let mut msg: heapless::Vec = heapless::Vec::new(); + msg.resize(64, 0x20).map_err(|_| TlsError::EncodeError)?; + msg.extend_from_slice(ctx_str) + .map_err(|_| TlsError::EncodeError)?; + msg.extend_from_slice(&key_schedule.transcript_hash().clone().finalize()) + .map_err(|_| TlsError::EncodeError)?; + + let signature = signing_key.sign(&msg); + + let certificate_verify = CertificateVerify { + signature_scheme: signing_key.signature_scheme(), + signature: heapless::Vec::from_slice(&*signature).unwrap(), + }; + + ( + Ok(State::ClientFinished), + ClientRecord::Handshake( + ClientHandshake::ClientCertVerify(certificate_verify), + true, + ), + ) + } + Err(e) => { + error!("Failed to obtain signing key: {:?}", e); + ( + Err(e), + ClientRecord::Alert( + Alert::new(AlertLevel::Warning, AlertDescription::CloseNotify), + true, + ), + ) + } }; let (write_key_schedule, read_key_schedule) = key_schedule.as_split(); buffer - .write_record( - &ClientRecord::Handshake(ClientHandshake::ClientCertVerify(certificate_verify), true), - write_key_schedule, - Some(read_key_schedule), - ) - .map(|slice| (State::ClientFinished, slice)) + .write_record(&record, write_key_schedule, Some(read_key_schedule)) + .map(|slice| (result, slice)) } fn client_finished<'r, CipherSuite>( From e28a5223812e459c49277deb03d7d7c6cb9db275 Mon Sep 17 00:00:00 2001 From: Mathias Date: Sat, 24 Feb 2024 20:43:54 +0100 Subject: [PATCH 15/19] Simplify signer trait bounds and allow all signatures, not just ecdsa --- Cargo.toml | 4 +- examples/blocking/src/main.rs | 34 ++++++++++++++-- src/asynch.rs | 9 ----- src/blocking.rs | 7 ---- src/config.rs | 75 +++++++---------------------------- src/connection.rs | 23 ++--------- src/lib.rs | 2 +- tests/client_cert_test.rs | 21 +++++----- 8 files changed, 63 insertions(+), 112 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 175471a5..c4d722fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,6 @@ atomic-polyfill = "1" p256 = { version = "0.13.2", default-features = false, features = [ "ecdh", "ecdsa", - "arithmetic", "sha256", ] } rand_core = { version = "0.6.3", default-features = false } @@ -35,7 +34,7 @@ embedded-io-async = "0.6" embedded-io-adapters = { version = "0.6", optional = true } generic-array = { version = "0.14", default-features = false } webpki = { package = "rustls-webpki", version = "0.101.7", default-features = false, optional = true } -ecdsa = { version = "0.16.9", default-features = false } +signature = { version = "2.2", default-features = false } # Logging alternatives log = { version = "0.4", optional = true } @@ -52,6 +51,7 @@ rand = "0.8" log = "0.4" pem-parser = "0.1.1" openssl = "0.10.44" +ecdsa = { version = "0.16.9", default-features = false } [features] default = ["std", "log", "tokio"] diff --git a/examples/blocking/src/main.rs b/examples/blocking/src/main.rs index a429fa45..f972328e 100644 --- a/examples/blocking/src/main.rs +++ b/examples/blocking/src/main.rs @@ -6,6 +6,29 @@ use rand::rngs::OsRng; use std::net::TcpStream; use std::time::SystemTime; +struct Provider<'a> { + rng: OsRng, + verifier: CertVerifier<'a, Aes128GcmSha256, SystemTime, 4096>, +} + +impl<'a> CryptoProvider for Provider<'a> { + type CipherSuite = Aes128GcmSha256; + + type SecureRandom = OsRng; + + type SignatureCurve; + + fn rng(&mut self) -> &mut Self::SecureRandom { + &mut self.rng + } + + fn verifier( + &mut self, + ) -> Result<&mut impl TlsVerifier<'_, Self::CipherSuite>, embedded_tls::TlsError> { + Ok(&mut self.verifier) + } +} + fn main() { env_logger::init(); let stream = TcpStream::connect("127.0.0.1:12345").expect("error connecting to server"); @@ -14,15 +37,18 @@ fn main() { let mut read_record_buffer = [0; 16384]; let mut write_record_buffer = [0; 16384]; let config = TlsConfig::new().with_server_name("localhost"); - let mut tls: TlsConnection, Aes128GcmSha256> = TlsConnection::new( + let mut tls = TlsConnection::new( FromStd::new(stream), &mut read_record_buffer, &mut write_record_buffer, ); - let mut rng = OsRng; - tls.open::>(TlsContext::new( - &config, &mut rng, + tls.open(TlsContext::new( + &config, + Provider { + rng: OsRng, + verifier: CertVerifier::new(), + }, )) .expect("error establishing TLS connection"); diff --git a/src/asynch.rs b/src/asynch.rs index bc15957f..e085ba9c 100644 --- a/src/asynch.rs +++ b/src/asynch.rs @@ -9,13 +9,9 @@ use crate::record_reader::RecordReader; use crate::split::{SplitState, SplitStateContainer}; use crate::write_buffer::WriteBuffer; use crate::TlsError; -use ecdsa::elliptic_curve::CurveArithmetic; -use ecdsa::hazmat::SignPrimitive; -use ecdsa::SignatureSize; use embedded_io::Error as _; use embedded_io::ErrorType; use embedded_io_async::{BufRead, Read as AsyncRead, Write as AsyncWrite}; -use generic_array::ArrayLength; pub use crate::config::*; #[cfg(feature = "std")] @@ -80,11 +76,6 @@ where ) -> Result<(), TlsError> where Provider: CryptoProvider, - SignatureSize: - core::ops::Add + ArrayLength, - ecdsa::der::MaxSize: ArrayLength, - ::Scalar: - SignPrimitive, { let mut handshake: Handshake = Handshake::new(); if let Ok(verifier) = context.crypto_provider.verifier() { diff --git a/src/blocking.rs b/src/blocking.rs index 3de0927b..33c0336f 100644 --- a/src/blocking.rs +++ b/src/blocking.rs @@ -8,10 +8,8 @@ use crate::record::{ClientRecord, ClientRecordHeader}; use crate::record_reader::RecordReader; use crate::split::{SplitState, SplitStateContainer}; use crate::write_buffer::WriteBuffer; -use ecdsa::{elliptic_curve::CurveArithmetic, hazmat::SignPrimitive, SignatureSize}; use embedded_io::Error as _; use embedded_io::{BufRead, ErrorType, Read, Write}; -use generic_array::ArrayLength; pub use crate::config::*; #[cfg(feature = "std")] @@ -77,11 +75,6 @@ where ) -> Result<(), TlsError> where Provider: CryptoProvider, - SignatureSize: - core::ops::Add + ArrayLength, - ecdsa::der::MaxSize: ArrayLength, - ::Scalar: - SignPrimitive, { let mut handshake: Handshake = Handshake::new(); if let Ok(verifier) = context.crypto_provider.verifier() { diff --git a/src/config.rs b/src/config.rs index 21e59f55..26d04129 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,4 @@ use core::marker::PhantomData; -use core::ops::Deref; use crate::cipher_suites::CipherSuite; use crate::extensions::extension_data::signature_algorithms::SignatureScheme; @@ -10,21 +9,13 @@ use crate::TlsError; use aes_gcm::{AeadInPlace, Aes128Gcm, Aes256Gcm, KeyInit}; use digest::core_api::BlockSizeUser; use digest::{Digest, FixedOutput, OutputSizeUser, Reset}; -use ecdsa::signature::RandomizedSigner; use generic_array::ArrayLength; use heapless::Vec; -use p256::NistP256; use rand_core::CryptoRngCore; pub use sha2::Sha256; pub use sha2::Sha384; use typenum::{Sum, U10, U12, U16, U32}; -use ecdsa::{ - elliptic_curve::{CurveArithmetic, SecretKey}, - hazmat::{DigestPrimitive, SignPrimitive}, - PrimeCurve, SignatureSize, SigningKey, -}; - pub use crate::extensions::extension_data::max_fragment_length::MaxFragmentLength; pub(crate) const TLS_RECORD_MAX: usize = 16384; @@ -156,58 +147,10 @@ impl TlsClock for NoClock { } } -#[derive(Debug)] -pub struct Signature -where - SignatureSize: core::ops::Add + ArrayLength, - ecdsa::der::MaxSize: ArrayLength, -{ - signature: ecdsa::der::Signature, -} - -impl Deref for Signature -where - SignatureSize: core::ops::Add + ArrayLength, - ecdsa::der::MaxSize: ArrayLength, -{ - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - self.signature.as_bytes() - } -} - -pub struct Signer<'a, T: PrimeCurve, RNG: CryptoRngCore> { - pub secret_key: SecretKey, - pub scheme: SignatureScheme, - pub rng: &'a mut RNG, -} - -impl<'a, T: PrimeCurve, RNG: CryptoRngCore> Signer<'a, T, RNG> -where - SignatureSize: core::ops::Add + ArrayLength, - ecdsa::der::MaxSize: ArrayLength, -{ - pub fn sign(&mut self, message: &[u8]) -> Signature - where - T: CurveArithmetic + DigestPrimitive, - ::Scalar: SignPrimitive, - { - let signing_key = SigningKey::from(&self.secret_key); - let signature = signing_key.sign_with_rng(self.rng, &message); - - Signature { signature } - } - - pub fn signature_scheme(&self) -> SignatureScheme { - self.scheme - } -} - pub trait CryptoProvider { type CipherSuite: TlsCipherSuite; type SecureRandom: CryptoRngCore; - type SignatureCurve: CurveArithmetic + DigestPrimitive; + type Signature: AsRef<[u8]>; fn rng(&mut self) -> &mut Self::SecureRandom; @@ -221,8 +164,16 @@ pub trait CryptoProvider { fn signer( &mut self, _key_der: &[u8], - ) -> Result, crate::TlsError> { - Err::, _>(crate::TlsError::Unimplemented) + ) -> Result<(impl signature::SignerMut, SignatureScheme), crate::TlsError> { + Err::<(NoSign, _), crate::TlsError>(crate::TlsError::Unimplemented) + } +} + +pub struct NoSign; + +impl signature::Signer for NoSign { + fn try_sign(&self, _msg: &[u8]) -> Result { + unimplemented!() } } @@ -245,7 +196,9 @@ impl CryptoProvider { type CipherSuite = CipherSuite; type SecureRandom = RNG; - type SignatureCurve = NistP256; + type Signature = &'static [u8]; + // type SignatureCurve = NistP256; + // type Signature = (); fn rng(&mut self) -> &mut Self::SecureRandom { &mut self.rng diff --git a/src/connection.rs b/src/connection.rs index f1f1903a..5a970cf6 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -11,16 +11,15 @@ use crate::{ use crate::{CertificateVerify, CryptoProvider, TlsError, TlsVerifier}; use core::fmt::Debug; use digest::Digest; -use ecdsa::{elliptic_curve::CurveArithmetic, hazmat::SignPrimitive, SignatureSize}; use embedded_io::Error as _; use embedded_io::{Read as BlockingRead, Write as BlockingWrite}; use embedded_io_async::{Read as AsyncRead, Write as AsyncWrite}; -use generic_array::ArrayLength; use crate::application_data::ApplicationData; use crate::buffer::CryptoBuffer; use digest::generic_array::typenum::Unsigned; use p256::ecdh::EphemeralSecret; +use signature::SignerMut; use crate::content_types::ContentType; use crate::parse_buffer::ParseBuffer; @@ -178,11 +177,6 @@ impl<'a> State { where Transport: AsyncRead + AsyncWrite + 'a, Provider: CryptoProvider, - SignatureSize: - core::ops::Add + ArrayLength, - ecdsa::der::MaxSize: ArrayLength, - ::Scalar: - SignPrimitive, { match self { State::ClientHello => { @@ -252,11 +246,6 @@ impl<'a> State { where Transport: BlockingRead + BlockingWrite + 'a, Provider: CryptoProvider, - SignatureSize: - core::ops::Add + ArrayLength, - ecdsa::der::MaxSize: ArrayLength, - ::Scalar: - SignPrimitive, { match self { State::ClientHello => { @@ -557,13 +546,9 @@ fn client_cert_verify<'r, Provider>( ) -> Result<(Result, &'r [u8]), TlsError> where Provider: CryptoProvider, - SignatureSize: - core::ops::Add + ArrayLength, - ecdsa::der::MaxSize: ArrayLength, - ::Scalar: SignPrimitive, { let (result, record) = match crypto_provider.signer(config.priv_key) { - Ok(mut signing_key) => { + Ok((mut signing_key, signature_scheme)) => { let ctx_str = b"TLS 1.3, client CertificateVerify\x00"; let mut msg: heapless::Vec = heapless::Vec::new(); msg.resize(64, 0x20).map_err(|_| TlsError::EncodeError)?; @@ -575,8 +560,8 @@ where let signature = signing_key.sign(&msg); let certificate_verify = CertificateVerify { - signature_scheme: signing_key.signature_scheme(), - signature: heapless::Vec::from_slice(&*signature).unwrap(), + signature_scheme, + signature: heapless::Vec::from_slice(signature.as_ref()).unwrap(), }; ( diff --git a/src/lib.rs b/src/lib.rs index 1ca5c7cc..92cdff6f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,7 +66,7 @@ mod record_reader; mod split; mod write_buffer; -pub use config::{Signature, UnsecureProvider}; +pub use config::UnsecureProvider; pub use extensions::extension_data::signature_algorithms::SignatureScheme; pub use handshake::certificate_verify::CertificateVerify; diff --git a/tests/client_cert_test.rs b/tests/client_cert_test.rs index 4d094c13..859d19ff 100644 --- a/tests/client_cert_test.rs +++ b/tests/client_cert_test.rs @@ -1,6 +1,7 @@ use ecdsa::elliptic_curve::SecretKey; use embedded_io_adapters::tokio_1::FromTokio; -use embedded_tls::{CryptoProvider, SignatureScheme, Signer}; +use embedded_tls::{CryptoProvider, SignatureScheme}; +use p256::ecdsa::SigningKey; use rand::rngs::OsRng; use rustls::server::AllowAnyAuthenticatedClient; use std::net::SocketAddr; @@ -71,7 +72,7 @@ struct Provider { impl CryptoProvider for Provider { type CipherSuite = embedded_tls::Aes128GcmSha256; type SecureRandom = OsRng; - type SignatureCurve = p256::NistP256; + type Signature = p256::ecdsa::DerSignature; fn rng(&mut self) -> &mut Self::SecureRandom { &mut self.rng @@ -80,13 +81,15 @@ impl CryptoProvider for Provider { fn signer( &mut self, key_der: &[u8], - ) -> Result, embedded_tls::TlsError> { - Ok(Signer { - secret_key: SecretKey::from_sec1_der(key_der) - .map_err(|_| embedded_tls::TlsError::InvalidPrivateKey)?, - scheme: SignatureScheme::EcdsaSecp256r1Sha256, - rng: &mut self.rng, - }) + ) -> Result<(impl signature::SignerMut, SignatureScheme), embedded_tls::TlsError> + { + let secret_key = SecretKey::from_sec1_der(key_der) + .map_err(|_| embedded_tls::TlsError::InvalidPrivateKey)?; + + Ok(( + SigningKey::from(&secret_key), + SignatureScheme::EcdsaSecp256r1Sha256, + )) } } From ec81da46ff68af4d9000989a89a051e2aa9701ca Mon Sep 17 00:00:00 2001 From: Mathias Date: Sat, 24 Feb 2024 20:50:39 +0100 Subject: [PATCH 16/19] Fix examples --- examples/blocking/src/main.rs | 2 +- examples/embassy/src/main.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/blocking/src/main.rs b/examples/blocking/src/main.rs index f972328e..cc607196 100644 --- a/examples/blocking/src/main.rs +++ b/examples/blocking/src/main.rs @@ -16,7 +16,7 @@ impl<'a> CryptoProvider for Provider<'a> { type SecureRandom = OsRng; - type SignatureCurve; + type Signature = &'static [u8]; fn rng(&mut self) -> &mut Self::SecureRandom { &mut self.rng diff --git a/examples/embassy/src/main.rs b/examples/embassy/src/main.rs index 51904541..8daee608 100644 --- a/examples/embassy/src/main.rs +++ b/examples/embassy/src/main.rs @@ -5,7 +5,7 @@ use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; use embassy_net_tuntap::TunTapDevice; use embassy_time::Duration; use embedded_io_async::Write; -use embedded_tls::{Aes128GcmSha256, NoVerify, TlsConfig, TlsConnection, TlsContext}; +use embedded_tls::{Aes128GcmSha256, TlsConfig, TlsConnection, TlsContext, UnsecureProvider}; use heapless::Vec; use log::*; use rand::{rngs::OsRng, RngCore}; @@ -81,7 +81,6 @@ async fn main_task(spawner: Spawner) { let mut read_record_buffer = [0; 16384]; let mut write_record_buffer = [0; 16384]; - let mut rng = OsRng; let config = TlsConfig::new().with_server_name("example.com"); let mut tls = TlsConnection::new(socket, &mut read_record_buffer, &mut write_record_buffer); From 6f5e7d3d0da6242cbceebb2e0a381c95a5e77c5b Mon Sep 17 00:00:00 2001 From: Mathias Date: Tue, 27 Feb 2024 08:37:38 +0100 Subject: [PATCH 17/19] Slightly change the CryptoProvider trait to not have associated SecureRandom, but rather have a return type impl bound. Also add blanket impl of CryptoProvider for mutable references --- src/config.rs | 35 ++++++++++++++++++++++++++++------- src/handshake/client_hello.rs | 4 ++-- tests/client_cert_test.rs | 7 ++++--- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/config.rs b/src/config.rs index 26d04129..6bde7e7c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -149,10 +149,9 @@ impl TlsClock for NoClock { pub trait CryptoProvider { type CipherSuite: TlsCipherSuite; - type SecureRandom: CryptoRngCore; type Signature: AsRef<[u8]>; - fn rng(&mut self) -> &mut Self::SecureRandom; + fn rng(&mut self) -> impl CryptoRngCore; fn verifier( &mut self, @@ -164,11 +163,36 @@ pub trait CryptoProvider { fn signer( &mut self, _key_der: &[u8], - ) -> Result<(impl signature::SignerMut, SignatureScheme), crate::TlsError> { + ) -> Result<(impl signature::SignerMut, SignatureScheme), crate::TlsError> + { Err::<(NoSign, _), crate::TlsError>(crate::TlsError::Unimplemented) } } +impl CryptoProvider for &mut T { + type CipherSuite = T::CipherSuite; + + type Signature = T::Signature; + + fn rng(&mut self) -> impl CryptoRngCore { + T::rng(self) + } + + fn verifier( + &mut self, + ) -> Result<&mut impl TlsVerifier<'_, Self::CipherSuite>, crate::TlsError> { + T::verifier(self) + } + + fn signer( + &mut self, + key_der: &[u8], + ) -> Result<(impl signature::SignerMut, SignatureScheme), crate::TlsError> + { + T::signer(self, key_der) + } +} + pub struct NoSign; impl signature::Signer for NoSign { @@ -195,12 +219,9 @@ impl CryptoProvider for UnsecureProvider { type CipherSuite = CipherSuite; - type SecureRandom = RNG; type Signature = &'static [u8]; - // type SignatureCurve = NistP256; - // type Signature = (); - fn rng(&mut self) -> &mut Self::SecureRandom { + fn rng(&mut self) -> impl CryptoRngCore { &mut self.rng } } diff --git a/src/handshake/client_hello.rs b/src/handshake/client_hello.rs index c0e4cb68..0c943936 100644 --- a/src/handshake/client_hello.rs +++ b/src/handshake/client_hello.rs @@ -37,7 +37,7 @@ impl<'config, CipherSuite> ClientHello<'config, CipherSuite> where CipherSuite: TlsCipherSuite, { - pub fn new(config: &'config TlsConfig<'config>, provider: &mut Provider) -> Self + pub fn new(config: &'config TlsConfig<'config>, mut provider: Provider) -> Self where Provider: CryptoProvider, { @@ -48,7 +48,7 @@ where config, random, cipher_suite: PhantomData, - secret: EphemeralSecret::random(provider.rng()), + secret: EphemeralSecret::random(&mut provider.rng()), } } diff --git a/tests/client_cert_test.rs b/tests/client_cert_test.rs index 859d19ff..d8b6d9a0 100644 --- a/tests/client_cert_test.rs +++ b/tests/client_cert_test.rs @@ -3,6 +3,7 @@ use embedded_io_adapters::tokio_1::FromTokio; use embedded_tls::{CryptoProvider, SignatureScheme}; use p256::ecdsa::SigningKey; use rand::rngs::OsRng; +use rand_core::CryptoRngCore; use rustls::server::AllowAnyAuthenticatedClient; use std::net::SocketAddr; use std::sync::Once; @@ -71,10 +72,9 @@ struct Provider { impl CryptoProvider for Provider { type CipherSuite = embedded_tls::Aes128GcmSha256; - type SecureRandom = OsRng; type Signature = p256::ecdsa::DerSignature; - fn rng(&mut self) -> &mut Self::SecureRandom { + fn rng(&mut self) -> impl CryptoRngCore { &mut self.rng } @@ -129,7 +129,8 @@ async fn test_client_certificate_auth() { log::info!("SIZE of connection is {}", core::mem::size_of_val(&tls)); - let open_fut = tls.open(TlsContext::new(&config, Provider::default())); + let mut provider = Provider::default(); + let open_fut = tls.open(TlsContext::new(&config, &mut provider)); log::info!("SIZE of open fut is {}", core::mem::size_of_val(&open_fut)); open_fut.await.expect("error establishing TLS connection"); log::info!("Established"); From d325a3140072b24c21977249574ec58711e16c22 Mon Sep 17 00:00:00 2001 From: Mathias Date: Tue, 27 Feb 2024 15:13:53 +0100 Subject: [PATCH 18/19] Add a software signer based on p256 to the default UnsecureProvider --- Cargo.toml | 2 +- examples/blocking/src/main.rs | 4 +--- src/config.rs | 19 ++++++++++++++++++- src/lib.rs | 1 + 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c4d722fd..9869aff2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ embedded-io-adapters = { version = "0.6", optional = true } generic-array = { version = "0.14", default-features = false } webpki = { package = "rustls-webpki", version = "0.101.7", default-features = false, optional = true } signature = { version = "2.2", default-features = false } +ecdsa = { version = "0.16.9", default-features = false } # Logging alternatives log = { version = "0.4", optional = true } @@ -51,7 +52,6 @@ rand = "0.8" log = "0.4" pem-parser = "0.1.1" openssl = "0.10.44" -ecdsa = { version = "0.16.9", default-features = false } [features] default = ["std", "log", "tokio"] diff --git a/examples/blocking/src/main.rs b/examples/blocking/src/main.rs index cc607196..30a48212 100644 --- a/examples/blocking/src/main.rs +++ b/examples/blocking/src/main.rs @@ -14,11 +14,9 @@ struct Provider<'a> { impl<'a> CryptoProvider for Provider<'a> { type CipherSuite = Aes128GcmSha256; - type SecureRandom = OsRng; - type Signature = &'static [u8]; - fn rng(&mut self) -> &mut Self::SecureRandom { + fn rng(&mut self) -> impl embedded_tls::CryptoRngCore { &mut self.rng } diff --git a/src/config.rs b/src/config.rs index 6bde7e7c..8a64ab1c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,10 +9,13 @@ use crate::TlsError; use aes_gcm::{AeadInPlace, Aes128Gcm, Aes256Gcm, KeyInit}; use digest::core_api::BlockSizeUser; use digest::{Digest, FixedOutput, OutputSizeUser, Reset}; +use ecdsa::elliptic_curve::SecretKey; use generic_array::ArrayLength; use heapless::Vec; +use p256::ecdsa::SigningKey; use rand_core::CryptoRngCore; pub use sha2::Sha256; + pub use sha2::Sha384; use typenum::{Sum, U10, U12, U16, U32}; @@ -219,11 +222,25 @@ impl CryptoProvider for UnsecureProvider { type CipherSuite = CipherSuite; - type Signature = &'static [u8]; + type Signature = p256::ecdsa::DerSignature; fn rng(&mut self) -> impl CryptoRngCore { &mut self.rng } + + fn signer( + &mut self, + key_der: &[u8], + ) -> Result<(impl signature::SignerMut, SignatureScheme), crate::TlsError> + { + let secret_key = + SecretKey::from_sec1_der(key_der).map_err(|_| TlsError::InvalidPrivateKey)?; + + Ok(( + SigningKey::from(&secret_key), + SignatureScheme::EcdsaSecp256r1Sha256, + )) + } } #[derive(Debug)] diff --git a/src/lib.rs b/src/lib.rs index 92cdff6f..5874f4c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,6 +69,7 @@ mod write_buffer; pub use config::UnsecureProvider; pub use extensions::extension_data::signature_algorithms::SignatureScheme; pub use handshake::certificate_verify::CertificateVerify; +pub use rand_core::{CryptoRng, CryptoRngCore}; #[cfg(feature = "webpki")] pub mod webpki; From 0b0be9bce1561153b0d8a270ac26d1ef9c38d0a0 Mon Sep 17 00:00:00 2001 From: Mathias Date: Thu, 29 Feb 2024 13:52:15 +0100 Subject: [PATCH 19/19] Remove lifetime from TlsVerifier, and change webpki to hold hostname as an owned heapless String --- CHANGELOG.md | 2 ++ examples/blocking/src/main.rs | 8 ++++---- src/asynch.rs | 7 +++++-- src/blocking.rs | 7 +++++-- src/config.rs | 22 ++++++---------------- src/webpki.rs | 21 ++++++++++----------- 6 files changed, 32 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38ba4ac1..7a4605b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- Add missing implementation to support Client Certificate Authorization (#135) + ## 0.17.0 - 2024-01-06 - Update to stable rust diff --git a/examples/blocking/src/main.rs b/examples/blocking/src/main.rs index 30a48212..1afcaf9d 100644 --- a/examples/blocking/src/main.rs +++ b/examples/blocking/src/main.rs @@ -6,12 +6,12 @@ use rand::rngs::OsRng; use std::net::TcpStream; use std::time::SystemTime; -struct Provider<'a> { +struct Provider { rng: OsRng, - verifier: CertVerifier<'a, Aes128GcmSha256, SystemTime, 4096>, + verifier: CertVerifier, } -impl<'a> CryptoProvider for Provider<'a> { +impl CryptoProvider for Provider { type CipherSuite = Aes128GcmSha256; type Signature = &'static [u8]; @@ -22,7 +22,7 @@ impl<'a> CryptoProvider for Provider<'a> { fn verifier( &mut self, - ) -> Result<&mut impl TlsVerifier<'_, Self::CipherSuite>, embedded_tls::TlsError> { + ) -> Result<&mut impl TlsVerifier, embedded_tls::TlsError> { Ok(&mut self.verifier) } } diff --git a/src/asynch.rs b/src/asynch.rs index e085ba9c..5d05dc83 100644 --- a/src/asynch.rs +++ b/src/asynch.rs @@ -78,8 +78,11 @@ where Provider: CryptoProvider, { let mut handshake: Handshake = Handshake::new(); - if let Ok(verifier) = context.crypto_provider.verifier() { - verifier.set_hostname_verification(context.config.server_name)?; + if let (Ok(verifier), Some(server_name)) = ( + context.crypto_provider.verifier(), + context.config.server_name, + ) { + verifier.set_hostname_verification(server_name)?; } let mut state = State::ClientHello; diff --git a/src/blocking.rs b/src/blocking.rs index 33c0336f..2e6fc83d 100644 --- a/src/blocking.rs +++ b/src/blocking.rs @@ -77,8 +77,11 @@ where Provider: CryptoProvider, { let mut handshake: Handshake = Handshake::new(); - if let Ok(verifier) = context.crypto_provider.verifier() { - verifier.set_hostname_verification(context.config.server_name)?; + if let (Ok(verifier), Some(server_name)) = ( + context.crypto_provider.verifier(), + context.config.server_name, + ) { + verifier.set_hostname_verification(server_name)?; } let mut state = State::ClientHello; diff --git a/src/config.rs b/src/config.rs index 8a64ab1c..6a377fc5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -70,15 +70,12 @@ impl TlsCipherSuite for Aes256GcmSha384 { /// The verifier is responsible for verifying certificates and signatures. Since certificate verification is /// an expensive process, this trait allows clients to choose how much verification should take place, /// and also to skip the verification if the server is verified through other means (I.e. a pre-shared key). -pub trait TlsVerifier<'a, CipherSuite> +pub trait TlsVerifier where CipherSuite: TlsCipherSuite, { /// Host verification is enabled by passing a server hostname. - fn set_hostname_verification( - &mut self, - hostname: Option<&'a str>, - ) -> Result<(), crate::TlsError>; + fn set_hostname_verification(&mut self, hostname: &str) -> Result<(), crate::TlsError>; /// Verify a certificate. /// @@ -100,14 +97,11 @@ where pub struct NoVerify; -impl<'a, CipherSuite> TlsVerifier<'a, CipherSuite> for NoVerify +impl TlsVerifier for NoVerify where CipherSuite: TlsCipherSuite, { - fn set_hostname_verification( - &mut self, - _hostname: Option<&'a str>, - ) -> Result<(), crate::TlsError> { + fn set_hostname_verification(&mut self, _hostname: &str) -> Result<(), crate::TlsError> { Ok(()) } @@ -156,9 +150,7 @@ pub trait CryptoProvider { fn rng(&mut self) -> impl CryptoRngCore; - fn verifier( - &mut self, - ) -> Result<&mut impl TlsVerifier<'_, Self::CipherSuite>, crate::TlsError> { + fn verifier(&mut self) -> Result<&mut impl TlsVerifier, crate::TlsError> { Err::<&mut NoVerify, _>(crate::TlsError::Unimplemented) } @@ -181,9 +173,7 @@ impl CryptoProvider for &mut T { T::rng(self) } - fn verifier( - &mut self, - ) -> Result<&mut impl TlsVerifier<'_, Self::CipherSuite>, crate::TlsError> { + fn verifier(&mut self) -> Result<&mut impl TlsVerifier, crate::TlsError> { T::verifier(self) } diff --git a/src/webpki.rs b/src/webpki.rs index ea7b02ea..2734d76b 100644 --- a/src/webpki.rs +++ b/src/webpki.rs @@ -89,18 +89,18 @@ static ALL_SIGALGS: &[&webpki::SignatureAlgorithm] = &[ &webpki::ED25519, ]; -pub struct CertVerifier<'a, CipherSuite, Clock, const CERT_SIZE: usize> +pub struct CertVerifier where Clock: TlsClock, CipherSuite: TlsCipherSuite, { - host: Option<&'a str>, + host: Option>, certificate_transcript: Option, certificate: Option>, _clock: PhantomData, } -impl<'a, CipherSuite, Clock, const CERT_SIZE: usize> CertVerifier<'a, CipherSuite, Clock, CERT_SIZE> +impl CertVerifier where Clock: TlsClock, CipherSuite: TlsCipherSuite, @@ -115,17 +115,16 @@ where } } -impl<'a, CipherSuite, Clock, const CERT_SIZE: usize> TlsVerifier<'a, CipherSuite> - for CertVerifier<'a, CipherSuite, Clock, CERT_SIZE> +impl TlsVerifier + for CertVerifier where CipherSuite: TlsCipherSuite, Clock: TlsClock, { - fn set_hostname_verification( - &mut self, - hostname: Option<&'a str>, - ) -> Result<(), crate::TlsError> { - self.host = hostname; + fn set_hostname_verification(&mut self, hostname: &str) -> Result<(), TlsError> { + self.host.replace( + heapless::String::try_from(hostname).map_err(|_| TlsError::InsufficientSpace)?, + ); Ok(()) } @@ -135,7 +134,7 @@ where ca: &Option, cert: ServerCertificate, ) -> Result<(), TlsError> { - verify_certificate(self.host.clone(), ca, &cert, Clock::now())?; + verify_certificate(self.host.as_deref(), ca, &cert, Clock::now())?; self.certificate.replace(cert.try_into()?); self.certificate_transcript.replace(transcript.clone()); Ok(())