summaryrefslogtreecommitdiff
path: root/vendor/github.com/pion/dtls/v2/pkg
diff options
context:
space:
mode:
authorkali kaneko (leap communications) <kali@leap.se>2021-11-29 01:46:27 +0100
committerkali kaneko (leap communications) <kali@leap.se>2021-11-29 18:14:16 +0100
commit18f52af5be3a9a0c73811706108f790d65ee9c67 (patch)
treee13cbacb47d56919caa9c44a2b45dec1497a7860 /vendor/github.com/pion/dtls/v2/pkg
parentebcef0d57b6ecb5a40c6579f6be07182dd3033ba (diff)
[pkg] update vendor
Diffstat (limited to 'vendor/github.com/pion/dtls/v2/pkg')
-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
49 files changed, 3551 insertions, 0 deletions
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
+}