pion / dtls

DTLS 1.2 Server/Client implementation for Go
https://pion.ly/
MIT License
602 stars 160 forks source link

Implement DTLS 1.2 Connection IDs #558

Closed hasheddan closed 1 year ago

hasheddan commented 1 year ago

Description

Implements DTLS 1.2 Connection ID support as defined in https://datatracker.ietf.org/doc/html/rfc9146.

Remaining work:

Notes for early reviewers:

Currently, if you want an endpoint to be able to update its remote address, you need to implement a custom Listener that uses connection ID's rather than remote address to determine what PacketServer to route packets to. This functionality is dependent on pion/transport/udp, and I demonstrated what an example could look like in https://github.com/pion/transport/pull/252. However, as mentioned on that PR, the intention is to move the functionality to live here in pion/dtls, and I am in progress of doing so. We could feasibly make that a separate PR given that this one is "feature complete" in that it can successfully negotiate and use connection IDs as both a client and server (as demonstrated by the new e2e tests). Either way, the UDP connection package needs to be added in this PR or a subsequent one.

Another area of interest is automated testing against other libraries. The current OpenSSL tests cannot be expanded for this use-case as it does not support connection IDs. I have performed manual validation by expanding the DTLS client example in mbedTLS as demonstrated here: https://github.com/Mbed-TLS/mbedtls/compare/development...hasheddan:mbedtls:feat/cid-example. I would like to expand the e2e testing suite in this repository to include mbedTLS with connection IDs enabled, though we will need to build our own client, which could also be deferred to a subsequent PR.

An area that I do not anticipate expanding scope of this PR to cover quite yet is saving connection state. For my particular use-case is is vital that we able to persist connection state across server restarts. Note that this is different from saving sessions as connection IDs must actually be renegotiated upon session resumption, whereas ideally with connection IDs enabled a server could continue receiving from an endpoint after restart by recovering all state. I would like to ensure this functionality is enabled prior to cutting a v3 release as I believe it could result in breaking changes.

Lastly, I am in progress of increasing unit test coverage across the board, though it is not anticipated that this will result in any functional changes to what is currently implemented as it is already being validated through existing unit tests (testing with connection IDs not enabled), as well as e2e test.

Testing Locally

If reviewers would like to experiment with enabling connection IDs locally, you can use the following commands to only run the CID e2e tests.

docker build -t pion-dtls-e2e -f e2e/Dockerfile .
docker run -i --rm --net=host pion-dtls-e2e go test -run=.*CID.* -v

Using the host's network namespace allows you to capture on the loopback interface in wireshark. Using the dtls filter will help eliminate other noise. Your output should look something like the following:

image

Reference issue

Fixes #256 Fixes #367

codecov[bot] commented 1 year ago

Codecov Report

Patch coverage: 83.48% and project coverage change: +0.21% :tada:

Comparison is base (a1d270f) 76.75% compared to head (ed08ac1) 76.97%.

Additional details and impacted files ```diff @@ Coverage Diff @@ ## master #558 +/- ## ========================================== + Coverage 76.75% 76.97% +0.21% ========================================== Files 95 99 +4 Lines 5675 6011 +336 ========================================== + Hits 4356 4627 +271 - Misses 972 1016 +44 - Partials 347 368 +21 ``` | Flag | Coverage Δ | | |---|---|---| | go | `77.00% <83.48%> (+0.21%)` | :arrow_up: | | wasm | `61.74% <44.14%> (-5.24%)` | :arrow_down: | Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#carryforward-flags-in-the-pull-request-comment) to find out more. | [Files Changed](https://app.codecov.io/gh/pion/dtls/pull/558?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion) | Coverage Δ | | |---|---|---| | [cipher\_suite.go](https://app.codecov.io/gh/pion/dtls/pull/558?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-Y2lwaGVyX3N1aXRlLmdv) | `98.51% <ø> (ø)` | | | [config.go](https://app.codecov.io/gh/pion/dtls/pull/558?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-Y29uZmlnLmdv) | `100.00% <ø> (ø)` | | | [handshaker.go](https://app.codecov.io/gh/pion/dtls/pull/558?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-aGFuZHNoYWtlci5nbw==) | `76.79% <ø> (ø)` | | | [state.go](https://app.codecov.io/gh/pion/dtls/pull/558?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-c3RhdGUuZ28=) | `90.90% <ø> (ø)` | | | [pkg/protocol/extension/connection\_id.go](https://app.codecov.io/gh/pion/dtls/pull/558?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-cGtnL3Byb3RvY29sL2V4dGVuc2lvbi9jb25uZWN0aW9uX2lkLmdv) | `68.96% <68.96%> (ø)` | | | [pkg/crypto/ciphersuite/cbc.go](https://app.codecov.io/gh/pion/dtls/pull/558?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-cGtnL2NyeXB0by9jaXBoZXJzdWl0ZS9jYmMuZ28=) | `69.51% <77.96%> (+1.47%)` | :arrow_up: | | [conn.go](https://app.codecov.io/gh/pion/dtls/pull/558?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-Y29ubi5nbw==) | `80.56% <78.10%> (-0.96%)` | :arrow_down: | | [pkg/protocol/recordlayer/header.go](https://app.codecov.io/gh/pion/dtls/pull/558?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-cGtnL3Byb3RvY29sL3JlY29yZGxheWVyL2hlYWRlci5nbw==) | `85.36% <78.57%> (+5.36%)` | :arrow_up: | | [connection\_id.go](https://app.codecov.io/gh/pion/dtls/pull/558?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-Y29ubmVjdGlvbl9pZC5nbw==) | `80.00% <80.00%> (ø)` | | | [pkg/protocol/recordlayer/inner\_plaintext.go](https://app.codecov.io/gh/pion/dtls/pull/558?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-cGtnL3Byb3RvY29sL3JlY29yZGxheWVyL2lubmVyX3BsYWludGV4dC5nbw==) | `80.95% <80.95%> (ø)` | | | ... and [21 more](https://app.codecov.io/gh/pion/dtls/pull/558?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion) | |

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

boaks commented 1 year ago

Pretty cool! I like the docker stuff! Is it possible to start a server only with the docker image? And to try some handshakes with clients using other implementations?

daenney commented 1 year ago

Pretty cool! I like the docker stuff! Is it possible to start a server only with the docker image? And to try some handshakes with clients using other implementations?

Right now we only use Docker for the E2E CI tests, and they start a specific subset of tests using a build tag. However, you can look at examples/listen for how to start a server using this library to handle DTLS. Since it's Go the resulting binary can be copied into a tiny base image.

So, very crudely, it could be along the lines of:

# Start by building the application.
FROM golang:1.20 as build

WORKDIR /go/src/app
COPY . .

RUN go mod download
RUN CGO_ENABLED=0 go build examples/listen/verify -o /go/bin/verify

# Now copy it into our base image.
FROM gcr.io/distroless/static-debian11
COPY --from=build /go/bin/verify /
CMD ["/verify"]

The only thing you'd really have to do is adapt the accept loop.

boaks commented 1 year ago

So, very crudely, it could be along the lines of:

That results on "my machine" in:

package examples/listen/verify is not in GOROOT (/usr/local/go/src/examples/listen/verify)
malformed import path "-o": leading dash
stat /go/bin/verify: directory not found

I'm no GO user, so I'll just wait for others results.

hasheddan commented 1 year ago

@boaks apologies for the delay here! I have put together a test server and image that can be found at https://github.com/hasheddan/dtls-interop/tree/pion/dtls/cid/pion/cid_server. I will continue building this out with more functionality as I test against DTLS implementations. There are instructions for building and running the container image, and I have also pushed a preliminary version to DockerHub at hasheddan/dtls-interop-pion-cid-server.

The test server is setup to work out of the box with the example californium DTLS client. I tested by running the following and then executing the californium DTLS client.

docker run --rm --net host hasheddan/dtls-interop-pion-cid-server

The resulting packet capture can be found here. Please let me know if there is anything else I can do to help assist in your testing!

boaks commented 1 year ago

Very nice! I've tested it with an mbedtls client successfully.

boaks commented 1 year ago

The resulting packet capture can be found here.

Just to mention, as in my WikiPage for Captures: if the capture is compressed, it can be uploaded to a git comment just by drag&drop.

Please let me know if there is anything else I can do to help assist in your testing!

Thanks. For now, I only test the basic interoperability. That looks pretty good.