Skip to main content

Crate dimpl

Crate dimpl 

Source
Expand description

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.

§Goals

  • 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.

§Non‑goals

  • DTLS 1.0
  • Async (the crate is Sans‑IO and event‑loop agnostic)
  • no_std (at least not without allocation)
  • RSA
  • DHE

§Version selection

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 the supported_versions extension)

§Cryptography surface

  • Cipher suites (TLS 1.2 over DTLS)
    • ECDHE_ECDSA_AES256_GCM_SHA384
    • ECDHE_ECDSA_AES128_GCM_SHA256
    • ECDHE_ECDSA_CHACHA20_POLY1305_SHA256
  • Cipher suites (TLS 1.3 over DTLS)
    • TLS_AES_128_GCM_SHA256
    • TLS_AES_256_GCM_SHA384
    • TLS_CHACHA20_POLY1305_SHA256
  • AEAD: AES‑GCM 128/256, ChaCha20‑Poly1305 (no CBC/EtM modes).
  • Key exchange: ECDHE (P‑256/P‑384), X25519
  • 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, and SRTP_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.

§Certificate model

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.).

§Sans‑IO integration model

Drive the engine with three calls:

The output is an Output enum with borrowed references into your provided buffer:

  • Packet(&[u8]): send on your UDP socket
  • Timeout(Instant): schedule a timer and call handle_timeout at/after it
  • Connected: handshake complete
  • PeerCert(&[u8]): peer leaf certificate (DER) — validate in your app
  • KeyingMaterial(KeyingMaterial, SrtpProfile): DTLS‑SRTP export
  • ApplicationData(&[u8]): plaintext received from peer

§Example (Sans‑IO loop)

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);

§MSRV

Rust 1.85.0

§Status

  • Session resumption is not implemented (WebRTC does a full handshake on ICE restart).
  • Renegotiation is not implemented (WebRTC does full restart).

Re-exports§

pub use crypto::KeyingMaterial;
pub use crypto::SrtpProfile;

Modules§

certificate
Certificate generation and formatting utilities exposed via the public certificate module.
crypto
Cryptographic primitives and helpers used by the DTLS engine.

Structs§

Config
DTLS configuration shared by all connections.
Dtls
Sans-IO DTLS endpoint (client or server).
DtlsCertificate
Certificate and private key pair.
Sequence
DTLS record sequence number (epoch + sequence).

Enums§

CompressionMethod
TLS compression methods.
ContentType
DTLS record content types.
Error
Errors returned by DTLS processing functions.
HashAlgorithm
Hash algorithms used in DTLS (RFC 5246, RFC 8446).
NamedGroup
Elliptic curves and key exchange groups (RFC 8422, RFC 8446).
Output
Output events produced by the DTLS engine when polled.
ProtocolVersion
DTLS protocol version identifiers.
SignatureAlgorithm
Signature algorithms used in DTLS handshakes.