Skip to content

DTLS 1.3 support #1468

Description

@JonathanLennox

BouncyCastle should support DTLS 1.3.

It's not imminently needed, but since (D)TLS 1.2 doesn't seem likely to get any post-quantum KEMs, DTLS 1.3 will be needed to protect DTLS traffic (and things derived from it, like WebRTC traffic) from harvest-now-decrypt-later attacks.

Activity

  1. Horcrux7 commented on Dec 7, 2023

    @Horcrux7

    If I try to use DTLS 1.3 I get the follow exception:

    org.bouncycastle.tls.TlsFatalAlert: internal_error(80)
    	at org.bouncycastle.tls.DTLSClientProtocol.generateClientHello(DTLSClientProtocol.java:406)
    	at org.bouncycastle.tls.DTLSClientProtocol.clientHandshake(DTLSClientProtocol.java:91)
    	at org.bouncycastle.tls.DTLSClientProtocol.connect(DTLSClientProtocol.java:52)
    

    Any progress on it?

  2. Frosne commented on Jan 25, 2024

    @Frosne

    Hello,
    Do you have any update on supporting DTLS1.3?

    Thanks.

  3. pretti-vusion commented on Sep 17, 2024

    @pretti-vusion

    Hello,
    is there any update or timeline to be shared regarding this topic?

    BR

  4. Horcrux7 commented on Sep 18, 2024

    @Horcrux7

    I think until the value of SERVER_LATEST_SUPPORTED_DTLS is changed, there is no progress: https://github.com/bcgit/bc-java/blob/main/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java#L25

  5. mondain commented on Sep 11, 2026

    @mondain

    We (Red5 Pro) plan to implement DTLS 1.3 (RFC 9147) in bctls, targeting the certificate-based 1-RTT handshake, unified record header with record number encryption, ACK-based retransmission, HelloRetryRequest cookies, KeyUpdate, and the RFC 5705 exporter for DTLS-SRTP. PSK resumption, early data, and connection IDs would follow separately. We intend to submit it as a series of five smaller PRs (record layer, reliable handshake, client, server, post-handshake), keeping the existing DTLS 1.2 tests green at each step, with interop tested against BoringSSL and wolfSSL.

    Before we start: is there in-progress work on this we should build on, or a preferred structure for the changes? Happy to adjust the plan.

  6. xnox commented on Sep 11, 2026

    @xnox

    If you can please also test interop with OpenSSL 4.1 or master.

  7. JonathanLennox commented on Sep 11, 2026

    @JonathanLennox
    Author

    @mondain That's great to hear!

    Especially if you're looking at DTLS-SRTP I'd also suggest testing against NSS (Firefox).

    You're likely aware of this but there's a thread on the IETF TLS mailing list about the state of DTLS interop at https://mailarchive.ietf.org/arch/msg/tls/6ca1XMbTsd1m1qJPPRhD0bhQujs/ that would likely be useful to follow.

    Is there any chance that while you're working in DTLS you could also take a look at #1487?

  8. mondain commented on Sep 11, 2026

    @mondain

    First PR of the series is up: #2439 — the DTLS 1.3 record layer (RFC 9147 section 4). Unified header, record number encryption, the epoch model, and the DTLS 1.3 paths in DTLSRecordLayer. DTLS 1.3 is not negotiable yet, so nothing reaches the new code until the handshake PRs land.

    One thing worth a maintainer's opinion early, since later PRs build on it: the three DTLS 1.3 record operations are on a new optional TlsDTLS13Cipher interface rather than on TlsCipher, so that third-party TlsCrypto implementations keep compiling. That leaves TlsCipher and the other cipher implementations untouched by this PR. Happy to move them onto TlsCipher instead if you would rather take the API break in a suitable release.

    @xnox noted the OpenSSL request — agreed, the interop harness will cover OpenSSL alongside BoringSSL and wolfSSL. It gates the client and server PRs rather than this one, since there is no handshake to interop with yet.

  9. mondain commented on Sep 12, 2026

    @mondain

    Part 3 of the DTLS 1.3 series is up: #2441, the client and server handshakes. It stacks on #2440 (reliable handshake) which stacks on #2439 (record layer).

    The series was planned as five parts and is now four. The client and the server went in together because they are mirror images of each other, and splitting them would have left a part that could not be tested against anything. Part 4 is the post-handshake work: KeyUpdate, NewSessionTicket, and post-handshake ACKs.

    With #2441 a pair of peers that list DTLSv13 completes a certificate-authenticated 1-RTT handshake, including HelloRetryRequest, optional client authentication, and recovery from packet loss. DTLS-SRTP (RFC 5764) works over it, which was the motivation: both peers derive identical exporter material and the profile is negotiated through the encrypted EncryptedExtensions.

    Two things worth flagging for anyone reading the diff.

    The DTLS 1.3 transcript hashes a 4-byte TLS-style handshake header, not DTLS's 12-byte one (RFC 9147 5.2). An earlier draft of this work had it wrong, and no amount of BC-to-BC testing could have caught it, because both peers would have agreed on the same wrong transcript. It is now asserted against an independently computed digest rather than against another BC peer.

    DTLS 1.3 forbids HelloVerifyRequest, so DTLSVerifier cannot front a 1.3 handshake. A 1.3-capable server reached through it now refuses with a diagnostic naming the cause, rather than failing obscurely later. That means DTLS 1.3 currently has no address-validation countermeasure at all. A stateless HelloRetryRequest front end is real work with new public API and belongs in its own PR; a half-measure was written and then removed rather than shipped, because a cookie demand that can be bypassed is worse than none.

    @xnox, @JonathanLennox — on interop: none has run yet, and that is the honest headline risk on #2441. I have not tested against OpenSSL, NSS, BoringSSL or wolfSSL. The most likely failure I know of is a cookie-only HelloRetryRequest: a stateless third-party server's retry carries a cookie and no key_share, and this client currently answers missing_extension. OpenSSL master and NSS are both on the harness list. If anyone has a DTLS 1.3 endpoint they can point this at, that would be more useful right now than another review pass.

    This work was produced with generative-AI assistance, per the contributing guidelines.

  10. mondain commented on Sep 12, 2026

    @mondain

    The last part of the DTLS 1.3 series is up: #2442, post-handshake. It stacks on #2441, #2440 and #2439.

    That completes the four parts. Together they give bctls a DTLS 1.3 implementation sufficient for WebRTC: the record layer with the unified header and record number encryption, the reliable handshake with ACKs, the client and server handshakes, and now KeyUpdate, NewSessionTicket and acknowledgements at the application epochs. DTLS-SRTP works over it, which was the motivation.

    Three things from this part are worth stating here rather than leaving in the diff.

    The two rules of RFC 9147 section 8 have different triggers, and conflating them is the natural mistake. The sender may not transmit at the new epoch until its KeyUpdate is acknowledged; the receiver may not release the pre-update keys until something actually decrypts under the new ones. An acknowledgement is not a decryption. They are implemented in separate commits and the separation is structural rather than a matter of comments.

    There is one deliberate deviation from a MUST. RFC 8446 4.6.3 requires answering update_requested before the next application data record; RFC 9147 5.8.4 forbids sending a KeyUpdate while one is unacknowledged. When our own is outstanding, both cannot hold. This follows 9147, because it is the DTLS specification constraining a rule it inherits, because its rule is load-bearing for epoch reconstruction with only two epoch bits on the wire, and because the alternative is stalling the data path in response to a peer-controlled message. The obligation is deferred rather than dropped. I have flagged it in the PR body because a reader who finds only the 8446 quotation would reasonably take it for an oversight.

    Four files shared with TLS over TCP are touched, and the PR explains why the existing in-place rekey path cannot be reused: DTLS needs the pre-update cipher to stay usable in both directions, and rekeying in place destroys exactly that.

    @xnox, @JonathanLennox — the interop position is unchanged and it remains the honest headline risk on the whole series: nothing has been tested against OpenSSL, NSS, BoringSSL or wolfSSL. Two facts are pinned by byte-level tests against independently computed values, the DTLS 1.3 transcript header form and the HelloRetryRequest synthetic transcript. Everything else is currently proven BC-to-BC, which by construction cannot catch an error both peers make identically. The most likely concrete failure I know of is still a cookie-only HelloRetryRequest, which this client answers with missing_extension. If either of you can point a DTLS 1.3 endpoint at this, that would be worth more right now than another review pass.

    Marked as closing this issue, though that is for the maintainers to judge once the stack is reviewed.

    This work was produced with generative-AI assistance, per the contributing guidelines.

  11. mondain commented on Sep 13, 2026

    @mondain

    Built and tested "working" on our WebRTC server for DTLS 1.3; please review and if there are concerns or questions, let me know.

  12. 42 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions