Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,25 @@ Four constructors control which DTLS version is used:
- **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).
- **Connection ID** ([RFC 9146]) is supported for DTLS 1.2 (extension codepoint
54 / 0x0036). Configure with [`Config::with_connection_id`][with_cid];
`Output::ConnectionId` is emitted when negotiation completes. The CID is a
**routing hint, not authorization to change the send address**: per RFC
9146 §6 the caller must (a) wait for an authentication-positive signal
(e.g. `ApplicationData` from `poll_output`) before updating peer address
— `handle_packet` returning `Ok(())` is **not** proof of authentication,
since invalid records are silently discarded per RFC 6347 §4.1.2.7; (b)
require strict-monotonic (epoch, sequence_number) on the authenticated
record; (c) apply an address-reachability policy. See
[`Config::with_connection_id`][with_cid] rustdoc for the full pattern.

### Known non-interop: pre-RFC Connection ID codepoint 53 (0x35)
Older implementations that predate RFC 9146 — notably OpenSSL before 3.2 and
some embedded stacks — use extension type `53` from
`draft-ietf-tls-dtls-connection-id-07`. dimpl implements the final RFC 9146
codepoint (54) only, so peers stuck on the draft codepoint will fall back to
legacy framing instead of successfully negotiating CID. This is expected for
roaming PSK/IoT deployments that still ship the draft codepoint.

### Certificate model
During the handshake the engine emits
Expand Down Expand Up @@ -188,6 +207,8 @@ Rust 1.85.0
[RFC 5764]: https://www.rfc-editor.org/rfc/rfc5764
[RFC 7714]: https://www.rfc-editor.org/rfc/rfc7714
[RFC 7627]: https://www.rfc-editor.org/rfc/rfc7627
[RFC 9146]: https://www.rfc-editor.org/rfc/rfc9146
[with_cid]: https://docs.rs/dimpl/latest/dimpl/struct.ConfigBuilder.html#method.with_connection_id


License: MIT OR Apache-2.0
16 changes: 15 additions & 1 deletion src/auto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const EXT_PADDING: u16 = 0x0015;
const EXT_EXTENDED_MASTER_SECRET: u16 = 0x0017;
const EXT_SUPPORTED_VERSIONS: u16 = 0x002B;
const EXT_KEY_SHARE: u16 = 0x0033;
const EXT_CONNECTION_ID: u16 = 0x0036;
const EXT_RENEGOTIATION_INFO: u16 = 0xFF01;

/// A self-contained hybrid ClientHello compatible with both DTLS 1.2 and 1.3.
Expand Down Expand Up @@ -189,7 +190,20 @@ impl HybridClientHello {
ext_buf.push(0); // renegotiated_connection length = 0
ext_entries.push((EXT_RENEGOTIATION_INFO, start, ext_buf.len()));

// 9. padding: fill to MTU
// 9. connection_id (RFC 9146, DTLS 1.2 compat): emit when the caller
// configured a CID. Without this, auto-mode hybrid CH1 would omit
// the extension, causing CH1 (no CID) / CH2 (with CID) to disagree
// across HVR; `Config::build` already rejects a CID-without-DTLS-1.2
// combination, so reaching here guarantees at least one DTLS 1.2
// suite is offered.
if let Some(cid) = config.connection_id() {
let start = ext_buf.len();
ext_buf.push(cid.len() as u8);
ext_buf.extend_from_slice(cid);
ext_entries.push((EXT_CONNECTION_ID, start, ext_buf.len()));
}

// 10. padding: fill to MTU
let record_header = 13usize;
let handshake_header = 12usize;
let body_so_far = ch_body.len()
Expand Down
5 changes: 5 additions & 0 deletions src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ impl Buf {
self.0.resize(len, value);
}

/// Shorten the buffer to the specified length, dropping trailing bytes.
pub fn truncate(&mut self, len: usize) {
self.0.truncate(len);
}

/// Convert the buffer into the underlying `Vec<u8>`.
pub fn into_vec(mut self) -> Vec<u8> {
std::mem::take(&mut self.0)
Expand Down
Loading
Loading