dimpl — DTLS 1.2 and 1.3 implementation (Sans‑IO, Sync)
dimpl is a DTLS 1.2 and 1.3 implementation aimed at WebRTC. It is a Sans‑IO state machine you embed into your own UDP/RTC event loop: you feed incoming datagrams, poll for outgoing records or timers, and wire up certificate verification and SRTP key export yourself.
- DTLS 1.2 and 1.3: Implements the DTLS handshake and record layer used by WebRTC.
- Safety:
forbid(unsafe_code)throughout the crate. - Minimal Rust‑only deps: Uses small, well‑maintained Rust crypto crates.
- Low overhead: Tight control over allocations and buffers; Sans‑IO integration.
- DTLS 1.0
- Async (the crate is Sans‑IO and event‑loop agnostic)
- no_std (at least not without allocation)
- RSA
- DHE
Three constructors control which DTLS version is used:
- [
Dtls::new_12] — explicit DTLS 1.2 - [
Dtls::new_13] — explicit DTLS 1.3 - [
Dtls::new_auto] — auto‑sense: the first incoming ClientHello determines the version (based on thesupported_versionsextension)
- Cipher suites (TLS 1.2 over DTLS)
ECDHE_ECDSA_AES256_GCM_SHA384ECDHE_ECDSA_AES128_GCM_SHA256
- Cipher suites (TLS 1.3 over DTLS)
TLS_AES_128_GCM_SHA256TLS_AES_256_GCM_SHA384
- AEAD: AES‑GCM 128/256 only (no CBC/EtM modes).
- Key exchange: ECDHE (P‑256/P‑384)
- Signatures: ECDSA P‑256/SHA‑256, ECDSA P‑384/SHA‑384
- DTLS‑SRTP: Exports keying material for
SRTP_AEAD_AES_256_GCM,SRTP_AEAD_AES_128_GCM, andSRTP_AES128_CM_SHA1_80(RFC 5764, RFC 7714). - Extended Master Secret (RFC 7627) is negotiated and enforced (DTLS 1.2).
- Not supported: PSK cipher suites.
During the handshake the engine emits [Output::PeerCert] with the peer's
leaf certificate (DER). The crate uses that certificate to verify DTLS
handshake messages, but it does not perform any PKI validation. Your
application is responsible for validating the peer certificate according to
your policy (fingerprint, chain building, name/EKU checks, pinning, etc.).
Drive the engine with three calls:
Dtls::handle_packet— feed an entire received UDP datagram.Dtls::poll_output— drain pending output: DTLS records, timers, events.Dtls::handle_timeout— trigger retransmissions/time‑based progress.
The output is an [Output] enum with borrowed references into your provided buffer:
Packet(&[u8]): send on your UDP socketTimeout(Instant): schedule a timer and callhandle_timeoutat/after itConnected: handshake completePeerCert(&[u8]): peer leaf certificate (DER) — validate in your appKeyingMaterial(KeyingMaterial, SrtpProfile): DTLS‑SRTP exportApplicationData(&[u8]): plaintext received from peer
use std::sync::Arc;
use std::time::Instant;
use dimpl::{certificate, Config, Dtls, Output};
// Stub I/O to keep the example focused on the state machine
enum Event { Udp(Vec<u8>), Timer(Instant) }
fn wait_next_event(_next_wake: Option<Instant>) -> Event { Event::Udp(Vec::new()) }
fn send_udp(_bytes: &[u8]) {}
fn example_event_loop(mut dtls: Dtls) -> Result<(), dimpl::Error> {
let mut next_wake: Option<Instant> = None;
loop {
// Drain engine output until we have to wait for I/O or a timer
let mut out_buf = vec![0u8; 2048];
loop {
match dtls.poll_output(&mut out_buf) {
Output::Packet(p) => send_udp(p),
Output::Timeout(t) => { next_wake = Some(t); break; }
Output::Connected => {
// DTLS established — application may start sending
}
Output::PeerCert(_der) => {
// Inspect peer leaf certificate if desired
}
Output::KeyingMaterial(_km, _profile) => {
// Provide to SRTP stack
}
Output::ApplicationData(_data) => {
// Deliver plaintext to application
}
}
}
// Block waiting for either UDP input or the scheduled timeout
match wait_next_event(next_wake) {
Event::Udp(pkt) => dtls.handle_packet(&pkt)?,
Event::Timer(now) => dtls.handle_timeout(now)?,
}
}
}
fn mk_dtls_client() -> Dtls {
let cert = certificate::generate_self_signed_certificate().unwrap();
let cfg = Arc::new(Config::default());
let mut dtls = Dtls::new_12(cfg, cert, Instant::now());
dtls.set_active(true); // client role
dtls
}
// Putting it together
let dtls = mk_dtls_client();
let _ = example_event_loop(dtls);Rust 1.81.0
- Session resumption is not implemented (WebRTC does a full handshake on ICE restart).
- Renegotiation is not implemented (WebRTC does full restart).
License: MIT OR Apache-2.0