Three v4 release candidates against a tag freeze notice in pion/dtls
DTLS 1.2 implementation for Go (DTLS 1.3 in progress). Pion DTLS A Go implementation of DTLS Native [DTLS 1.2][rfc6347] implementation in the Go programming language.
At a glance
- What is it?
- pion/dtls is a Go datagram TLS library: seventeen DTLS 1.2 cipher suites and three DTLS 1.3 ones, with DTLS 1.3 sitting in release candidates on a branch its own README calls frozen from tagging, and no professional security review on record.
- Who is it for?
- Adopt pion/dtls if you are already inside the Pion ecosystem and need DTLS 1.2 with working OpenSSL interop, and pin the 1.3 path to a named v4.0.0-rc tag rather than to main. Pass on it if you need an externally reviewed suite list, renegotiation, compression or a DTLS 1.0 fallback, because none of those are in the tree.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- pion/dtls714 ★ · +24
| Repository | 2026-08-04 | 2026-11-14 |
|---|---|---|
| pion/dtls | 690 | 714 |
24 Stars in the last 102 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The tag freeze notice sits next to three release candidates in four days
A warning box near the top of the README says the branch is frozen from tagging while DTLS 1.3 work is underway, and it routes bug fixes and DTLS 1.2 improvements to the `v3` branch, which is the one that can be used for tags until 1.3 is ready. The release history does not match that arrangement. Three v4.0.0 release candidates were tagged inside four days: rc.1 on 2026-09-28, rc.2 on 2026-09-29 and rc.3 on 2026-10-01, the last landing on the same date as the most recent push. Meanwhile go.mod already declares the module as `github.com/pion/dtls/v4`, so anyone importing this branch resolves a v4 path while the page sends them to a v3 branch for anything they want to tag. A consumer pinning this code ends up with a release candidate under a v4 import path, and a page that says the branch takes no tags.
DTLS 1.3 is listed as implemented and described as in progress
The project's summary line calls it a DTLS 1.2 implementation for Go and puts DTLS 1.3 in progress in parentheses. Further down, RFC 9147 sits in the same Implemented list as RFC 6347, and the current features claim DTLS 1.3 client and server, external PSK under `psk_ke` and `psk_dhe_ke` with SHA-256 or SHA-384, several PSK identities offered per handshake for server selection, connection IDs in both versions, the RFC 9853 return routability check, local path probing and migration through `Conn.AddPath`, `Path.Probe` and `Path.Switch`, and traffic key updates through `Conn.UpdateKeys`. Nothing marks which of those are finished. One line above the feature list sits the fact that matters most in a crypto library: a long term goal is a professional security review, and maybe an inclusion in stdlib. The review is a goal, not a done thing, and the version carrying the newest features is the one without one.
Seven RFCs cited by the cipher tables never reach the implemented list
The RFC section has one list, headed Implemented, holding seven entries: 6347 for DTLS 1.2, 9146 for the DTLS 1.2 connection identifier, 9147 for DTLS 1.3, 9853 for the return routability check, 5705 for key export, 7627 for extended master secret, and 7301 for ALPN. The reference links at the foot of the page also define 5289, 5487, 5489, 6655, 7905, 8422 and 8446, and every one of those turns up only in the cipher tables. TLS_AES_128_GCM_SHA256 for DTLS 1.3 is attributed to RFC 8446, which the Implemented list never names. So that list is not a map of what the library negotiates, and reading it as one understates the surface. The three DTLS 1.3 suites rest on 8446. The DTLS 1.2 tables rest on 6655, 5289, 8422 and 7905. Coverage has to be checked against the suite tables.
CCM stops at 256 bits for the short tag, and RSA never gets CCM at all
The suite tables are uneven in ways that decide interoperability. Under DTLS 1.2 ECDHE there are ten suites. The CCM pair, TLS_ECDHE_ECDSA_WITH_AES_128_CCM and its tagged _8 variant, exists only for ECDSA keys, while RSA clients get GCM, CBC with SHA and ChaCha20 but never CCM. The PSK table holds six suites, and the size naming falls apart there: AES_128_CCM and AES_128_CCM_8 both appear, but the 256-bit entry exists only as AES_256_CCM_8, so a 256-bit CCM key with the longer tag has no suite to match. No PSK suite above 128 bits exists in GCM or CBC either, while the ECDHE table does offer 256-bit GCM. The combined ECDHE and PSK group, the one that binds a channel to a shared secret, holds a single entry, TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, with no 256-bit or AEAD option. The interop example for that mode hardcodes the PSK in plaintext:
openssl s_server -dtls1_2 -accept 4444 -nocert -psk abc123 -cipher PSK-AES128-CCM8
openssl s_client -dtls1_2 -connect 127.0.0.1:4444 -psk abc123 -cipher PSK-AES128-CCM8Note that this pins the weak tag length variant, and that both commands request DTLS 1.2 even though the library also speaks 1.3.
DTLS 1.0, renegotiation and compression are refused on purpose
An Excluded Features block names three things: DTLS 1.0, renegotiation and compression. Each one closes a path. With no 1.0 there is no fallback for a peer that predates 1.2, so the handshake fails outright instead of downgrading. With no renegotiation, a long-lived association cannot derive fresh key material the old way, which is why the 1.3 side offers traffic key updates through `Conn.UpdateKeys` alongside post-handshake connection ID updates, and why the 1.2 side leans on session serialization and resumption, with `session.go` and `resume.go` at the repository root. With no compression there is no CRIME-style surface to worry about, a small piece of good news for a library whose datagrams can carry attacker chosen bytes. Packet loss and re-ordering during the handshake are claimed as handled, and `flight_test.go` and `handshaker_test.go` at the root are where that would be exercised.
The self signed recipe prompts for a subject and reuses one key on both ends
Certificate interop with OpenSSL is the one worked example the page gives, and two details in it are worth naming. The certificate signing request line carries no subject argument, so `openssl req` stops and asks for subject fields at the terminal instead of running unattended, which turns a three line recipe into an interactive one. Then the client is handed the same `cert.pem` and `key.pem` the server just used, with no certificate authority anywhere in the pair, so both ends present one self signed identity and neither side verifies a chain. Both commands request DTLS 1.2 only. The whole thing is four lines:
openssl ecparam -out key.pem -name prime256v1 -genkey
openssl req -new -sha256 -key key.pem -out server.csr
openssl x509 -req -sha256 -days 365 -in server.csr -signkey key.pem -out cert.pem
openssl s_server -dtls1_2 -cert cert.pem -key key.pem -accept 4444
openssl s_client -dtls1_2 -connect 127.0.0.1:4444 -debug -cert cert.pem -key key.pemThe key is prime256v1, so the ECDHE curves offered are wider than the certificate key ever is. A 365 day leaf generated on the spot makes this a loopback smoke test, not a template for anything leaving the machine.
An mDNS example directory with no section to explain it
The `examples/` tree holds five directories: `certificates/`, `dial/`, `listen/`, `mdns/` and `util/`. The page walks two of them, pairing a listener with a dialer on 127.0.0.1:4444 for the self signed case and doing the same again for PSK key exchange. Nothing explains `mdns/`, `certificates/` or `util/`. The library root is split the same way, with `internal/` and `pkg/` holding the bulk of the implementation next to flat files for the connection itself, `conn.go`, `options.go`, `listener.go`, `state.go`, `connection_id.go`, `detached_conn.go` and `srtp_protection_profile.go`. That last file is worth a look, because SRTP keying material has to come out of the same handshake, which makes the negotiated protection profile a DTLS concern and not only an SRTP one. Peer discovery is where the undocumented directory would live, and the page gives no starting point for it. The four runnable examples it does document are:
go run examples/listen/selfsign/main.go
go run examples/dial/selfsign/main.go
go run examples/listen/psk/main.go
go run examples/dial/psk/main.goThere is no `go get` line anywhere on the page, so the module path in go.mod is the only installation instruction a reader gets.
Two errno build variants and a YAML library in a handshake package
Two root files, `errors_errno.go` and `errors_noerrno.go`, carry parallel implementations of the error surface, and `errors_errno_test.go` sits alongside them. The shape is a build tag switch between targets that expose numeric error codes and targets that do not, which is a real concern for a library whose transport is datagrams and whose errors often surface as socket failures. `golang.org/x/sys v0.41.0` is in the requirement list, the module that carries platform syscall definitions. The rest of go.mod is short: `pion/logging v0.2.4`, `pion/transport/v5 v5.1.1`, `testify v1.12.1` and `golang.org/x/crypto v0.48.0`, with a single indirect entry, `go.yaml.in/yaml/v3 v3.0.5`. A package that ships no configuration file still drags a YAML parser into the build graph. The language floor is Go 1.24.0 and the module declares the v4 path. The licence is MIT, with a `LICENSE` file at the root next to a `LICENSES/` directory and a `.reuse/` folder, the layout the REUSE specification expects.
Editorial conclusion
Adopt pion/dtls if you are already inside the Pion ecosystem and need DTLS 1.2 with working OpenSSL interop, and pin the 1.3 path to a named v4.0.0-rc tag rather than to main. Pass on it if you need an externally reviewed suite list, renegotiation, compression or a DTLS 1.0 fallback, because none of those are in the tree. Before committing, read go.mod for the module path and the Go 1.24.0 floor, count your required cipher against the suite tables rather than the RFC list, and decide whether the v3 branch or the frozen main branch is where your fix belongs.
Frequently asked questions
What does DTLS stand for, and which version does pion/dtls implement?
DTLS is the Datagram Transport Layer Security protocol. pion/dtls implements version 1.2 under RFC 6347 and version 1.3 under RFC 9147 in Go, and RFC 9146 adds the connection identifier for DTLS 1.2.
Is DTLS better than TLS for a Go service?
The project draws no comparison between the two protocols, so this page argues nothing here. What it states is scope: seventeen DTLS 1.2 suites and three DTLS 1.3 suites, with DTLS 1.0, renegotiation and compression excluded outright.
How does pion/dtls run key exchange during a handshake?
Over ECDHE with curve25519, nistp256 or nistp384, or over PSK. On DTLS 1.3 it also takes external PSKs under `psk_ke` and `psk_dhe_ke` with SHA-256 or SHA-384, and a client can offer several PSK identities per handshake for the server to select from. Packet loss and re-ordering during handshaking are handled.
Does pion/dtls interoperate with OpenSSL?
Yes. The page gives an `openssl s_server` and `openssl s_client` pair for the self signed examples on 127.0.0.1:4444, and a second pair for the PSK examples using `-nocert`, `-psk abc123` and `-cipher PSK-AES128-CCM8`.
Which Go version and module path does pion/dtls need?
go.mod declares `module github.com/pion/dtls/v4` and a `go 1.24.0` floor. Requirements are `pion/logging v0.2.4`, `pion/transport/v5 v5.1.1`, `testify v1.12.1`, `golang.org/x/crypto v0.48.0` and `golang.org/x/sys v0.41.0`, with `go.yaml.in/yaml/v3 v3.0.5` as the one indirect entry.
How do I install pion/dtls?
No `go get` line appears on the page. It gives the module path `github.com/pion/dtls/v4` and four runnable examples instead: `go run examples/listen/selfsign/main.go` with the matching dial example for certificates, and the `psk` pair for PSK. The licence is MIT.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pion-dtls)Star history chart for your README
[](https://hysenlabs.com/projects/pion-dtls)Was this useful?