rustls-ccm 0.2.0

CCM and CCM-8 cipher suites for rustls (TLS 1.2 and TLS 1.3)
Documentation

rustls-ccm

AES-CCM cipher suites for rustls.

Neither aws-lc-rs nor ring expose AES-CCM, so rustls's built-in providers cannot offer these suites. This crate fills the gap using the RustCrypto aes + ccm crates, plugged in via rustls's CryptoProvider extension point.

Why

CCM cipher suites are required or recommended by several IoT and energy protocols:

  • IEEE 2030.5 (Smart Energy) — mandates TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
  • Matter / Thread — uses TLS 1.3 TLS_AES_128_CCM_SHA256
  • RFC 7925 (constrained-device TLS) — profiles CCM and CCM-8 suites
  • CoAP over DTLS — commonly uses CCM-8 for bandwidth efficiency

Without this crate, using rustls for these protocols requires falling back to OpenSSL or BoringSSL (which removed CCM entirely).

Cipher suites

TLS 1.2 (RFC 7251)

Suite Tag Key
TLS_ECDHE_ECDSA_WITH_AES_128_CCM 16 B 128-bit
TLS_ECDHE_ECDSA_WITH_AES_256_CCM 16 B 256-bit
TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 8 B 128-bit
TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 8 B 256-bit

TLS 1.3 (RFC 8446)

Suite Tag Key
TLS_AES_128_CCM_SHA256 16 B 128-bit
TLS_AES_128_CCM_8_SHA256 8 B 128-bit

Usage

[dependencies]
rustls-ccm = "0.2"
rustls = "0.23"

Quick start — all CCM suites

let provider = rustls_ccm::crypto_provider();
let config = rustls::ClientConfig::builder_with_provider(provider.into())
    .with_safe_default_protocol_versions()
    .unwrap();

The CCM suites are appended after the provider defaults, so AES-GCM / ChaCha20-Poly1305 keep priority and CCM is negotiated only with peers that offer nothing stronger. To prefer CCM (e.g. for a profile that mandates it), put the suites you want in front, as below.

Pick specific suites

use rustls::crypto::CryptoProvider;

let mut provider = rustls::crypto::aws_lc_rs::default_provider();
provider.cipher_suites.insert(0, *rustls_ccm::TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8);

let config = rustls::ClientConfig::builder_with_provider(provider.into())
    .with_safe_default_protocol_versions()
    .unwrap();

Limitations

  • Raw traffic-secret extraction for kTLS/hardware offload (dangerous_extract_secrets()) is not supported — rustls's ConnectionTrafficSecrets has no CCM variant, so extract_keys returns UnsupportedOperationError for all CCM suites. SSLKEYLOGFILE-style key logging (rustls::KeyLog) is unaffected and works normally.

How it works

The crate borrows key exchange (ECDHE), signature (ECDSA), hash (SHA-256), PRF, and HKDF implementations from the aws-lc-rs provider. Only the AEAD algorithm is replaced with a CCM implementation built on RustCrypto's aes and ccm crates.

Testing

cargo test runs loopback handshake tests for every suite, plus interoperability tests against openssl s_server covering all six suites in both record directions. The interop tests need an OpenSSL 3.x binary (openssl on PATH, a Homebrew openssl@3 install, or the OPENSSL env var) and are skipped with a notice when none is found — macOS's bundled LibreSSL does not support the CCM suites.

License

MIT OR Apache-2.0