summaryrefslogtreecommitdiff
path: root/vendor/github.com/pion/dtls
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/pion/dtls')
-rw-r--r--vendor/github.com/pion/dtls/v2/.editorconfig21
-rw-r--r--vendor/github.com/pion/dtls/v2/.gitignore24
-rw-r--r--vendor/github.com/pion/dtls/v2/.golangci.yml89
-rw-r--r--vendor/github.com/pion/dtls/v2/LICENSE21
-rw-r--r--vendor/github.com/pion/dtls/v2/Makefile6
-rw-r--r--vendor/github.com/pion/dtls/v2/README.md155
-rw-r--r--vendor/github.com/pion/dtls/v2/certificate.go67
-rw-r--r--vendor/github.com/pion/dtls/v2/cipher_suite.go213
-rw-r--r--vendor/github.com/pion/dtls/v2/cipher_suite_go114.go40
-rw-r--r--vendor/github.com/pion/dtls/v2/codecov.yml20
-rw-r--r--vendor/github.com/pion/dtls/v2/compression_method.go9
-rw-r--r--vendor/github.com/pion/dtls/v2/config.go193
-rw-r--r--vendor/github.com/pion/dtls/v2/conn.go978
-rw-r--r--vendor/github.com/pion/dtls/v2/crypto.go221
-rw-r--r--vendor/github.com/pion/dtls/v2/dtls.go2
-rw-r--r--vendor/github.com/pion/dtls/v2/errors.go141
-rw-r--r--vendor/github.com/pion/dtls/v2/errors_errno.go25
-rw-r--r--vendor/github.com/pion/dtls/v2/errors_noerrno.go14
-rw-r--r--vendor/github.com/pion/dtls/v2/flight.go75
-rw-r--r--vendor/github.com/pion/dtls/v2/flight0handler.go102
-rw-r--r--vendor/github.com/pion/dtls/v2/flight1handler.go112
-rw-r--r--vendor/github.com/pion/dtls/v2/flight2handler.go61
-rw-r--r--vendor/github.com/pion/dtls/v2/flight3handler.go194
-rw-r--r--vendor/github.com/pion/dtls/v2/flight4handler.go337
-rw-r--r--vendor/github.com/pion/dtls/v2/flight5handler.go323
-rw-r--r--vendor/github.com/pion/dtls/v2/flight6handler.go82
-rw-r--r--vendor/github.com/pion/dtls/v2/flighthandler.go57
-rw-r--r--vendor/github.com/pion/dtls/v2/fragment_buffer.go111
-rw-r--r--vendor/github.com/pion/dtls/v2/fuzz.go38
-rw-r--r--vendor/github.com/pion/dtls/v2/go.mod12
-rw-r--r--vendor/github.com/pion/dtls/v2/go.sum48
-rw-r--r--vendor/github.com/pion/dtls/v2/handshake_cache.go171
-rw-r--r--vendor/github.com/pion/dtls/v2/handshaker.go334
-rw-r--r--vendor/github.com/pion/dtls/v2/internal/ciphersuite/aes_128_ccm.go108
-rw-r--r--vendor/github.com/pion/dtls/v2/internal/ciphersuite/ciphersuite.go71
-rw-r--r--vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_ccm.go11
-rw-r--r--vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_ccm8.go11
-rw-r--r--vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_gcm_sha256.go92
-rw-r--r--vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_256_cbc_sha.go101
-rw-r--r--vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_rsa_with_aes_128_gcm_sha256.go22
-rw-r--r--vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_rsa_with_aes_256_cbc_sha.go22
-rw-r--r--vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_cbc_sha256.go100
-rw-r--r--vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_ccm.go11
-rw-r--r--vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_ccm8.go11
-rw-r--r--vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_gcm_sha256.go27
-rw-r--r--vendor/github.com/pion/dtls/v2/internal/closer/closer.go45
-rw-r--r--vendor/github.com/pion/dtls/v2/internal/util/util.go39
-rw-r--r--vendor/github.com/pion/dtls/v2/listener.go80
-rw-r--r--vendor/github.com/pion/dtls/v2/packet.go9
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/crypto/ccm/ccm.go251
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/cbc.go164
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/ccm.go104
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/ciphersuite.go72
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/gcm.go100
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/crypto/clientcertificate/client_certificate.go22
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/crypto/elliptic/elliptic.go99
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/crypto/fingerprint/fingerprint.go50
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/crypto/fingerprint/hash.go37
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/crypto/hash/hash.go126
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/crypto/prf/prf.go224
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/crypto/signature/signature.go24
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/crypto/signaturehash/errors.go9
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/crypto/signaturehash/signaturehash.go93
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/alert/alert.go160
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/application_data.go26
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/change_cipher_spec.go28
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/compression_method.go48
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/content.go21
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/errors.go104
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/extension/errors.go14
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/extension/extension.go96
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/extension/renegotiation_info.go43
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/extension/server_name.go78
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/extension/srtp_protection_profile.go21
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_elliptic_curves.go62
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_point_formats.go62
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_signature_algorithms.go70
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/extension/use_master_secret.go45
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/extension/use_srtp.go59
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/cipher_suite.go29
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/errors.go25
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/handshake.go145
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/header.go50
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_certificate.go66
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_certificate_request.go100
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_certificate_verify.go61
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_client_hello.go125
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_client_key_exchange.go56
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_finished.go27
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_hello_verify_request.go62
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_server_hello.go106
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_server_hello_done.go22
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_server_key_exchange.go119
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/random.go49
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/recordlayer/errors.go16
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/recordlayer/header.go61
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/recordlayer/recordlayer.go99
-rw-r--r--vendor/github.com/pion/dtls/v2/pkg/protocol/version.go21
-rw-r--r--vendor/github.com/pion/dtls/v2/renovate.json15
-rw-r--r--vendor/github.com/pion/dtls/v2/resume.go19
-rw-r--r--vendor/github.com/pion/dtls/v2/srtp_protection_profile.go14
-rw-r--r--vendor/github.com/pion/dtls/v2/state.go194
-rw-r--r--vendor/github.com/pion/dtls/v2/util.go38
103 files changed, 8887 insertions, 0 deletions
diff --git a/vendor/github.com/pion/dtls/v2/.editorconfig b/vendor/github.com/pion/dtls/v2/.editorconfig
new file mode 100644
index 0000000..d2b3206
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/.editorconfig
@@ -0,0 +1,21 @@
+# http://editorconfig.org/
+
+root = true
+
+[*]
+charset = utf-8
+insert_final_newline = true
+trim_trailing_whitespace = true
+end_of_line = lf
+
+[*.go]
+indent_style = tab
+indent_size = 4
+
+[{*.yml,*.yaml}]
+indent_style = space
+indent_size = 2
+
+# Makefiles always use tabs for indentation
+[Makefile]
+indent_style = tab
diff --git a/vendor/github.com/pion/dtls/v2/.gitignore b/vendor/github.com/pion/dtls/v2/.gitignore
new file mode 100644
index 0000000..83db74b
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/.gitignore
@@ -0,0 +1,24 @@
+### JetBrains IDE ###
+#####################
+.idea/
+
+### Emacs Temporary Files ###
+#############################
+*~
+
+### Folders ###
+###############
+bin/
+vendor/
+node_modules/
+
+### Files ###
+#############
+*.ivf
+*.ogg
+tags
+cover.out
+*.sw[poe]
+*.wasm
+examples/sfu-ws/cert.pem
+examples/sfu-ws/key.pem
diff --git a/vendor/github.com/pion/dtls/v2/.golangci.yml b/vendor/github.com/pion/dtls/v2/.golangci.yml
new file mode 100644
index 0000000..d6162c9
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/.golangci.yml
@@ -0,0 +1,89 @@
+linters-settings:
+ govet:
+ check-shadowing: true
+ misspell:
+ locale: US
+ exhaustive:
+ default-signifies-exhaustive: true
+ gomodguard:
+ blocked:
+ modules:
+ - github.com/pkg/errors:
+ recommendations:
+ - errors
+
+linters:
+ enable:
+ - asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers
+ - bodyclose # checks whether HTTP response body is closed successfully
+ - deadcode # Finds unused code
+ - depguard # Go linter that checks if package imports are in a list of acceptable packages
+ - dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
+ - dupl # Tool for code clone detection
+ - errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
+ - exhaustive # check exhaustiveness of enum switch statements
+ - exportloopref # checks for pointers to enclosing loop variables
+ - gci # Gci control golang package import order and make it always deterministic.
+ - gochecknoglobals # Checks that no globals are present in Go code
+ - gochecknoinits # Checks that no init functions are present in Go code
+ - gocognit # Computes and checks the cognitive complexity of functions
+ - goconst # Finds repeated strings that could be replaced by a constant
+ - gocritic # The most opinionated Go source code linter
+ - godox # Tool for detection of FIXME, TODO and other comment keywords
+ - goerr113 # Golang linter to check the errors handling expressions
+ - gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
+ - gofumpt # Gofumpt checks whether code was gofumpt-ed.
+ - goheader # Checks is file header matches to pattern
+ - goimports # Goimports does everything that gofmt does. Additionally it checks unused imports
+ - golint # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes
+ - gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations.
+ - goprintffuncname # Checks that printf-like functions are named with `f` at the end
+ - gosec # Inspects source code for security problems
+ - gosimple # Linter for Go source code that specializes in simplifying a code
+ - govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
+ - ineffassign # Detects when assignments to existing variables are not used
+ - misspell # Finds commonly misspelled English words in comments
+ - nakedret # Finds naked returns in functions greater than a specified function length
+ - noctx # noctx finds sending http request without context.Context
+ - scopelint # Scopelint checks for unpinned variables in go programs
+ - staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks
+ - structcheck # Finds unused struct fields
+ - stylecheck # Stylecheck is a replacement for golint
+ - typecheck # Like the front-end of a Go compiler, parses and type-checks Go code
+ - unconvert # Remove unnecessary type conversions
+ - unparam # Reports unused function parameters
+ - unused # Checks Go code for unused constants, variables, functions and types
+ - varcheck # Finds unused global variables and constants
+ - whitespace # Tool for detection of leading and trailing whitespace
+ disable:
+ - funlen # Tool for detection of long functions
+ - gocyclo # Computes and checks the cyclomatic complexity of functions
+ - godot # Check if comments end in a period
+ - gomnd # An analyzer to detect magic numbers.
+ - lll # Reports long lines
+ - maligned # Tool to detect Go structs that would take less memory if their fields were sorted
+ - nestif # Reports deeply nested if statements
+ - nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity
+ - nolintlint # Reports ill-formed or insufficient nolint directives
+ - prealloc # Finds slice declarations that could potentially be preallocated
+ - rowserrcheck # checks whether Err of rows is checked successfully
+ - sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed.
+ - testpackage # linter that makes you use a separate _test package
+ - wsl # Whitespace Linter - Forces you to use empty lines!
+
+issues:
+ exclude-use-default: false
+ exclude-rules:
+ # Allow complex tests, better to be self contained
+ - path: _test\.go
+ linters:
+ - gocognit
+
+ # Allow complex main function in examples
+ - path: examples
+ text: "of func `main` is high"
+ linters:
+ - gocognit
+
+run:
+ skip-dirs-use-default: false
diff --git a/vendor/github.com/pion/dtls/v2/LICENSE b/vendor/github.com/pion/dtls/v2/LICENSE
new file mode 100644
index 0000000..ab60297
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/pion/dtls/v2/Makefile b/vendor/github.com/pion/dtls/v2/Makefile
new file mode 100644
index 0000000..1df38b2
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/Makefile
@@ -0,0 +1,6 @@
+fuzz-build-record-layer: fuzz-prepare
+ go-fuzz-build -tags gofuzz -func FuzzRecordLayer
+fuzz-run-record-layer:
+ go-fuzz -bin dtls-fuzz.zip -workdir fuzz
+fuzz-prepare:
+ @GO111MODULE=on go mod vendor
diff --git a/vendor/github.com/pion/dtls/v2/README.md b/vendor/github.com/pion/dtls/v2/README.md
new file mode 100644
index 0000000..62cac7c
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/README.md
@@ -0,0 +1,155 @@
+<h1 align="center">
+ <br>
+ Pion DTLS
+ <br>
+</h1>
+<h4 align="center">A Go implementation of DTLS</h4>
+<p align="center">
+ <a href="https://pion.ly"><img src="https://img.shields.io/badge/pion-dtls-gray.svg?longCache=true&colorB=brightgreen" alt="Pion DTLS"></a>
+ <a href="https://sourcegraph.com/github.com/pion/dtls"><img src="https://sourcegraph.com/github.com/pion/dtls/-/badge.svg" alt="Sourcegraph Widget"></a>
+ <a href="https://pion.ly/slack"><img src="https://img.shields.io/badge/join-us%20on%20slack-gray.svg?longCache=true&logo=slack&colorB=brightgreen" alt="Slack Widget"></a>
+ <br>
+ <a href="https://travis-ci.org/pion/dtls"><img src="https://travis-ci.org/pion/dtls.svg?branch=master" alt="Build Status"></a>
+ <a href="https://pkg.go.dev/github.com/pion/dtls"><img src="https://godoc.org/github.com/pion/dtls?status.svg" alt="GoDoc"></a>
+ <a href="https://codecov.io/gh/pion/dtls"><img src="https://codecov.io/gh/pion/dtls/branch/master/graph/badge.svg" alt="Coverage Status"></a>
+ <a href="https://goreportcard.com/report/github.com/pion/dtls"><img src="https://goreportcard.com/badge/github.com/pion/dtls" alt="Go Report Card"></a>
+ <a href="https://www.codacy.com/app/Sean-Der/dtls"><img src="https://api.codacy.com/project/badge/Grade/18f4aec384894e6aac0b94effe51961d" alt="Codacy Badge"></a>
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
+</p>
+<br>
+
+Native [DTLS 1.2][rfc6347] implementation in the Go programming language.
+
+A long term goal is a professional security review, and maye inclusion in stdlib.
+
+[rfc6347]: https://tools.ietf.org/html/rfc6347
+
+### Goals/Progress
+This will only be targeting DTLS 1.2, and the most modern/common cipher suites.
+We would love contributes that fall under the 'Planned Features' and fixing any bugs!
+
+#### Current features
+* DTLS 1.2 Client/Server
+* Key Exchange via ECDHE(curve25519, nistp256, nistp384) and PSK
+* Packet loss and re-ordering is handled during handshaking
+* Key export ([RFC 5705][rfc5705])
+* Serialization and Resumption of sessions
+* Extended Master Secret extension ([RFC 7627][rfc7627])
+
+[rfc5705]: https://tools.ietf.org/html/rfc5705
+[rfc7627]: https://tools.ietf.org/html/rfc7627
+
+#### Supported ciphers
+
+##### ECDHE
+* TLS_ECDHE_ECDSA_WITH_AES_128_CCM ([RFC 6655][rfc6655])
+* TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 ([RFC 6655][rfc6655])
+* TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 ([RFC 5289][rfc5289])
+* TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ([RFC 5289][rfc5289])
+* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA ([RFC 8422][rfc8422])
+* TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA ([RFC 8422][rfc8422])
+
+##### PSK
+* TLS_PSK_WITH_AES_128_CCM ([RFC 6655][rfc6655])
+* TLS_PSK_WITH_AES_128_CCM_8 ([RFC 6655][rfc6655])
+* TLS_PSK_WITH_AES_128_GCM_SHA256 ([RFC 5487][rfc5487])
+* TLS_PSK_WITH_AES_128_CBC_SHA256 ([RFC 5487][rfc5487])
+
+[rfc5289]: https://tools.ietf.org/html/rfc5289
+[rfc8422]: https://tools.ietf.org/html/rfc8422
+[rfc6655]: https://tools.ietf.org/html/rfc6655
+[rfc5487]: https://tools.ietf.org/html/rfc5487
+
+#### Planned Features
+* Chacha20Poly1305
+
+#### Excluded Features
+* DTLS 1.0
+* Renegotiation
+* Compression
+
+### Using
+
+This library needs at least Go 1.13, and you should have [Go modules
+enabled](https://github.com/golang/go/wiki/Modules).
+
+#### Pion DTLS
+For a DTLS 1.2 Server that listens on 127.0.0.1:4444
+```sh
+go run examples/listen/selfsign/main.go
+```
+
+For a DTLS 1.2 Client that connects to 127.0.0.1:4444
+```sh
+go run examples/dial/selfsign/main.go
+```
+
+#### OpenSSL
+Pion DTLS can connect to itself and OpenSSL.
+```
+ // Generate a certificate
+ 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
+
+ // Use with examples/dial/selfsign/main.go
+ openssl s_server -dtls1_2 -cert cert.pem -key key.pem -accept 4444
+
+ // Use with examples/listen/selfsign/main.go
+ openssl s_client -dtls1_2 -connect 127.0.0.1:4444 -debug -cert cert.pem -key key.pem
+```
+
+### Using with PSK
+Pion DTLS also comes with examples that do key exchange via PSK
+
+
+#### Pion DTLS
+```sh
+go run examples/listen/psk/main.go
+```
+
+```sh
+go run examples/dial/psk/main.go
+```
+
+#### OpenSSL
+```
+ // Use with examples/dial/psk/main.go
+ openssl s_server -dtls1_2 -accept 4444 -nocert -psk abc123 -cipher PSK-AES128-CCM8
+
+ // Use with examples/listen/psk/main.go
+ openssl s_client -dtls1_2 -connect 127.0.0.1:4444 -psk abc123 -cipher PSK-AES128-CCM8
+```
+
+### Contributing
+Check out the **[contributing wiki](https://github.com/pion/webrtc/wiki/Contributing)** to join the group of amazing people making this project possible:
+
+* [Sean DuBois](https://github.com/Sean-Der) - *Original Author*
+* [Michiel De Backker](https://github.com/backkem) - *Public API*
+* [Chris Hiszpanski](https://github.com/thinkski) - *Support Signature Algorithms Extension*
+* [Iñigo Garcia Olaizola](https://github.com/igolaizola) - *Serialization & resumption, cert verification, E2E*
+* [Daniele Sluijters](https://github.com/daenney) - *AES-CCM support*
+* [Jin Lei](https://github.com/jinleileiking) - *Logging*
+* [Hugo Arregui](https://github.com/hugoArregui)
+* [Lander Noterman](https://github.com/LanderN)
+* [Aleksandr Razumov](https://github.com/ernado) - *Fuzzing*
+* [Ryan Gordon](https://github.com/ryangordon)
+* [Stefan Tatschner](https://rumpelsepp.org/contact.html)
+* [Hayden James](https://github.com/hjames9)
+* [Jozef Kralik](https://github.com/jkralik)
+* [Robert Eperjesi](https://github.com/epes)
+* [Atsushi Watanabe](https://github.com/at-wat)
+* [Julien Salleyron](https://github.com/juliens) - *Server Name Indication*
+* [Jeroen de Bruijn](https://github.com/vidavidorra)
+* [bjdgyc](https://github.com/bjdgyc)
+* [Jeffrey Stoke (Jeff Ctor)](https://github.com/jeffreystoke) - *Fragmentbuffer Fix*
+* [Frank Olbricht](https://github.com/folbricht)
+* [ZHENK](https://github.com/scorpionknifes)
+* [Carson Hoffman](https://github.com/CarsonHoffman)
+* [Vadim Filimonov](https://github.com/fffilimonov)
+* [Jim Wert](https://github.com/bocajim)
+* [Alvaro Viebrantz](https://github.com/alvarowolfx)
+* [Kegan Dougal](https://github.com/Kegsay)
+
+### License
+MIT License - see [LICENSE](LICENSE) for full text
diff --git a/vendor/github.com/pion/dtls/v2/certificate.go b/vendor/github.com/pion/dtls/v2/certificate.go
new file mode 100644
index 0000000..c99e1c9
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/certificate.go
@@ -0,0 +1,67 @@
+package dtls
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "strings"
+)
+
+func (c *handshakeConfig) getCertificate(serverName string) (*tls.Certificate, error) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if c.nameToCertificate == nil {
+ nameToCertificate := make(map[string]*tls.Certificate)
+ for i := range c.localCertificates {
+ cert := &c.localCertificates[i]
+ x509Cert := cert.Leaf
+ if x509Cert == nil {
+ var parseErr error
+ x509Cert, parseErr = x509.ParseCertificate(cert.Certificate[0])
+ if parseErr != nil {
+ continue
+ }
+ }
+ if len(x509Cert.Subject.CommonName) > 0 {
+ nameToCertificate[strings.ToLower(x509Cert.Subject.CommonName)] = cert
+ }
+ for _, san := range x509Cert.DNSNames {
+ nameToCertificate[strings.ToLower(san)] = cert
+ }
+ }
+ c.nameToCertificate = nameToCertificate
+ }
+
+ if len(c.localCertificates) == 0 {
+ return nil, errNoCertificates
+ }
+
+ if len(c.localCertificates) == 1 {
+ // There's only one choice, so no point doing any work.
+ return &c.localCertificates[0], nil
+ }
+
+ if len(serverName) == 0 {
+ return &c.localCertificates[0], nil
+ }
+
+ name := strings.TrimRight(strings.ToLower(serverName), ".")
+
+ if cert, ok := c.nameToCertificate[name]; ok {
+ return cert, nil
+ }
+
+ // try replacing labels in the name with wildcards until we get a
+ // match.
+ labels := strings.Split(name, ".")
+ for i := range labels {
+ labels[i] = "*"
+ candidate := strings.Join(labels, ".")
+ if cert, ok := c.nameToCertificate[candidate]; ok {
+ return cert, nil
+ }
+ }
+
+ // If nothing matches, return the first certificate.
+ return &c.localCertificates[0], nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/cipher_suite.go b/vendor/github.com/pion/dtls/v2/cipher_suite.go
new file mode 100644
index 0000000..ed10609
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/cipher_suite.go
@@ -0,0 +1,213 @@
+package dtls
+
+import (
+ "fmt"
+ "hash"
+
+ "github.com/pion/dtls/v2/internal/ciphersuite"
+ "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+)
+
+// CipherSuiteID is an ID for our supported CipherSuites
+type CipherSuiteID = ciphersuite.ID
+
+// Supported Cipher Suites
+const (
+ // AES-128-CCM
+ TLS_ECDHE_ECDSA_WITH_AES_128_CCM CipherSuiteID = ciphersuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM //nolint:golint,stylecheck
+ TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 CipherSuiteID = ciphersuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 //nolint:golint,stylecheck
+
+ // AES-128-GCM-SHA256
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 CipherSuiteID = ciphersuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 //nolint:golint,stylecheck
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 CipherSuiteID = ciphersuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 //nolint:golint,stylecheck
+
+ // AES-256-CBC-SHA
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA CipherSuiteID = ciphersuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA //nolint:golint,stylecheck
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA CipherSuiteID = ciphersuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA //nolint:golint,stylecheck
+
+ TLS_PSK_WITH_AES_128_CCM CipherSuiteID = ciphersuite.TLS_PSK_WITH_AES_128_CCM //nolint:golint,stylecheck
+ TLS_PSK_WITH_AES_128_CCM_8 CipherSuiteID = ciphersuite.TLS_PSK_WITH_AES_128_CCM_8 //nolint:golint,stylecheck
+ TLS_PSK_WITH_AES_128_GCM_SHA256 CipherSuiteID = ciphersuite.TLS_PSK_WITH_AES_128_GCM_SHA256 //nolint:golint,stylecheck
+ TLS_PSK_WITH_AES_128_CBC_SHA256 CipherSuiteID = ciphersuite.TLS_PSK_WITH_AES_128_CBC_SHA256 //nolint:golint,stylecheck
+)
+
+// CipherSuiteAuthenticationType controls what authentication method is using during the handshake for a CipherSuite
+type CipherSuiteAuthenticationType = ciphersuite.AuthenticationType
+
+// AuthenticationType Enums
+const (
+ CipherSuiteAuthenticationTypeCertificate CipherSuiteAuthenticationType = ciphersuite.AuthenticationTypeCertificate
+ CipherSuiteAuthenticationTypePreSharedKey CipherSuiteAuthenticationType = ciphersuite.AuthenticationTypePreSharedKey
+ CipherSuiteAuthenticationTypeAnonymous CipherSuiteAuthenticationType = ciphersuite.AuthenticationTypeAnonymous
+)
+
+var _ = allCipherSuites() // Necessary until this function isn't only used by Go 1.14
+
+// CipherSuite is an interface that all DTLS CipherSuites must satisfy
+type CipherSuite interface {
+ // String of CipherSuite, only used for logging
+ String() string
+
+ // ID of CipherSuite.
+ ID() CipherSuiteID
+
+ // What type of Certificate does this CipherSuite use
+ CertificateType() clientcertificate.Type
+
+ // What Hash function is used during verification
+ HashFunc() func() hash.Hash
+
+ // AuthenticationType controls what authentication method is using during the handshake
+ AuthenticationType() CipherSuiteAuthenticationType
+
+ // Called when keying material has been generated, should initialize the internal cipher
+ Init(masterSecret, clientRandom, serverRandom []byte, isClient bool) error
+ IsInitialized() bool
+
+ Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error)
+ Decrypt(in []byte) ([]byte, error)
+}
+
+// CipherSuiteName provides the same functionality as tls.CipherSuiteName
+// that appeared first in Go 1.14.
+//
+// Our implementation differs slightly in that it takes in a CiperSuiteID,
+// like the rest of our library, instead of a uint16 like crypto/tls.
+func CipherSuiteName(id CipherSuiteID) string {
+ suite := cipherSuiteForID(id, nil)
+ if suite != nil {
+ return suite.String()
+ }
+ return fmt.Sprintf("0x%04X", uint16(id))
+}
+
+// Taken from https://www.iana.org/assignments/tls-parameters/tls-parameters.xml
+// A cipherSuite is a specific combination of key agreement, cipher and MAC
+// function.
+func cipherSuiteForID(id CipherSuiteID, customCiphers func() []CipherSuite) CipherSuite {
+ switch id { //nolint:exhaustive
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
+ return ciphersuite.NewTLSEcdheEcdsaWithAes128Ccm()
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ return ciphersuite.NewTLSEcdheEcdsaWithAes128Ccm8()
+ case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ return &ciphersuite.TLSEcdheEcdsaWithAes128GcmSha256{}
+ case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ return &ciphersuite.TLSEcdheRsaWithAes128GcmSha256{}
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ return &ciphersuite.TLSEcdheEcdsaWithAes256CbcSha{}
+ case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ return &ciphersuite.TLSEcdheRsaWithAes256CbcSha{}
+ case TLS_PSK_WITH_AES_128_CCM:
+ return ciphersuite.NewTLSPskWithAes128Ccm()
+ case TLS_PSK_WITH_AES_128_CCM_8:
+ return ciphersuite.NewTLSPskWithAes128Ccm8()
+ case TLS_PSK_WITH_AES_128_GCM_SHA256:
+ return &ciphersuite.TLSPskWithAes128GcmSha256{}
+ case TLS_PSK_WITH_AES_128_CBC_SHA256:
+ return &ciphersuite.TLSPskWithAes128CbcSha256{}
+ }
+
+ if customCiphers != nil {
+ for _, c := range customCiphers() {
+ if c.ID() == id {
+ return c
+ }
+ }
+ }
+
+ return nil
+}
+
+// CipherSuites we support in order of preference
+func defaultCipherSuites() []CipherSuite {
+ return []CipherSuite{
+ &ciphersuite.TLSEcdheEcdsaWithAes128GcmSha256{},
+ &ciphersuite.TLSEcdheRsaWithAes128GcmSha256{},
+ &ciphersuite.TLSEcdheEcdsaWithAes256CbcSha{},
+ &ciphersuite.TLSEcdheRsaWithAes256CbcSha{},
+ }
+}
+
+func allCipherSuites() []CipherSuite {
+ return []CipherSuite{
+ ciphersuite.NewTLSEcdheEcdsaWithAes128Ccm(),
+ ciphersuite.NewTLSEcdheEcdsaWithAes128Ccm8(),
+ &ciphersuite.TLSEcdheEcdsaWithAes128GcmSha256{},
+ &ciphersuite.TLSEcdheRsaWithAes128GcmSha256{},
+ &ciphersuite.TLSEcdheEcdsaWithAes256CbcSha{},
+ &ciphersuite.TLSEcdheRsaWithAes256CbcSha{},
+ ciphersuite.NewTLSPskWithAes128Ccm(),
+ ciphersuite.NewTLSPskWithAes128Ccm8(),
+ &ciphersuite.TLSPskWithAes128GcmSha256{},
+ }
+}
+
+func cipherSuiteIDs(cipherSuites []CipherSuite) []uint16 {
+ rtrn := []uint16{}
+ for _, c := range cipherSuites {
+ rtrn = append(rtrn, uint16(c.ID()))
+ }
+ return rtrn
+}
+
+func parseCipherSuites(userSelectedSuites []CipherSuiteID, customCipherSuites func() []CipherSuite, includeCertificateSuites, includePSKSuites bool) ([]CipherSuite, error) {
+ cipherSuitesForIDs := func(ids []CipherSuiteID) ([]CipherSuite, error) {
+ cipherSuites := []CipherSuite{}
+ for _, id := range ids {
+ c := cipherSuiteForID(id, nil)
+ if c == nil {
+ return nil, &invalidCipherSuite{id}
+ }
+ cipherSuites = append(cipherSuites, c)
+ }
+ return cipherSuites, nil
+ }
+
+ var (
+ cipherSuites []CipherSuite
+ err error
+ i int
+ )
+ if userSelectedSuites != nil {
+ cipherSuites, err = cipherSuitesForIDs(userSelectedSuites)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ cipherSuites = defaultCipherSuites()
+ }
+
+ // Put CustomCipherSuites before ID selected suites
+ if customCipherSuites != nil {
+ cipherSuites = append(customCipherSuites(), cipherSuites...)
+ }
+
+ var foundCertificateSuite, foundPSKSuite, foundAnonymousSuite bool
+ for _, c := range cipherSuites {
+ switch {
+ case includeCertificateSuites && c.AuthenticationType() == CipherSuiteAuthenticationTypeCertificate:
+ foundCertificateSuite = true
+ case includePSKSuites && c.AuthenticationType() == CipherSuiteAuthenticationTypePreSharedKey:
+ foundPSKSuite = true
+ case c.AuthenticationType() == CipherSuiteAuthenticationTypeAnonymous:
+ foundAnonymousSuite = true
+ default:
+ continue
+ }
+ cipherSuites[i] = c
+ i++
+ }
+
+ switch {
+ case includeCertificateSuites && !foundCertificateSuite && !foundAnonymousSuite:
+ return nil, errNoAvailableCertificateCipherSuite
+ case includePSKSuites && !foundPSKSuite:
+ return nil, errNoAvailablePSKCipherSuite
+ case i == 0:
+ return nil, errNoAvailableCipherSuites
+ }
+
+ return cipherSuites[:i], nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/cipher_suite_go114.go b/vendor/github.com/pion/dtls/v2/cipher_suite_go114.go
new file mode 100644
index 0000000..7bba16e
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/cipher_suite_go114.go
@@ -0,0 +1,40 @@
+// +build go1.14
+
+package dtls
+
+import (
+ "crypto/tls"
+)
+
+// VersionDTLS12 is the DTLS version in the same style as
+// VersionTLSXX from crypto/tls
+const VersionDTLS12 = 0xfefd
+
+// Convert from our cipherSuite interface to a tls.CipherSuite struct
+func toTLSCipherSuite(c CipherSuite) *tls.CipherSuite {
+ return &tls.CipherSuite{
+ ID: uint16(c.ID()),
+ Name: c.String(),
+ SupportedVersions: []uint16{VersionDTLS12},
+ Insecure: false,
+ }
+}
+
+// CipherSuites returns a list of cipher suites currently implemented by this
+// package, excluding those with security issues, which are returned by
+// InsecureCipherSuites.
+func CipherSuites() []*tls.CipherSuite {
+ suites := allCipherSuites()
+ res := make([]*tls.CipherSuite, len(suites))
+ for i, c := range suites {
+ res[i] = toTLSCipherSuite(c)
+ }
+ return res
+}
+
+// InsecureCipherSuites returns a list of cipher suites currently implemented by
+// this package and which have security issues.
+func InsecureCipherSuites() []*tls.CipherSuite {
+ var res []*tls.CipherSuite
+ return res
+}
diff --git a/vendor/github.com/pion/dtls/v2/codecov.yml b/vendor/github.com/pion/dtls/v2/codecov.yml
new file mode 100644
index 0000000..085200a
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/codecov.yml
@@ -0,0 +1,20 @@
+#
+# DO NOT EDIT THIS FILE
+#
+# It is automatically copied from https://github.com/pion/.goassets repository.
+#
+
+coverage:
+ status:
+ project:
+ default:
+ # Allow decreasing 2% of total coverage to avoid noise.
+ threshold: 2%
+ patch:
+ default:
+ target: 70%
+ only_pulls: true
+
+ignore:
+ - "examples/*"
+ - "examples/**/*"
diff --git a/vendor/github.com/pion/dtls/v2/compression_method.go b/vendor/github.com/pion/dtls/v2/compression_method.go
new file mode 100644
index 0000000..693eb7a
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/compression_method.go
@@ -0,0 +1,9 @@
+package dtls
+
+import "github.com/pion/dtls/v2/pkg/protocol"
+
+func defaultCompressionMethods() []*protocol.CompressionMethod {
+ return []*protocol.CompressionMethod{
+ {},
+ }
+}
diff --git a/vendor/github.com/pion/dtls/v2/config.go b/vendor/github.com/pion/dtls/v2/config.go
new file mode 100644
index 0000000..5ad42da
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/config.go
@@ -0,0 +1,193 @@
+package dtls
+
+import (
+ "context"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/tls"
+ "crypto/x509"
+ "io"
+ "time"
+
+ "github.com/pion/logging"
+)
+
+const keyLogLabelTLS12 = "CLIENT_RANDOM"
+
+// Config is used to configure a DTLS client or server.
+// After a Config is passed to a DTLS function it must not be modified.
+type Config struct {
+ // Certificates contains certificate chain to present to the other side of the connection.
+ // Server MUST set this if PSK is non-nil
+ // client SHOULD sets this so CertificateRequests can be handled if PSK is non-nil
+ Certificates []tls.Certificate
+
+ // CipherSuites is a list of supported cipher suites.
+ // If CipherSuites is nil, a default list is used
+ CipherSuites []CipherSuiteID
+
+ // CustomCipherSuites is a list of CipherSuites that can be
+ // provided by the user. This allow users to user Ciphers that are reserved
+ // for private usage.
+ CustomCipherSuites func() []CipherSuite
+
+ // SignatureSchemes contains the signature and hash schemes that the peer requests to verify.
+ SignatureSchemes []tls.SignatureScheme
+
+ // SRTPProtectionProfiles are the supported protection profiles
+ // Clients will send this via use_srtp and assert that the server properly responds
+ // Servers will assert that clients send one of these profiles and will respond as needed
+ SRTPProtectionProfiles []SRTPProtectionProfile
+
+ // ClientAuth determines the server's policy for
+ // TLS Client Authentication. The default is NoClientCert.
+ ClientAuth ClientAuthType
+
+ // RequireExtendedMasterSecret determines if the "Extended Master Secret" extension
+ // should be disabled, requested, or required (default requested).
+ ExtendedMasterSecret ExtendedMasterSecretType
+
+ // FlightInterval controls how often we send outbound handshake messages
+ // defaults to time.Second
+ FlightInterval time.Duration
+
+ // PSK sets the pre-shared key used by this DTLS connection
+ // If PSK is non-nil only PSK CipherSuites will be used
+ PSK PSKCallback
+ PSKIdentityHint []byte
+
+ // InsecureSkipVerify controls whether a client verifies the
+ // server's certificate chain and host name.
+ // If InsecureSkipVerify is true, TLS accepts any certificate
+ // presented by the server and any host name in that certificate.
+ // In this mode, TLS is susceptible to man-in-the-middle attacks.
+ // This should be used only for testing.
+ InsecureSkipVerify bool
+
+ // InsecureHashes allows the use of hashing algorithms that are known
+ // to be vulnerable.
+ InsecureHashes bool
+
+ // VerifyPeerCertificate, if not nil, is called after normal
+ // certificate verification by either a client or server. It
+ // receives the certificate provided by the peer and also a flag
+ // that tells if normal verification has succeedded. If it returns a
+ // non-nil error, the handshake is aborted and that error results.
+ //
+ // If normal verification fails then the handshake will abort before
+ // considering this callback. If normal verification is disabled by
+ // setting InsecureSkipVerify, or (for a server) when ClientAuth is
+ // RequestClientCert or RequireAnyClientCert, then this callback will
+ // be considered but the verifiedChains will always be nil.
+ VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
+
+ // RootCAs defines the set of root certificate authorities
+ // that one peer uses when verifying the other peer's certificates.
+ // If RootCAs is nil, TLS uses the host's root CA set.
+ RootCAs *x509.CertPool
+
+ // ClientCAs defines the set of root certificate authorities
+ // that servers use if required to verify a client certificate
+ // by the policy in ClientAuth.
+ ClientCAs *x509.CertPool
+
+ // ServerName is used to verify the hostname on the returned
+ // certificates unless InsecureSkipVerify is given.
+ ServerName string
+
+ LoggerFactory logging.LoggerFactory
+
+ // ConnectContextMaker is a function to make a context used in Dial(),
+ // Client(), Server(), and Accept(). If nil, the default ConnectContextMaker
+ // is used. It can be implemented as following.
+ //
+ // func ConnectContextMaker() (context.Context, func()) {
+ // return context.WithTimeout(context.Background(), 30*time.Second)
+ // }
+ ConnectContextMaker func() (context.Context, func())
+
+ // MTU is the length at which handshake messages will be fragmented to
+ // fit within the maximum transmission unit (default is 1200 bytes)
+ MTU int
+
+ // ReplayProtectionWindow is the size of the replay attack protection window.
+ // Duplication of the sequence number is checked in this window size.
+ // Packet with sequence number older than this value compared to the latest
+ // accepted packet will be discarded. (default is 64)
+ ReplayProtectionWindow int
+
+ // KeyLogWriter optionally specifies a destination for TLS master secrets
+ // in NSS key log format that can be used to allow external programs
+ // such as Wireshark to decrypt TLS connections.
+ // See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format.
+ // Use of KeyLogWriter compromises security and should only be
+ // used for debugging.
+ KeyLogWriter io.Writer
+}
+
+func defaultConnectContextMaker() (context.Context, func()) {
+ return context.WithTimeout(context.Background(), 30*time.Second)
+}
+
+func (c *Config) connectContextMaker() (context.Context, func()) {
+ if c.ConnectContextMaker == nil {
+ return defaultConnectContextMaker()
+ }
+ return c.ConnectContextMaker()
+}
+
+const defaultMTU = 1200 // bytes
+
+// PSKCallback is called once we have the remote's PSKIdentityHint.
+// If the remote provided none it will be nil
+type PSKCallback func([]byte) ([]byte, error)
+
+// ClientAuthType declares the policy the server will follow for
+// TLS Client Authentication.
+type ClientAuthType int
+
+// ClientAuthType enums
+const (
+ NoClientCert ClientAuthType = iota
+ RequestClientCert
+ RequireAnyClientCert
+ VerifyClientCertIfGiven
+ RequireAndVerifyClientCert
+)
+
+// ExtendedMasterSecretType declares the policy the client and server
+// will follow for the Extended Master Secret extension
+type ExtendedMasterSecretType int
+
+// ExtendedMasterSecretType enums
+const (
+ RequestExtendedMasterSecret ExtendedMasterSecretType = iota
+ RequireExtendedMasterSecret
+ DisableExtendedMasterSecret
+)
+
+func validateConfig(config *Config) error {
+ switch {
+ case config == nil:
+ return errNoConfigProvided
+ case config.PSKIdentityHint != nil && config.PSK == nil:
+ return errIdentityNoPSK
+ }
+
+ for _, cert := range config.Certificates {
+ if cert.Certificate == nil {
+ return errInvalidCertificate
+ }
+ if cert.PrivateKey != nil {
+ switch cert.PrivateKey.(type) {
+ case ed25519.PrivateKey:
+ case *ecdsa.PrivateKey:
+ default:
+ return errInvalidPrivateKey
+ }
+ }
+ }
+
+ _, err := parseCipherSuites(config.CipherSuites, config.CustomCipherSuites, config.PSK == nil || len(config.Certificates) > 0, config.PSK != nil)
+ return err
+}
diff --git a/vendor/github.com/pion/dtls/v2/conn.go b/vendor/github.com/pion/dtls/v2/conn.go
new file mode 100644
index 0000000..42d732f
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/conn.go
@@ -0,0 +1,978 @@
+package dtls
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/pion/dtls/v2/internal/closer"
+ "github.com/pion/dtls/v2/pkg/crypto/elliptic"
+ "github.com/pion/dtls/v2/pkg/crypto/signaturehash"
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/alert"
+ "github.com/pion/dtls/v2/pkg/protocol/handshake"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+ "github.com/pion/logging"
+ "github.com/pion/transport/connctx"
+ "github.com/pion/transport/deadline"
+ "github.com/pion/transport/replaydetector"
+)
+
+const (
+ initialTickerInterval = time.Second
+ cookieLength = 20
+ defaultNamedCurve = elliptic.X25519
+ inboundBufferSize = 8192
+ // Default replay protection window is specified by RFC 6347 Section 4.1.2.6
+ defaultReplayProtectionWindow = 64
+)
+
+func invalidKeyingLabels() map[string]bool {
+ return map[string]bool{
+ "client finished": true,
+ "server finished": true,
+ "master secret": true,
+ "key expansion": true,
+ }
+}
+
+// Conn represents a DTLS connection
+type Conn struct {
+ lock sync.RWMutex // Internal lock (must not be public)
+ nextConn connctx.ConnCtx // Embedded Conn, typically a udpconn we read/write from
+ fragmentBuffer *fragmentBuffer // out-of-order and missing fragment handling
+ handshakeCache *handshakeCache // caching of handshake messages for verifyData generation
+ decrypted chan interface{} // Decrypted Application Data or error, pull by calling `Read`
+
+ state State // Internal state
+
+ maximumTransmissionUnit int
+
+ handshakeCompletedSuccessfully atomic.Value
+
+ encryptedPackets [][]byte
+
+ connectionClosedByUser bool
+ closeLock sync.Mutex
+ closed *closer.Closer
+ handshakeLoopsFinished sync.WaitGroup
+
+ readDeadline *deadline.Deadline
+ writeDeadline *deadline.Deadline
+
+ log logging.LeveledLogger
+
+ reading chan struct{}
+ handshakeRecv chan chan struct{}
+ cancelHandshaker func()
+ cancelHandshakeReader func()
+
+ fsm *handshakeFSM
+
+ replayProtectionWindow uint
+}
+
+func createConn(ctx context.Context, nextConn net.Conn, config *Config, isClient bool, initialState *State) (*Conn, error) {
+ err := validateConfig(config)
+ if err != nil {
+ return nil, err
+ }
+
+ if nextConn == nil {
+ return nil, errNilNextConn
+ }
+
+ cipherSuites, err := parseCipherSuites(config.CipherSuites, config.CustomCipherSuites, config.PSK == nil || len(config.Certificates) > 0, config.PSK != nil)
+ if err != nil {
+ return nil, err
+ }
+
+ signatureSchemes, err := signaturehash.ParseSignatureSchemes(config.SignatureSchemes, config.InsecureHashes)
+ if err != nil {
+ return nil, err
+ }
+
+ workerInterval := initialTickerInterval
+ if config.FlightInterval != 0 {
+ workerInterval = config.FlightInterval
+ }
+
+ loggerFactory := config.LoggerFactory
+ if loggerFactory == nil {
+ loggerFactory = logging.NewDefaultLoggerFactory()
+ }
+
+ logger := loggerFactory.NewLogger("dtls")
+
+ mtu := config.MTU
+ if mtu <= 0 {
+ mtu = defaultMTU
+ }
+
+ replayProtectionWindow := config.ReplayProtectionWindow
+ if replayProtectionWindow <= 0 {
+ replayProtectionWindow = defaultReplayProtectionWindow
+ }
+
+ c := &Conn{
+ nextConn: connctx.New(nextConn),
+ fragmentBuffer: newFragmentBuffer(),
+ handshakeCache: newHandshakeCache(),
+ maximumTransmissionUnit: mtu,
+
+ decrypted: make(chan interface{}, 1),
+ log: logger,
+
+ readDeadline: deadline.New(),
+ writeDeadline: deadline.New(),
+
+ reading: make(chan struct{}, 1),
+ handshakeRecv: make(chan chan struct{}),
+ closed: closer.NewCloser(),
+ cancelHandshaker: func() {},
+
+ replayProtectionWindow: uint(replayProtectionWindow),
+
+ state: State{
+ isClient: isClient,
+ },
+ }
+
+ c.setRemoteEpoch(0)
+ c.setLocalEpoch(0)
+
+ serverName := config.ServerName
+ // Use host from conn address when serverName is not provided
+ if isClient && serverName == "" && nextConn.RemoteAddr() != nil {
+ remoteAddr := nextConn.RemoteAddr().String()
+ var host string
+ host, _, err = net.SplitHostPort(remoteAddr)
+ if err != nil {
+ serverName = remoteAddr
+ } else {
+ serverName = host
+ }
+ }
+
+ hsCfg := &handshakeConfig{
+ localPSKCallback: config.PSK,
+ localPSKIdentityHint: config.PSKIdentityHint,
+ localCipherSuites: cipherSuites,
+ localSignatureSchemes: signatureSchemes,
+ extendedMasterSecret: config.ExtendedMasterSecret,
+ localSRTPProtectionProfiles: config.SRTPProtectionProfiles,
+ serverName: serverName,
+ clientAuth: config.ClientAuth,
+ localCertificates: config.Certificates,
+ insecureSkipVerify: config.InsecureSkipVerify,
+ verifyPeerCertificate: config.VerifyPeerCertificate,
+ rootCAs: config.RootCAs,
+ clientCAs: config.ClientCAs,
+ customCipherSuites: config.CustomCipherSuites,
+ retransmitInterval: workerInterval,
+ log: logger,
+ initialEpoch: 0,
+ keyLogWriter: config.KeyLogWriter,
+ }
+
+ var initialFlight flightVal
+ var initialFSMState handshakeState
+
+ if initialState != nil {
+ if c.state.isClient {
+ initialFlight = flight5
+ } else {
+ initialFlight = flight6
+ }
+ initialFSMState = handshakeFinished
+
+ c.state = *initialState
+ } else {
+ if c.state.isClient {
+ initialFlight = flight1
+ } else {
+ initialFlight = flight0
+ }
+ initialFSMState = handshakePreparing
+ }
+ // Do handshake
+ if err := c.handshake(ctx, hsCfg, initialFlight, initialFSMState); err != nil {
+ return nil, err
+ }
+
+ c.log.Trace("Handshake Completed")
+
+ return c, nil
+}
+
+// Dial connects to the given network address and establishes a DTLS connection on top.
+// Connection handshake will timeout using ConnectContextMaker in the Config.
+// If you want to specify the timeout duration, use DialWithContext() instead.
+func Dial(network string, raddr *net.UDPAddr, config *Config) (*Conn, error) {
+ ctx, cancel := config.connectContextMaker()
+ defer cancel()
+
+ return DialWithContext(ctx, network, raddr, config)
+}
+
+// Client establishes a DTLS connection over an existing connection.
+// Connection handshake will timeout using ConnectContextMaker in the Config.
+// If you want to specify the timeout duration, use ClientWithContext() instead.
+func Client(conn net.Conn, config *Config) (*Conn, error) {
+ ctx, cancel := config.connectContextMaker()
+ defer cancel()
+
+ return ClientWithContext(ctx, conn, config)
+}
+
+// Server listens for incoming DTLS connections.
+// Connection handshake will timeout using ConnectContextMaker in the Config.
+// If you want to specify the timeout duration, use ServerWithContext() instead.
+func Server(conn net.Conn, config *Config) (*Conn, error) {
+ ctx, cancel := config.connectContextMaker()
+ defer cancel()
+
+ return ServerWithContext(ctx, conn, config)
+}
+
+// DialWithContext connects to the given network address and establishes a DTLS connection on top.
+func DialWithContext(ctx context.Context, network string, raddr *net.UDPAddr, config *Config) (*Conn, error) {
+ pConn, err := net.DialUDP(network, nil, raddr)
+ if err != nil {
+ return nil, err
+ }
+ return ClientWithContext(ctx, pConn, config)
+}
+
+// ClientWithContext establishes a DTLS connection over an existing connection.
+func ClientWithContext(ctx context.Context, conn net.Conn, config *Config) (*Conn, error) {
+ switch {
+ case config == nil:
+ return nil, errNoConfigProvided
+ case config.PSK != nil && config.PSKIdentityHint == nil:
+ return nil, errPSKAndIdentityMustBeSetForClient
+ }
+
+ return createConn(ctx, conn, config, true, nil)
+}
+
+// ServerWithContext listens for incoming DTLS connections.
+func ServerWithContext(ctx context.Context, conn net.Conn, config *Config) (*Conn, error) {
+ if config == nil {
+ return nil, errNoConfigProvided
+ }
+
+ return createConn(ctx, conn, config, false, nil)
+}
+
+// Read reads data from the connection.
+func (c *Conn) Read(p []byte) (n int, err error) {
+ if !c.isHandshakeCompletedSuccessfully() {
+ return 0, errHandshakeInProgress
+ }
+
+ select {
+ case <-c.readDeadline.Done():
+ return 0, errDeadlineExceeded
+ default:
+ }
+
+ for {
+ select {
+ case <-c.readDeadline.Done():
+ return 0, errDeadlineExceeded
+ case out, ok := <-c.decrypted:
+ if !ok {
+ return 0, io.EOF
+ }
+ switch val := out.(type) {
+ case ([]byte):
+ if len(p) < len(val) {
+ return 0, errBufferTooSmall
+ }
+ copy(p, val)
+ return len(val), nil
+ case (error):
+ return 0, val
+ }
+ }
+ }
+}
+
+// Write writes len(p) bytes from p to the DTLS connection
+func (c *Conn) Write(p []byte) (int, error) {
+ if c.isConnectionClosed() {
+ return 0, ErrConnClosed
+ }
+
+ select {
+ case <-c.writeDeadline.Done():
+ return 0, errDeadlineExceeded
+ default:
+ }
+
+ if !c.isHandshakeCompletedSuccessfully() {
+ return 0, errHandshakeInProgress
+ }
+
+ return len(p), c.writePackets(c.writeDeadline, []*packet{
+ {
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Epoch: c.getLocalEpoch(),
+ Version: protocol.Version1_2,
+ },
+ Content: &protocol.ApplicationData{
+ Data: p,
+ },
+ },
+ shouldEncrypt: true,
+ },
+ })
+}
+
+// Close closes the connection.
+func (c *Conn) Close() error {
+ err := c.close(true)
+ c.handshakeLoopsFinished.Wait()
+ return err
+}
+
+// ConnectionState returns basic DTLS details about the connection.
+// Note that this replaced the `Export` function of v1.
+func (c *Conn) ConnectionState() State {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+ return *c.state.clone()
+}
+
+// SelectedSRTPProtectionProfile returns the selected SRTPProtectionProfile
+func (c *Conn) SelectedSRTPProtectionProfile() (SRTPProtectionProfile, bool) {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+
+ if c.state.srtpProtectionProfile == 0 {
+ return 0, false
+ }
+
+ return c.state.srtpProtectionProfile, true
+}
+
+func (c *Conn) writePackets(ctx context.Context, pkts []*packet) error {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ var rawPackets [][]byte
+
+ for _, p := range pkts {
+ if h, ok := p.record.Content.(*handshake.Handshake); ok {
+ handshakeRaw, err := p.record.Marshal()
+ if err != nil {
+ return err
+ }
+
+ c.log.Tracef("[handshake:%v] -> %s (epoch: %d, seq: %d)",
+ srvCliStr(c.state.isClient), h.Header.Type.String(),
+ p.record.Header.Epoch, h.Header.MessageSequence)
+ c.handshakeCache.push(handshakeRaw[recordlayer.HeaderSize:], p.record.Header.Epoch, h.Header.MessageSequence, h.Header.Type, c.state.isClient)
+
+ rawHandshakePackets, err := c.processHandshakePacket(p, h)
+ if err != nil {
+ return err
+ }
+ rawPackets = append(rawPackets, rawHandshakePackets...)
+ } else {
+ rawPacket, err := c.processPacket(p)
+ if err != nil {
+ return err
+ }
+ rawPackets = append(rawPackets, rawPacket)
+ }
+ }
+ if len(rawPackets) == 0 {
+ return nil
+ }
+ compactedRawPackets := c.compactRawPackets(rawPackets)
+
+ for _, compactedRawPackets := range compactedRawPackets {
+ if _, err := c.nextConn.WriteContext(ctx, compactedRawPackets); err != nil {
+ return netError(err)
+ }
+ }
+
+ return nil
+}
+
+func (c *Conn) compactRawPackets(rawPackets [][]byte) [][]byte {
+ combinedRawPackets := make([][]byte, 0)
+ currentCombinedRawPacket := make([]byte, 0)
+
+ for _, rawPacket := range rawPackets {
+ if len(currentCombinedRawPacket) > 0 && len(currentCombinedRawPacket)+len(rawPacket) >= c.maximumTransmissionUnit {
+ combinedRawPackets = append(combinedRawPackets, currentCombinedRawPacket)
+ currentCombinedRawPacket = []byte{}
+ }
+ currentCombinedRawPacket = append(currentCombinedRawPacket, rawPacket...)
+ }
+
+ combinedRawPackets = append(combinedRawPackets, currentCombinedRawPacket)
+
+ return combinedRawPackets
+}
+
+func (c *Conn) processPacket(p *packet) ([]byte, error) {
+ epoch := p.record.Header.Epoch
+ for len(c.state.localSequenceNumber) <= int(epoch) {
+ c.state.localSequenceNumber = append(c.state.localSequenceNumber, uint64(0))
+ }
+ seq := atomic.AddUint64(&c.state.localSequenceNumber[epoch], 1) - 1
+ if seq > recordlayer.MaxSequenceNumber {
+ // RFC 6347 Section 4.1.0
+ // The implementation must either abandon an association or rehandshake
+ // prior to allowing the sequence number to wrap.
+ return nil, errSequenceNumberOverflow
+ }
+ p.record.Header.SequenceNumber = seq
+
+ rawPacket, err := p.record.Marshal()
+ if err != nil {
+ return nil, err
+ }
+
+ if p.shouldEncrypt {
+ var err error
+ rawPacket, err = c.state.cipherSuite.Encrypt(p.record, rawPacket)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return rawPacket, nil
+}
+
+func (c *Conn) processHandshakePacket(p *packet, h *handshake.Handshake) ([][]byte, error) {
+ rawPackets := make([][]byte, 0)
+
+ handshakeFragments, err := c.fragmentHandshake(h)
+ if err != nil {
+ return nil, err
+ }
+ epoch := p.record.Header.Epoch
+ for len(c.state.localSequenceNumber) <= int(epoch) {
+ c.state.localSequenceNumber = append(c.state.localSequenceNumber, uint64(0))
+ }
+
+ for _, handshakeFragment := range handshakeFragments {
+ seq := atomic.AddUint64(&c.state.localSequenceNumber[epoch], 1) - 1
+ if seq > recordlayer.MaxSequenceNumber {
+ return nil, errSequenceNumberOverflow
+ }
+
+ recordlayerHeader := &recordlayer.Header{
+ Version: p.record.Header.Version,
+ ContentType: p.record.Header.ContentType,
+ ContentLen: uint16(len(handshakeFragment)),
+ Epoch: p.record.Header.Epoch,
+ SequenceNumber: seq,
+ }
+
+ recordlayerHeaderBytes, err := recordlayerHeader.Marshal()
+ if err != nil {
+ return nil, err
+ }
+
+ p.record.Header = *recordlayerHeader
+
+ rawPacket := append(recordlayerHeaderBytes, handshakeFragment...)
+ if p.shouldEncrypt {
+ var err error
+ rawPacket, err = c.state.cipherSuite.Encrypt(p.record, rawPacket)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ rawPackets = append(rawPackets, rawPacket)
+ }
+
+ return rawPackets, nil
+}
+
+func (c *Conn) fragmentHandshake(h *handshake.Handshake) ([][]byte, error) {
+ content, err := h.Message.Marshal()
+ if err != nil {
+ return nil, err
+ }
+
+ fragmentedHandshakes := make([][]byte, 0)
+
+ contentFragments := splitBytes(content, c.maximumTransmissionUnit)
+ if len(contentFragments) == 0 {
+ contentFragments = [][]byte{
+ {},
+ }
+ }
+
+ offset := 0
+ for _, contentFragment := range contentFragments {
+ contentFragmentLen := len(contentFragment)
+
+ headerFragment := &handshake.Header{
+ Type: h.Header.Type,
+ Length: h.Header.Length,
+ MessageSequence: h.Header.MessageSequence,
+ FragmentOffset: uint32(offset),
+ FragmentLength: uint32(contentFragmentLen),
+ }
+
+ offset += contentFragmentLen
+
+ headerFragmentRaw, err := headerFragment.Marshal()
+ if err != nil {
+ return nil, err
+ }
+
+ fragmentedHandshake := append(headerFragmentRaw, contentFragment...)
+ fragmentedHandshakes = append(fragmentedHandshakes, fragmentedHandshake)
+ }
+
+ return fragmentedHandshakes, nil
+}
+
+var poolReadBuffer = sync.Pool{ //nolint:gochecknoglobals
+ New: func() interface{} {
+ b := make([]byte, inboundBufferSize)
+ return &b
+ },
+}
+
+func (c *Conn) readAndBuffer(ctx context.Context) error {
+ bufptr := poolReadBuffer.Get().(*[]byte)
+ defer poolReadBuffer.Put(bufptr)
+
+ b := *bufptr
+ i, err := c.nextConn.ReadContext(ctx, b)
+ if err != nil {
+ return netError(err)
+ }
+
+ pkts, err := recordlayer.UnpackDatagram(b[:i])
+ if err != nil {
+ return err
+ }
+
+ var hasHandshake bool
+ for _, p := range pkts {
+ hs, alert, err := c.handleIncomingPacket(p, true)
+ if alert != nil {
+ if alertErr := c.notify(ctx, alert.Level, alert.Description); alertErr != nil {
+ if err == nil {
+ err = alertErr
+ }
+ }
+ }
+ if hs {
+ hasHandshake = true
+ }
+ switch e := err.(type) {
+ case nil:
+ case *errAlert:
+ if e.IsFatalOrCloseNotify() {
+ return e
+ }
+ default:
+ return e
+ }
+ }
+ if hasHandshake {
+ done := make(chan struct{})
+ select {
+ case c.handshakeRecv <- done:
+ // If the other party may retransmit the flight,
+ // we should respond even if it not a new message.
+ <-done
+ case <-c.fsm.Done():
+ }
+ }
+ return nil
+}
+
+func (c *Conn) handleQueuedPackets(ctx context.Context) error {
+ pkts := c.encryptedPackets
+ c.encryptedPackets = nil
+
+ for _, p := range pkts {
+ _, alert, err := c.handleIncomingPacket(p, false) // don't re-enqueue
+ if alert != nil {
+ if alertErr := c.notify(ctx, alert.Level, alert.Description); alertErr != nil {
+ if err == nil {
+ err = alertErr
+ }
+ }
+ }
+ switch e := err.(type) {
+ case nil:
+ case *errAlert:
+ if e.IsFatalOrCloseNotify() {
+ return e
+ }
+ default:
+ return e
+ }
+ }
+ return nil
+}
+
+func (c *Conn) handleIncomingPacket(buf []byte, enqueue bool) (bool, *alert.Alert, error) { //nolint:gocognit
+ h := &recordlayer.Header{}
+ if err := h.Unmarshal(buf); err != nil {
+ // Decode error must be silently discarded
+ // [RFC6347 Section-4.1.2.7]
+ c.log.Debugf("discarded broken packet: %v", err)
+ return false, nil, nil
+ }
+
+ // Validate epoch
+ remoteEpoch := c.getRemoteEpoch()
+ if h.Epoch > remoteEpoch {
+ if h.Epoch > remoteEpoch+1 {
+ c.log.Debugf("discarded future packet (epoch: %d, seq: %d)",
+ h.Epoch, h.SequenceNumber,
+ )
+ return false, nil, nil
+ }
+ if enqueue {
+ c.log.Debug("received packet of next epoch, queuing packet")
+ c.encryptedPackets = append(c.encryptedPackets, buf)
+ }
+ return false, nil, nil
+ }
+
+ // Anti-replay protection
+ for len(c.state.replayDetector) <= int(h.Epoch) {
+ c.state.replayDetector = append(c.state.replayDetector,
+ replaydetector.New(c.replayProtectionWindow, recordlayer.MaxSequenceNumber),
+ )
+ }
+ markPacketAsValid, ok := c.state.replayDetector[int(h.Epoch)].Check(h.SequenceNumber)
+ if !ok {
+ c.log.Debugf("discarded duplicated packet (epoch: %d, seq: %d)",
+ h.Epoch, h.SequenceNumber,
+ )
+ return false, nil, nil
+ }
+
+ // Decrypt
+ if h.Epoch != 0 {
+ if c.state.cipherSuite == nil || !c.state.cipherSuite.IsInitialized() {
+ if enqueue {
+ c.encryptedPackets = append(c.encryptedPackets, buf)
+ c.log.Debug("handshake not finished, queuing packet")
+ }
+ return false, nil, nil
+ }
+
+ var err error
+ buf, err = c.state.cipherSuite.Decrypt(buf)
+ if err != nil {
+ c.log.Debugf("%s: decrypt failed: %s", srvCliStr(c.state.isClient), err)
+ return false, nil, nil
+ }
+ }
+
+ isHandshake, err := c.fragmentBuffer.push(append([]byte{}, buf...))
+ if err != nil {
+ // Decode error must be silently discarded
+ // [RFC6347 Section-4.1.2.7]
+ c.log.Debugf("defragment failed: %s", err)
+ return false, nil, nil
+ } else if isHandshake {
+ markPacketAsValid()
+ for out, epoch := c.fragmentBuffer.pop(); out != nil; out, epoch = c.fragmentBuffer.pop() {
+ rawHandshake := &handshake.Handshake{}
+ if err := rawHandshake.Unmarshal(out); err != nil {
+ c.log.Debugf("%s: handshake parse failed: %s", srvCliStr(c.state.isClient), err)
+ continue
+ }
+
+ _ = c.handshakeCache.push(out, epoch, rawHandshake.Header.MessageSequence, rawHandshake.Header.Type, !c.state.isClient)
+ }
+
+ return true, nil, nil
+ }
+
+ r := &recordlayer.RecordLayer{}
+ if err := r.Unmarshal(buf); err != nil {
+ return false, &alert.Alert{Level: alert.Fatal, Description: alert.DecodeError}, err
+ }
+
+ switch content := r.Content.(type) {
+ case *alert.Alert:
+ c.log.Tracef("%s: <- %s", srvCliStr(c.state.isClient), content.String())
+ var a *alert.Alert
+ if content.Description == alert.CloseNotify {
+ // Respond with a close_notify [RFC5246 Section 7.2.1]
+ a = &alert.Alert{Level: alert.Warning, Description: alert.CloseNotify}
+ }
+ markPacketAsValid()
+ return false, a, &errAlert{content}
+ case *protocol.ChangeCipherSpec:
+ if c.state.cipherSuite == nil || !c.state.cipherSuite.IsInitialized() {
+ if enqueue {
+ c.encryptedPackets = append(c.encryptedPackets, buf)
+ c.log.Debugf("CipherSuite not initialized, queuing packet")
+ }
+ return false, nil, nil
+ }
+
+ newRemoteEpoch := h.Epoch + 1
+ c.log.Tracef("%s: <- ChangeCipherSpec (epoch: %d)", srvCliStr(c.state.isClient), newRemoteEpoch)
+
+ if c.getRemoteEpoch()+1 == newRemoteEpoch {
+ c.setRemoteEpoch(newRemoteEpoch)
+ markPacketAsValid()
+ }
+ case *protocol.ApplicationData:
+ if h.Epoch == 0 {
+ return false, &alert.Alert{Level: alert.Fatal, Description: alert.UnexpectedMessage}, errApplicationDataEpochZero
+ }
+
+ markPacketAsValid()
+
+ select {
+ case c.decrypted <- content.Data:
+ case <-c.closed.Done():
+ }
+
+ default:
+ return false, &alert.Alert{Level: alert.Fatal, Description: alert.UnexpectedMessage}, fmt.Errorf("%w: %d", errUnhandledContextType, content.ContentType())
+ }
+ return false, nil, nil
+}
+
+func (c *Conn) recvHandshake() <-chan chan struct{} {
+ return c.handshakeRecv
+}
+
+func (c *Conn) notify(ctx context.Context, level alert.Level, desc alert.Description) error {
+ return c.writePackets(ctx, []*packet{
+ {
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Epoch: c.getLocalEpoch(),
+ Version: protocol.Version1_2,
+ },
+ Content: &alert.Alert{
+ Level: level,
+ Description: desc,
+ },
+ },
+ shouldEncrypt: c.isHandshakeCompletedSuccessfully(),
+ },
+ })
+}
+
+func (c *Conn) setHandshakeCompletedSuccessfully() {
+ c.handshakeCompletedSuccessfully.Store(struct{ bool }{true})
+}
+
+func (c *Conn) isHandshakeCompletedSuccessfully() bool {
+ boolean, _ := c.handshakeCompletedSuccessfully.Load().(struct{ bool })
+ return boolean.bool
+}
+
+func (c *Conn) handshake(ctx context.Context, cfg *handshakeConfig, initialFlight flightVal, initialState handshakeState) error { //nolint:gocognit
+ c.fsm = newHandshakeFSM(&c.state, c.handshakeCache, cfg, initialFlight)
+
+ done := make(chan struct{})
+ ctxRead, cancelRead := context.WithCancel(context.Background())
+ c.cancelHandshakeReader = cancelRead
+ cfg.onFlightState = func(f flightVal, s handshakeState) {
+ if s == handshakeFinished && !c.isHandshakeCompletedSuccessfully() {
+ c.setHandshakeCompletedSuccessfully()
+ close(done)
+ }
+ }
+
+ ctxHs, cancel := context.WithCancel(context.Background())
+ c.cancelHandshaker = cancel
+
+ firstErr := make(chan error, 1)
+
+ c.handshakeLoopsFinished.Add(2)
+
+ // Handshake routine should be live until close.
+ // The other party may request retransmission of the last flight to cope with packet drop.
+ go func() {
+ defer c.handshakeLoopsFinished.Done()
+ err := c.fsm.Run(ctxHs, c, initialState)
+ if !errors.Is(err, context.Canceled) {
+ select {
+ case firstErr <- err:
+ default:
+ }
+ }
+ }()
+ go func() {
+ defer func() {
+ // Escaping read loop.
+ // It's safe to close decrypted channnel now.
+ close(c.decrypted)
+
+ // Force stop handshaker when the underlying connection is closed.
+ cancel()
+ }()
+ defer c.handshakeLoopsFinished.Done()
+ for {
+ if err := c.readAndBuffer(ctxRead); err != nil {
+ switch e := err.(type) {
+ case *errAlert:
+ if !e.IsFatalOrCloseNotify() {
+ if c.isHandshakeCompletedSuccessfully() {
+ // Pass the error to Read()
+ select {
+ case c.decrypted <- err:
+ case <-c.closed.Done():
+ }
+ }
+ continue // non-fatal alert must not stop read loop
+ }
+ case error:
+ switch err {
+ case context.DeadlineExceeded, context.Canceled, io.EOF:
+ default:
+ if c.isHandshakeCompletedSuccessfully() {
+ // Keep read loop and pass the read error to Read()
+ select {
+ case c.decrypted <- err:
+ case <-c.closed.Done():
+ }
+ continue // non-fatal alert must not stop read loop
+ }
+ }
+ }
+ select {
+ case firstErr <- err:
+ default:
+ }
+
+ if e, ok := err.(*errAlert); ok {
+ if e.IsFatalOrCloseNotify() {
+ _ = c.close(false)
+ }
+ }
+ return
+ }
+ }
+ }()
+
+ select {
+ case err := <-firstErr:
+ cancelRead()
+ cancel()
+ return c.translateHandshakeCtxError(err)
+ case <-ctx.Done():
+ cancelRead()
+ cancel()
+ return c.translateHandshakeCtxError(ctx.Err())
+ case <-done:
+ return nil
+ }
+}
+
+func (c *Conn) translateHandshakeCtxError(err error) error {
+ if err == nil {
+ return nil
+ }
+ if errors.Is(err, context.Canceled) && c.isHandshakeCompletedSuccessfully() {
+ return nil
+ }
+ return &HandshakeError{Err: err}
+}
+
+func (c *Conn) close(byUser bool) error {
+ c.cancelHandshaker()
+ c.cancelHandshakeReader()
+
+ if c.isHandshakeCompletedSuccessfully() && byUser {
+ // Discard error from notify() to return non-error on the first user call of Close()
+ // even if the underlying connection is already closed.
+ _ = c.notify(context.Background(), alert.Warning, alert.CloseNotify)
+ }
+
+ c.closeLock.Lock()
+ // Don't return ErrConnClosed at the first time of the call from user.
+ closedByUser := c.connectionClosedByUser
+ if byUser {
+ c.connectionClosedByUser = true
+ }
+ c.closed.Close()
+ c.closeLock.Unlock()
+
+ if closedByUser {
+ return ErrConnClosed
+ }
+
+ return c.nextConn.Close()
+}
+
+func (c *Conn) isConnectionClosed() bool {
+ select {
+ case <-c.closed.Done():
+ return true
+ default:
+ return false
+ }
+}
+
+func (c *Conn) setLocalEpoch(epoch uint16) {
+ c.state.localEpoch.Store(epoch)
+}
+
+func (c *Conn) getLocalEpoch() uint16 {
+ return c.state.localEpoch.Load().(uint16)
+}
+
+func (c *Conn) setRemoteEpoch(epoch uint16) {
+ c.state.remoteEpoch.Store(epoch)
+}
+
+func (c *Conn) getRemoteEpoch() uint16 {
+ return c.state.remoteEpoch.Load().(uint16)
+}
+
+// LocalAddr implements net.Conn.LocalAddr
+func (c *Conn) LocalAddr() net.Addr {
+ return c.nextConn.LocalAddr()
+}
+
+// RemoteAddr implements net.Conn.RemoteAddr
+func (c *Conn) RemoteAddr() net.Addr {
+ return c.nextConn.RemoteAddr()
+}
+
+// SetDeadline implements net.Conn.SetDeadline
+func (c *Conn) SetDeadline(t time.Time) error {
+ c.readDeadline.Set(t)
+ return c.SetWriteDeadline(t)
+}
+
+// SetReadDeadline implements net.Conn.SetReadDeadline
+func (c *Conn) SetReadDeadline(t time.Time) error {
+ c.readDeadline.Set(t)
+ // Read deadline is fully managed by this layer.
+ // Don't set read deadline to underlying connection.
+ return nil
+}
+
+// SetWriteDeadline implements net.Conn.SetWriteDeadline
+func (c *Conn) SetWriteDeadline(t time.Time) error {
+ c.writeDeadline.Set(t)
+ // Write deadline is also fully managed by this layer.
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/crypto.go b/vendor/github.com/pion/dtls/v2/crypto.go
new file mode 100644
index 0000000..768ee47
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/crypto.go
@@ -0,0 +1,221 @@
+package dtls
+
+import (
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/sha256"
+ "crypto/x509"
+ "encoding/asn1"
+ "encoding/binary"
+ "math/big"
+ "time"
+
+ "github.com/pion/dtls/v2/pkg/crypto/elliptic"
+ "github.com/pion/dtls/v2/pkg/crypto/hash"
+)
+
+type ecdsaSignature struct {
+ R, S *big.Int
+}
+
+func valueKeyMessage(clientRandom, serverRandom, publicKey []byte, namedCurve elliptic.Curve) []byte {
+ serverECDHParams := make([]byte, 4)
+ serverECDHParams[0] = 3 // named curve
+ binary.BigEndian.PutUint16(serverECDHParams[1:], uint16(namedCurve))
+ serverECDHParams[3] = byte(len(publicKey))
+
+ plaintext := []byte{}
+ plaintext = append(plaintext, clientRandom...)
+ plaintext = append(plaintext, serverRandom...)
+ plaintext = append(plaintext, serverECDHParams...)
+ plaintext = append(plaintext, publicKey...)
+
+ return plaintext
+}
+
+// If the client provided a "signature_algorithms" extension, then all
+// certificates provided by the server MUST be signed by a
+// hash/signature algorithm pair that appears in that extension
+//
+// https://tools.ietf.org/html/rfc5246#section-7.4.2
+func generateKeySignature(clientRandom, serverRandom, publicKey []byte, namedCurve elliptic.Curve, privateKey crypto.PrivateKey, hashAlgorithm hash.Algorithm) ([]byte, error) {
+ msg := valueKeyMessage(clientRandom, serverRandom, publicKey, namedCurve)
+ switch p := privateKey.(type) {
+ case ed25519.PrivateKey:
+ // https://crypto.stackexchange.com/a/55483
+ return p.Sign(rand.Reader, msg, crypto.Hash(0))
+ case *ecdsa.PrivateKey:
+ hashed := hashAlgorithm.Digest(msg)
+ return p.Sign(rand.Reader, hashed, hashAlgorithm.CryptoHash())
+ case *rsa.PrivateKey:
+ hashed := hashAlgorithm.Digest(msg)
+ return p.Sign(rand.Reader, hashed, hashAlgorithm.CryptoHash())
+ }
+
+ return nil, errKeySignatureGenerateUnimplemented
+}
+
+func verifyKeySignature(message, remoteKeySignature []byte, hashAlgorithm hash.Algorithm, rawCertificates [][]byte) error { //nolint:dupl
+ if len(rawCertificates) == 0 {
+ return errLengthMismatch
+ }
+ certificate, err := x509.ParseCertificate(rawCertificates[0])
+ if err != nil {
+ return err
+ }
+
+ switch p := certificate.PublicKey.(type) {
+ case ed25519.PublicKey:
+ if ok := ed25519.Verify(p, message, remoteKeySignature); !ok {
+ return errKeySignatureMismatch
+ }
+ return nil
+ case *ecdsa.PublicKey:
+ ecdsaSig := &ecdsaSignature{}
+ if _, err := asn1.Unmarshal(remoteKeySignature, ecdsaSig); err != nil {
+ return err
+ }
+ if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
+ return errInvalidECDSASignature
+ }
+ hashed := hashAlgorithm.Digest(message)
+ if !ecdsa.Verify(p, hashed, ecdsaSig.R, ecdsaSig.S) {
+ return errKeySignatureMismatch
+ }
+ return nil
+ case *rsa.PublicKey:
+ switch certificate.SignatureAlgorithm {
+ case x509.SHA1WithRSA, x509.SHA256WithRSA, x509.SHA384WithRSA, x509.SHA512WithRSA:
+ hashed := hashAlgorithm.Digest(message)
+ return rsa.VerifyPKCS1v15(p, hashAlgorithm.CryptoHash(), hashed, remoteKeySignature)
+ default:
+ return errKeySignatureVerifyUnimplemented
+ }
+ }
+
+ return errKeySignatureVerifyUnimplemented
+}
+
+// If the server has sent a CertificateRequest message, the client MUST send the Certificate
+// message. The ClientKeyExchange message is now sent, and the content
+// of that message will depend on the public key algorithm selected
+// between the ClientHello and the ServerHello. If the client has sent
+// a certificate with signing ability, a digitally-signed
+// CertificateVerify message is sent to explicitly verify possession of
+// the private key in the certificate.
+// https://tools.ietf.org/html/rfc5246#section-7.3
+func generateCertificateVerify(handshakeBodies []byte, privateKey crypto.PrivateKey, hashAlgorithm hash.Algorithm) ([]byte, error) {
+ h := sha256.New()
+ if _, err := h.Write(handshakeBodies); err != nil {
+ return nil, err
+ }
+ hashed := h.Sum(nil)
+
+ switch p := privateKey.(type) {
+ case ed25519.PrivateKey:
+ // https://crypto.stackexchange.com/a/55483
+ return p.Sign(rand.Reader, hashed, crypto.Hash(0))
+ case *ecdsa.PrivateKey:
+ return p.Sign(rand.Reader, hashed, hashAlgorithm.CryptoHash())
+ case *rsa.PrivateKey:
+ return p.Sign(rand.Reader, hashed, hashAlgorithm.CryptoHash())
+ }
+
+ return nil, errInvalidSignatureAlgorithm
+}
+
+func verifyCertificateVerify(handshakeBodies []byte, hashAlgorithm hash.Algorithm, remoteKeySignature []byte, rawCertificates [][]byte) error { //nolint:dupl
+ if len(rawCertificates) == 0 {
+ return errLengthMismatch
+ }
+ certificate, err := x509.ParseCertificate(rawCertificates[0])
+ if err != nil {
+ return err
+ }
+
+ switch p := certificate.PublicKey.(type) {
+ case ed25519.PublicKey:
+ if ok := ed25519.Verify(p, handshakeBodies, remoteKeySignature); !ok {
+ return errKeySignatureMismatch
+ }
+ return nil
+ case *ecdsa.PublicKey:
+ ecdsaSig := &ecdsaSignature{}
+ if _, err := asn1.Unmarshal(remoteKeySignature, ecdsaSig); err != nil {
+ return err
+ }
+ if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
+ return errInvalidECDSASignature
+ }
+ hash := hashAlgorithm.Digest(handshakeBodies)
+ if !ecdsa.Verify(p, hash, ecdsaSig.R, ecdsaSig.S) {
+ return errKeySignatureMismatch
+ }
+ return nil
+ case *rsa.PublicKey:
+ switch certificate.SignatureAlgorithm {
+ case x509.SHA1WithRSA, x509.SHA256WithRSA, x509.SHA384WithRSA, x509.SHA512WithRSA:
+ hash := hashAlgorithm.Digest(handshakeBodies)
+ return rsa.VerifyPKCS1v15(p, hashAlgorithm.CryptoHash(), hash, remoteKeySignature)
+ default:
+ return errKeySignatureVerifyUnimplemented
+ }
+ }
+
+ return errKeySignatureVerifyUnimplemented
+}
+
+func loadCerts(rawCertificates [][]byte) ([]*x509.Certificate, error) {
+ if len(rawCertificates) == 0 {
+ return nil, errLengthMismatch
+ }
+
+ certs := make([]*x509.Certificate, 0, len(rawCertificates))
+ for _, rawCert := range rawCertificates {
+ cert, err := x509.ParseCertificate(rawCert)
+ if err != nil {
+ return nil, err
+ }
+ certs = append(certs, cert)
+ }
+ return certs, nil
+}
+
+func verifyClientCert(rawCertificates [][]byte, roots *x509.CertPool) (chains [][]*x509.Certificate, err error) {
+ certificate, err := loadCerts(rawCertificates)
+ if err != nil {
+ return nil, err
+ }
+ intermediateCAPool := x509.NewCertPool()
+ for _, cert := range certificate[1:] {
+ intermediateCAPool.AddCert(cert)
+ }
+ opts := x509.VerifyOptions{
+ Roots: roots,
+ CurrentTime: time.Now(),
+ Intermediates: intermediateCAPool,
+ KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
+ }
+ return certificate[0].Verify(opts)
+}
+
+func verifyServerCert(rawCertificates [][]byte, roots *x509.CertPool, serverName string) (chains [][]*x509.Certificate, err error) {
+ certificate, err := loadCerts(rawCertificates)
+ if err != nil {
+ return nil, err
+ }
+ intermediateCAPool := x509.NewCertPool()
+ for _, cert := range certificate[1:] {
+ intermediateCAPool.AddCert(cert)
+ }
+ opts := x509.VerifyOptions{
+ Roots: roots,
+ CurrentTime: time.Now(),
+ DNSName: serverName,
+ Intermediates: intermediateCAPool,
+ }
+ return certificate[0].Verify(opts)
+}
diff --git a/vendor/github.com/pion/dtls/v2/dtls.go b/vendor/github.com/pion/dtls/v2/dtls.go
new file mode 100644
index 0000000..125b904
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/dtls.go
@@ -0,0 +1,2 @@
+// Package dtls implements Datagram Transport Layer Security (DTLS) 1.2
+package dtls
diff --git a/vendor/github.com/pion/dtls/v2/errors.go b/vendor/github.com/pion/dtls/v2/errors.go
new file mode 100644
index 0000000..2e16388
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/errors.go
@@ -0,0 +1,141 @@
+package dtls
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "os"
+
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/alert"
+ "golang.org/x/xerrors"
+)
+
+// Typed errors
+var (
+ ErrConnClosed = &FatalError{Err: errors.New("conn is closed")} //nolint:goerr113
+
+ errDeadlineExceeded = &TimeoutError{Err: xerrors.Errorf("read/write timeout: %w", context.DeadlineExceeded)}
+ errInvalidContentType = &TemporaryError{Err: errors.New("invalid content type")} //nolint:goerr113
+
+ errBufferTooSmall = &TemporaryError{Err: errors.New("buffer is too small")} //nolint:goerr113
+ errContextUnsupported = &TemporaryError{Err: errors.New("context is not supported for ExportKeyingMaterial")} //nolint:goerr113
+ errHandshakeInProgress = &TemporaryError{Err: errors.New("handshake is in progress")} //nolint:goerr113
+ errReservedExportKeyingMaterial = &TemporaryError{Err: errors.New("ExportKeyingMaterial can not be used with a reserved label")} //nolint:goerr113
+ errApplicationDataEpochZero = &TemporaryError{Err: errors.New("ApplicationData with epoch of 0")} //nolint:goerr113
+ errUnhandledContextType = &TemporaryError{Err: errors.New("unhandled contentType")} //nolint:goerr113
+
+ errCertificateVerifyNoCertificate = &FatalError{Err: errors.New("client sent certificate verify but we have no certificate to verify")} //nolint:goerr113
+ errCipherSuiteNoIntersection = &FatalError{Err: errors.New("client+server do not support any shared cipher suites")} //nolint:goerr113
+ errClientCertificateNotVerified = &FatalError{Err: errors.New("client sent certificate but did not verify it")} //nolint:goerr113
+ errClientCertificateRequired = &FatalError{Err: errors.New("server required client verification, but got none")} //nolint:goerr113
+ errClientNoMatchingSRTPProfile = &FatalError{Err: errors.New("server responded with SRTP Profile we do not support")} //nolint:goerr113
+ errClientRequiredButNoServerEMS = &FatalError{Err: errors.New("client required Extended Master Secret extension, but server does not support it")} //nolint:goerr113
+ errCookieMismatch = &FatalError{Err: errors.New("client+server cookie does not match")} //nolint:goerr113
+ errIdentityNoPSK = &FatalError{Err: errors.New("PSK Identity Hint provided but PSK is nil")} //nolint:goerr113
+ errInvalidCertificate = &FatalError{Err: errors.New("no certificate provided")} //nolint:goerr113
+ errInvalidCipherSuite = &FatalError{Err: errors.New("invalid or unknown cipher suite")} //nolint:goerr113
+ errInvalidECDSASignature = &FatalError{Err: errors.New("ECDSA signature contained zero or negative values")} //nolint:goerr113
+ errInvalidPrivateKey = &FatalError{Err: errors.New("invalid private key type")} //nolint:goerr113
+ errInvalidSignatureAlgorithm = &FatalError{Err: errors.New("invalid signature algorithm")} //nolint:goerr113
+ errKeySignatureMismatch = &FatalError{Err: errors.New("expected and actual key signature do not match")} //nolint:goerr113
+ errNilNextConn = &FatalError{Err: errors.New("Conn can not be created with a nil nextConn")} //nolint:goerr113
+ errNoAvailableCipherSuites = &FatalError{Err: errors.New("connection can not be created, no CipherSuites satisfy this Config")} //nolint:goerr113
+ errNoAvailablePSKCipherSuite = &FatalError{Err: errors.New("connection can not be created, pre-shared key present but no compatible CipherSuite")} //nolint:goerr113
+ errNoAvailableCertificateCipherSuite = &FatalError{Err: errors.New("connection can not be created, certificate present but no compatible CipherSuite")} //nolint:goerr113
+ errNoAvailableSignatureSchemes = &FatalError{Err: errors.New("connection can not be created, no SignatureScheme satisfy this Config")} //nolint:goerr113
+ errNoCertificates = &FatalError{Err: errors.New("no certificates configured")} //nolint:goerr113
+ errNoConfigProvided = &FatalError{Err: errors.New("no config provided")} //nolint:goerr113
+ errNoSupportedEllipticCurves = &FatalError{Err: errors.New("client requested zero or more elliptic curves that are not supported by the server")} //nolint:goerr113
+ errUnsupportedProtocolVersion = &FatalError{Err: errors.New("unsupported protocol version")} //nolint:goerr113
+ errPSKAndIdentityMustBeSetForClient = &FatalError{Err: errors.New("PSK and PSK Identity Hint must both be set for client")} //nolint:goerr113
+ errRequestedButNoSRTPExtension = &FatalError{Err: errors.New("SRTP support was requested but server did not respond with use_srtp extension")} //nolint:goerr113
+ errServerNoMatchingSRTPProfile = &FatalError{Err: errors.New("client requested SRTP but we have no matching profiles")} //nolint:goerr113
+ errServerRequiredButNoClientEMS = &FatalError{Err: errors.New("server requires the Extended Master Secret extension, but the client does not support it")} //nolint:goerr113
+ errVerifyDataMismatch = &FatalError{Err: errors.New("expected and actual verify data does not match")} //nolint:goerr113
+
+ errInvalidFlight = &InternalError{Err: errors.New("invalid flight number")} //nolint:goerr113
+ errKeySignatureGenerateUnimplemented = &InternalError{Err: errors.New("unable to generate key signature, unimplemented")} //nolint:goerr113
+ errKeySignatureVerifyUnimplemented = &InternalError{Err: errors.New("unable to verify key signature, unimplemented")} //nolint:goerr113
+ errLengthMismatch = &InternalError{Err: errors.New("data length and declared length do not match")} //nolint:goerr113
+ errSequenceNumberOverflow = &InternalError{Err: errors.New("sequence number overflow")} //nolint:goerr113
+ errInvalidFSMTransition = &InternalError{Err: errors.New("invalid state machine transition")} //nolint:goerr113
+)
+
+// FatalError indicates that the DTLS connection is no longer available.
+// It is mainly caused by wrong configuration of server or client.
+type FatalError = protocol.FatalError
+
+// InternalError indicates and internal error caused by the implementation, and the DTLS connection is no longer available.
+// It is mainly caused by bugs or tried to use unimplemented features.
+type InternalError = protocol.InternalError
+
+// TemporaryError indicates that the DTLS connection is still available, but the request was failed temporary.
+type TemporaryError = protocol.TemporaryError
+
+// TimeoutError indicates that the request was timed out.
+type TimeoutError = protocol.TimeoutError
+
+// HandshakeError indicates that the handshake failed.
+type HandshakeError = protocol.HandshakeError
+
+// invalidCipherSuite indicates an attempt at using an unsupported cipher suite.
+type invalidCipherSuite struct {
+ id CipherSuiteID
+}
+
+func (e *invalidCipherSuite) Error() string {
+ return fmt.Sprintf("CipherSuite with id(%d) is not valid", e.id)
+}
+
+func (e *invalidCipherSuite) Is(err error) bool {
+ if other, ok := err.(*invalidCipherSuite); ok {
+ return e.id == other.id
+ }
+ return false
+}
+
+// errAlert wraps DTLS alert notification as an error
+type errAlert struct {
+ *alert.Alert
+}
+
+func (e *errAlert) Error() string {
+ return fmt.Sprintf("alert: %s", e.Alert.String())
+}
+
+func (e *errAlert) IsFatalOrCloseNotify() bool {
+ return e.Level == alert.Fatal || e.Description == alert.CloseNotify
+}
+
+func (e *errAlert) Is(err error) bool {
+ if other, ok := err.(*errAlert); ok {
+ return e.Level == other.Level && e.Description == other.Description
+ }
+ return false
+}
+
+// netError translates an error from underlying Conn to corresponding net.Error.
+func netError(err error) error {
+ switch err {
+ case io.EOF, context.Canceled, context.DeadlineExceeded:
+ // Return io.EOF and context errors as is.
+ return err
+ }
+ switch e := err.(type) {
+ case (*net.OpError):
+ if se, ok := e.Err.(*os.SyscallError); ok {
+ if se.Timeout() {
+ return &TimeoutError{Err: err}
+ }
+ if isOpErrorTemporary(se) {
+ return &TemporaryError{Err: err}
+ }
+ }
+ case (net.Error):
+ return err
+ }
+ return &FatalError{Err: err}
+}
diff --git a/vendor/github.com/pion/dtls/v2/errors_errno.go b/vendor/github.com/pion/dtls/v2/errors_errno.go
new file mode 100644
index 0000000..a9a439b
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/errors_errno.go
@@ -0,0 +1,25 @@
+// +build aix darwin dragonfly freebsd linux nacl nacljs netbsd openbsd solaris windows
+
+// For systems having syscall.Errno.
+// Update build targets by following command:
+// $ grep -R ECONN $(go env GOROOT)/src/syscall/zerrors_*.go \
+// | tr "." "_" | cut -d"_" -f"2" | sort | uniq
+
+package dtls
+
+import (
+ "os"
+ "syscall"
+)
+
+func isOpErrorTemporary(err *os.SyscallError) bool {
+ if ne, ok := err.Err.(syscall.Errno); ok {
+ switch ne {
+ case syscall.ECONNREFUSED:
+ return true
+ default:
+ return false
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/pion/dtls/v2/errors_noerrno.go b/vendor/github.com/pion/dtls/v2/errors_noerrno.go
new file mode 100644
index 0000000..fcc37ce
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/errors_noerrno.go
@@ -0,0 +1,14 @@
+// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!nacl,!nacljs,!netbsd,!openbsd,!solaris,!windows
+
+// For systems without syscall.Errno.
+// Build targets must be inverse of errors_errno.go
+
+package dtls
+
+import (
+ "os"
+)
+
+func isOpErrorTemporary(err *os.SyscallError) bool {
+ return false
+}
diff --git a/vendor/github.com/pion/dtls/v2/flight.go b/vendor/github.com/pion/dtls/v2/flight.go
new file mode 100644
index 0000000..580ee48
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/flight.go
@@ -0,0 +1,75 @@
+package dtls
+
+/*
+ DTLS messages are grouped into a series of message flights, according
+ to the diagrams below. Although each flight of messages may consist
+ of a number of messages, they should be viewed as monolithic for the
+ purpose of timeout and retransmission.
+ https://tools.ietf.org/html/rfc4347#section-4.2.4
+ Client Server
+ ------ ------
+ Waiting Flight 0
+
+ ClientHello --------> Flight 1
+
+ <------- HelloVerifyRequest Flight 2
+
+ ClientHello --------> Flight 3
+
+ ServerHello \
+ Certificate* \
+ ServerKeyExchange* Flight 4
+ CertificateRequest* /
+ <-------- ServerHelloDone /
+
+ Certificate* \
+ ClientKeyExchange \
+ CertificateVerify* Flight 5
+ [ChangeCipherSpec] /
+ Finished --------> /
+
+ [ChangeCipherSpec] \ Flight 6
+ <-------- Finished /
+
+*/
+
+type flightVal uint8
+
+const (
+ flight0 flightVal = iota + 1
+ flight1
+ flight2
+ flight3
+ flight4
+ flight5
+ flight6
+)
+
+func (f flightVal) String() string {
+ switch f {
+ case flight0:
+ return "Flight 0"
+ case flight1:
+ return "Flight 1"
+ case flight2:
+ return "Flight 2"
+ case flight3:
+ return "Flight 3"
+ case flight4:
+ return "Flight 4"
+ case flight5:
+ return "Flight 5"
+ case flight6:
+ return "Flight 6"
+ default:
+ return "Invalid Flight"
+ }
+}
+
+func (f flightVal) isLastSendFlight() bool {
+ return f == flight6
+}
+
+func (f flightVal) isLastRecvFlight() bool {
+ return f == flight5
+}
diff --git a/vendor/github.com/pion/dtls/v2/flight0handler.go b/vendor/github.com/pion/dtls/v2/flight0handler.go
new file mode 100644
index 0000000..949d7c0
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/flight0handler.go
@@ -0,0 +1,102 @@
+package dtls
+
+import (
+ "context"
+ "crypto/rand"
+
+ "github.com/pion/dtls/v2/pkg/crypto/elliptic"
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/alert"
+ "github.com/pion/dtls/v2/pkg/protocol/extension"
+ "github.com/pion/dtls/v2/pkg/protocol/handshake"
+)
+
+func flight0Parse(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) {
+ seq, msgs, ok := cache.fullPullMap(0,
+ handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
+ )
+ if !ok {
+ // No valid message received. Keep reading
+ return 0, nil, nil
+ }
+ state.handshakeRecvSequence = seq
+
+ var clientHello *handshake.MessageClientHello
+
+ // Validate type
+ if clientHello, ok = msgs[handshake.TypeClientHello].(*handshake.MessageClientHello); !ok {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
+ }
+
+ if !clientHello.Version.Equal(protocol.Version1_2) {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.ProtocolVersion}, errUnsupportedProtocolVersion
+ }
+
+ state.remoteRandom = clientHello.Random
+
+ cipherSuites := []CipherSuite{}
+ for _, id := range clientHello.CipherSuiteIDs {
+ if c := cipherSuiteForID(CipherSuiteID(id), cfg.customCipherSuites); c != nil {
+ cipherSuites = append(cipherSuites, c)
+ }
+ }
+
+ if state.cipherSuite, ok = findMatchingCipherSuite(cipherSuites, cfg.localCipherSuites); !ok {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errCipherSuiteNoIntersection
+ }
+
+ for _, val := range clientHello.Extensions {
+ switch e := val.(type) {
+ case *extension.SupportedEllipticCurves:
+ if len(e.EllipticCurves) == 0 {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errNoSupportedEllipticCurves
+ }
+ state.namedCurve = e.EllipticCurves[0]
+ case *extension.UseSRTP:
+ profile, ok := findMatchingSRTPProfile(e.ProtectionProfiles, cfg.localSRTPProtectionProfiles)
+ if !ok {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errServerNoMatchingSRTPProfile
+ }
+ state.srtpProtectionProfile = profile
+ case *extension.UseExtendedMasterSecret:
+ if cfg.extendedMasterSecret != DisableExtendedMasterSecret {
+ state.extendedMasterSecret = true
+ }
+ case *extension.ServerName:
+ state.serverName = e.ServerName // remote server name
+ }
+ }
+
+ if cfg.extendedMasterSecret == RequireExtendedMasterSecret && !state.extendedMasterSecret {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errServerRequiredButNoClientEMS
+ }
+
+ if state.localKeypair == nil {
+ var err error
+ state.localKeypair, err = elliptic.GenerateKeypair(state.namedCurve)
+ if err != nil {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.IllegalParameter}, err
+ }
+ }
+
+ return flight2, nil, nil
+}
+
+func flight0Generate(c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) {
+ // Initialize
+ state.cookie = make([]byte, cookieLength)
+ if _, err := rand.Read(state.cookie); err != nil {
+ return nil, nil, err
+ }
+
+ var zeroEpoch uint16
+ state.localEpoch.Store(zeroEpoch)
+ state.remoteEpoch.Store(zeroEpoch)
+ state.namedCurve = defaultNamedCurve
+
+ if err := state.localRandom.Populate(); err != nil {
+ return nil, nil, err
+ }
+
+ return nil, nil, nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/flight1handler.go b/vendor/github.com/pion/dtls/v2/flight1handler.go
new file mode 100644
index 0000000..9229292
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/flight1handler.go
@@ -0,0 +1,112 @@
+package dtls
+
+import (
+ "context"
+
+ "github.com/pion/dtls/v2/pkg/crypto/elliptic"
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/alert"
+ "github.com/pion/dtls/v2/pkg/protocol/extension"
+ "github.com/pion/dtls/v2/pkg/protocol/handshake"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+)
+
+func flight1Parse(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) {
+ // HelloVerifyRequest can be skipped by the server,
+ // so allow ServerHello during flight1 also
+ seq, msgs, ok := cache.fullPullMap(state.handshakeRecvSequence,
+ handshakeCachePullRule{handshake.TypeHelloVerifyRequest, cfg.initialEpoch, false, true},
+ handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, true},
+ )
+ if !ok {
+ // No valid message received. Keep reading
+ return 0, nil, nil
+ }
+
+ if _, ok := msgs[handshake.TypeServerHello]; ok {
+ // Flight1 and flight2 were skipped.
+ // Parse as flight3.
+ return flight3Parse(ctx, c, state, cache, cfg)
+ }
+
+ if h, ok := msgs[handshake.TypeHelloVerifyRequest].(*handshake.MessageHelloVerifyRequest); ok {
+ // DTLS 1.2 clients must not assume that the server will use the protocol version
+ // specified in HelloVerifyRequest message. RFC 6347 Section 4.2.1
+ if !h.Version.Equal(protocol.Version1_0) && !h.Version.Equal(protocol.Version1_2) {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.ProtocolVersion}, errUnsupportedProtocolVersion
+ }
+ state.cookie = append([]byte{}, h.Cookie...)
+ state.handshakeRecvSequence = seq
+ return flight3, nil, nil
+ }
+
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
+}
+
+func flight1Generate(c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) {
+ var zeroEpoch uint16
+ state.localEpoch.Store(zeroEpoch)
+ state.remoteEpoch.Store(zeroEpoch)
+ state.namedCurve = defaultNamedCurve
+ state.cookie = nil
+
+ if err := state.localRandom.Populate(); err != nil {
+ return nil, nil, err
+ }
+
+ extensions := []extension.Extension{
+ &extension.SupportedSignatureAlgorithms{
+ SignatureHashAlgorithms: cfg.localSignatureSchemes,
+ },
+ &extension.RenegotiationInfo{
+ RenegotiatedConnection: 0,
+ },
+ }
+ if cfg.localPSKCallback == nil {
+ extensions = append(extensions, []extension.Extension{
+ &extension.SupportedEllipticCurves{
+ EllipticCurves: []elliptic.Curve{elliptic.X25519, elliptic.P256, elliptic.P384},
+ },
+ &extension.SupportedPointFormats{
+ PointFormats: []elliptic.CurvePointFormat{elliptic.CurvePointFormatUncompressed},
+ },
+ }...)
+ }
+
+ if len(cfg.localSRTPProtectionProfiles) > 0 {
+ extensions = append(extensions, &extension.UseSRTP{
+ ProtectionProfiles: cfg.localSRTPProtectionProfiles,
+ })
+ }
+
+ if cfg.extendedMasterSecret == RequestExtendedMasterSecret ||
+ cfg.extendedMasterSecret == RequireExtendedMasterSecret {
+ extensions = append(extensions, &extension.UseExtendedMasterSecret{
+ Supported: true,
+ })
+ }
+
+ if len(cfg.serverName) > 0 {
+ extensions = append(extensions, &extension.ServerName{ServerName: cfg.serverName})
+ }
+
+ return []*packet{
+ {
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Version: protocol.Version1_2,
+ },
+ Content: &handshake.Handshake{
+ Message: &handshake.MessageClientHello{
+ Version: protocol.Version1_2,
+ Cookie: state.cookie,
+ Random: state.localRandom,
+ CipherSuiteIDs: cipherSuiteIDs(cfg.localCipherSuites),
+ CompressionMethods: defaultCompressionMethods(),
+ Extensions: extensions,
+ },
+ },
+ },
+ },
+ }, nil, nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/flight2handler.go b/vendor/github.com/pion/dtls/v2/flight2handler.go
new file mode 100644
index 0000000..bb8e91d
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/flight2handler.go
@@ -0,0 +1,61 @@
+package dtls
+
+import (
+ "bytes"
+ "context"
+
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/alert"
+ "github.com/pion/dtls/v2/pkg/protocol/handshake"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+)
+
+func flight2Parse(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) {
+ seq, msgs, ok := cache.fullPullMap(state.handshakeRecvSequence,
+ handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
+ )
+ if !ok {
+ // Client may retransmit the first ClientHello when HelloVerifyRequest is dropped.
+ // Parse as flight 0 in this case.
+ return flight0Parse(ctx, c, state, cache, cfg)
+ }
+ state.handshakeRecvSequence = seq
+
+ var clientHello *handshake.MessageClientHello
+
+ // Validate type
+ if clientHello, ok = msgs[handshake.TypeClientHello].(*handshake.MessageClientHello); !ok {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
+ }
+
+ if !clientHello.Version.Equal(protocol.Version1_2) {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.ProtocolVersion}, errUnsupportedProtocolVersion
+ }
+
+ if len(clientHello.Cookie) == 0 {
+ return 0, nil, nil
+ }
+ if !bytes.Equal(state.cookie, clientHello.Cookie) {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.AccessDenied}, errCookieMismatch
+ }
+ return flight4, nil, nil
+}
+
+func flight2Generate(c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) {
+ state.handshakeSendSequence = 0
+ return []*packet{
+ {
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Version: protocol.Version1_2,
+ },
+ Content: &handshake.Handshake{
+ Message: &handshake.MessageHelloVerifyRequest{
+ Version: protocol.Version1_2,
+ Cookie: state.cookie,
+ },
+ },
+ },
+ },
+ }, nil, nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/flight3handler.go b/vendor/github.com/pion/dtls/v2/flight3handler.go
new file mode 100644
index 0000000..f953be8
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/flight3handler.go
@@ -0,0 +1,194 @@
+package dtls
+
+import (
+ "context"
+
+ "github.com/pion/dtls/v2/pkg/crypto/elliptic"
+ "github.com/pion/dtls/v2/pkg/crypto/prf"
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/alert"
+ "github.com/pion/dtls/v2/pkg/protocol/extension"
+ "github.com/pion/dtls/v2/pkg/protocol/handshake"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+)
+
+func flight3Parse(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) { //nolint:gocognit
+ // Clients may receive multiple HelloVerifyRequest messages with different cookies.
+ // Clients SHOULD handle this by sending a new ClientHello with a cookie in response
+ // to the new HelloVerifyRequest. RFC 6347 Section 4.2.1
+ seq, msgs, ok := cache.fullPullMap(state.handshakeRecvSequence,
+ handshakeCachePullRule{handshake.TypeHelloVerifyRequest, cfg.initialEpoch, false, true},
+ )
+ if ok {
+ if h, msgOk := msgs[handshake.TypeHelloVerifyRequest].(*handshake.MessageHelloVerifyRequest); msgOk {
+ // DTLS 1.2 clients must not assume that the server will use the protocol version
+ // specified in HelloVerifyRequest message. RFC 6347 Section 4.2.1
+ if !h.Version.Equal(protocol.Version1_0) && !h.Version.Equal(protocol.Version1_2) {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.ProtocolVersion}, errUnsupportedProtocolVersion
+ }
+ state.cookie = append([]byte{}, h.Cookie...)
+ state.handshakeRecvSequence = seq
+ return flight3, nil, nil
+ }
+ }
+
+ if cfg.localPSKCallback != nil {
+ seq, msgs, ok = cache.fullPullMap(state.handshakeRecvSequence,
+ handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, true},
+ handshakeCachePullRule{handshake.TypeServerHelloDone, cfg.initialEpoch, false, false},
+ )
+ } else {
+ seq, msgs, ok = cache.fullPullMap(state.handshakeRecvSequence,
+ handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, false, true},
+ handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificateRequest, cfg.initialEpoch, false, true},
+ handshakeCachePullRule{handshake.TypeServerHelloDone, cfg.initialEpoch, false, false},
+ )
+ }
+ if !ok {
+ // Don't have enough messages. Keep reading
+ return 0, nil, nil
+ }
+ state.handshakeRecvSequence = seq
+
+ if h, ok := msgs[handshake.TypeServerHello].(*handshake.MessageServerHello); ok {
+ if !h.Version.Equal(protocol.Version1_2) {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.ProtocolVersion}, errUnsupportedProtocolVersion
+ }
+ for _, v := range h.Extensions {
+ switch e := v.(type) {
+ case *extension.UseSRTP:
+ profile, ok := findMatchingSRTPProfile(e.ProtectionProfiles, cfg.localSRTPProtectionProfiles)
+ if !ok {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.IllegalParameter}, errClientNoMatchingSRTPProfile
+ }
+ state.srtpProtectionProfile = profile
+ case *extension.UseExtendedMasterSecret:
+ if cfg.extendedMasterSecret != DisableExtendedMasterSecret {
+ state.extendedMasterSecret = true
+ }
+ }
+ }
+ if cfg.extendedMasterSecret == RequireExtendedMasterSecret && !state.extendedMasterSecret {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errClientRequiredButNoServerEMS
+ }
+ if len(cfg.localSRTPProtectionProfiles) > 0 && state.srtpProtectionProfile == 0 {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errRequestedButNoSRTPExtension
+ }
+
+ remoteCipherSuite := cipherSuiteForID(CipherSuiteID(*h.CipherSuiteID), cfg.customCipherSuites)
+ if remoteCipherSuite == nil {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errCipherSuiteNoIntersection
+ }
+
+ selectedCipherSuite, ok := findMatchingCipherSuite([]CipherSuite{remoteCipherSuite}, cfg.localCipherSuites)
+ if !ok {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errInvalidCipherSuite
+ }
+
+ state.cipherSuite = selectedCipherSuite
+ state.remoteRandom = h.Random
+ cfg.log.Tracef("[handshake] use cipher suite: %s", selectedCipherSuite.String())
+ }
+
+ if h, ok := msgs[handshake.TypeCertificate].(*handshake.MessageCertificate); ok {
+ state.PeerCertificates = h.Certificate
+ } else if state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypeCertificate {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.NoCertificate}, errInvalidCertificate
+ }
+
+ if h, ok := msgs[handshake.TypeServerKeyExchange].(*handshake.MessageServerKeyExchange); ok {
+ alertPtr, err := handleServerKeyExchange(c, state, cfg, h)
+ if err != nil {
+ return 0, alertPtr, err
+ }
+ }
+
+ if _, ok := msgs[handshake.TypeCertificateRequest].(*handshake.MessageCertificateRequest); ok {
+ state.remoteRequestedCertificate = true
+ }
+
+ return flight5, nil, nil
+}
+
+func handleServerKeyExchange(_ flightConn, state *State, cfg *handshakeConfig, h *handshake.MessageServerKeyExchange) (*alert.Alert, error) {
+ var err error
+ if cfg.localPSKCallback != nil {
+ var psk []byte
+ if psk, err = cfg.localPSKCallback(h.IdentityHint); err != nil {
+ return &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+ state.IdentityHint = h.IdentityHint
+ state.preMasterSecret = prf.PSKPreMasterSecret(psk)
+ } else {
+ if state.localKeypair, err = elliptic.GenerateKeypair(h.NamedCurve); err != nil {
+ return &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+
+ if state.preMasterSecret, err = prf.PreMasterSecret(h.PublicKey, state.localKeypair.PrivateKey, state.localKeypair.Curve); err != nil {
+ return &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+ }
+
+ return nil, nil
+}
+
+func flight3Generate(c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) {
+ extensions := []extension.Extension{
+ &extension.SupportedSignatureAlgorithms{
+ SignatureHashAlgorithms: cfg.localSignatureSchemes,
+ },
+ &extension.RenegotiationInfo{
+ RenegotiatedConnection: 0,
+ },
+ }
+ if cfg.localPSKCallback == nil {
+ extensions = append(extensions, []extension.Extension{
+ &extension.SupportedEllipticCurves{
+ EllipticCurves: []elliptic.Curve{elliptic.X25519, elliptic.P256, elliptic.P384},
+ },
+ &extension.SupportedPointFormats{
+ PointFormats: []elliptic.CurvePointFormat{elliptic.CurvePointFormatUncompressed},
+ },
+ }...)
+ }
+
+ if len(cfg.localSRTPProtectionProfiles) > 0 {
+ extensions = append(extensions, &extension.UseSRTP{
+ ProtectionProfiles: cfg.localSRTPProtectionProfiles,
+ })
+ }
+
+ if cfg.extendedMasterSecret == RequestExtendedMasterSecret ||
+ cfg.extendedMasterSecret == RequireExtendedMasterSecret {
+ extensions = append(extensions, &extension.UseExtendedMasterSecret{
+ Supported: true,
+ })
+ }
+
+ if len(cfg.serverName) > 0 {
+ extensions = append(extensions, &extension.ServerName{ServerName: cfg.serverName})
+ }
+
+ return []*packet{
+ {
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Version: protocol.Version1_2,
+ },
+ Content: &handshake.Handshake{
+ Message: &handshake.MessageClientHello{
+ Version: protocol.Version1_2,
+ Cookie: state.cookie,
+ Random: state.localRandom,
+ CipherSuiteIDs: cipherSuiteIDs(cfg.localCipherSuites),
+ CompressionMethods: defaultCompressionMethods(),
+ Extensions: extensions,
+ },
+ },
+ },
+ },
+ }, nil, nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/flight4handler.go b/vendor/github.com/pion/dtls/v2/flight4handler.go
new file mode 100644
index 0000000..d791c9d
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/flight4handler.go
@@ -0,0 +1,337 @@
+package dtls
+
+import (
+ "context"
+ "crypto/x509"
+
+ "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
+ "github.com/pion/dtls/v2/pkg/crypto/elliptic"
+ "github.com/pion/dtls/v2/pkg/crypto/prf"
+ "github.com/pion/dtls/v2/pkg/crypto/signaturehash"
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/alert"
+ "github.com/pion/dtls/v2/pkg/protocol/extension"
+ "github.com/pion/dtls/v2/pkg/protocol/handshake"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+)
+
+func flight4Parse(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) { //nolint:gocognit
+ seq, msgs, ok := cache.fullPullMap(state.handshakeRecvSequence,
+ handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, true, true},
+ handshakeCachePullRule{handshake.TypeClientKeyExchange, cfg.initialEpoch, true, false},
+ handshakeCachePullRule{handshake.TypeCertificateVerify, cfg.initialEpoch, true, true},
+ )
+ if !ok {
+ // No valid message received. Keep reading
+ return 0, nil, nil
+ }
+
+ // Validate type
+ var clientKeyExchange *handshake.MessageClientKeyExchange
+ if clientKeyExchange, ok = msgs[handshake.TypeClientKeyExchange].(*handshake.MessageClientKeyExchange); !ok {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
+ }
+
+ if h, hasCert := msgs[handshake.TypeCertificate].(*handshake.MessageCertificate); hasCert {
+ state.PeerCertificates = h.Certificate
+ }
+
+ if h, hasCertVerify := msgs[handshake.TypeCertificateVerify].(*handshake.MessageCertificateVerify); hasCertVerify {
+ if state.PeerCertificates == nil {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.NoCertificate}, errCertificateVerifyNoCertificate
+ }
+
+ plainText := cache.pullAndMerge(
+ handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
+ handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificateRequest, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeServerHelloDone, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, true, false},
+ handshakeCachePullRule{handshake.TypeClientKeyExchange, cfg.initialEpoch, true, false},
+ )
+
+ // Verify that the pair of hash algorithm and signiture is listed.
+ var validSignatureScheme bool
+ for _, ss := range cfg.localSignatureSchemes {
+ if ss.Hash == h.HashAlgorithm && ss.Signature == h.SignatureAlgorithm {
+ validSignatureScheme = true
+ break
+ }
+ }
+ if !validSignatureScheme {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errNoAvailableSignatureSchemes
+ }
+
+ if err := verifyCertificateVerify(plainText, h.HashAlgorithm, h.Signature, state.PeerCertificates); err != nil {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, err
+ }
+ var chains [][]*x509.Certificate
+ var err error
+ var verified bool
+ if cfg.clientAuth >= VerifyClientCertIfGiven {
+ if chains, err = verifyClientCert(state.PeerCertificates, cfg.clientCAs); err != nil {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, err
+ }
+ verified = true
+ }
+ if cfg.verifyPeerCertificate != nil {
+ if err := cfg.verifyPeerCertificate(state.PeerCertificates, chains); err != nil {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, err
+ }
+ }
+ state.peerCertificatesVerified = verified
+ }
+
+ if !state.cipherSuite.IsInitialized() {
+ serverRandom := state.localRandom.MarshalFixed()
+ clientRandom := state.remoteRandom.MarshalFixed()
+
+ var err error
+ var preMasterSecret []byte
+ if state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypePreSharedKey {
+ var psk []byte
+ if psk, err = cfg.localPSKCallback(clientKeyExchange.IdentityHint); err != nil {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+ state.IdentityHint = clientKeyExchange.IdentityHint
+ preMasterSecret = prf.PSKPreMasterSecret(psk)
+ } else {
+ preMasterSecret, err = prf.PreMasterSecret(clientKeyExchange.PublicKey, state.localKeypair.PrivateKey, state.localKeypair.Curve)
+ if err != nil {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.IllegalParameter}, err
+ }
+ }
+
+ if state.extendedMasterSecret {
+ var sessionHash []byte
+ sessionHash, err = cache.sessionHash(state.cipherSuite.HashFunc(), cfg.initialEpoch)
+ if err != nil {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+
+ state.masterSecret, err = prf.ExtendedMasterSecret(preMasterSecret, sessionHash, state.cipherSuite.HashFunc())
+ if err != nil {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+ } else {
+ state.masterSecret, err = prf.MasterSecret(preMasterSecret, clientRandom[:], serverRandom[:], state.cipherSuite.HashFunc())
+ if err != nil {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+ }
+
+ if err := state.cipherSuite.Init(state.masterSecret, clientRandom[:], serverRandom[:], false); err != nil {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+ cfg.writeKeyLog(keyLogLabelTLS12, clientRandom[:], state.masterSecret)
+ }
+
+ // Now, encrypted packets can be handled
+ if err := c.handleQueuedPackets(ctx); err != nil {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+
+ seq, msgs, ok = cache.fullPullMap(seq,
+ handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, true, false},
+ )
+ if !ok {
+ // No valid message received. Keep reading
+ return 0, nil, nil
+ }
+ state.handshakeRecvSequence = seq
+
+ if _, ok = msgs[handshake.TypeFinished].(*handshake.MessageFinished); !ok {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
+ }
+
+ if state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypeAnonymous {
+ return flight6, nil, nil
+ }
+
+ switch cfg.clientAuth {
+ case RequireAnyClientCert:
+ if state.PeerCertificates == nil {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.NoCertificate}, errClientCertificateRequired
+ }
+ case VerifyClientCertIfGiven:
+ if state.PeerCertificates != nil && !state.peerCertificatesVerified {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, errClientCertificateNotVerified
+ }
+ case RequireAndVerifyClientCert:
+ if state.PeerCertificates == nil {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.NoCertificate}, errClientCertificateRequired
+ }
+ if !state.peerCertificatesVerified {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, errClientCertificateNotVerified
+ }
+ case NoClientCert, RequestClientCert:
+ return flight6, nil, nil
+ }
+
+ return flight6, nil, nil
+}
+
+func flight4Generate(c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) {
+ extensions := []extension.Extension{&extension.RenegotiationInfo{
+ RenegotiatedConnection: 0,
+ }}
+ if (cfg.extendedMasterSecret == RequestExtendedMasterSecret ||
+ cfg.extendedMasterSecret == RequireExtendedMasterSecret) && state.extendedMasterSecret {
+ extensions = append(extensions, &extension.UseExtendedMasterSecret{
+ Supported: true,
+ })
+ }
+ if state.srtpProtectionProfile != 0 {
+ extensions = append(extensions, &extension.UseSRTP{
+ ProtectionProfiles: []SRTPProtectionProfile{state.srtpProtectionProfile},
+ })
+ }
+ if state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypeCertificate {
+ extensions = append(extensions, []extension.Extension{
+ &extension.SupportedEllipticCurves{
+ EllipticCurves: []elliptic.Curve{elliptic.X25519, elliptic.P256, elliptic.P384},
+ },
+ &extension.SupportedPointFormats{
+ PointFormats: []elliptic.CurvePointFormat{elliptic.CurvePointFormatUncompressed},
+ },
+ }...)
+ }
+
+ var pkts []*packet
+ cipherSuiteID := uint16(state.cipherSuite.ID())
+
+ pkts = append(pkts, &packet{
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Version: protocol.Version1_2,
+ },
+ Content: &handshake.Handshake{
+ Message: &handshake.MessageServerHello{
+ Version: protocol.Version1_2,
+ Random: state.localRandom,
+ CipherSuiteID: &cipherSuiteID,
+ CompressionMethod: defaultCompressionMethods()[0],
+ Extensions: extensions,
+ },
+ },
+ },
+ })
+
+ switch {
+ case state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypeCertificate:
+ certificate, err := cfg.getCertificate(cfg.serverName)
+ if err != nil {
+ return nil, &alert.Alert{Level: alert.Fatal, Description: alert.HandshakeFailure}, err
+ }
+
+ pkts = append(pkts, &packet{
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Version: protocol.Version1_2,
+ },
+ Content: &handshake.Handshake{
+ Message: &handshake.MessageCertificate{
+ Certificate: certificate.Certificate,
+ },
+ },
+ },
+ })
+
+ serverRandom := state.localRandom.MarshalFixed()
+ clientRandom := state.remoteRandom.MarshalFixed()
+
+ // Find compatible signature scheme
+ signatureHashAlgo, err := signaturehash.SelectSignatureScheme(cfg.localSignatureSchemes, certificate.PrivateKey)
+ if err != nil {
+ return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, err
+ }
+
+ signature, err := generateKeySignature(clientRandom[:], serverRandom[:], state.localKeypair.PublicKey, state.namedCurve, certificate.PrivateKey, signatureHashAlgo.Hash)
+ if err != nil {
+ return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+ state.localKeySignature = signature
+
+ pkts = append(pkts, &packet{
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Version: protocol.Version1_2,
+ },
+ Content: &handshake.Handshake{
+ Message: &handshake.MessageServerKeyExchange{
+ EllipticCurveType: elliptic.CurveTypeNamedCurve,
+ NamedCurve: state.namedCurve,
+ PublicKey: state.localKeypair.PublicKey,
+ HashAlgorithm: signatureHashAlgo.Hash,
+ SignatureAlgorithm: signatureHashAlgo.Signature,
+ Signature: state.localKeySignature,
+ },
+ },
+ },
+ })
+
+ if cfg.clientAuth > NoClientCert {
+ pkts = append(pkts, &packet{
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Version: protocol.Version1_2,
+ },
+ Content: &handshake.Handshake{
+ Message: &handshake.MessageCertificateRequest{
+ CertificateTypes: []clientcertificate.Type{clientcertificate.RSASign, clientcertificate.ECDSASign},
+ SignatureHashAlgorithms: cfg.localSignatureSchemes,
+ },
+ },
+ },
+ })
+ }
+ case cfg.localPSKIdentityHint != nil:
+ // To help the client in selecting which identity to use, the server
+ // can provide a "PSK identity hint" in the ServerKeyExchange message.
+ // If no hint is provided, the ServerKeyExchange message is omitted.
+ //
+ // https://tools.ietf.org/html/rfc4279#section-2
+ pkts = append(pkts, &packet{
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Version: protocol.Version1_2,
+ },
+ Content: &handshake.Handshake{
+ Message: &handshake.MessageServerKeyExchange{
+ IdentityHint: cfg.localPSKIdentityHint,
+ },
+ },
+ },
+ })
+ case state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypeAnonymous:
+ pkts = append(pkts, &packet{
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Version: protocol.Version1_2,
+ },
+ Content: &handshake.Handshake{
+ Message: &handshake.MessageServerKeyExchange{
+ EllipticCurveType: elliptic.CurveTypeNamedCurve,
+ NamedCurve: state.namedCurve,
+ PublicKey: state.localKeypair.PublicKey,
+ },
+ },
+ },
+ })
+ }
+
+ pkts = append(pkts, &packet{
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Version: protocol.Version1_2,
+ },
+ Content: &handshake.Handshake{
+ Message: &handshake.MessageServerHelloDone{},
+ },
+ },
+ })
+
+ return pkts, nil, nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/flight5handler.go b/vendor/github.com/pion/dtls/v2/flight5handler.go
new file mode 100644
index 0000000..baa1d5c
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/flight5handler.go
@@ -0,0 +1,323 @@
+package dtls
+
+import (
+ "bytes"
+ "context"
+ "crypto"
+ "crypto/x509"
+
+ "github.com/pion/dtls/v2/pkg/crypto/prf"
+ "github.com/pion/dtls/v2/pkg/crypto/signaturehash"
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/alert"
+ "github.com/pion/dtls/v2/pkg/protocol/handshake"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+)
+
+func flight5Parse(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) {
+ _, msgs, ok := cache.fullPullMap(state.handshakeRecvSequence,
+ handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, false, false},
+ )
+ if !ok {
+ // No valid message received. Keep reading
+ return 0, nil, nil
+ }
+
+ var finished *handshake.MessageFinished
+ if finished, ok = msgs[handshake.TypeFinished].(*handshake.MessageFinished); !ok {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
+ }
+ plainText := cache.pullAndMerge(
+ handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
+ handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificateRequest, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeServerHelloDone, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, true, false},
+ handshakeCachePullRule{handshake.TypeClientKeyExchange, cfg.initialEpoch, true, false},
+ handshakeCachePullRule{handshake.TypeCertificateVerify, cfg.initialEpoch, true, false},
+ handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, true, false},
+ )
+
+ expectedVerifyData, err := prf.VerifyDataServer(state.masterSecret, plainText, state.cipherSuite.HashFunc())
+ if err != nil {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+ if !bytes.Equal(expectedVerifyData, finished.VerifyData) {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.HandshakeFailure}, errVerifyDataMismatch
+ }
+
+ return flight5, nil, nil
+}
+
+func flight5Generate(c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) { //nolint:gocognit
+ var certBytes [][]byte
+ var privateKey crypto.PrivateKey
+ if len(cfg.localCertificates) > 0 {
+ certificate, err := cfg.getCertificate(cfg.serverName)
+ if err != nil {
+ return nil, &alert.Alert{Level: alert.Fatal, Description: alert.HandshakeFailure}, err
+ }
+ certBytes = certificate.Certificate
+ privateKey = certificate.PrivateKey
+ }
+
+ var pkts []*packet
+
+ if state.remoteRequestedCertificate {
+ pkts = append(pkts,
+ &packet{
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Version: protocol.Version1_2,
+ },
+ Content: &handshake.Handshake{
+ Message: &handshake.MessageCertificate{
+ Certificate: certBytes,
+ },
+ },
+ },
+ })
+ }
+
+ clientKeyExchange := &handshake.MessageClientKeyExchange{}
+ if cfg.localPSKCallback == nil {
+ clientKeyExchange.PublicKey = state.localKeypair.PublicKey
+ } else {
+ clientKeyExchange.IdentityHint = cfg.localPSKIdentityHint
+ }
+
+ pkts = append(pkts,
+ &packet{
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Version: protocol.Version1_2,
+ },
+ Content: &handshake.Handshake{
+ Message: clientKeyExchange,
+ },
+ },
+ })
+
+ serverKeyExchangeData := cache.pullAndMerge(
+ handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, false},
+ )
+
+ serverKeyExchange := &handshake.MessageServerKeyExchange{}
+
+ // handshakeMessageServerKeyExchange is optional for PSK
+ if len(serverKeyExchangeData) == 0 {
+ alertPtr, err := handleServerKeyExchange(c, state, cfg, &handshake.MessageServerKeyExchange{})
+ if err != nil {
+ return nil, alertPtr, err
+ }
+ } else {
+ rawHandshake := &handshake.Handshake{}
+ err := rawHandshake.Unmarshal(serverKeyExchangeData)
+ if err != nil {
+ return nil, &alert.Alert{Level: alert.Fatal, Description: alert.UnexpectedMessage}, err
+ }
+
+ switch h := rawHandshake.Message.(type) {
+ case *handshake.MessageServerKeyExchange:
+ serverKeyExchange = h
+ default:
+ return nil, &alert.Alert{Level: alert.Fatal, Description: alert.UnexpectedMessage}, errInvalidContentType
+ }
+ }
+
+ // Append not-yet-sent packets
+ merged := []byte{}
+ seqPred := uint16(state.handshakeSendSequence)
+ for _, p := range pkts {
+ h, ok := p.record.Content.(*handshake.Handshake)
+ if !ok {
+ return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, errInvalidContentType
+ }
+ h.Header.MessageSequence = seqPred
+ seqPred++
+ raw, err := h.Marshal()
+ if err != nil {
+ return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+ merged = append(merged, raw...)
+ }
+
+ if alertPtr, err := initalizeCipherSuite(state, cache, cfg, serverKeyExchange, merged); err != nil {
+ return nil, alertPtr, err
+ }
+
+ // If the client has sent a certificate with signing ability, a digitally-signed
+ // CertificateVerify message is sent to explicitly verify possession of the
+ // private key in the certificate.
+ if state.remoteRequestedCertificate && len(cfg.localCertificates) > 0 {
+ plainText := append(cache.pullAndMerge(
+ handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
+ handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificateRequest, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeServerHelloDone, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, true, false},
+ handshakeCachePullRule{handshake.TypeClientKeyExchange, cfg.initialEpoch, true, false},
+ ), merged...)
+
+ // Find compatible signature scheme
+ signatureHashAlgo, err := signaturehash.SelectSignatureScheme(cfg.localSignatureSchemes, privateKey)
+ if err != nil {
+ return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, err
+ }
+
+ certVerify, err := generateCertificateVerify(plainText, privateKey, signatureHashAlgo.Hash)
+ if err != nil {
+ return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+ state.localCertificatesVerify = certVerify
+
+ p := &packet{
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Version: protocol.Version1_2,
+ },
+ Content: &handshake.Handshake{
+ Message: &handshake.MessageCertificateVerify{
+ HashAlgorithm: signatureHashAlgo.Hash,
+ SignatureAlgorithm: signatureHashAlgo.Signature,
+ Signature: state.localCertificatesVerify,
+ },
+ },
+ },
+ }
+ pkts = append(pkts, p)
+
+ h, ok := p.record.Content.(*handshake.Handshake)
+ if !ok {
+ return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, errInvalidContentType
+ }
+ h.Header.MessageSequence = seqPred
+ // seqPred++ // this is the last use of seqPred
+ raw, err := h.Marshal()
+ if err != nil {
+ return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+ merged = append(merged, raw...)
+ }
+
+ pkts = append(pkts,
+ &packet{
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Version: protocol.Version1_2,
+ },
+ Content: &protocol.ChangeCipherSpec{},
+ },
+ })
+
+ if len(state.localVerifyData) == 0 {
+ plainText := cache.pullAndMerge(
+ handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
+ handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificateRequest, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeServerHelloDone, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, true, false},
+ handshakeCachePullRule{handshake.TypeClientKeyExchange, cfg.initialEpoch, true, false},
+ handshakeCachePullRule{handshake.TypeCertificateVerify, cfg.initialEpoch, true, false},
+ handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, true, false},
+ )
+
+ var err error
+ state.localVerifyData, err = prf.VerifyDataClient(state.masterSecret, append(plainText, merged...), state.cipherSuite.HashFunc())
+ if err != nil {
+ return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+ }
+
+ pkts = append(pkts,
+ &packet{
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Version: protocol.Version1_2,
+ Epoch: 1,
+ },
+ Content: &handshake.Handshake{
+ Message: &handshake.MessageFinished{
+ VerifyData: state.localVerifyData,
+ },
+ },
+ },
+ shouldEncrypt: true,
+ resetLocalSequenceNumber: true,
+ })
+
+ return pkts, nil, nil
+}
+
+func initalizeCipherSuite(state *State, cache *handshakeCache, cfg *handshakeConfig, h *handshake.MessageServerKeyExchange, sendingPlainText []byte) (*alert.Alert, error) { //nolint:gocognit
+ if state.cipherSuite.IsInitialized() {
+ return nil, nil
+ }
+
+ clientRandom := state.localRandom.MarshalFixed()
+ serverRandom := state.remoteRandom.MarshalFixed()
+
+ var err error
+
+ if state.extendedMasterSecret {
+ var sessionHash []byte
+ sessionHash, err = cache.sessionHash(state.cipherSuite.HashFunc(), cfg.initialEpoch, sendingPlainText)
+ if err != nil {
+ return &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+
+ state.masterSecret, err = prf.ExtendedMasterSecret(state.preMasterSecret, sessionHash, state.cipherSuite.HashFunc())
+ if err != nil {
+ return &alert.Alert{Level: alert.Fatal, Description: alert.IllegalParameter}, err
+ }
+ } else {
+ state.masterSecret, err = prf.MasterSecret(state.preMasterSecret, clientRandom[:], serverRandom[:], state.cipherSuite.HashFunc())
+ if err != nil {
+ return &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+ }
+
+ if state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypeCertificate {
+ // Verify that the pair of hash algorithm and signiture is listed.
+ var validSignatureScheme bool
+ for _, ss := range cfg.localSignatureSchemes {
+ if ss.Hash == h.HashAlgorithm && ss.Signature == h.SignatureAlgorithm {
+ validSignatureScheme = true
+ break
+ }
+ }
+ if !validSignatureScheme {
+ return &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errNoAvailableSignatureSchemes
+ }
+
+ expectedMsg := valueKeyMessage(clientRandom[:], serverRandom[:], h.PublicKey, h.NamedCurve)
+ if err = verifyKeySignature(expectedMsg, h.Signature, h.HashAlgorithm, state.PeerCertificates); err != nil {
+ return &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, err
+ }
+ var chains [][]*x509.Certificate
+ if !cfg.insecureSkipVerify {
+ if chains, err = verifyServerCert(state.PeerCertificates, cfg.rootCAs, cfg.serverName); err != nil {
+ return &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, err
+ }
+ }
+ if cfg.verifyPeerCertificate != nil {
+ if err = cfg.verifyPeerCertificate(state.PeerCertificates, chains); err != nil {
+ return &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, err
+ }
+ }
+ }
+
+ if err = state.cipherSuite.Init(state.masterSecret, clientRandom[:], serverRandom[:], true); err != nil {
+ return &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+
+ cfg.writeKeyLog(keyLogLabelTLS12, clientRandom[:], state.masterSecret)
+
+ return nil, nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/flight6handler.go b/vendor/github.com/pion/dtls/v2/flight6handler.go
new file mode 100644
index 0000000..10de5ad
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/flight6handler.go
@@ -0,0 +1,82 @@
+package dtls
+
+import (
+ "context"
+
+ "github.com/pion/dtls/v2/pkg/crypto/prf"
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/alert"
+ "github.com/pion/dtls/v2/pkg/protocol/handshake"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+)
+
+func flight6Parse(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) {
+ _, msgs, ok := cache.fullPullMap(state.handshakeRecvSequence-1,
+ handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, true, false},
+ )
+ if !ok {
+ // No valid message received. Keep reading
+ return 0, nil, nil
+ }
+
+ if _, ok = msgs[handshake.TypeFinished].(*handshake.MessageFinished); !ok {
+ return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
+ }
+
+ // Other party retransmitted the last flight.
+ return flight6, nil, nil
+}
+
+func flight6Generate(c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) {
+ var pkts []*packet
+
+ pkts = append(pkts,
+ &packet{
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Version: protocol.Version1_2,
+ },
+ Content: &protocol.ChangeCipherSpec{},
+ },
+ })
+
+ if len(state.localVerifyData) == 0 {
+ plainText := cache.pullAndMerge(
+ handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
+ handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificateRequest, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeServerHelloDone, cfg.initialEpoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, true, false},
+ handshakeCachePullRule{handshake.TypeClientKeyExchange, cfg.initialEpoch, true, false},
+ handshakeCachePullRule{handshake.TypeCertificateVerify, cfg.initialEpoch, true, false},
+ handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, true, false},
+ )
+
+ var err error
+ state.localVerifyData, err = prf.VerifyDataServer(state.masterSecret, plainText, state.cipherSuite.HashFunc())
+ if err != nil {
+ return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
+ }
+ }
+
+ pkts = append(pkts,
+ &packet{
+ record: &recordlayer.RecordLayer{
+ Header: recordlayer.Header{
+ Version: protocol.Version1_2,
+ Epoch: 1,
+ },
+ Content: &handshake.Handshake{
+ Message: &handshake.MessageFinished{
+ VerifyData: state.localVerifyData,
+ },
+ },
+ },
+ shouldEncrypt: true,
+ resetLocalSequenceNumber: true,
+ },
+ )
+ return pkts, nil, nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/flighthandler.go b/vendor/github.com/pion/dtls/v2/flighthandler.go
new file mode 100644
index 0000000..b364c09
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/flighthandler.go
@@ -0,0 +1,57 @@
+package dtls
+
+import (
+ "context"
+
+ "github.com/pion/dtls/v2/pkg/protocol/alert"
+)
+
+// Parse received handshakes and return next flightVal
+type flightParser func(context.Context, flightConn, *State, *handshakeCache, *handshakeConfig) (flightVal, *alert.Alert, error)
+
+// Generate flights
+type flightGenerator func(flightConn, *State, *handshakeCache, *handshakeConfig) ([]*packet, *alert.Alert, error)
+
+func (f flightVal) getFlightParser() (flightParser, error) {
+ switch f {
+ case flight0:
+ return flight0Parse, nil
+ case flight1:
+ return flight1Parse, nil
+ case flight2:
+ return flight2Parse, nil
+ case flight3:
+ return flight3Parse, nil
+ case flight4:
+ return flight4Parse, nil
+ case flight5:
+ return flight5Parse, nil
+ case flight6:
+ return flight6Parse, nil
+ default:
+ return nil, errInvalidFlight
+ }
+}
+
+func (f flightVal) getFlightGenerator() (gen flightGenerator, retransmit bool, err error) {
+ switch f {
+ case flight0:
+ return flight0Generate, true, nil
+ case flight1:
+ return flight1Generate, true, nil
+ case flight2:
+ // https://tools.ietf.org/html/rfc6347#section-3.2.1
+ // HelloVerifyRequests must not be retransmitted.
+ return flight2Generate, false, nil
+ case flight3:
+ return flight3Generate, true, nil
+ case flight4:
+ return flight4Generate, true, nil
+ case flight5:
+ return flight5Generate, true, nil
+ case flight6:
+ return flight6Generate, true, nil
+ default:
+ return nil, false, errInvalidFlight
+ }
+}
diff --git a/vendor/github.com/pion/dtls/v2/fragment_buffer.go b/vendor/github.com/pion/dtls/v2/fragment_buffer.go
new file mode 100644
index 0000000..0274993
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/fragment_buffer.go
@@ -0,0 +1,111 @@
+package dtls
+
+import (
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/handshake"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+)
+
+type fragment struct {
+ recordLayerHeader recordlayer.Header
+ handshakeHeader handshake.Header
+ data []byte
+}
+
+type fragmentBuffer struct {
+ // map of MessageSequenceNumbers that hold slices of fragments
+ cache map[uint16][]*fragment
+
+ currentMessageSequenceNumber uint16
+}
+
+func newFragmentBuffer() *fragmentBuffer {
+ return &fragmentBuffer{cache: map[uint16][]*fragment{}}
+}
+
+// Attempts to push a DTLS packet to the fragmentBuffer
+// when it returns true it means the fragmentBuffer has inserted and the buffer shouldn't be handled
+// when an error returns it is fatal, and the DTLS connection should be stopped
+func (f *fragmentBuffer) push(buf []byte) (bool, error) {
+ frag := new(fragment)
+ if err := frag.recordLayerHeader.Unmarshal(buf); err != nil {
+ return false, err
+ }
+
+ // fragment isn't a handshake, we don't need to handle it
+ if frag.recordLayerHeader.ContentType != protocol.ContentTypeHandshake {
+ return false, nil
+ }
+
+ for buf = buf[recordlayer.HeaderSize:]; len(buf) != 0; frag = new(fragment) {
+ if err := frag.handshakeHeader.Unmarshal(buf); err != nil {
+ return false, err
+ }
+
+ if _, ok := f.cache[frag.handshakeHeader.MessageSequence]; !ok {
+ f.cache[frag.handshakeHeader.MessageSequence] = []*fragment{}
+ }
+
+ // end index should be the length of handshake header but if the handshake
+ // was fragmented, we should keep them all
+ end := int(handshake.HeaderLength + frag.handshakeHeader.Length)
+ if size := len(buf); end > size {
+ end = size
+ }
+
+ // Discard all headers, when rebuilding the packet we will re-build
+ frag.data = append([]byte{}, buf[handshake.HeaderLength:end]...)
+ f.cache[frag.handshakeHeader.MessageSequence] = append(f.cache[frag.handshakeHeader.MessageSequence], frag)
+ buf = buf[end:]
+ }
+
+ return true, nil
+}
+
+func (f *fragmentBuffer) pop() (content []byte, epoch uint16) {
+ frags, ok := f.cache[f.currentMessageSequenceNumber]
+ if !ok {
+ return nil, 0
+ }
+
+ // Go doesn't support recursive lambdas
+ var appendMessage func(targetOffset uint32) bool
+
+ rawMessage := []byte{}
+ appendMessage = func(targetOffset uint32) bool {
+ for _, f := range frags {
+ if f.handshakeHeader.FragmentOffset == targetOffset {
+ fragmentEnd := (f.handshakeHeader.FragmentOffset + f.handshakeHeader.FragmentLength)
+ if fragmentEnd != f.handshakeHeader.Length {
+ if !appendMessage(fragmentEnd) {
+ return false
+ }
+ }
+
+ rawMessage = append(f.data, rawMessage...)
+ return true
+ }
+ }
+ return false
+ }
+
+ // Recursively collect up
+ if !appendMessage(0) {
+ return nil, 0
+ }
+
+ firstHeader := frags[0].handshakeHeader
+ firstHeader.FragmentOffset = 0
+ firstHeader.FragmentLength = firstHeader.Length
+
+ rawHeader, err := firstHeader.Marshal()
+ if err != nil {
+ return nil, 0
+ }
+
+ messageEpoch := frags[0].recordLayerHeader.Epoch
+
+ delete(f.cache, f.currentMessageSequenceNumber)
+ f.currentMessageSequenceNumber++
+ return append(rawHeader, rawMessage...), messageEpoch
+}
diff --git a/vendor/github.com/pion/dtls/v2/fuzz.go b/vendor/github.com/pion/dtls/v2/fuzz.go
new file mode 100644
index 0000000..56c1bf2
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/fuzz.go
@@ -0,0 +1,38 @@
+// +build gofuzz
+
+package dtls
+
+import "fmt"
+
+func partialHeaderMismatch(a, b recordlayer.Header) bool {
+ // Ignoring content length for now.
+ a.contentLen = b.contentLen
+ return a != b
+}
+
+func FuzzRecordLayer(data []byte) int {
+ var r recordLayer
+ if err := r.Unmarshal(data); err != nil {
+ return 0
+ }
+ buf, err := r.Marshal()
+ if err != nil {
+ return 1
+ }
+ if len(buf) == 0 {
+ panic("zero buff") // nolint
+ }
+ var nr recordLayer
+ if err = nr.Unmarshal(data); err != nil {
+ panic(err) // nolint
+ }
+ if partialHeaderMismatch(nr.recordlayer.Header, r.recordlayer.Header) {
+ panic( // nolint
+ fmt.Sprintf("header mismatch: %+v != %+v",
+ nr.recordlayer.Header, r.recordlayer.Header,
+ ),
+ )
+ }
+
+ return 1
+}
diff --git a/vendor/github.com/pion/dtls/v2/go.mod b/vendor/github.com/pion/dtls/v2/go.mod
new file mode 100644
index 0000000..33b60e0
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/go.mod
@@ -0,0 +1,12 @@
+module github.com/pion/dtls/v2
+
+require (
+ github.com/pion/logging v0.2.2
+ github.com/pion/transport v0.12.2
+ github.com/pion/udp v0.1.0
+ golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
+ golang.org/x/net v0.0.0-20210119194325-5f4716e94777
+ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
+)
+
+go 1.13
diff --git a/vendor/github.com/pion/dtls/v2/go.sum b/vendor/github.com/pion/dtls/v2/go.sum
new file mode 100644
index 0000000..fa7c410
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/go.sum
@@ -0,0 +1,48 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
+github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
+github.com/pion/transport v0.10.0 h1:9M12BSneJm6ggGhJyWpDveFOstJsTiQjkLf4M44rm80=
+github.com/pion/transport v0.10.0/go.mod h1:BnHnUipd0rZQyTVB2SBGojFHT9CBt5C5TcsJSQGkvSE=
+github.com/pion/transport v0.12.2 h1:WYEjhloRHt1R86LhUKjC5y+P52Y11/QqEUalvtzVoys=
+github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
+github.com/pion/udp v0.1.0 h1:uGxQsNyrqG3GLINv36Ff60covYmfrLoxzwnCsIYspXI=
+github.com/pion/udp v0.1.0/go.mod h1:BPELIjbwE9PRbd/zxI/KYBnbo7B6+oA6YuEaNE8lths=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
+golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7 h1:3uJsdck53FDIpWwLeAXlia9p4C8j0BO2xZrqzKpL0D8=
+golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
+golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/vendor/github.com/pion/dtls/v2/handshake_cache.go b/vendor/github.com/pion/dtls/v2/handshake_cache.go
new file mode 100644
index 0000000..063a858
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/handshake_cache.go
@@ -0,0 +1,171 @@
+package dtls
+
+import (
+ "sync"
+
+ "github.com/pion/dtls/v2/pkg/crypto/prf"
+ "github.com/pion/dtls/v2/pkg/protocol/handshake"
+)
+
+type handshakeCacheItem struct {
+ typ handshake.Type
+ isClient bool
+ epoch uint16
+ messageSequence uint16
+ data []byte
+}
+
+type handshakeCachePullRule struct {
+ typ handshake.Type
+ epoch uint16
+ isClient bool
+ optional bool
+}
+
+type handshakeCache struct {
+ cache []*handshakeCacheItem
+ mu sync.Mutex
+}
+
+func newHandshakeCache() *handshakeCache {
+ return &handshakeCache{}
+}
+
+func (h *handshakeCache) push(data []byte, epoch, messageSequence uint16, typ handshake.Type, isClient bool) bool { //nolint
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ for _, i := range h.cache {
+ if i.messageSequence == messageSequence &&
+ i.isClient == isClient {
+ return false
+ }
+ }
+
+ h.cache = append(h.cache, &handshakeCacheItem{
+ data: append([]byte{}, data...),
+ epoch: epoch,
+ messageSequence: messageSequence,
+ typ: typ,
+ isClient: isClient,
+ })
+ return true
+}
+
+// returns a list handshakes that match the requested rules
+// the list will contain null entries for rules that can't be satisfied
+// multiple entries may match a rule, but only the last match is returned (ie ClientHello with cookies)
+func (h *handshakeCache) pull(rules ...handshakeCachePullRule) []*handshakeCacheItem {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ out := make([]*handshakeCacheItem, len(rules))
+ for i, r := range rules {
+ for _, c := range h.cache {
+ if c.typ == r.typ && c.isClient == r.isClient && c.epoch == r.epoch {
+ switch {
+ case out[i] == nil:
+ out[i] = c
+ case out[i].messageSequence < c.messageSequence:
+ out[i] = c
+ }
+ }
+ }
+ }
+
+ return out
+}
+
+// fullPullMap pulls all handshakes between rules[0] to rules[len(rules)-1] as map.
+func (h *handshakeCache) fullPullMap(startSeq int, rules ...handshakeCachePullRule) (int, map[handshake.Type]handshake.Message, bool) {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ ci := make(map[handshake.Type]*handshakeCacheItem)
+ for _, r := range rules {
+ var item *handshakeCacheItem
+ for _, c := range h.cache {
+ if c.typ == r.typ && c.isClient == r.isClient && c.epoch == r.epoch {
+ switch {
+ case item == nil:
+ item = c
+ case item.messageSequence < c.messageSequence:
+ item = c
+ }
+ }
+ }
+ if !r.optional && item == nil {
+ // Missing mandatory message.
+ return startSeq, nil, false
+ }
+ ci[r.typ] = item
+ }
+ out := make(map[handshake.Type]handshake.Message)
+ seq := startSeq
+ for _, r := range rules {
+ t := r.typ
+ i := ci[t]
+ if i == nil {
+ continue
+ }
+ rawHandshake := &handshake.Handshake{}
+ if err := rawHandshake.Unmarshal(i.data); err != nil {
+ return startSeq, nil, false
+ }
+ if uint16(seq) != rawHandshake.Header.MessageSequence {
+ // There is a gap. Some messages are not arrived.
+ return startSeq, nil, false
+ }
+ seq++
+ out[t] = rawHandshake.Message
+ }
+ return seq, out, true
+}
+
+// pullAndMerge calls pull and then merges the results, ignoring any null entries
+func (h *handshakeCache) pullAndMerge(rules ...handshakeCachePullRule) []byte {
+ merged := []byte{}
+
+ for _, p := range h.pull(rules...) {
+ if p != nil {
+ merged = append(merged, p.data...)
+ }
+ }
+ return merged
+}
+
+// sessionHash returns the session hash for Extended Master Secret support
+// https://tools.ietf.org/html/draft-ietf-tls-session-hash-06#section-4
+func (h *handshakeCache) sessionHash(hf prf.HashFunc, epoch uint16, additional ...[]byte) ([]byte, error) {
+ merged := []byte{}
+
+ // Order defined by https://tools.ietf.org/html/rfc5246#section-7.3
+ handshakeBuffer := h.pull(
+ handshakeCachePullRule{handshake.TypeClientHello, epoch, true, false},
+ handshakeCachePullRule{handshake.TypeServerHello, epoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificate, epoch, false, false},
+ handshakeCachePullRule{handshake.TypeServerKeyExchange, epoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificateRequest, epoch, false, false},
+ handshakeCachePullRule{handshake.TypeServerHelloDone, epoch, false, false},
+ handshakeCachePullRule{handshake.TypeCertificate, epoch, true, false},
+ handshakeCachePullRule{handshake.TypeClientKeyExchange, epoch, true, false},
+ )
+
+ for _, p := range handshakeBuffer {
+ if p == nil {
+ continue
+ }
+
+ merged = append(merged, p.data...)
+ }
+ for _, a := range additional {
+ merged = append(merged, a...)
+ }
+
+ hash := hf()
+ if _, err := hash.Write(merged); err != nil {
+ return []byte{}, err
+ }
+
+ return hash.Sum(nil), nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/handshaker.go b/vendor/github.com/pion/dtls/v2/handshaker.go
new file mode 100644
index 0000000..0f5077e
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/handshaker.go
@@ -0,0 +1,334 @@
+package dtls
+
+import (
+ "context"
+ "crypto/tls"
+ "crypto/x509"
+ "fmt"
+ "io"
+ "sync"
+ "time"
+
+ "github.com/pion/dtls/v2/pkg/crypto/signaturehash"
+ "github.com/pion/dtls/v2/pkg/protocol/alert"
+ "github.com/pion/dtls/v2/pkg/protocol/handshake"
+ "github.com/pion/logging"
+)
+
+// [RFC6347 Section-4.2.4]
+// +-----------+
+// +---> | PREPARING | <--------------------+
+// | +-----------+ |
+// | | |
+// | | Buffer next flight |
+// | | |
+// | \|/ |
+// | +-----------+ |
+// | | SENDING |<------------------+ | Send
+// | +-----------+ | | HelloRequest
+// Receive | | | |
+// next | | Send flight | | or
+// flight | +--------+ | |
+// | | | Set retransmit timer | | Receive
+// | | \|/ | | HelloRequest
+// | | +-----------+ | | Send
+// +--)--| WAITING |-------------------+ | ClientHello
+// | | +-----------+ Timer expires | |
+// | | | | |
+// | | +------------------------+ |
+// Receive | | Send Read retransmit |
+// last | | last |
+// flight | | flight |
+// | | |
+// \|/\|/ |
+// +-----------+ |
+// | FINISHED | -------------------------------+
+// +-----------+
+// | /|\
+// | |
+// +---+
+// Read retransmit
+// Retransmit last flight
+
+type handshakeState uint8
+
+const (
+ handshakeErrored handshakeState = iota
+ handshakePreparing
+ handshakeSending
+ handshakeWaiting
+ handshakeFinished
+)
+
+func (s handshakeState) String() string {
+ switch s {
+ case handshakeErrored:
+ return "Errored"
+ case handshakePreparing:
+ return "Preparing"
+ case handshakeSending:
+ return "Sending"
+ case handshakeWaiting:
+ return "Waiting"
+ case handshakeFinished:
+ return "Finished"
+ default:
+ return "Unknown"
+ }
+}
+
+type handshakeFSM struct {
+ currentFlight flightVal
+ flights []*packet
+ retransmit bool
+ state *State
+ cache *handshakeCache
+ cfg *handshakeConfig
+ closed chan struct{}
+}
+
+type handshakeConfig struct {
+ localPSKCallback PSKCallback
+ localPSKIdentityHint []byte
+ localCipherSuites []CipherSuite // Available CipherSuites
+ localSignatureSchemes []signaturehash.Algorithm // Available signature schemes
+ extendedMasterSecret ExtendedMasterSecretType // Policy for the Extended Master Support extension
+ localSRTPProtectionProfiles []SRTPProtectionProfile // Available SRTPProtectionProfiles, if empty no SRTP support
+ serverName string
+ clientAuth ClientAuthType // If we are a client should we request a client certificate
+ localCertificates []tls.Certificate
+ nameToCertificate map[string]*tls.Certificate
+ insecureSkipVerify bool
+ verifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
+ rootCAs *x509.CertPool
+ clientCAs *x509.CertPool
+ retransmitInterval time.Duration
+ customCipherSuites func() []CipherSuite
+
+ onFlightState func(flightVal, handshakeState)
+ log logging.LeveledLogger
+ keyLogWriter io.Writer
+
+ initialEpoch uint16
+
+ mu sync.Mutex
+}
+
+type flightConn interface {
+ notify(ctx context.Context, level alert.Level, desc alert.Description) error
+ writePackets(context.Context, []*packet) error
+ recvHandshake() <-chan chan struct{}
+ setLocalEpoch(epoch uint16)
+ handleQueuedPackets(context.Context) error
+}
+
+func (c *handshakeConfig) writeKeyLog(label string, clientRandom, secret []byte) {
+ if c.keyLogWriter == nil {
+ return
+ }
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ _, err := c.keyLogWriter.Write([]byte(fmt.Sprintf("%s %x %x\n", label, clientRandom, secret)))
+ if err != nil {
+ c.log.Debugf("failed to write key log file: %s", err)
+ }
+}
+
+func srvCliStr(isClient bool) string {
+ if isClient {
+ return "client"
+ }
+ return "server"
+}
+
+func newHandshakeFSM(
+ s *State, cache *handshakeCache, cfg *handshakeConfig,
+ initialFlight flightVal,
+) *handshakeFSM {
+ return &handshakeFSM{
+ currentFlight: initialFlight,
+ state: s,
+ cache: cache,
+ cfg: cfg,
+ closed: make(chan struct{}),
+ }
+}
+
+func (s *handshakeFSM) Run(ctx context.Context, c flightConn, initialState handshakeState) error {
+ state := initialState
+ defer func() {
+ close(s.closed)
+ }()
+ for {
+ s.cfg.log.Tracef("[handshake:%s] %s: %s", srvCliStr(s.state.isClient), s.currentFlight.String(), state.String())
+ if s.cfg.onFlightState != nil {
+ s.cfg.onFlightState(s.currentFlight, state)
+ }
+ var err error
+ switch state {
+ case handshakePreparing:
+ state, err = s.prepare(ctx, c)
+ case handshakeSending:
+ state, err = s.send(ctx, c)
+ case handshakeWaiting:
+ state, err = s.wait(ctx, c)
+ case handshakeFinished:
+ state, err = s.finish(ctx, c)
+ default:
+ return errInvalidFSMTransition
+ }
+ if err != nil {
+ return err
+ }
+ }
+}
+
+func (s *handshakeFSM) Done() <-chan struct{} {
+ return s.closed
+}
+
+func (s *handshakeFSM) prepare(ctx context.Context, c flightConn) (handshakeState, error) {
+ s.flights = nil
+ // Prepare flights
+ var (
+ a *alert.Alert
+ err error
+ pkts []*packet
+ )
+ gen, retransmit, errFlight := s.currentFlight.getFlightGenerator()
+ if errFlight != nil {
+ err = errFlight
+ a = &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}
+ } else {
+ pkts, a, err = gen(c, s.state, s.cache, s.cfg)
+ s.retransmit = retransmit
+ }
+ if a != nil {
+ if alertErr := c.notify(ctx, a.Level, a.Description); alertErr != nil {
+ if err != nil {
+ err = alertErr
+ }
+ }
+ }
+ if err != nil {
+ return handshakeErrored, err
+ }
+
+ s.flights = pkts
+ epoch := s.cfg.initialEpoch
+ nextEpoch := epoch
+ for _, p := range s.flights {
+ p.record.Header.Epoch += epoch
+ if p.record.Header.Epoch > nextEpoch {
+ nextEpoch = p.record.Header.Epoch
+ }
+ if h, ok := p.record.Content.(*handshake.Handshake); ok {
+ h.Header.MessageSequence = uint16(s.state.handshakeSendSequence)
+ s.state.handshakeSendSequence++
+ }
+ }
+ if epoch != nextEpoch {
+ s.cfg.log.Tracef("[handshake:%s] -> changeCipherSpec (epoch: %d)", srvCliStr(s.state.isClient), nextEpoch)
+ c.setLocalEpoch(nextEpoch)
+ }
+ return handshakeSending, nil
+}
+
+func (s *handshakeFSM) send(ctx context.Context, c flightConn) (handshakeState, error) {
+ // Send flights
+ if err := c.writePackets(ctx, s.flights); err != nil {
+ return handshakeErrored, err
+ }
+
+ if s.currentFlight.isLastSendFlight() {
+ return handshakeFinished, nil
+ }
+ return handshakeWaiting, nil
+}
+
+func (s *handshakeFSM) wait(ctx context.Context, c flightConn) (handshakeState, error) { //nolint:gocognit
+ parse, errFlight := s.currentFlight.getFlightParser()
+ if errFlight != nil {
+ if alertErr := c.notify(ctx, alert.Fatal, alert.InternalError); alertErr != nil {
+ if errFlight != nil {
+ return handshakeErrored, alertErr
+ }
+ }
+ return handshakeErrored, errFlight
+ }
+
+ retransmitTimer := time.NewTimer(s.cfg.retransmitInterval)
+ for {
+ select {
+ case done := <-c.recvHandshake():
+ nextFlight, alert, err := parse(ctx, c, s.state, s.cache, s.cfg)
+ close(done)
+ if alert != nil {
+ if alertErr := c.notify(ctx, alert.Level, alert.Description); alertErr != nil {
+ if err != nil {
+ err = alertErr
+ }
+ }
+ }
+ if err != nil {
+ return handshakeErrored, err
+ }
+ if nextFlight == 0 {
+ break
+ }
+ s.cfg.log.Tracef("[handshake:%s] %s -> %s", srvCliStr(s.state.isClient), s.currentFlight.String(), nextFlight.String())
+ if nextFlight.isLastRecvFlight() && s.currentFlight == nextFlight {
+ return handshakeFinished, nil
+ }
+ s.currentFlight = nextFlight
+ return handshakePreparing, nil
+
+ case <-retransmitTimer.C:
+ if !s.retransmit {
+ return handshakeWaiting, nil
+ }
+ return handshakeSending, nil
+ case <-ctx.Done():
+ return handshakeErrored, ctx.Err()
+ }
+ }
+}
+
+func (s *handshakeFSM) finish(ctx context.Context, c flightConn) (handshakeState, error) {
+ parse, errFlight := s.currentFlight.getFlightParser()
+ if errFlight != nil {
+ if alertErr := c.notify(ctx, alert.Fatal, alert.InternalError); alertErr != nil {
+ if errFlight != nil {
+ return handshakeErrored, alertErr
+ }
+ }
+ return handshakeErrored, errFlight
+ }
+
+ retransmitTimer := time.NewTimer(s.cfg.retransmitInterval)
+ select {
+ case done := <-c.recvHandshake():
+ nextFlight, alert, err := parse(ctx, c, s.state, s.cache, s.cfg)
+ close(done)
+ if alert != nil {
+ if alertErr := c.notify(ctx, alert.Level, alert.Description); alertErr != nil {
+ if err != nil {
+ err = alertErr
+ }
+ }
+ }
+ if err != nil {
+ return handshakeErrored, err
+ }
+ if nextFlight == 0 {
+ break
+ }
+ <-retransmitTimer.C
+ // Retransmit last flight
+ return handshakeSending, nil
+
+ case <-ctx.Done():
+ return handshakeErrored, ctx.Err()
+ }
+ return handshakeFinished, nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/internal/ciphersuite/aes_128_ccm.go b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/aes_128_ccm.go
new file mode 100644
index 0000000..dcc5379
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/aes_128_ccm.go
@@ -0,0 +1,108 @@
+package ciphersuite
+
+import (
+ "crypto/sha256"
+ "fmt"
+ "hash"
+ "sync/atomic"
+
+ "github.com/pion/dtls/v2/pkg/crypto/ciphersuite"
+ "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
+ "github.com/pion/dtls/v2/pkg/crypto/prf"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+)
+
+// Aes128Ccm is a base class used by multiple AES-CCM Ciphers
+type Aes128Ccm struct {
+ ccm atomic.Value // *cryptoCCM
+ clientCertificateType clientcertificate.Type
+ id ID
+ psk bool
+ cryptoCCMTagLen ciphersuite.CCMTagLen
+}
+
+func newAes128Ccm(clientCertificateType clientcertificate.Type, id ID, psk bool, cryptoCCMTagLen ciphersuite.CCMTagLen) *Aes128Ccm {
+ return &Aes128Ccm{
+ clientCertificateType: clientCertificateType,
+ id: id,
+ psk: psk,
+ cryptoCCMTagLen: cryptoCCMTagLen,
+ }
+}
+
+// CertificateType returns what type of certificate this CipherSuite exchanges
+func (c *Aes128Ccm) CertificateType() clientcertificate.Type {
+ return c.clientCertificateType
+}
+
+// ID returns the ID of the CipherSuite
+func (c *Aes128Ccm) ID() ID {
+ return c.id
+}
+
+func (c *Aes128Ccm) String() string {
+ return c.id.String()
+}
+
+// HashFunc returns the hashing func for this CipherSuite
+func (c *Aes128Ccm) HashFunc() func() hash.Hash {
+ return sha256.New
+}
+
+// AuthenticationType controls what authentication method is using during the handshake
+func (c *Aes128Ccm) AuthenticationType() AuthenticationType {
+ if c.psk {
+ return AuthenticationTypePreSharedKey
+ }
+ return AuthenticationTypeCertificate
+}
+
+// IsInitialized returns if the CipherSuite has keying material and can
+// encrypt/decrypt packets
+func (c *Aes128Ccm) IsInitialized() bool {
+ return c.ccm.Load() != nil
+}
+
+// Init initializes the internal Cipher with keying material
+func (c *Aes128Ccm) Init(masterSecret, clientRandom, serverRandom []byte, isClient bool) error {
+ const (
+ prfMacLen = 0
+ prfKeyLen = 16
+ prfIvLen = 4
+ )
+
+ keys, err := prf.GenerateEncryptionKeys(masterSecret, clientRandom, serverRandom, prfMacLen, prfKeyLen, prfIvLen, c.HashFunc())
+ if err != nil {
+ return err
+ }
+
+ var ccm *ciphersuite.CCM
+ if isClient {
+ ccm, err = ciphersuite.NewCCM(c.cryptoCCMTagLen, keys.ClientWriteKey, keys.ClientWriteIV, keys.ServerWriteKey, keys.ServerWriteIV)
+ } else {
+ ccm, err = ciphersuite.NewCCM(c.cryptoCCMTagLen, keys.ServerWriteKey, keys.ServerWriteIV, keys.ClientWriteKey, keys.ClientWriteIV)
+ }
+ c.ccm.Store(ccm)
+
+ return err
+}
+
+// Encrypt encrypts a single TLS RecordLayer
+func (c *Aes128Ccm) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error) {
+ ccm := c.ccm.Load()
+ if ccm == nil {
+ return nil, fmt.Errorf("%w, unable to encrypt", errCipherSuiteNotInit)
+ }
+
+ return ccm.(*ciphersuite.CCM).Encrypt(pkt, raw)
+}
+
+// Decrypt decrypts a single TLS RecordLayer
+func (c *Aes128Ccm) Decrypt(raw []byte) ([]byte, error) {
+ ccm := c.ccm.Load()
+ if ccm == nil {
+ return nil, fmt.Errorf("%w, unable to decrypt", errCipherSuiteNotInit)
+ }
+
+ return ccm.(*ciphersuite.CCM).Decrypt(raw)
+}
diff --git a/vendor/github.com/pion/dtls/v2/internal/ciphersuite/ciphersuite.go b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/ciphersuite.go
new file mode 100644
index 0000000..3a4fb43
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/ciphersuite.go
@@ -0,0 +1,71 @@
+// Package ciphersuite provides TLS Ciphers as registered with the IANA https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4
+package ciphersuite
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/pion/dtls/v2/pkg/protocol"
+)
+
+var errCipherSuiteNotInit = &protocol.TemporaryError{Err: errors.New("CipherSuite has not been initialized")} //nolint:goerr113
+
+// ID is an ID for our supported CipherSuites
+type ID uint16
+
+func (i ID) String() string {
+ switch i {
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
+ return "TLS_ECDHE_ECDSA_WITH_AES_128_CCM"
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ return "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8"
+ case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
+ case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"
+ case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"
+ case TLS_PSK_WITH_AES_128_CCM:
+ return "TLS_PSK_WITH_AES_128_CCM"
+ case TLS_PSK_WITH_AES_128_CCM_8:
+ return "TLS_PSK_WITH_AES_128_CCM_8"
+ case TLS_PSK_WITH_AES_128_GCM_SHA256:
+ return "TLS_PSK_WITH_AES_128_GCM_SHA256"
+ case TLS_PSK_WITH_AES_128_CBC_SHA256:
+ return "TLS_PSK_WITH_AES_128_CBC_SHA256"
+ default:
+ return fmt.Sprintf("unknown(%v)", uint16(i))
+ }
+}
+
+// Supported Cipher Suites
+const (
+ // AES-128-CCM
+ TLS_ECDHE_ECDSA_WITH_AES_128_CCM ID = 0xc0ac //nolint:golint,stylecheck
+ TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 ID = 0xc0ae //nolint:golint,stylecheck
+
+ // AES-128-GCM-SHA256
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 ID = 0xc02b //nolint:golint,stylecheck
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ID = 0xc02f //nolint:golint,stylecheck
+
+ // AES-256-CBC-SHA
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA ID = 0xc00a //nolint:golint,stylecheck
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA ID = 0xc014 //nolint:golint,stylecheck
+
+ TLS_PSK_WITH_AES_128_CCM ID = 0xc0a4 //nolint:golint,stylecheck
+ TLS_PSK_WITH_AES_128_CCM_8 ID = 0xc0a8 //nolint:golint,stylecheck
+ TLS_PSK_WITH_AES_128_GCM_SHA256 ID = 0x00a8 //nolint:golint,stylecheck
+ TLS_PSK_WITH_AES_128_CBC_SHA256 ID = 0x00ae //nolint:golint,stylecheck
+)
+
+// AuthenticationType controls what authentication method is using during the handshake
+type AuthenticationType int
+
+// AuthenticationType Enums
+const (
+ AuthenticationTypeCertificate AuthenticationType = iota + 1
+ AuthenticationTypePreSharedKey
+ AuthenticationTypeAnonymous
+)
diff --git a/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_ccm.go b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_ccm.go
new file mode 100644
index 0000000..ac73556
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_ccm.go
@@ -0,0 +1,11 @@
+package ciphersuite
+
+import (
+ "github.com/pion/dtls/v2/pkg/crypto/ciphersuite"
+ "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
+)
+
+// NewTLSEcdheEcdsaWithAes128Ccm constructs a TLS_ECDHE_ECDSA_WITH_AES_128_CCM Cipher
+func NewTLSEcdheEcdsaWithAes128Ccm() *Aes128Ccm {
+ return newAes128Ccm(clientcertificate.ECDSASign, TLS_ECDHE_ECDSA_WITH_AES_128_CCM, false, ciphersuite.CCMTagLength)
+}
diff --git a/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_ccm8.go b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_ccm8.go
new file mode 100644
index 0000000..49b1a83
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_ccm8.go
@@ -0,0 +1,11 @@
+package ciphersuite
+
+import (
+ "github.com/pion/dtls/v2/pkg/crypto/ciphersuite"
+ "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
+)
+
+// NewTLSEcdheEcdsaWithAes128Ccm8 creates a new TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 CipherSuite
+func NewTLSEcdheEcdsaWithAes128Ccm8() *Aes128Ccm {
+ return newAes128Ccm(clientcertificate.ECDSASign, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, false, ciphersuite.CCMTagLength8)
+}
diff --git a/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_gcm_sha256.go b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_gcm_sha256.go
new file mode 100644
index 0000000..b491320
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_gcm_sha256.go
@@ -0,0 +1,92 @@
+package ciphersuite
+
+import (
+ "crypto/sha256"
+ "fmt"
+ "hash"
+ "sync/atomic"
+
+ "github.com/pion/dtls/v2/pkg/crypto/ciphersuite"
+ "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
+ "github.com/pion/dtls/v2/pkg/crypto/prf"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+)
+
+// TLSEcdheEcdsaWithAes128GcmSha256 represents a TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 CipherSuite
+type TLSEcdheEcdsaWithAes128GcmSha256 struct {
+ gcm atomic.Value // *cryptoGCM
+}
+
+// CertificateType returns what type of certficate this CipherSuite exchanges
+func (c *TLSEcdheEcdsaWithAes128GcmSha256) CertificateType() clientcertificate.Type {
+ return clientcertificate.ECDSASign
+}
+
+// ID returns the ID of the CipherSuite
+func (c *TLSEcdheEcdsaWithAes128GcmSha256) ID() ID {
+ return TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+}
+
+func (c *TLSEcdheEcdsaWithAes128GcmSha256) String() string {
+ return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
+}
+
+// HashFunc returns the hashing func for this CipherSuite
+func (c *TLSEcdheEcdsaWithAes128GcmSha256) HashFunc() func() hash.Hash {
+ return sha256.New
+}
+
+// AuthenticationType controls what authentication method is using during the handshake
+func (c *TLSEcdheEcdsaWithAes128GcmSha256) AuthenticationType() AuthenticationType {
+ return AuthenticationTypeCertificate
+}
+
+// IsInitialized returns if the CipherSuite has keying material and can
+// encrypt/decrypt packets
+func (c *TLSEcdheEcdsaWithAes128GcmSha256) IsInitialized() bool {
+ return c.gcm.Load() != nil
+}
+
+// Init initializes the internal Cipher with keying material
+func (c *TLSEcdheEcdsaWithAes128GcmSha256) Init(masterSecret, clientRandom, serverRandom []byte, isClient bool) error {
+ const (
+ prfMacLen = 0
+ prfKeyLen = 16
+ prfIvLen = 4
+ )
+
+ keys, err := prf.GenerateEncryptionKeys(masterSecret, clientRandom, serverRandom, prfMacLen, prfKeyLen, prfIvLen, c.HashFunc())
+ if err != nil {
+ return err
+ }
+
+ var gcm *ciphersuite.GCM
+ if isClient {
+ gcm, err = ciphersuite.NewGCM(keys.ClientWriteKey, keys.ClientWriteIV, keys.ServerWriteKey, keys.ServerWriteIV)
+ } else {
+ gcm, err = ciphersuite.NewGCM(keys.ServerWriteKey, keys.ServerWriteIV, keys.ClientWriteKey, keys.ClientWriteIV)
+ }
+ c.gcm.Store(gcm)
+
+ return err
+}
+
+// Encrypt encrypts a single TLS RecordLayer
+func (c *TLSEcdheEcdsaWithAes128GcmSha256) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error) {
+ gcm := c.gcm.Load()
+ if gcm == nil {
+ return nil, fmt.Errorf("%w, unable to encrypt", errCipherSuiteNotInit)
+ }
+
+ return gcm.(*ciphersuite.GCM).Encrypt(pkt, raw)
+}
+
+// Decrypt decrypts a single TLS RecordLayer
+func (c *TLSEcdheEcdsaWithAes128GcmSha256) Decrypt(raw []byte) ([]byte, error) {
+ gcm := c.gcm.Load()
+ if gcm == nil {
+ return nil, fmt.Errorf("%w, unable to decrypt", errCipherSuiteNotInit)
+ }
+
+ return gcm.(*ciphersuite.GCM).Decrypt(raw)
+}
diff --git a/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_256_cbc_sha.go b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_256_cbc_sha.go
new file mode 100644
index 0000000..f7a33ad
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_256_cbc_sha.go
@@ -0,0 +1,101 @@
+package ciphersuite
+
+import (
+ "crypto/sha1" //nolint: gosec,gci
+ "crypto/sha256"
+ "fmt"
+ "hash"
+ "sync/atomic"
+
+ "github.com/pion/dtls/v2/pkg/crypto/ciphersuite"
+ "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
+ "github.com/pion/dtls/v2/pkg/crypto/prf"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+)
+
+// TLSEcdheEcdsaWithAes256CbcSha represents a TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA CipherSuite
+type TLSEcdheEcdsaWithAes256CbcSha struct {
+ cbc atomic.Value // *cryptoCBC
+}
+
+// CertificateType returns what type of certficate this CipherSuite exchanges
+func (c *TLSEcdheEcdsaWithAes256CbcSha) CertificateType() clientcertificate.Type {
+ return clientcertificate.ECDSASign
+}
+
+// ID returns the ID of the CipherSuite
+func (c *TLSEcdheEcdsaWithAes256CbcSha) ID() ID {
+ return TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+}
+
+func (c *TLSEcdheEcdsaWithAes256CbcSha) String() string {
+ return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"
+}
+
+// HashFunc returns the hashing func for this CipherSuite
+func (c *TLSEcdheEcdsaWithAes256CbcSha) HashFunc() func() hash.Hash {
+ return sha256.New
+}
+
+// AuthenticationType controls what authentication method is using during the handshake
+func (c *TLSEcdheEcdsaWithAes256CbcSha) AuthenticationType() AuthenticationType {
+ return AuthenticationTypeCertificate
+}
+
+// IsInitialized returns if the CipherSuite has keying material and can
+// encrypt/decrypt packets
+func (c *TLSEcdheEcdsaWithAes256CbcSha) IsInitialized() bool {
+ return c.cbc.Load() != nil
+}
+
+// Init initializes the internal Cipher with keying material
+func (c *TLSEcdheEcdsaWithAes256CbcSha) Init(masterSecret, clientRandom, serverRandom []byte, isClient bool) error {
+ const (
+ prfMacLen = 20
+ prfKeyLen = 32
+ prfIvLen = 16
+ )
+
+ keys, err := prf.GenerateEncryptionKeys(masterSecret, clientRandom, serverRandom, prfMacLen, prfKeyLen, prfIvLen, c.HashFunc())
+ if err != nil {
+ return err
+ }
+
+ var cbc *ciphersuite.CBC
+ if isClient {
+ cbc, err = ciphersuite.NewCBC(
+ keys.ClientWriteKey, keys.ClientWriteIV, keys.ClientMACKey,
+ keys.ServerWriteKey, keys.ServerWriteIV, keys.ServerMACKey,
+ sha1.New,
+ )
+ } else {
+ cbc, err = ciphersuite.NewCBC(
+ keys.ServerWriteKey, keys.ServerWriteIV, keys.ServerMACKey,
+ keys.ClientWriteKey, keys.ClientWriteIV, keys.ClientMACKey,
+ sha1.New,
+ )
+ }
+ c.cbc.Store(cbc)
+
+ return err
+}
+
+// Encrypt encrypts a single TLS RecordLayer
+func (c *TLSEcdheEcdsaWithAes256CbcSha) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error) {
+ cbc := c.cbc.Load()
+ if cbc == nil { // !c.isInitialized()
+ return nil, fmt.Errorf("%w, unable to encrypt", errCipherSuiteNotInit)
+ }
+
+ return cbc.(*ciphersuite.CBC).Encrypt(pkt, raw)
+}
+
+// Decrypt decrypts a single TLS RecordLayer
+func (c *TLSEcdheEcdsaWithAes256CbcSha) Decrypt(raw []byte) ([]byte, error) {
+ cbc := c.cbc.Load()
+ if cbc == nil { // !c.isInitialized()
+ return nil, fmt.Errorf("%w, unable to decrypt", errCipherSuiteNotInit)
+ }
+
+ return cbc.(*ciphersuite.CBC).Decrypt(raw)
+}
diff --git a/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_rsa_with_aes_128_gcm_sha256.go b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_rsa_with_aes_128_gcm_sha256.go
new file mode 100644
index 0000000..70400c3
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_rsa_with_aes_128_gcm_sha256.go
@@ -0,0 +1,22 @@
+package ciphersuite
+
+import "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
+
+// TLSEcdheRsaWithAes128GcmSha256 implements the TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 CipherSuite
+type TLSEcdheRsaWithAes128GcmSha256 struct {
+ TLSEcdheEcdsaWithAes128GcmSha256
+}
+
+// CertificateType returns what type of certificate this CipherSuite exchanges
+func (c *TLSEcdheRsaWithAes128GcmSha256) CertificateType() clientcertificate.Type {
+ return clientcertificate.RSASign
+}
+
+// ID returns the ID of the CipherSuite
+func (c *TLSEcdheRsaWithAes128GcmSha256) ID() ID {
+ return TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+}
+
+func (c *TLSEcdheRsaWithAes128GcmSha256) String() string {
+ return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
+}
diff --git a/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_rsa_with_aes_256_cbc_sha.go b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_rsa_with_aes_256_cbc_sha.go
new file mode 100644
index 0000000..0d82dc3
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_rsa_with_aes_256_cbc_sha.go
@@ -0,0 +1,22 @@
+package ciphersuite
+
+import "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
+
+// TLSEcdheRsaWithAes256CbcSha implements the TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA CipherSuite
+type TLSEcdheRsaWithAes256CbcSha struct {
+ TLSEcdheEcdsaWithAes256CbcSha
+}
+
+// CertificateType returns what type of certificate this CipherSuite exchanges
+func (c *TLSEcdheRsaWithAes256CbcSha) CertificateType() clientcertificate.Type {
+ return clientcertificate.RSASign
+}
+
+// ID returns the ID of the CipherSuite
+func (c *TLSEcdheRsaWithAes256CbcSha) ID() ID {
+ return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+}
+
+func (c *TLSEcdheRsaWithAes256CbcSha) String() string {
+ return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"
+}
diff --git a/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_cbc_sha256.go b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_cbc_sha256.go
new file mode 100644
index 0000000..43e5e38
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_cbc_sha256.go
@@ -0,0 +1,100 @@
+package ciphersuite
+
+import (
+ "crypto/sha256"
+ "fmt"
+ "hash"
+ "sync/atomic"
+
+ "github.com/pion/dtls/v2/pkg/crypto/ciphersuite"
+ "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
+ "github.com/pion/dtls/v2/pkg/crypto/prf"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+)
+
+// TLSPskWithAes128CbcSha256 implements the TLS_PSK_WITH_AES_128_CBC_SHA256 CipherSuite
+type TLSPskWithAes128CbcSha256 struct {
+ cbc atomic.Value // *cryptoCBC
+}
+
+// CertificateType returns what type of certificate this CipherSuite exchanges
+func (c *TLSPskWithAes128CbcSha256) CertificateType() clientcertificate.Type {
+ return clientcertificate.Type(0)
+}
+
+// ID returns the ID of the CipherSuite
+func (c *TLSPskWithAes128CbcSha256) ID() ID {
+ return TLS_PSK_WITH_AES_128_CBC_SHA256
+}
+
+func (c *TLSPskWithAes128CbcSha256) String() string {
+ return "TLS_PSK_WITH_AES_128_CBC_SHA256"
+}
+
+// HashFunc returns the hashing func for this CipherSuite
+func (c *TLSPskWithAes128CbcSha256) HashFunc() func() hash.Hash {
+ return sha256.New
+}
+
+// AuthenticationType controls what authentication method is using during the handshake
+func (c *TLSPskWithAes128CbcSha256) AuthenticationType() AuthenticationType {
+ return AuthenticationTypePreSharedKey
+}
+
+// IsInitialized returns if the CipherSuite has keying material and can
+// encrypt/decrypt packets
+func (c *TLSPskWithAes128CbcSha256) IsInitialized() bool {
+ return c.cbc.Load() != nil
+}
+
+// Init initializes the internal Cipher with keying material
+func (c *TLSPskWithAes128CbcSha256) Init(masterSecret, clientRandom, serverRandom []byte, isClient bool) error {
+ const (
+ prfMacLen = 32
+ prfKeyLen = 16
+ prfIvLen = 16
+ )
+
+ keys, err := prf.GenerateEncryptionKeys(masterSecret, clientRandom, serverRandom, prfMacLen, prfKeyLen, prfIvLen, c.HashFunc())
+ if err != nil {
+ return err
+ }
+
+ var cbc *ciphersuite.CBC
+ if isClient {
+ cbc, err = ciphersuite.NewCBC(
+ keys.ClientWriteKey, keys.ClientWriteIV, keys.ClientMACKey,
+ keys.ServerWriteKey, keys.ServerWriteIV, keys.ServerMACKey,
+ c.HashFunc(),
+ )
+ } else {
+ cbc, err = ciphersuite.NewCBC(
+ keys.ServerWriteKey, keys.ServerWriteIV, keys.ServerMACKey,
+ keys.ClientWriteKey, keys.ClientWriteIV, keys.ClientMACKey,
+ c.HashFunc(),
+ )
+ }
+ c.cbc.Store(cbc)
+
+ return err
+}
+
+// Encrypt encrypts a single TLS RecordLayer
+func (c *TLSPskWithAes128CbcSha256) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error) {
+ cbc := c.cbc.Load()
+ if cbc == nil { // !c.isInitialized()
+ return nil, fmt.Errorf("%w, unable to decrypt", errCipherSuiteNotInit)
+ }
+
+ return cbc.(*ciphersuite.CBC).Encrypt(pkt, raw)
+}
+
+// Decrypt decrypts a single TLS RecordLayer
+func (c *TLSPskWithAes128CbcSha256) Decrypt(raw []byte) ([]byte, error) {
+ cbc := c.cbc.Load()
+ if cbc == nil { // !c.isInitialized()
+ return nil, fmt.Errorf("%w, unable to decrypt", errCipherSuiteNotInit)
+ }
+
+ return cbc.(*ciphersuite.CBC).Decrypt(raw)
+}
diff --git a/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_ccm.go b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_ccm.go
new file mode 100644
index 0000000..8c13bb1
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_ccm.go
@@ -0,0 +1,11 @@
+package ciphersuite
+
+import (
+ "github.com/pion/dtls/v2/pkg/crypto/ciphersuite"
+ "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
+)
+
+// NewTLSPskWithAes128Ccm returns the TLS_PSK_WITH_AES_128_CCM CipherSuite
+func NewTLSPskWithAes128Ccm() *Aes128Ccm {
+ return newAes128Ccm(clientcertificate.Type(0), TLS_PSK_WITH_AES_128_CCM, true, ciphersuite.CCMTagLength)
+}
diff --git a/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_ccm8.go b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_ccm8.go
new file mode 100644
index 0000000..d04abb4
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_ccm8.go
@@ -0,0 +1,11 @@
+package ciphersuite
+
+import (
+ "github.com/pion/dtls/v2/pkg/crypto/ciphersuite"
+ "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
+)
+
+// NewTLSPskWithAes128Ccm8 returns the TLS_PSK_WITH_AES_128_CCM_8 CipherSuite
+func NewTLSPskWithAes128Ccm8() *Aes128Ccm {
+ return newAes128Ccm(clientcertificate.Type(0), TLS_PSK_WITH_AES_128_CCM_8, true, ciphersuite.CCMTagLength8)
+}
diff --git a/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_gcm_sha256.go b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_gcm_sha256.go
new file mode 100644
index 0000000..5f10335
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_gcm_sha256.go
@@ -0,0 +1,27 @@
+package ciphersuite
+
+import "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
+
+// TLSPskWithAes128GcmSha256 implements the TLS_PSK_WITH_AES_128_GCM_SHA256 CipherSuite
+type TLSPskWithAes128GcmSha256 struct {
+ TLSEcdheEcdsaWithAes128GcmSha256
+}
+
+// CertificateType returns what type of certificate this CipherSuite exchanges
+func (c *TLSPskWithAes128GcmSha256) CertificateType() clientcertificate.Type {
+ return clientcertificate.Type(0)
+}
+
+// ID returns the ID of the CipherSuite
+func (c *TLSPskWithAes128GcmSha256) ID() ID {
+ return TLS_PSK_WITH_AES_128_GCM_SHA256
+}
+
+func (c *TLSPskWithAes128GcmSha256) String() string {
+ return "TLS_PSK_WITH_AES_128_GCM_SHA256"
+}
+
+// AuthenticationType controls what authentication method is using during the handshake
+func (c *TLSPskWithAes128GcmSha256) AuthenticationType() AuthenticationType {
+ return AuthenticationTypePreSharedKey
+}
diff --git a/vendor/github.com/pion/dtls/v2/internal/closer/closer.go b/vendor/github.com/pion/dtls/v2/internal/closer/closer.go
new file mode 100644
index 0000000..b99e13e
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/internal/closer/closer.go
@@ -0,0 +1,45 @@
+// Package closer provides signaling channel for shutdown
+package closer
+
+import (
+ "context"
+)
+
+// Closer allows for each signaling a channel for shutdown
+type Closer struct {
+ ctx context.Context
+ closeFunc func()
+}
+
+// NewCloser creates a new instance of Closer
+func NewCloser() *Closer {
+ ctx, closeFunc := context.WithCancel(context.Background())
+ return &Closer{
+ ctx: ctx,
+ closeFunc: closeFunc,
+ }
+}
+
+// NewCloserWithParent creates a new instance of Closer with a parent context
+func NewCloserWithParent(ctx context.Context) *Closer {
+ ctx, closeFunc := context.WithCancel(ctx)
+ return &Closer{
+ ctx: ctx,
+ closeFunc: closeFunc,
+ }
+}
+
+// Done returns a channel signaling when it is done
+func (c *Closer) Done() <-chan struct{} {
+ return c.ctx.Done()
+}
+
+// Err returns an error of the context
+func (c *Closer) Err() error {
+ return c.ctx.Err()
+}
+
+// Close sends a signal to trigger the ctx done channel
+func (c *Closer) Close() {
+ c.closeFunc()
+}
diff --git a/vendor/github.com/pion/dtls/v2/internal/util/util.go b/vendor/github.com/pion/dtls/v2/internal/util/util.go
new file mode 100644
index 0000000..746a670
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/internal/util/util.go
@@ -0,0 +1,39 @@
+// Package util contains small helpers used across the repo
+package util
+
+import (
+ "encoding/binary"
+)
+
+// BigEndianUint24 returns the value of a big endian uint24
+func BigEndianUint24(raw []byte) uint32 {
+ if len(raw) < 3 {
+ return 0
+ }
+
+ rawCopy := make([]byte, 4)
+ copy(rawCopy[1:], raw)
+ return binary.BigEndian.Uint32(rawCopy)
+}
+
+// PutBigEndianUint24 encodes a uint24 and places into out
+func PutBigEndianUint24(out []byte, in uint32) {
+ tmp := make([]byte, 4)
+ binary.BigEndian.PutUint32(tmp, in)
+ copy(out, tmp[1:])
+}
+
+// PutBigEndianUint48 encodes a uint64 and places into out
+func PutBigEndianUint48(out []byte, in uint64) {
+ tmp := make([]byte, 8)
+ binary.BigEndian.PutUint64(tmp, in)
+ copy(out, tmp[2:])
+}
+
+// Max returns the larger value
+func Max(a, b int) int {
+ if a > b {
+ return a
+ }
+ return b
+}
diff --git a/vendor/github.com/pion/dtls/v2/listener.go b/vendor/github.com/pion/dtls/v2/listener.go
new file mode 100644
index 0000000..bf80345
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/listener.go
@@ -0,0 +1,80 @@
+package dtls
+
+import (
+ "net"
+
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+ "github.com/pion/udp"
+)
+
+// Listen creates a DTLS listener
+func Listen(network string, laddr *net.UDPAddr, config *Config) (net.Listener, error) {
+ if err := validateConfig(config); err != nil {
+ return nil, err
+ }
+
+ lc := udp.ListenConfig{
+ AcceptFilter: func(packet []byte) bool {
+ pkts, err := recordlayer.UnpackDatagram(packet)
+ if err != nil || len(pkts) < 1 {
+ return false
+ }
+ h := &recordlayer.Header{}
+ if err := h.Unmarshal(pkts[0]); err != nil {
+ return false
+ }
+ return h.ContentType == protocol.ContentTypeHandshake
+ },
+ }
+ parent, err := lc.Listen(network, laddr)
+ if err != nil {
+ return nil, err
+ }
+ return &listener{
+ config: config,
+ parent: parent,
+ }, nil
+}
+
+// NewListener creates a DTLS listener which accepts connections from an inner Listener.
+func NewListener(inner net.Listener, config *Config) (net.Listener, error) {
+ if err := validateConfig(config); err != nil {
+ return nil, err
+ }
+
+ return &listener{
+ config: config,
+ parent: inner,
+ }, nil
+}
+
+// listener represents a DTLS listener
+type listener struct {
+ config *Config
+ parent net.Listener
+}
+
+// Accept waits for and returns the next connection to the listener.
+// You have to either close or read on all connection that are created.
+// Connection handshake will timeout using ConnectContextMaker in the Config.
+// If you want to specify the timeout duration, set ConnectContextMaker.
+func (l *listener) Accept() (net.Conn, error) {
+ c, err := l.parent.Accept()
+ if err != nil {
+ return nil, err
+ }
+ return Server(c, l.config)
+}
+
+// Close closes the listener.
+// Any blocked Accept operations will be unblocked and return errors.
+// Already Accepted connections are not closed.
+func (l *listener) Close() error {
+ return l.parent.Close()
+}
+
+// Addr returns the listener's network address.
+func (l *listener) Addr() net.Addr {
+ return l.parent.Addr()
+}
diff --git a/vendor/github.com/pion/dtls/v2/packet.go b/vendor/github.com/pion/dtls/v2/packet.go
new file mode 100644
index 0000000..8366a3c
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/packet.go
@@ -0,0 +1,9 @@
+package dtls
+
+import "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+
+type packet struct {
+ record *recordlayer.RecordLayer
+ shouldEncrypt bool
+ resetLocalSequenceNumber bool
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/crypto/ccm/ccm.go b/vendor/github.com/pion/dtls/v2/pkg/crypto/ccm/ccm.go
new file mode 100644
index 0000000..20e3436
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/crypto/ccm/ccm.go
@@ -0,0 +1,251 @@
+// Package ccm implements a CCM, Counter with CBC-MAC
+// as per RFC 3610.
+//
+// See https://tools.ietf.org/html/rfc3610
+//
+// This code was lifted from https://github.com/bocajim/dtls/blob/a3300364a283fcb490d28a93d7fcfa7ba437fbbe/ccm/ccm.go
+// and as such was not written by the Pions authors. Like Pions this
+// code is licensed under MIT.
+//
+// A request for including CCM into the Go standard library
+// can be found as issue #27484 on the https://github.com/golang/go/
+// repository.
+package ccm
+
+import (
+ "crypto/cipher"
+ "crypto/subtle"
+ "encoding/binary"
+ "errors"
+ "math"
+)
+
+// ccm represents a Counter with CBC-MAC with a specific key.
+type ccm struct {
+ b cipher.Block
+ M uint8
+ L uint8
+}
+
+const ccmBlockSize = 16
+
+// CCM is a block cipher in Counter with CBC-MAC mode.
+// Providing authenticated encryption with associated data via the cipher.AEAD interface.
+type CCM interface {
+ cipher.AEAD
+ // MaxLength returns the maxium length of plaintext in calls to Seal.
+ // The maximum length of ciphertext in calls to Open is MaxLength()+Overhead().
+ // The maximum length is related to CCM's `L` parameter (15-noncesize) and
+ // is 1<<(8*L) - 1 (but also limited by the maxium size of an int).
+ MaxLength() int
+}
+
+var (
+ errInvalidBlockSize = errors.New("ccm: NewCCM requires 128-bit block cipher")
+ errInvalidTagSize = errors.New("ccm: tagsize must be 4, 6, 8, 10, 12, 14, or 16")
+ errInvalidNonceSize = errors.New("ccm: invalid nonce size")
+)
+
+// NewCCM returns the given 128-bit block cipher wrapped in CCM.
+// The tagsize must be an even integer between 4 and 16 inclusive
+// and is used as CCM's `M` parameter.
+// The noncesize must be an integer between 7 and 13 inclusive,
+// 15-noncesize is used as CCM's `L` parameter.
+func NewCCM(b cipher.Block, tagsize, noncesize int) (CCM, error) {
+ if b.BlockSize() != ccmBlockSize {
+ return nil, errInvalidBlockSize
+ }
+ if tagsize < 4 || tagsize > 16 || tagsize&1 != 0 {
+ return nil, errInvalidTagSize
+ }
+ lensize := 15 - noncesize
+ if lensize < 2 || lensize > 8 {
+ return nil, errInvalidNonceSize
+ }
+ c := &ccm{b: b, M: uint8(tagsize), L: uint8(lensize)}
+ return c, nil
+}
+
+func (c *ccm) NonceSize() int { return 15 - int(c.L) }
+func (c *ccm) Overhead() int { return int(c.M) }
+func (c *ccm) MaxLength() int { return maxlen(c.L, c.Overhead()) }
+
+func maxlen(l uint8, tagsize int) int {
+ max := (uint64(1) << (8 * l)) - 1
+ if m64 := uint64(math.MaxInt64) - uint64(tagsize); l > 8 || max > m64 {
+ max = m64 // The maximum lentgh on a 64bit arch
+ }
+ if max != uint64(int(max)) {
+ return math.MaxInt32 - tagsize // We have only 32bit int's
+ }
+ return int(max)
+}
+
+// MaxNonceLength returns the maximum nonce length for a given plaintext length.
+// A return value <= 0 indicates that plaintext length is too large for
+// any nonce length.
+func MaxNonceLength(pdatalen int) int {
+ const tagsize = 16
+ for L := 2; L <= 8; L++ {
+ if maxlen(uint8(L), tagsize) >= pdatalen {
+ return 15 - L
+ }
+ }
+ return 0
+}
+
+func (c *ccm) cbcRound(mac, data []byte) {
+ for i := 0; i < ccmBlockSize; i++ {
+ mac[i] ^= data[i]
+ }
+ c.b.Encrypt(mac, mac)
+}
+
+func (c *ccm) cbcData(mac, data []byte) {
+ for len(data) >= ccmBlockSize {
+ c.cbcRound(mac, data[:ccmBlockSize])
+ data = data[ccmBlockSize:]
+ }
+ if len(data) > 0 {
+ var block [ccmBlockSize]byte
+ copy(block[:], data)
+ c.cbcRound(mac, block[:])
+ }
+}
+
+var errPlaintextTooLong = errors.New("ccm: plaintext too large")
+
+func (c *ccm) tag(nonce, plaintext, adata []byte) ([]byte, error) {
+ var mac [ccmBlockSize]byte
+
+ if len(adata) > 0 {
+ mac[0] |= 1 << 6
+ }
+ mac[0] |= (c.M - 2) << 2
+ mac[0] |= c.L - 1
+ if len(nonce) != c.NonceSize() {
+ return nil, errInvalidNonceSize
+ }
+ if len(plaintext) > c.MaxLength() {
+ return nil, errPlaintextTooLong
+ }
+ binary.BigEndian.PutUint64(mac[ccmBlockSize-8:], uint64(len(plaintext)))
+ copy(mac[1:ccmBlockSize-c.L], nonce)
+ c.b.Encrypt(mac[:], mac[:])
+
+ var block [ccmBlockSize]byte
+ if n := uint64(len(adata)); n > 0 {
+ // First adata block includes adata length
+ i := 2
+ if n <= 0xfeff {
+ binary.BigEndian.PutUint16(block[:i], uint16(n))
+ } else {
+ block[0] = 0xfe
+ block[1] = 0xff
+ if n < uint64(1<<32) {
+ i = 2 + 4
+ binary.BigEndian.PutUint32(block[2:i], uint32(n))
+ } else {
+ i = 2 + 8
+ binary.BigEndian.PutUint64(block[2:i], n)
+ }
+ }
+ i = copy(block[i:], adata)
+ c.cbcRound(mac[:], block[:])
+ c.cbcData(mac[:], adata[i:])
+ }
+
+ if len(plaintext) > 0 {
+ c.cbcData(mac[:], plaintext)
+ }
+
+ return mac[:c.M], nil
+}
+
+// sliceForAppend takes a slice and a requested number of bytes. It returns a
+// slice with the contents of the given slice followed by that many bytes and a
+// second slice that aliases into it and contains only the extra bytes. If the
+// original slice has sufficient capacity then no allocation is performed.
+// From crypto/cipher/gcm.go
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+ if total := len(in) + n; cap(in) >= total {
+ head = in[:total]
+ } else {
+ head = make([]byte, total)
+ copy(head, in)
+ }
+ tail = head[len(in):]
+ return
+}
+
+// Seal encrypts and authenticates plaintext, authenticates the
+// additional data and appends the result to dst, returning the updated
+// slice. The nonce must be NonceSize() bytes long and unique for all
+// time, for a given key.
+// The plaintext must be no longer than MaxLength() bytes long.
+//
+// The plaintext and dst may alias exactly or not at all.
+func (c *ccm) Seal(dst, nonce, plaintext, adata []byte) []byte {
+ tag, err := c.tag(nonce, plaintext, adata)
+ if err != nil {
+ // The cipher.AEAD interface doesn't allow for an error return.
+ panic(err) // nolint
+ }
+
+ var iv, s0 [ccmBlockSize]byte
+ iv[0] = c.L - 1
+ copy(iv[1:ccmBlockSize-c.L], nonce)
+ c.b.Encrypt(s0[:], iv[:])
+ for i := 0; i < int(c.M); i++ {
+ tag[i] ^= s0[i]
+ }
+ iv[len(iv)-1] |= 1
+ stream := cipher.NewCTR(c.b, iv[:])
+ ret, out := sliceForAppend(dst, len(plaintext)+int(c.M))
+ stream.XORKeyStream(out, plaintext)
+ copy(out[len(plaintext):], tag)
+ return ret
+}
+
+var (
+ errOpen = errors.New("ccm: message authentication failed")
+ errCiphertextTooShort = errors.New("ccm: ciphertext too short")
+ errCiphertextTooLong = errors.New("ccm: ciphertext too long")
+)
+
+func (c *ccm) Open(dst, nonce, ciphertext, adata []byte) ([]byte, error) {
+ if len(ciphertext) < int(c.M) {
+ return nil, errCiphertextTooShort
+ }
+ if len(ciphertext) > c.MaxLength()+c.Overhead() {
+ return nil, errCiphertextTooLong
+ }
+
+ tag := make([]byte, int(c.M))
+ copy(tag, ciphertext[len(ciphertext)-int(c.M):])
+ ciphertextWithoutTag := ciphertext[:len(ciphertext)-int(c.M)]
+
+ var iv, s0 [ccmBlockSize]byte
+ iv[0] = c.L - 1
+ copy(iv[1:ccmBlockSize-c.L], nonce)
+ c.b.Encrypt(s0[:], iv[:])
+ for i := 0; i < int(c.M); i++ {
+ tag[i] ^= s0[i]
+ }
+ iv[len(iv)-1] |= 1
+ stream := cipher.NewCTR(c.b, iv[:])
+
+ // Cannot decrypt directly to dst since we're not supposed to
+ // reveal the plaintext to the caller if authentication fails.
+ plaintext := make([]byte, len(ciphertextWithoutTag))
+ stream.XORKeyStream(plaintext, ciphertextWithoutTag)
+ expectedTag, err := c.tag(nonce, plaintext, adata)
+ if err != nil {
+ return nil, err
+ }
+
+ if subtle.ConstantTimeCompare(tag, expectedTag) != 1 {
+ return nil, errOpen
+ }
+ return append(dst, plaintext...), nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/cbc.go b/vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/cbc.go
new file mode 100644
index 0000000..8ff1634
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/cbc.go
@@ -0,0 +1,164 @@
+package ciphersuite
+
+import ( //nolint:gci
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/hmac"
+ "crypto/rand"
+ "encoding/binary"
+ "hash"
+
+ "github.com/pion/dtls/v2/internal/util"
+ "github.com/pion/dtls/v2/pkg/crypto/prf"
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+)
+
+// block ciphers using cipher block chaining.
+type cbcMode interface {
+ cipher.BlockMode
+ SetIV([]byte)
+}
+
+// CBC Provides an API to Encrypt/Decrypt DTLS 1.2 Packets
+type CBC struct {
+ writeCBC, readCBC cbcMode
+ writeMac, readMac []byte
+ h prf.HashFunc
+}
+
+// NewCBC creates a DTLS CBC Cipher
+func NewCBC(localKey, localWriteIV, localMac, remoteKey, remoteWriteIV, remoteMac []byte, h prf.HashFunc) (*CBC, error) {
+ writeBlock, err := aes.NewCipher(localKey)
+ if err != nil {
+ return nil, err
+ }
+
+ readBlock, err := aes.NewCipher(remoteKey)
+ if err != nil {
+ return nil, err
+ }
+
+ return &CBC{
+ writeCBC: cipher.NewCBCEncrypter(writeBlock, localWriteIV).(cbcMode),
+ writeMac: localMac,
+
+ readCBC: cipher.NewCBCDecrypter(readBlock, remoteWriteIV).(cbcMode),
+ readMac: remoteMac,
+ h: h,
+ }, nil
+}
+
+// Encrypt encrypt a DTLS RecordLayer message
+func (c *CBC) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error) {
+ payload := raw[recordlayer.HeaderSize:]
+ raw = raw[:recordlayer.HeaderSize]
+ blockSize := c.writeCBC.BlockSize()
+
+ // Generate + Append MAC
+ h := pkt.Header
+
+ MAC, err := c.hmac(h.Epoch, h.SequenceNumber, h.ContentType, h.Version, payload, c.writeMac, c.h)
+ if err != nil {
+ return nil, err
+ }
+ payload = append(payload, MAC...)
+
+ // Generate + Append padding
+ padding := make([]byte, blockSize-len(payload)%blockSize)
+ paddingLen := len(padding)
+ for i := 0; i < paddingLen; i++ {
+ padding[i] = byte(paddingLen - 1)
+ }
+ payload = append(payload, padding...)
+
+ // Generate IV
+ iv := make([]byte, blockSize)
+ if _, err := rand.Read(iv); err != nil {
+ return nil, err
+ }
+
+ // Set IV + Encrypt + Prepend IV
+ c.writeCBC.SetIV(iv)
+ c.writeCBC.CryptBlocks(payload, payload)
+ payload = append(iv, payload...)
+
+ // Prepend unencrypte header with encrypted payload
+ raw = append(raw, payload...)
+
+ // Update recordLayer size to include IV+MAC+Padding
+ binary.BigEndian.PutUint16(raw[recordlayer.HeaderSize-2:], uint16(len(raw)-recordlayer.HeaderSize))
+
+ return raw, nil
+}
+
+// Decrypt decrypts a DTLS RecordLayer message
+func (c *CBC) Decrypt(in []byte) ([]byte, error) {
+ body := in[recordlayer.HeaderSize:]
+ blockSize := c.readCBC.BlockSize()
+ mac := c.h()
+
+ var h recordlayer.Header
+ err := h.Unmarshal(in)
+ switch {
+ case err != nil:
+ return nil, err
+ case h.ContentType == protocol.ContentTypeChangeCipherSpec:
+ // Nothing to encrypt with ChangeCipherSpec
+ return in, nil
+ case len(body)%blockSize != 0 || len(body) < blockSize+util.Max(mac.Size()+1, blockSize):
+ return nil, errNotEnoughRoomForNonce
+ }
+
+ // Set + remove per record IV
+ c.readCBC.SetIV(body[:blockSize])
+ body = body[blockSize:]
+
+ // Decrypt
+ c.readCBC.CryptBlocks(body, body)
+
+ // Padding+MAC needs to be checked in constant time
+ // Otherwise we reveal information about the level of correctness
+ paddingLen, paddingGood := examinePadding(body)
+ if paddingGood != 255 {
+ return nil, errInvalidMAC
+ }
+
+ macSize := mac.Size()
+ if len(body) < macSize {
+ return nil, errInvalidMAC
+ }
+
+ dataEnd := len(body) - macSize - paddingLen
+
+ expectedMAC := body[dataEnd : dataEnd+macSize]
+ actualMAC, err := c.hmac(h.Epoch, h.SequenceNumber, h.ContentType, h.Version, body[:dataEnd], c.readMac, c.h)
+
+ // Compute Local MAC and compare
+ if err != nil || !hmac.Equal(actualMAC, expectedMAC) {
+ return nil, errInvalidMAC
+ }
+
+ return append(in[:recordlayer.HeaderSize], body[:dataEnd]...), nil
+}
+
+func (c *CBC) hmac(epoch uint16, sequenceNumber uint64, contentType protocol.ContentType, protocolVersion protocol.Version, payload []byte, key []byte, hf func() hash.Hash) ([]byte, error) {
+ h := hmac.New(hf, key)
+
+ msg := make([]byte, 13)
+
+ binary.BigEndian.PutUint16(msg, epoch)
+ util.PutBigEndianUint48(msg[2:], sequenceNumber)
+ msg[8] = byte(contentType)
+ msg[9] = protocolVersion.Major
+ msg[10] = protocolVersion.Minor
+ binary.BigEndian.PutUint16(msg[11:], uint16(len(payload)))
+
+ if _, err := h.Write(msg); err != nil {
+ return nil, err
+ } else if _, err := h.Write(payload); err != nil {
+ return nil, err
+ }
+
+ return h.Sum(nil), nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/ccm.go b/vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/ccm.go
new file mode 100644
index 0000000..354b1cc
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/ccm.go
@@ -0,0 +1,104 @@
+package ciphersuite
+
+import (
+ "crypto/aes"
+ "crypto/rand"
+ "encoding/binary"
+ "fmt"
+
+ "github.com/pion/dtls/v2/pkg/crypto/ccm"
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+)
+
+// CCMTagLen is the length of Authentication Tag
+type CCMTagLen int
+
+// CCM Enums
+const (
+ CCMTagLength8 CCMTagLen = 8
+ CCMTagLength CCMTagLen = 16
+ ccmNonceLength = 12
+)
+
+// CCM Provides an API to Encrypt/Decrypt DTLS 1.2 Packets
+type CCM struct {
+ localCCM, remoteCCM ccm.CCM
+ localWriteIV, remoteWriteIV []byte
+ tagLen CCMTagLen
+}
+
+// NewCCM creates a DTLS GCM Cipher
+func NewCCM(tagLen CCMTagLen, localKey, localWriteIV, remoteKey, remoteWriteIV []byte) (*CCM, error) {
+ localBlock, err := aes.NewCipher(localKey)
+ if err != nil {
+ return nil, err
+ }
+ localCCM, err := ccm.NewCCM(localBlock, int(tagLen), ccmNonceLength)
+ if err != nil {
+ return nil, err
+ }
+
+ remoteBlock, err := aes.NewCipher(remoteKey)
+ if err != nil {
+ return nil, err
+ }
+ remoteCCM, err := ccm.NewCCM(remoteBlock, int(tagLen), ccmNonceLength)
+ if err != nil {
+ return nil, err
+ }
+
+ return &CCM{
+ localCCM: localCCM,
+ localWriteIV: localWriteIV,
+ remoteCCM: remoteCCM,
+ remoteWriteIV: remoteWriteIV,
+ tagLen: tagLen,
+ }, nil
+}
+
+// Encrypt encrypt a DTLS RecordLayer message
+func (c *CCM) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error) {
+ payload := raw[recordlayer.HeaderSize:]
+ raw = raw[:recordlayer.HeaderSize]
+
+ nonce := append(append([]byte{}, c.localWriteIV[:4]...), make([]byte, 8)...)
+ if _, err := rand.Read(nonce[4:]); err != nil {
+ return nil, err
+ }
+
+ additionalData := generateAEADAdditionalData(&pkt.Header, len(payload))
+ encryptedPayload := c.localCCM.Seal(nil, nonce, payload, additionalData)
+
+ encryptedPayload = append(nonce[4:], encryptedPayload...)
+ raw = append(raw, encryptedPayload...)
+
+ // Update recordLayer size to include explicit nonce
+ binary.BigEndian.PutUint16(raw[recordlayer.HeaderSize-2:], uint16(len(raw)-recordlayer.HeaderSize))
+ return raw, nil
+}
+
+// Decrypt decrypts a DTLS RecordLayer message
+func (c *CCM) Decrypt(in []byte) ([]byte, error) {
+ var h recordlayer.Header
+ err := h.Unmarshal(in)
+ switch {
+ case err != nil:
+ return nil, err
+ case h.ContentType == protocol.ContentTypeChangeCipherSpec:
+ // Nothing to encrypt with ChangeCipherSpec
+ return in, nil
+ case len(in) <= (8 + recordlayer.HeaderSize):
+ return nil, errNotEnoughRoomForNonce
+ }
+
+ nonce := append(append([]byte{}, c.remoteWriteIV[:4]...), in[recordlayer.HeaderSize:recordlayer.HeaderSize+8]...)
+ out := in[recordlayer.HeaderSize+8:]
+
+ additionalData := generateAEADAdditionalData(&h, len(out)-int(c.tagLen))
+ out, err = c.remoteCCM.Open(out[:0], nonce, out, additionalData)
+ if err != nil {
+ return nil, fmt.Errorf("%w: %v", errDecryptPacket, err)
+ }
+ return append(in[:recordlayer.HeaderSize], out...), nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/ciphersuite.go b/vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/ciphersuite.go
new file mode 100644
index 0000000..72beffd
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/ciphersuite.go
@@ -0,0 +1,72 @@
+// Package ciphersuite provides the crypto operations needed for a DTLS CipherSuite
+package ciphersuite
+
+import (
+ "encoding/binary"
+ "errors"
+
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+)
+
+var (
+ errNotEnoughRoomForNonce = &protocol.InternalError{Err: errors.New("buffer not long enough to contain nonce")} //nolint:goerr113
+ errDecryptPacket = &protocol.TemporaryError{Err: errors.New("failed to decrypt packet")} //nolint:goerr113
+ errInvalidMAC = &protocol.TemporaryError{Err: errors.New("invalid mac")} //nolint:goerr113
+)
+
+func generateAEADAdditionalData(h *recordlayer.Header, payloadLen int) []byte {
+ var additionalData [13]byte
+ // SequenceNumber MUST be set first
+ // we only want uint48, clobbering an extra 2 (using uint64, Golang doesn't have uint48)
+ binary.BigEndian.PutUint64(additionalData[:], h.SequenceNumber)
+ binary.BigEndian.PutUint16(additionalData[:], h.Epoch)
+ additionalData[8] = byte(h.ContentType)
+ additionalData[9] = h.Version.Major
+ additionalData[10] = h.Version.Minor
+ binary.BigEndian.PutUint16(additionalData[len(additionalData)-2:], uint16(payloadLen))
+
+ return additionalData[:]
+}
+
+// examinePadding returns, in constant time, the length of the padding to remove
+// from the end of payload. It also returns a byte which is equal to 255 if the
+// padding was valid and 0 otherwise. See RFC 2246, Section 6.2.3.2.
+//
+// https://github.com/golang/go/blob/039c2081d1178f90a8fa2f4e6958693129f8de33/src/crypto/tls/conn.go#L245
+func examinePadding(payload []byte) (toRemove int, good byte) {
+ if len(payload) < 1 {
+ return 0, 0
+ }
+
+ paddingLen := payload[len(payload)-1]
+ t := uint(len(payload)-1) - uint(paddingLen)
+ // if len(payload) >= (paddingLen - 1) then the MSB of t is zero
+ good = byte(int32(^t) >> 31)
+
+ // The maximum possible padding length plus the actual length field
+ toCheck := 256
+ // The length of the padded data is public, so we can use an if here
+ if toCheck > len(payload) {
+ toCheck = len(payload)
+ }
+
+ for i := 0; i < toCheck; i++ {
+ t := uint(paddingLen) - uint(i)
+ // if i <= paddingLen then the MSB of t is zero
+ mask := byte(int32(^t) >> 31)
+ b := payload[len(payload)-1-i]
+ good &^= mask&paddingLen ^ mask&b
+ }
+
+ // We AND together the bits of good and replicate the result across
+ // all the bits.
+ good &= good << 4
+ good &= good << 2
+ good &= good << 1
+ good = uint8(int8(good) >> 7)
+
+ toRemove = int(paddingLen) + 1
+
+ return toRemove, good
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/gcm.go b/vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/gcm.go
new file mode 100644
index 0000000..af986d4
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/gcm.go
@@ -0,0 +1,100 @@
+package ciphersuite
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/rand"
+ "encoding/binary"
+ "fmt"
+
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
+)
+
+const (
+ gcmTagLength = 16
+ gcmNonceLength = 12
+)
+
+// GCM Provides an API to Encrypt/Decrypt DTLS 1.2 Packets
+type GCM struct {
+ localGCM, remoteGCM cipher.AEAD
+ localWriteIV, remoteWriteIV []byte
+}
+
+// NewGCM creates a DTLS GCM Cipher
+func NewGCM(localKey, localWriteIV, remoteKey, remoteWriteIV []byte) (*GCM, error) {
+ localBlock, err := aes.NewCipher(localKey)
+ if err != nil {
+ return nil, err
+ }
+ localGCM, err := cipher.NewGCM(localBlock)
+ if err != nil {
+ return nil, err
+ }
+
+ remoteBlock, err := aes.NewCipher(remoteKey)
+ if err != nil {
+ return nil, err
+ }
+ remoteGCM, err := cipher.NewGCM(remoteBlock)
+ if err != nil {
+ return nil, err
+ }
+
+ return &GCM{
+ localGCM: localGCM,
+ localWriteIV: localWriteIV,
+ remoteGCM: remoteGCM,
+ remoteWriteIV: remoteWriteIV,
+ }, nil
+}
+
+// Encrypt encrypt a DTLS RecordLayer message
+func (g *GCM) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error) {
+ payload := raw[recordlayer.HeaderSize:]
+ raw = raw[:recordlayer.HeaderSize]
+
+ nonce := make([]byte, gcmNonceLength)
+ copy(nonce, g.localWriteIV[:4])
+ if _, err := rand.Read(nonce[4:]); err != nil {
+ return nil, err
+ }
+
+ additionalData := generateAEADAdditionalData(&pkt.Header, len(payload))
+ encryptedPayload := g.localGCM.Seal(nil, nonce, payload, additionalData)
+ r := make([]byte, len(raw)+len(nonce[4:])+len(encryptedPayload))
+ copy(r, raw)
+ copy(r[len(raw):], nonce[4:])
+ copy(r[len(raw)+len(nonce[4:]):], encryptedPayload)
+
+ // Update recordLayer size to include explicit nonce
+ binary.BigEndian.PutUint16(r[recordlayer.HeaderSize-2:], uint16(len(r)-recordlayer.HeaderSize))
+ return r, nil
+}
+
+// Decrypt decrypts a DTLS RecordLayer message
+func (g *GCM) Decrypt(in []byte) ([]byte, error) {
+ var h recordlayer.Header
+ err := h.Unmarshal(in)
+ switch {
+ case err != nil:
+ return nil, err
+ case h.ContentType == protocol.ContentTypeChangeCipherSpec:
+ // Nothing to encrypt with ChangeCipherSpec
+ return in, nil
+ case len(in) <= (8 + recordlayer.HeaderSize):
+ return nil, errNotEnoughRoomForNonce
+ }
+
+ nonce := make([]byte, 0, gcmNonceLength)
+ nonce = append(append(nonce, g.remoteWriteIV[:4]...), in[recordlayer.HeaderSize:recordlayer.HeaderSize+8]...)
+ out := in[recordlayer.HeaderSize+8:]
+
+ additionalData := generateAEADAdditionalData(&h, len(out)-gcmTagLength)
+ out, err = g.remoteGCM.Open(out[:0], nonce, out, additionalData)
+ if err != nil {
+ return nil, fmt.Errorf("%w: %v", errDecryptPacket, err)
+ }
+ return append(in[:recordlayer.HeaderSize], out...), nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/crypto/clientcertificate/client_certificate.go b/vendor/github.com/pion/dtls/v2/pkg/crypto/clientcertificate/client_certificate.go
new file mode 100644
index 0000000..c222c01
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/crypto/clientcertificate/client_certificate.go
@@ -0,0 +1,22 @@
+// Package clientcertificate provides all the support Client Certificate types
+package clientcertificate
+
+// Type is used to communicate what
+// type of certificate is being transported
+//
+//https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-2
+type Type byte
+
+// ClientCertificateType enums
+const (
+ RSASign Type = 1
+ ECDSASign Type = 64
+)
+
+// Types returns all valid ClientCertificate Types
+func Types() map[Type]bool {
+ return map[Type]bool{
+ RSASign: true,
+ ECDSASign: true,
+ }
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/crypto/elliptic/elliptic.go b/vendor/github.com/pion/dtls/v2/pkg/crypto/elliptic/elliptic.go
new file mode 100644
index 0000000..5b0e4fa
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/crypto/elliptic/elliptic.go
@@ -0,0 +1,99 @@
+// Package elliptic provides elliptic curve cryptography for DTLS
+package elliptic
+
+import (
+ "crypto/elliptic"
+ "crypto/rand"
+ "errors"
+
+ "golang.org/x/crypto/curve25519"
+)
+
+var errInvalidNamedCurve = errors.New("invalid named curve")
+
+// CurvePointFormat is used to represent the IANA registered curve points
+//
+// https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
+type CurvePointFormat byte
+
+// CurvePointFormat enums
+const (
+ CurvePointFormatUncompressed CurvePointFormat = 0
+)
+
+// Keypair is a Curve with a Private/Public Keypair
+type Keypair struct {
+ Curve Curve
+ PublicKey []byte
+ PrivateKey []byte
+}
+
+// CurveType is used to represent the IANA registered curve types for TLS
+//
+// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-10
+type CurveType byte
+
+// CurveType enums
+const (
+ CurveTypeNamedCurve CurveType = 0x03
+)
+
+// CurveTypes returns all known curves
+func CurveTypes() map[CurveType]struct{} {
+ return map[CurveType]struct{}{
+ CurveTypeNamedCurve: {},
+ }
+}
+
+// Curve is used to represent the IANA registered curves for TLS
+//
+// https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
+type Curve uint16
+
+// Curve enums
+const (
+ P256 Curve = 0x0017
+ P384 Curve = 0x0018
+ X25519 Curve = 0x001d
+)
+
+// Curves returns all curves we implement
+func Curves() map[Curve]bool {
+ return map[Curve]bool{
+ X25519: true,
+ P256: true,
+ P384: true,
+ }
+}
+
+// GenerateKeypair generates a keypair for the given Curve
+func GenerateKeypair(c Curve) (*Keypair, error) {
+ switch c { //nolint:golint
+ case X25519:
+ tmp := make([]byte, 32)
+ if _, err := rand.Read(tmp); err != nil {
+ return nil, err
+ }
+
+ var public, private [32]byte
+ copy(private[:], tmp)
+
+ curve25519.ScalarBaseMult(&public, &private)
+ return &Keypair{X25519, public[:], private[:]}, nil
+ case P256:
+ return ellipticCurveKeypair(P256, elliptic.P256(), elliptic.P256())
+ case P384:
+ return ellipticCurveKeypair(P384, elliptic.P384(), elliptic.P384())
+ default:
+ return nil, errInvalidNamedCurve
+ }
+}
+
+func ellipticCurveKeypair(nc Curve, c1, c2 elliptic.Curve) (*Keypair, error) {
+ privateKey, x, y, err := elliptic.GenerateKey(c1, rand.Reader)
+ if err != nil {
+ return nil, err
+ }
+
+ return &Keypair{nc, elliptic.Marshal(c2, x, y), privateKey}, nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/crypto/fingerprint/fingerprint.go b/vendor/github.com/pion/dtls/v2/pkg/crypto/fingerprint/fingerprint.go
new file mode 100644
index 0000000..215b44e
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/crypto/fingerprint/fingerprint.go
@@ -0,0 +1,50 @@
+// Package fingerprint provides a helper to create fingerprint string from certificate
+package fingerprint
+
+import (
+ "crypto"
+ "crypto/x509"
+ "errors"
+ "fmt"
+)
+
+var (
+ errHashUnavailable = errors.New("fingerprint: hash algorithm is not linked into the binary")
+ errInvalidFingerprintLength = errors.New("fingerprint: invalid fingerprint length")
+)
+
+// Fingerprint creates a fingerprint for a certificate using the specified hash algorithm
+func Fingerprint(cert *x509.Certificate, algo crypto.Hash) (string, error) {
+ if !algo.Available() {
+ return "", errHashUnavailable
+ }
+ h := algo.New()
+ for i := 0; i < len(cert.Raw); {
+ n, _ := h.Write(cert.Raw[i:])
+ // Hash.Writer is specified to be never returning an error.
+ // https://golang.org/pkg/hash/#Hash
+ i += n
+ }
+ digest := []byte(fmt.Sprintf("%x", h.Sum(nil)))
+
+ digestlen := len(digest)
+ if digestlen == 0 {
+ return "", nil
+ }
+ if digestlen%2 != 0 {
+ return "", errInvalidFingerprintLength
+ }
+ res := make([]byte, digestlen>>1+digestlen-1)
+
+ pos := 0
+ for i, c := range digest {
+ res[pos] = c
+ pos++
+ if (i)%2 != 0 && i < digestlen-1 {
+ res[pos] = byte(':')
+ pos++
+ }
+ }
+
+ return string(res), nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/crypto/fingerprint/hash.go b/vendor/github.com/pion/dtls/v2/pkg/crypto/fingerprint/hash.go
new file mode 100644
index 0000000..09107db
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/crypto/fingerprint/hash.go
@@ -0,0 +1,37 @@
+package fingerprint
+
+import (
+ "crypto"
+ "errors"
+)
+
+var errInvalidHashAlgorithm = errors.New("fingerprint: invalid hash algorithm")
+
+func nameToHash() map[string]crypto.Hash {
+ return map[string]crypto.Hash{
+ "md5": crypto.MD5, // [RFC3279]
+ "sha-1": crypto.SHA1, // [RFC3279]
+ "sha-224": crypto.SHA224, // [RFC4055]
+ "sha-256": crypto.SHA256, // [RFC4055]
+ "sha-384": crypto.SHA384, // [RFC4055]
+ "sha-512": crypto.SHA512, // [RFC4055]
+ }
+}
+
+// HashFromString allows looking up a hash algorithm by it's string representation
+func HashFromString(s string) (crypto.Hash, error) {
+ if h, ok := nameToHash()[s]; ok {
+ return h, nil
+ }
+ return 0, errInvalidHashAlgorithm
+}
+
+// StringFromHash allows looking up a string representation of the crypto.Hash.
+func StringFromHash(hash crypto.Hash) (string, error) {
+ for s, h := range nameToHash() {
+ if h == hash {
+ return s, nil
+ }
+ }
+ return "", errInvalidHashAlgorithm
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/crypto/hash/hash.go b/vendor/github.com/pion/dtls/v2/pkg/crypto/hash/hash.go
new file mode 100644
index 0000000..660326f
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/crypto/hash/hash.go
@@ -0,0 +1,126 @@
+// Package hash provides TLS HashAlgorithm as defined in TLS 1.2
+package hash
+
+import ( //nolint:gci
+ "crypto"
+ "crypto/md5" //nolint:gosec
+ "crypto/sha1" //nolint:gosec
+ "crypto/sha256"
+ "crypto/sha512"
+)
+
+// Algorithm is used to indicate the hash algorithm used
+// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-18
+type Algorithm uint16
+
+// Supported hash algorithms
+const (
+ None Algorithm = 0 // Blacklisted
+ MD5 Algorithm = 1 // Blacklisted
+ SHA1 Algorithm = 2 // Blacklisted
+ SHA224 Algorithm = 3
+ SHA256 Algorithm = 4
+ SHA384 Algorithm = 5
+ SHA512 Algorithm = 6
+ Ed25519 Algorithm = 8
+)
+
+// String makes hashAlgorithm printable
+func (a Algorithm) String() string {
+ switch a {
+ case None:
+ return "none"
+ case MD5:
+ return "md5" // [RFC3279]
+ case SHA1:
+ return "sha-1" // [RFC3279]
+ case SHA224:
+ return "sha-224" // [RFC4055]
+ case SHA256:
+ return "sha-256" // [RFC4055]
+ case SHA384:
+ return "sha-384" // [RFC4055]
+ case SHA512:
+ return "sha-512" // [RFC4055]
+ case Ed25519:
+ return "null"
+ default:
+ return "unknown or unsupported hash algorithm"
+ }
+}
+
+// Digest performs a digest on the passed value
+func (a Algorithm) Digest(b []byte) []byte {
+ switch a {
+ case None:
+ return nil
+ case MD5:
+ hash := md5.Sum(b) // #nosec
+ return hash[:]
+ case SHA1:
+ hash := sha1.Sum(b) // #nosec
+ return hash[:]
+ case SHA224:
+ hash := sha256.Sum224(b)
+ return hash[:]
+ case SHA256:
+ hash := sha256.Sum256(b)
+ return hash[:]
+ case SHA384:
+ hash := sha512.Sum384(b)
+ return hash[:]
+ case SHA512:
+ hash := sha512.Sum512(b)
+ return hash[:]
+ default:
+ return nil
+ }
+}
+
+// Insecure returns if the given HashAlgorithm is considered secure in DTLS 1.2
+func (a Algorithm) Insecure() bool {
+ switch a {
+ case None, MD5, SHA1:
+ return true
+ default:
+ return false
+ }
+}
+
+// CryptoHash returns the crypto.Hash implementation for the given HashAlgorithm
+func (a Algorithm) CryptoHash() crypto.Hash {
+ switch a {
+ case None:
+ return crypto.Hash(0)
+ case MD5:
+ return crypto.MD5
+ case SHA1:
+ return crypto.SHA1
+ case SHA224:
+ return crypto.SHA224
+ case SHA256:
+ return crypto.SHA256
+ case SHA384:
+ return crypto.SHA384
+ case SHA512:
+ return crypto.SHA512
+ case Ed25519:
+ return crypto.Hash(0)
+ default:
+ return crypto.Hash(0)
+ }
+}
+
+// Algorithms returns all the supported Hash Algorithms
+func Algorithms() map[Algorithm]struct{} {
+ return map[Algorithm]struct{}{
+ None: {},
+ MD5: {},
+ SHA1: {},
+ SHA224: {},
+ SHA256: {},
+ SHA384: {},
+ SHA512: {},
+ Ed25519: {},
+ }
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/crypto/prf/prf.go b/vendor/github.com/pion/dtls/v2/pkg/crypto/prf/prf.go
new file mode 100644
index 0000000..d33df19
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/crypto/prf/prf.go
@@ -0,0 +1,224 @@
+// Package prf implements TLS 1.2 Pseudorandom functions
+package prf
+
+import ( //nolint:gci
+ ellipticStdlib "crypto/elliptic"
+ "crypto/hmac"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "hash"
+ "math"
+
+ "github.com/pion/dtls/v2/pkg/crypto/elliptic"
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "golang.org/x/crypto/curve25519"
+)
+
+const (
+ masterSecretLabel = "master secret"
+ extendedMasterSecretLabel = "extended master secret"
+ keyExpansionLabel = "key expansion"
+ verifyDataClientLabel = "client finished"
+ verifyDataServerLabel = "server finished"
+)
+
+// HashFunc allows callers to decide what hash is used in PRF
+type HashFunc func() hash.Hash
+
+// EncryptionKeys is all the state needed for a TLS CipherSuite
+type EncryptionKeys struct {
+ MasterSecret []byte
+ ClientMACKey []byte
+ ServerMACKey []byte
+ ClientWriteKey []byte
+ ServerWriteKey []byte
+ ClientWriteIV []byte
+ ServerWriteIV []byte
+}
+
+var errInvalidNamedCurve = &protocol.FatalError{Err: errors.New("invalid named curve")} //nolint:goerr113
+
+func (e *EncryptionKeys) String() string {
+ return fmt.Sprintf(`encryptionKeys:
+- masterSecret: %#v
+- clientMACKey: %#v
+- serverMACKey: %#v
+- clientWriteKey: %#v
+- serverWriteKey: %#v
+- clientWriteIV: %#v
+- serverWriteIV: %#v
+`,
+ e.MasterSecret,
+ e.ClientMACKey,
+ e.ServerMACKey,
+ e.ClientWriteKey,
+ e.ServerWriteKey,
+ e.ClientWriteIV,
+ e.ServerWriteIV)
+}
+
+// PSKPreMasterSecret generates the PSK Premaster Secret
+// The premaster secret is formed as follows: if the PSK is N octets
+// long, concatenate a uint16 with the value N, N zero octets, a second
+// uint16 with the value N, and the PSK itself.
+//
+// https://tools.ietf.org/html/rfc4279#section-2
+func PSKPreMasterSecret(psk []byte) []byte {
+ pskLen := uint16(len(psk))
+
+ out := append(make([]byte, 2+pskLen+2), psk...)
+ binary.BigEndian.PutUint16(out, pskLen)
+ binary.BigEndian.PutUint16(out[2+pskLen:], pskLen)
+
+ return out
+}
+
+// PreMasterSecret implements TLS 1.2 Premaster Secret generation given a keypair and a curve
+func PreMasterSecret(publicKey, privateKey []byte, curve elliptic.Curve) ([]byte, error) {
+ switch curve {
+ case elliptic.X25519:
+ return curve25519.X25519(privateKey, publicKey)
+ case elliptic.P256:
+ return ellipticCurvePreMasterSecret(publicKey, privateKey, ellipticStdlib.P256(), ellipticStdlib.P256())
+ case elliptic.P384:
+ return ellipticCurvePreMasterSecret(publicKey, privateKey, ellipticStdlib.P384(), ellipticStdlib.P384())
+ default:
+ return nil, errInvalidNamedCurve
+ }
+}
+
+func ellipticCurvePreMasterSecret(publicKey, privateKey []byte, c1, c2 ellipticStdlib.Curve) ([]byte, error) {
+ x, y := ellipticStdlib.Unmarshal(c1, publicKey)
+ if x == nil || y == nil {
+ return nil, errInvalidNamedCurve
+ }
+
+ result, _ := c2.ScalarMult(x, y, privateKey)
+ preMasterSecret := make([]byte, (c2.Params().BitSize+7)>>3)
+ resultBytes := result.Bytes()
+ copy(preMasterSecret[len(preMasterSecret)-len(resultBytes):], resultBytes)
+ return preMasterSecret, nil
+}
+
+// PHash is PRF is the SHA-256 hash function is used for all cipher suites
+// defined in this TLS 1.2 document and in TLS documents published prior to this
+// document when TLS 1.2 is negotiated. New cipher suites MUST explicitly
+// specify a PRF and, in general, SHOULD use the TLS PRF with SHA-256 or a
+// stronger standard hash function.
+//
+// P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
+// HMAC_hash(secret, A(2) + seed) +
+// HMAC_hash(secret, A(3) + seed) + ...
+//
+// A() is defined as:
+//
+// A(0) = seed
+// A(i) = HMAC_hash(secret, A(i-1))
+//
+// P_hash can be iterated as many times as necessary to produce the
+// required quantity of data. For example, if P_SHA256 is being used to
+// create 80 bytes of data, it will have to be iterated three times
+// (through A(3)), creating 96 bytes of output data; the last 16 bytes
+// of the final iteration will then be discarded, leaving 80 bytes of
+// output data.
+//
+// https://tools.ietf.org/html/rfc4346w
+func PHash(secret, seed []byte, requestedLength int, h HashFunc) ([]byte, error) {
+ hmacSHA256 := func(key, data []byte) ([]byte, error) {
+ mac := hmac.New(h, key)
+ if _, err := mac.Write(data); err != nil {
+ return nil, err
+ }
+ return mac.Sum(nil), nil
+ }
+
+ var err error
+ lastRound := seed
+ out := []byte{}
+
+ iterations := int(math.Ceil(float64(requestedLength) / float64(h().Size())))
+ for i := 0; i < iterations; i++ {
+ lastRound, err = hmacSHA256(secret, lastRound)
+ if err != nil {
+ return nil, err
+ }
+ withSecret, err := hmacSHA256(secret, append(lastRound, seed...))
+ if err != nil {
+ return nil, err
+ }
+ out = append(out, withSecret...)
+ }
+
+ return out[:requestedLength], nil
+}
+
+// ExtendedMasterSecret generates a Extended MasterSecret as defined in
+// https://tools.ietf.org/html/rfc7627
+func ExtendedMasterSecret(preMasterSecret, sessionHash []byte, h HashFunc) ([]byte, error) {
+ seed := append([]byte(extendedMasterSecretLabel), sessionHash...)
+ return PHash(preMasterSecret, seed, 48, h)
+}
+
+// MasterSecret generates a TLS 1.2 MasterSecret
+func MasterSecret(preMasterSecret, clientRandom, serverRandom []byte, h HashFunc) ([]byte, error) {
+ seed := append(append([]byte(masterSecretLabel), clientRandom...), serverRandom...)
+ return PHash(preMasterSecret, seed, 48, h)
+}
+
+// GenerateEncryptionKeys is the final step TLS 1.2 PRF. Given all state generated so far generates
+// the final keys need for encryption
+func GenerateEncryptionKeys(masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int, h HashFunc) (*EncryptionKeys, error) {
+ seed := append(append([]byte(keyExpansionLabel), serverRandom...), clientRandom...)
+ keyMaterial, err := PHash(masterSecret, seed, (2*macLen)+(2*keyLen)+(2*ivLen), h)
+ if err != nil {
+ return nil, err
+ }
+
+ clientMACKey := keyMaterial[:macLen]
+ keyMaterial = keyMaterial[macLen:]
+
+ serverMACKey := keyMaterial[:macLen]
+ keyMaterial = keyMaterial[macLen:]
+
+ clientWriteKey := keyMaterial[:keyLen]
+ keyMaterial = keyMaterial[keyLen:]
+
+ serverWriteKey := keyMaterial[:keyLen]
+ keyMaterial = keyMaterial[keyLen:]
+
+ clientWriteIV := keyMaterial[:ivLen]
+ keyMaterial = keyMaterial[ivLen:]
+
+ serverWriteIV := keyMaterial[:ivLen]
+
+ return &EncryptionKeys{
+ MasterSecret: masterSecret,
+ ClientMACKey: clientMACKey,
+ ServerMACKey: serverMACKey,
+ ClientWriteKey: clientWriteKey,
+ ServerWriteKey: serverWriteKey,
+ ClientWriteIV: clientWriteIV,
+ ServerWriteIV: serverWriteIV,
+ }, nil
+}
+
+func prfVerifyData(masterSecret, handshakeBodies []byte, label string, hashFunc HashFunc) ([]byte, error) {
+ h := hashFunc()
+ if _, err := h.Write(handshakeBodies); err != nil {
+ return nil, err
+ }
+
+ seed := append([]byte(label), h.Sum(nil)...)
+ return PHash(masterSecret, seed, 12, hashFunc)
+}
+
+// VerifyDataClient is caled on the Client Side to either verify or generate the VerifyData message
+func VerifyDataClient(masterSecret, handshakeBodies []byte, h HashFunc) ([]byte, error) {
+ return prfVerifyData(masterSecret, handshakeBodies, verifyDataClientLabel, h)
+}
+
+// VerifyDataServer is caled on the Server Side to either verify or generate the VerifyData message
+func VerifyDataServer(masterSecret, handshakeBodies []byte, h HashFunc) ([]byte, error) {
+ return prfVerifyData(masterSecret, handshakeBodies, verifyDataServerLabel, h)
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/crypto/signature/signature.go b/vendor/github.com/pion/dtls/v2/pkg/crypto/signature/signature.go
new file mode 100644
index 0000000..d9150eb
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/crypto/signature/signature.go
@@ -0,0 +1,24 @@
+// Package signature provides our implemented Signature Algorithms
+package signature
+
+// Algorithm as defined in TLS 1.2
+// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-16
+type Algorithm uint16
+
+// SignatureAlgorithm enums
+const (
+ Anonymous Algorithm = 0
+ RSA Algorithm = 1
+ ECDSA Algorithm = 3
+ Ed25519 Algorithm = 7
+)
+
+// Algorithms returns all implemented Signature Algorithms
+func Algorithms() map[Algorithm]struct{} {
+ return map[Algorithm]struct{}{
+ Anonymous: {},
+ RSA: {},
+ ECDSA: {},
+ Ed25519: {},
+ }
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/crypto/signaturehash/errors.go b/vendor/github.com/pion/dtls/v2/pkg/crypto/signaturehash/errors.go
new file mode 100644
index 0000000..9d9d3b3
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/crypto/signaturehash/errors.go
@@ -0,0 +1,9 @@
+package signaturehash
+
+import "errors"
+
+var (
+ errNoAvailableSignatureSchemes = errors.New("connection can not be created, no SignatureScheme satisfy this Config")
+ errInvalidSignatureAlgorithm = errors.New("invalid signature algorithm")
+ errInvalidHashAlgorithm = errors.New("invalid hash algorithm")
+)
diff --git a/vendor/github.com/pion/dtls/v2/pkg/crypto/signaturehash/signaturehash.go b/vendor/github.com/pion/dtls/v2/pkg/crypto/signaturehash/signaturehash.go
new file mode 100644
index 0000000..f2017bc
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/crypto/signaturehash/signaturehash.go
@@ -0,0 +1,93 @@
+// Package signaturehash provides the SignatureHashAlgorithm as defined in TLS 1.2
+package signaturehash
+
+import (
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/rsa"
+ "crypto/tls"
+
+ "github.com/pion/dtls/v2/pkg/crypto/hash"
+ "github.com/pion/dtls/v2/pkg/crypto/signature"
+ "golang.org/x/xerrors"
+)
+
+// Algorithm is a signature/hash algorithm pairs which may be used in
+// digital signatures.
+//
+// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+type Algorithm struct {
+ Hash hash.Algorithm
+ Signature signature.Algorithm
+}
+
+// Algorithms are all the know SignatureHash Algorithms
+func Algorithms() []Algorithm {
+ return []Algorithm{
+ {hash.SHA256, signature.ECDSA},
+ {hash.SHA384, signature.ECDSA},
+ {hash.SHA512, signature.ECDSA},
+ {hash.SHA256, signature.RSA},
+ {hash.SHA384, signature.RSA},
+ {hash.SHA512, signature.RSA},
+ {hash.Ed25519, signature.Ed25519},
+ }
+}
+
+// SelectSignatureScheme returns most preferred and compatible scheme.
+func SelectSignatureScheme(sigs []Algorithm, privateKey crypto.PrivateKey) (Algorithm, error) {
+ for _, ss := range sigs {
+ if ss.isCompatible(privateKey) {
+ return ss, nil
+ }
+ }
+ return Algorithm{}, errNoAvailableSignatureSchemes
+}
+
+// isCompatible checks that given private key is compatible with the signature scheme.
+func (a *Algorithm) isCompatible(privateKey crypto.PrivateKey) bool {
+ switch privateKey.(type) {
+ case ed25519.PrivateKey:
+ return a.Signature == signature.Ed25519
+ case *ecdsa.PrivateKey:
+ return a.Signature == signature.ECDSA
+ case *rsa.PrivateKey:
+ return a.Signature == signature.RSA
+ default:
+ return false
+ }
+}
+
+// ParseSignatureSchemes translates []tls.SignatureScheme to []signatureHashAlgorithm.
+// It returns default signature scheme list if no SignatureScheme is passed.
+func ParseSignatureSchemes(sigs []tls.SignatureScheme, insecureHashes bool) ([]Algorithm, error) {
+ if len(sigs) == 0 {
+ return Algorithms(), nil
+ }
+ out := []Algorithm{}
+ for _, ss := range sigs {
+ sig := signature.Algorithm(ss & 0xFF)
+ if _, ok := signature.Algorithms()[sig]; !ok {
+ return nil,
+ xerrors.Errorf("SignatureScheme %04x: %w", ss, errInvalidSignatureAlgorithm)
+ }
+ h := hash.Algorithm(ss >> 8)
+ if _, ok := hash.Algorithms()[h]; !ok || (ok && h == hash.None) {
+ return nil, xerrors.Errorf("SignatureScheme %04x: %w", ss, errInvalidHashAlgorithm)
+ }
+ if h.Insecure() && !insecureHashes {
+ continue
+ }
+ out = append(out, Algorithm{
+ Hash: h,
+ Signature: sig,
+ })
+ }
+
+ if len(out) == 0 {
+ return nil, errNoAvailableSignatureSchemes
+ }
+
+ return out, nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/alert/alert.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/alert/alert.go
new file mode 100644
index 0000000..9eb2e6a
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/alert/alert.go
@@ -0,0 +1,160 @@
+// Package alert implements TLS alert protocol https://tools.ietf.org/html/rfc5246#section-7.2
+package alert
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/pion/dtls/v2/pkg/protocol"
+)
+
+var errBufferTooSmall = &protocol.TemporaryError{Err: errors.New("buffer is too small")} //nolint:goerr113
+
+// Level is the level of the TLS Alert
+type Level byte
+
+// Level enums
+const (
+ Warning Level = 1
+ Fatal Level = 2
+)
+
+func (l Level) String() string {
+ switch l {
+ case Warning:
+ return "Warning"
+ case Fatal:
+ return "Fatal"
+ default:
+ return "Invalid alert level"
+ }
+}
+
+// Description is the extended info of the TLS Alert
+type Description byte
+
+// Description enums
+const (
+ CloseNotify Description = 0
+ UnexpectedMessage Description = 10
+ BadRecordMac Description = 20
+ DecryptionFailed Description = 21
+ RecordOverflow Description = 22
+ DecompressionFailure Description = 30
+ HandshakeFailure Description = 40
+ NoCertificate Description = 41
+ BadCertificate Description = 42
+ UnsupportedCertificate Description = 43
+ CertificateRevoked Description = 44
+ CertificateExpired Description = 45
+ CertificateUnknown Description = 46
+ IllegalParameter Description = 47
+ UnknownCA Description = 48
+ AccessDenied Description = 49
+ DecodeError Description = 50
+ DecryptError Description = 51
+ ExportRestriction Description = 60
+ ProtocolVersion Description = 70
+ InsufficientSecurity Description = 71
+ InternalError Description = 80
+ UserCanceled Description = 90
+ NoRenegotiation Description = 100
+ UnsupportedExtension Description = 110
+)
+
+func (d Description) String() string {
+ switch d {
+ case CloseNotify:
+ return "CloseNotify"
+ case UnexpectedMessage:
+ return "UnexpectedMessage"
+ case BadRecordMac:
+ return "BadRecordMac"
+ case DecryptionFailed:
+ return "DecryptionFailed"
+ case RecordOverflow:
+ return "RecordOverflow"
+ case DecompressionFailure:
+ return "DecompressionFailure"
+ case HandshakeFailure:
+ return "HandshakeFailure"
+ case NoCertificate:
+ return "NoCertificate"
+ case BadCertificate:
+ return "BadCertificate"
+ case UnsupportedCertificate:
+ return "UnsupportedCertificate"
+ case CertificateRevoked:
+ return "CertificateRevoked"
+ case CertificateExpired:
+ return "CertificateExpired"
+ case CertificateUnknown:
+ return "CertificateUnknown"
+ case IllegalParameter:
+ return "IllegalParameter"
+ case UnknownCA:
+ return "UnknownCA"
+ case AccessDenied:
+ return "AccessDenied"
+ case DecodeError:
+ return "DecodeError"
+ case DecryptError:
+ return "DecryptError"
+ case ExportRestriction:
+ return "ExportRestriction"
+ case ProtocolVersion:
+ return "ProtocolVersion"
+ case InsufficientSecurity:
+ return "InsufficientSecurity"
+ case InternalError:
+ return "InternalError"
+ case UserCanceled:
+ return "UserCanceled"
+ case NoRenegotiation:
+ return "NoRenegotiation"
+ case UnsupportedExtension:
+ return "UnsupportedExtension"
+ default:
+ return "Invalid alert description"
+ }
+}
+
+// Alert is one of the content types supported by the TLS record layer.
+// Alert messages convey the severity of the message
+// (warning or fatal) and a description of the alert. Alert messages
+// with a level of fatal result in the immediate termination of the
+// connection. In this case, other connections corresponding to the
+// session may continue, but the session identifier MUST be invalidated,
+// preventing the failed session from being used to establish new
+// connections. Like other messages, alert messages are encrypted and
+// compressed, as specified by the current connection state.
+// https://tools.ietf.org/html/rfc5246#section-7.2
+type Alert struct {
+ Level Level
+ Description Description
+}
+
+// ContentType returns the ContentType of this Content
+func (a Alert) ContentType() protocol.ContentType {
+ return protocol.ContentTypeAlert
+}
+
+// Marshal returns the encoded alert
+func (a *Alert) Marshal() ([]byte, error) {
+ return []byte{byte(a.Level), byte(a.Description)}, nil
+}
+
+// Unmarshal populates the alert from binary data
+func (a *Alert) Unmarshal(data []byte) error {
+ if len(data) != 2 {
+ return errBufferTooSmall
+ }
+
+ a.Level = Level(data[0])
+ a.Description = Description(data[1])
+ return nil
+}
+
+func (a *Alert) String() string {
+ return fmt.Sprintf("Alert %s: %s", a.Level, a.Description)
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/application_data.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/application_data.go
new file mode 100644
index 0000000..e5fd6f5
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/application_data.go
@@ -0,0 +1,26 @@
+package protocol
+
+// ApplicationData messages are carried by the record layer and are
+// fragmented, compressed, and encrypted based on the current connection
+// state. The messages are treated as transparent data to the record
+// layer.
+// https://tools.ietf.org/html/rfc5246#section-10
+type ApplicationData struct {
+ Data []byte
+}
+
+// ContentType returns the ContentType of this content
+func (a ApplicationData) ContentType() ContentType {
+ return ContentTypeApplicationData
+}
+
+// Marshal encodes the ApplicationData to binary
+func (a *ApplicationData) Marshal() ([]byte, error) {
+ return append([]byte{}, a.Data...), nil
+}
+
+// Unmarshal populates the ApplicationData from binary
+func (a *ApplicationData) Unmarshal(data []byte) error {
+ a.Data = append([]byte{}, data...)
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/change_cipher_spec.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/change_cipher_spec.go
new file mode 100644
index 0000000..67b0052
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/change_cipher_spec.go
@@ -0,0 +1,28 @@
+package protocol
+
+// ChangeCipherSpec protocol exists to signal transitions in
+// ciphering strategies. The protocol consists of a single message,
+// which is encrypted and compressed under the current (not the pending)
+// connection state. The message consists of a single byte of value 1.
+// https://tools.ietf.org/html/rfc5246#section-7.1
+type ChangeCipherSpec struct {
+}
+
+// ContentType returns the ContentType of this content
+func (c ChangeCipherSpec) ContentType() ContentType {
+ return ContentTypeChangeCipherSpec
+}
+
+// Marshal encodes the ChangeCipherSpec to binary
+func (c *ChangeCipherSpec) Marshal() ([]byte, error) {
+ return []byte{0x01}, nil
+}
+
+// Unmarshal populates the ChangeCipherSpec from binary
+func (c *ChangeCipherSpec) Unmarshal(data []byte) error {
+ if len(data) == 1 && data[0] == 0x01 {
+ return nil
+ }
+
+ return errInvalidCipherSpec
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/compression_method.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/compression_method.go
new file mode 100644
index 0000000..678e816
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/compression_method.go
@@ -0,0 +1,48 @@
+package protocol
+
+// CompressionMethodID is the ID for a CompressionMethod
+type CompressionMethodID byte
+
+const (
+ compressionMethodNull CompressionMethodID = 0
+)
+
+// CompressionMethod represents a TLS Compression Method
+type CompressionMethod struct {
+ ID CompressionMethodID
+}
+
+// CompressionMethods returns all supported CompressionMethods
+func CompressionMethods() map[CompressionMethodID]*CompressionMethod {
+ return map[CompressionMethodID]*CompressionMethod{
+ compressionMethodNull: {ID: compressionMethodNull},
+ }
+}
+
+// DecodeCompressionMethods the given compression methods
+func DecodeCompressionMethods(buf []byte) ([]*CompressionMethod, error) {
+ if len(buf) < 1 {
+ return nil, errBufferTooSmall
+ }
+ compressionMethodsCount := int(buf[0])
+ c := []*CompressionMethod{}
+ for i := 0; i < compressionMethodsCount; i++ {
+ if len(buf) <= i+1 {
+ return nil, errBufferTooSmall
+ }
+ id := CompressionMethodID(buf[i+1])
+ if compressionMethod, ok := CompressionMethods()[id]; ok {
+ c = append(c, compressionMethod)
+ }
+ }
+ return c, nil
+}
+
+// EncodeCompressionMethods the given compression methods
+func EncodeCompressionMethods(c []*CompressionMethod) []byte {
+ out := []byte{byte(len(c))}
+ for i := len(c); i > 0; i-- {
+ out = append(out, byte(c[i-1].ID))
+ }
+ return out
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/content.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/content.go
new file mode 100644
index 0000000..47e5c96
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/content.go
@@ -0,0 +1,21 @@
+package protocol
+
+// ContentType represents the IANA Registered ContentTypes
+//
+// https://tools.ietf.org/html/rfc4346#section-6.2.1
+type ContentType uint8
+
+// ContentType enums
+const (
+ ContentTypeChangeCipherSpec ContentType = 20
+ ContentTypeAlert ContentType = 21
+ ContentTypeHandshake ContentType = 22
+ ContentTypeApplicationData ContentType = 23
+)
+
+// Content is the top level distinguisher for a DTLS Datagram
+type Content interface {
+ ContentType() ContentType
+ Marshal() ([]byte, error)
+ Unmarshal(data []byte) error
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/errors.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/errors.go
new file mode 100644
index 0000000..e52014a
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/errors.go
@@ -0,0 +1,104 @@
+package protocol
+
+import (
+ "errors"
+ "fmt"
+ "net"
+)
+
+var (
+ errBufferTooSmall = &TemporaryError{Err: errors.New("buffer is too small")} //nolint:goerr113
+ errInvalidCipherSpec = &FatalError{Err: errors.New("cipher spec invalid")} //nolint:goerr113
+)
+
+// FatalError indicates that the DTLS connection is no longer available.
+// It is mainly caused by wrong configuration of server or client.
+type FatalError struct {
+ Err error
+}
+
+// InternalError indicates and internal error caused by the implementation, and the DTLS connection is no longer available.
+// It is mainly caused by bugs or tried to use unimplemented features.
+type InternalError struct {
+ Err error
+}
+
+// TemporaryError indicates that the DTLS connection is still available, but the request was failed temporary.
+type TemporaryError struct {
+ Err error
+}
+
+// TimeoutError indicates that the request was timed out.
+type TimeoutError struct {
+ Err error
+}
+
+// HandshakeError indicates that the handshake failed.
+type HandshakeError struct {
+ Err error
+}
+
+// Timeout implements net.Error.Timeout()
+func (*FatalError) Timeout() bool { return false }
+
+// Temporary implements net.Error.Temporary()
+func (*FatalError) Temporary() bool { return false }
+
+// Unwrap implements Go1.13 error unwrapper.
+func (e *FatalError) Unwrap() error { return e.Err }
+
+func (e *FatalError) Error() string { return fmt.Sprintf("dtls fatal: %v", e.Err) }
+
+// Timeout implements net.Error.Timeout()
+func (*InternalError) Timeout() bool { return false }
+
+// Temporary implements net.Error.Temporary()
+func (*InternalError) Temporary() bool { return false }
+
+// Unwrap implements Go1.13 error unwrapper.
+func (e *InternalError) Unwrap() error { return e.Err }
+
+func (e *InternalError) Error() string { return fmt.Sprintf("dtls internal: %v", e.Err) }
+
+// Timeout implements net.Error.Timeout()
+func (*TemporaryError) Timeout() bool { return false }
+
+// Temporary implements net.Error.Temporary()
+func (*TemporaryError) Temporary() bool { return true }
+
+// Unwrap implements Go1.13 error unwrapper.
+func (e *TemporaryError) Unwrap() error { return e.Err }
+
+func (e *TemporaryError) Error() string { return fmt.Sprintf("dtls temporary: %v", e.Err) }
+
+// Timeout implements net.Error.Timeout()
+func (*TimeoutError) Timeout() bool { return true }
+
+// Temporary implements net.Error.Temporary()
+func (*TimeoutError) Temporary() bool { return true }
+
+// Unwrap implements Go1.13 error unwrapper.
+func (e *TimeoutError) Unwrap() error { return e.Err }
+
+func (e *TimeoutError) Error() string { return fmt.Sprintf("dtls timeout: %v", e.Err) }
+
+// Timeout implements net.Error.Timeout()
+func (e *HandshakeError) Timeout() bool {
+ if netErr, ok := e.Err.(net.Error); ok {
+ return netErr.Timeout()
+ }
+ return false
+}
+
+// Temporary implements net.Error.Temporary()
+func (e *HandshakeError) Temporary() bool {
+ if netErr, ok := e.Err.(net.Error); ok {
+ return netErr.Temporary()
+ }
+ return false
+}
+
+// Unwrap implements Go1.13 error unwrapper.
+func (e *HandshakeError) Unwrap() error { return e.Err }
+
+func (e *HandshakeError) Error() string { return fmt.Sprintf("handshake error: %v", e.Err) }
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/errors.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/errors.go
new file mode 100644
index 0000000..23ed9b2
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/errors.go
@@ -0,0 +1,14 @@
+package extension
+
+import (
+ "errors"
+
+ "github.com/pion/dtls/v2/pkg/protocol"
+)
+
+var (
+ errBufferTooSmall = &protocol.TemporaryError{Err: errors.New("buffer is too small")} //nolint:goerr113
+ errInvalidExtensionType = &protocol.FatalError{Err: errors.New("invalid extension type")} //nolint:goerr113
+ errInvalidSNIFormat = &protocol.FatalError{Err: errors.New("invalid server name format")} //nolint:goerr113
+ errLengthMismatch = &protocol.InternalError{Err: errors.New("data length and declared length do not match")} //nolint:goerr113
+)
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/extension.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/extension.go
new file mode 100644
index 0000000..39b1fc8
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/extension.go
@@ -0,0 +1,96 @@
+// Package extension implements the extension values in the ClientHello/ServerHello
+package extension
+
+import "encoding/binary"
+
+// TypeValue is the 2 byte value for a TLS Extension as registered in the IANA
+//
+// https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
+type TypeValue uint16
+
+// TypeValue constants
+const (
+ ServerNameTypeValue TypeValue = 0
+ SupportedEllipticCurvesTypeValue TypeValue = 10
+ SupportedPointFormatsTypeValue TypeValue = 11
+ SupportedSignatureAlgorithmsTypeValue TypeValue = 13
+ UseSRTPTypeValue TypeValue = 14
+ UseExtendedMasterSecretTypeValue TypeValue = 23
+ RenegotiationInfoTypeValue TypeValue = 65281
+)
+
+// Extension represents a single TLS extension
+type Extension interface {
+ Marshal() ([]byte, error)
+ Unmarshal(data []byte) error
+ TypeValue() TypeValue
+}
+
+// Unmarshal many extensions at once
+func Unmarshal(buf []byte) ([]Extension, error) {
+ switch {
+ case len(buf) == 0:
+ return []Extension{}, nil
+ case len(buf) < 2:
+ return nil, errBufferTooSmall
+ }
+
+ declaredLen := binary.BigEndian.Uint16(buf)
+ if len(buf)-2 != int(declaredLen) {
+ return nil, errLengthMismatch
+ }
+
+ extensions := []Extension{}
+ unmarshalAndAppend := func(data []byte, e Extension) error {
+ err := e.Unmarshal(data)
+ if err != nil {
+ return err
+ }
+ extensions = append(extensions, e)
+ return nil
+ }
+
+ for offset := 2; offset < len(buf); {
+ if len(buf) < (offset + 2) {
+ return nil, errBufferTooSmall
+ }
+ var err error
+ switch TypeValue(binary.BigEndian.Uint16(buf[offset:])) {
+ case ServerNameTypeValue:
+ err = unmarshalAndAppend(buf[offset:], &ServerName{})
+ case SupportedEllipticCurvesTypeValue:
+ err = unmarshalAndAppend(buf[offset:], &SupportedEllipticCurves{})
+ case UseSRTPTypeValue:
+ err = unmarshalAndAppend(buf[offset:], &UseSRTP{})
+ case UseExtendedMasterSecretTypeValue:
+ err = unmarshalAndAppend(buf[offset:], &UseExtendedMasterSecret{})
+ case RenegotiationInfoTypeValue:
+ err = unmarshalAndAppend(buf[offset:], &RenegotiationInfo{})
+ default:
+ }
+ if err != nil {
+ return nil, err
+ }
+ if len(buf) < (offset + 4) {
+ return nil, errBufferTooSmall
+ }
+ extensionLength := binary.BigEndian.Uint16(buf[offset+2:])
+ offset += (4 + int(extensionLength))
+ }
+ return extensions, nil
+}
+
+// Marshal many extensions at once
+func Marshal(e []Extension) ([]byte, error) {
+ extensions := []byte{}
+ for _, e := range e {
+ raw, err := e.Marshal()
+ if err != nil {
+ return nil, err
+ }
+ extensions = append(extensions, raw...)
+ }
+ out := []byte{0x00, 0x00}
+ binary.BigEndian.PutUint16(out, uint16(len(extensions)))
+ return append(out, extensions...), nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/renegotiation_info.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/renegotiation_info.go
new file mode 100644
index 0000000..8378c3d
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/renegotiation_info.go
@@ -0,0 +1,43 @@
+package extension
+
+import "encoding/binary"
+
+const (
+ renegotiationInfoHeaderSize = 5
+)
+
+// RenegotiationInfo allows a Client/Server to
+// communicate their renegotation support
+//
+// https://tools.ietf.org/html/rfc5746
+type RenegotiationInfo struct {
+ RenegotiatedConnection uint8
+}
+
+// TypeValue returns the extension TypeValue
+func (r RenegotiationInfo) TypeValue() TypeValue {
+ return RenegotiationInfoTypeValue
+}
+
+// Marshal encodes the extension
+func (r *RenegotiationInfo) Marshal() ([]byte, error) {
+ out := make([]byte, renegotiationInfoHeaderSize)
+
+ binary.BigEndian.PutUint16(out, uint16(r.TypeValue()))
+ binary.BigEndian.PutUint16(out[2:], uint16(1)) // length
+ out[4] = r.RenegotiatedConnection
+ return out, nil
+}
+
+// Unmarshal populates the extension from encoded data
+func (r *RenegotiationInfo) Unmarshal(data []byte) error {
+ if len(data) < renegotiationInfoHeaderSize {
+ return errBufferTooSmall
+ } else if TypeValue(binary.BigEndian.Uint16(data)) != r.TypeValue() {
+ return errInvalidExtensionType
+ }
+
+ r.RenegotiatedConnection = data[4]
+
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/server_name.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/server_name.go
new file mode 100644
index 0000000..a08033f
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/server_name.go
@@ -0,0 +1,78 @@
+package extension
+
+import (
+ "strings"
+
+ "golang.org/x/crypto/cryptobyte"
+)
+
+const serverNameTypeDNSHostName = 0
+
+// ServerName allows the client to inform the server the specific
+// name it wishs to contact. Useful if multiple DNS names resolve
+// to one IP
+//
+// https://tools.ietf.org/html/rfc6066#section-3
+type ServerName struct {
+ ServerName string
+}
+
+// TypeValue returns the extension TypeValue
+func (s ServerName) TypeValue() TypeValue {
+ return ServerNameTypeValue
+}
+
+// Marshal encodes the extension
+func (s *ServerName) Marshal() ([]byte, error) {
+ var b cryptobyte.Builder
+ b.AddUint16(uint16(s.TypeValue()))
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint8(serverNameTypeDNSHostName)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes([]byte(s.ServerName))
+ })
+ })
+ })
+ return b.Bytes()
+}
+
+// Unmarshal populates the extension from encoded data
+func (s *ServerName) Unmarshal(data []byte) error {
+ val := cryptobyte.String(data)
+ var extension uint16
+ val.ReadUint16(&extension)
+ if TypeValue(extension) != s.TypeValue() {
+ return errInvalidExtensionType
+ }
+
+ var extData cryptobyte.String
+ val.ReadUint16LengthPrefixed(&extData)
+
+ var nameList cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&nameList) || nameList.Empty() {
+ return errInvalidSNIFormat
+ }
+ for !nameList.Empty() {
+ var nameType uint8
+ var serverName cryptobyte.String
+ if !nameList.ReadUint8(&nameType) ||
+ !nameList.ReadUint16LengthPrefixed(&serverName) ||
+ serverName.Empty() {
+ return errInvalidSNIFormat
+ }
+ if nameType != serverNameTypeDNSHostName {
+ continue
+ }
+ if len(s.ServerName) != 0 {
+ // Multiple names of the same name_type are prohibited.
+ return errInvalidSNIFormat
+ }
+ s.ServerName = string(serverName)
+ // An SNI value may not include a trailing dot.
+ if strings.HasSuffix(s.ServerName, ".") {
+ return errInvalidSNIFormat
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/srtp_protection_profile.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/srtp_protection_profile.go
new file mode 100644
index 0000000..2c4d1d4
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/srtp_protection_profile.go
@@ -0,0 +1,21 @@
+package extension
+
+// SRTPProtectionProfile defines the parameters and options that are in effect for the SRTP processing
+// https://tools.ietf.org/html/rfc5764#section-4.1.2
+type SRTPProtectionProfile uint16
+
+const (
+ SRTP_AES128_CM_HMAC_SHA1_80 SRTPProtectionProfile = 0x0001 // nolint
+ SRTP_AES128_CM_HMAC_SHA1_32 SRTPProtectionProfile = 0x0002 // nolint
+ SRTP_AEAD_AES_128_GCM SRTPProtectionProfile = 0x0007 // nolint
+ SRTP_AEAD_AES_256_GCM SRTPProtectionProfile = 0x0008 // nolint
+)
+
+func srtpProtectionProfiles() map[SRTPProtectionProfile]bool {
+ return map[SRTPProtectionProfile]bool{
+ SRTP_AES128_CM_HMAC_SHA1_80: true,
+ SRTP_AES128_CM_HMAC_SHA1_32: true,
+ SRTP_AEAD_AES_128_GCM: true,
+ SRTP_AEAD_AES_256_GCM: true,
+ }
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_elliptic_curves.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_elliptic_curves.go
new file mode 100644
index 0000000..8f077fc
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_elliptic_curves.go
@@ -0,0 +1,62 @@
+package extension
+
+import (
+ "encoding/binary"
+
+ "github.com/pion/dtls/v2/pkg/crypto/elliptic"
+)
+
+const (
+ supportedGroupsHeaderSize = 6
+)
+
+// SupportedEllipticCurves allows a Client/Server to communicate
+// what curves they both support
+//
+// https://tools.ietf.org/html/rfc8422#section-5.1.1
+type SupportedEllipticCurves struct {
+ EllipticCurves []elliptic.Curve
+}
+
+// TypeValue returns the extension TypeValue
+func (s SupportedEllipticCurves) TypeValue() TypeValue {
+ return SupportedEllipticCurvesTypeValue
+}
+
+// Marshal encodes the extension
+func (s *SupportedEllipticCurves) Marshal() ([]byte, error) {
+ out := make([]byte, supportedGroupsHeaderSize)
+
+ binary.BigEndian.PutUint16(out, uint16(s.TypeValue()))
+ binary.BigEndian.PutUint16(out[2:], uint16(2+(len(s.EllipticCurves)*2)))
+ binary.BigEndian.PutUint16(out[4:], uint16(len(s.EllipticCurves)*2))
+
+ for _, v := range s.EllipticCurves {
+ out = append(out, []byte{0x00, 0x00}...)
+ binary.BigEndian.PutUint16(out[len(out)-2:], uint16(v))
+ }
+
+ return out, nil
+}
+
+// Unmarshal populates the extension from encoded data
+func (s *SupportedEllipticCurves) Unmarshal(data []byte) error {
+ if len(data) <= supportedGroupsHeaderSize {
+ return errBufferTooSmall
+ } else if TypeValue(binary.BigEndian.Uint16(data)) != s.TypeValue() {
+ return errInvalidExtensionType
+ }
+
+ groupCount := int(binary.BigEndian.Uint16(data[4:]) / 2)
+ if supportedGroupsHeaderSize+(groupCount*2) > len(data) {
+ return errLengthMismatch
+ }
+
+ for i := 0; i < groupCount; i++ {
+ supportedGroupID := elliptic.Curve(binary.BigEndian.Uint16(data[(supportedGroupsHeaderSize + (i * 2)):]))
+ if _, ok := elliptic.Curves()[supportedGroupID]; ok {
+ s.EllipticCurves = append(s.EllipticCurves, supportedGroupID)
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_point_formats.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_point_formats.go
new file mode 100644
index 0000000..873d078
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_point_formats.go
@@ -0,0 +1,62 @@
+package extension
+
+import (
+ "encoding/binary"
+
+ "github.com/pion/dtls/v2/pkg/crypto/elliptic"
+)
+
+const (
+ supportedPointFormatsSize = 5
+)
+
+// SupportedPointFormats allows a Client/Server to negotiate
+// the EllipticCurvePointFormats
+//
+// https://tools.ietf.org/html/rfc4492#section-5.1.2
+type SupportedPointFormats struct {
+ PointFormats []elliptic.CurvePointFormat
+}
+
+// TypeValue returns the extension TypeValue
+func (s SupportedPointFormats) TypeValue() TypeValue {
+ return SupportedPointFormatsTypeValue
+}
+
+// Marshal encodes the extension
+func (s *SupportedPointFormats) Marshal() ([]byte, error) {
+ out := make([]byte, supportedPointFormatsSize)
+
+ binary.BigEndian.PutUint16(out, uint16(s.TypeValue()))
+ binary.BigEndian.PutUint16(out[2:], uint16(1+(len(s.PointFormats))))
+ out[4] = byte(len(s.PointFormats))
+
+ for _, v := range s.PointFormats {
+ out = append(out, byte(v))
+ }
+ return out, nil
+}
+
+// Unmarshal populates the extension from encoded data
+func (s *SupportedPointFormats) Unmarshal(data []byte) error {
+ if len(data) <= supportedPointFormatsSize {
+ return errBufferTooSmall
+ } else if TypeValue(binary.BigEndian.Uint16(data)) != s.TypeValue() {
+ return errInvalidExtensionType
+ }
+
+ pointFormatCount := int(binary.BigEndian.Uint16(data[4:]))
+ if supportedGroupsHeaderSize+(pointFormatCount) > len(data) {
+ return errLengthMismatch
+ }
+
+ for i := 0; i < pointFormatCount; i++ {
+ p := elliptic.CurvePointFormat(data[supportedPointFormatsSize+i])
+ switch p {
+ case elliptic.CurvePointFormatUncompressed:
+ s.PointFormats = append(s.PointFormats, p)
+ default:
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_signature_algorithms.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_signature_algorithms.go
new file mode 100644
index 0000000..ee284f6
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_signature_algorithms.go
@@ -0,0 +1,70 @@
+package extension
+
+import (
+ "encoding/binary"
+
+ "github.com/pion/dtls/v2/pkg/crypto/hash"
+ "github.com/pion/dtls/v2/pkg/crypto/signature"
+ "github.com/pion/dtls/v2/pkg/crypto/signaturehash"
+)
+
+const (
+ supportedSignatureAlgorithmsHeaderSize = 6
+)
+
+// SupportedSignatureAlgorithms allows a Client/Server to
+// negotiate what SignatureHash Algorithms they both support
+//
+// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+type SupportedSignatureAlgorithms struct {
+ SignatureHashAlgorithms []signaturehash.Algorithm
+}
+
+// TypeValue returns the extension TypeValue
+func (s SupportedSignatureAlgorithms) TypeValue() TypeValue {
+ return SupportedSignatureAlgorithmsTypeValue
+}
+
+// Marshal encodes the extension
+func (s *SupportedSignatureAlgorithms) Marshal() ([]byte, error) {
+ out := make([]byte, supportedSignatureAlgorithmsHeaderSize)
+
+ binary.BigEndian.PutUint16(out, uint16(s.TypeValue()))
+ binary.BigEndian.PutUint16(out[2:], uint16(2+(len(s.SignatureHashAlgorithms)*2)))
+ binary.BigEndian.PutUint16(out[4:], uint16(len(s.SignatureHashAlgorithms)*2))
+ for _, v := range s.SignatureHashAlgorithms {
+ out = append(out, []byte{0x00, 0x00}...)
+ out[len(out)-2] = byte(v.Hash)
+ out[len(out)-1] = byte(v.Signature)
+ }
+
+ return out, nil
+}
+
+// Unmarshal populates the extension from encoded data
+func (s *SupportedSignatureAlgorithms) Unmarshal(data []byte) error {
+ if len(data) <= supportedSignatureAlgorithmsHeaderSize {
+ return errBufferTooSmall
+ } else if TypeValue(binary.BigEndian.Uint16(data)) != s.TypeValue() {
+ return errInvalidExtensionType
+ }
+
+ algorithmCount := int(binary.BigEndian.Uint16(data[4:]) / 2)
+ if supportedSignatureAlgorithmsHeaderSize+(algorithmCount*2) > len(data) {
+ return errLengthMismatch
+ }
+ for i := 0; i < algorithmCount; i++ {
+ supportedHashAlgorithm := hash.Algorithm(data[supportedSignatureAlgorithmsHeaderSize+(i*2)])
+ supportedSignatureAlgorithm := signature.Algorithm(data[supportedSignatureAlgorithmsHeaderSize+(i*2)+1])
+ if _, ok := hash.Algorithms()[supportedHashAlgorithm]; ok {
+ if _, ok := signature.Algorithms()[supportedSignatureAlgorithm]; ok {
+ s.SignatureHashAlgorithms = append(s.SignatureHashAlgorithms, signaturehash.Algorithm{
+ Hash: supportedHashAlgorithm,
+ Signature: supportedSignatureAlgorithm,
+ })
+ }
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/use_master_secret.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/use_master_secret.go
new file mode 100644
index 0000000..04ddc95
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/use_master_secret.go
@@ -0,0 +1,45 @@
+package extension
+
+import "encoding/binary"
+
+const (
+ useExtendedMasterSecretHeaderSize = 4
+)
+
+// UseExtendedMasterSecret defines a TLS extension that contextually binds the
+// master secret to a log of the full handshake that computes it, thus
+// preventing MITM attacks.
+type UseExtendedMasterSecret struct {
+ Supported bool
+}
+
+// TypeValue returns the extension TypeValue
+func (u UseExtendedMasterSecret) TypeValue() TypeValue {
+ return UseExtendedMasterSecretTypeValue
+}
+
+// Marshal encodes the extension
+func (u *UseExtendedMasterSecret) Marshal() ([]byte, error) {
+ if !u.Supported {
+ return []byte{}, nil
+ }
+
+ out := make([]byte, useExtendedMasterSecretHeaderSize)
+
+ binary.BigEndian.PutUint16(out, uint16(u.TypeValue()))
+ binary.BigEndian.PutUint16(out[2:], uint16(0)) // length
+ return out, nil
+}
+
+// Unmarshal populates the extension from encoded data
+func (u *UseExtendedMasterSecret) Unmarshal(data []byte) error {
+ if len(data) < useExtendedMasterSecretHeaderSize {
+ return errBufferTooSmall
+ } else if TypeValue(binary.BigEndian.Uint16(data)) != u.TypeValue() {
+ return errInvalidExtensionType
+ }
+
+ u.Supported = true
+
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/use_srtp.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/use_srtp.go
new file mode 100644
index 0000000..729fa3a
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/extension/use_srtp.go
@@ -0,0 +1,59 @@
+package extension
+
+import "encoding/binary"
+
+const (
+ useSRTPHeaderSize = 6
+)
+
+// UseSRTP allows a Client/Server to negotiate what SRTPProtectionProfiles
+// they both support
+//
+// https://tools.ietf.org/html/rfc8422
+type UseSRTP struct {
+ ProtectionProfiles []SRTPProtectionProfile
+}
+
+// TypeValue returns the extension TypeValue
+func (u UseSRTP) TypeValue() TypeValue {
+ return UseSRTPTypeValue
+}
+
+// Marshal encodes the extension
+func (u *UseSRTP) Marshal() ([]byte, error) {
+ out := make([]byte, useSRTPHeaderSize)
+
+ binary.BigEndian.PutUint16(out, uint16(u.TypeValue()))
+ binary.BigEndian.PutUint16(out[2:], uint16(2+(len(u.ProtectionProfiles)*2)+ /* MKI Length */ 1))
+ binary.BigEndian.PutUint16(out[4:], uint16(len(u.ProtectionProfiles)*2))
+
+ for _, v := range u.ProtectionProfiles {
+ out = append(out, []byte{0x00, 0x00}...)
+ binary.BigEndian.PutUint16(out[len(out)-2:], uint16(v))
+ }
+
+ out = append(out, 0x00) /* MKI Length */
+ return out, nil
+}
+
+// Unmarshal populates the extension from encoded data
+func (u *UseSRTP) Unmarshal(data []byte) error {
+ if len(data) <= useSRTPHeaderSize {
+ return errBufferTooSmall
+ } else if TypeValue(binary.BigEndian.Uint16(data)) != u.TypeValue() {
+ return errInvalidExtensionType
+ }
+
+ profileCount := int(binary.BigEndian.Uint16(data[4:]) / 2)
+ if supportedGroupsHeaderSize+(profileCount*2) > len(data) {
+ return errLengthMismatch
+ }
+
+ for i := 0; i < profileCount; i++ {
+ supportedProfile := SRTPProtectionProfile(binary.BigEndian.Uint16(data[(useSRTPHeaderSize + (i * 2)):]))
+ if _, ok := srtpProtectionProfiles()[supportedProfile]; ok {
+ u.ProtectionProfiles = append(u.ProtectionProfiles, supportedProfile)
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/cipher_suite.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/cipher_suite.go
new file mode 100644
index 0000000..e8fbdea
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/cipher_suite.go
@@ -0,0 +1,29 @@
+package handshake
+
+import "encoding/binary"
+
+func decodeCipherSuiteIDs(buf []byte) ([]uint16, error) {
+ if len(buf) < 2 {
+ return nil, errBufferTooSmall
+ }
+ cipherSuitesCount := int(binary.BigEndian.Uint16(buf[0:])) / 2
+ rtrn := make([]uint16, cipherSuitesCount)
+ for i := 0; i < cipherSuitesCount; i++ {
+ if len(buf) < (i*2 + 4) {
+ return nil, errBufferTooSmall
+ }
+
+ rtrn[i] = binary.BigEndian.Uint16(buf[(i*2)+2:])
+ }
+ return rtrn, nil
+}
+
+func encodeCipherSuiteIDs(cipherSuiteIDs []uint16) []byte {
+ out := []byte{0x00, 0x00}
+ binary.BigEndian.PutUint16(out[len(out)-2:], uint16(len(cipherSuiteIDs)*2))
+ for _, id := range cipherSuiteIDs {
+ out = append(out, []byte{0x00, 0x00}...)
+ binary.BigEndian.PutUint16(out[len(out)-2:], id)
+ }
+ return out
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/errors.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/errors.go
new file mode 100644
index 0000000..ac77c04
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/errors.go
@@ -0,0 +1,25 @@
+package handshake
+
+import (
+ "errors"
+
+ "github.com/pion/dtls/v2/pkg/protocol"
+)
+
+// Typed errors
+var (
+ errUnableToMarshalFragmented = &protocol.InternalError{Err: errors.New("unable to marshal fragmented handshakes")} //nolint:goerr113
+ errHandshakeMessageUnset = &protocol.InternalError{Err: errors.New("handshake message unset, unable to marshal")} //nolint:goerr113
+ errBufferTooSmall = &protocol.TemporaryError{Err: errors.New("buffer is too small")} //nolint:goerr113
+ errLengthMismatch = &protocol.InternalError{Err: errors.New("data length and declared length do not match")} //nolint:goerr113
+ errInvalidClientKeyExchange = &protocol.FatalError{Err: errors.New("unable to determine if ClientKeyExchange is a public key or PSK Identity")} //nolint:goerr113
+ errInvalidHashAlgorithm = &protocol.FatalError{Err: errors.New("invalid hash algorithm")} //nolint:goerr113
+ errInvalidSignatureAlgorithm = &protocol.FatalError{Err: errors.New("invalid signature algorithm")} //nolint:goerr113
+ errCookieTooLong = &protocol.FatalError{Err: errors.New("cookie must not be longer then 255 bytes")} //nolint:goerr113
+ errInvalidEllipticCurveType = &protocol.FatalError{Err: errors.New("invalid or unknown elliptic curve type")} //nolint:goerr113
+ errInvalidNamedCurve = &protocol.FatalError{Err: errors.New("invalid named curve")} //nolint:goerr113
+ errCipherSuiteUnset = &protocol.FatalError{Err: errors.New("server hello can not be created without a cipher suite")} //nolint:goerr113
+ errCompressionMethodUnset = &protocol.FatalError{Err: errors.New("server hello can not be created without a compression method")} //nolint:goerr113
+ errInvalidCompressionMethod = &protocol.FatalError{Err: errors.New("invalid or unknown compression method")} //nolint:goerr113
+ errNotImplemented = &protocol.InternalError{Err: errors.New("feature has not been implemented yet")} //nolint:goerr113
+)
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/handshake.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/handshake.go
new file mode 100644
index 0000000..4aa493e
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/handshake.go
@@ -0,0 +1,145 @@
+// Package handshake provides the DTLS wire protocol for handshakes
+package handshake
+
+import (
+ "github.com/pion/dtls/v2/internal/util"
+ "github.com/pion/dtls/v2/pkg/protocol"
+)
+
+// Type is the unique identifier for each handshake message
+// https://tools.ietf.org/html/rfc5246#section-7.4
+type Type uint8
+
+// Types of DTLS Handshake messages we know about
+const (
+ TypeHelloRequest Type = 0
+ TypeClientHello Type = 1
+ TypeServerHello Type = 2
+ TypeHelloVerifyRequest Type = 3
+ TypeCertificate Type = 11
+ TypeServerKeyExchange Type = 12
+ TypeCertificateRequest Type = 13
+ TypeServerHelloDone Type = 14
+ TypeCertificateVerify Type = 15
+ TypeClientKeyExchange Type = 16
+ TypeFinished Type = 20
+)
+
+// String returns the string representation of this type
+func (t Type) String() string {
+ switch t {
+ case TypeHelloRequest:
+ return "HelloRequest"
+ case TypeClientHello:
+ return "ClientHello"
+ case TypeServerHello:
+ return "ServerHello"
+ case TypeHelloVerifyRequest:
+ return "HelloVerifyRequest"
+ case TypeCertificate:
+ return "TypeCertificate"
+ case TypeServerKeyExchange:
+ return "ServerKeyExchange"
+ case TypeCertificateRequest:
+ return "CertificateRequest"
+ case TypeServerHelloDone:
+ return "ServerHelloDone"
+ case TypeCertificateVerify:
+ return "CertificateVerify"
+ case TypeClientKeyExchange:
+ return "ClientKeyExchange"
+ case TypeFinished:
+ return "Finished"
+ }
+ return ""
+}
+
+// Message is the body of a Handshake datagram
+type Message interface {
+ Marshal() ([]byte, error)
+ Unmarshal(data []byte) error
+
+ Type() Type
+}
+
+// Handshake protocol is responsible for selecting a cipher spec and
+// generating a master secret, which together comprise the primary
+// cryptographic parameters associated with a secure session. The
+// handshake protocol can also optionally authenticate parties who have
+// certificates signed by a trusted certificate authority.
+// https://tools.ietf.org/html/rfc5246#section-7.3
+type Handshake struct {
+ Header Header
+ Message Message
+}
+
+// ContentType returns what kind of content this message is carying
+func (h Handshake) ContentType() protocol.ContentType {
+ return protocol.ContentTypeHandshake
+}
+
+// Marshal encodes a handshake into a binary message
+func (h *Handshake) Marshal() ([]byte, error) {
+ if h.Message == nil {
+ return nil, errHandshakeMessageUnset
+ } else if h.Header.FragmentOffset != 0 {
+ return nil, errUnableToMarshalFragmented
+ }
+
+ msg, err := h.Message.Marshal()
+ if err != nil {
+ return nil, err
+ }
+
+ h.Header.Length = uint32(len(msg))
+ h.Header.FragmentLength = h.Header.Length
+ h.Header.Type = h.Message.Type()
+ header, err := h.Header.Marshal()
+ if err != nil {
+ return nil, err
+ }
+
+ return append(header, msg...), nil
+}
+
+// Unmarshal decodes a handshake from a binary message
+func (h *Handshake) Unmarshal(data []byte) error {
+ if err := h.Header.Unmarshal(data); err != nil {
+ return err
+ }
+
+ reportedLen := util.BigEndianUint24(data[1:])
+ if uint32(len(data)-HeaderLength) != reportedLen {
+ return errLengthMismatch
+ } else if reportedLen != h.Header.FragmentLength {
+ return errLengthMismatch
+ }
+
+ switch Type(data[0]) {
+ case TypeHelloRequest:
+ return errNotImplemented
+ case TypeClientHello:
+ h.Message = &MessageClientHello{}
+ case TypeHelloVerifyRequest:
+ h.Message = &MessageHelloVerifyRequest{}
+ case TypeServerHello:
+ h.Message = &MessageServerHello{}
+ case TypeCertificate:
+ h.Message = &MessageCertificate{}
+ case TypeServerKeyExchange:
+ h.Message = &MessageServerKeyExchange{}
+ case TypeCertificateRequest:
+ h.Message = &MessageCertificateRequest{}
+ case TypeServerHelloDone:
+ h.Message = &MessageServerHelloDone{}
+ case TypeClientKeyExchange:
+ h.Message = &MessageClientKeyExchange{}
+ case TypeFinished:
+ h.Message = &MessageFinished{}
+ case TypeCertificateVerify:
+ h.Message = &MessageCertificateVerify{}
+ default:
+ return errNotImplemented
+ }
+ return h.Message.Unmarshal(data[HeaderLength:])
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/header.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/header.go
new file mode 100644
index 0000000..cb6a224
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/header.go
@@ -0,0 +1,50 @@
+package handshake
+
+import (
+ "encoding/binary"
+
+ "github.com/pion/dtls/v2/internal/util"
+)
+
+// HeaderLength msg_len for Handshake messages assumes an extra
+// 12 bytes for sequence, fragment and version information vs TLS
+const HeaderLength = 12
+
+// Header is the static first 12 bytes of each RecordLayer
+// of type Handshake. These fields allow us to support message loss, reordering, and
+// message fragmentation,
+//
+// https://tools.ietf.org/html/rfc6347#section-4.2.2
+type Header struct {
+ Type Type
+ Length uint32 // uint24 in spec
+ MessageSequence uint16
+ FragmentOffset uint32 // uint24 in spec
+ FragmentLength uint32 // uint24 in spec
+}
+
+// Marshal encodes the Header
+func (h *Header) Marshal() ([]byte, error) {
+ out := make([]byte, HeaderLength)
+
+ out[0] = byte(h.Type)
+ util.PutBigEndianUint24(out[1:], h.Length)
+ binary.BigEndian.PutUint16(out[4:], h.MessageSequence)
+ util.PutBigEndianUint24(out[6:], h.FragmentOffset)
+ util.PutBigEndianUint24(out[9:], h.FragmentLength)
+ return out, nil
+}
+
+// Unmarshal populates the header from encoded data
+func (h *Header) Unmarshal(data []byte) error {
+ if len(data) < HeaderLength {
+ return errBufferTooSmall
+ }
+
+ h.Type = Type(data[0])
+ h.Length = util.BigEndianUint24(data[1:])
+ h.MessageSequence = binary.BigEndian.Uint16(data[4:])
+ h.FragmentOffset = util.BigEndianUint24(data[6:])
+ h.FragmentLength = util.BigEndianUint24(data[9:])
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_certificate.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_certificate.go
new file mode 100644
index 0000000..05fb746
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_certificate.go
@@ -0,0 +1,66 @@
+package handshake
+
+import (
+ "github.com/pion/dtls/v2/internal/util"
+)
+
+// MessageCertificate is a DTLS Handshake Message
+// it can contain either a Client or Server Certificate
+//
+// https://tools.ietf.org/html/rfc5246#section-7.4.2
+type MessageCertificate struct {
+ Certificate [][]byte
+}
+
+// Type returns the Handshake Type
+func (m MessageCertificate) Type() Type {
+ return TypeCertificate
+}
+
+const (
+ handshakeMessageCertificateLengthFieldSize = 3
+)
+
+// Marshal encodes the Handshake
+func (m *MessageCertificate) Marshal() ([]byte, error) {
+ out := make([]byte, handshakeMessageCertificateLengthFieldSize)
+
+ for _, r := range m.Certificate {
+ // Certificate Length
+ out = append(out, make([]byte, handshakeMessageCertificateLengthFieldSize)...)
+ util.PutBigEndianUint24(out[len(out)-handshakeMessageCertificateLengthFieldSize:], uint32(len(r)))
+
+ // Certificate body
+ out = append(out, append([]byte{}, r...)...)
+ }
+
+ // Total Payload Size
+ util.PutBigEndianUint24(out[0:], uint32(len(out[handshakeMessageCertificateLengthFieldSize:])))
+ return out, nil
+}
+
+// Unmarshal populates the message from encoded data
+func (m *MessageCertificate) Unmarshal(data []byte) error {
+ if len(data) < handshakeMessageCertificateLengthFieldSize {
+ return errBufferTooSmall
+ }
+
+ if certificateBodyLen := int(util.BigEndianUint24(data)); certificateBodyLen+handshakeMessageCertificateLengthFieldSize != len(data) {
+ return errLengthMismatch
+ }
+
+ offset := handshakeMessageCertificateLengthFieldSize
+ for offset < len(data) {
+ certificateLen := int(util.BigEndianUint24(data[offset:]))
+ offset += handshakeMessageCertificateLengthFieldSize
+
+ if offset+certificateLen > len(data) {
+ return errLengthMismatch
+ }
+
+ m.Certificate = append(m.Certificate, append([]byte{}, data[offset:offset+certificateLen]...))
+ offset += certificateLen
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_certificate_request.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_certificate_request.go
new file mode 100644
index 0000000..e711f39
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_certificate_request.go
@@ -0,0 +1,100 @@
+package handshake
+
+import (
+ "encoding/binary"
+
+ "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
+ "github.com/pion/dtls/v2/pkg/crypto/hash"
+ "github.com/pion/dtls/v2/pkg/crypto/signature"
+ "github.com/pion/dtls/v2/pkg/crypto/signaturehash"
+)
+
+/*
+MessageCertificateRequest is so a non-anonymous server can optionally
+request a certificate from the client, if appropriate for the selected cipher
+suite. This message, if sent, will immediately follow the ServerKeyExchange
+message (if it is sent; otherwise, this message follows the
+server's Certificate message).
+
+https://tools.ietf.org/html/rfc5246#section-7.4.4
+*/
+type MessageCertificateRequest struct {
+ CertificateTypes []clientcertificate.Type
+ SignatureHashAlgorithms []signaturehash.Algorithm
+}
+
+const (
+ messageCertificateRequestMinLength = 5
+)
+
+// Type returns the Handshake Type
+func (m MessageCertificateRequest) Type() Type {
+ return TypeCertificateRequest
+}
+
+// Marshal encodes the Handshake
+func (m *MessageCertificateRequest) Marshal() ([]byte, error) {
+ out := []byte{byte(len(m.CertificateTypes))}
+ for _, v := range m.CertificateTypes {
+ out = append(out, byte(v))
+ }
+
+ out = append(out, []byte{0x00, 0x00}...)
+ binary.BigEndian.PutUint16(out[len(out)-2:], uint16(len(m.SignatureHashAlgorithms)*2))
+ for _, v := range m.SignatureHashAlgorithms {
+ out = append(out, byte(v.Hash))
+ out = append(out, byte(v.Signature))
+ }
+
+ out = append(out, []byte{0x00, 0x00}...) // Distinguished Names Length
+ return out, nil
+}
+
+// Unmarshal populates the message from encoded data
+func (m *MessageCertificateRequest) Unmarshal(data []byte) error {
+ if len(data) < messageCertificateRequestMinLength {
+ return errBufferTooSmall
+ }
+
+ offset := 0
+ certificateTypesLength := int(data[0])
+ offset++
+
+ if (offset + certificateTypesLength) > len(data) {
+ return errBufferTooSmall
+ }
+
+ for i := 0; i < certificateTypesLength; i++ {
+ certType := clientcertificate.Type(data[offset+i])
+ if _, ok := clientcertificate.Types()[certType]; ok {
+ m.CertificateTypes = append(m.CertificateTypes, certType)
+ }
+ }
+ offset += certificateTypesLength
+ if len(data) < offset+2 {
+ return errBufferTooSmall
+ }
+ signatureHashAlgorithmsLength := int(binary.BigEndian.Uint16(data[offset:]))
+ offset += 2
+
+ if (offset + signatureHashAlgorithmsLength) > len(data) {
+ return errBufferTooSmall
+ }
+
+ for i := 0; i < signatureHashAlgorithmsLength; i += 2 {
+ if len(data) < (offset + i + 2) {
+ return errBufferTooSmall
+ }
+ h := hash.Algorithm(data[offset+i])
+ s := signature.Algorithm(data[offset+i+1])
+
+ if _, ok := hash.Algorithms()[h]; !ok {
+ continue
+ } else if _, ok := signature.Algorithms()[s]; !ok {
+ continue
+ }
+ m.SignatureHashAlgorithms = append(m.SignatureHashAlgorithms, signaturehash.Algorithm{Signature: s, Hash: h})
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_certificate_verify.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_certificate_verify.go
new file mode 100644
index 0000000..fb5e463
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_certificate_verify.go
@@ -0,0 +1,61 @@
+package handshake
+
+import (
+ "encoding/binary"
+
+ "github.com/pion/dtls/v2/pkg/crypto/hash"
+ "github.com/pion/dtls/v2/pkg/crypto/signature"
+)
+
+// MessageCertificateVerify provide explicit verification of a
+// client certificate.
+//
+// https://tools.ietf.org/html/rfc5246#section-7.4.8
+type MessageCertificateVerify struct {
+ HashAlgorithm hash.Algorithm
+ SignatureAlgorithm signature.Algorithm
+ Signature []byte
+}
+
+const handshakeMessageCertificateVerifyMinLength = 4
+
+// Type returns the Handshake Type
+func (m MessageCertificateVerify) Type() Type {
+ return TypeCertificateVerify
+}
+
+// Marshal encodes the Handshake
+func (m *MessageCertificateVerify) Marshal() ([]byte, error) {
+ out := make([]byte, 1+1+2+len(m.Signature))
+
+ out[0] = byte(m.HashAlgorithm)
+ out[1] = byte(m.SignatureAlgorithm)
+ binary.BigEndian.PutUint16(out[2:], uint16(len(m.Signature)))
+ copy(out[4:], m.Signature)
+ return out, nil
+}
+
+// Unmarshal populates the message from encoded data
+func (m *MessageCertificateVerify) Unmarshal(data []byte) error {
+ if len(data) < handshakeMessageCertificateVerifyMinLength {
+ return errBufferTooSmall
+ }
+
+ m.HashAlgorithm = hash.Algorithm(data[0])
+ if _, ok := hash.Algorithms()[m.HashAlgorithm]; !ok {
+ return errInvalidHashAlgorithm
+ }
+
+ m.SignatureAlgorithm = signature.Algorithm(data[1])
+ if _, ok := signature.Algorithms()[m.SignatureAlgorithm]; !ok {
+ return errInvalidSignatureAlgorithm
+ }
+
+ signatureLength := int(binary.BigEndian.Uint16(data[2:]))
+ if (signatureLength + 4) != len(data) {
+ return errBufferTooSmall
+ }
+
+ m.Signature = append([]byte{}, data[4:]...)
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_client_hello.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_client_hello.go
new file mode 100644
index 0000000..cb8a100
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_client_hello.go
@@ -0,0 +1,125 @@
+package handshake
+
+import (
+ "encoding/binary"
+
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/extension"
+)
+
+/*
+MessageClientHello is for when a client first connects to a server it is
+required to send the client hello as its first message. The client can also send a
+client hello in response to a hello request or on its own
+initiative in order to renegotiate the security parameters in an
+existing connection.
+*/
+type MessageClientHello struct {
+ Version protocol.Version
+ Random Random
+ Cookie []byte
+
+ CipherSuiteIDs []uint16
+ CompressionMethods []*protocol.CompressionMethod
+ Extensions []extension.Extension
+}
+
+const handshakeMessageClientHelloVariableWidthStart = 34
+
+// Type returns the Handshake Type
+func (m MessageClientHello) Type() Type {
+ return TypeClientHello
+}
+
+// Marshal encodes the Handshake
+func (m *MessageClientHello) Marshal() ([]byte, error) {
+ if len(m.Cookie) > 255 {
+ return nil, errCookieTooLong
+ }
+
+ out := make([]byte, handshakeMessageClientHelloVariableWidthStart)
+ out[0] = m.Version.Major
+ out[1] = m.Version.Minor
+
+ rand := m.Random.MarshalFixed()
+ copy(out[2:], rand[:])
+
+ out = append(out, 0x00) // SessionID
+
+ out = append(out, byte(len(m.Cookie)))
+ out = append(out, m.Cookie...)
+ out = append(out, encodeCipherSuiteIDs(m.CipherSuiteIDs)...)
+ out = append(out, protocol.EncodeCompressionMethods(m.CompressionMethods)...)
+
+ extensions, err := extension.Marshal(m.Extensions)
+ if err != nil {
+ return nil, err
+ }
+
+ return append(out, extensions...), nil
+}
+
+// Unmarshal populates the message from encoded data
+func (m *MessageClientHello) Unmarshal(data []byte) error {
+ if len(data) < 2+RandomLength {
+ return errBufferTooSmall
+ }
+
+ m.Version.Major = data[0]
+ m.Version.Minor = data[1]
+
+ var random [RandomLength]byte
+ copy(random[:], data[2:])
+ m.Random.UnmarshalFixed(random)
+
+ // rest of packet has variable width sections
+ currOffset := handshakeMessageClientHelloVariableWidthStart
+ currOffset += int(data[currOffset]) + 1 // SessionID
+
+ currOffset++
+ if len(data) <= currOffset {
+ return errBufferTooSmall
+ }
+ n := int(data[currOffset-1])
+ if len(data) <= currOffset+n {
+ return errBufferTooSmall
+ }
+ m.Cookie = append([]byte{}, data[currOffset:currOffset+n]...)
+ currOffset += len(m.Cookie)
+
+ // Cipher Suites
+ if len(data) < currOffset {
+ return errBufferTooSmall
+ }
+ cipherSuiteIDs, err := decodeCipherSuiteIDs(data[currOffset:])
+ if err != nil {
+ return err
+ }
+ m.CipherSuiteIDs = cipherSuiteIDs
+ if len(data) < currOffset+2 {
+ return errBufferTooSmall
+ }
+ currOffset += int(binary.BigEndian.Uint16(data[currOffset:])) + 2
+
+ // Compression Methods
+ if len(data) < currOffset {
+ return errBufferTooSmall
+ }
+ compressionMethods, err := protocol.DecodeCompressionMethods(data[currOffset:])
+ if err != nil {
+ return err
+ }
+ m.CompressionMethods = compressionMethods
+ if len(data) < currOffset {
+ return errBufferTooSmall
+ }
+ currOffset += int(data[currOffset]) + 1
+
+ // Extensions
+ extensions, err := extension.Unmarshal(data[currOffset:])
+ if err != nil {
+ return err
+ }
+ m.Extensions = extensions
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_client_key_exchange.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_client_key_exchange.go
new file mode 100644
index 0000000..f8fc369
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_client_key_exchange.go
@@ -0,0 +1,56 @@
+package handshake
+
+import (
+ "encoding/binary"
+)
+
+// MessageClientKeyExchange is a DTLS Handshake Message
+// With this message, the premaster secret is set, either by direct
+// transmission of the RSA-encrypted secret or by the transmission of
+// Diffie-Hellman parameters that will allow each side to agree upon
+// the same premaster secret.
+//
+// https://tools.ietf.org/html/rfc5246#section-7.4.7
+type MessageClientKeyExchange struct {
+ IdentityHint []byte
+ PublicKey []byte
+}
+
+// Type returns the Handshake Type
+func (m MessageClientKeyExchange) Type() Type {
+ return TypeClientKeyExchange
+}
+
+// Marshal encodes the Handshake
+func (m *MessageClientKeyExchange) Marshal() ([]byte, error) {
+ switch {
+ case (m.IdentityHint != nil && m.PublicKey != nil) || (m.IdentityHint == nil && m.PublicKey == nil):
+ return nil, errInvalidClientKeyExchange
+ case m.PublicKey != nil:
+ return append([]byte{byte(len(m.PublicKey))}, m.PublicKey...), nil
+ default:
+ out := append([]byte{0x00, 0x00}, m.IdentityHint...)
+ binary.BigEndian.PutUint16(out, uint16(len(out)-2))
+ return out, nil
+ }
+}
+
+// Unmarshal populates the message from encoded data
+func (m *MessageClientKeyExchange) Unmarshal(data []byte) error {
+ if len(data) < 2 {
+ return errBufferTooSmall
+ }
+
+ // If parsed as PSK return early and only populate PSK Identity Hint
+ if pskLength := binary.BigEndian.Uint16(data); len(data) == int(pskLength+2) {
+ m.IdentityHint = append([]byte{}, data[2:]...)
+ return nil
+ }
+
+ if publicKeyLength := int(data[0]); len(data) != publicKeyLength+1 {
+ return errBufferTooSmall
+ }
+
+ m.PublicKey = append([]byte{}, data[1:]...)
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_finished.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_finished.go
new file mode 100644
index 0000000..c65d42a
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_finished.go
@@ -0,0 +1,27 @@
+package handshake
+
+// MessageFinished is a DTLS Handshake Message
+// this message is the first one protected with the just
+// negotiated algorithms, keys, and secrets. Recipients of Finished
+// messages MUST verify that the contents are correct.
+//
+// https://tools.ietf.org/html/rfc5246#section-7.4.9
+type MessageFinished struct {
+ VerifyData []byte
+}
+
+// Type returns the Handshake Type
+func (m MessageFinished) Type() Type {
+ return TypeFinished
+}
+
+// Marshal encodes the Handshake
+func (m *MessageFinished) Marshal() ([]byte, error) {
+ return append([]byte{}, m.VerifyData...), nil
+}
+
+// Unmarshal populates the message from encoded data
+func (m *MessageFinished) Unmarshal(data []byte) error {
+ m.VerifyData = append([]byte{}, data...)
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_hello_verify_request.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_hello_verify_request.go
new file mode 100644
index 0000000..ef834dc
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_hello_verify_request.go
@@ -0,0 +1,62 @@
+package handshake
+
+import (
+ "github.com/pion/dtls/v2/pkg/protocol"
+)
+
+// MessageHelloVerifyRequest is as follows:
+//
+// struct {
+// ProtocolVersion server_version;
+// opaque cookie<0..2^8-1>;
+// } HelloVerifyRequest;
+//
+// The HelloVerifyRequest message type is hello_verify_request(3).
+//
+// When the client sends its ClientHello message to the server, the server
+// MAY respond with a HelloVerifyRequest message. This message contains
+// a stateless cookie generated using the technique of [PHOTURIS]. The
+// client MUST retransmit the ClientHello with the cookie added.
+//
+// https://tools.ietf.org/html/rfc6347#section-4.2.1
+type MessageHelloVerifyRequest struct {
+ Version protocol.Version
+ Cookie []byte
+}
+
+// Type returns the Handshake Type
+func (m MessageHelloVerifyRequest) Type() Type {
+ return TypeHelloVerifyRequest
+}
+
+// Marshal encodes the Handshake
+func (m *MessageHelloVerifyRequest) Marshal() ([]byte, error) {
+ if len(m.Cookie) > 255 {
+ return nil, errCookieTooLong
+ }
+
+ out := make([]byte, 3+len(m.Cookie))
+ out[0] = m.Version.Major
+ out[1] = m.Version.Minor
+ out[2] = byte(len(m.Cookie))
+ copy(out[3:], m.Cookie)
+
+ return out, nil
+}
+
+// Unmarshal populates the message from encoded data
+func (m *MessageHelloVerifyRequest) Unmarshal(data []byte) error {
+ if len(data) < 3 {
+ return errBufferTooSmall
+ }
+ m.Version.Major = data[0]
+ m.Version.Minor = data[1]
+ cookieLength := data[2]
+ if len(data) < (int(cookieLength) + 3) {
+ return errBufferTooSmall
+ }
+ m.Cookie = make([]byte, cookieLength)
+
+ copy(m.Cookie, data[3:3+cookieLength])
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_server_hello.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_server_hello.go
new file mode 100644
index 0000000..c4b181f
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_server_hello.go
@@ -0,0 +1,106 @@
+package handshake
+
+import (
+ "encoding/binary"
+
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/extension"
+)
+
+// MessageServerHello is sent in response to a ClientHello
+// message when it was able to find an acceptable set of algorithms.
+// If it cannot find such a match, it will respond with a handshake
+// failure alert.
+//
+// https://tools.ietf.org/html/rfc5246#section-7.4.1.3
+type MessageServerHello struct {
+ Version protocol.Version
+ Random Random
+
+ CipherSuiteID *uint16
+ CompressionMethod *protocol.CompressionMethod
+ Extensions []extension.Extension
+}
+
+const messageServerHelloVariableWidthStart = 2 + RandomLength
+
+// Type returns the Handshake Type
+func (m MessageServerHello) Type() Type {
+ return TypeServerHello
+}
+
+// Marshal encodes the Handshake
+func (m *MessageServerHello) Marshal() ([]byte, error) {
+ if m.CipherSuiteID == nil {
+ return nil, errCipherSuiteUnset
+ } else if m.CompressionMethod == nil {
+ return nil, errCompressionMethodUnset
+ }
+
+ out := make([]byte, messageServerHelloVariableWidthStart)
+ out[0] = m.Version.Major
+ out[1] = m.Version.Minor
+
+ rand := m.Random.MarshalFixed()
+ copy(out[2:], rand[:])
+
+ out = append(out, 0x00) // SessionID
+
+ out = append(out, []byte{0x00, 0x00}...)
+ binary.BigEndian.PutUint16(out[len(out)-2:], *m.CipherSuiteID)
+
+ out = append(out, byte(m.CompressionMethod.ID))
+
+ extensions, err := extension.Marshal(m.Extensions)
+ if err != nil {
+ return nil, err
+ }
+
+ return append(out, extensions...), nil
+}
+
+// Unmarshal populates the message from encoded data
+func (m *MessageServerHello) Unmarshal(data []byte) error {
+ if len(data) < 2+RandomLength {
+ return errBufferTooSmall
+ }
+
+ m.Version.Major = data[0]
+ m.Version.Minor = data[1]
+
+ var random [RandomLength]byte
+ copy(random[:], data[2:])
+ m.Random.UnmarshalFixed(random)
+
+ currOffset := messageServerHelloVariableWidthStart
+ currOffset += int(data[currOffset]) + 1 // SessionID
+ if len(data) < (currOffset + 2) {
+ return errBufferTooSmall
+ }
+
+ m.CipherSuiteID = new(uint16)
+ *m.CipherSuiteID = binary.BigEndian.Uint16(data[currOffset:])
+ currOffset += 2
+
+ if len(data) < currOffset {
+ return errBufferTooSmall
+ }
+ if compressionMethod, ok := protocol.CompressionMethods()[protocol.CompressionMethodID(data[currOffset])]; ok {
+ m.CompressionMethod = compressionMethod
+ currOffset++
+ } else {
+ return errInvalidCompressionMethod
+ }
+
+ if len(data) <= currOffset {
+ m.Extensions = []extension.Extension{}
+ return nil
+ }
+
+ extensions, err := extension.Unmarshal(data[currOffset:])
+ if err != nil {
+ return err
+ }
+ m.Extensions = extensions
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_server_hello_done.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_server_hello_done.go
new file mode 100644
index 0000000..a004802
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_server_hello_done.go
@@ -0,0 +1,22 @@
+package handshake
+
+// MessageServerHelloDone is final non-encrypted message from server
+// this communicates server has sent all its handshake messages and next
+// should be MessageFinished
+type MessageServerHelloDone struct {
+}
+
+// Type returns the Handshake Type
+func (m MessageServerHelloDone) Type() Type {
+ return TypeServerHelloDone
+}
+
+// Marshal encodes the Handshake
+func (m *MessageServerHelloDone) Marshal() ([]byte, error) {
+ return []byte{}, nil
+}
+
+// Unmarshal populates the message from encoded data
+func (m *MessageServerHelloDone) Unmarshal(data []byte) error {
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_server_key_exchange.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_server_key_exchange.go
new file mode 100644
index 0000000..4148fe0
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/message_server_key_exchange.go
@@ -0,0 +1,119 @@
+package handshake
+
+import (
+ "encoding/binary"
+
+ "github.com/pion/dtls/v2/pkg/crypto/elliptic"
+ "github.com/pion/dtls/v2/pkg/crypto/hash"
+ "github.com/pion/dtls/v2/pkg/crypto/signature"
+)
+
+// MessageServerKeyExchange supports ECDH and PSK
+type MessageServerKeyExchange struct {
+ IdentityHint []byte
+
+ EllipticCurveType elliptic.CurveType
+ NamedCurve elliptic.Curve
+ PublicKey []byte
+ HashAlgorithm hash.Algorithm
+ SignatureAlgorithm signature.Algorithm
+ Signature []byte
+}
+
+// Type returns the Handshake Type
+func (m MessageServerKeyExchange) Type() Type {
+ return TypeServerKeyExchange
+}
+
+// Marshal encodes the Handshake
+func (m *MessageServerKeyExchange) Marshal() ([]byte, error) {
+ if m.IdentityHint != nil {
+ out := append([]byte{0x00, 0x00}, m.IdentityHint...)
+ binary.BigEndian.PutUint16(out, uint16(len(out)-2))
+ return out, nil
+ }
+
+ out := []byte{byte(m.EllipticCurveType), 0x00, 0x00}
+ binary.BigEndian.PutUint16(out[1:], uint16(m.NamedCurve))
+
+ out = append(out, byte(len(m.PublicKey)))
+ out = append(out, m.PublicKey...)
+
+ if m.HashAlgorithm == hash.None && m.SignatureAlgorithm == signature.Anonymous && len(m.Signature) == 0 {
+ return out, nil
+ }
+
+ out = append(out, []byte{byte(m.HashAlgorithm), byte(m.SignatureAlgorithm), 0x00, 0x00}...)
+ binary.BigEndian.PutUint16(out[len(out)-2:], uint16(len(m.Signature)))
+ out = append(out, m.Signature...)
+
+ return out, nil
+}
+
+// Unmarshal populates the message from encoded data
+func (m *MessageServerKeyExchange) Unmarshal(data []byte) error {
+ if len(data) < 2 {
+ return errBufferTooSmall
+ }
+
+ // If parsed as PSK return early and only populate PSK Identity Hint
+ if pskLength := binary.BigEndian.Uint16(data); len(data) == int(pskLength+2) {
+ m.IdentityHint = append([]byte{}, data[2:]...)
+ return nil
+ }
+
+ if _, ok := elliptic.CurveTypes()[elliptic.CurveType(data[0])]; ok {
+ m.EllipticCurveType = elliptic.CurveType(data[0])
+ } else {
+ return errInvalidEllipticCurveType
+ }
+
+ if len(data[1:]) < 2 {
+ return errBufferTooSmall
+ }
+ m.NamedCurve = elliptic.Curve(binary.BigEndian.Uint16(data[1:3]))
+ if _, ok := elliptic.Curves()[m.NamedCurve]; !ok {
+ return errInvalidNamedCurve
+ }
+ if len(data) < 4 {
+ return errBufferTooSmall
+ }
+
+ publicKeyLength := int(data[3])
+ offset := 4 + publicKeyLength
+ if len(data) < offset {
+ return errBufferTooSmall
+ }
+ m.PublicKey = append([]byte{}, data[4:offset]...)
+
+ // Anon connection doesn't contains hashAlgorithm, signatureAlgorithm, signature
+ if len(data) == offset {
+ return nil
+ } else if len(data) <= offset {
+ return errBufferTooSmall
+ }
+
+ m.HashAlgorithm = hash.Algorithm(data[offset])
+ if _, ok := hash.Algorithms()[m.HashAlgorithm]; !ok {
+ return errInvalidHashAlgorithm
+ }
+ offset++
+ if len(data) <= offset {
+ return errBufferTooSmall
+ }
+ m.SignatureAlgorithm = signature.Algorithm(data[offset])
+ if _, ok := signature.Algorithms()[m.SignatureAlgorithm]; !ok {
+ return errInvalidSignatureAlgorithm
+ }
+ offset++
+ if len(data) < offset+2 {
+ return errBufferTooSmall
+ }
+ signatureLength := int(binary.BigEndian.Uint16(data[offset:]))
+ offset += 2
+ if len(data) < offset+signatureLength {
+ return errBufferTooSmall
+ }
+ m.Signature = append([]byte{}, data[offset:offset+signatureLength]...)
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/random.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/random.go
new file mode 100644
index 0000000..0ade936
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/random.go
@@ -0,0 +1,49 @@
+package handshake
+
+import (
+ "crypto/rand"
+ "encoding/binary"
+ "time"
+)
+
+// Consts for Random in Handshake
+const (
+ RandomBytesLength = 28
+ RandomLength = RandomBytesLength + 4
+)
+
+// Random value that is used in ClientHello and ServerHello
+//
+// https://tools.ietf.org/html/rfc4346#section-7.4.1.2
+type Random struct {
+ GMTUnixTime time.Time
+ RandomBytes [RandomBytesLength]byte
+}
+
+// MarshalFixed encodes the Handshake
+func (r *Random) MarshalFixed() [RandomLength]byte {
+ var out [RandomLength]byte
+
+ binary.BigEndian.PutUint32(out[0:], uint32(r.GMTUnixTime.Unix()))
+ copy(out[4:], r.RandomBytes[:])
+
+ return out
+}
+
+// UnmarshalFixed populates the message from encoded data
+func (r *Random) UnmarshalFixed(data [RandomLength]byte) {
+ r.GMTUnixTime = time.Unix(int64(binary.BigEndian.Uint32(data[0:])), 0)
+ copy(r.RandomBytes[:], data[4:])
+}
+
+// Populate fills the handshakeRandom with random values
+// may be called multiple times
+func (r *Random) Populate() error {
+ r.GMTUnixTime = time.Now()
+
+ tmp := make([]byte, RandomBytesLength)
+ _, err := rand.Read(tmp)
+ copy(r.RandomBytes[:], tmp)
+
+ return err
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/recordlayer/errors.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/recordlayer/errors.go
new file mode 100644
index 0000000..7033d40
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/recordlayer/errors.go
@@ -0,0 +1,16 @@
+// Package recordlayer implements the TLS Record Layer https://tools.ietf.org/html/rfc5246#section-6
+package recordlayer
+
+import (
+ "errors"
+
+ "github.com/pion/dtls/v2/pkg/protocol"
+)
+
+var (
+ errBufferTooSmall = &protocol.TemporaryError{Err: errors.New("buffer is too small")} //nolint:goerr113
+ errInvalidPacketLength = &protocol.TemporaryError{Err: errors.New("packet length and declared length do not match")} //nolint:goerr113
+ errSequenceNumberOverflow = &protocol.InternalError{Err: errors.New("sequence number overflow")} //nolint:goerr113
+ errUnsupportedProtocolVersion = &protocol.FatalError{Err: errors.New("unsupported protocol version")} //nolint:goerr113
+ errInvalidContentType = &protocol.TemporaryError{Err: errors.New("invalid content type")} //nolint:goerr113
+)
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/recordlayer/header.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/recordlayer/header.go
new file mode 100644
index 0000000..65047d7
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/recordlayer/header.go
@@ -0,0 +1,61 @@
+package recordlayer
+
+import (
+ "encoding/binary"
+
+ "github.com/pion/dtls/v2/internal/util"
+ "github.com/pion/dtls/v2/pkg/protocol"
+)
+
+// Header implements a TLS RecordLayer header
+type Header struct {
+ ContentType protocol.ContentType
+ ContentLen uint16
+ Version protocol.Version
+ Epoch uint16
+ SequenceNumber uint64 // uint48 in spec
+}
+
+// RecordLayer enums
+const (
+ HeaderSize = 13
+ MaxSequenceNumber = 0x0000FFFFFFFFFFFF
+)
+
+// Marshal encodes a TLS RecordLayer Header to binary
+func (h *Header) Marshal() ([]byte, error) {
+ if h.SequenceNumber > MaxSequenceNumber {
+ return nil, errSequenceNumberOverflow
+ }
+
+ out := make([]byte, HeaderSize)
+ out[0] = byte(h.ContentType)
+ out[1] = h.Version.Major
+ out[2] = h.Version.Minor
+ binary.BigEndian.PutUint16(out[3:], h.Epoch)
+ util.PutBigEndianUint48(out[5:], h.SequenceNumber)
+ binary.BigEndian.PutUint16(out[HeaderSize-2:], h.ContentLen)
+ return out, nil
+}
+
+// Unmarshal populates a TLS RecordLayer Header from binary
+func (h *Header) Unmarshal(data []byte) error {
+ if len(data) < HeaderSize {
+ return errBufferTooSmall
+ }
+ h.ContentType = protocol.ContentType(data[0])
+ h.Version.Major = data[1]
+ h.Version.Minor = data[2]
+ h.Epoch = binary.BigEndian.Uint16(data[3:])
+
+ // SequenceNumber is stored as uint48, make into uint64
+ seqCopy := make([]byte, 8)
+ copy(seqCopy[2:], data[5:11])
+ h.SequenceNumber = binary.BigEndian.Uint64(seqCopy)
+
+ if !h.Version.Equal(protocol.Version1_0) && !h.Version.Equal(protocol.Version1_2) {
+ return errUnsupportedProtocolVersion
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/recordlayer/recordlayer.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/recordlayer/recordlayer.go
new file mode 100644
index 0000000..67e5a72
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/recordlayer/recordlayer.go
@@ -0,0 +1,99 @@
+package recordlayer
+
+import (
+ "encoding/binary"
+
+ "github.com/pion/dtls/v2/pkg/protocol"
+ "github.com/pion/dtls/v2/pkg/protocol/alert"
+ "github.com/pion/dtls/v2/pkg/protocol/handshake"
+)
+
+// RecordLayer which handles all data transport.
+// The record layer is assumed to sit directly on top of some
+// reliable transport such as TCP. The record layer can carry four types of content:
+//
+// 1. Handshake messages—used for algorithm negotiation and key establishment.
+// 2. ChangeCipherSpec messages—really part of the handshake but technically a separate kind of message.
+// 3. Alert messages—used to signal that errors have occurred
+// 4. Application layer data
+//
+// The DTLS record layer is extremely similar to that of TLS 1.1. The
+// only change is the inclusion of an explicit sequence number in the
+// record. This sequence number allows the recipient to correctly
+// verify the TLS MAC.
+//
+// https://tools.ietf.org/html/rfc4347#section-4.1
+type RecordLayer struct {
+ Header Header
+ Content protocol.Content
+}
+
+// Marshal encodes the RecordLayer to binary
+func (r *RecordLayer) Marshal() ([]byte, error) {
+ contentRaw, err := r.Content.Marshal()
+ if err != nil {
+ return nil, err
+ }
+
+ r.Header.ContentLen = uint16(len(contentRaw))
+ r.Header.ContentType = r.Content.ContentType()
+
+ headerRaw, err := r.Header.Marshal()
+ if err != nil {
+ return nil, err
+ }
+
+ return append(headerRaw, contentRaw...), nil
+}
+
+// Unmarshal populates the RecordLayer from binary
+func (r *RecordLayer) Unmarshal(data []byte) error {
+ if len(data) < HeaderSize {
+ return errBufferTooSmall
+ }
+ if err := r.Header.Unmarshal(data); err != nil {
+ return err
+ }
+
+ switch protocol.ContentType(data[0]) {
+ case protocol.ContentTypeChangeCipherSpec:
+ r.Content = &protocol.ChangeCipherSpec{}
+ case protocol.ContentTypeAlert:
+ r.Content = &alert.Alert{}
+ case protocol.ContentTypeHandshake:
+ r.Content = &handshake.Handshake{}
+ case protocol.ContentTypeApplicationData:
+ r.Content = &protocol.ApplicationData{}
+ default:
+ return errInvalidContentType
+ }
+
+ return r.Content.Unmarshal(data[HeaderSize:])
+}
+
+// UnpackDatagram extracts all RecordLayer messages from a single datagram.
+// Note that as with TLS, multiple handshake messages may be placed in
+// the same DTLS record, provided that there is room and that they are
+// part of the same flight. Thus, there are two acceptable ways to pack
+// two DTLS messages into the same datagram: in the same record or in
+// separate records.
+// https://tools.ietf.org/html/rfc6347#section-4.2.3
+func UnpackDatagram(buf []byte) ([][]byte, error) {
+ out := [][]byte{}
+
+ for offset := 0; len(buf) != offset; {
+ if len(buf)-offset <= HeaderSize {
+ return nil, errInvalidPacketLength
+ }
+
+ pktLen := (HeaderSize + int(binary.BigEndian.Uint16(buf[offset+11:])))
+ if offset+pktLen > len(buf) {
+ return nil, errInvalidPacketLength
+ }
+
+ out = append(out, buf[offset:offset+pktLen])
+ offset += pktLen
+ }
+
+ return out, nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/pkg/protocol/version.go b/vendor/github.com/pion/dtls/v2/pkg/protocol/version.go
new file mode 100644
index 0000000..d5ddb1d
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/pkg/protocol/version.go
@@ -0,0 +1,21 @@
+// Package protocol provides the DTLS wire format
+package protocol
+
+// Version enums
+var (
+ Version1_0 = Version{Major: 0xfe, Minor: 0xff} //nolint:gochecknoglobals
+ Version1_2 = Version{Major: 0xfe, Minor: 0xfd} //nolint:gochecknoglobals
+)
+
+// Version is the minor/major value in the RecordLayer
+// and ClientHello/ServerHello
+//
+// https://tools.ietf.org/html/rfc4346#section-6.2.1
+type Version struct {
+ Major, Minor uint8
+}
+
+// Equal determines if two protocol versions are equal
+func (v Version) Equal(x Version) bool {
+ return v.Major == x.Major && v.Minor == x.Minor
+}
diff --git a/vendor/github.com/pion/dtls/v2/renovate.json b/vendor/github.com/pion/dtls/v2/renovate.json
new file mode 100644
index 0000000..4400fd9
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/renovate.json
@@ -0,0 +1,15 @@
+{
+ "extends": [
+ "config:base"
+ ],
+ "postUpdateOptions": [
+ "gomodTidy"
+ ],
+ "commitBody": "Generated by renovateBot",
+ "packageRules": [
+ {
+ "packagePatterns": ["^golang.org/x/"],
+ "schedule": ["on the first day of the month"]
+ }
+ ]
+}
diff --git a/vendor/github.com/pion/dtls/v2/resume.go b/vendor/github.com/pion/dtls/v2/resume.go
new file mode 100644
index 0000000..40e55e4
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/resume.go
@@ -0,0 +1,19 @@
+package dtls
+
+import (
+ "context"
+ "net"
+)
+
+// Resume imports an already established dtls connection using a specific dtls state
+func Resume(state *State, conn net.Conn, config *Config) (*Conn, error) {
+ if err := state.initCipherSuite(); err != nil {
+ return nil, err
+ }
+ c, err := createConn(context.Background(), conn, config, state.isClient, state)
+ if err != nil {
+ return nil, err
+ }
+
+ return c, nil
+}
diff --git a/vendor/github.com/pion/dtls/v2/srtp_protection_profile.go b/vendor/github.com/pion/dtls/v2/srtp_protection_profile.go
new file mode 100644
index 0000000..1c3ae55
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/srtp_protection_profile.go
@@ -0,0 +1,14 @@
+package dtls
+
+import "github.com/pion/dtls/v2/pkg/protocol/extension"
+
+// SRTPProtectionProfile defines the parameters and options that are in effect for the SRTP processing
+// https://tools.ietf.org/html/rfc5764#section-4.1.2
+type SRTPProtectionProfile = extension.SRTPProtectionProfile
+
+const (
+ SRTP_AES128_CM_HMAC_SHA1_80 SRTPProtectionProfile = extension.SRTP_AES128_CM_HMAC_SHA1_80 // nolint
+ SRTP_AES128_CM_HMAC_SHA1_32 SRTPProtectionProfile = extension.SRTP_AES128_CM_HMAC_SHA1_32 // nolint
+ SRTP_AEAD_AES_128_GCM SRTPProtectionProfile = extension.SRTP_AEAD_AES_128_GCM // nolint
+ SRTP_AEAD_AES_256_GCM SRTPProtectionProfile = extension.SRTP_AEAD_AES_256_GCM // nolint
+)
diff --git a/vendor/github.com/pion/dtls/v2/state.go b/vendor/github.com/pion/dtls/v2/state.go
new file mode 100644
index 0000000..53fca6a
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/state.go
@@ -0,0 +1,194 @@
+package dtls
+
+import (
+ "bytes"
+ "encoding/gob"
+ "sync/atomic"
+
+ "github.com/pion/dtls/v2/pkg/crypto/elliptic"
+ "github.com/pion/dtls/v2/pkg/crypto/prf"
+ "github.com/pion/dtls/v2/pkg/protocol/handshake"
+ "github.com/pion/transport/replaydetector"
+)
+
+// State holds the dtls connection state and implements both encoding.BinaryMarshaler and encoding.BinaryUnmarshaler
+type State struct {
+ localEpoch, remoteEpoch atomic.Value
+ localSequenceNumber []uint64 // uint48
+ localRandom, remoteRandom handshake.Random
+ masterSecret []byte
+ cipherSuite CipherSuite // nil if a cipherSuite hasn't been chosen
+
+ srtpProtectionProfile SRTPProtectionProfile // Negotiated SRTPProtectionProfile
+ PeerCertificates [][]byte
+ IdentityHint []byte
+
+ isClient bool
+
+ preMasterSecret []byte
+ extendedMasterSecret bool
+
+ namedCurve elliptic.Curve
+ localKeypair *elliptic.Keypair
+ cookie []byte
+ handshakeSendSequence int
+ handshakeRecvSequence int
+ serverName string
+ remoteRequestedCertificate bool // Did we get a CertificateRequest
+ localCertificatesVerify []byte // cache CertificateVerify
+ localVerifyData []byte // cached VerifyData
+ localKeySignature []byte // cached keySignature
+ peerCertificatesVerified bool
+
+ replayDetector []replaydetector.ReplayDetector
+}
+
+type serializedState struct {
+ LocalEpoch uint16
+ RemoteEpoch uint16
+ LocalRandom [handshake.RandomLength]byte
+ RemoteRandom [handshake.RandomLength]byte
+ CipherSuiteID uint16
+ MasterSecret []byte
+ SequenceNumber uint64
+ SRTPProtectionProfile uint16
+ PeerCertificates [][]byte
+ IdentityHint []byte
+ IsClient bool
+}
+
+func (s *State) clone() *State {
+ serialized := s.serialize()
+ state := &State{}
+ state.deserialize(*serialized)
+
+ return state
+}
+
+func (s *State) serialize() *serializedState {
+ // Marshal random values
+ localRnd := s.localRandom.MarshalFixed()
+ remoteRnd := s.remoteRandom.MarshalFixed()
+
+ epoch := s.localEpoch.Load().(uint16)
+ return &serializedState{
+ LocalEpoch: epoch,
+ RemoteEpoch: s.remoteEpoch.Load().(uint16),
+ CipherSuiteID: uint16(s.cipherSuite.ID()),
+ MasterSecret: s.masterSecret,
+ SequenceNumber: atomic.LoadUint64(&s.localSequenceNumber[epoch]),
+ LocalRandom: localRnd,
+ RemoteRandom: remoteRnd,
+ SRTPProtectionProfile: uint16(s.srtpProtectionProfile),
+ PeerCertificates: s.PeerCertificates,
+ IdentityHint: s.IdentityHint,
+ IsClient: s.isClient,
+ }
+}
+
+func (s *State) deserialize(serialized serializedState) {
+ // Set epoch values
+ epoch := serialized.LocalEpoch
+ s.localEpoch.Store(serialized.LocalEpoch)
+ s.remoteEpoch.Store(serialized.RemoteEpoch)
+
+ for len(s.localSequenceNumber) <= int(epoch) {
+ s.localSequenceNumber = append(s.localSequenceNumber, uint64(0))
+ }
+
+ // Set random values
+ localRandom := &handshake.Random{}
+ localRandom.UnmarshalFixed(serialized.LocalRandom)
+ s.localRandom = *localRandom
+
+ remoteRandom := &handshake.Random{}
+ remoteRandom.UnmarshalFixed(serialized.RemoteRandom)
+ s.remoteRandom = *remoteRandom
+
+ s.isClient = serialized.IsClient
+
+ // Set master secret
+ s.masterSecret = serialized.MasterSecret
+
+ // Set cipher suite
+ s.cipherSuite = cipherSuiteForID(CipherSuiteID(serialized.CipherSuiteID), nil)
+
+ atomic.StoreUint64(&s.localSequenceNumber[epoch], serialized.SequenceNumber)
+ s.srtpProtectionProfile = SRTPProtectionProfile(serialized.SRTPProtectionProfile)
+
+ // Set remote certificate
+ s.PeerCertificates = serialized.PeerCertificates
+ s.IdentityHint = serialized.IdentityHint
+}
+
+func (s *State) initCipherSuite() error {
+ if s.cipherSuite.IsInitialized() {
+ return nil
+ }
+
+ localRandom := s.localRandom.MarshalFixed()
+ remoteRandom := s.remoteRandom.MarshalFixed()
+
+ var err error
+ if s.isClient {
+ err = s.cipherSuite.Init(s.masterSecret, localRandom[:], remoteRandom[:], true)
+ } else {
+ err = s.cipherSuite.Init(s.masterSecret, remoteRandom[:], localRandom[:], false)
+ }
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// MarshalBinary is a binary.BinaryMarshaler.MarshalBinary implementation
+func (s *State) MarshalBinary() ([]byte, error) {
+ serialized := s.serialize()
+
+ var buf bytes.Buffer
+ enc := gob.NewEncoder(&buf)
+ if err := enc.Encode(*serialized); err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// UnmarshalBinary is a binary.BinaryUnmarshaler.UnmarshalBinary implementation
+func (s *State) UnmarshalBinary(data []byte) error {
+ enc := gob.NewDecoder(bytes.NewBuffer(data))
+ var serialized serializedState
+ if err := enc.Decode(&serialized); err != nil {
+ return err
+ }
+
+ s.deserialize(serialized)
+ if err := s.initCipherSuite(); err != nil {
+ return err
+ }
+ return nil
+}
+
+// ExportKeyingMaterial returns length bytes of exported key material in a new
+// slice as defined in RFC 5705.
+// This allows protocols to use DTLS for key establishment, but
+// then use some of the keying material for their own purposes
+func (s *State) ExportKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
+ if s.localEpoch.Load().(uint16) == 0 {
+ return nil, errHandshakeInProgress
+ } else if len(context) != 0 {
+ return nil, errContextUnsupported
+ } else if _, ok := invalidKeyingLabels()[label]; ok {
+ return nil, errReservedExportKeyingMaterial
+ }
+
+ localRandom := s.localRandom.MarshalFixed()
+ remoteRandom := s.remoteRandom.MarshalFixed()
+
+ seed := []byte(label)
+ if s.isClient {
+ seed = append(append(seed, localRandom[:]...), remoteRandom[:]...)
+ } else {
+ seed = append(append(seed, remoteRandom[:]...), localRandom[:]...)
+ }
+ return prf.PHash(s.masterSecret, seed, length, s.cipherSuite.HashFunc())
+}
diff --git a/vendor/github.com/pion/dtls/v2/util.go b/vendor/github.com/pion/dtls/v2/util.go
new file mode 100644
index 0000000..745182d
--- /dev/null
+++ b/vendor/github.com/pion/dtls/v2/util.go
@@ -0,0 +1,38 @@
+package dtls
+
+func findMatchingSRTPProfile(a, b []SRTPProtectionProfile) (SRTPProtectionProfile, bool) {
+ for _, aProfile := range a {
+ for _, bProfile := range b {
+ if aProfile == bProfile {
+ return aProfile, true
+ }
+ }
+ }
+ return 0, false
+}
+
+func findMatchingCipherSuite(a, b []CipherSuite) (CipherSuite, bool) { //nolint
+ for _, aSuite := range a {
+ for _, bSuite := range b {
+ if aSuite.ID() == bSuite.ID() {
+ return aSuite, true
+ }
+ }
+ }
+ return nil, false
+}
+
+func splitBytes(bytes []byte, splitLen int) [][]byte {
+ splitBytes := make([][]byte, 0)
+ numBytes := len(bytes)
+ for i := 0; i < numBytes; i += splitLen {
+ j := i + splitLen
+ if j > numBytes {
+ j = numBytes
+ }
+
+ splitBytes = append(splitBytes, bytes[i:j])
+ }
+
+ return splitBytes
+}