Repository navigation
DTLS 1.3 support #1468
Description
Activity
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?
Hello,
Do you have any update on supporting DTLS1.3?Thanks.
Hello,
is there any update or timeline to be shared regarding this topic?BR
I think until the value of
SERVER_LATEST_SUPPORTED_DTLSis changed, there is no progress: https://github.com/bcgit/bc-java/blob/main/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java#L25We (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.
Reacted by Volker BerlinIf you can please also test interop with OpenSSL 4.1 or master.
Reacted by Paul Gregoire@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?
Reacted by Paul GregoireFirst 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
TlsDTLS13Cipherinterface rather than onTlsCipher, so that third-partyTlsCryptoimplementations keep compiling. That leavesTlsCipherand the other cipher implementations untouched by this PR. Happy to move them ontoTlsCipherinstead 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.
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
DTLSv13completes 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
DTLSVerifiercannot 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 answersmissing_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.
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_requestedbefore 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.
Built and tested "working" on our WebRTC server for DTLS 1.3; please review and if there are concerns or questions, let me know.
42 remaining items
- added 15 commits that reference this issue
on Sep 20, 2026
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.