# `XGW.DTLS`
[🔗](https://github.com/Lazarus404/xgw/blob/main/lib/xgw/dtls.ex#L1)

Starts and completes the DTLS handshake that unlocks encrypted media keys.

## Why DTLS comes after ICE

**ICE** only finds a working IP/port path. That path is still unauthenticated
for media encryption. **DTLS** (Datagram TLS) is TLS over UDP: the two peers
exchange certificates, prove possession of private keys, and agree on
cryptographic material. WebRTC then derives **SRTP** keys from that material
so RTP/RTCP packets can be encrypted efficiently.

This module is the server-side accept path used by `XGW.Peer`:

- listen/accept on the shared Listener UDP socket via `XGW.DTLS.Transport`
- finish the handshake and verify the remote fingerprint
- export SRTP keys through `XGW.DTLS.SrtpKeys`

Start the accept loop only after ICE has selected a remote pair; otherwise
DTLS packets have nowhere trustworthy to go.

## RFCs

* RFC 9147 / RFC 6347 -- DTLS 1.3 / 1.2
* RFC 5764 -- DTLS extension for SRTP key export
* RFC 8122 -- certificate fingerprint verification against SDP

# `keys`

```elixir
@type keys() :: XGW.DTLS.SrtpKeys.keys()
```

DTLS-exported SRTP key tuple (client and server write pairs).

# `close`

```elixir
@spec close(:ssl.sslsocket() | nil, :ssl.sslsocket() | nil) :: :ok
```

Closes DTLS listen and connection sockets.

# `export_srtp_keys`

```elixir
@spec export_srtp_keys(:ssl.sslsocket()) :: {:ok, keys()} | {:error, term()}
```

Exports DTLS-SRTP keying material from a connected DTLS socket.

# `handshake`

```elixir
@spec handshake(:ssl.sslsocket()) :: {:ok, :ssl.sslsocket()} | {:error, term()}
```

Completes transport accept and DTLS handshake on `listen_sock`.

# `inject`

```elixir
@spec inject(pid(), :inet.ip_address(), :inet.port_number(), binary()) :: :ok
```

Injects a DTLS datagram into the OTP ssl transport on the listener UDP socket.

# `listen_opts`

```elixir
@spec listen_opts(keyword()) :: keyword()
```

SSL listen options for WebRTC DTLS-SRTP on a shared UDP port.

# `start_accept`

```elixir
@spec start_accept(:ssl.sslsocket(), pid(), keyword()) :: {:ok, pid()}
```

Starts a linked accept loop on `listen_sock`. Completion is reported to
`peer` as `{:xgw_internal, :dtls_ready, ssl_sock, export_result}`.

Options:

  * `:expected_fingerprint` - remote `%Fingerprint{}` from SDP offer

# `verify_fingerprint`

```elixir
@spec verify_fingerprint(:ssl.sslsocket(), XMediaLib.SDP.Fingerprint.t()) :: boolean()
```

Verifies the peer certificate fingerprint against SDP.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
