diff --git a/Cargo.toml b/Cargo.toml index f2008a9..9dbfd7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,4 +19,4 @@ resolver = "2" [workspace.dependencies] boring = { version = "4.0", default-features = false } boring-sys = { version = "4.0", default-features = false } -rustls = { version = "=0.22.0-alpha.4", default-features = false } +rustls = { version = "=0.22.0-alpha.5", default-features = false } diff --git a/Readme.md b/Readme.md index 855d785..10ec339 100644 --- a/Readme.md +++ b/Readme.md @@ -7,7 +7,7 @@ This is just a dump of me figuring out how to interface with boring and rustls. It works to establish a connection and exchange data but I haven't written real tests yet, nor did I cleanup the code or made the effort to make it look nice. There is probably some code in here that should rather live in the `boring` crate. -Further, the rustls crypto provider API is still not stable it seems. This works currently with `rustls = 0.22.0-alpha.4`. +Further, the rustls crypto provider API is still not stable it seems. This works currently with `rustls = 0.22.0-alpha.5`. ### Supported ciphers Currently, supports only TLS 1.3: @@ -17,6 +17,8 @@ AES_256_GCM_SHA384 CHACHA20_POLY1305_SHA256 ``` +QUIC: not yet supported + TLS 1.2: ``` ECDHE_ECDSA_AES128_GCM_SHA256 diff --git a/boring-rustls-provider/src/aead.rs b/boring-rustls-provider/src/aead.rs index 2976b9d..9d6058d 100644 --- a/boring-rustls-provider/src/aead.rs +++ b/boring-rustls-provider/src/aead.rs @@ -109,7 +109,7 @@ where T: BoringAead, { fn encrypt( - &self, + &mut self, msg: cipher::BorrowedPlainMessage, seq: u64, ) -> Result { @@ -121,8 +121,7 @@ where let fixed_iv_len = ::FIXED_IV_LEN; let explicit_nonce_len = ::EXPLICIT_NONCE_LEN; - let total_len = - msg.payload.len() + self.crypter.max_overhead() + explicit_nonce_len; + let total_len = self.encrypted_payload_len(msg.payload.len()); let mut full_payload = Vec::with_capacity(total_len); full_payload.extend_from_slice(&nonce.0.as_ref()[fixed_iv_len..]); @@ -139,7 +138,7 @@ where } ProtocolVersion::TLSv1_3 => { - let total_len = msg.payload.len() + 1 + self.crypter.max_overhead(); + let total_len = self.encrypted_payload_len(msg.payload.len()); let mut payload = Vec::with_capacity(total_len); payload.extend_from_slice(msg.payload); @@ -160,10 +159,15 @@ where } } - // Next version seems to add this - // fn encrypted_payload_len(&self, payload_len: usize) -> usize { - // payload_len + 1 + self.crypter.max_overhead() - // } + fn encrypted_payload_len(&self, payload_len: usize) -> usize { + match self.tls_version { + ProtocolVersion::TLSv1_2 => { + payload_len + self.crypter.max_overhead() + ::EXPLICIT_NONCE_LEN + } + ProtocolVersion::TLSv1_3 => payload_len + 1 + self.crypter.max_overhead(), + _ => unimplemented!(), + } + } } impl cipher::MessageDecrypter for BoringAeadCrypter @@ -171,7 +175,7 @@ where T: BoringAead, { fn decrypt( - &self, + &mut self, mut m: cipher::OpaqueMessage, seq: u64, ) -> Result { diff --git a/boring-rustls-provider/src/tls12.rs b/boring-rustls-provider/src/tls12.rs index e76b43e..faf8d12 100644 --- a/boring-rustls-provider/src/tls12.rs +++ b/boring-rustls-provider/src/tls12.rs @@ -26,6 +26,8 @@ pub static ECDHE_ECDSA_AES128_GCM_SHA256: Tls12CipherSuite = Tls12CipherSuite { common: rustls::CipherSuiteCommon { suite: rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, hash_provider: hash::SHA256, + confidentiality_limit: 1 << 23, + integrity_limit: 1 << 52, }, aead_alg: &aead::Aead::::DEFAULT, prf_provider: &PRF_SHA256, @@ -37,6 +39,8 @@ pub static ECDHE_RSA_AES128_GCM_SHA256: Tls12CipherSuite = Tls12CipherSuite { common: rustls::CipherSuiteCommon { suite: rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, hash_provider: hash::SHA256, + confidentiality_limit: 1 << 23, + integrity_limit: 1 << 52, }, aead_alg: &aead::Aead::::DEFAULT, prf_provider: &PRF_SHA256, @@ -48,6 +52,8 @@ pub static ECDHE_ECDSA_AES256_GCM_SHA384: Tls12CipherSuite = Tls12CipherSuite { common: rustls::CipherSuiteCommon { suite: rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, hash_provider: hash::SHA384, + confidentiality_limit: 1 << 23, + integrity_limit: 1 << 52, }, aead_alg: &aead::Aead::::DEFAULT, prf_provider: &PRF_SHA384, @@ -59,6 +65,8 @@ pub static ECDHE_RSA_AES256_GCM_SHA384: Tls12CipherSuite = Tls12CipherSuite { common: rustls::CipherSuiteCommon { suite: rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, hash_provider: hash::SHA384, + confidentiality_limit: 1 << 23, + integrity_limit: 1 << 52, }, aead_alg: &aead::Aead::::DEFAULT, prf_provider: &PRF_SHA384, @@ -70,6 +78,8 @@ pub static ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: Tls12CipherSuite = Tls12Ci common: rustls::CipherSuiteCommon { suite: rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, hash_provider: hash::SHA256, + confidentiality_limit: u64::MAX, + integrity_limit: 1 << 36, }, aead_alg: &aead::Aead::::DEFAULT, prf_provider: &PRF_SHA256, @@ -81,6 +91,8 @@ pub static ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: Tls12CipherSuite = Tls12Ciph common: rustls::CipherSuiteCommon { suite: rustls::CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, hash_provider: hash::SHA256, + confidentiality_limit: u64::MAX, + integrity_limit: 1 << 36, }, aead_alg: &aead::Aead::::DEFAULT, prf_provider: &PRF_SHA256, diff --git a/boring-rustls-provider/src/tls13.rs b/boring-rustls-provider/src/tls13.rs index 691d4c6..c400bad 100644 --- a/boring-rustls-provider/src/tls13.rs +++ b/boring-rustls-provider/src/tls13.rs @@ -6,26 +6,35 @@ pub static AES_128_GCM_SHA256: Tls13CipherSuite = Tls13CipherSuite { common: rustls::CipherSuiteCommon { suite: rustls::CipherSuite::TLS13_AES_128_GCM_SHA256, hash_provider: hash::SHA256, + confidentiality_limit: 1 << 23, + integrity_limit: 1 << 52, }, hkdf_provider: &hkdf::Hkdf::::DEFAULT, aead_alg: &aead::Aead::::DEFAULT, + quic: None, }; pub static AES_256_GCM_SHA384: Tls13CipherSuite = Tls13CipherSuite { common: rustls::CipherSuiteCommon { suite: rustls::CipherSuite::TLS13_AES_256_GCM_SHA384, hash_provider: hash::SHA384, + confidentiality_limit: 1 << 23, + integrity_limit: 1 << 52, }, hkdf_provider: &hkdf::Hkdf::::DEFAULT, aead_alg: &aead::Aead::::DEFAULT, + quic: None, }; pub static CHACHA20_POLY1305_SHA256: Tls13CipherSuite = Tls13CipherSuite { common: rustls::CipherSuiteCommon { suite: rustls::CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, hash_provider: hash::SHA256, + confidentiality_limit: u64::MAX, + integrity_limit: 1 << 36, }, hkdf_provider: &hkdf::Hkdf::::DEFAULT, aead_alg: &aead::Aead::::DEFAULT, + quic: None, }; diff --git a/boring-rustls-provider/tests/e2e.rs b/boring-rustls-provider/tests/e2e.rs index eb291b0..212f1ca 100644 --- a/boring-rustls-provider/tests/e2e.rs +++ b/boring-rustls-provider/tests/e2e.rs @@ -8,7 +8,7 @@ use tokio::{ use boring_rustls_provider::{tls12, tls13, PROVIDER}; use rustls::{ version::{TLS12, TLS13}, - ServerConfig, SupportedCipherSuite, + ClientConfig, ServerConfig, SupportedCipherSuite, }; use rustls_pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}; use tokio::net::TcpListener; @@ -28,7 +28,7 @@ async fn test_tls13_crypto() { ]; for cipher in ciphers { - let config = rustls::ClientConfig::builder_with_provider(PROVIDER) + let config = ClientConfig::builder_with_provider(PROVIDER) .with_cipher_suites(&[cipher]) .with_safe_default_kx_groups() .with_protocol_versions(&[&TLS13]) @@ -36,22 +36,7 @@ async fn test_tls13_crypto() { .with_root_certificates(root_store.clone()) .with_no_client_auth(); - let listener = new_listener().await; - let addr = listener.local_addr().unwrap(); - tokio::spawn(spawn_echo_server(listener, server_config.clone())); - - let connector = TlsConnector::from(Arc::new(config)); - let stream = TcpStream::connect(&addr).await.unwrap(); - - let mut stream = connector - .connect(rustls::ServerName::try_from("localhost").unwrap(), stream) - .await - .unwrap(); - - stream.write_all(b"HELLO").await.unwrap(); - let mut buf = Vec::new(); - let bytes = stream.read_to_end(&mut buf).await.unwrap(); - assert_eq!(&buf[..bytes], b"HELLO"); + do_exchange(config, server_config.clone()).await; } } @@ -69,7 +54,7 @@ async fn test_tls12_ec_crypto() { ]; for cipher in ciphers { - let config = rustls::ClientConfig::builder_with_provider(PROVIDER) + let config = ClientConfig::builder_with_provider(PROVIDER) .with_cipher_suites(&[cipher]) .with_safe_default_kx_groups() .with_protocol_versions(&[&TLS12]) @@ -77,22 +62,7 @@ async fn test_tls12_ec_crypto() { .with_root_certificates(root_store.clone()) .with_no_client_auth(); - let listener = new_listener().await; - let addr = listener.local_addr().unwrap(); - tokio::spawn(spawn_echo_server(listener, server_config.clone())); - - let connector = TlsConnector::from(Arc::new(config)); - let stream = TcpStream::connect(&addr).await.unwrap(); - - let mut stream = connector - .connect(rustls::ServerName::try_from("localhost").unwrap(), stream) - .await - .unwrap(); - - stream.write_all(b"HELLO").await.unwrap(); - let mut buf = Vec::new(); - let bytes = stream.read_to_end(&mut buf).await.unwrap(); - assert_eq!(&buf[..bytes], b"HELLO"); + do_exchange(config, server_config.clone()).await; } } @@ -110,7 +80,7 @@ async fn test_tls12_rsa_crypto() { ]; for cipher in ciphers { - let config = rustls::ClientConfig::builder_with_provider(PROVIDER) + let config = ClientConfig::builder_with_provider(PROVIDER) .with_cipher_suites(&[cipher]) .with_safe_default_kx_groups() .with_protocol_versions(&[&TLS12]) @@ -118,22 +88,7 @@ async fn test_tls12_rsa_crypto() { .with_root_certificates(root_store.clone()) .with_no_client_auth(); - let listener = new_listener().await; - let addr = listener.local_addr().unwrap(); - tokio::spawn(spawn_echo_server(listener, server_config.clone())); - - let connector = TlsConnector::from(Arc::new(config)); - let stream = TcpStream::connect(&addr).await.unwrap(); - - let mut stream = connector - .connect(rustls::ServerName::try_from("localhost").unwrap(), stream) - .await - .unwrap(); - - stream.write_all(b"HELLO").await.unwrap(); - let mut buf = Vec::new(); - let bytes = stream.read_to_end(&mut buf).await.unwrap(); - assert_eq!(&buf[..bytes], b"HELLO"); + do_exchange(config, server_config.clone()).await; } } @@ -141,6 +96,28 @@ async fn new_listener() -> TcpListener { TcpListener::bind("localhost:0").await.unwrap() } +async fn do_exchange(config: ClientConfig, server_config: Arc) { + let listener = new_listener().await; + let addr = listener.local_addr().unwrap(); + tokio::spawn(spawn_echo_server(listener, server_config.clone())); + + let connector = TlsConnector::from(Arc::new(config)); + let stream = TcpStream::connect(&addr).await.unwrap(); + + let mut stream = connector + .connect( + rustls_pki_types::ServerName::try_from("localhost").unwrap(), + stream, + ) + .await + .unwrap(); + + stream.write_all(b"HELLO").await.unwrap(); + let mut buf = Vec::new(); + let bytes = stream.read_to_end(&mut buf).await.unwrap(); + assert_eq!(&buf[..bytes], b"HELLO"); +} + async fn spawn_echo_server(listener: TcpListener, config: Arc) { let acceptor = TlsAcceptor::from(config);