Pion DTLS

repository·main·Indexed 20 days ago

https://github.com/pion/dtls

A native Go implementation of the Datagram Transport Layer Security (DTLS) protocol, specifically targeting version 1.2. It provides secure datagram transport with support for ECDHE and PSK key exchange, session resumption, and various cipher suites including GCM, CCM, CBC, and ChaCha20Poly1305. Designed for high-performance real-time media applications such as WebRTC.

Tokens
11.4K
Snippets
37
Records
56
Agent score
67%

What's inside pion-dtls

  1. Overview of Pion DTLS

    main

    Pion DTLS is a native implementation of DTLS 1.2 in the Go programming language. It provides secure datagram transport with support for modern cipher suites, key exchange via ECDHE and PSK, and handles packet loss and re-ordering during the handshake process.

    Key Features:

    • DTLS 1.2 Client and Server support.
    • Key Exchange: ECDHE (curve25519, nistp256, nistp384) and PSK.
    • Session features: Serialization, Resumption, and Key Export ([RFC 5705]).
    • Extensions: Extended Master Secret ([RFC 7627]) and ALPN ([RFC 7301]).

    Note on Versions:

    • The v3 branch is currently focused on DTLS 1.2 improvements and bug fixes.
    • DTLS 1.3 work and breaking changes are targeted at the main branch.
  2. Run Specific Ciphersuite Benchmarks

    main

    You can target specific algorithms or operations (Encrypt/Decrypt) using the -bench flag. All commands require the -tags=bench build tag.

    GCM

    • All GCM: go test -tags=bench -bench=BenchmarkGCM -benchmem
    • GCM Encrypt: go test -tags=bench -bench=BenchmarkGCMEncrypt -benchmem
    • GCM Decrypt: go test -tags=bench -bench=BenchmarkGCMDecrypt -benchmem

    CCM

    • All CCM: go test -tags=bench -bench=BenchmarkCCM -benchmem
    • CCM Encrypt: go test -tags=bench -bench=BenchmarkCCMEncrypt -benchmem
    • CCM Decrypt: go test -tags=bench -bench=BenchmarkCCMDecrypt -benchmem

    CBC

    • All CBC: go test -tags=bench -bench=BenchmarkCBC -benchmem
    • CBC Encrypt: go test -tags=bench -bench=BenchmarkCBCEncrypt -benchmem
    • CBC Decrypt: go test -tags=bench -bench=BenchmarkCBCDecrypt -benchmem

    ChaCha20Poly1305

    • All ChaCha20Poly1305: go test -tags=bench -bench=BenchmarkChaCha20Poly1305 -benchmem
    • ChaCha20Poly1305 Encrypt: go test -tags=bench -bench=BenchmarkChaCha20Poly1305Encrypt -benchmem
    • ChaCha20Poly1305 Decrypt: go test -tags=bench -bench=BenchmarkChaCha20Poly1305Decrypt -benchmem

    Payload Size Filtering

    Use regex in the -bench flag to filter by payload size:

    • 1KB payloads: go test -tags=bench -bench=/1KB -benchmem
    • 16B payloads: go test -tags=bench -bench=/16B -benchmem
  3. Profile Ciphersuite Performance

    main

    To identify bottlenecks in cipher operations, you can generate CPU or memory profiles using the -cpuprofile or -memprofile flags during benchmarking.

    # Generate and inspect CPU profile
    go test -tags=bench -bench=BenchmarkGCMEncrypt -benchmem -cpuprofile=cpu.prof
    go tool pprof -top cpu.prof
    
    # Generate and inspect memory profile
    go test -tags=bench -bench=BenchmarkGCMEncrypt -benchmem -memprofile=mem.prof
    go tool pprof -top -alloc_objects mem.prof
  4. Run Ciphersuite Benchmarks

    main

    The package includes benchmarks for all cipher operations across various payload sizes.

    Important: Benchmarks are excluded from regular test runs via build tags. You must include -tags=bench in your command to execute them.

    # Run all ciphersuite benchmarks
    go test -tags=bench -bench=. -benchmem
  5. Configure Benchmark Execution Options

    main

    When running benchmarks, you can use standard Go testing flags to improve accuracy or collect more data:

    • Increase benchmark time: Use -benchtime to allow more iterations for more stable results.
    • Run multiple times: Use -count to execute the benchmark suite multiple times.
    # Increase benchmark time to 5s for accuracy
    go test -tags=bench -bench=BenchmarkGCM -benchmem -benchtime=5s
    
    # Run the benchmark 5 times
    go test -tags=bench -bench=BenchmarkGCM -benchmem -count=5
  6. Connect Pion DTLS to OpenSSL

    main

    Pion DTLS is compatible with OpenSSL. To test interoperability, you can generate certificates and use OpenSSL's s_server and s_client commands.

    1. Generate certificates:

    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

    2. Use OpenSSL as a Server (to connect with Pion Client):

    openssl s_server -dtls1_2 -cert cert.pem -key key.pem -accept 4444

    3. Use OpenSSL as a Client (to connect with Pion Server):

    openssl s_client -dtls1_2 -connect 127.0.0.1:4444 -debug -cert cert.pem -key key.pem
    # Generate certificates
    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 as Server
    openssl s_server -dtls1_2 -cert cert.pem -key key.pem -accept 4444
    
    # OpenSSL as Client
    openssl s_client -dtls1_2 -connect 127.0.0.1:4444 -debug -cert cert.pem -key key.pem
  7. Use Pre-Shared Key (PSK) with Pion DTLS

    main

    Pion DTLS supports key exchange via Pre-Shared Keys (PSK). You can run the provided examples or connect to OpenSSL using PSK.

    Pion DTLS Examples:

    • Server: go run examples/listen/psk/main.go
    • Client: go run examples/dial/psk/main.go

    OpenSSL Interoperability with PSK:

    To use OpenSSL as a server for a Pion client:

    openssl s_server -dtls1_2 -accept 4444 -nocert -psk abc123 -cipher PSK-AES128-CCM8

    To use OpenSSL as a client for a Pion server:

    openssl s_client -dtls1_2 -connect 127.0.0.1:4444 -psk abc123 -cipher PSK-AES128-CCM8
    # Pion PSK Server
    go run examples/listen/psk/main.go
    
    # Pion PSK Client
    go run examples/dial/psk/main.go
    
    # OpenSSL PSK Server
    openssl s_server -dtls1_2 -accept 4444 -nocert -psk abc123 -cipher PSK-AES128-CCM8
    
    # OpenSSL PSK Client
    openssl s_client -dtls1_2 -connect 127.0.0.1:4444 -psk abc123 -cipher PSK-AES128-CCM8
  8. Generate certificates for DTLS examples

    main

    To run the DTLS examples provided in this repository, you need to generate specific certificates using OpenSSL. These commands create a self-signed server certificate and a client certificate signed by that server.

    Note: These commands were tested with OpenSSL 1.1.1d. Arguments may vary depending on your OpenSSL version.

    # 1. Create extensions required for certificate validation
    $ EXTFILE='extfile.conf'
    $ echo 'subjectAltName = IP:127.0.0.1\nbasicConstraints = critical,CA:true' > "${EXTFILE}"
    
    # 2. Generate Server Certificate
    $ SERVER_NAME='server'
    $ openssl ecparam -name prime256v1 -genkey -noout -out "${SERVER_NAME}.pem"
    $ openssl req -key "${SERVER_NAME}.pem" -new -sha256 -subj '/C=NL' -out "${SERVER_NAME}.csr"
    $ openssl x509 -req -in "${SERVER_NAME}.csr" -extfile "${EXTFILE}" -days 365 -signkey "${SERVER_NAME}.pem" -sha256 -out "${SERVER_NAME}.pub.pem"
    
    # 3. Generate Client Certificate (signed by the server)
    $ CLIENT_NAME='client'
    $ openssl ecparam -name prime256v1 -genkey -noout -out "${CLIENT_NAME}.pem"
    $ openssl req -key "${CLIENT_NAME}.pem" -new -sha256 -subj '/C=NL' -out "${CLIENT_NAME}.csr"
    $ openssl x509 -req -in "${CLIENT_NAME}.csr" -extfile "${EXTFILE}" -days 365 -CA "${SERVER_NAME}.pub.pem" -CAkey "${SERVER_NAME}.pem" -set_serial '0xabcd' -sha256 -out "${CLIENT_NAME}.pub.pem"
    
    # 4. Cleanup temporary files
    $ rm "${EXTFILE}" "${SERVER_NAME}.csr" "${CLIENT_NAME}.csr"
  9. Run Pion DTLS Self-Signed Examples

    main

    You can run built-in examples to test a DTLS 1.2 server and client using self-signed certificates. This requires Go 1.21 or later with Go modules enabled.

    To run a server listening on 127.0.0.1:4444:

    go run examples/listen/selfsign/main.go

    To run a client connecting to 127.0.0.1:4444:

    go run examples/dial/selfsign/main.go
    go run examples/listen/selfsign/main.go
    go run examples/dial/selfsign/main.go
  10. How DTLS packet processing works

    main

    The Conn type handles incoming datagrams through a multi-stage pipeline designed to handle both DTLS 1.2 (legacy) and DTLS 1.3 (ciphertext) packets:

    1. Classification: prepareIncomingPacket determines if the packet is DTLS 1.3 ciphertext or a legacy DTLS 1.2 packet.
    2. Decryption/Unmarshalling:
      • DTLS 1.3: Uses prepareCiphertextPacket to unmarshal and decrypt the record.
      • DTLS 1.2: Uses prepareLegacyPacket to unmarshal the header and decrypt the payload if an epoch is present.
    3. Replay Protection: The connection uses a ReplayDetector to check the sequenceNumber against a sliding window to prevent replay attacks.
    4. Handshake Buffering: If the packet is a handshake record, it is passed to bufferHandshakeRecord to handle fragmentation and reassembly.
    5. Content Handling: Once decrypted, the record content (Handshake, Alert, or Application Data) is dispatched via handleRecordContent.
  11. Handle DTLS 1.3 and DTLS 1.2 version negotiation

    main

    The connection supports a dual-stack version negotiation phase. During this phase, the connection can receive and buffer packets for both DTLS 1.2 and DTLS 1.3 before the final protocol version is pinned.

    • Server side: negotiateVersionServer reads and buffers messages until a ClientHello is fully received, then selects the version.
    • Client side: negotiateVersionClient generates the initial flight and waits for the server's response to decide the version.

    Once a version is selected via setNegotiatedVersion, the internal state is activated for either DTLS 1.2 or DTLS 1.3.