24
vendor/github.com/pion/datachannel/.gitignore
generated
vendored
Normal file
24
vendor/github.com/pion/datachannel/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
### JetBrains IDE ###
|
||||
#####################
|
||||
.idea/
|
||||
|
||||
### Emacs Temporary Files ###
|
||||
#############################
|
||||
*~
|
||||
|
||||
### Folders ###
|
||||
###############
|
||||
bin/
|
||||
vendor/
|
||||
node_modules/
|
||||
|
||||
### Files ###
|
||||
#############
|
||||
*.ivf
|
||||
*.ogg
|
||||
tags
|
||||
cover.out
|
||||
*.sw[poe]
|
||||
*.wasm
|
||||
examples/sfu-ws/cert.pem
|
||||
examples/sfu-ws/key.pem
|
||||
89
vendor/github.com/pion/datachannel/.golangci.yml
generated
vendored
Normal file
89
vendor/github.com/pion/datachannel/.golangci.yml
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
linters-settings:
|
||||
govet:
|
||||
check-shadowing: true
|
||||
misspell:
|
||||
locale: US
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: true
|
||||
gomodguard:
|
||||
blocked:
|
||||
modules:
|
||||
- github.com/pkg/errors:
|
||||
recommendations:
|
||||
- errors
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers
|
||||
- bodyclose # checks whether HTTP response body is closed successfully
|
||||
- deadcode # Finds unused code
|
||||
- depguard # Go linter that checks if package imports are in a list of acceptable packages
|
||||
- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
|
||||
- dupl # Tool for code clone detection
|
||||
- errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
|
||||
- exhaustive # check exhaustiveness of enum switch statements
|
||||
- exportloopref # checks for pointers to enclosing loop variables
|
||||
- gci # Gci control golang package import order and make it always deterministic.
|
||||
- gochecknoglobals # Checks that no globals are present in Go code
|
||||
- gochecknoinits # Checks that no init functions are present in Go code
|
||||
- gocognit # Computes and checks the cognitive complexity of functions
|
||||
- goconst # Finds repeated strings that could be replaced by a constant
|
||||
- gocritic # The most opinionated Go source code linter
|
||||
- godox # Tool for detection of FIXME, TODO and other comment keywords
|
||||
- goerr113 # Golang linter to check the errors handling expressions
|
||||
- gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
|
||||
- gofumpt # Gofumpt checks whether code was gofumpt-ed.
|
||||
- goheader # Checks is file header matches to pattern
|
||||
- goimports # Goimports does everything that gofmt does. Additionally it checks unused imports
|
||||
- golint # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes
|
||||
- gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations.
|
||||
- goprintffuncname # Checks that printf-like functions are named with `f` at the end
|
||||
- gosec # Inspects source code for security problems
|
||||
- gosimple # Linter for Go source code that specializes in simplifying a code
|
||||
- govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
|
||||
- ineffassign # Detects when assignments to existing variables are not used
|
||||
- misspell # Finds commonly misspelled English words in comments
|
||||
- nakedret # Finds naked returns in functions greater than a specified function length
|
||||
- noctx # noctx finds sending http request without context.Context
|
||||
- scopelint # Scopelint checks for unpinned variables in go programs
|
||||
- staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks
|
||||
- structcheck # Finds unused struct fields
|
||||
- stylecheck # Stylecheck is a replacement for golint
|
||||
- typecheck # Like the front-end of a Go compiler, parses and type-checks Go code
|
||||
- unconvert # Remove unnecessary type conversions
|
||||
- unparam # Reports unused function parameters
|
||||
- unused # Checks Go code for unused constants, variables, functions and types
|
||||
- varcheck # Finds unused global variables and constants
|
||||
- whitespace # Tool for detection of leading and trailing whitespace
|
||||
disable:
|
||||
- funlen # Tool for detection of long functions
|
||||
- gocyclo # Computes and checks the cyclomatic complexity of functions
|
||||
- godot # Check if comments end in a period
|
||||
- gomnd # An analyzer to detect magic numbers.
|
||||
- lll # Reports long lines
|
||||
- maligned # Tool to detect Go structs that would take less memory if their fields were sorted
|
||||
- nestif # Reports deeply nested if statements
|
||||
- nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity
|
||||
- nolintlint # Reports ill-formed or insufficient nolint directives
|
||||
- prealloc # Finds slice declarations that could potentially be preallocated
|
||||
- rowserrcheck # checks whether Err of rows is checked successfully
|
||||
- sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed.
|
||||
- testpackage # linter that makes you use a separate _test package
|
||||
- wsl # Whitespace Linter - Forces you to use empty lines!
|
||||
|
||||
issues:
|
||||
exclude-use-default: false
|
||||
exclude-rules:
|
||||
# Allow complex tests, better to be self contained
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- gocognit
|
||||
|
||||
# Allow complex main function in examples
|
||||
- path: examples
|
||||
text: "of func `main` is high"
|
||||
linters:
|
||||
- gocognit
|
||||
|
||||
run:
|
||||
skip-dirs-use-default: false
|
||||
16
vendor/github.com/pion/datachannel/AUTHORS.txt
generated
vendored
Normal file
16
vendor/github.com/pion/datachannel/AUTHORS.txt
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
# Thank you to everyone that made Pion possible. If you are interested in contributing
|
||||
# we would love to have you https://github.com/pion/webrtc/wiki/Contributing
|
||||
#
|
||||
# This file is auto generated, using git to list all individuals contributors.
|
||||
# see `.github/generate-authors.sh` for the scripting
|
||||
Atsushi Watanabe <atsushi.w@ieee.org>
|
||||
backkem <mail@backkem.me>
|
||||
Benny Daon <benny@tuzig.com>
|
||||
Eric Daniels <eric@erdaniels.com>
|
||||
Hugo Arregui <hugo.arregui@gmail.com>
|
||||
Hugo Arregui <hugo@decentraland.org>
|
||||
John Bradley <jrb@turrettech.com>
|
||||
Norman Rasmussen <norman@rasmussen.co.za>
|
||||
Sean DuBois <seaduboi@amazon.com>
|
||||
Sean DuBois <sean@siobud.com>
|
||||
Yutaka Takeda <yt0916@gmail.com>
|
||||
20
vendor/github.com/pion/datachannel/DESIGN.md
generated
vendored
Normal file
20
vendor/github.com/pion/datachannel/DESIGN.md
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<h1 align="center">
|
||||
Design
|
||||
</h1>
|
||||
|
||||
### Portable
|
||||
Pion Data Channels is written in Go and extremely portable. Anywhere Golang runs, Pion Data Channels should work as well! Instead of dealing with complicated
|
||||
cross-compiling of multiple libraries, you now can run anywhere with one `go build`
|
||||
|
||||
### Simple API
|
||||
The API is based on an io.ReadWriteCloser.
|
||||
|
||||
### Readable
|
||||
If code comes from an RFC we try to make sure everything is commented with a link to the spec.
|
||||
This makes learning and debugging easier, this library was written to also serve as a guide for others.
|
||||
|
||||
### Tested
|
||||
Every commit is tested via travis-ci Go provides fantastic facilities for testing, and more will be added as time goes on.
|
||||
|
||||
### Shared libraries
|
||||
Every pion product is built using shared libraries, allowing others to review and reuse our libraries.
|
||||
21
vendor/github.com/pion/datachannel/LICENSE
generated
vendored
Normal file
21
vendor/github.com/pion/datachannel/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
37
vendor/github.com/pion/datachannel/README.md
generated
vendored
Normal file
37
vendor/github.com/pion/datachannel/README.md
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<h1 align="center">
|
||||
<br>
|
||||
Pion Data Channels
|
||||
<br>
|
||||
</h1>
|
||||
<h4 align="center">A Go implementation of WebRTC Data Channels</h4>
|
||||
<p align="center">
|
||||
<a href="https://pion.ly"><img src="https://img.shields.io/badge/pion-datachannel-gray.svg?longCache=true&colorB=brightgreen" alt="Pion Data Channels"></a>
|
||||
<!--<a href="https://sourcegraph.com/github.com/pion/webrtc?badge"><img src="https://sourcegraph.com/github.com/pion/webrtc/-/badge.svg" alt="Sourcegraph Widget"></a>-->
|
||||
<a href="https://pion.ly/slack"><img src="https://img.shields.io/badge/join-us%20on%20slack-gray.svg?longCache=true&logo=slack&colorB=brightgreen" alt="Slack Widget"></a>
|
||||
<br>
|
||||
<a href="https://travis-ci.org/pion/datachannel"><img src="https://travis-ci.org/pion/datachannel.svg?branch=master" alt="Build Status"></a>
|
||||
<a href="https://pkg.go.dev/github.com/pion/datachannel"><img src="https://godoc.org/github.com/pion/datachannel?status.svg" alt="GoDoc"></a>
|
||||
<a href="https://codecov.io/gh/pion/datachannel"><img src="https://codecov.io/gh/pion/datachannel/branch/master/graph/badge.svg" alt="Coverage Status"></a>
|
||||
<a href="https://goreportcard.com/report/github.com/pion/datachannel"><img src="https://goreportcard.com/badge/github.com/pion/datachannel" alt="Go Report Card"></a>
|
||||
<!--<a href="https://www.codacy.com/app/Sean-Der/webrtc"><img src="https://api.codacy.com/project/badge/Grade/18f4aec384894e6aac0b94effe51961d" alt="Codacy Badge"></a>-->
|
||||
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
|
||||
</p>
|
||||
<br>
|
||||
|
||||
See [DESIGN.md](DESIGN.md) for an overview of features and future goals.
|
||||
|
||||
### Roadmap
|
||||
The library is used as a part of our WebRTC implementation. Please refer to that [roadmap](https://github.com/pion/webrtc/issues/9) to track our major milestones.
|
||||
|
||||
### Community
|
||||
Pion has an active community on the [Golang Slack](https://invite.slack.golangbridge.org/). Sign up and join the **#pion** channel for discussions and support. You can also use [Pion mailing list](https://groups.google.com/forum/#!forum/pion).
|
||||
|
||||
We are always looking to support **your projects**. Please reach out if you have something to build!
|
||||
|
||||
If you need commercial support or don't want to use public methods you can contact us at [team@pion.ly](mailto:team@pion.ly)
|
||||
|
||||
### Contributing
|
||||
Check out the **[contributing wiki](https://github.com/pion/webrtc/wiki/Contributing)** to join the group of amazing people making this project possible:
|
||||
|
||||
### License
|
||||
MIT License - see [LICENSE](LICENSE) for full text
|
||||
20
vendor/github.com/pion/datachannel/codecov.yml
generated
vendored
Normal file
20
vendor/github.com/pion/datachannel/codecov.yml
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# DO NOT EDIT THIS FILE
|
||||
#
|
||||
# It is automatically copied from https://github.com/pion/.goassets repository.
|
||||
#
|
||||
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
# Allow decreasing 2% of total coverage to avoid noise.
|
||||
threshold: 2%
|
||||
patch:
|
||||
default:
|
||||
target: 70%
|
||||
only_pulls: true
|
||||
|
||||
ignore:
|
||||
- "examples/*"
|
||||
- "examples/**/*"
|
||||
391
vendor/github.com/pion/datachannel/datachannel.go
generated
vendored
Normal file
391
vendor/github.com/pion/datachannel/datachannel.go
generated
vendored
Normal file
@@ -0,0 +1,391 @@
|
||||
// Package datachannel implements WebRTC Data Channels
|
||||
package datachannel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/pion/logging"
|
||||
"github.com/pion/sctp"
|
||||
)
|
||||
|
||||
const receiveMTU = 8192
|
||||
|
||||
// Reader is an extended io.Reader
|
||||
// that also returns if the message is text.
|
||||
type Reader interface {
|
||||
ReadDataChannel([]byte) (int, bool, error)
|
||||
}
|
||||
|
||||
// Writer is an extended io.Writer
|
||||
// that also allows indicating if a message is text.
|
||||
type Writer interface {
|
||||
WriteDataChannel([]byte, bool) (int, error)
|
||||
}
|
||||
|
||||
// ReadWriteCloser is an extended io.ReadWriteCloser
|
||||
// that also implements our Reader and Writer.
|
||||
type ReadWriteCloser interface {
|
||||
io.Reader
|
||||
io.Writer
|
||||
Reader
|
||||
Writer
|
||||
io.Closer
|
||||
}
|
||||
|
||||
// DataChannel represents a data channel
|
||||
type DataChannel struct {
|
||||
Config
|
||||
|
||||
// stats
|
||||
messagesSent uint32
|
||||
messagesReceived uint32
|
||||
bytesSent uint64
|
||||
bytesReceived uint64
|
||||
|
||||
mu sync.Mutex
|
||||
onOpenCompleteHandler func()
|
||||
openCompleteHandlerOnce sync.Once
|
||||
|
||||
stream *sctp.Stream
|
||||
log logging.LeveledLogger
|
||||
}
|
||||
|
||||
// Config is used to configure the data channel.
|
||||
type Config struct {
|
||||
ChannelType ChannelType
|
||||
Negotiated bool
|
||||
Priority uint16
|
||||
ReliabilityParameter uint32
|
||||
Label string
|
||||
Protocol string
|
||||
LoggerFactory logging.LoggerFactory
|
||||
}
|
||||
|
||||
func newDataChannel(stream *sctp.Stream, config *Config) (*DataChannel, error) {
|
||||
return &DataChannel{
|
||||
Config: *config,
|
||||
stream: stream,
|
||||
log: config.LoggerFactory.NewLogger("datachannel"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Dial opens a data channels over SCTP
|
||||
func Dial(a *sctp.Association, id uint16, config *Config) (*DataChannel, error) {
|
||||
stream, err := a.OpenStream(id, sctp.PayloadTypeWebRTCBinary)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dc, err := Client(stream, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return dc, nil
|
||||
}
|
||||
|
||||
// Client opens a data channel over an SCTP stream
|
||||
func Client(stream *sctp.Stream, config *Config) (*DataChannel, error) {
|
||||
msg := &channelOpen{
|
||||
ChannelType: config.ChannelType,
|
||||
Priority: config.Priority,
|
||||
ReliabilityParameter: config.ReliabilityParameter,
|
||||
|
||||
Label: []byte(config.Label),
|
||||
Protocol: []byte(config.Protocol),
|
||||
}
|
||||
|
||||
if !config.Negotiated {
|
||||
rawMsg, err := msg.Marshal()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal ChannelOpen %w", err)
|
||||
}
|
||||
|
||||
if _, err = stream.WriteSCTP(rawMsg, sctp.PayloadTypeWebRTCDCEP); err != nil {
|
||||
return nil, fmt.Errorf("failed to send ChannelOpen %w", err)
|
||||
}
|
||||
}
|
||||
return newDataChannel(stream, config)
|
||||
}
|
||||
|
||||
// Accept is used to accept incoming data channels over SCTP
|
||||
func Accept(a *sctp.Association, config *Config, existingChannels ...*DataChannel) (*DataChannel, error) {
|
||||
stream, err := a.AcceptStream()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, ch := range existingChannels {
|
||||
if ch.StreamIdentifier() == stream.StreamIdentifier() {
|
||||
ch.stream.SetDefaultPayloadType(sctp.PayloadTypeWebRTCBinary)
|
||||
return ch, nil
|
||||
}
|
||||
}
|
||||
|
||||
stream.SetDefaultPayloadType(sctp.PayloadTypeWebRTCBinary)
|
||||
|
||||
dc, err := Server(stream, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return dc, nil
|
||||
}
|
||||
|
||||
// Server accepts a data channel over an SCTP stream
|
||||
func Server(stream *sctp.Stream, config *Config) (*DataChannel, error) {
|
||||
buffer := make([]byte, receiveMTU)
|
||||
n, ppi, err := stream.ReadSCTP(buffer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ppi != sctp.PayloadTypeWebRTCDCEP {
|
||||
return nil, fmt.Errorf("%w %s", ErrInvalidPayloadProtocolIdentifier, ppi)
|
||||
}
|
||||
|
||||
openMsg, err := parseExpectDataChannelOpen(buffer[:n])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse DataChannelOpen packet %w", err)
|
||||
}
|
||||
|
||||
config.ChannelType = openMsg.ChannelType
|
||||
config.Priority = openMsg.Priority
|
||||
config.ReliabilityParameter = openMsg.ReliabilityParameter
|
||||
config.Label = string(openMsg.Label)
|
||||
config.Protocol = string(openMsg.Protocol)
|
||||
|
||||
dataChannel, err := newDataChannel(stream, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = dataChannel.writeDataChannelAck()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = dataChannel.commitReliabilityParams()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dataChannel, nil
|
||||
}
|
||||
|
||||
// Read reads a packet of len(p) bytes as binary data
|
||||
func (c *DataChannel) Read(p []byte) (int, error) {
|
||||
n, _, err := c.ReadDataChannel(p)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// ReadDataChannel reads a packet of len(p) bytes
|
||||
func (c *DataChannel) ReadDataChannel(p []byte) (int, bool, error) {
|
||||
for {
|
||||
n, ppi, err := c.stream.ReadSCTP(p)
|
||||
if err == io.EOF {
|
||||
// When the peer sees that an incoming stream was
|
||||
// reset, it also resets its corresponding outgoing stream.
|
||||
if closeErr := c.stream.Close(); closeErr != nil {
|
||||
return 0, false, closeErr
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return 0, false, err
|
||||
}
|
||||
|
||||
if ppi == sctp.PayloadTypeWebRTCDCEP {
|
||||
if err = c.handleDCEP(p[:n]); err != nil {
|
||||
c.log.Errorf("Failed to handle DCEP: %s", err.Error())
|
||||
}
|
||||
continue
|
||||
} else if ppi == sctp.PayloadTypeWebRTCBinaryEmpty || ppi == sctp.PayloadTypeWebRTCStringEmpty {
|
||||
n = 0
|
||||
}
|
||||
|
||||
atomic.AddUint32(&c.messagesReceived, 1)
|
||||
atomic.AddUint64(&c.bytesReceived, uint64(n))
|
||||
|
||||
isString := ppi == sctp.PayloadTypeWebRTCString || ppi == sctp.PayloadTypeWebRTCStringEmpty
|
||||
return n, isString, err
|
||||
}
|
||||
}
|
||||
|
||||
// MessagesSent returns the number of messages sent
|
||||
func (c *DataChannel) MessagesSent() uint32 {
|
||||
return atomic.LoadUint32(&c.messagesSent)
|
||||
}
|
||||
|
||||
// MessagesReceived returns the number of messages received
|
||||
func (c *DataChannel) MessagesReceived() uint32 {
|
||||
return atomic.LoadUint32(&c.messagesReceived)
|
||||
}
|
||||
|
||||
// OnOpen sets an event handler which is invoked when
|
||||
// a DATA_CHANNEL_ACK message is received.
|
||||
// The handler is called only on thefor the channel opened
|
||||
// https://datatracker.ietf.org/doc/html/draft-ietf-rtcweb-data-protocol-09#section-5.2
|
||||
func (c *DataChannel) OnOpen(f func()) {
|
||||
c.mu.Lock()
|
||||
c.openCompleteHandlerOnce = sync.Once{}
|
||||
c.onOpenCompleteHandler = f
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
func (c *DataChannel) onOpenComplete() {
|
||||
c.mu.Lock()
|
||||
hdlr := c.onOpenCompleteHandler
|
||||
c.mu.Unlock()
|
||||
|
||||
if hdlr != nil {
|
||||
go c.openCompleteHandlerOnce.Do(func() {
|
||||
hdlr()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// BytesSent returns the number of bytes sent
|
||||
func (c *DataChannel) BytesSent() uint64 {
|
||||
return atomic.LoadUint64(&c.bytesSent)
|
||||
}
|
||||
|
||||
// BytesReceived returns the number of bytes received
|
||||
func (c *DataChannel) BytesReceived() uint64 {
|
||||
return atomic.LoadUint64(&c.bytesReceived)
|
||||
}
|
||||
|
||||
// StreamIdentifier returns the Stream identifier associated to the stream.
|
||||
func (c *DataChannel) StreamIdentifier() uint16 {
|
||||
return c.stream.StreamIdentifier()
|
||||
}
|
||||
|
||||
func (c *DataChannel) handleDCEP(data []byte) error {
|
||||
msg, err := parse(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse DataChannel packet %w", err)
|
||||
}
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case *channelAck:
|
||||
c.log.Debug("Received DATA_CHANNEL_ACK")
|
||||
if err = c.commitReliabilityParams(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.onOpenComplete()
|
||||
default:
|
||||
return fmt.Errorf("%w %v", ErrInvalidMessageType, msg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write writes len(p) bytes from p as binary data
|
||||
func (c *DataChannel) Write(p []byte) (n int, err error) {
|
||||
return c.WriteDataChannel(p, false)
|
||||
}
|
||||
|
||||
// WriteDataChannel writes len(p) bytes from p
|
||||
func (c *DataChannel) WriteDataChannel(p []byte, isString bool) (n int, err error) {
|
||||
// https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-12#section-6.6
|
||||
// SCTP does not support the sending of empty user messages. Therefore,
|
||||
// if an empty message has to be sent, the appropriate PPID (WebRTC
|
||||
// String Empty or WebRTC Binary Empty) is used and the SCTP user
|
||||
// message of one zero byte is sent. When receiving an SCTP user
|
||||
// message with one of these PPIDs, the receiver MUST ignore the SCTP
|
||||
// user message and process it as an empty message.
|
||||
var ppi sctp.PayloadProtocolIdentifier
|
||||
switch {
|
||||
case !isString && len(p) > 0:
|
||||
ppi = sctp.PayloadTypeWebRTCBinary
|
||||
case !isString && len(p) == 0:
|
||||
ppi = sctp.PayloadTypeWebRTCBinaryEmpty
|
||||
case isString && len(p) > 0:
|
||||
ppi = sctp.PayloadTypeWebRTCString
|
||||
case isString && len(p) == 0:
|
||||
ppi = sctp.PayloadTypeWebRTCStringEmpty
|
||||
}
|
||||
|
||||
atomic.AddUint32(&c.messagesSent, 1)
|
||||
atomic.AddUint64(&c.bytesSent, uint64(len(p)))
|
||||
|
||||
if len(p) == 0 {
|
||||
_, err := c.stream.WriteSCTP([]byte{0}, ppi)
|
||||
return 0, err
|
||||
}
|
||||
return c.stream.WriteSCTP(p, ppi)
|
||||
}
|
||||
|
||||
func (c *DataChannel) writeDataChannelAck() error {
|
||||
ack := channelAck{}
|
||||
ackMsg, err := ack.Marshal()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal ChannelOpen ACK: %w", err)
|
||||
}
|
||||
|
||||
if _, err = c.stream.WriteSCTP(ackMsg, sctp.PayloadTypeWebRTCDCEP); err != nil {
|
||||
return fmt.Errorf("failed to send ChannelOpen ACK: %w", err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Close closes the DataChannel and the underlying SCTP stream.
|
||||
func (c *DataChannel) Close() error {
|
||||
// https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-6.7
|
||||
// Closing of a data channel MUST be signaled by resetting the
|
||||
// corresponding outgoing streams [RFC6525]. This means that if one
|
||||
// side decides to close the data channel, it resets the corresponding
|
||||
// outgoing stream. When the peer sees that an incoming stream was
|
||||
// reset, it also resets its corresponding outgoing stream. Once this
|
||||
// is completed, the data channel is closed. Resetting a stream sets
|
||||
// the Stream Sequence Numbers (SSNs) of the stream back to 'zero' with
|
||||
// a corresponding notification to the application layer that the reset
|
||||
// has been performed. Streams are available for reuse after a reset
|
||||
// has been performed.
|
||||
return c.stream.Close()
|
||||
}
|
||||
|
||||
// BufferedAmount returns the number of bytes of data currently queued to be
|
||||
// sent over this stream.
|
||||
func (c *DataChannel) BufferedAmount() uint64 {
|
||||
return c.stream.BufferedAmount()
|
||||
}
|
||||
|
||||
// BufferedAmountLowThreshold returns the number of bytes of buffered outgoing
|
||||
// data that is considered "low." Defaults to 0.
|
||||
func (c *DataChannel) BufferedAmountLowThreshold() uint64 {
|
||||
return c.stream.BufferedAmountLowThreshold()
|
||||
}
|
||||
|
||||
// SetBufferedAmountLowThreshold is used to update the threshold.
|
||||
// See BufferedAmountLowThreshold().
|
||||
func (c *DataChannel) SetBufferedAmountLowThreshold(th uint64) {
|
||||
c.stream.SetBufferedAmountLowThreshold(th)
|
||||
}
|
||||
|
||||
// OnBufferedAmountLow sets the callback handler which would be called when the
|
||||
// number of bytes of outgoing data buffered is lower than the threshold.
|
||||
func (c *DataChannel) OnBufferedAmountLow(f func()) {
|
||||
c.stream.OnBufferedAmountLow(f)
|
||||
}
|
||||
|
||||
func (c *DataChannel) commitReliabilityParams() error {
|
||||
switch c.Config.ChannelType {
|
||||
case ChannelTypeReliable:
|
||||
c.stream.SetReliabilityParams(false, sctp.ReliabilityTypeReliable, c.Config.ReliabilityParameter)
|
||||
case ChannelTypeReliableUnordered:
|
||||
c.stream.SetReliabilityParams(true, sctp.ReliabilityTypeReliable, c.Config.ReliabilityParameter)
|
||||
case ChannelTypePartialReliableRexmit:
|
||||
c.stream.SetReliabilityParams(false, sctp.ReliabilityTypeRexmit, c.Config.ReliabilityParameter)
|
||||
case ChannelTypePartialReliableRexmitUnordered:
|
||||
c.stream.SetReliabilityParams(true, sctp.ReliabilityTypeRexmit, c.Config.ReliabilityParameter)
|
||||
case ChannelTypePartialReliableTimed:
|
||||
c.stream.SetReliabilityParams(false, sctp.ReliabilityTypeTimed, c.Config.ReliabilityParameter)
|
||||
case ChannelTypePartialReliableTimedUnordered:
|
||||
c.stream.SetReliabilityParams(true, sctp.ReliabilityTypeTimed, c.Config.ReliabilityParameter)
|
||||
default:
|
||||
return fmt.Errorf("%w %v", ErrInvalidChannelType, c.Config.ChannelType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
24
vendor/github.com/pion/datachannel/errors.go
generated
vendored
Normal file
24
vendor/github.com/pion/datachannel/errors.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package datachannel
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
// ErrDataChannelMessageTooShort means that the data isn't long enough to be a valid DataChannel message
|
||||
ErrDataChannelMessageTooShort = errors.New("DataChannel message is not long enough to determine type")
|
||||
|
||||
// ErrInvalidPayloadProtocolIdentifier means that we got a DataChannel messages with a Payload Protocol Identifier
|
||||
// we don't know how to handle
|
||||
ErrInvalidPayloadProtocolIdentifier = errors.New("DataChannel message Payload Protocol Identifier is value we can't handle")
|
||||
|
||||
// ErrInvalidChannelType means that the remote requested a channel type that we don't support
|
||||
ErrInvalidChannelType = errors.New("invalid Channel Type")
|
||||
|
||||
// ErrInvalidMessageType is returned when a DataChannel Message has a type we don't support
|
||||
ErrInvalidMessageType = errors.New("invalid Message Type")
|
||||
|
||||
// ErrExpectedAndActualLengthMismatch is when the declared length and actual length don't match
|
||||
ErrExpectedAndActualLengthMismatch = errors.New("expected and actual length do not match")
|
||||
|
||||
// ErrUnexpectedDataChannelType is when a message type does not match the expected type
|
||||
ErrUnexpectedDataChannelType = errors.New("expected and actual message type does not match")
|
||||
)
|
||||
73
vendor/github.com/pion/datachannel/message.go
generated
vendored
Normal file
73
vendor/github.com/pion/datachannel/message.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
package datachannel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// message is a parsed DataChannel message
|
||||
type message interface {
|
||||
Marshal() ([]byte, error)
|
||||
Unmarshal([]byte) error
|
||||
}
|
||||
|
||||
// messageType is the first byte in a DataChannel message that specifies type
|
||||
type messageType byte
|
||||
|
||||
// DataChannel Message Types
|
||||
const (
|
||||
dataChannelAck messageType = 0x02
|
||||
dataChannelOpen messageType = 0x03
|
||||
)
|
||||
|
||||
func (t messageType) String() string {
|
||||
switch t {
|
||||
case dataChannelAck:
|
||||
return "DataChannelAck"
|
||||
case dataChannelOpen:
|
||||
return "DataChannelOpen"
|
||||
default:
|
||||
return fmt.Sprintf("Unknown MessageType: %d", t)
|
||||
}
|
||||
}
|
||||
|
||||
// parse accepts raw input and returns a DataChannel message
|
||||
func parse(raw []byte) (message, error) {
|
||||
if len(raw) == 0 {
|
||||
return nil, ErrDataChannelMessageTooShort
|
||||
}
|
||||
|
||||
var msg message
|
||||
switch messageType(raw[0]) {
|
||||
case dataChannelOpen:
|
||||
msg = &channelOpen{}
|
||||
case dataChannelAck:
|
||||
msg = &channelAck{}
|
||||
default:
|
||||
return nil, fmt.Errorf("%w %v", ErrInvalidMessageType, messageType(raw[0]))
|
||||
}
|
||||
|
||||
if err := msg.Unmarshal(raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// parseExpectDataChannelOpen parses a DataChannelOpen message
|
||||
// or throws an error
|
||||
func parseExpectDataChannelOpen(raw []byte) (*channelOpen, error) {
|
||||
if len(raw) == 0 {
|
||||
return nil, ErrDataChannelMessageTooShort
|
||||
}
|
||||
|
||||
if actualTyp := messageType(raw[0]); actualTyp != dataChannelOpen {
|
||||
return nil, fmt.Errorf("%w expected(%s) actual(%s)", ErrUnexpectedDataChannelType, actualTyp, dataChannelOpen)
|
||||
}
|
||||
|
||||
msg := &channelOpen{}
|
||||
if err := msg.Unmarshal(raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
22
vendor/github.com/pion/datachannel/message_channel_ack.go
generated
vendored
Normal file
22
vendor/github.com/pion/datachannel/message_channel_ack.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package datachannel
|
||||
|
||||
// channelAck is used to ACK a DataChannel open
|
||||
type channelAck struct{}
|
||||
|
||||
const (
|
||||
channelOpenAckLength = 4
|
||||
)
|
||||
|
||||
// Marshal returns raw bytes for the given message
|
||||
func (c *channelAck) Marshal() ([]byte, error) {
|
||||
raw := make([]byte, channelOpenAckLength)
|
||||
raw[0] = uint8(dataChannelAck)
|
||||
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
// Unmarshal populates the struct with the given raw data
|
||||
func (c *channelAck) Unmarshal(raw []byte) error {
|
||||
// Message type already checked in Parse and there is no further data
|
||||
return nil
|
||||
}
|
||||
122
vendor/github.com/pion/datachannel/message_channel_open.go
generated
vendored
Normal file
122
vendor/github.com/pion/datachannel/message_channel_open.go
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
package datachannel
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
/*
|
||||
channelOpen represents a DATA_CHANNEL_OPEN Message
|
||||
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Message Type | Channel Type | Priority |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Reliability Parameter |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Label Length | Protocol Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
| Label |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
| Protocol |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
type channelOpen struct {
|
||||
ChannelType ChannelType
|
||||
Priority uint16
|
||||
ReliabilityParameter uint32
|
||||
|
||||
Label []byte
|
||||
Protocol []byte
|
||||
}
|
||||
|
||||
const (
|
||||
channelOpenHeaderLength = 12
|
||||
)
|
||||
|
||||
// ChannelType determines the reliability of the WebRTC DataChannel
|
||||
type ChannelType byte
|
||||
|
||||
// ChannelType enums
|
||||
const (
|
||||
// ChannelTypeReliable determines the Data Channel provides a
|
||||
// reliable in-order bi-directional communication.
|
||||
ChannelTypeReliable ChannelType = 0x00
|
||||
// ChannelTypeReliableUnordered determines the Data Channel
|
||||
// provides a reliable unordered bi-directional communication.
|
||||
ChannelTypeReliableUnordered ChannelType = 0x80
|
||||
// ChannelTypePartialReliableRexmit determines the Data Channel
|
||||
// provides a partially-reliable in-order bi-directional communication.
|
||||
// User messages will not be retransmitted more times than specified in the Reliability Parameter.
|
||||
ChannelTypePartialReliableRexmit ChannelType = 0x01
|
||||
// ChannelTypePartialReliableRexmitUnordered determines
|
||||
// the Data Channel provides a partial reliable unordered bi-directional communication.
|
||||
// User messages will not be retransmitted more times than specified in the Reliability Parameter.
|
||||
ChannelTypePartialReliableRexmitUnordered ChannelType = 0x81
|
||||
// ChannelTypePartialReliableTimed determines the Data Channel
|
||||
// provides a partial reliable in-order bi-directional communication.
|
||||
// User messages might not be transmitted or retransmitted after
|
||||
// a specified life-time given in milli- seconds in the Reliability Parameter.
|
||||
// This life-time starts when providing the user message to the protocol stack.
|
||||
ChannelTypePartialReliableTimed ChannelType = 0x02
|
||||
// The Data Channel provides a partial reliable unordered bi-directional
|
||||
// communication. User messages might not be transmitted or retransmitted
|
||||
// after a specified life-time given in milli- seconds in the Reliability Parameter.
|
||||
// This life-time starts when providing the user message to the protocol stack.
|
||||
ChannelTypePartialReliableTimedUnordered ChannelType = 0x82
|
||||
)
|
||||
|
||||
// ChannelPriority enums
|
||||
const (
|
||||
ChannelPriorityBelowNormal uint16 = 128
|
||||
ChannelPriorityNormal uint16 = 256
|
||||
ChannelPriorityHigh uint16 = 512
|
||||
ChannelPriorityExtraHigh uint16 = 1024
|
||||
)
|
||||
|
||||
// Marshal returns raw bytes for the given message
|
||||
func (c *channelOpen) Marshal() ([]byte, error) {
|
||||
labelLength := len(c.Label)
|
||||
protocolLength := len(c.Protocol)
|
||||
|
||||
totalLen := channelOpenHeaderLength + labelLength + protocolLength
|
||||
raw := make([]byte, totalLen)
|
||||
|
||||
raw[0] = uint8(dataChannelOpen)
|
||||
raw[1] = byte(c.ChannelType)
|
||||
binary.BigEndian.PutUint16(raw[2:], c.Priority)
|
||||
binary.BigEndian.PutUint32(raw[4:], c.ReliabilityParameter)
|
||||
binary.BigEndian.PutUint16(raw[8:], uint16(labelLength))
|
||||
binary.BigEndian.PutUint16(raw[10:], uint16(protocolLength))
|
||||
endLabel := channelOpenHeaderLength + labelLength
|
||||
copy(raw[channelOpenHeaderLength:endLabel], c.Label)
|
||||
copy(raw[endLabel:endLabel+protocolLength], c.Protocol)
|
||||
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
// Unmarshal populates the struct with the given raw data
|
||||
func (c *channelOpen) Unmarshal(raw []byte) error {
|
||||
if len(raw) < channelOpenHeaderLength {
|
||||
return fmt.Errorf("%w expected(%d) actual(%d)", ErrExpectedAndActualLengthMismatch, channelOpenHeaderLength, len(raw))
|
||||
}
|
||||
c.ChannelType = ChannelType(raw[1])
|
||||
c.Priority = binary.BigEndian.Uint16(raw[2:])
|
||||
c.ReliabilityParameter = binary.BigEndian.Uint32(raw[4:])
|
||||
|
||||
labelLength := binary.BigEndian.Uint16(raw[8:])
|
||||
protocolLength := binary.BigEndian.Uint16(raw[10:])
|
||||
|
||||
if expectedLen := int(channelOpenHeaderLength + labelLength + protocolLength); len(raw) != expectedLen {
|
||||
return fmt.Errorf("%w expected(%d) actual(%d)", ErrExpectedAndActualLengthMismatch, expectedLen, len(raw))
|
||||
}
|
||||
|
||||
c.Label = raw[channelOpenHeaderLength : channelOpenHeaderLength+labelLength]
|
||||
c.Protocol = raw[channelOpenHeaderLength+labelLength : channelOpenHeaderLength+labelLength+protocolLength]
|
||||
return nil
|
||||
}
|
||||
26
vendor/github.com/pion/datachannel/renovate.json
generated
vendored
Normal file
26
vendor/github.com/pion/datachannel/renovate.json
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"extends": [
|
||||
"config:base"
|
||||
],
|
||||
"postUpdateOptions": [
|
||||
"gomodTidy"
|
||||
],
|
||||
"commitBody": "Generated by renovateBot",
|
||||
"packageRules": [
|
||||
{
|
||||
"matchUpdateTypes": ["minor", "patch", "pin", "digest"],
|
||||
"automerge": true
|
||||
},
|
||||
{
|
||||
"packagePatterns": ["^golang.org/x/"],
|
||||
"schedule": ["on the first day of the month"]
|
||||
}
|
||||
],
|
||||
"ignorePaths": [
|
||||
".github/workflows/generate-authors.yml",
|
||||
".github/workflows/lint.yaml",
|
||||
".github/workflows/renovate-go-mod-fix.yaml",
|
||||
".github/workflows/test.yaml",
|
||||
".github/workflows/tidy-check.yaml"
|
||||
]
|
||||
}
|
||||
21
vendor/github.com/pion/dtls/v2/.editorconfig
generated
vendored
Normal file
21
vendor/github.com/pion/dtls/v2/.editorconfig
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# http://editorconfig.org/
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
end_of_line = lf
|
||||
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[{*.yml,*.yaml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# Makefiles always use tabs for indentation
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
24
vendor/github.com/pion/dtls/v2/.gitignore
generated
vendored
Normal file
24
vendor/github.com/pion/dtls/v2/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
### JetBrains IDE ###
|
||||
#####################
|
||||
.idea/
|
||||
|
||||
### Emacs Temporary Files ###
|
||||
#############################
|
||||
*~
|
||||
|
||||
### Folders ###
|
||||
###############
|
||||
bin/
|
||||
vendor/
|
||||
node_modules/
|
||||
|
||||
### Files ###
|
||||
#############
|
||||
*.ivf
|
||||
*.ogg
|
||||
tags
|
||||
cover.out
|
||||
*.sw[poe]
|
||||
*.wasm
|
||||
examples/sfu-ws/cert.pem
|
||||
examples/sfu-ws/key.pem
|
||||
89
vendor/github.com/pion/dtls/v2/.golangci.yml
generated
vendored
Normal file
89
vendor/github.com/pion/dtls/v2/.golangci.yml
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
linters-settings:
|
||||
govet:
|
||||
check-shadowing: true
|
||||
misspell:
|
||||
locale: US
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: true
|
||||
gomodguard:
|
||||
blocked:
|
||||
modules:
|
||||
- github.com/pkg/errors:
|
||||
recommendations:
|
||||
- errors
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers
|
||||
- bodyclose # checks whether HTTP response body is closed successfully
|
||||
- deadcode # Finds unused code
|
||||
- depguard # Go linter that checks if package imports are in a list of acceptable packages
|
||||
- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
|
||||
- dupl # Tool for code clone detection
|
||||
- errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
|
||||
- exhaustive # check exhaustiveness of enum switch statements
|
||||
- exportloopref # checks for pointers to enclosing loop variables
|
||||
- gci # Gci control golang package import order and make it always deterministic.
|
||||
- gochecknoglobals # Checks that no globals are present in Go code
|
||||
- gochecknoinits # Checks that no init functions are present in Go code
|
||||
- gocognit # Computes and checks the cognitive complexity of functions
|
||||
- goconst # Finds repeated strings that could be replaced by a constant
|
||||
- gocritic # The most opinionated Go source code linter
|
||||
- godox # Tool for detection of FIXME, TODO and other comment keywords
|
||||
- goerr113 # Golang linter to check the errors handling expressions
|
||||
- gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
|
||||
- gofumpt # Gofumpt checks whether code was gofumpt-ed.
|
||||
- goheader # Checks is file header matches to pattern
|
||||
- goimports # Goimports does everything that gofmt does. Additionally it checks unused imports
|
||||
- golint # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes
|
||||
- gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations.
|
||||
- goprintffuncname # Checks that printf-like functions are named with `f` at the end
|
||||
- gosec # Inspects source code for security problems
|
||||
- gosimple # Linter for Go source code that specializes in simplifying a code
|
||||
- govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
|
||||
- ineffassign # Detects when assignments to existing variables are not used
|
||||
- misspell # Finds commonly misspelled English words in comments
|
||||
- nakedret # Finds naked returns in functions greater than a specified function length
|
||||
- noctx # noctx finds sending http request without context.Context
|
||||
- scopelint # Scopelint checks for unpinned variables in go programs
|
||||
- staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks
|
||||
- structcheck # Finds unused struct fields
|
||||
- stylecheck # Stylecheck is a replacement for golint
|
||||
- typecheck # Like the front-end of a Go compiler, parses and type-checks Go code
|
||||
- unconvert # Remove unnecessary type conversions
|
||||
- unparam # Reports unused function parameters
|
||||
- unused # Checks Go code for unused constants, variables, functions and types
|
||||
- varcheck # Finds unused global variables and constants
|
||||
- whitespace # Tool for detection of leading and trailing whitespace
|
||||
disable:
|
||||
- funlen # Tool for detection of long functions
|
||||
- gocyclo # Computes and checks the cyclomatic complexity of functions
|
||||
- godot # Check if comments end in a period
|
||||
- gomnd # An analyzer to detect magic numbers.
|
||||
- lll # Reports long lines
|
||||
- maligned # Tool to detect Go structs that would take less memory if their fields were sorted
|
||||
- nestif # Reports deeply nested if statements
|
||||
- nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity
|
||||
- nolintlint # Reports ill-formed or insufficient nolint directives
|
||||
- prealloc # Finds slice declarations that could potentially be preallocated
|
||||
- rowserrcheck # checks whether Err of rows is checked successfully
|
||||
- sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed.
|
||||
- testpackage # linter that makes you use a separate _test package
|
||||
- wsl # Whitespace Linter - Forces you to use empty lines!
|
||||
|
||||
issues:
|
||||
exclude-use-default: false
|
||||
exclude-rules:
|
||||
# Allow complex tests, better to be self contained
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- gocognit
|
||||
|
||||
# Allow complex main function in examples
|
||||
- path: examples
|
||||
text: "of func `main` is high"
|
||||
linters:
|
||||
- gocognit
|
||||
|
||||
run:
|
||||
skip-dirs-use-default: false
|
||||
45
vendor/github.com/pion/dtls/v2/AUTHORS.txt
generated
vendored
Normal file
45
vendor/github.com/pion/dtls/v2/AUTHORS.txt
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
# Thank you to everyone that made Pion possible. If you are interested in contributing
|
||||
# we would love to have you https://github.com/pion/webrtc/wiki/Contributing
|
||||
#
|
||||
# This file is auto generated, using git to list all individuals contributors.
|
||||
# see `.github/generate-authors.sh` for the scripting
|
||||
Aleksandr Razumov <ar@gortc.io>
|
||||
alvarowolfx <alvarowolfx@gmail.com>
|
||||
Arlo Breault <arlolra@gmail.com>
|
||||
Atsushi Watanabe <atsushi.w@ieee.org>
|
||||
backkem <mail@backkem.me>
|
||||
bjdgyc <bjdgyc@163.com>
|
||||
boks1971 <raja.gobi@tutanota.com>
|
||||
Bragadeesh <bragboy@gmail.com>
|
||||
Carson Hoffman <c@rsonhoffman.com>
|
||||
Cecylia Bocovich <cohosh@torproject.org>
|
||||
Chris Hiszpanski <thinkski@users.noreply.github.com>
|
||||
Daniele Sluijters <daenney@users.noreply.github.com>
|
||||
folbrich <frank.olbricht@gmail.com>
|
||||
Hayden James <hayden.james@gmail.com>
|
||||
Hugo Arregui <hugo.arregui@gmail.com>
|
||||
Hugo Arregui <hugo@decentraland.org>
|
||||
igolaizola <11333576+igolaizola@users.noreply.github.com>
|
||||
Jeffrey Stoke <me@arhat.dev>
|
||||
Jeroen de Bruijn <vidavidorra+jdbruijn@gmail.com>
|
||||
Jeroen de Bruijn <vidavidorra@gmail.com>
|
||||
Jim Wert <jimwert@gmail.com>
|
||||
jinleileiking <jinleileiking@gmail.com>
|
||||
Jozef Kralik <jojo.lwin@gmail.com>
|
||||
Julien Salleyron <julien.salleyron@gmail.com>
|
||||
Kegan Dougal <kegan@matrix.org>
|
||||
Lander Noterman <lander.noterman@basalte.be>
|
||||
Len <len@hpcnt.com>
|
||||
Lukas Lihotzki <lukas@lihotzki.de>
|
||||
Michael Zabka <zabka.michael@gmail.com>
|
||||
Michiel De Backker <mail@backkem.me>
|
||||
Robert Eperjesi <eperjesi@uber.com>
|
||||
Ryan Gordon <ryan.gordon@getcruise.com>
|
||||
Sean DuBois <seaduboi@amazon.com>
|
||||
Sean DuBois <sean@siobud.com>
|
||||
Stefan Tatschner <stefan@rumpelsepp.org>
|
||||
Vadim <fffilimonov@yandex.ru>
|
||||
Vadim Filimonov <fffilimonov@yandex.ru>
|
||||
wmiao <wu.miao@viasat.com>
|
||||
ZHENK <chengzhenyang@gmail.com>
|
||||
吕海涛 <hi@taoshu.in>
|
||||
21
vendor/github.com/pion/dtls/v2/LICENSE
generated
vendored
Normal file
21
vendor/github.com/pion/dtls/v2/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
6
vendor/github.com/pion/dtls/v2/Makefile
generated
vendored
Normal file
6
vendor/github.com/pion/dtls/v2/Makefile
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
fuzz-build-record-layer: fuzz-prepare
|
||||
go-fuzz-build -tags gofuzz -func FuzzRecordLayer
|
||||
fuzz-run-record-layer:
|
||||
go-fuzz -bin dtls-fuzz.zip -workdir fuzz
|
||||
fuzz-prepare:
|
||||
@GO111MODULE=on go mod vendor
|
||||
132
vendor/github.com/pion/dtls/v2/README.md
generated
vendored
Normal file
132
vendor/github.com/pion/dtls/v2/README.md
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
<h1 align="center">
|
||||
<br>
|
||||
Pion DTLS
|
||||
<br>
|
||||
</h1>
|
||||
<h4 align="center">A Go implementation of DTLS</h4>
|
||||
<p align="center">
|
||||
<a href="https://pion.ly"><img src="https://img.shields.io/badge/pion-dtls-gray.svg?longCache=true&colorB=brightgreen" alt="Pion DTLS"></a>
|
||||
<a href="https://sourcegraph.com/github.com/pion/dtls"><img src="https://sourcegraph.com/github.com/pion/dtls/-/badge.svg" alt="Sourcegraph Widget"></a>
|
||||
<a href="https://pion.ly/slack"><img src="https://img.shields.io/badge/join-us%20on%20slack-gray.svg?longCache=true&logo=slack&colorB=brightgreen" alt="Slack Widget"></a>
|
||||
<br>
|
||||
<a href="https://travis-ci.org/pion/dtls"><img src="https://travis-ci.org/pion/dtls.svg?branch=master" alt="Build Status"></a>
|
||||
<a href="https://pkg.go.dev/github.com/pion/dtls/v2"><img src="https://godoc.org/github.com/pion/dtls?status.svg" alt="GoDoc"></a>
|
||||
<a href="https://codecov.io/gh/pion/dtls"><img src="https://codecov.io/gh/pion/dtls/branch/master/graph/badge.svg" alt="Coverage Status"></a>
|
||||
<a href="https://goreportcard.com/report/github.com/pion/dtls"><img src="https://goreportcard.com/badge/github.com/pion/dtls" alt="Go Report Card"></a>
|
||||
<a href="https://www.codacy.com/app/Sean-Der/dtls"><img src="https://api.codacy.com/project/badge/Grade/18f4aec384894e6aac0b94effe51961d" alt="Codacy Badge"></a>
|
||||
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
|
||||
</p>
|
||||
<br>
|
||||
|
||||
Native [DTLS 1.2][rfc6347] implementation in the Go programming language.
|
||||
|
||||
A long term goal is a professional security review, and maybe an inclusion in stdlib.
|
||||
|
||||
[rfc6347]: https://tools.ietf.org/html/rfc6347
|
||||
|
||||
### Goals/Progress
|
||||
This will only be targeting DTLS 1.2, and the most modern/common cipher suites.
|
||||
We would love contributions that fall under the 'Planned Features' and any bug fixes!
|
||||
|
||||
#### Current features
|
||||
* DTLS 1.2 Client/Server
|
||||
* Key Exchange via ECDHE(curve25519, nistp256, nistp384) and PSK
|
||||
* Packet loss and re-ordering is handled during handshaking
|
||||
* Key export ([RFC 5705][rfc5705])
|
||||
* Serialization and Resumption of sessions
|
||||
* Extended Master Secret extension ([RFC 7627][rfc7627])
|
||||
* ALPN extension ([RFC 7301][rfc7301])
|
||||
|
||||
[rfc5705]: https://tools.ietf.org/html/rfc5705
|
||||
[rfc7627]: https://tools.ietf.org/html/rfc7627
|
||||
[rfc7301]: https://tools.ietf.org/html/rfc7301
|
||||
|
||||
#### Supported ciphers
|
||||
|
||||
##### ECDHE
|
||||
* TLS_ECDHE_ECDSA_WITH_AES_128_CCM ([RFC 6655][rfc6655])
|
||||
* TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 ([RFC 6655][rfc6655])
|
||||
* TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 ([RFC 5289][rfc5289])
|
||||
* TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ([RFC 5289][rfc5289])
|
||||
* TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 ([RFC 5289][rfc5289])
|
||||
* TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ([RFC 5289][rfc5289])
|
||||
* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA ([RFC 8422][rfc8422])
|
||||
* TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA ([RFC 8422][rfc8422])
|
||||
|
||||
##### PSK
|
||||
* TLS_PSK_WITH_AES_128_CCM ([RFC 6655][rfc6655])
|
||||
* TLS_PSK_WITH_AES_128_CCM_8 ([RFC 6655][rfc6655])
|
||||
* TLS_PSK_WITH_AES_128_GCM_SHA256 ([RFC 5487][rfc5487])
|
||||
* TLS_PSK_WITH_AES_128_CBC_SHA256 ([RFC 5487][rfc5487])
|
||||
|
||||
[rfc5289]: https://tools.ietf.org/html/rfc5289
|
||||
[rfc8422]: https://tools.ietf.org/html/rfc8422
|
||||
[rfc6655]: https://tools.ietf.org/html/rfc6655
|
||||
[rfc5487]: https://tools.ietf.org/html/rfc5487
|
||||
|
||||
#### Planned Features
|
||||
* Chacha20Poly1305
|
||||
|
||||
#### Excluded Features
|
||||
* DTLS 1.0
|
||||
* Renegotiation
|
||||
* Compression
|
||||
|
||||
### Using
|
||||
|
||||
This library needs at least Go 1.13, and you should have [Go modules
|
||||
enabled](https://github.com/golang/go/wiki/Modules).
|
||||
|
||||
#### Pion DTLS
|
||||
For a DTLS 1.2 Server that listens on 127.0.0.1:4444
|
||||
```sh
|
||||
go run examples/listen/selfsign/main.go
|
||||
```
|
||||
|
||||
For a DTLS 1.2 Client that connects to 127.0.0.1:4444
|
||||
```sh
|
||||
go run examples/dial/selfsign/main.go
|
||||
```
|
||||
|
||||
#### OpenSSL
|
||||
Pion DTLS can connect to itself and OpenSSL.
|
||||
```
|
||||
// Generate a certificate
|
||||
openssl ecparam -out key.pem -name prime256v1 -genkey
|
||||
openssl req -new -sha256 -key key.pem -out server.csr
|
||||
openssl x509 -req -sha256 -days 365 -in server.csr -signkey key.pem -out cert.pem
|
||||
|
||||
// Use with examples/dial/selfsign/main.go
|
||||
openssl s_server -dtls1_2 -cert cert.pem -key key.pem -accept 4444
|
||||
|
||||
// Use with examples/listen/selfsign/main.go
|
||||
openssl s_client -dtls1_2 -connect 127.0.0.1:4444 -debug -cert cert.pem -key key.pem
|
||||
```
|
||||
|
||||
### Using with PSK
|
||||
Pion DTLS also comes with examples that do key exchange via PSK
|
||||
|
||||
|
||||
#### Pion DTLS
|
||||
```sh
|
||||
go run examples/listen/psk/main.go
|
||||
```
|
||||
|
||||
```sh
|
||||
go run examples/dial/psk/main.go
|
||||
```
|
||||
|
||||
#### OpenSSL
|
||||
```
|
||||
// Use with examples/dial/psk/main.go
|
||||
openssl s_server -dtls1_2 -accept 4444 -nocert -psk abc123 -cipher PSK-AES128-CCM8
|
||||
|
||||
// Use with examples/listen/psk/main.go
|
||||
openssl s_client -dtls1_2 -connect 127.0.0.1:4444 -psk abc123 -cipher PSK-AES128-CCM8
|
||||
```
|
||||
|
||||
### Contributing
|
||||
Check out the **[contributing wiki](https://github.com/pion/webrtc/wiki/Contributing)** to join the group of amazing people making this project possible:
|
||||
|
||||
### License
|
||||
MIT License - see [LICENSE](LICENSE) for full text
|
||||
67
vendor/github.com/pion/dtls/v2/certificate.go
generated
vendored
Normal file
67
vendor/github.com/pion/dtls/v2/certificate.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (c *handshakeConfig) getCertificate(serverName string) (*tls.Certificate, error) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
if c.nameToCertificate == nil {
|
||||
nameToCertificate := make(map[string]*tls.Certificate)
|
||||
for i := range c.localCertificates {
|
||||
cert := &c.localCertificates[i]
|
||||
x509Cert := cert.Leaf
|
||||
if x509Cert == nil {
|
||||
var parseErr error
|
||||
x509Cert, parseErr = x509.ParseCertificate(cert.Certificate[0])
|
||||
if parseErr != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if len(x509Cert.Subject.CommonName) > 0 {
|
||||
nameToCertificate[strings.ToLower(x509Cert.Subject.CommonName)] = cert
|
||||
}
|
||||
for _, san := range x509Cert.DNSNames {
|
||||
nameToCertificate[strings.ToLower(san)] = cert
|
||||
}
|
||||
}
|
||||
c.nameToCertificate = nameToCertificate
|
||||
}
|
||||
|
||||
if len(c.localCertificates) == 0 {
|
||||
return nil, errNoCertificates
|
||||
}
|
||||
|
||||
if len(c.localCertificates) == 1 {
|
||||
// There's only one choice, so no point doing any work.
|
||||
return &c.localCertificates[0], nil
|
||||
}
|
||||
|
||||
if len(serverName) == 0 {
|
||||
return &c.localCertificates[0], nil
|
||||
}
|
||||
|
||||
name := strings.TrimRight(strings.ToLower(serverName), ".")
|
||||
|
||||
if cert, ok := c.nameToCertificate[name]; ok {
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// try replacing labels in the name with wildcards until we get a
|
||||
// match.
|
||||
labels := strings.Split(name, ".")
|
||||
for i := range labels {
|
||||
labels[i] = "*"
|
||||
candidate := strings.Join(labels, ".")
|
||||
if cert, ok := c.nameToCertificate[candidate]; ok {
|
||||
return cert, nil
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing matches, return the first certificate.
|
||||
return &c.localCertificates[0], nil
|
||||
}
|
||||
248
vendor/github.com/pion/dtls/v2/cipher_suite.go
generated
vendored
Normal file
248
vendor/github.com/pion/dtls/v2/cipher_suite.go
generated
vendored
Normal file
@@ -0,0 +1,248 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"hash"
|
||||
|
||||
"github.com/pion/dtls/v2/internal/ciphersuite"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
|
||||
)
|
||||
|
||||
// CipherSuiteID is an ID for our supported CipherSuites
|
||||
type CipherSuiteID = ciphersuite.ID
|
||||
|
||||
// Supported Cipher Suites
|
||||
const (
|
||||
// AES-128-CCM
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_CCM CipherSuiteID = ciphersuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM //nolint:golint,stylecheck
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 CipherSuiteID = ciphersuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 //nolint:golint,stylecheck
|
||||
|
||||
// AES-128-GCM-SHA256
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 CipherSuiteID = ciphersuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 //nolint:golint,stylecheck
|
||||
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 CipherSuiteID = ciphersuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 //nolint:golint,stylecheck
|
||||
|
||||
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 CipherSuiteID = ciphersuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 //nolint:golint,stylecheck
|
||||
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 CipherSuiteID = ciphersuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 //nolint:golint,stylecheck
|
||||
|
||||
// AES-256-CBC-SHA
|
||||
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA CipherSuiteID = ciphersuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA //nolint:golint,stylecheck
|
||||
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA CipherSuiteID = ciphersuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA //nolint:golint,stylecheck
|
||||
|
||||
TLS_PSK_WITH_AES_128_CCM CipherSuiteID = ciphersuite.TLS_PSK_WITH_AES_128_CCM //nolint:golint,stylecheck
|
||||
TLS_PSK_WITH_AES_128_CCM_8 CipherSuiteID = ciphersuite.TLS_PSK_WITH_AES_128_CCM_8 //nolint:golint,stylecheck
|
||||
TLS_PSK_WITH_AES_128_GCM_SHA256 CipherSuiteID = ciphersuite.TLS_PSK_WITH_AES_128_GCM_SHA256 //nolint:golint,stylecheck
|
||||
TLS_PSK_WITH_AES_128_CBC_SHA256 CipherSuiteID = ciphersuite.TLS_PSK_WITH_AES_128_CBC_SHA256 //nolint:golint,stylecheck
|
||||
)
|
||||
|
||||
// CipherSuiteAuthenticationType controls what authentication method is using during the handshake for a CipherSuite
|
||||
type CipherSuiteAuthenticationType = ciphersuite.AuthenticationType
|
||||
|
||||
// AuthenticationType Enums
|
||||
const (
|
||||
CipherSuiteAuthenticationTypeCertificate CipherSuiteAuthenticationType = ciphersuite.AuthenticationTypeCertificate
|
||||
CipherSuiteAuthenticationTypePreSharedKey CipherSuiteAuthenticationType = ciphersuite.AuthenticationTypePreSharedKey
|
||||
CipherSuiteAuthenticationTypeAnonymous CipherSuiteAuthenticationType = ciphersuite.AuthenticationTypeAnonymous
|
||||
)
|
||||
|
||||
var _ = allCipherSuites() // Necessary until this function isn't only used by Go 1.14
|
||||
|
||||
// CipherSuite is an interface that all DTLS CipherSuites must satisfy
|
||||
type CipherSuite interface {
|
||||
// String of CipherSuite, only used for logging
|
||||
String() string
|
||||
|
||||
// ID of CipherSuite.
|
||||
ID() CipherSuiteID
|
||||
|
||||
// What type of Certificate does this CipherSuite use
|
||||
CertificateType() clientcertificate.Type
|
||||
|
||||
// What Hash function is used during verification
|
||||
HashFunc() func() hash.Hash
|
||||
|
||||
// AuthenticationType controls what authentication method is using during the handshake
|
||||
AuthenticationType() CipherSuiteAuthenticationType
|
||||
|
||||
// Called when keying material has been generated, should initialize the internal cipher
|
||||
Init(masterSecret, clientRandom, serverRandom []byte, isClient bool) error
|
||||
IsInitialized() bool
|
||||
Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error)
|
||||
Decrypt(in []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
// CipherSuiteName provides the same functionality as tls.CipherSuiteName
|
||||
// that appeared first in Go 1.14.
|
||||
//
|
||||
// Our implementation differs slightly in that it takes in a CiperSuiteID,
|
||||
// like the rest of our library, instead of a uint16 like crypto/tls.
|
||||
func CipherSuiteName(id CipherSuiteID) string {
|
||||
suite := cipherSuiteForID(id, nil)
|
||||
if suite != nil {
|
||||
return suite.String()
|
||||
}
|
||||
return fmt.Sprintf("0x%04X", uint16(id))
|
||||
}
|
||||
|
||||
// Taken from https://www.iana.org/assignments/tls-parameters/tls-parameters.xml
|
||||
// A cipherSuite is a specific combination of key agreement, cipher and MAC
|
||||
// function.
|
||||
func cipherSuiteForID(id CipherSuiteID, customCiphers func() []CipherSuite) CipherSuite {
|
||||
switch id { //nolint:exhaustive
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
|
||||
return ciphersuite.NewTLSEcdheEcdsaWithAes128Ccm()
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
|
||||
return ciphersuite.NewTLSEcdheEcdsaWithAes128Ccm8()
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
|
||||
return &ciphersuite.TLSEcdheEcdsaWithAes128GcmSha256{}
|
||||
case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
|
||||
return &ciphersuite.TLSEcdheRsaWithAes128GcmSha256{}
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
|
||||
return &ciphersuite.TLSEcdheEcdsaWithAes256CbcSha{}
|
||||
case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
|
||||
return &ciphersuite.TLSEcdheRsaWithAes256CbcSha{}
|
||||
case TLS_PSK_WITH_AES_128_CCM:
|
||||
return ciphersuite.NewTLSPskWithAes128Ccm()
|
||||
case TLS_PSK_WITH_AES_128_CCM_8:
|
||||
return ciphersuite.NewTLSPskWithAes128Ccm8()
|
||||
case TLS_PSK_WITH_AES_128_GCM_SHA256:
|
||||
return &ciphersuite.TLSPskWithAes128GcmSha256{}
|
||||
case TLS_PSK_WITH_AES_128_CBC_SHA256:
|
||||
return &ciphersuite.TLSPskWithAes128CbcSha256{}
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
|
||||
return &ciphersuite.TLSEcdheEcdsaWithAes256GcmSha384{}
|
||||
case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
|
||||
return &ciphersuite.TLSEcdheRsaWithAes256GcmSha384{}
|
||||
}
|
||||
|
||||
if customCiphers != nil {
|
||||
for _, c := range customCiphers() {
|
||||
if c.ID() == id {
|
||||
return c
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CipherSuites we support in order of preference
|
||||
func defaultCipherSuites() []CipherSuite {
|
||||
return []CipherSuite{
|
||||
&ciphersuite.TLSEcdheEcdsaWithAes128GcmSha256{},
|
||||
&ciphersuite.TLSEcdheRsaWithAes128GcmSha256{},
|
||||
&ciphersuite.TLSEcdheEcdsaWithAes256CbcSha{},
|
||||
&ciphersuite.TLSEcdheRsaWithAes256CbcSha{},
|
||||
&ciphersuite.TLSEcdheEcdsaWithAes256GcmSha384{},
|
||||
&ciphersuite.TLSEcdheRsaWithAes256GcmSha384{},
|
||||
}
|
||||
}
|
||||
|
||||
func allCipherSuites() []CipherSuite {
|
||||
return []CipherSuite{
|
||||
ciphersuite.NewTLSEcdheEcdsaWithAes128Ccm(),
|
||||
ciphersuite.NewTLSEcdheEcdsaWithAes128Ccm8(),
|
||||
&ciphersuite.TLSEcdheEcdsaWithAes128GcmSha256{},
|
||||
&ciphersuite.TLSEcdheRsaWithAes128GcmSha256{},
|
||||
&ciphersuite.TLSEcdheEcdsaWithAes256CbcSha{},
|
||||
&ciphersuite.TLSEcdheRsaWithAes256CbcSha{},
|
||||
ciphersuite.NewTLSPskWithAes128Ccm(),
|
||||
ciphersuite.NewTLSPskWithAes128Ccm8(),
|
||||
&ciphersuite.TLSPskWithAes128GcmSha256{},
|
||||
&ciphersuite.TLSEcdheEcdsaWithAes256GcmSha384{},
|
||||
&ciphersuite.TLSEcdheRsaWithAes256GcmSha384{},
|
||||
}
|
||||
}
|
||||
|
||||
func cipherSuiteIDs(cipherSuites []CipherSuite) []uint16 {
|
||||
rtrn := []uint16{}
|
||||
for _, c := range cipherSuites {
|
||||
rtrn = append(rtrn, uint16(c.ID()))
|
||||
}
|
||||
return rtrn
|
||||
}
|
||||
|
||||
func parseCipherSuites(userSelectedSuites []CipherSuiteID, customCipherSuites func() []CipherSuite, includeCertificateSuites, includePSKSuites bool) ([]CipherSuite, error) {
|
||||
cipherSuitesForIDs := func(ids []CipherSuiteID) ([]CipherSuite, error) {
|
||||
cipherSuites := []CipherSuite{}
|
||||
for _, id := range ids {
|
||||
c := cipherSuiteForID(id, nil)
|
||||
if c == nil {
|
||||
return nil, &invalidCipherSuite{id}
|
||||
}
|
||||
cipherSuites = append(cipherSuites, c)
|
||||
}
|
||||
return cipherSuites, nil
|
||||
}
|
||||
|
||||
var (
|
||||
cipherSuites []CipherSuite
|
||||
err error
|
||||
i int
|
||||
)
|
||||
if userSelectedSuites != nil {
|
||||
cipherSuites, err = cipherSuitesForIDs(userSelectedSuites)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
cipherSuites = defaultCipherSuites()
|
||||
}
|
||||
|
||||
// Put CustomCipherSuites before ID selected suites
|
||||
if customCipherSuites != nil {
|
||||
cipherSuites = append(customCipherSuites(), cipherSuites...)
|
||||
}
|
||||
|
||||
var foundCertificateSuite, foundPSKSuite, foundAnonymousSuite bool
|
||||
for _, c := range cipherSuites {
|
||||
switch {
|
||||
case includeCertificateSuites && c.AuthenticationType() == CipherSuiteAuthenticationTypeCertificate:
|
||||
foundCertificateSuite = true
|
||||
case includePSKSuites && c.AuthenticationType() == CipherSuiteAuthenticationTypePreSharedKey:
|
||||
foundPSKSuite = true
|
||||
case c.AuthenticationType() == CipherSuiteAuthenticationTypeAnonymous:
|
||||
foundAnonymousSuite = true
|
||||
default:
|
||||
continue
|
||||
}
|
||||
cipherSuites[i] = c
|
||||
i++
|
||||
}
|
||||
|
||||
switch {
|
||||
case includeCertificateSuites && !foundCertificateSuite && !foundAnonymousSuite:
|
||||
return nil, errNoAvailableCertificateCipherSuite
|
||||
case includePSKSuites && !foundPSKSuite:
|
||||
return nil, errNoAvailablePSKCipherSuite
|
||||
case i == 0:
|
||||
return nil, errNoAvailableCipherSuites
|
||||
}
|
||||
|
||||
return cipherSuites[:i], nil
|
||||
}
|
||||
|
||||
func filterCipherSuitesForCertificate(cert *tls.Certificate, cipherSuites []CipherSuite) []CipherSuite {
|
||||
if cert == nil || cert.PrivateKey == nil {
|
||||
return cipherSuites
|
||||
}
|
||||
var certType clientcertificate.Type
|
||||
switch cert.PrivateKey.(type) {
|
||||
case ed25519.PrivateKey, *ecdsa.PrivateKey:
|
||||
certType = clientcertificate.ECDSASign
|
||||
case *rsa.PrivateKey:
|
||||
certType = clientcertificate.RSASign
|
||||
}
|
||||
|
||||
filtered := []CipherSuite{}
|
||||
for _, c := range cipherSuites {
|
||||
if c.AuthenticationType() != CipherSuiteAuthenticationTypeCertificate || certType == c.CertificateType() {
|
||||
filtered = append(filtered, c)
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
41
vendor/github.com/pion/dtls/v2/cipher_suite_go114.go
generated
vendored
Normal file
41
vendor/github.com/pion/dtls/v2/cipher_suite_go114.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
//go:build go1.14
|
||||
// +build go1.14
|
||||
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
)
|
||||
|
||||
// VersionDTLS12 is the DTLS version in the same style as
|
||||
// VersionTLSXX from crypto/tls
|
||||
const VersionDTLS12 = 0xfefd
|
||||
|
||||
// Convert from our cipherSuite interface to a tls.CipherSuite struct
|
||||
func toTLSCipherSuite(c CipherSuite) *tls.CipherSuite {
|
||||
return &tls.CipherSuite{
|
||||
ID: uint16(c.ID()),
|
||||
Name: c.String(),
|
||||
SupportedVersions: []uint16{VersionDTLS12},
|
||||
Insecure: false,
|
||||
}
|
||||
}
|
||||
|
||||
// CipherSuites returns a list of cipher suites currently implemented by this
|
||||
// package, excluding those with security issues, which are returned by
|
||||
// InsecureCipherSuites.
|
||||
func CipherSuites() []*tls.CipherSuite {
|
||||
suites := allCipherSuites()
|
||||
res := make([]*tls.CipherSuite, len(suites))
|
||||
for i, c := range suites {
|
||||
res[i] = toTLSCipherSuite(c)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// InsecureCipherSuites returns a list of cipher suites currently implemented by
|
||||
// this package and which have security issues.
|
||||
func InsecureCipherSuites() []*tls.CipherSuite {
|
||||
var res []*tls.CipherSuite
|
||||
return res
|
||||
}
|
||||
20
vendor/github.com/pion/dtls/v2/codecov.yml
generated
vendored
Normal file
20
vendor/github.com/pion/dtls/v2/codecov.yml
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# DO NOT EDIT THIS FILE
|
||||
#
|
||||
# It is automatically copied from https://github.com/pion/.goassets repository.
|
||||
#
|
||||
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
# Allow decreasing 2% of total coverage to avoid noise.
|
||||
threshold: 2%
|
||||
patch:
|
||||
default:
|
||||
target: 70%
|
||||
only_pulls: true
|
||||
|
||||
ignore:
|
||||
- "examples/*"
|
||||
- "examples/**/*"
|
||||
9
vendor/github.com/pion/dtls/v2/compression_method.go
generated
vendored
Normal file
9
vendor/github.com/pion/dtls/v2/compression_method.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package dtls
|
||||
|
||||
import "github.com/pion/dtls/v2/pkg/protocol"
|
||||
|
||||
func defaultCompressionMethods() []*protocol.CompressionMethod {
|
||||
return []*protocol.CompressionMethod{
|
||||
{},
|
||||
}
|
||||
}
|
||||
201
vendor/github.com/pion/dtls/v2/config.go
generated
vendored
Normal file
201
vendor/github.com/pion/dtls/v2/config.go
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/pion/logging"
|
||||
)
|
||||
|
||||
const keyLogLabelTLS12 = "CLIENT_RANDOM"
|
||||
|
||||
// Config is used to configure a DTLS client or server.
|
||||
// After a Config is passed to a DTLS function it must not be modified.
|
||||
type Config struct {
|
||||
// Certificates contains certificate chain to present to the other side of the connection.
|
||||
// Server MUST set this if PSK is non-nil
|
||||
// client SHOULD sets this so CertificateRequests can be handled if PSK is non-nil
|
||||
Certificates []tls.Certificate
|
||||
|
||||
// CipherSuites is a list of supported cipher suites.
|
||||
// If CipherSuites is nil, a default list is used
|
||||
CipherSuites []CipherSuiteID
|
||||
|
||||
// CustomCipherSuites is a list of CipherSuites that can be
|
||||
// provided by the user. This allow users to user Ciphers that are reserved
|
||||
// for private usage.
|
||||
CustomCipherSuites func() []CipherSuite
|
||||
|
||||
// SignatureSchemes contains the signature and hash schemes that the peer requests to verify.
|
||||
SignatureSchemes []tls.SignatureScheme
|
||||
|
||||
// SRTPProtectionProfiles are the supported protection profiles
|
||||
// Clients will send this via use_srtp and assert that the server properly responds
|
||||
// Servers will assert that clients send one of these profiles and will respond as needed
|
||||
SRTPProtectionProfiles []SRTPProtectionProfile
|
||||
|
||||
// ClientAuth determines the server's policy for
|
||||
// TLS Client Authentication. The default is NoClientCert.
|
||||
ClientAuth ClientAuthType
|
||||
|
||||
// RequireExtendedMasterSecret determines if the "Extended Master Secret" extension
|
||||
// should be disabled, requested, or required (default requested).
|
||||
ExtendedMasterSecret ExtendedMasterSecretType
|
||||
|
||||
// FlightInterval controls how often we send outbound handshake messages
|
||||
// defaults to time.Second
|
||||
FlightInterval time.Duration
|
||||
|
||||
// PSK sets the pre-shared key used by this DTLS connection
|
||||
// If PSK is non-nil only PSK CipherSuites will be used
|
||||
PSK PSKCallback
|
||||
PSKIdentityHint []byte
|
||||
|
||||
// InsecureSkipVerify controls whether a client verifies the
|
||||
// server's certificate chain and host name.
|
||||
// If InsecureSkipVerify is true, TLS accepts any certificate
|
||||
// presented by the server and any host name in that certificate.
|
||||
// In this mode, TLS is susceptible to man-in-the-middle attacks.
|
||||
// This should be used only for testing.
|
||||
InsecureSkipVerify bool
|
||||
|
||||
// InsecureHashes allows the use of hashing algorithms that are known
|
||||
// to be vulnerable.
|
||||
InsecureHashes bool
|
||||
|
||||
// VerifyPeerCertificate, if not nil, is called after normal
|
||||
// certificate verification by either a client or server. It
|
||||
// receives the certificate provided by the peer and also a flag
|
||||
// that tells if normal verification has succeedded. If it returns a
|
||||
// non-nil error, the handshake is aborted and that error results.
|
||||
//
|
||||
// If normal verification fails then the handshake will abort before
|
||||
// considering this callback. If normal verification is disabled by
|
||||
// setting InsecureSkipVerify, or (for a server) when ClientAuth is
|
||||
// RequestClientCert or RequireAnyClientCert, then this callback will
|
||||
// be considered but the verifiedChains will always be nil.
|
||||
VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
|
||||
|
||||
// RootCAs defines the set of root certificate authorities
|
||||
// that one peer uses when verifying the other peer's certificates.
|
||||
// If RootCAs is nil, TLS uses the host's root CA set.
|
||||
RootCAs *x509.CertPool
|
||||
|
||||
// ClientCAs defines the set of root certificate authorities
|
||||
// that servers use if required to verify a client certificate
|
||||
// by the policy in ClientAuth.
|
||||
ClientCAs *x509.CertPool
|
||||
|
||||
// ServerName is used to verify the hostname on the returned
|
||||
// certificates unless InsecureSkipVerify is given.
|
||||
ServerName string
|
||||
|
||||
LoggerFactory logging.LoggerFactory
|
||||
|
||||
// ConnectContextMaker is a function to make a context used in Dial(),
|
||||
// Client(), Server(), and Accept(). If nil, the default ConnectContextMaker
|
||||
// is used. It can be implemented as following.
|
||||
//
|
||||
// func ConnectContextMaker() (context.Context, func()) {
|
||||
// return context.WithTimeout(context.Background(), 30*time.Second)
|
||||
// }
|
||||
ConnectContextMaker func() (context.Context, func())
|
||||
|
||||
// MTU is the length at which handshake messages will be fragmented to
|
||||
// fit within the maximum transmission unit (default is 1200 bytes)
|
||||
MTU int
|
||||
|
||||
// ReplayProtectionWindow is the size of the replay attack protection window.
|
||||
// Duplication of the sequence number is checked in this window size.
|
||||
// Packet with sequence number older than this value compared to the latest
|
||||
// accepted packet will be discarded. (default is 64)
|
||||
ReplayProtectionWindow int
|
||||
|
||||
// KeyLogWriter optionally specifies a destination for TLS master secrets
|
||||
// in NSS key log format that can be used to allow external programs
|
||||
// such as Wireshark to decrypt TLS connections.
|
||||
// See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format.
|
||||
// Use of KeyLogWriter compromises security and should only be
|
||||
// used for debugging.
|
||||
KeyLogWriter io.Writer
|
||||
|
||||
// SessionStore is the container to store session for resumption.
|
||||
SessionStore SessionStore
|
||||
|
||||
// List of application protocols the peer supports, for ALPN
|
||||
SupportedProtocols []string
|
||||
}
|
||||
|
||||
func defaultConnectContextMaker() (context.Context, func()) {
|
||||
return context.WithTimeout(context.Background(), 30*time.Second)
|
||||
}
|
||||
|
||||
func (c *Config) connectContextMaker() (context.Context, func()) {
|
||||
if c.ConnectContextMaker == nil {
|
||||
return defaultConnectContextMaker()
|
||||
}
|
||||
return c.ConnectContextMaker()
|
||||
}
|
||||
|
||||
const defaultMTU = 1200 // bytes
|
||||
|
||||
// PSKCallback is called once we have the remote's PSKIdentityHint.
|
||||
// If the remote provided none it will be nil
|
||||
type PSKCallback func([]byte) ([]byte, error)
|
||||
|
||||
// ClientAuthType declares the policy the server will follow for
|
||||
// TLS Client Authentication.
|
||||
type ClientAuthType int
|
||||
|
||||
// ClientAuthType enums
|
||||
const (
|
||||
NoClientCert ClientAuthType = iota
|
||||
RequestClientCert
|
||||
RequireAnyClientCert
|
||||
VerifyClientCertIfGiven
|
||||
RequireAndVerifyClientCert
|
||||
)
|
||||
|
||||
// ExtendedMasterSecretType declares the policy the client and server
|
||||
// will follow for the Extended Master Secret extension
|
||||
type ExtendedMasterSecretType int
|
||||
|
||||
// ExtendedMasterSecretType enums
|
||||
const (
|
||||
RequestExtendedMasterSecret ExtendedMasterSecretType = iota
|
||||
RequireExtendedMasterSecret
|
||||
DisableExtendedMasterSecret
|
||||
)
|
||||
|
||||
func validateConfig(config *Config) error {
|
||||
switch {
|
||||
case config == nil:
|
||||
return errNoConfigProvided
|
||||
case config.PSKIdentityHint != nil && config.PSK == nil:
|
||||
return errIdentityNoPSK
|
||||
}
|
||||
|
||||
for _, cert := range config.Certificates {
|
||||
if cert.Certificate == nil {
|
||||
return errInvalidCertificate
|
||||
}
|
||||
if cert.PrivateKey != nil {
|
||||
switch cert.PrivateKey.(type) {
|
||||
case ed25519.PrivateKey:
|
||||
case *ecdsa.PrivateKey:
|
||||
case *rsa.PrivateKey:
|
||||
default:
|
||||
return errInvalidPrivateKey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err := parseCipherSuites(config.CipherSuites, config.CustomCipherSuites, config.PSK == nil || len(config.Certificates) > 0, config.PSK != nil)
|
||||
return err
|
||||
}
|
||||
1004
vendor/github.com/pion/dtls/v2/conn.go
generated
vendored
Normal file
1004
vendor/github.com/pion/dtls/v2/conn.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
221
vendor/github.com/pion/dtls/v2/crypto.go
generated
vendored
Normal file
221
vendor/github.com/pion/dtls/v2/crypto.go
generated
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/binary"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/crypto/elliptic"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/hash"
|
||||
)
|
||||
|
||||
type ecdsaSignature struct {
|
||||
R, S *big.Int
|
||||
}
|
||||
|
||||
func valueKeyMessage(clientRandom, serverRandom, publicKey []byte, namedCurve elliptic.Curve) []byte {
|
||||
serverECDHParams := make([]byte, 4)
|
||||
serverECDHParams[0] = 3 // named curve
|
||||
binary.BigEndian.PutUint16(serverECDHParams[1:], uint16(namedCurve))
|
||||
serverECDHParams[3] = byte(len(publicKey))
|
||||
|
||||
plaintext := []byte{}
|
||||
plaintext = append(plaintext, clientRandom...)
|
||||
plaintext = append(plaintext, serverRandom...)
|
||||
plaintext = append(plaintext, serverECDHParams...)
|
||||
plaintext = append(plaintext, publicKey...)
|
||||
|
||||
return plaintext
|
||||
}
|
||||
|
||||
// If the client provided a "signature_algorithms" extension, then all
|
||||
// certificates provided by the server MUST be signed by a
|
||||
// hash/signature algorithm pair that appears in that extension
|
||||
//
|
||||
// https://tools.ietf.org/html/rfc5246#section-7.4.2
|
||||
func generateKeySignature(clientRandom, serverRandom, publicKey []byte, namedCurve elliptic.Curve, privateKey crypto.PrivateKey, hashAlgorithm hash.Algorithm) ([]byte, error) {
|
||||
msg := valueKeyMessage(clientRandom, serverRandom, publicKey, namedCurve)
|
||||
switch p := privateKey.(type) {
|
||||
case ed25519.PrivateKey:
|
||||
// https://crypto.stackexchange.com/a/55483
|
||||
return p.Sign(rand.Reader, msg, crypto.Hash(0))
|
||||
case *ecdsa.PrivateKey:
|
||||
hashed := hashAlgorithm.Digest(msg)
|
||||
return p.Sign(rand.Reader, hashed, hashAlgorithm.CryptoHash())
|
||||
case *rsa.PrivateKey:
|
||||
hashed := hashAlgorithm.Digest(msg)
|
||||
return p.Sign(rand.Reader, hashed, hashAlgorithm.CryptoHash())
|
||||
}
|
||||
|
||||
return nil, errKeySignatureGenerateUnimplemented
|
||||
}
|
||||
|
||||
func verifyKeySignature(message, remoteKeySignature []byte, hashAlgorithm hash.Algorithm, rawCertificates [][]byte) error { //nolint:dupl
|
||||
if len(rawCertificates) == 0 {
|
||||
return errLengthMismatch
|
||||
}
|
||||
certificate, err := x509.ParseCertificate(rawCertificates[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch p := certificate.PublicKey.(type) {
|
||||
case ed25519.PublicKey:
|
||||
if ok := ed25519.Verify(p, message, remoteKeySignature); !ok {
|
||||
return errKeySignatureMismatch
|
||||
}
|
||||
return nil
|
||||
case *ecdsa.PublicKey:
|
||||
ecdsaSig := &ecdsaSignature{}
|
||||
if _, err := asn1.Unmarshal(remoteKeySignature, ecdsaSig); err != nil {
|
||||
return err
|
||||
}
|
||||
if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
|
||||
return errInvalidECDSASignature
|
||||
}
|
||||
hashed := hashAlgorithm.Digest(message)
|
||||
if !ecdsa.Verify(p, hashed, ecdsaSig.R, ecdsaSig.S) {
|
||||
return errKeySignatureMismatch
|
||||
}
|
||||
return nil
|
||||
case *rsa.PublicKey:
|
||||
switch certificate.SignatureAlgorithm {
|
||||
case x509.SHA1WithRSA, x509.SHA256WithRSA, x509.SHA384WithRSA, x509.SHA512WithRSA:
|
||||
hashed := hashAlgorithm.Digest(message)
|
||||
return rsa.VerifyPKCS1v15(p, hashAlgorithm.CryptoHash(), hashed, remoteKeySignature)
|
||||
default:
|
||||
return errKeySignatureVerifyUnimplemented
|
||||
}
|
||||
}
|
||||
|
||||
return errKeySignatureVerifyUnimplemented
|
||||
}
|
||||
|
||||
// If the server has sent a CertificateRequest message, the client MUST send the Certificate
|
||||
// message. The ClientKeyExchange message is now sent, and the content
|
||||
// of that message will depend on the public key algorithm selected
|
||||
// between the ClientHello and the ServerHello. If the client has sent
|
||||
// a certificate with signing ability, a digitally-signed
|
||||
// CertificateVerify message is sent to explicitly verify possession of
|
||||
// the private key in the certificate.
|
||||
// https://tools.ietf.org/html/rfc5246#section-7.3
|
||||
func generateCertificateVerify(handshakeBodies []byte, privateKey crypto.PrivateKey, hashAlgorithm hash.Algorithm) ([]byte, error) {
|
||||
h := sha256.New()
|
||||
if _, err := h.Write(handshakeBodies); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hashed := h.Sum(nil)
|
||||
|
||||
switch p := privateKey.(type) {
|
||||
case ed25519.PrivateKey:
|
||||
// https://crypto.stackexchange.com/a/55483
|
||||
return p.Sign(rand.Reader, hashed, crypto.Hash(0))
|
||||
case *ecdsa.PrivateKey:
|
||||
return p.Sign(rand.Reader, hashed, hashAlgorithm.CryptoHash())
|
||||
case *rsa.PrivateKey:
|
||||
return p.Sign(rand.Reader, hashed, hashAlgorithm.CryptoHash())
|
||||
}
|
||||
|
||||
return nil, errInvalidSignatureAlgorithm
|
||||
}
|
||||
|
||||
func verifyCertificateVerify(handshakeBodies []byte, hashAlgorithm hash.Algorithm, remoteKeySignature []byte, rawCertificates [][]byte) error { //nolint:dupl
|
||||
if len(rawCertificates) == 0 {
|
||||
return errLengthMismatch
|
||||
}
|
||||
certificate, err := x509.ParseCertificate(rawCertificates[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch p := certificate.PublicKey.(type) {
|
||||
case ed25519.PublicKey:
|
||||
if ok := ed25519.Verify(p, handshakeBodies, remoteKeySignature); !ok {
|
||||
return errKeySignatureMismatch
|
||||
}
|
||||
return nil
|
||||
case *ecdsa.PublicKey:
|
||||
ecdsaSig := &ecdsaSignature{}
|
||||
if _, err := asn1.Unmarshal(remoteKeySignature, ecdsaSig); err != nil {
|
||||
return err
|
||||
}
|
||||
if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
|
||||
return errInvalidECDSASignature
|
||||
}
|
||||
hash := hashAlgorithm.Digest(handshakeBodies)
|
||||
if !ecdsa.Verify(p, hash, ecdsaSig.R, ecdsaSig.S) {
|
||||
return errKeySignatureMismatch
|
||||
}
|
||||
return nil
|
||||
case *rsa.PublicKey:
|
||||
switch certificate.SignatureAlgorithm {
|
||||
case x509.SHA1WithRSA, x509.SHA256WithRSA, x509.SHA384WithRSA, x509.SHA512WithRSA:
|
||||
hash := hashAlgorithm.Digest(handshakeBodies)
|
||||
return rsa.VerifyPKCS1v15(p, hashAlgorithm.CryptoHash(), hash, remoteKeySignature)
|
||||
default:
|
||||
return errKeySignatureVerifyUnimplemented
|
||||
}
|
||||
}
|
||||
|
||||
return errKeySignatureVerifyUnimplemented
|
||||
}
|
||||
|
||||
func loadCerts(rawCertificates [][]byte) ([]*x509.Certificate, error) {
|
||||
if len(rawCertificates) == 0 {
|
||||
return nil, errLengthMismatch
|
||||
}
|
||||
|
||||
certs := make([]*x509.Certificate, 0, len(rawCertificates))
|
||||
for _, rawCert := range rawCertificates {
|
||||
cert, err := x509.ParseCertificate(rawCert)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certs = append(certs, cert)
|
||||
}
|
||||
return certs, nil
|
||||
}
|
||||
|
||||
func verifyClientCert(rawCertificates [][]byte, roots *x509.CertPool) (chains [][]*x509.Certificate, err error) {
|
||||
certificate, err := loadCerts(rawCertificates)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
intermediateCAPool := x509.NewCertPool()
|
||||
for _, cert := range certificate[1:] {
|
||||
intermediateCAPool.AddCert(cert)
|
||||
}
|
||||
opts := x509.VerifyOptions{
|
||||
Roots: roots,
|
||||
CurrentTime: time.Now(),
|
||||
Intermediates: intermediateCAPool,
|
||||
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
return certificate[0].Verify(opts)
|
||||
}
|
||||
|
||||
func verifyServerCert(rawCertificates [][]byte, roots *x509.CertPool, serverName string) (chains [][]*x509.Certificate, err error) {
|
||||
certificate, err := loadCerts(rawCertificates)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
intermediateCAPool := x509.NewCertPool()
|
||||
for _, cert := range certificate[1:] {
|
||||
intermediateCAPool.AddCert(cert)
|
||||
}
|
||||
opts := x509.VerifyOptions{
|
||||
Roots: roots,
|
||||
CurrentTime: time.Now(),
|
||||
DNSName: serverName,
|
||||
Intermediates: intermediateCAPool,
|
||||
}
|
||||
return certificate[0].Verify(opts)
|
||||
}
|
||||
2
vendor/github.com/pion/dtls/v2/dtls.go
generated
vendored
Normal file
2
vendor/github.com/pion/dtls/v2/dtls.go
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package dtls implements Datagram Transport Layer Security (DTLS) 1.2
|
||||
package dtls
|
||||
141
vendor/github.com/pion/dtls/v2/errors.go
generated
vendored
Normal file
141
vendor/github.com/pion/dtls/v2/errors.go
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/protocol"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/alert"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// Typed errors
|
||||
var (
|
||||
ErrConnClosed = &FatalError{Err: errors.New("conn is closed")} //nolint:goerr113
|
||||
|
||||
errDeadlineExceeded = &TimeoutError{Err: xerrors.Errorf("read/write timeout: %w", context.DeadlineExceeded)}
|
||||
errInvalidContentType = &TemporaryError{Err: errors.New("invalid content type")} //nolint:goerr113
|
||||
|
||||
errBufferTooSmall = &TemporaryError{Err: errors.New("buffer is too small")} //nolint:goerr113
|
||||
errContextUnsupported = &TemporaryError{Err: errors.New("context is not supported for ExportKeyingMaterial")} //nolint:goerr113
|
||||
errHandshakeInProgress = &TemporaryError{Err: errors.New("handshake is in progress")} //nolint:goerr113
|
||||
errReservedExportKeyingMaterial = &TemporaryError{Err: errors.New("ExportKeyingMaterial can not be used with a reserved label")} //nolint:goerr113
|
||||
errApplicationDataEpochZero = &TemporaryError{Err: errors.New("ApplicationData with epoch of 0")} //nolint:goerr113
|
||||
errUnhandledContextType = &TemporaryError{Err: errors.New("unhandled contentType")} //nolint:goerr113
|
||||
|
||||
errCertificateVerifyNoCertificate = &FatalError{Err: errors.New("client sent certificate verify but we have no certificate to verify")} //nolint:goerr113
|
||||
errCipherSuiteNoIntersection = &FatalError{Err: errors.New("client+server do not support any shared cipher suites")} //nolint:goerr113
|
||||
errClientCertificateNotVerified = &FatalError{Err: errors.New("client sent certificate but did not verify it")} //nolint:goerr113
|
||||
errClientCertificateRequired = &FatalError{Err: errors.New("server required client verification, but got none")} //nolint:goerr113
|
||||
errClientNoMatchingSRTPProfile = &FatalError{Err: errors.New("server responded with SRTP Profile we do not support")} //nolint:goerr113
|
||||
errClientRequiredButNoServerEMS = &FatalError{Err: errors.New("client required Extended Master Secret extension, but server does not support it")} //nolint:goerr113
|
||||
errCookieMismatch = &FatalError{Err: errors.New("client+server cookie does not match")} //nolint:goerr113
|
||||
errIdentityNoPSK = &FatalError{Err: errors.New("PSK Identity Hint provided but PSK is nil")} //nolint:goerr113
|
||||
errInvalidCertificate = &FatalError{Err: errors.New("no certificate provided")} //nolint:goerr113
|
||||
errInvalidCipherSuite = &FatalError{Err: errors.New("invalid or unknown cipher suite")} //nolint:goerr113
|
||||
errInvalidECDSASignature = &FatalError{Err: errors.New("ECDSA signature contained zero or negative values")} //nolint:goerr113
|
||||
errInvalidPrivateKey = &FatalError{Err: errors.New("invalid private key type")} //nolint:goerr113
|
||||
errInvalidSignatureAlgorithm = &FatalError{Err: errors.New("invalid signature algorithm")} //nolint:goerr113
|
||||
errKeySignatureMismatch = &FatalError{Err: errors.New("expected and actual key signature do not match")} //nolint:goerr113
|
||||
errNilNextConn = &FatalError{Err: errors.New("Conn can not be created with a nil nextConn")} //nolint:goerr113
|
||||
errNoAvailableCipherSuites = &FatalError{Err: errors.New("connection can not be created, no CipherSuites satisfy this Config")} //nolint:goerr113
|
||||
errNoAvailablePSKCipherSuite = &FatalError{Err: errors.New("connection can not be created, pre-shared key present but no compatible CipherSuite")} //nolint:goerr113
|
||||
errNoAvailableCertificateCipherSuite = &FatalError{Err: errors.New("connection can not be created, certificate present but no compatible CipherSuite")} //nolint:goerr113
|
||||
errNoAvailableSignatureSchemes = &FatalError{Err: errors.New("connection can not be created, no SignatureScheme satisfy this Config")} //nolint:goerr113
|
||||
errNoCertificates = &FatalError{Err: errors.New("no certificates configured")} //nolint:goerr113
|
||||
errNoConfigProvided = &FatalError{Err: errors.New("no config provided")} //nolint:goerr113
|
||||
errNoSupportedEllipticCurves = &FatalError{Err: errors.New("client requested zero or more elliptic curves that are not supported by the server")} //nolint:goerr113
|
||||
errUnsupportedProtocolVersion = &FatalError{Err: errors.New("unsupported protocol version")} //nolint:goerr113
|
||||
errPSKAndIdentityMustBeSetForClient = &FatalError{Err: errors.New("PSK and PSK Identity Hint must both be set for client")} //nolint:goerr113
|
||||
errRequestedButNoSRTPExtension = &FatalError{Err: errors.New("SRTP support was requested but server did not respond with use_srtp extension")} //nolint:goerr113
|
||||
errServerNoMatchingSRTPProfile = &FatalError{Err: errors.New("client requested SRTP but we have no matching profiles")} //nolint:goerr113
|
||||
errServerRequiredButNoClientEMS = &FatalError{Err: errors.New("server requires the Extended Master Secret extension, but the client does not support it")} //nolint:goerr113
|
||||
errVerifyDataMismatch = &FatalError{Err: errors.New("expected and actual verify data does not match")} //nolint:goerr113
|
||||
|
||||
errInvalidFlight = &InternalError{Err: errors.New("invalid flight number")} //nolint:goerr113
|
||||
errKeySignatureGenerateUnimplemented = &InternalError{Err: errors.New("unable to generate key signature, unimplemented")} //nolint:goerr113
|
||||
errKeySignatureVerifyUnimplemented = &InternalError{Err: errors.New("unable to verify key signature, unimplemented")} //nolint:goerr113
|
||||
errLengthMismatch = &InternalError{Err: errors.New("data length and declared length do not match")} //nolint:goerr113
|
||||
errSequenceNumberOverflow = &InternalError{Err: errors.New("sequence number overflow")} //nolint:goerr113
|
||||
errInvalidFSMTransition = &InternalError{Err: errors.New("invalid state machine transition")} //nolint:goerr113
|
||||
)
|
||||
|
||||
// FatalError indicates that the DTLS connection is no longer available.
|
||||
// It is mainly caused by wrong configuration of server or client.
|
||||
type FatalError = protocol.FatalError
|
||||
|
||||
// InternalError indicates and internal error caused by the implementation, and the DTLS connection is no longer available.
|
||||
// It is mainly caused by bugs or tried to use unimplemented features.
|
||||
type InternalError = protocol.InternalError
|
||||
|
||||
// TemporaryError indicates that the DTLS connection is still available, but the request was failed temporary.
|
||||
type TemporaryError = protocol.TemporaryError
|
||||
|
||||
// TimeoutError indicates that the request was timed out.
|
||||
type TimeoutError = protocol.TimeoutError
|
||||
|
||||
// HandshakeError indicates that the handshake failed.
|
||||
type HandshakeError = protocol.HandshakeError
|
||||
|
||||
// invalidCipherSuite indicates an attempt at using an unsupported cipher suite.
|
||||
type invalidCipherSuite struct {
|
||||
id CipherSuiteID
|
||||
}
|
||||
|
||||
func (e *invalidCipherSuite) Error() string {
|
||||
return fmt.Sprintf("CipherSuite with id(%d) is not valid", e.id)
|
||||
}
|
||||
|
||||
func (e *invalidCipherSuite) Is(err error) bool {
|
||||
if other, ok := err.(*invalidCipherSuite); ok {
|
||||
return e.id == other.id
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// errAlert wraps DTLS alert notification as an error
|
||||
type errAlert struct {
|
||||
*alert.Alert
|
||||
}
|
||||
|
||||
func (e *errAlert) Error() string {
|
||||
return fmt.Sprintf("alert: %s", e.Alert.String())
|
||||
}
|
||||
|
||||
func (e *errAlert) IsFatalOrCloseNotify() bool {
|
||||
return e.Level == alert.Fatal || e.Description == alert.CloseNotify
|
||||
}
|
||||
|
||||
func (e *errAlert) Is(err error) bool {
|
||||
if other, ok := err.(*errAlert); ok {
|
||||
return e.Level == other.Level && e.Description == other.Description
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// netError translates an error from underlying Conn to corresponding net.Error.
|
||||
func netError(err error) error {
|
||||
switch err {
|
||||
case io.EOF, context.Canceled, context.DeadlineExceeded:
|
||||
// Return io.EOF and context errors as is.
|
||||
return err
|
||||
}
|
||||
switch e := err.(type) {
|
||||
case (*net.OpError):
|
||||
if se, ok := e.Err.(*os.SyscallError); ok {
|
||||
if se.Timeout() {
|
||||
return &TimeoutError{Err: err}
|
||||
}
|
||||
if isOpErrorTemporary(se) {
|
||||
return &TemporaryError{Err: err}
|
||||
}
|
||||
}
|
||||
case (net.Error):
|
||||
return err
|
||||
}
|
||||
return &FatalError{Err: err}
|
||||
}
|
||||
26
vendor/github.com/pion/dtls/v2/errors_errno.go
generated
vendored
Normal file
26
vendor/github.com/pion/dtls/v2/errors_errno.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || nacl || nacljs || netbsd || openbsd || solaris || windows
|
||||
// +build aix darwin dragonfly freebsd linux nacl nacljs netbsd openbsd solaris windows
|
||||
|
||||
// For systems having syscall.Errno.
|
||||
// Update build targets by following command:
|
||||
// $ grep -R ECONN $(go env GOROOT)/src/syscall/zerrors_*.go \
|
||||
// | tr "." "_" | cut -d"_" -f"2" | sort | uniq
|
||||
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func isOpErrorTemporary(err *os.SyscallError) bool {
|
||||
if ne, ok := err.Err.(syscall.Errno); ok {
|
||||
switch ne {
|
||||
case syscall.ECONNREFUSED:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
15
vendor/github.com/pion/dtls/v2/errors_noerrno.go
generated
vendored
Normal file
15
vendor/github.com/pion/dtls/v2/errors_noerrno.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !nacl && !nacljs && !netbsd && !openbsd && !solaris && !windows
|
||||
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!nacl,!nacljs,!netbsd,!openbsd,!solaris,!windows
|
||||
|
||||
// For systems without syscall.Errno.
|
||||
// Build targets must be inverse of errors_errno.go
|
||||
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func isOpErrorTemporary(err *os.SyscallError) bool {
|
||||
return false
|
||||
}
|
||||
101
vendor/github.com/pion/dtls/v2/flight.go
generated
vendored
Normal file
101
vendor/github.com/pion/dtls/v2/flight.go
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
package dtls
|
||||
|
||||
/*
|
||||
DTLS messages are grouped into a series of message flights, according
|
||||
to the diagrams below. Although each flight of messages may consist
|
||||
of a number of messages, they should be viewed as monolithic for the
|
||||
purpose of timeout and retransmission.
|
||||
https://tools.ietf.org/html/rfc4347#section-4.2.4
|
||||
|
||||
Message flights for full handshake:
|
||||
|
||||
Client Server
|
||||
------ ------
|
||||
Waiting Flight 0
|
||||
|
||||
ClientHello --------> Flight 1
|
||||
|
||||
<------- HelloVerifyRequest Flight 2
|
||||
|
||||
ClientHello --------> Flight 3
|
||||
|
||||
ServerHello \
|
||||
Certificate* \
|
||||
ServerKeyExchange* Flight 4
|
||||
CertificateRequest* /
|
||||
<-------- ServerHelloDone /
|
||||
|
||||
Certificate* \
|
||||
ClientKeyExchange \
|
||||
CertificateVerify* Flight 5
|
||||
[ChangeCipherSpec] /
|
||||
Finished --------> /
|
||||
|
||||
[ChangeCipherSpec] \ Flight 6
|
||||
<-------- Finished /
|
||||
|
||||
Message flights for session-resuming handshake (no cookie exchange):
|
||||
|
||||
Client Server
|
||||
------ ------
|
||||
Waiting Flight 0
|
||||
|
||||
ClientHello --------> Flight 1
|
||||
|
||||
ServerHello \
|
||||
[ChangeCipherSpec] Flight 4b
|
||||
<-------- Finished /
|
||||
|
||||
[ChangeCipherSpec] \ Flight 5b
|
||||
Finished --------> /
|
||||
|
||||
[ChangeCipherSpec] \ Flight 6
|
||||
<-------- Finished /
|
||||
*/
|
||||
|
||||
type flightVal uint8
|
||||
|
||||
const (
|
||||
flight0 flightVal = iota + 1
|
||||
flight1
|
||||
flight2
|
||||
flight3
|
||||
flight4
|
||||
flight4b
|
||||
flight5
|
||||
flight5b
|
||||
flight6
|
||||
)
|
||||
|
||||
func (f flightVal) String() string {
|
||||
switch f {
|
||||
case flight0:
|
||||
return "Flight 0"
|
||||
case flight1:
|
||||
return "Flight 1"
|
||||
case flight2:
|
||||
return "Flight 2"
|
||||
case flight3:
|
||||
return "Flight 3"
|
||||
case flight4:
|
||||
return "Flight 4"
|
||||
case flight4b:
|
||||
return "Flight 4b"
|
||||
case flight5:
|
||||
return "Flight 5"
|
||||
case flight5b:
|
||||
return "Flight 5b"
|
||||
case flight6:
|
||||
return "Flight 6"
|
||||
default:
|
||||
return "Invalid Flight"
|
||||
}
|
||||
}
|
||||
|
||||
func (f flightVal) isLastSendFlight() bool {
|
||||
return f == flight6 || f == flight5b
|
||||
}
|
||||
|
||||
func (f flightVal) isLastRecvFlight() bool {
|
||||
return f == flight5 || f == flight4b
|
||||
}
|
||||
127
vendor/github.com/pion/dtls/v2/flight0handler.go
generated
vendored
Normal file
127
vendor/github.com/pion/dtls/v2/flight0handler.go
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/crypto/elliptic"
|
||||
"github.com/pion/dtls/v2/pkg/protocol"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/alert"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/extension"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/handshake"
|
||||
)
|
||||
|
||||
func flight0Parse(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) {
|
||||
seq, msgs, ok := cache.fullPullMap(0,
|
||||
handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
|
||||
)
|
||||
if !ok {
|
||||
// No valid message received. Keep reading
|
||||
return 0, nil, nil
|
||||
}
|
||||
state.handshakeRecvSequence = seq
|
||||
|
||||
var clientHello *handshake.MessageClientHello
|
||||
|
||||
// Validate type
|
||||
if clientHello, ok = msgs[handshake.TypeClientHello].(*handshake.MessageClientHello); !ok {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
|
||||
}
|
||||
|
||||
if !clientHello.Version.Equal(protocol.Version1_2) {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.ProtocolVersion}, errUnsupportedProtocolVersion
|
||||
}
|
||||
|
||||
state.remoteRandom = clientHello.Random
|
||||
|
||||
cipherSuites := []CipherSuite{}
|
||||
for _, id := range clientHello.CipherSuiteIDs {
|
||||
if c := cipherSuiteForID(CipherSuiteID(id), cfg.customCipherSuites); c != nil {
|
||||
cipherSuites = append(cipherSuites, c)
|
||||
}
|
||||
}
|
||||
|
||||
if state.cipherSuite, ok = findMatchingCipherSuite(cipherSuites, cfg.localCipherSuites); !ok {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errCipherSuiteNoIntersection
|
||||
}
|
||||
|
||||
for _, val := range clientHello.Extensions {
|
||||
switch e := val.(type) {
|
||||
case *extension.SupportedEllipticCurves:
|
||||
if len(e.EllipticCurves) == 0 {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errNoSupportedEllipticCurves
|
||||
}
|
||||
state.namedCurve = e.EllipticCurves[0]
|
||||
case *extension.UseSRTP:
|
||||
profile, ok := findMatchingSRTPProfile(e.ProtectionProfiles, cfg.localSRTPProtectionProfiles)
|
||||
if !ok {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errServerNoMatchingSRTPProfile
|
||||
}
|
||||
state.srtpProtectionProfile = profile
|
||||
case *extension.UseExtendedMasterSecret:
|
||||
if cfg.extendedMasterSecret != DisableExtendedMasterSecret {
|
||||
state.extendedMasterSecret = true
|
||||
}
|
||||
case *extension.ServerName:
|
||||
state.serverName = e.ServerName // remote server name
|
||||
case *extension.ALPN:
|
||||
state.peerSupportedProtocols = e.ProtocolNameList
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.extendedMasterSecret == RequireExtendedMasterSecret && !state.extendedMasterSecret {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errServerRequiredButNoClientEMS
|
||||
}
|
||||
|
||||
if state.localKeypair == nil {
|
||||
var err error
|
||||
state.localKeypair, err = elliptic.GenerateKeypair(state.namedCurve)
|
||||
if err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.IllegalParameter}, err
|
||||
}
|
||||
}
|
||||
|
||||
return handleHelloResume(clientHello.SessionID, state, cfg, flight2)
|
||||
}
|
||||
|
||||
func handleHelloResume(sessionID []byte, state *State, cfg *handshakeConfig, next flightVal) (flightVal, *alert.Alert, error) {
|
||||
if len(sessionID) > 0 && cfg.sessionStore != nil {
|
||||
if s, err := cfg.sessionStore.Get(sessionID); err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
} else if s.ID != nil {
|
||||
cfg.log.Tracef("[handshake] resume session: %x", sessionID)
|
||||
|
||||
state.SessionID = sessionID
|
||||
state.masterSecret = s.Secret
|
||||
|
||||
if err := state.initCipherSuite(); err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
|
||||
clientRandom := state.localRandom.MarshalFixed()
|
||||
cfg.writeKeyLog(keyLogLabelTLS12, clientRandom[:], state.masterSecret)
|
||||
|
||||
return flight4b, nil, nil
|
||||
}
|
||||
}
|
||||
return next, nil, nil
|
||||
}
|
||||
|
||||
func flight0Generate(c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) {
|
||||
// Initialize
|
||||
state.cookie = make([]byte, cookieLength)
|
||||
if _, err := rand.Read(state.cookie); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var zeroEpoch uint16
|
||||
state.localEpoch.Store(zeroEpoch)
|
||||
state.remoteEpoch.Store(zeroEpoch)
|
||||
state.namedCurve = defaultNamedCurve
|
||||
|
||||
if err := state.localRandom.Populate(); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return nil, nil, nil
|
||||
}
|
||||
129
vendor/github.com/pion/dtls/v2/flight1handler.go
generated
vendored
Normal file
129
vendor/github.com/pion/dtls/v2/flight1handler.go
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/crypto/elliptic"
|
||||
"github.com/pion/dtls/v2/pkg/protocol"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/alert"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/extension"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/handshake"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
|
||||
)
|
||||
|
||||
func flight1Parse(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) {
|
||||
// HelloVerifyRequest can be skipped by the server,
|
||||
// so allow ServerHello during flight1 also
|
||||
seq, msgs, ok := cache.fullPullMap(state.handshakeRecvSequence,
|
||||
handshakeCachePullRule{handshake.TypeHelloVerifyRequest, cfg.initialEpoch, false, true},
|
||||
handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, true},
|
||||
)
|
||||
if !ok {
|
||||
// No valid message received. Keep reading
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
if _, ok := msgs[handshake.TypeServerHello]; ok {
|
||||
// Flight1 and flight2 were skipped.
|
||||
// Parse as flight3.
|
||||
return flight3Parse(ctx, c, state, cache, cfg)
|
||||
}
|
||||
|
||||
if h, ok := msgs[handshake.TypeHelloVerifyRequest].(*handshake.MessageHelloVerifyRequest); ok {
|
||||
// DTLS 1.2 clients must not assume that the server will use the protocol version
|
||||
// specified in HelloVerifyRequest message. RFC 6347 Section 4.2.1
|
||||
if !h.Version.Equal(protocol.Version1_0) && !h.Version.Equal(protocol.Version1_2) {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.ProtocolVersion}, errUnsupportedProtocolVersion
|
||||
}
|
||||
state.cookie = append([]byte{}, h.Cookie...)
|
||||
state.handshakeRecvSequence = seq
|
||||
return flight3, nil, nil
|
||||
}
|
||||
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
|
||||
}
|
||||
|
||||
func flight1Generate(c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) {
|
||||
var zeroEpoch uint16
|
||||
state.localEpoch.Store(zeroEpoch)
|
||||
state.remoteEpoch.Store(zeroEpoch)
|
||||
state.namedCurve = defaultNamedCurve
|
||||
state.cookie = nil
|
||||
|
||||
if err := state.localRandom.Populate(); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
extensions := []extension.Extension{
|
||||
&extension.SupportedSignatureAlgorithms{
|
||||
SignatureHashAlgorithms: cfg.localSignatureSchemes,
|
||||
},
|
||||
&extension.RenegotiationInfo{
|
||||
RenegotiatedConnection: 0,
|
||||
},
|
||||
}
|
||||
if cfg.localPSKCallback == nil {
|
||||
extensions = append(extensions, []extension.Extension{
|
||||
&extension.SupportedEllipticCurves{
|
||||
EllipticCurves: []elliptic.Curve{elliptic.X25519, elliptic.P256, elliptic.P384},
|
||||
},
|
||||
&extension.SupportedPointFormats{
|
||||
PointFormats: []elliptic.CurvePointFormat{elliptic.CurvePointFormatUncompressed},
|
||||
},
|
||||
}...)
|
||||
}
|
||||
|
||||
if len(cfg.localSRTPProtectionProfiles) > 0 {
|
||||
extensions = append(extensions, &extension.UseSRTP{
|
||||
ProtectionProfiles: cfg.localSRTPProtectionProfiles,
|
||||
})
|
||||
}
|
||||
|
||||
if cfg.extendedMasterSecret == RequestExtendedMasterSecret ||
|
||||
cfg.extendedMasterSecret == RequireExtendedMasterSecret {
|
||||
extensions = append(extensions, &extension.UseExtendedMasterSecret{
|
||||
Supported: true,
|
||||
})
|
||||
}
|
||||
|
||||
if len(cfg.serverName) > 0 {
|
||||
extensions = append(extensions, &extension.ServerName{ServerName: cfg.serverName})
|
||||
}
|
||||
|
||||
if len(cfg.supportedProtocols) > 0 {
|
||||
extensions = append(extensions, &extension.ALPN{ProtocolNameList: cfg.supportedProtocols})
|
||||
}
|
||||
|
||||
if cfg.sessionStore != nil {
|
||||
cfg.log.Tracef("[handshake] try to resume session")
|
||||
if s, err := cfg.sessionStore.Get(c.sessionKey()); err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
} else if s.ID != nil {
|
||||
cfg.log.Tracef("[handshake] get saved session: %x", s.ID)
|
||||
|
||||
state.SessionID = s.ID
|
||||
state.masterSecret = s.Secret
|
||||
}
|
||||
}
|
||||
|
||||
return []*packet{
|
||||
{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: &handshake.Handshake{
|
||||
Message: &handshake.MessageClientHello{
|
||||
Version: protocol.Version1_2,
|
||||
SessionID: state.SessionID,
|
||||
Cookie: state.cookie,
|
||||
Random: state.localRandom,
|
||||
CipherSuiteIDs: cipherSuiteIDs(cfg.localCipherSuites),
|
||||
CompressionMethods: defaultCompressionMethods(),
|
||||
Extensions: extensions,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil, nil
|
||||
}
|
||||
61
vendor/github.com/pion/dtls/v2/flight2handler.go
generated
vendored
Normal file
61
vendor/github.com/pion/dtls/v2/flight2handler.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/protocol"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/alert"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/handshake"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
|
||||
)
|
||||
|
||||
func flight2Parse(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) {
|
||||
seq, msgs, ok := cache.fullPullMap(state.handshakeRecvSequence,
|
||||
handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
|
||||
)
|
||||
if !ok {
|
||||
// Client may retransmit the first ClientHello when HelloVerifyRequest is dropped.
|
||||
// Parse as flight 0 in this case.
|
||||
return flight0Parse(ctx, c, state, cache, cfg)
|
||||
}
|
||||
state.handshakeRecvSequence = seq
|
||||
|
||||
var clientHello *handshake.MessageClientHello
|
||||
|
||||
// Validate type
|
||||
if clientHello, ok = msgs[handshake.TypeClientHello].(*handshake.MessageClientHello); !ok {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
|
||||
}
|
||||
|
||||
if !clientHello.Version.Equal(protocol.Version1_2) {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.ProtocolVersion}, errUnsupportedProtocolVersion
|
||||
}
|
||||
|
||||
if len(clientHello.Cookie) == 0 {
|
||||
return 0, nil, nil
|
||||
}
|
||||
if !bytes.Equal(state.cookie, clientHello.Cookie) {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.AccessDenied}, errCookieMismatch
|
||||
}
|
||||
return flight4, nil, nil
|
||||
}
|
||||
|
||||
func flight2Generate(c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) {
|
||||
state.handshakeSendSequence = 0
|
||||
return []*packet{
|
||||
{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: &handshake.Handshake{
|
||||
Message: &handshake.MessageHelloVerifyRequest{
|
||||
Version: protocol.Version1_2,
|
||||
Cookie: state.cookie,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil, nil
|
||||
}
|
||||
271
vendor/github.com/pion/dtls/v2/flight3handler.go
generated
vendored
Normal file
271
vendor/github.com/pion/dtls/v2/flight3handler.go
generated
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/crypto/elliptic"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/prf"
|
||||
"github.com/pion/dtls/v2/pkg/protocol"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/alert"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/extension"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/handshake"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
|
||||
)
|
||||
|
||||
func flight3Parse(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) { //nolint:gocognit
|
||||
// Clients may receive multiple HelloVerifyRequest messages with different cookies.
|
||||
// Clients SHOULD handle this by sending a new ClientHello with a cookie in response
|
||||
// to the new HelloVerifyRequest. RFC 6347 Section 4.2.1
|
||||
seq, msgs, ok := cache.fullPullMap(state.handshakeRecvSequence,
|
||||
handshakeCachePullRule{handshake.TypeHelloVerifyRequest, cfg.initialEpoch, false, true},
|
||||
)
|
||||
if ok {
|
||||
if h, msgOk := msgs[handshake.TypeHelloVerifyRequest].(*handshake.MessageHelloVerifyRequest); msgOk {
|
||||
// DTLS 1.2 clients must not assume that the server will use the protocol version
|
||||
// specified in HelloVerifyRequest message. RFC 6347 Section 4.2.1
|
||||
if !h.Version.Equal(protocol.Version1_0) && !h.Version.Equal(protocol.Version1_2) {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.ProtocolVersion}, errUnsupportedProtocolVersion
|
||||
}
|
||||
state.cookie = append([]byte{}, h.Cookie...)
|
||||
state.handshakeRecvSequence = seq
|
||||
return flight3, nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
_, msgs, ok = cache.fullPullMap(state.handshakeRecvSequence,
|
||||
handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
|
||||
)
|
||||
if !ok {
|
||||
// Don't have enough messages. Keep reading
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
if h, msgOk := msgs[handshake.TypeServerHello].(*handshake.MessageServerHello); msgOk {
|
||||
if !h.Version.Equal(protocol.Version1_2) {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.ProtocolVersion}, errUnsupportedProtocolVersion
|
||||
}
|
||||
for _, v := range h.Extensions {
|
||||
switch e := v.(type) {
|
||||
case *extension.UseSRTP:
|
||||
profile, found := findMatchingSRTPProfile(e.ProtectionProfiles, cfg.localSRTPProtectionProfiles)
|
||||
if !found {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.IllegalParameter}, errClientNoMatchingSRTPProfile
|
||||
}
|
||||
state.srtpProtectionProfile = profile
|
||||
case *extension.UseExtendedMasterSecret:
|
||||
if cfg.extendedMasterSecret != DisableExtendedMasterSecret {
|
||||
state.extendedMasterSecret = true
|
||||
}
|
||||
case *extension.ALPN:
|
||||
if len(e.ProtocolNameList) > 1 { // This should be exactly 1, the zero case is handle when unmarshalling
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, extension.ErrALPNInvalidFormat // Meh, internal error?
|
||||
}
|
||||
state.NegotiatedProtocol = e.ProtocolNameList[0]
|
||||
}
|
||||
}
|
||||
if cfg.extendedMasterSecret == RequireExtendedMasterSecret && !state.extendedMasterSecret {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errClientRequiredButNoServerEMS
|
||||
}
|
||||
if len(cfg.localSRTPProtectionProfiles) > 0 && state.srtpProtectionProfile == 0 {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errRequestedButNoSRTPExtension
|
||||
}
|
||||
|
||||
remoteCipherSuite := cipherSuiteForID(CipherSuiteID(*h.CipherSuiteID), cfg.customCipherSuites)
|
||||
if remoteCipherSuite == nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errCipherSuiteNoIntersection
|
||||
}
|
||||
|
||||
selectedCipherSuite, found := findMatchingCipherSuite([]CipherSuite{remoteCipherSuite}, cfg.localCipherSuites)
|
||||
if !found {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errInvalidCipherSuite
|
||||
}
|
||||
|
||||
state.cipherSuite = selectedCipherSuite
|
||||
state.remoteRandom = h.Random
|
||||
cfg.log.Tracef("[handshake] use cipher suite: %s", selectedCipherSuite.String())
|
||||
|
||||
if len(h.SessionID) > 0 && bytes.Equal(state.SessionID, h.SessionID) {
|
||||
return handleResumption(ctx, c, state, cache, cfg)
|
||||
}
|
||||
|
||||
if len(state.SessionID) > 0 {
|
||||
cfg.log.Tracef("[handshake] clean old session : %s", state.SessionID)
|
||||
if err := cfg.sessionStore.Del(state.SessionID); err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.sessionStore == nil {
|
||||
state.SessionID = []byte{}
|
||||
} else {
|
||||
state.SessionID = h.SessionID
|
||||
}
|
||||
|
||||
state.masterSecret = []byte{}
|
||||
}
|
||||
|
||||
if cfg.localPSKCallback != nil {
|
||||
seq, msgs, ok = cache.fullPullMap(state.handshakeRecvSequence+1,
|
||||
handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, true},
|
||||
handshakeCachePullRule{handshake.TypeServerHelloDone, cfg.initialEpoch, false, false},
|
||||
)
|
||||
} else {
|
||||
seq, msgs, ok = cache.fullPullMap(state.handshakeRecvSequence+1,
|
||||
handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, false, true},
|
||||
handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificateRequest, cfg.initialEpoch, false, true},
|
||||
handshakeCachePullRule{handshake.TypeServerHelloDone, cfg.initialEpoch, false, false},
|
||||
)
|
||||
}
|
||||
if !ok {
|
||||
// Don't have enough messages. Keep reading
|
||||
return 0, nil, nil
|
||||
}
|
||||
state.handshakeRecvSequence = seq
|
||||
|
||||
if h, ok := msgs[handshake.TypeCertificate].(*handshake.MessageCertificate); ok {
|
||||
state.PeerCertificates = h.Certificate
|
||||
} else if state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypeCertificate {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.NoCertificate}, errInvalidCertificate
|
||||
}
|
||||
|
||||
if h, ok := msgs[handshake.TypeServerKeyExchange].(*handshake.MessageServerKeyExchange); ok {
|
||||
alertPtr, err := handleServerKeyExchange(c, state, cfg, h)
|
||||
if err != nil {
|
||||
return 0, alertPtr, err
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := msgs[handshake.TypeCertificateRequest].(*handshake.MessageCertificateRequest); ok {
|
||||
state.remoteRequestedCertificate = true
|
||||
}
|
||||
|
||||
return flight5, nil, nil
|
||||
}
|
||||
|
||||
func handleResumption(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) {
|
||||
if err := state.initCipherSuite(); err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
|
||||
// Now, encrypted packets can be handled
|
||||
if err := c.handleQueuedPackets(ctx); err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
|
||||
_, msgs, ok := cache.fullPullMap(state.handshakeRecvSequence+1,
|
||||
handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, false, false},
|
||||
)
|
||||
if !ok {
|
||||
// No valid message received. Keep reading
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
var finished *handshake.MessageFinished
|
||||
if finished, ok = msgs[handshake.TypeFinished].(*handshake.MessageFinished); !ok {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
|
||||
}
|
||||
plainText := cache.pullAndMerge(
|
||||
handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
|
||||
)
|
||||
|
||||
expectedVerifyData, err := prf.VerifyDataServer(state.masterSecret, plainText, state.cipherSuite.HashFunc())
|
||||
if err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
if !bytes.Equal(expectedVerifyData, finished.VerifyData) {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.HandshakeFailure}, errVerifyDataMismatch
|
||||
}
|
||||
|
||||
clientRandom := state.localRandom.MarshalFixed()
|
||||
cfg.writeKeyLog(keyLogLabelTLS12, clientRandom[:], state.masterSecret)
|
||||
|
||||
return flight5b, nil, nil
|
||||
}
|
||||
|
||||
func handleServerKeyExchange(_ flightConn, state *State, cfg *handshakeConfig, h *handshake.MessageServerKeyExchange) (*alert.Alert, error) {
|
||||
var err error
|
||||
if cfg.localPSKCallback != nil {
|
||||
var psk []byte
|
||||
if psk, err = cfg.localPSKCallback(h.IdentityHint); err != nil {
|
||||
return &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
state.IdentityHint = h.IdentityHint
|
||||
state.preMasterSecret = prf.PSKPreMasterSecret(psk)
|
||||
} else {
|
||||
if state.localKeypair, err = elliptic.GenerateKeypair(h.NamedCurve); err != nil {
|
||||
return &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
|
||||
if state.preMasterSecret, err = prf.PreMasterSecret(h.PublicKey, state.localKeypair.PrivateKey, state.localKeypair.Curve); err != nil {
|
||||
return &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func flight3Generate(c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) {
|
||||
extensions := []extension.Extension{
|
||||
&extension.SupportedSignatureAlgorithms{
|
||||
SignatureHashAlgorithms: cfg.localSignatureSchemes,
|
||||
},
|
||||
&extension.RenegotiationInfo{
|
||||
RenegotiatedConnection: 0,
|
||||
},
|
||||
}
|
||||
if cfg.localPSKCallback == nil {
|
||||
extensions = append(extensions, []extension.Extension{
|
||||
&extension.SupportedEllipticCurves{
|
||||
EllipticCurves: []elliptic.Curve{elliptic.X25519, elliptic.P256, elliptic.P384},
|
||||
},
|
||||
&extension.SupportedPointFormats{
|
||||
PointFormats: []elliptic.CurvePointFormat{elliptic.CurvePointFormatUncompressed},
|
||||
},
|
||||
}...)
|
||||
}
|
||||
|
||||
if len(cfg.localSRTPProtectionProfiles) > 0 {
|
||||
extensions = append(extensions, &extension.UseSRTP{
|
||||
ProtectionProfiles: cfg.localSRTPProtectionProfiles,
|
||||
})
|
||||
}
|
||||
|
||||
if cfg.extendedMasterSecret == RequestExtendedMasterSecret ||
|
||||
cfg.extendedMasterSecret == RequireExtendedMasterSecret {
|
||||
extensions = append(extensions, &extension.UseExtendedMasterSecret{
|
||||
Supported: true,
|
||||
})
|
||||
}
|
||||
|
||||
if len(cfg.serverName) > 0 {
|
||||
extensions = append(extensions, &extension.ServerName{ServerName: cfg.serverName})
|
||||
}
|
||||
|
||||
if len(cfg.supportedProtocols) > 0 {
|
||||
extensions = append(extensions, &extension.ALPN{ProtocolNameList: cfg.supportedProtocols})
|
||||
}
|
||||
|
||||
return []*packet{
|
||||
{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: &handshake.Handshake{
|
||||
Message: &handshake.MessageClientHello{
|
||||
Version: protocol.Version1_2,
|
||||
SessionID: state.SessionID,
|
||||
Cookie: state.cookie,
|
||||
Random: state.localRandom,
|
||||
CipherSuiteIDs: cipherSuiteIDs(cfg.localCipherSuites),
|
||||
CompressionMethods: defaultCompressionMethods(),
|
||||
Extensions: extensions,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil, nil
|
||||
}
|
||||
141
vendor/github.com/pion/dtls/v2/flight4bhandler.go
generated
vendored
Normal file
141
vendor/github.com/pion/dtls/v2/flight4bhandler.go
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/crypto/prf"
|
||||
"github.com/pion/dtls/v2/pkg/protocol"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/alert"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/extension"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/handshake"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
|
||||
)
|
||||
|
||||
func flight4bParse(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) {
|
||||
_, msgs, ok := cache.fullPullMap(state.handshakeRecvSequence,
|
||||
handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, true, false},
|
||||
)
|
||||
if !ok {
|
||||
// No valid message received. Keep reading
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
var finished *handshake.MessageFinished
|
||||
if finished, ok = msgs[handshake.TypeFinished].(*handshake.MessageFinished); !ok {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
|
||||
}
|
||||
|
||||
plainText := cache.pullAndMerge(
|
||||
handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, false, false},
|
||||
)
|
||||
|
||||
expectedVerifyData, err := prf.VerifyDataClient(state.masterSecret, plainText, state.cipherSuite.HashFunc())
|
||||
if err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
if !bytes.Equal(expectedVerifyData, finished.VerifyData) {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.HandshakeFailure}, errVerifyDataMismatch
|
||||
}
|
||||
|
||||
// Other party may re-transmit the last flight. Keep state to be flight4b.
|
||||
return flight4b, nil, nil
|
||||
}
|
||||
|
||||
func flight4bGenerate(c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) {
|
||||
var pkts []*packet
|
||||
|
||||
extensions := []extension.Extension{&extension.RenegotiationInfo{
|
||||
RenegotiatedConnection: 0,
|
||||
}}
|
||||
if (cfg.extendedMasterSecret == RequestExtendedMasterSecret ||
|
||||
cfg.extendedMasterSecret == RequireExtendedMasterSecret) && state.extendedMasterSecret {
|
||||
extensions = append(extensions, &extension.UseExtendedMasterSecret{
|
||||
Supported: true,
|
||||
})
|
||||
}
|
||||
if state.srtpProtectionProfile != 0 {
|
||||
extensions = append(extensions, &extension.UseSRTP{
|
||||
ProtectionProfiles: []SRTPProtectionProfile{state.srtpProtectionProfile},
|
||||
})
|
||||
}
|
||||
|
||||
selectedProto, err := extension.ALPNProtocolSelection(cfg.supportedProtocols, state.peerSupportedProtocols)
|
||||
if err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.NoApplicationProtocol}, err
|
||||
}
|
||||
if selectedProto != "" {
|
||||
extensions = append(extensions, &extension.ALPN{
|
||||
ProtocolNameList: []string{selectedProto},
|
||||
})
|
||||
state.NegotiatedProtocol = selectedProto
|
||||
}
|
||||
|
||||
cipherSuiteID := uint16(state.cipherSuite.ID())
|
||||
serverHello := &handshake.Handshake{
|
||||
Message: &handshake.MessageServerHello{
|
||||
Version: protocol.Version1_2,
|
||||
Random: state.localRandom,
|
||||
SessionID: state.SessionID,
|
||||
CipherSuiteID: &cipherSuiteID,
|
||||
CompressionMethod: defaultCompressionMethods()[0],
|
||||
Extensions: extensions,
|
||||
},
|
||||
}
|
||||
|
||||
serverHello.Header.MessageSequence = uint16(state.handshakeSendSequence)
|
||||
|
||||
if len(state.localVerifyData) == 0 {
|
||||
plainText := cache.pullAndMerge(
|
||||
handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
|
||||
)
|
||||
raw, err := serverHello.Marshal()
|
||||
if err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
plainText = append(plainText, raw...)
|
||||
|
||||
state.localVerifyData, err = prf.VerifyDataServer(state.masterSecret, plainText, state.cipherSuite.HashFunc())
|
||||
if err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
}
|
||||
|
||||
pkts = append(pkts,
|
||||
&packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: serverHello,
|
||||
},
|
||||
},
|
||||
&packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: &protocol.ChangeCipherSpec{},
|
||||
},
|
||||
},
|
||||
&packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
Epoch: 1,
|
||||
},
|
||||
Content: &handshake.Handshake{
|
||||
Message: &handshake.MessageFinished{
|
||||
VerifyData: state.localVerifyData,
|
||||
},
|
||||
},
|
||||
},
|
||||
shouldEncrypt: true,
|
||||
resetLocalSequenceNumber: true,
|
||||
},
|
||||
)
|
||||
|
||||
return pkts, nil, nil
|
||||
}
|
||||
369
vendor/github.com/pion/dtls/v2/flight4handler.go
generated
vendored
Normal file
369
vendor/github.com/pion/dtls/v2/flight4handler.go
generated
vendored
Normal file
@@ -0,0 +1,369 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/elliptic"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/prf"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/signaturehash"
|
||||
"github.com/pion/dtls/v2/pkg/protocol"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/alert"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/extension"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/handshake"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
|
||||
)
|
||||
|
||||
func flight4Parse(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) { //nolint:gocognit
|
||||
seq, msgs, ok := cache.fullPullMap(state.handshakeRecvSequence,
|
||||
handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, true, true},
|
||||
handshakeCachePullRule{handshake.TypeClientKeyExchange, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificateVerify, cfg.initialEpoch, true, true},
|
||||
)
|
||||
if !ok {
|
||||
// No valid message received. Keep reading
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
// Validate type
|
||||
var clientKeyExchange *handshake.MessageClientKeyExchange
|
||||
if clientKeyExchange, ok = msgs[handshake.TypeClientKeyExchange].(*handshake.MessageClientKeyExchange); !ok {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
|
||||
}
|
||||
|
||||
if h, hasCert := msgs[handshake.TypeCertificate].(*handshake.MessageCertificate); hasCert {
|
||||
state.PeerCertificates = h.Certificate
|
||||
// If the client offer its certificate, just disable session resumption.
|
||||
// Otherwise, we have to store the certificate identitfication and expire time.
|
||||
// And we have to check whether this certificate expired, revoked or changed.
|
||||
//
|
||||
// https://curl.se/docs/CVE-2016-5419.html
|
||||
state.SessionID = nil
|
||||
}
|
||||
|
||||
if h, hasCertVerify := msgs[handshake.TypeCertificateVerify].(*handshake.MessageCertificateVerify); hasCertVerify {
|
||||
if state.PeerCertificates == nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.NoCertificate}, errCertificateVerifyNoCertificate
|
||||
}
|
||||
|
||||
plainText := cache.pullAndMerge(
|
||||
handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificateRequest, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeServerHelloDone, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeClientKeyExchange, cfg.initialEpoch, true, false},
|
||||
)
|
||||
|
||||
// Verify that the pair of hash algorithm and signiture is listed.
|
||||
var validSignatureScheme bool
|
||||
for _, ss := range cfg.localSignatureSchemes {
|
||||
if ss.Hash == h.HashAlgorithm && ss.Signature == h.SignatureAlgorithm {
|
||||
validSignatureScheme = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !validSignatureScheme {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errNoAvailableSignatureSchemes
|
||||
}
|
||||
|
||||
if err := verifyCertificateVerify(plainText, h.HashAlgorithm, h.Signature, state.PeerCertificates); err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, err
|
||||
}
|
||||
var chains [][]*x509.Certificate
|
||||
var err error
|
||||
var verified bool
|
||||
if cfg.clientAuth >= VerifyClientCertIfGiven {
|
||||
if chains, err = verifyClientCert(state.PeerCertificates, cfg.clientCAs); err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, err
|
||||
}
|
||||
verified = true
|
||||
}
|
||||
if cfg.verifyPeerCertificate != nil {
|
||||
if err := cfg.verifyPeerCertificate(state.PeerCertificates, chains); err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, err
|
||||
}
|
||||
}
|
||||
state.peerCertificatesVerified = verified
|
||||
}
|
||||
|
||||
if !state.cipherSuite.IsInitialized() {
|
||||
serverRandom := state.localRandom.MarshalFixed()
|
||||
clientRandom := state.remoteRandom.MarshalFixed()
|
||||
|
||||
var err error
|
||||
var preMasterSecret []byte
|
||||
if state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypePreSharedKey {
|
||||
var psk []byte
|
||||
if psk, err = cfg.localPSKCallback(clientKeyExchange.IdentityHint); err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
state.IdentityHint = clientKeyExchange.IdentityHint
|
||||
preMasterSecret = prf.PSKPreMasterSecret(psk)
|
||||
} else {
|
||||
preMasterSecret, err = prf.PreMasterSecret(clientKeyExchange.PublicKey, state.localKeypair.PrivateKey, state.localKeypair.Curve)
|
||||
if err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.IllegalParameter}, err
|
||||
}
|
||||
}
|
||||
|
||||
if state.extendedMasterSecret {
|
||||
var sessionHash []byte
|
||||
sessionHash, err = cache.sessionHash(state.cipherSuite.HashFunc(), cfg.initialEpoch)
|
||||
if err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
|
||||
state.masterSecret, err = prf.ExtendedMasterSecret(preMasterSecret, sessionHash, state.cipherSuite.HashFunc())
|
||||
if err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
} else {
|
||||
state.masterSecret, err = prf.MasterSecret(preMasterSecret, clientRandom[:], serverRandom[:], state.cipherSuite.HashFunc())
|
||||
if err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := state.cipherSuite.Init(state.masterSecret, clientRandom[:], serverRandom[:], false); err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
cfg.writeKeyLog(keyLogLabelTLS12, clientRandom[:], state.masterSecret)
|
||||
}
|
||||
|
||||
if len(state.SessionID) > 0 {
|
||||
s := Session{
|
||||
ID: state.SessionID,
|
||||
Secret: state.masterSecret,
|
||||
}
|
||||
cfg.log.Tracef("[handshake] save new session: %x", s.ID)
|
||||
if err := cfg.sessionStore.Set(state.SessionID, s); err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
}
|
||||
|
||||
// Now, encrypted packets can be handled
|
||||
if err := c.handleQueuedPackets(ctx); err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
|
||||
seq, msgs, ok = cache.fullPullMap(seq,
|
||||
handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, true, false},
|
||||
)
|
||||
if !ok {
|
||||
// No valid message received. Keep reading
|
||||
return 0, nil, nil
|
||||
}
|
||||
state.handshakeRecvSequence = seq
|
||||
|
||||
if _, ok = msgs[handshake.TypeFinished].(*handshake.MessageFinished); !ok {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
|
||||
}
|
||||
|
||||
if state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypeAnonymous {
|
||||
return flight6, nil, nil
|
||||
}
|
||||
|
||||
switch cfg.clientAuth {
|
||||
case RequireAnyClientCert:
|
||||
if state.PeerCertificates == nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.NoCertificate}, errClientCertificateRequired
|
||||
}
|
||||
case VerifyClientCertIfGiven:
|
||||
if state.PeerCertificates != nil && !state.peerCertificatesVerified {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, errClientCertificateNotVerified
|
||||
}
|
||||
case RequireAndVerifyClientCert:
|
||||
if state.PeerCertificates == nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.NoCertificate}, errClientCertificateRequired
|
||||
}
|
||||
if !state.peerCertificatesVerified {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, errClientCertificateNotVerified
|
||||
}
|
||||
case NoClientCert, RequestClientCert:
|
||||
return flight6, nil, nil
|
||||
}
|
||||
|
||||
return flight6, nil, nil
|
||||
}
|
||||
|
||||
func flight4Generate(c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) {
|
||||
extensions := []extension.Extension{&extension.RenegotiationInfo{
|
||||
RenegotiatedConnection: 0,
|
||||
}}
|
||||
if (cfg.extendedMasterSecret == RequestExtendedMasterSecret ||
|
||||
cfg.extendedMasterSecret == RequireExtendedMasterSecret) && state.extendedMasterSecret {
|
||||
extensions = append(extensions, &extension.UseExtendedMasterSecret{
|
||||
Supported: true,
|
||||
})
|
||||
}
|
||||
if state.srtpProtectionProfile != 0 {
|
||||
extensions = append(extensions, &extension.UseSRTP{
|
||||
ProtectionProfiles: []SRTPProtectionProfile{state.srtpProtectionProfile},
|
||||
})
|
||||
}
|
||||
if state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypeCertificate {
|
||||
extensions = append(extensions, &extension.SupportedPointFormats{
|
||||
PointFormats: []elliptic.CurvePointFormat{elliptic.CurvePointFormatUncompressed},
|
||||
})
|
||||
}
|
||||
|
||||
selectedProto, err := extension.ALPNProtocolSelection(cfg.supportedProtocols, state.peerSupportedProtocols)
|
||||
if err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.NoApplicationProtocol}, err
|
||||
}
|
||||
if selectedProto != "" {
|
||||
extensions = append(extensions, &extension.ALPN{
|
||||
ProtocolNameList: []string{selectedProto},
|
||||
})
|
||||
state.NegotiatedProtocol = selectedProto
|
||||
}
|
||||
|
||||
var pkts []*packet
|
||||
cipherSuiteID := uint16(state.cipherSuite.ID())
|
||||
|
||||
if cfg.sessionStore != nil {
|
||||
state.SessionID = make([]byte, sessionLength)
|
||||
if _, err := rand.Read(state.SessionID); err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
}
|
||||
|
||||
pkts = append(pkts, &packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: &handshake.Handshake{
|
||||
Message: &handshake.MessageServerHello{
|
||||
Version: protocol.Version1_2,
|
||||
Random: state.localRandom,
|
||||
SessionID: state.SessionID,
|
||||
CipherSuiteID: &cipherSuiteID,
|
||||
CompressionMethod: defaultCompressionMethods()[0],
|
||||
Extensions: extensions,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
switch {
|
||||
case state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypeCertificate:
|
||||
certificate, err := cfg.getCertificate(state.serverName)
|
||||
if err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.HandshakeFailure}, err
|
||||
}
|
||||
|
||||
pkts = append(pkts, &packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: &handshake.Handshake{
|
||||
Message: &handshake.MessageCertificate{
|
||||
Certificate: certificate.Certificate,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
serverRandom := state.localRandom.MarshalFixed()
|
||||
clientRandom := state.remoteRandom.MarshalFixed()
|
||||
|
||||
// Find compatible signature scheme
|
||||
signatureHashAlgo, err := signaturehash.SelectSignatureScheme(cfg.localSignatureSchemes, certificate.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, err
|
||||
}
|
||||
|
||||
signature, err := generateKeySignature(clientRandom[:], serverRandom[:], state.localKeypair.PublicKey, state.namedCurve, certificate.PrivateKey, signatureHashAlgo.Hash)
|
||||
if err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
state.localKeySignature = signature
|
||||
|
||||
pkts = append(pkts, &packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: &handshake.Handshake{
|
||||
Message: &handshake.MessageServerKeyExchange{
|
||||
EllipticCurveType: elliptic.CurveTypeNamedCurve,
|
||||
NamedCurve: state.namedCurve,
|
||||
PublicKey: state.localKeypair.PublicKey,
|
||||
HashAlgorithm: signatureHashAlgo.Hash,
|
||||
SignatureAlgorithm: signatureHashAlgo.Signature,
|
||||
Signature: state.localKeySignature,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if cfg.clientAuth > NoClientCert {
|
||||
pkts = append(pkts, &packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: &handshake.Handshake{
|
||||
Message: &handshake.MessageCertificateRequest{
|
||||
CertificateTypes: []clientcertificate.Type{clientcertificate.RSASign, clientcertificate.ECDSASign},
|
||||
SignatureHashAlgorithms: cfg.localSignatureSchemes,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
case cfg.localPSKIdentityHint != nil:
|
||||
// To help the client in selecting which identity to use, the server
|
||||
// can provide a "PSK identity hint" in the ServerKeyExchange message.
|
||||
// If no hint is provided, the ServerKeyExchange message is omitted.
|
||||
//
|
||||
// https://tools.ietf.org/html/rfc4279#section-2
|
||||
pkts = append(pkts, &packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: &handshake.Handshake{
|
||||
Message: &handshake.MessageServerKeyExchange{
|
||||
IdentityHint: cfg.localPSKIdentityHint,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
case state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypeAnonymous:
|
||||
pkts = append(pkts, &packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: &handshake.Handshake{
|
||||
Message: &handshake.MessageServerKeyExchange{
|
||||
EllipticCurveType: elliptic.CurveTypeNamedCurve,
|
||||
NamedCurve: state.namedCurve,
|
||||
PublicKey: state.localKeypair.PublicKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pkts = append(pkts, &packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: &handshake.Handshake{
|
||||
Message: &handshake.MessageServerHelloDone{},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return pkts, nil, nil
|
||||
}
|
||||
75
vendor/github.com/pion/dtls/v2/flight5bhandler.go
generated
vendored
Normal file
75
vendor/github.com/pion/dtls/v2/flight5bhandler.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/crypto/prf"
|
||||
"github.com/pion/dtls/v2/pkg/protocol"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/alert"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/handshake"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
|
||||
)
|
||||
|
||||
func flight5bParse(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) {
|
||||
_, msgs, ok := cache.fullPullMap(state.handshakeRecvSequence-1,
|
||||
handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, false, false},
|
||||
)
|
||||
if !ok {
|
||||
// No valid message received. Keep reading
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
if _, ok = msgs[handshake.TypeFinished].(*handshake.MessageFinished); !ok {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
|
||||
}
|
||||
|
||||
// Other party may re-transmit the last flight. Keep state to be flight5b.
|
||||
return flight5b, nil, nil
|
||||
}
|
||||
|
||||
func flight5bGenerate(c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) { //nolint:gocognit
|
||||
var pkts []*packet
|
||||
|
||||
pkts = append(pkts,
|
||||
&packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: &protocol.ChangeCipherSpec{},
|
||||
},
|
||||
})
|
||||
|
||||
if len(state.localVerifyData) == 0 {
|
||||
plainText := cache.pullAndMerge(
|
||||
handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, false, false},
|
||||
)
|
||||
|
||||
var err error
|
||||
state.localVerifyData, err = prf.VerifyDataClient(state.masterSecret, plainText, state.cipherSuite.HashFunc())
|
||||
if err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
}
|
||||
|
||||
pkts = append(pkts,
|
||||
&packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
Epoch: 1,
|
||||
},
|
||||
Content: &handshake.Handshake{
|
||||
Message: &handshake.MessageFinished{
|
||||
VerifyData: state.localVerifyData,
|
||||
},
|
||||
},
|
||||
},
|
||||
shouldEncrypt: true,
|
||||
resetLocalSequenceNumber: true,
|
||||
})
|
||||
|
||||
return pkts, nil, nil
|
||||
}
|
||||
334
vendor/github.com/pion/dtls/v2/flight5handler.go
generated
vendored
Normal file
334
vendor/github.com/pion/dtls/v2/flight5handler.go
generated
vendored
Normal file
@@ -0,0 +1,334 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/crypto/prf"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/signaturehash"
|
||||
"github.com/pion/dtls/v2/pkg/protocol"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/alert"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/handshake"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
|
||||
)
|
||||
|
||||
func flight5Parse(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) {
|
||||
_, msgs, ok := cache.fullPullMap(state.handshakeRecvSequence,
|
||||
handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, false, false},
|
||||
)
|
||||
if !ok {
|
||||
// No valid message received. Keep reading
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
var finished *handshake.MessageFinished
|
||||
if finished, ok = msgs[handshake.TypeFinished].(*handshake.MessageFinished); !ok {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
|
||||
}
|
||||
plainText := cache.pullAndMerge(
|
||||
handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificateRequest, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeServerHelloDone, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeClientKeyExchange, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificateVerify, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, true, false},
|
||||
)
|
||||
|
||||
expectedVerifyData, err := prf.VerifyDataServer(state.masterSecret, plainText, state.cipherSuite.HashFunc())
|
||||
if err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
if !bytes.Equal(expectedVerifyData, finished.VerifyData) {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.HandshakeFailure}, errVerifyDataMismatch
|
||||
}
|
||||
|
||||
if len(state.SessionID) > 0 {
|
||||
s := Session{
|
||||
ID: state.SessionID,
|
||||
Secret: state.masterSecret,
|
||||
}
|
||||
cfg.log.Tracef("[handshake] save new session: %x", s.ID)
|
||||
if err := cfg.sessionStore.Set(c.sessionKey(), s); err != nil {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
}
|
||||
|
||||
return flight5, nil, nil
|
||||
}
|
||||
|
||||
func flight5Generate(c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) { //nolint:gocognit
|
||||
var certBytes [][]byte
|
||||
var privateKey crypto.PrivateKey
|
||||
if len(cfg.localCertificates) > 0 {
|
||||
certificate, err := cfg.getCertificate(cfg.serverName)
|
||||
if err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.HandshakeFailure}, err
|
||||
}
|
||||
certBytes = certificate.Certificate
|
||||
privateKey = certificate.PrivateKey
|
||||
}
|
||||
|
||||
var pkts []*packet
|
||||
|
||||
if state.remoteRequestedCertificate {
|
||||
pkts = append(pkts,
|
||||
&packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: &handshake.Handshake{
|
||||
Message: &handshake.MessageCertificate{
|
||||
Certificate: certBytes,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
clientKeyExchange := &handshake.MessageClientKeyExchange{}
|
||||
if cfg.localPSKCallback == nil {
|
||||
clientKeyExchange.PublicKey = state.localKeypair.PublicKey
|
||||
} else {
|
||||
clientKeyExchange.IdentityHint = cfg.localPSKIdentityHint
|
||||
}
|
||||
|
||||
pkts = append(pkts,
|
||||
&packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: &handshake.Handshake{
|
||||
Message: clientKeyExchange,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
serverKeyExchangeData := cache.pullAndMerge(
|
||||
handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, false},
|
||||
)
|
||||
|
||||
serverKeyExchange := &handshake.MessageServerKeyExchange{}
|
||||
|
||||
// handshakeMessageServerKeyExchange is optional for PSK
|
||||
if len(serverKeyExchangeData) == 0 {
|
||||
alertPtr, err := handleServerKeyExchange(c, state, cfg, &handshake.MessageServerKeyExchange{})
|
||||
if err != nil {
|
||||
return nil, alertPtr, err
|
||||
}
|
||||
} else {
|
||||
rawHandshake := &handshake.Handshake{}
|
||||
err := rawHandshake.Unmarshal(serverKeyExchangeData)
|
||||
if err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.UnexpectedMessage}, err
|
||||
}
|
||||
|
||||
switch h := rawHandshake.Message.(type) {
|
||||
case *handshake.MessageServerKeyExchange:
|
||||
serverKeyExchange = h
|
||||
default:
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.UnexpectedMessage}, errInvalidContentType
|
||||
}
|
||||
}
|
||||
|
||||
// Append not-yet-sent packets
|
||||
merged := []byte{}
|
||||
seqPred := uint16(state.handshakeSendSequence)
|
||||
for _, p := range pkts {
|
||||
h, ok := p.record.Content.(*handshake.Handshake)
|
||||
if !ok {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, errInvalidContentType
|
||||
}
|
||||
h.Header.MessageSequence = seqPred
|
||||
seqPred++
|
||||
raw, err := h.Marshal()
|
||||
if err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
merged = append(merged, raw...)
|
||||
}
|
||||
|
||||
if alertPtr, err := initalizeCipherSuite(state, cache, cfg, serverKeyExchange, merged); err != nil {
|
||||
return nil, alertPtr, err
|
||||
}
|
||||
|
||||
// If the client has sent a certificate with signing ability, a digitally-signed
|
||||
// CertificateVerify message is sent to explicitly verify possession of the
|
||||
// private key in the certificate.
|
||||
if state.remoteRequestedCertificate && len(cfg.localCertificates) > 0 {
|
||||
plainText := append(cache.pullAndMerge(
|
||||
handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificateRequest, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeServerHelloDone, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeClientKeyExchange, cfg.initialEpoch, true, false},
|
||||
), merged...)
|
||||
|
||||
// Find compatible signature scheme
|
||||
signatureHashAlgo, err := signaturehash.SelectSignatureScheme(cfg.localSignatureSchemes, privateKey)
|
||||
if err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, err
|
||||
}
|
||||
|
||||
certVerify, err := generateCertificateVerify(plainText, privateKey, signatureHashAlgo.Hash)
|
||||
if err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
state.localCertificatesVerify = certVerify
|
||||
|
||||
p := &packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: &handshake.Handshake{
|
||||
Message: &handshake.MessageCertificateVerify{
|
||||
HashAlgorithm: signatureHashAlgo.Hash,
|
||||
SignatureAlgorithm: signatureHashAlgo.Signature,
|
||||
Signature: state.localCertificatesVerify,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
pkts = append(pkts, p)
|
||||
|
||||
h, ok := p.record.Content.(*handshake.Handshake)
|
||||
if !ok {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, errInvalidContentType
|
||||
}
|
||||
h.Header.MessageSequence = seqPred
|
||||
// seqPred++ // this is the last use of seqPred
|
||||
raw, err := h.Marshal()
|
||||
if err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
merged = append(merged, raw...)
|
||||
}
|
||||
|
||||
pkts = append(pkts,
|
||||
&packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: &protocol.ChangeCipherSpec{},
|
||||
},
|
||||
})
|
||||
|
||||
if len(state.localVerifyData) == 0 {
|
||||
plainText := cache.pullAndMerge(
|
||||
handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificateRequest, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeServerHelloDone, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeClientKeyExchange, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificateVerify, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, true, false},
|
||||
)
|
||||
|
||||
var err error
|
||||
state.localVerifyData, err = prf.VerifyDataClient(state.masterSecret, append(plainText, merged...), state.cipherSuite.HashFunc())
|
||||
if err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
}
|
||||
|
||||
pkts = append(pkts,
|
||||
&packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
Epoch: 1,
|
||||
},
|
||||
Content: &handshake.Handshake{
|
||||
Message: &handshake.MessageFinished{
|
||||
VerifyData: state.localVerifyData,
|
||||
},
|
||||
},
|
||||
},
|
||||
shouldEncrypt: true,
|
||||
resetLocalSequenceNumber: true,
|
||||
})
|
||||
|
||||
return pkts, nil, nil
|
||||
}
|
||||
|
||||
func initalizeCipherSuite(state *State, cache *handshakeCache, cfg *handshakeConfig, h *handshake.MessageServerKeyExchange, sendingPlainText []byte) (*alert.Alert, error) { //nolint:gocognit
|
||||
if state.cipherSuite.IsInitialized() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
clientRandom := state.localRandom.MarshalFixed()
|
||||
serverRandom := state.remoteRandom.MarshalFixed()
|
||||
|
||||
var err error
|
||||
|
||||
if state.extendedMasterSecret {
|
||||
var sessionHash []byte
|
||||
sessionHash, err = cache.sessionHash(state.cipherSuite.HashFunc(), cfg.initialEpoch, sendingPlainText)
|
||||
if err != nil {
|
||||
return &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
|
||||
state.masterSecret, err = prf.ExtendedMasterSecret(state.preMasterSecret, sessionHash, state.cipherSuite.HashFunc())
|
||||
if err != nil {
|
||||
return &alert.Alert{Level: alert.Fatal, Description: alert.IllegalParameter}, err
|
||||
}
|
||||
} else {
|
||||
state.masterSecret, err = prf.MasterSecret(state.preMasterSecret, clientRandom[:], serverRandom[:], state.cipherSuite.HashFunc())
|
||||
if err != nil {
|
||||
return &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
}
|
||||
|
||||
if state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypeCertificate {
|
||||
// Verify that the pair of hash algorithm and signiture is listed.
|
||||
var validSignatureScheme bool
|
||||
for _, ss := range cfg.localSignatureSchemes {
|
||||
if ss.Hash == h.HashAlgorithm && ss.Signature == h.SignatureAlgorithm {
|
||||
validSignatureScheme = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !validSignatureScheme {
|
||||
return &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errNoAvailableSignatureSchemes
|
||||
}
|
||||
|
||||
expectedMsg := valueKeyMessage(clientRandom[:], serverRandom[:], h.PublicKey, h.NamedCurve)
|
||||
if err = verifyKeySignature(expectedMsg, h.Signature, h.HashAlgorithm, state.PeerCertificates); err != nil {
|
||||
return &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, err
|
||||
}
|
||||
var chains [][]*x509.Certificate
|
||||
if !cfg.insecureSkipVerify {
|
||||
if chains, err = verifyServerCert(state.PeerCertificates, cfg.rootCAs, cfg.serverName); err != nil {
|
||||
return &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, err
|
||||
}
|
||||
}
|
||||
if cfg.verifyPeerCertificate != nil {
|
||||
if err = cfg.verifyPeerCertificate(state.PeerCertificates, chains); err != nil {
|
||||
return &alert.Alert{Level: alert.Fatal, Description: alert.BadCertificate}, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err = state.cipherSuite.Init(state.masterSecret, clientRandom[:], serverRandom[:], true); err != nil {
|
||||
return &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
|
||||
cfg.writeKeyLog(keyLogLabelTLS12, clientRandom[:], state.masterSecret)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
82
vendor/github.com/pion/dtls/v2/flight6handler.go
generated
vendored
Normal file
82
vendor/github.com/pion/dtls/v2/flight6handler.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/crypto/prf"
|
||||
"github.com/pion/dtls/v2/pkg/protocol"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/alert"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/handshake"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
|
||||
)
|
||||
|
||||
func flight6Parse(ctx context.Context, c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) (flightVal, *alert.Alert, error) {
|
||||
_, msgs, ok := cache.fullPullMap(state.handshakeRecvSequence-1,
|
||||
handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, true, false},
|
||||
)
|
||||
if !ok {
|
||||
// No valid message received. Keep reading
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
if _, ok = msgs[handshake.TypeFinished].(*handshake.MessageFinished); !ok {
|
||||
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
|
||||
}
|
||||
|
||||
// Other party may re-transmit the last flight. Keep state to be flight6.
|
||||
return flight6, nil, nil
|
||||
}
|
||||
|
||||
func flight6Generate(c flightConn, state *State, cache *handshakeCache, cfg *handshakeConfig) ([]*packet, *alert.Alert, error) {
|
||||
var pkts []*packet
|
||||
|
||||
pkts = append(pkts,
|
||||
&packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
},
|
||||
Content: &protocol.ChangeCipherSpec{},
|
||||
},
|
||||
})
|
||||
|
||||
if len(state.localVerifyData) == 0 {
|
||||
plainText := cache.pullAndMerge(
|
||||
handshakeCachePullRule{handshake.TypeClientHello, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificateRequest, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeServerHelloDone, cfg.initialEpoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificate, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeClientKeyExchange, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificateVerify, cfg.initialEpoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeFinished, cfg.initialEpoch + 1, true, false},
|
||||
)
|
||||
|
||||
var err error
|
||||
state.localVerifyData, err = prf.VerifyDataServer(state.masterSecret, plainText, state.cipherSuite.HashFunc())
|
||||
if err != nil {
|
||||
return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, err
|
||||
}
|
||||
}
|
||||
|
||||
pkts = append(pkts,
|
||||
&packet{
|
||||
record: &recordlayer.RecordLayer{
|
||||
Header: recordlayer.Header{
|
||||
Version: protocol.Version1_2,
|
||||
Epoch: 1,
|
||||
},
|
||||
Content: &handshake.Handshake{
|
||||
Message: &handshake.MessageFinished{
|
||||
VerifyData: state.localVerifyData,
|
||||
},
|
||||
},
|
||||
},
|
||||
shouldEncrypt: true,
|
||||
resetLocalSequenceNumber: true,
|
||||
},
|
||||
)
|
||||
return pkts, nil, nil
|
||||
}
|
||||
65
vendor/github.com/pion/dtls/v2/flighthandler.go
generated
vendored
Normal file
65
vendor/github.com/pion/dtls/v2/flighthandler.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/protocol/alert"
|
||||
)
|
||||
|
||||
// Parse received handshakes and return next flightVal
|
||||
type flightParser func(context.Context, flightConn, *State, *handshakeCache, *handshakeConfig) (flightVal, *alert.Alert, error)
|
||||
|
||||
// Generate flights
|
||||
type flightGenerator func(flightConn, *State, *handshakeCache, *handshakeConfig) ([]*packet, *alert.Alert, error)
|
||||
|
||||
func (f flightVal) getFlightParser() (flightParser, error) {
|
||||
switch f {
|
||||
case flight0:
|
||||
return flight0Parse, nil
|
||||
case flight1:
|
||||
return flight1Parse, nil
|
||||
case flight2:
|
||||
return flight2Parse, nil
|
||||
case flight3:
|
||||
return flight3Parse, nil
|
||||
case flight4:
|
||||
return flight4Parse, nil
|
||||
case flight4b:
|
||||
return flight4bParse, nil
|
||||
case flight5:
|
||||
return flight5Parse, nil
|
||||
case flight5b:
|
||||
return flight5bParse, nil
|
||||
case flight6:
|
||||
return flight6Parse, nil
|
||||
default:
|
||||
return nil, errInvalidFlight
|
||||
}
|
||||
}
|
||||
|
||||
func (f flightVal) getFlightGenerator() (gen flightGenerator, retransmit bool, err error) {
|
||||
switch f {
|
||||
case flight0:
|
||||
return flight0Generate, true, nil
|
||||
case flight1:
|
||||
return flight1Generate, true, nil
|
||||
case flight2:
|
||||
// https://tools.ietf.org/html/rfc6347#section-3.2.1
|
||||
// HelloVerifyRequests must not be retransmitted.
|
||||
return flight2Generate, false, nil
|
||||
case flight3:
|
||||
return flight3Generate, true, nil
|
||||
case flight4:
|
||||
return flight4Generate, true, nil
|
||||
case flight4b:
|
||||
return flight4bGenerate, true, nil
|
||||
case flight5:
|
||||
return flight5Generate, true, nil
|
||||
case flight5b:
|
||||
return flight5bGenerate, true, nil
|
||||
case flight6:
|
||||
return flight6Generate, true, nil
|
||||
default:
|
||||
return nil, false, errInvalidFlight
|
||||
}
|
||||
}
|
||||
111
vendor/github.com/pion/dtls/v2/fragment_buffer.go
generated
vendored
Normal file
111
vendor/github.com/pion/dtls/v2/fragment_buffer.go
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"github.com/pion/dtls/v2/pkg/protocol"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/handshake"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
|
||||
)
|
||||
|
||||
type fragment struct {
|
||||
recordLayerHeader recordlayer.Header
|
||||
handshakeHeader handshake.Header
|
||||
data []byte
|
||||
}
|
||||
|
||||
type fragmentBuffer struct {
|
||||
// map of MessageSequenceNumbers that hold slices of fragments
|
||||
cache map[uint16][]*fragment
|
||||
|
||||
currentMessageSequenceNumber uint16
|
||||
}
|
||||
|
||||
func newFragmentBuffer() *fragmentBuffer {
|
||||
return &fragmentBuffer{cache: map[uint16][]*fragment{}}
|
||||
}
|
||||
|
||||
// Attempts to push a DTLS packet to the fragmentBuffer
|
||||
// when it returns true it means the fragmentBuffer has inserted and the buffer shouldn't be handled
|
||||
// when an error returns it is fatal, and the DTLS connection should be stopped
|
||||
func (f *fragmentBuffer) push(buf []byte) (bool, error) {
|
||||
frag := new(fragment)
|
||||
if err := frag.recordLayerHeader.Unmarshal(buf); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// fragment isn't a handshake, we don't need to handle it
|
||||
if frag.recordLayerHeader.ContentType != protocol.ContentTypeHandshake {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
for buf = buf[recordlayer.HeaderSize:]; len(buf) != 0; frag = new(fragment) {
|
||||
if err := frag.handshakeHeader.Unmarshal(buf); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if _, ok := f.cache[frag.handshakeHeader.MessageSequence]; !ok {
|
||||
f.cache[frag.handshakeHeader.MessageSequence] = []*fragment{}
|
||||
}
|
||||
|
||||
// end index should be the length of handshake header but if the handshake
|
||||
// was fragmented, we should keep them all
|
||||
end := int(handshake.HeaderLength + frag.handshakeHeader.Length)
|
||||
if size := len(buf); end > size {
|
||||
end = size
|
||||
}
|
||||
|
||||
// Discard all headers, when rebuilding the packet we will re-build
|
||||
frag.data = append([]byte{}, buf[handshake.HeaderLength:end]...)
|
||||
f.cache[frag.handshakeHeader.MessageSequence] = append(f.cache[frag.handshakeHeader.MessageSequence], frag)
|
||||
buf = buf[end:]
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (f *fragmentBuffer) pop() (content []byte, epoch uint16) {
|
||||
frags, ok := f.cache[f.currentMessageSequenceNumber]
|
||||
if !ok {
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
// Go doesn't support recursive lambdas
|
||||
var appendMessage func(targetOffset uint32) bool
|
||||
|
||||
rawMessage := []byte{}
|
||||
appendMessage = func(targetOffset uint32) bool {
|
||||
for _, f := range frags {
|
||||
if f.handshakeHeader.FragmentOffset == targetOffset {
|
||||
fragmentEnd := (f.handshakeHeader.FragmentOffset + f.handshakeHeader.FragmentLength)
|
||||
if fragmentEnd != f.handshakeHeader.Length {
|
||||
if !appendMessage(fragmentEnd) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
rawMessage = append(f.data, rawMessage...)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Recursively collect up
|
||||
if !appendMessage(0) {
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
firstHeader := frags[0].handshakeHeader
|
||||
firstHeader.FragmentOffset = 0
|
||||
firstHeader.FragmentLength = firstHeader.Length
|
||||
|
||||
rawHeader, err := firstHeader.Marshal()
|
||||
if err != nil {
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
messageEpoch := frags[0].recordLayerHeader.Epoch
|
||||
|
||||
delete(f.cache, f.currentMessageSequenceNumber)
|
||||
f.currentMessageSequenceNumber++
|
||||
return append(rawHeader, rawMessage...), messageEpoch
|
||||
}
|
||||
39
vendor/github.com/pion/dtls/v2/fuzz.go
generated
vendored
Normal file
39
vendor/github.com/pion/dtls/v2/fuzz.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
//go:build gofuzz
|
||||
// +build gofuzz
|
||||
|
||||
package dtls
|
||||
|
||||
import "fmt"
|
||||
|
||||
func partialHeaderMismatch(a, b recordlayer.Header) bool {
|
||||
// Ignoring content length for now.
|
||||
a.contentLen = b.contentLen
|
||||
return a != b
|
||||
}
|
||||
|
||||
func FuzzRecordLayer(data []byte) int {
|
||||
var r recordLayer
|
||||
if err := r.Unmarshal(data); err != nil {
|
||||
return 0
|
||||
}
|
||||
buf, err := r.Marshal()
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
if len(buf) == 0 {
|
||||
panic("zero buff") // nolint
|
||||
}
|
||||
var nr recordLayer
|
||||
if err = nr.Unmarshal(data); err != nil {
|
||||
panic(err) // nolint
|
||||
}
|
||||
if partialHeaderMismatch(nr.recordlayer.Header, r.recordlayer.Header) {
|
||||
panic( // nolint
|
||||
fmt.Sprintf("header mismatch: %+v != %+v",
|
||||
nr.recordlayer.Header, r.recordlayer.Header,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
171
vendor/github.com/pion/dtls/v2/handshake_cache.go
generated
vendored
Normal file
171
vendor/github.com/pion/dtls/v2/handshake_cache.go
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/crypto/prf"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/handshake"
|
||||
)
|
||||
|
||||
type handshakeCacheItem struct {
|
||||
typ handshake.Type
|
||||
isClient bool
|
||||
epoch uint16
|
||||
messageSequence uint16
|
||||
data []byte
|
||||
}
|
||||
|
||||
type handshakeCachePullRule struct {
|
||||
typ handshake.Type
|
||||
epoch uint16
|
||||
isClient bool
|
||||
optional bool
|
||||
}
|
||||
|
||||
type handshakeCache struct {
|
||||
cache []*handshakeCacheItem
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func newHandshakeCache() *handshakeCache {
|
||||
return &handshakeCache{}
|
||||
}
|
||||
|
||||
func (h *handshakeCache) push(data []byte, epoch, messageSequence uint16, typ handshake.Type, isClient bool) bool { //nolint
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
|
||||
for _, i := range h.cache {
|
||||
if i.messageSequence == messageSequence &&
|
||||
i.isClient == isClient {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
h.cache = append(h.cache, &handshakeCacheItem{
|
||||
data: append([]byte{}, data...),
|
||||
epoch: epoch,
|
||||
messageSequence: messageSequence,
|
||||
typ: typ,
|
||||
isClient: isClient,
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
// returns a list handshakes that match the requested rules
|
||||
// the list will contain null entries for rules that can't be satisfied
|
||||
// multiple entries may match a rule, but only the last match is returned (ie ClientHello with cookies)
|
||||
func (h *handshakeCache) pull(rules ...handshakeCachePullRule) []*handshakeCacheItem {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
|
||||
out := make([]*handshakeCacheItem, len(rules))
|
||||
for i, r := range rules {
|
||||
for _, c := range h.cache {
|
||||
if c.typ == r.typ && c.isClient == r.isClient && c.epoch == r.epoch {
|
||||
switch {
|
||||
case out[i] == nil:
|
||||
out[i] = c
|
||||
case out[i].messageSequence < c.messageSequence:
|
||||
out[i] = c
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// fullPullMap pulls all handshakes between rules[0] to rules[len(rules)-1] as map.
|
||||
func (h *handshakeCache) fullPullMap(startSeq int, rules ...handshakeCachePullRule) (int, map[handshake.Type]handshake.Message, bool) {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
|
||||
ci := make(map[handshake.Type]*handshakeCacheItem)
|
||||
for _, r := range rules {
|
||||
var item *handshakeCacheItem
|
||||
for _, c := range h.cache {
|
||||
if c.typ == r.typ && c.isClient == r.isClient && c.epoch == r.epoch {
|
||||
switch {
|
||||
case item == nil:
|
||||
item = c
|
||||
case item.messageSequence < c.messageSequence:
|
||||
item = c
|
||||
}
|
||||
}
|
||||
}
|
||||
if !r.optional && item == nil {
|
||||
// Missing mandatory message.
|
||||
return startSeq, nil, false
|
||||
}
|
||||
ci[r.typ] = item
|
||||
}
|
||||
out := make(map[handshake.Type]handshake.Message)
|
||||
seq := startSeq
|
||||
for _, r := range rules {
|
||||
t := r.typ
|
||||
i := ci[t]
|
||||
if i == nil {
|
||||
continue
|
||||
}
|
||||
rawHandshake := &handshake.Handshake{}
|
||||
if err := rawHandshake.Unmarshal(i.data); err != nil {
|
||||
return startSeq, nil, false
|
||||
}
|
||||
if uint16(seq) != rawHandshake.Header.MessageSequence {
|
||||
// There is a gap. Some messages are not arrived.
|
||||
return startSeq, nil, false
|
||||
}
|
||||
seq++
|
||||
out[t] = rawHandshake.Message
|
||||
}
|
||||
return seq, out, true
|
||||
}
|
||||
|
||||
// pullAndMerge calls pull and then merges the results, ignoring any null entries
|
||||
func (h *handshakeCache) pullAndMerge(rules ...handshakeCachePullRule) []byte {
|
||||
merged := []byte{}
|
||||
|
||||
for _, p := range h.pull(rules...) {
|
||||
if p != nil {
|
||||
merged = append(merged, p.data...)
|
||||
}
|
||||
}
|
||||
return merged
|
||||
}
|
||||
|
||||
// sessionHash returns the session hash for Extended Master Secret support
|
||||
// https://tools.ietf.org/html/draft-ietf-tls-session-hash-06#section-4
|
||||
func (h *handshakeCache) sessionHash(hf prf.HashFunc, epoch uint16, additional ...[]byte) ([]byte, error) {
|
||||
merged := []byte{}
|
||||
|
||||
// Order defined by https://tools.ietf.org/html/rfc5246#section-7.3
|
||||
handshakeBuffer := h.pull(
|
||||
handshakeCachePullRule{handshake.TypeClientHello, epoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeServerHello, epoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificate, epoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeServerKeyExchange, epoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificateRequest, epoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeServerHelloDone, epoch, false, false},
|
||||
handshakeCachePullRule{handshake.TypeCertificate, epoch, true, false},
|
||||
handshakeCachePullRule{handshake.TypeClientKeyExchange, epoch, true, false},
|
||||
)
|
||||
|
||||
for _, p := range handshakeBuffer {
|
||||
if p == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
merged = append(merged, p.data...)
|
||||
}
|
||||
for _, a := range additional {
|
||||
merged = append(merged, a...)
|
||||
}
|
||||
|
||||
hash := hf()
|
||||
if _, err := hash.Write(merged); err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
return hash.Sum(nil), nil
|
||||
}
|
||||
340
vendor/github.com/pion/dtls/v2/handshaker.go
generated
vendored
Normal file
340
vendor/github.com/pion/dtls/v2/handshaker.go
generated
vendored
Normal file
@@ -0,0 +1,340 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/crypto/signaturehash"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/alert"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/handshake"
|
||||
"github.com/pion/logging"
|
||||
)
|
||||
|
||||
// [RFC6347 Section-4.2.4]
|
||||
// +-----------+
|
||||
// +---> | PREPARING | <--------------------+
|
||||
// | +-----------+ |
|
||||
// | | |
|
||||
// | | Buffer next flight |
|
||||
// | | |
|
||||
// | \|/ |
|
||||
// | +-----------+ |
|
||||
// | | SENDING |<------------------+ | Send
|
||||
// | +-----------+ | | HelloRequest
|
||||
// Receive | | | |
|
||||
// next | | Send flight | | or
|
||||
// flight | +--------+ | |
|
||||
// | | | Set retransmit timer | | Receive
|
||||
// | | \|/ | | HelloRequest
|
||||
// | | +-----------+ | | Send
|
||||
// +--)--| WAITING |-------------------+ | ClientHello
|
||||
// | | +-----------+ Timer expires | |
|
||||
// | | | | |
|
||||
// | | +------------------------+ |
|
||||
// Receive | | Send Read retransmit |
|
||||
// last | | last |
|
||||
// flight | | flight |
|
||||
// | | |
|
||||
// \|/\|/ |
|
||||
// +-----------+ |
|
||||
// | FINISHED | -------------------------------+
|
||||
// +-----------+
|
||||
// | /|\
|
||||
// | |
|
||||
// +---+
|
||||
// Read retransmit
|
||||
// Retransmit last flight
|
||||
|
||||
type handshakeState uint8
|
||||
|
||||
const (
|
||||
handshakeErrored handshakeState = iota
|
||||
handshakePreparing
|
||||
handshakeSending
|
||||
handshakeWaiting
|
||||
handshakeFinished
|
||||
)
|
||||
|
||||
func (s handshakeState) String() string {
|
||||
switch s {
|
||||
case handshakeErrored:
|
||||
return "Errored"
|
||||
case handshakePreparing:
|
||||
return "Preparing"
|
||||
case handshakeSending:
|
||||
return "Sending"
|
||||
case handshakeWaiting:
|
||||
return "Waiting"
|
||||
case handshakeFinished:
|
||||
return "Finished"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
type handshakeFSM struct {
|
||||
currentFlight flightVal
|
||||
flights []*packet
|
||||
retransmit bool
|
||||
state *State
|
||||
cache *handshakeCache
|
||||
cfg *handshakeConfig
|
||||
closed chan struct{}
|
||||
}
|
||||
|
||||
type handshakeConfig struct {
|
||||
localPSKCallback PSKCallback
|
||||
localPSKIdentityHint []byte
|
||||
localCipherSuites []CipherSuite // Available CipherSuites
|
||||
localSignatureSchemes []signaturehash.Algorithm // Available signature schemes
|
||||
extendedMasterSecret ExtendedMasterSecretType // Policy for the Extended Master Support extension
|
||||
localSRTPProtectionProfiles []SRTPProtectionProfile // Available SRTPProtectionProfiles, if empty no SRTP support
|
||||
serverName string
|
||||
supportedProtocols []string
|
||||
clientAuth ClientAuthType // If we are a client should we request a client certificate
|
||||
localCertificates []tls.Certificate
|
||||
nameToCertificate map[string]*tls.Certificate
|
||||
insecureSkipVerify bool
|
||||
verifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
|
||||
sessionStore SessionStore
|
||||
rootCAs *x509.CertPool
|
||||
clientCAs *x509.CertPool
|
||||
retransmitInterval time.Duration
|
||||
customCipherSuites func() []CipherSuite
|
||||
|
||||
onFlightState func(flightVal, handshakeState)
|
||||
log logging.LeveledLogger
|
||||
keyLogWriter io.Writer
|
||||
|
||||
initialEpoch uint16
|
||||
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
type flightConn interface {
|
||||
notify(ctx context.Context, level alert.Level, desc alert.Description) error
|
||||
writePackets(context.Context, []*packet) error
|
||||
recvHandshake() <-chan chan struct{}
|
||||
setLocalEpoch(epoch uint16)
|
||||
handleQueuedPackets(context.Context) error
|
||||
sessionKey() []byte
|
||||
}
|
||||
|
||||
func (c *handshakeConfig) writeKeyLog(label string, clientRandom, secret []byte) {
|
||||
if c.keyLogWriter == nil {
|
||||
return
|
||||
}
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
_, err := c.keyLogWriter.Write([]byte(fmt.Sprintf("%s %x %x\n", label, clientRandom, secret)))
|
||||
if err != nil {
|
||||
c.log.Debugf("failed to write key log file: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func srvCliStr(isClient bool) string {
|
||||
if isClient {
|
||||
return "client"
|
||||
}
|
||||
return "server"
|
||||
}
|
||||
|
||||
func newHandshakeFSM(
|
||||
s *State, cache *handshakeCache, cfg *handshakeConfig,
|
||||
initialFlight flightVal,
|
||||
) *handshakeFSM {
|
||||
return &handshakeFSM{
|
||||
currentFlight: initialFlight,
|
||||
state: s,
|
||||
cache: cache,
|
||||
cfg: cfg,
|
||||
closed: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *handshakeFSM) Run(ctx context.Context, c flightConn, initialState handshakeState) error {
|
||||
state := initialState
|
||||
defer func() {
|
||||
close(s.closed)
|
||||
}()
|
||||
for {
|
||||
s.cfg.log.Tracef("[handshake:%s] %s: %s", srvCliStr(s.state.isClient), s.currentFlight.String(), state.String())
|
||||
if s.cfg.onFlightState != nil {
|
||||
s.cfg.onFlightState(s.currentFlight, state)
|
||||
}
|
||||
var err error
|
||||
switch state {
|
||||
case handshakePreparing:
|
||||
state, err = s.prepare(ctx, c)
|
||||
case handshakeSending:
|
||||
state, err = s.send(ctx, c)
|
||||
case handshakeWaiting:
|
||||
state, err = s.wait(ctx, c)
|
||||
case handshakeFinished:
|
||||
state, err = s.finish(ctx, c)
|
||||
default:
|
||||
return errInvalidFSMTransition
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *handshakeFSM) Done() <-chan struct{} {
|
||||
return s.closed
|
||||
}
|
||||
|
||||
func (s *handshakeFSM) prepare(ctx context.Context, c flightConn) (handshakeState, error) {
|
||||
s.flights = nil
|
||||
// Prepare flights
|
||||
var (
|
||||
a *alert.Alert
|
||||
err error
|
||||
pkts []*packet
|
||||
)
|
||||
gen, retransmit, errFlight := s.currentFlight.getFlightGenerator()
|
||||
if errFlight != nil {
|
||||
err = errFlight
|
||||
a = &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}
|
||||
} else {
|
||||
pkts, a, err = gen(c, s.state, s.cache, s.cfg)
|
||||
s.retransmit = retransmit
|
||||
}
|
||||
if a != nil {
|
||||
if alertErr := c.notify(ctx, a.Level, a.Description); alertErr != nil {
|
||||
if err != nil {
|
||||
err = alertErr
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return handshakeErrored, err
|
||||
}
|
||||
|
||||
s.flights = pkts
|
||||
epoch := s.cfg.initialEpoch
|
||||
nextEpoch := epoch
|
||||
for _, p := range s.flights {
|
||||
p.record.Header.Epoch += epoch
|
||||
if p.record.Header.Epoch > nextEpoch {
|
||||
nextEpoch = p.record.Header.Epoch
|
||||
}
|
||||
if h, ok := p.record.Content.(*handshake.Handshake); ok {
|
||||
h.Header.MessageSequence = uint16(s.state.handshakeSendSequence)
|
||||
s.state.handshakeSendSequence++
|
||||
}
|
||||
}
|
||||
if epoch != nextEpoch {
|
||||
s.cfg.log.Tracef("[handshake:%s] -> changeCipherSpec (epoch: %d)", srvCliStr(s.state.isClient), nextEpoch)
|
||||
c.setLocalEpoch(nextEpoch)
|
||||
}
|
||||
return handshakeSending, nil
|
||||
}
|
||||
|
||||
func (s *handshakeFSM) send(ctx context.Context, c flightConn) (handshakeState, error) {
|
||||
// Send flights
|
||||
if err := c.writePackets(ctx, s.flights); err != nil {
|
||||
return handshakeErrored, err
|
||||
}
|
||||
|
||||
if s.currentFlight.isLastSendFlight() {
|
||||
return handshakeFinished, nil
|
||||
}
|
||||
return handshakeWaiting, nil
|
||||
}
|
||||
|
||||
func (s *handshakeFSM) wait(ctx context.Context, c flightConn) (handshakeState, error) { //nolint:gocognit
|
||||
parse, errFlight := s.currentFlight.getFlightParser()
|
||||
if errFlight != nil {
|
||||
if alertErr := c.notify(ctx, alert.Fatal, alert.InternalError); alertErr != nil {
|
||||
if errFlight != nil {
|
||||
return handshakeErrored, alertErr
|
||||
}
|
||||
}
|
||||
return handshakeErrored, errFlight
|
||||
}
|
||||
|
||||
retransmitTimer := time.NewTimer(s.cfg.retransmitInterval)
|
||||
for {
|
||||
select {
|
||||
case done := <-c.recvHandshake():
|
||||
nextFlight, alert, err := parse(ctx, c, s.state, s.cache, s.cfg)
|
||||
close(done)
|
||||
if alert != nil {
|
||||
if alertErr := c.notify(ctx, alert.Level, alert.Description); alertErr != nil {
|
||||
if err != nil {
|
||||
err = alertErr
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return handshakeErrored, err
|
||||
}
|
||||
if nextFlight == 0 {
|
||||
break
|
||||
}
|
||||
s.cfg.log.Tracef("[handshake:%s] %s -> %s", srvCliStr(s.state.isClient), s.currentFlight.String(), nextFlight.String())
|
||||
if nextFlight.isLastRecvFlight() && s.currentFlight == nextFlight {
|
||||
return handshakeFinished, nil
|
||||
}
|
||||
s.currentFlight = nextFlight
|
||||
return handshakePreparing, nil
|
||||
|
||||
case <-retransmitTimer.C:
|
||||
if !s.retransmit {
|
||||
return handshakeWaiting, nil
|
||||
}
|
||||
return handshakeSending, nil
|
||||
case <-ctx.Done():
|
||||
return handshakeErrored, ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *handshakeFSM) finish(ctx context.Context, c flightConn) (handshakeState, error) {
|
||||
parse, errFlight := s.currentFlight.getFlightParser()
|
||||
if errFlight != nil {
|
||||
if alertErr := c.notify(ctx, alert.Fatal, alert.InternalError); alertErr != nil {
|
||||
if errFlight != nil {
|
||||
return handshakeErrored, alertErr
|
||||
}
|
||||
}
|
||||
return handshakeErrored, errFlight
|
||||
}
|
||||
|
||||
retransmitTimer := time.NewTimer(s.cfg.retransmitInterval)
|
||||
select {
|
||||
case done := <-c.recvHandshake():
|
||||
nextFlight, alert, err := parse(ctx, c, s.state, s.cache, s.cfg)
|
||||
close(done)
|
||||
if alert != nil {
|
||||
if alertErr := c.notify(ctx, alert.Level, alert.Description); alertErr != nil {
|
||||
if err != nil {
|
||||
err = alertErr
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return handshakeErrored, err
|
||||
}
|
||||
if nextFlight == 0 {
|
||||
break
|
||||
}
|
||||
if nextFlight.isLastRecvFlight() && s.currentFlight == nextFlight {
|
||||
return handshakeFinished, nil
|
||||
}
|
||||
<-retransmitTimer.C
|
||||
// Retransmit last flight
|
||||
return handshakeSending, nil
|
||||
|
||||
case <-ctx.Done():
|
||||
return handshakeErrored, ctx.Err()
|
||||
}
|
||||
return handshakeFinished, nil
|
||||
}
|
||||
108
vendor/github.com/pion/dtls/v2/internal/ciphersuite/aes_128_ccm.go
generated
vendored
Normal file
108
vendor/github.com/pion/dtls/v2/internal/ciphersuite/aes_128_ccm.go
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
package ciphersuite
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"hash"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/crypto/ciphersuite"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/prf"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
|
||||
)
|
||||
|
||||
// Aes128Ccm is a base class used by multiple AES-CCM Ciphers
|
||||
type Aes128Ccm struct {
|
||||
ccm atomic.Value // *cryptoCCM
|
||||
clientCertificateType clientcertificate.Type
|
||||
id ID
|
||||
psk bool
|
||||
cryptoCCMTagLen ciphersuite.CCMTagLen
|
||||
}
|
||||
|
||||
func newAes128Ccm(clientCertificateType clientcertificate.Type, id ID, psk bool, cryptoCCMTagLen ciphersuite.CCMTagLen) *Aes128Ccm {
|
||||
return &Aes128Ccm{
|
||||
clientCertificateType: clientCertificateType,
|
||||
id: id,
|
||||
psk: psk,
|
||||
cryptoCCMTagLen: cryptoCCMTagLen,
|
||||
}
|
||||
}
|
||||
|
||||
// CertificateType returns what type of certificate this CipherSuite exchanges
|
||||
func (c *Aes128Ccm) CertificateType() clientcertificate.Type {
|
||||
return c.clientCertificateType
|
||||
}
|
||||
|
||||
// ID returns the ID of the CipherSuite
|
||||
func (c *Aes128Ccm) ID() ID {
|
||||
return c.id
|
||||
}
|
||||
|
||||
func (c *Aes128Ccm) String() string {
|
||||
return c.id.String()
|
||||
}
|
||||
|
||||
// HashFunc returns the hashing func for this CipherSuite
|
||||
func (c *Aes128Ccm) HashFunc() func() hash.Hash {
|
||||
return sha256.New
|
||||
}
|
||||
|
||||
// AuthenticationType controls what authentication method is using during the handshake
|
||||
func (c *Aes128Ccm) AuthenticationType() AuthenticationType {
|
||||
if c.psk {
|
||||
return AuthenticationTypePreSharedKey
|
||||
}
|
||||
return AuthenticationTypeCertificate
|
||||
}
|
||||
|
||||
// IsInitialized returns if the CipherSuite has keying material and can
|
||||
// encrypt/decrypt packets
|
||||
func (c *Aes128Ccm) IsInitialized() bool {
|
||||
return c.ccm.Load() != nil
|
||||
}
|
||||
|
||||
// Init initializes the internal Cipher with keying material
|
||||
func (c *Aes128Ccm) Init(masterSecret, clientRandom, serverRandom []byte, isClient bool) error {
|
||||
const (
|
||||
prfMacLen = 0
|
||||
prfKeyLen = 16
|
||||
prfIvLen = 4
|
||||
)
|
||||
|
||||
keys, err := prf.GenerateEncryptionKeys(masterSecret, clientRandom, serverRandom, prfMacLen, prfKeyLen, prfIvLen, c.HashFunc())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var ccm *ciphersuite.CCM
|
||||
if isClient {
|
||||
ccm, err = ciphersuite.NewCCM(c.cryptoCCMTagLen, keys.ClientWriteKey, keys.ClientWriteIV, keys.ServerWriteKey, keys.ServerWriteIV)
|
||||
} else {
|
||||
ccm, err = ciphersuite.NewCCM(c.cryptoCCMTagLen, keys.ServerWriteKey, keys.ServerWriteIV, keys.ClientWriteKey, keys.ClientWriteIV)
|
||||
}
|
||||
c.ccm.Store(ccm)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Encrypt encrypts a single TLS RecordLayer
|
||||
func (c *Aes128Ccm) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error) {
|
||||
ccm := c.ccm.Load()
|
||||
if ccm == nil {
|
||||
return nil, fmt.Errorf("%w, unable to encrypt", errCipherSuiteNotInit)
|
||||
}
|
||||
|
||||
return ccm.(*ciphersuite.CCM).Encrypt(pkt, raw)
|
||||
}
|
||||
|
||||
// Decrypt decrypts a single TLS RecordLayer
|
||||
func (c *Aes128Ccm) Decrypt(raw []byte) ([]byte, error) {
|
||||
ccm := c.ccm.Load()
|
||||
if ccm == nil {
|
||||
return nil, fmt.Errorf("%w, unable to decrypt", errCipherSuiteNotInit)
|
||||
}
|
||||
|
||||
return ccm.(*ciphersuite.CCM).Decrypt(raw)
|
||||
}
|
||||
77
vendor/github.com/pion/dtls/v2/internal/ciphersuite/ciphersuite.go
generated
vendored
Normal file
77
vendor/github.com/pion/dtls/v2/internal/ciphersuite/ciphersuite.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
// Package ciphersuite provides TLS Ciphers as registered with the IANA https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4
|
||||
package ciphersuite
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/protocol"
|
||||
)
|
||||
|
||||
var errCipherSuiteNotInit = &protocol.TemporaryError{Err: errors.New("CipherSuite has not been initialized")} //nolint:goerr113
|
||||
|
||||
// ID is an ID for our supported CipherSuites
|
||||
type ID uint16
|
||||
|
||||
func (i ID) String() string {
|
||||
switch i {
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
|
||||
return "TLS_ECDHE_ECDSA_WITH_AES_128_CCM"
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
|
||||
return "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8"
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
|
||||
return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
|
||||
case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
|
||||
return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
|
||||
return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"
|
||||
case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
|
||||
return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"
|
||||
case TLS_PSK_WITH_AES_128_CCM:
|
||||
return "TLS_PSK_WITH_AES_128_CCM"
|
||||
case TLS_PSK_WITH_AES_128_CCM_8:
|
||||
return "TLS_PSK_WITH_AES_128_CCM_8"
|
||||
case TLS_PSK_WITH_AES_128_GCM_SHA256:
|
||||
return "TLS_PSK_WITH_AES_128_GCM_SHA256"
|
||||
case TLS_PSK_WITH_AES_128_CBC_SHA256:
|
||||
return "TLS_PSK_WITH_AES_128_CBC_SHA256"
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
|
||||
return "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
|
||||
case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
|
||||
return "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
|
||||
default:
|
||||
return fmt.Sprintf("unknown(%v)", uint16(i))
|
||||
}
|
||||
}
|
||||
|
||||
// Supported Cipher Suites
|
||||
const (
|
||||
// AES-128-CCM
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_CCM ID = 0xc0ac //nolint:golint,stylecheck
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 ID = 0xc0ae //nolint:golint,stylecheck
|
||||
|
||||
// AES-128-GCM-SHA256
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 ID = 0xc02b //nolint:golint,stylecheck
|
||||
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ID = 0xc02f //nolint:golint,stylecheck
|
||||
|
||||
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 ID = 0xc02c //nolint:golint,stylecheck
|
||||
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ID = 0xc030 //nolint:golint,stylecheck
|
||||
// AES-256-CBC-SHA
|
||||
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA ID = 0xc00a //nolint:golint,stylecheck
|
||||
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA ID = 0xc014 //nolint:golint,stylecheck
|
||||
|
||||
TLS_PSK_WITH_AES_128_CCM ID = 0xc0a4 //nolint:golint,stylecheck
|
||||
TLS_PSK_WITH_AES_128_CCM_8 ID = 0xc0a8 //nolint:golint,stylecheck
|
||||
TLS_PSK_WITH_AES_128_GCM_SHA256 ID = 0x00a8 //nolint:golint,stylecheck
|
||||
TLS_PSK_WITH_AES_128_CBC_SHA256 ID = 0x00ae //nolint:golint,stylecheck
|
||||
)
|
||||
|
||||
// AuthenticationType controls what authentication method is using during the handshake
|
||||
type AuthenticationType int
|
||||
|
||||
// AuthenticationType Enums
|
||||
const (
|
||||
AuthenticationTypeCertificate AuthenticationType = iota + 1
|
||||
AuthenticationTypePreSharedKey
|
||||
AuthenticationTypeAnonymous
|
||||
)
|
||||
11
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_ccm.go
generated
vendored
Normal file
11
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_ccm.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package ciphersuite
|
||||
|
||||
import (
|
||||
"github.com/pion/dtls/v2/pkg/crypto/ciphersuite"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
|
||||
)
|
||||
|
||||
// NewTLSEcdheEcdsaWithAes128Ccm constructs a TLS_ECDHE_ECDSA_WITH_AES_128_CCM Cipher
|
||||
func NewTLSEcdheEcdsaWithAes128Ccm() *Aes128Ccm {
|
||||
return newAes128Ccm(clientcertificate.ECDSASign, TLS_ECDHE_ECDSA_WITH_AES_128_CCM, false, ciphersuite.CCMTagLength)
|
||||
}
|
||||
11
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_ccm8.go
generated
vendored
Normal file
11
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_ccm8.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package ciphersuite
|
||||
|
||||
import (
|
||||
"github.com/pion/dtls/v2/pkg/crypto/ciphersuite"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
|
||||
)
|
||||
|
||||
// NewTLSEcdheEcdsaWithAes128Ccm8 creates a new TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 CipherSuite
|
||||
func NewTLSEcdheEcdsaWithAes128Ccm8() *Aes128Ccm {
|
||||
return newAes128Ccm(clientcertificate.ECDSASign, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, false, ciphersuite.CCMTagLength8)
|
||||
}
|
||||
95
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_gcm_sha256.go
generated
vendored
Normal file
95
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_gcm_sha256.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
package ciphersuite
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"hash"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/crypto/ciphersuite"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/prf"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
|
||||
)
|
||||
|
||||
// TLSEcdheEcdsaWithAes128GcmSha256 represents a TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 CipherSuite
|
||||
type TLSEcdheEcdsaWithAes128GcmSha256 struct {
|
||||
gcm atomic.Value // *cryptoGCM
|
||||
}
|
||||
|
||||
// CertificateType returns what type of certficate this CipherSuite exchanges
|
||||
func (c *TLSEcdheEcdsaWithAes128GcmSha256) CertificateType() clientcertificate.Type {
|
||||
return clientcertificate.ECDSASign
|
||||
}
|
||||
|
||||
// ID returns the ID of the CipherSuite
|
||||
func (c *TLSEcdheEcdsaWithAes128GcmSha256) ID() ID {
|
||||
return TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
}
|
||||
|
||||
func (c *TLSEcdheEcdsaWithAes128GcmSha256) String() string {
|
||||
return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
|
||||
}
|
||||
|
||||
// HashFunc returns the hashing func for this CipherSuite
|
||||
func (c *TLSEcdheEcdsaWithAes128GcmSha256) HashFunc() func() hash.Hash {
|
||||
return sha256.New
|
||||
}
|
||||
|
||||
// AuthenticationType controls what authentication method is using during the handshake
|
||||
func (c *TLSEcdheEcdsaWithAes128GcmSha256) AuthenticationType() AuthenticationType {
|
||||
return AuthenticationTypeCertificate
|
||||
}
|
||||
|
||||
// IsInitialized returns if the CipherSuite has keying material and can
|
||||
// encrypt/decrypt packets
|
||||
func (c *TLSEcdheEcdsaWithAes128GcmSha256) IsInitialized() bool {
|
||||
return c.gcm.Load() != nil
|
||||
}
|
||||
|
||||
func (c *TLSEcdheEcdsaWithAes128GcmSha256) init(masterSecret, clientRandom, serverRandom []byte, isClient bool, prfMacLen, prfKeyLen, prfIvLen int, hashFunc func() hash.Hash) error {
|
||||
keys, err := prf.GenerateEncryptionKeys(masterSecret, clientRandom, serverRandom, prfMacLen, prfKeyLen, prfIvLen, hashFunc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var gcm *ciphersuite.GCM
|
||||
if isClient {
|
||||
gcm, err = ciphersuite.NewGCM(keys.ClientWriteKey, keys.ClientWriteIV, keys.ServerWriteKey, keys.ServerWriteIV)
|
||||
} else {
|
||||
gcm, err = ciphersuite.NewGCM(keys.ServerWriteKey, keys.ServerWriteIV, keys.ClientWriteKey, keys.ClientWriteIV)
|
||||
}
|
||||
c.gcm.Store(gcm)
|
||||
return err
|
||||
}
|
||||
|
||||
// Init initializes the internal Cipher with keying material
|
||||
func (c *TLSEcdheEcdsaWithAes128GcmSha256) Init(masterSecret, clientRandom, serverRandom []byte, isClient bool) error {
|
||||
const (
|
||||
prfMacLen = 0
|
||||
prfKeyLen = 16
|
||||
prfIvLen = 4
|
||||
)
|
||||
|
||||
return c.init(masterSecret, clientRandom, serverRandom, isClient, prfMacLen, prfKeyLen, prfIvLen, c.HashFunc())
|
||||
}
|
||||
|
||||
// Encrypt encrypts a single TLS RecordLayer
|
||||
func (c *TLSEcdheEcdsaWithAes128GcmSha256) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error) {
|
||||
gcm := c.gcm.Load()
|
||||
if gcm == nil {
|
||||
return nil, fmt.Errorf("%w, unable to encrypt", errCipherSuiteNotInit)
|
||||
}
|
||||
|
||||
return gcm.(*ciphersuite.GCM).Encrypt(pkt, raw)
|
||||
}
|
||||
|
||||
// Decrypt decrypts a single TLS RecordLayer
|
||||
func (c *TLSEcdheEcdsaWithAes128GcmSha256) Decrypt(raw []byte) ([]byte, error) {
|
||||
gcm := c.gcm.Load()
|
||||
if gcm == nil {
|
||||
return nil, fmt.Errorf("%w, unable to decrypt", errCipherSuiteNotInit)
|
||||
}
|
||||
|
||||
return gcm.(*ciphersuite.GCM).Decrypt(raw)
|
||||
}
|
||||
101
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_256_cbc_sha.go
generated
vendored
Normal file
101
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_256_cbc_sha.go
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
package ciphersuite
|
||||
|
||||
import (
|
||||
"crypto/sha1" //nolint: gosec,gci
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"hash"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/crypto/ciphersuite"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/prf"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
|
||||
)
|
||||
|
||||
// TLSEcdheEcdsaWithAes256CbcSha represents a TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA CipherSuite
|
||||
type TLSEcdheEcdsaWithAes256CbcSha struct {
|
||||
cbc atomic.Value // *cryptoCBC
|
||||
}
|
||||
|
||||
// CertificateType returns what type of certficate this CipherSuite exchanges
|
||||
func (c *TLSEcdheEcdsaWithAes256CbcSha) CertificateType() clientcertificate.Type {
|
||||
return clientcertificate.ECDSASign
|
||||
}
|
||||
|
||||
// ID returns the ID of the CipherSuite
|
||||
func (c *TLSEcdheEcdsaWithAes256CbcSha) ID() ID {
|
||||
return TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
|
||||
}
|
||||
|
||||
func (c *TLSEcdheEcdsaWithAes256CbcSha) String() string {
|
||||
return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"
|
||||
}
|
||||
|
||||
// HashFunc returns the hashing func for this CipherSuite
|
||||
func (c *TLSEcdheEcdsaWithAes256CbcSha) HashFunc() func() hash.Hash {
|
||||
return sha256.New
|
||||
}
|
||||
|
||||
// AuthenticationType controls what authentication method is using during the handshake
|
||||
func (c *TLSEcdheEcdsaWithAes256CbcSha) AuthenticationType() AuthenticationType {
|
||||
return AuthenticationTypeCertificate
|
||||
}
|
||||
|
||||
// IsInitialized returns if the CipherSuite has keying material and can
|
||||
// encrypt/decrypt packets
|
||||
func (c *TLSEcdheEcdsaWithAes256CbcSha) IsInitialized() bool {
|
||||
return c.cbc.Load() != nil
|
||||
}
|
||||
|
||||
// Init initializes the internal Cipher with keying material
|
||||
func (c *TLSEcdheEcdsaWithAes256CbcSha) Init(masterSecret, clientRandom, serverRandom []byte, isClient bool) error {
|
||||
const (
|
||||
prfMacLen = 20
|
||||
prfKeyLen = 32
|
||||
prfIvLen = 16
|
||||
)
|
||||
|
||||
keys, err := prf.GenerateEncryptionKeys(masterSecret, clientRandom, serverRandom, prfMacLen, prfKeyLen, prfIvLen, c.HashFunc())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var cbc *ciphersuite.CBC
|
||||
if isClient {
|
||||
cbc, err = ciphersuite.NewCBC(
|
||||
keys.ClientWriteKey, keys.ClientWriteIV, keys.ClientMACKey,
|
||||
keys.ServerWriteKey, keys.ServerWriteIV, keys.ServerMACKey,
|
||||
sha1.New,
|
||||
)
|
||||
} else {
|
||||
cbc, err = ciphersuite.NewCBC(
|
||||
keys.ServerWriteKey, keys.ServerWriteIV, keys.ServerMACKey,
|
||||
keys.ClientWriteKey, keys.ClientWriteIV, keys.ClientMACKey,
|
||||
sha1.New,
|
||||
)
|
||||
}
|
||||
c.cbc.Store(cbc)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Encrypt encrypts a single TLS RecordLayer
|
||||
func (c *TLSEcdheEcdsaWithAes256CbcSha) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error) {
|
||||
cbc := c.cbc.Load()
|
||||
if cbc == nil { // !c.isInitialized()
|
||||
return nil, fmt.Errorf("%w, unable to encrypt", errCipherSuiteNotInit)
|
||||
}
|
||||
|
||||
return cbc.(*ciphersuite.CBC).Encrypt(pkt, raw)
|
||||
}
|
||||
|
||||
// Decrypt decrypts a single TLS RecordLayer
|
||||
func (c *TLSEcdheEcdsaWithAes256CbcSha) Decrypt(raw []byte) ([]byte, error) {
|
||||
cbc := c.cbc.Load()
|
||||
if cbc == nil { // !c.isInitialized()
|
||||
return nil, fmt.Errorf("%w, unable to decrypt", errCipherSuiteNotInit)
|
||||
}
|
||||
|
||||
return cbc.(*ciphersuite.CBC).Decrypt(raw)
|
||||
}
|
||||
36
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_256_gcm_sha384.go
generated
vendored
Normal file
36
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_256_gcm_sha384.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package ciphersuite
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// TLSEcdheEcdsaWithAes256GcmSha384 represents a TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 CipherSuite
|
||||
type TLSEcdheEcdsaWithAes256GcmSha384 struct {
|
||||
TLSEcdheEcdsaWithAes128GcmSha256
|
||||
}
|
||||
|
||||
// ID returns the ID of the CipherSuite
|
||||
func (c *TLSEcdheEcdsaWithAes256GcmSha384) ID() ID {
|
||||
return TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
|
||||
}
|
||||
|
||||
func (c *TLSEcdheEcdsaWithAes256GcmSha384) String() string {
|
||||
return "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
|
||||
}
|
||||
|
||||
// HashFunc returns the hashing func for this CipherSuite
|
||||
func (c *TLSEcdheEcdsaWithAes256GcmSha384) HashFunc() func() hash.Hash {
|
||||
return sha512.New384
|
||||
}
|
||||
|
||||
// Init initializes the internal Cipher with keying material
|
||||
func (c *TLSEcdheEcdsaWithAes256GcmSha384) Init(masterSecret, clientRandom, serverRandom []byte, isClient bool) error {
|
||||
const (
|
||||
prfMacLen = 0
|
||||
prfKeyLen = 32
|
||||
prfIvLen = 4
|
||||
)
|
||||
|
||||
return c.init(masterSecret, clientRandom, serverRandom, isClient, prfMacLen, prfKeyLen, prfIvLen, c.HashFunc())
|
||||
}
|
||||
22
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_rsa_with_aes_128_gcm_sha256.go
generated
vendored
Normal file
22
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_rsa_with_aes_128_gcm_sha256.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package ciphersuite
|
||||
|
||||
import "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
|
||||
|
||||
// TLSEcdheRsaWithAes128GcmSha256 implements the TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 CipherSuite
|
||||
type TLSEcdheRsaWithAes128GcmSha256 struct {
|
||||
TLSEcdheEcdsaWithAes128GcmSha256
|
||||
}
|
||||
|
||||
// CertificateType returns what type of certificate this CipherSuite exchanges
|
||||
func (c *TLSEcdheRsaWithAes128GcmSha256) CertificateType() clientcertificate.Type {
|
||||
return clientcertificate.RSASign
|
||||
}
|
||||
|
||||
// ID returns the ID of the CipherSuite
|
||||
func (c *TLSEcdheRsaWithAes128GcmSha256) ID() ID {
|
||||
return TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
}
|
||||
|
||||
func (c *TLSEcdheRsaWithAes128GcmSha256) String() string {
|
||||
return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||
}
|
||||
22
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_rsa_with_aes_256_cbc_sha.go
generated
vendored
Normal file
22
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_rsa_with_aes_256_cbc_sha.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package ciphersuite
|
||||
|
||||
import "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
|
||||
|
||||
// TLSEcdheRsaWithAes256CbcSha implements the TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA CipherSuite
|
||||
type TLSEcdheRsaWithAes256CbcSha struct {
|
||||
TLSEcdheEcdsaWithAes256CbcSha
|
||||
}
|
||||
|
||||
// CertificateType returns what type of certificate this CipherSuite exchanges
|
||||
func (c *TLSEcdheRsaWithAes256CbcSha) CertificateType() clientcertificate.Type {
|
||||
return clientcertificate.RSASign
|
||||
}
|
||||
|
||||
// ID returns the ID of the CipherSuite
|
||||
func (c *TLSEcdheRsaWithAes256CbcSha) ID() ID {
|
||||
return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
|
||||
}
|
||||
|
||||
func (c *TLSEcdheRsaWithAes256CbcSha) String() string {
|
||||
return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"
|
||||
}
|
||||
22
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_rsa_with_aes_256_gcm_sha384.go
generated
vendored
Normal file
22
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_ecdhe_rsa_with_aes_256_gcm_sha384.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package ciphersuite
|
||||
|
||||
import "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
|
||||
|
||||
// TLSEcdheRsaWithAes256GcmSha384 implements the TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 CipherSuite
|
||||
type TLSEcdheRsaWithAes256GcmSha384 struct {
|
||||
TLSEcdheEcdsaWithAes256GcmSha384
|
||||
}
|
||||
|
||||
// CertificateType returns what type of certificate this CipherSuite exchanges
|
||||
func (c *TLSEcdheRsaWithAes256GcmSha384) CertificateType() clientcertificate.Type {
|
||||
return clientcertificate.RSASign
|
||||
}
|
||||
|
||||
// ID returns the ID of the CipherSuite
|
||||
func (c *TLSEcdheRsaWithAes256GcmSha384) ID() ID {
|
||||
return TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
||||
}
|
||||
|
||||
func (c *TLSEcdheRsaWithAes256GcmSha384) String() string {
|
||||
return "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
|
||||
}
|
||||
100
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_cbc_sha256.go
generated
vendored
Normal file
100
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_cbc_sha256.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
package ciphersuite
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"hash"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/crypto/ciphersuite"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/prf"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
|
||||
)
|
||||
|
||||
// TLSPskWithAes128CbcSha256 implements the TLS_PSK_WITH_AES_128_CBC_SHA256 CipherSuite
|
||||
type TLSPskWithAes128CbcSha256 struct {
|
||||
cbc atomic.Value // *cryptoCBC
|
||||
}
|
||||
|
||||
// CertificateType returns what type of certificate this CipherSuite exchanges
|
||||
func (c *TLSPskWithAes128CbcSha256) CertificateType() clientcertificate.Type {
|
||||
return clientcertificate.Type(0)
|
||||
}
|
||||
|
||||
// ID returns the ID of the CipherSuite
|
||||
func (c *TLSPskWithAes128CbcSha256) ID() ID {
|
||||
return TLS_PSK_WITH_AES_128_CBC_SHA256
|
||||
}
|
||||
|
||||
func (c *TLSPskWithAes128CbcSha256) String() string {
|
||||
return "TLS_PSK_WITH_AES_128_CBC_SHA256"
|
||||
}
|
||||
|
||||
// HashFunc returns the hashing func for this CipherSuite
|
||||
func (c *TLSPskWithAes128CbcSha256) HashFunc() func() hash.Hash {
|
||||
return sha256.New
|
||||
}
|
||||
|
||||
// AuthenticationType controls what authentication method is using during the handshake
|
||||
func (c *TLSPskWithAes128CbcSha256) AuthenticationType() AuthenticationType {
|
||||
return AuthenticationTypePreSharedKey
|
||||
}
|
||||
|
||||
// IsInitialized returns if the CipherSuite has keying material and can
|
||||
// encrypt/decrypt packets
|
||||
func (c *TLSPskWithAes128CbcSha256) IsInitialized() bool {
|
||||
return c.cbc.Load() != nil
|
||||
}
|
||||
|
||||
// Init initializes the internal Cipher with keying material
|
||||
func (c *TLSPskWithAes128CbcSha256) Init(masterSecret, clientRandom, serverRandom []byte, isClient bool) error {
|
||||
const (
|
||||
prfMacLen = 32
|
||||
prfKeyLen = 16
|
||||
prfIvLen = 16
|
||||
)
|
||||
|
||||
keys, err := prf.GenerateEncryptionKeys(masterSecret, clientRandom, serverRandom, prfMacLen, prfKeyLen, prfIvLen, c.HashFunc())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var cbc *ciphersuite.CBC
|
||||
if isClient {
|
||||
cbc, err = ciphersuite.NewCBC(
|
||||
keys.ClientWriteKey, keys.ClientWriteIV, keys.ClientMACKey,
|
||||
keys.ServerWriteKey, keys.ServerWriteIV, keys.ServerMACKey,
|
||||
c.HashFunc(),
|
||||
)
|
||||
} else {
|
||||
cbc, err = ciphersuite.NewCBC(
|
||||
keys.ServerWriteKey, keys.ServerWriteIV, keys.ServerMACKey,
|
||||
keys.ClientWriteKey, keys.ClientWriteIV, keys.ClientMACKey,
|
||||
c.HashFunc(),
|
||||
)
|
||||
}
|
||||
c.cbc.Store(cbc)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Encrypt encrypts a single TLS RecordLayer
|
||||
func (c *TLSPskWithAes128CbcSha256) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error) {
|
||||
cbc := c.cbc.Load()
|
||||
if cbc == nil { // !c.isInitialized()
|
||||
return nil, fmt.Errorf("%w, unable to decrypt", errCipherSuiteNotInit)
|
||||
}
|
||||
|
||||
return cbc.(*ciphersuite.CBC).Encrypt(pkt, raw)
|
||||
}
|
||||
|
||||
// Decrypt decrypts a single TLS RecordLayer
|
||||
func (c *TLSPskWithAes128CbcSha256) Decrypt(raw []byte) ([]byte, error) {
|
||||
cbc := c.cbc.Load()
|
||||
if cbc == nil { // !c.isInitialized()
|
||||
return nil, fmt.Errorf("%w, unable to decrypt", errCipherSuiteNotInit)
|
||||
}
|
||||
|
||||
return cbc.(*ciphersuite.CBC).Decrypt(raw)
|
||||
}
|
||||
11
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_ccm.go
generated
vendored
Normal file
11
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_ccm.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package ciphersuite
|
||||
|
||||
import (
|
||||
"github.com/pion/dtls/v2/pkg/crypto/ciphersuite"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
|
||||
)
|
||||
|
||||
// NewTLSPskWithAes128Ccm returns the TLS_PSK_WITH_AES_128_CCM CipherSuite
|
||||
func NewTLSPskWithAes128Ccm() *Aes128Ccm {
|
||||
return newAes128Ccm(clientcertificate.Type(0), TLS_PSK_WITH_AES_128_CCM, true, ciphersuite.CCMTagLength)
|
||||
}
|
||||
11
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_ccm8.go
generated
vendored
Normal file
11
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_ccm8.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package ciphersuite
|
||||
|
||||
import (
|
||||
"github.com/pion/dtls/v2/pkg/crypto/ciphersuite"
|
||||
"github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
|
||||
)
|
||||
|
||||
// NewTLSPskWithAes128Ccm8 returns the TLS_PSK_WITH_AES_128_CCM_8 CipherSuite
|
||||
func NewTLSPskWithAes128Ccm8() *Aes128Ccm {
|
||||
return newAes128Ccm(clientcertificate.Type(0), TLS_PSK_WITH_AES_128_CCM_8, true, ciphersuite.CCMTagLength8)
|
||||
}
|
||||
27
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_gcm_sha256.go
generated
vendored
Normal file
27
vendor/github.com/pion/dtls/v2/internal/ciphersuite/tls_psk_with_aes_128_gcm_sha256.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
package ciphersuite
|
||||
|
||||
import "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
|
||||
|
||||
// TLSPskWithAes128GcmSha256 implements the TLS_PSK_WITH_AES_128_GCM_SHA256 CipherSuite
|
||||
type TLSPskWithAes128GcmSha256 struct {
|
||||
TLSEcdheEcdsaWithAes128GcmSha256
|
||||
}
|
||||
|
||||
// CertificateType returns what type of certificate this CipherSuite exchanges
|
||||
func (c *TLSPskWithAes128GcmSha256) CertificateType() clientcertificate.Type {
|
||||
return clientcertificate.Type(0)
|
||||
}
|
||||
|
||||
// ID returns the ID of the CipherSuite
|
||||
func (c *TLSPskWithAes128GcmSha256) ID() ID {
|
||||
return TLS_PSK_WITH_AES_128_GCM_SHA256
|
||||
}
|
||||
|
||||
func (c *TLSPskWithAes128GcmSha256) String() string {
|
||||
return "TLS_PSK_WITH_AES_128_GCM_SHA256"
|
||||
}
|
||||
|
||||
// AuthenticationType controls what authentication method is using during the handshake
|
||||
func (c *TLSPskWithAes128GcmSha256) AuthenticationType() AuthenticationType {
|
||||
return AuthenticationTypePreSharedKey
|
||||
}
|
||||
45
vendor/github.com/pion/dtls/v2/internal/closer/closer.go
generated
vendored
Normal file
45
vendor/github.com/pion/dtls/v2/internal/closer/closer.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
// Package closer provides signaling channel for shutdown
|
||||
package closer
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// Closer allows for each signaling a channel for shutdown
|
||||
type Closer struct {
|
||||
ctx context.Context
|
||||
closeFunc func()
|
||||
}
|
||||
|
||||
// NewCloser creates a new instance of Closer
|
||||
func NewCloser() *Closer {
|
||||
ctx, closeFunc := context.WithCancel(context.Background())
|
||||
return &Closer{
|
||||
ctx: ctx,
|
||||
closeFunc: closeFunc,
|
||||
}
|
||||
}
|
||||
|
||||
// NewCloserWithParent creates a new instance of Closer with a parent context
|
||||
func NewCloserWithParent(ctx context.Context) *Closer {
|
||||
ctx, closeFunc := context.WithCancel(ctx)
|
||||
return &Closer{
|
||||
ctx: ctx,
|
||||
closeFunc: closeFunc,
|
||||
}
|
||||
}
|
||||
|
||||
// Done returns a channel signaling when it is done
|
||||
func (c *Closer) Done() <-chan struct{} {
|
||||
return c.ctx.Done()
|
||||
}
|
||||
|
||||
// Err returns an error of the context
|
||||
func (c *Closer) Err() error {
|
||||
return c.ctx.Err()
|
||||
}
|
||||
|
||||
// Close sends a signal to trigger the ctx done channel
|
||||
func (c *Closer) Close() {
|
||||
c.closeFunc()
|
||||
}
|
||||
39
vendor/github.com/pion/dtls/v2/internal/util/util.go
generated
vendored
Normal file
39
vendor/github.com/pion/dtls/v2/internal/util/util.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
// Package util contains small helpers used across the repo
|
||||
package util
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// BigEndianUint24 returns the value of a big endian uint24
|
||||
func BigEndianUint24(raw []byte) uint32 {
|
||||
if len(raw) < 3 {
|
||||
return 0
|
||||
}
|
||||
|
||||
rawCopy := make([]byte, 4)
|
||||
copy(rawCopy[1:], raw)
|
||||
return binary.BigEndian.Uint32(rawCopy)
|
||||
}
|
||||
|
||||
// PutBigEndianUint24 encodes a uint24 and places into out
|
||||
func PutBigEndianUint24(out []byte, in uint32) {
|
||||
tmp := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(tmp, in)
|
||||
copy(out, tmp[1:])
|
||||
}
|
||||
|
||||
// PutBigEndianUint48 encodes a uint64 and places into out
|
||||
func PutBigEndianUint48(out []byte, in uint64) {
|
||||
tmp := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(tmp, in)
|
||||
copy(out, tmp[2:])
|
||||
}
|
||||
|
||||
// Max returns the larger value
|
||||
func Max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
80
vendor/github.com/pion/dtls/v2/listener.go
generated
vendored
Normal file
80
vendor/github.com/pion/dtls/v2/listener.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/protocol"
|
||||
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
|
||||
"github.com/pion/udp"
|
||||
)
|
||||
|
||||
// Listen creates a DTLS listener
|
||||
func Listen(network string, laddr *net.UDPAddr, config *Config) (net.Listener, error) {
|
||||
if err := validateConfig(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lc := udp.ListenConfig{
|
||||
AcceptFilter: func(packet []byte) bool {
|
||||
pkts, err := recordlayer.UnpackDatagram(packet)
|
||||
if err != nil || len(pkts) < 1 {
|
||||
return false
|
||||
}
|
||||
h := &recordlayer.Header{}
|
||||
if err := h.Unmarshal(pkts[0]); err != nil {
|
||||
return false
|
||||
}
|
||||
return h.ContentType == protocol.ContentTypeHandshake
|
||||
},
|
||||
}
|
||||
parent, err := lc.Listen(network, laddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &listener{
|
||||
config: config,
|
||||
parent: parent,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewListener creates a DTLS listener which accepts connections from an inner Listener.
|
||||
func NewListener(inner net.Listener, config *Config) (net.Listener, error) {
|
||||
if err := validateConfig(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &listener{
|
||||
config: config,
|
||||
parent: inner,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// listener represents a DTLS listener
|
||||
type listener struct {
|
||||
config *Config
|
||||
parent net.Listener
|
||||
}
|
||||
|
||||
// Accept waits for and returns the next connection to the listener.
|
||||
// You have to either close or read on all connection that are created.
|
||||
// Connection handshake will timeout using ConnectContextMaker in the Config.
|
||||
// If you want to specify the timeout duration, set ConnectContextMaker.
|
||||
func (l *listener) Accept() (net.Conn, error) {
|
||||
c, err := l.parent.Accept()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Server(c, l.config)
|
||||
}
|
||||
|
||||
// Close closes the listener.
|
||||
// Any blocked Accept operations will be unblocked and return errors.
|
||||
// Already Accepted connections are not closed.
|
||||
func (l *listener) Close() error {
|
||||
return l.parent.Close()
|
||||
}
|
||||
|
||||
// Addr returns the listener's network address.
|
||||
func (l *listener) Addr() net.Addr {
|
||||
return l.parent.Addr()
|
||||
}
|
||||
9
vendor/github.com/pion/dtls/v2/packet.go
generated
vendored
Normal file
9
vendor/github.com/pion/dtls/v2/packet.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package dtls
|
||||
|
||||
import "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
|
||||
|
||||
type packet struct {
|
||||
record *recordlayer.RecordLayer
|
||||
shouldEncrypt bool
|
||||
resetLocalSequenceNumber bool
|
||||
}
|
||||
251
vendor/github.com/pion/dtls/v2/pkg/crypto/ccm/ccm.go
generated
vendored
Normal file
251
vendor/github.com/pion/dtls/v2/pkg/crypto/ccm/ccm.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
164
vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/cbc.go
generated
vendored
Normal file
164
vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/cbc.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
104
vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/ccm.go
generated
vendored
Normal file
104
vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/ccm.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
72
vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/ciphersuite.go
generated
vendored
Normal file
72
vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/ciphersuite.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
100
vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/gcm.go
generated
vendored
Normal file
100
vendor/github.com/pion/dtls/v2/pkg/crypto/ciphersuite/gcm.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
22
vendor/github.com/pion/dtls/v2/pkg/crypto/clientcertificate/client_certificate.go
generated
vendored
Normal file
22
vendor/github.com/pion/dtls/v2/pkg/crypto/clientcertificate/client_certificate.go
generated
vendored
Normal file
@@ -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,
|
||||
}
|
||||
}
|
||||
99
vendor/github.com/pion/dtls/v2/pkg/crypto/elliptic/elliptic.go
generated
vendored
Normal file
99
vendor/github.com/pion/dtls/v2/pkg/crypto/elliptic/elliptic.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
50
vendor/github.com/pion/dtls/v2/pkg/crypto/fingerprint/fingerprint.go
generated
vendored
Normal file
50
vendor/github.com/pion/dtls/v2/pkg/crypto/fingerprint/fingerprint.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
37
vendor/github.com/pion/dtls/v2/pkg/crypto/fingerprint/hash.go
generated
vendored
Normal file
37
vendor/github.com/pion/dtls/v2/pkg/crypto/fingerprint/hash.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
126
vendor/github.com/pion/dtls/v2/pkg/crypto/hash/hash.go
generated
vendored
Normal file
126
vendor/github.com/pion/dtls/v2/pkg/crypto/hash/hash.go
generated
vendored
Normal file
@@ -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: {},
|
||||
}
|
||||
}
|
||||
224
vendor/github.com/pion/dtls/v2/pkg/crypto/prf/prf.go
generated
vendored
Normal file
224
vendor/github.com/pion/dtls/v2/pkg/crypto/prf/prf.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
24
vendor/github.com/pion/dtls/v2/pkg/crypto/signature/signature.go
generated
vendored
Normal file
24
vendor/github.com/pion/dtls/v2/pkg/crypto/signature/signature.go
generated
vendored
Normal file
@@ -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: {},
|
||||
}
|
||||
}
|
||||
9
vendor/github.com/pion/dtls/v2/pkg/crypto/signaturehash/errors.go
generated
vendored
Normal file
9
vendor/github.com/pion/dtls/v2/pkg/crypto/signaturehash/errors.go
generated
vendored
Normal file
@@ -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")
|
||||
)
|
||||
93
vendor/github.com/pion/dtls/v2/pkg/crypto/signaturehash/signaturehash.go
generated
vendored
Normal file
93
vendor/github.com/pion/dtls/v2/pkg/crypto/signaturehash/signaturehash.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
163
vendor/github.com/pion/dtls/v2/pkg/protocol/alert/alert.go
generated
vendored
Normal file
163
vendor/github.com/pion/dtls/v2/pkg/protocol/alert/alert.go
generated
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
// 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
|
||||
NoApplicationProtocol Description = 120
|
||||
)
|
||||
|
||||
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"
|
||||
case NoApplicationProtocol:
|
||||
return "NoApplicationProtocol"
|
||||
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)
|
||||
}
|
||||
26
vendor/github.com/pion/dtls/v2/pkg/protocol/application_data.go
generated
vendored
Normal file
26
vendor/github.com/pion/dtls/v2/pkg/protocol/application_data.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
27
vendor/github.com/pion/dtls/v2/pkg/protocol/change_cipher_spec.go
generated
vendored
Normal file
27
vendor/github.com/pion/dtls/v2/pkg/protocol/change_cipher_spec.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
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
|
||||
}
|
||||
48
vendor/github.com/pion/dtls/v2/pkg/protocol/compression_method.go
generated
vendored
Normal file
48
vendor/github.com/pion/dtls/v2/pkg/protocol/compression_method.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
21
vendor/github.com/pion/dtls/v2/pkg/protocol/content.go
generated
vendored
Normal file
21
vendor/github.com/pion/dtls/v2/pkg/protocol/content.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
104
vendor/github.com/pion/dtls/v2/pkg/protocol/errors.go
generated
vendored
Normal file
104
vendor/github.com/pion/dtls/v2/pkg/protocol/errors.go
generated
vendored
Normal file
@@ -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) }
|
||||
77
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/alpn.go
generated
vendored
Normal file
77
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/alpn.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
package extension
|
||||
|
||||
import (
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
)
|
||||
|
||||
// ALPN is a TLS extension for application-layer protocol negotiation within
|
||||
// the TLS handshake.
|
||||
//
|
||||
// https://tools.ietf.org/html/rfc7301
|
||||
type ALPN struct {
|
||||
ProtocolNameList []string
|
||||
}
|
||||
|
||||
// TypeValue returns the extension TypeValue
|
||||
func (a ALPN) TypeValue() TypeValue {
|
||||
return ALPNTypeValue
|
||||
}
|
||||
|
||||
// Marshal encodes the extension
|
||||
func (a *ALPN) Marshal() ([]byte, error) {
|
||||
var b cryptobyte.Builder
|
||||
b.AddUint16(uint16(a.TypeValue()))
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, proto := range a.ProtocolNameList {
|
||||
p := proto // Satisfy range scope lint
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes([]byte(p))
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
// Unmarshal populates the extension from encoded data
|
||||
func (a *ALPN) Unmarshal(data []byte) error {
|
||||
val := cryptobyte.String(data)
|
||||
|
||||
var extension uint16
|
||||
val.ReadUint16(&extension)
|
||||
if TypeValue(extension) != a.TypeValue() {
|
||||
return errInvalidExtensionType
|
||||
}
|
||||
|
||||
var extData cryptobyte.String
|
||||
val.ReadUint16LengthPrefixed(&extData)
|
||||
|
||||
var protoList cryptobyte.String
|
||||
if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
|
||||
return ErrALPNInvalidFormat
|
||||
}
|
||||
for !protoList.Empty() {
|
||||
var proto cryptobyte.String
|
||||
if !protoList.ReadUint8LengthPrefixed(&proto) || proto.Empty() {
|
||||
return ErrALPNInvalidFormat
|
||||
}
|
||||
a.ProtocolNameList = append(a.ProtocolNameList, string(proto))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ALPNProtocolSelection negotiates a shared protocol according to #3.2 of rfc7301
|
||||
func ALPNProtocolSelection(supportedProtocols, peerSupportedProtocols []string) (string, error) {
|
||||
if len(supportedProtocols) == 0 || len(peerSupportedProtocols) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
for _, s := range supportedProtocols {
|
||||
for _, c := range peerSupportedProtocols {
|
||||
if s == c {
|
||||
return s, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", errALPNNoAppProto
|
||||
}
|
||||
17
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/errors.go
generated
vendored
Normal file
17
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/errors.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package extension
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/pion/dtls/v2/pkg/protocol"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrALPNInvalidFormat is raised when the ALPN format is invalid
|
||||
ErrALPNInvalidFormat = &protocol.FatalError{Err: errors.New("invalid alpn format")} //nolint:goerr113
|
||||
errALPNNoAppProto = &protocol.FatalError{Err: errors.New("no application protocol")} //nolint:goerr113
|
||||
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
|
||||
)
|
||||
99
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/extension.go
generated
vendored
Normal file
99
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/extension.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
// 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
|
||||
ALPNTypeValue TypeValue = 16
|
||||
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 ALPNTypeValue:
|
||||
err = unmarshalAndAppend(buf[offset:], &ALPN{})
|
||||
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
|
||||
}
|
||||
43
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/renegotiation_info.go
generated
vendored
Normal file
43
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/renegotiation_info.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
78
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/server_name.go
generated
vendored
Normal file
78
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/server_name.go
generated
vendored
Normal file
@@ -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 wishes 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
|
||||
}
|
||||
21
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/srtp_protection_profile.go
generated
vendored
Normal file
21
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/srtp_protection_profile.go
generated
vendored
Normal file
@@ -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,
|
||||
}
|
||||
}
|
||||
62
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_elliptic_curves.go
generated
vendored
Normal file
62
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_elliptic_curves.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
62
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_point_formats.go
generated
vendored
Normal file
62
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_point_formats.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
70
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_signature_algorithms.go
generated
vendored
Normal file
70
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/supported_signature_algorithms.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
45
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/use_master_secret.go
generated
vendored
Normal file
45
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/use_master_secret.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
59
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/use_srtp.go
generated
vendored
Normal file
59
vendor/github.com/pion/dtls/v2/pkg/protocol/extension/use_srtp.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
29
vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/cipher_suite.go
generated
vendored
Normal file
29
vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/cipher_suite.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
25
vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/errors.go
generated
vendored
Normal file
25
vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/errors.go
generated
vendored
Normal file
@@ -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
|
||||
)
|
||||
144
vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/handshake.go
generated
vendored
Normal file
144
vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/handshake.go
generated
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
// 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:])
|
||||
}
|
||||
50
vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/header.go
generated
vendored
Normal file
50
vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/header.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user