Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature(*): Add missing implementation to support Client Certificate Authorization #135

Merged
merged 20 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
f0aac34
Started work on implementing the missing state of ClientCertVerify de…
MathiasKoch Feb 6, 2024
e009299
Add signature algorithms to CertificateRequest, and add priv_key to C…
MathiasKoch Feb 6, 2024
b95e3e7
Add client_cert_verify signature emit function
MathiasKoch Feb 6, 2024
9823055
Fix client cert authentication test, and fix encoding issues derived …
MathiasKoch Feb 9, 2024
03ab597
Add new CryptoProvider trait, and implement signing capabilities for …
MathiasKoch Feb 14, 2024
f3c82f0
Remove webpki as default feature again
MathiasKoch Feb 14, 2024
c8d634d
Use full buffer to update transcript on finalize_encrypted
MathiasKoch Feb 14, 2024
1718c0a
Revert to old test certificates and remove rustls client test
MathiasKoch Feb 14, 2024
10031b0
Cleanup signature struct slightly
MathiasKoch Feb 14, 2024
8b5d9d7
Revert public api in webpki impl
MathiasKoch Feb 14, 2024
2c8bd0f
Fix doctest
MathiasKoch Feb 15, 2024
c86644e
Rename SimpleProvider to UnsecureProvider
MathiasKoch Feb 15, 2024
67cbb0d
Fix 4/5 examples building
MathiasKoch Feb 15, 2024
c511ea7
Send ClientRecord::Alert if signer operation fails due to invalid pri…
MathiasKoch Feb 15, 2024
e28a522
Simplify signer trait bounds and allow all signatures, not just ecdsa
MathiasKoch Feb 24, 2024
ec81da4
Fix examples
MathiasKoch Feb 24, 2024
6f5e7d3
Slightly change the CryptoProvider trait to not have associated Secur…
MathiasKoch Feb 27, 2024
d325a31
Add a software signer based on p256 to the default UnsecureProvider
MathiasKoch Feb 27, 2024
0b0be9b
Remove lifetime from TlsVerifier, and change webpki to hold hostname …
MathiasKoch Feb 29, 2024
0564440
Rebase on master
MathiasKoch Feb 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 11 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,19 @@ 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",
"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 }
Expand All @@ -28,13 +34,15 @@ 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 }
signature = { version = "2.2", default-features = false }
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"
Expand Down
32 changes: 28 additions & 4 deletions examples/blocking/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,27 @@ use rand::rngs::OsRng;
use std::net::TcpStream;
use std::time::SystemTime;

struct Provider {
rng: OsRng,
verifier: CertVerifier<Aes128GcmSha256, SystemTime, 4096>,
}

impl CryptoProvider for Provider {
type CipherSuite = Aes128GcmSha256;

type Signature = &'static [u8];

fn rng(&mut self) -> impl embedded_tls::CryptoRngCore {
&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");
Expand All @@ -14,15 +35,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<FromStd<TcpStream>, 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::<OsRng, CertVerifier<Aes128GcmSha256, SystemTime, 4096>>(TlsContext::new(
&config, &mut rng,
tls.open(TlsContext::new(
&config,
Provider {
rng: OsRng,
verifier: CertVerifier::new(),
},
))
.expect("error establishing TLS connection");

Expand Down
19 changes: 10 additions & 9 deletions examples/embassy/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -57,7 +57,7 @@ async fn main_task(spawner: Spawner) {
device,
config,
RESOURCES.init(StackResources::<3>::new()),
seed
seed,
));

// Launch network task
Expand All @@ -81,14 +81,15 @@ 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<TcpSocket, Aes128GcmSha256> =
TlsConnection::new(socket, &mut read_record_buffer, &mut write_record_buffer);

tls.open::<OsRng, NoVerify>(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::<Aes128GcmSha256>(OsRng),
))
.await
.expect("error establishing TLS connection");

tls.write_all(b"ping").await.expect("error writing data");
tls.flush().await.expect("error flushing data");
Expand Down
12 changes: 7 additions & 5 deletions examples/nrf52/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Dummy, Aes128GcmSha256> =
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::<Rng, NoVerify>(TlsContext::new(&config, &mut rng))
.expect("error establishing TLS connection");
tls.open(TlsContext::new(
&config,
UnsecureProvider::new::<Aes128GcmSha256>(rng),
))
.expect("error establishing TLS connection");

tls.write_all(b"ping").expect("error writing data");
tls.flush().expect("error flushing data");
Expand Down
12 changes: 7 additions & 5 deletions examples/tokio-psk/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,18 @@ async fn main() -> Result<(), Box<dyn Error>> {
let config = TlsConfig::new()
.with_server_name("localhost")
.with_psk(&[0xaa, 0xbb, 0xcc, 0xdd], &[b"vader"]);
let mut rng = OsRng;
let mut tls: TlsConnection<FromTokio<TcpStream>, Aes128GcmSha256> = TlsConnection::new(
let mut tls = TlsConnection::new(
FromTokio::new(stream),
&mut read_record_buffer,
&mut write_record_buffer,
);

tls.open::<OsRng, NoVerify>(TlsContext::new(&config, &mut rng))
.await
.expect("error establishing TLS connection");
tls.open(TlsContext::new(
&config,
UnsecureProvider::new::<Aes128GcmSha256>(OsRng),
))
.await
.expect("error establishing TLS connection");

tls.write_all(b"ping").await.expect("error writing data");
tls.flush().await.expect("error flushing data");
Expand Down
12 changes: 7 additions & 5 deletions examples/tokio/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,18 @@ async fn main() -> Result<(), Box<dyn Error>> {
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<FromTokio<TcpStream>, Aes128GcmSha256> = TlsConnection::new(
let mut tls = TlsConnection::new(
FromTokio::new(stream),
&mut read_record_buffer,
&mut write_record_buffer,
);

tls.open::<OsRng, NoVerify>(TlsContext::new(&config, &mut rng))
.await
.expect("error establishing TLS connection");
tls.open(TlsContext::new(
&config,
UnsecureProvider::new::<Aes128GcmSha256>(OsRng),
))
.await
.expect("error establishing TLS connection");

tls.write_all(b"ping").await.expect("error writing data");
tls.flush().await.expect("error flushing data");
Expand Down
19 changes: 11 additions & 8 deletions src/asynch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use crate::TlsError;
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};

pub use crate::config::*;
#[cfg(feature = "std")]
Expand Down Expand Up @@ -71,16 +70,20 @@ 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<CipherSuite = CipherSuite>,
{
let mut handshake: Handshake<CipherSuite, Verifier> =
Handshake::new(Verifier::new(context.config.server_name));
let mut handshake: Handshake<CipherSuite> = Handshake::new();
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;

while state != State::ApplicationData {
Expand All @@ -92,7 +95,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);
Expand Down
19 changes: 11 additions & 8 deletions src/blocking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use crate::split::{SplitState, SplitStateContainer};
use crate::write_buffer::WriteBuffer;
use embedded_io::Error as _;
use embedded_io::{BufRead, ErrorType, Read, Write};
use rand_core::{CryptoRng, RngCore};

pub use crate::config::*;
#[cfg(feature = "std")]
Expand Down Expand Up @@ -70,16 +69,20 @@ 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<CipherSuite = CipherSuite>,
{
let mut handshake: Handshake<CipherSuite, Verifier> =
Handshake::new(Verifier::new(context.config.server_name));
let mut handshake: Handshake<CipherSuite> = Handshake::new();
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;

while state != State::ApplicationData {
Expand All @@ -90,7 +93,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;
Expand Down
Loading