131 lines
3.2 KiB
Go
131 lines
3.2 KiB
Go
|
package handshake
|
||
|
|
||
|
import (
|
||
|
"encoding/binary"
|
||
|
|
||
|
"github.com/pion/dtls/v2/pkg/protocol"
|
||
|
"github.com/pion/dtls/v2/pkg/protocol/extension"
|
||
|
)
|
||
|
|
||
|
/*
|
||
|
MessageClientHello is for when a client first connects to a server it is
|
||
|
required to send the client hello as its first message. The client can also send a
|
||
|
client hello in response to a hello request or on its own
|
||
|
initiative in order to renegotiate the security parameters in an
|
||
|
existing connection.
|
||
|
*/
|
||
|
type MessageClientHello struct {
|
||
|
Version protocol.Version
|
||
|
Random Random
|
||
|
Cookie []byte
|
||
|
|
||
|
SessionID []byte // TODO 添加anylink支持
|
||
|
|
||
|
CipherSuiteIDs []uint16
|
||
|
CompressionMethods []*protocol.CompressionMethod
|
||
|
Extensions []extension.Extension
|
||
|
}
|
||
|
|
||
|
const handshakeMessageClientHelloVariableWidthStart = 34
|
||
|
|
||
|
// Type returns the Handshake Type
|
||
|
func (m MessageClientHello) Type() Type {
|
||
|
return TypeClientHello
|
||
|
}
|
||
|
|
||
|
// Marshal encodes the Handshake
|
||
|
func (m *MessageClientHello) Marshal() ([]byte, error) {
|
||
|
if len(m.Cookie) > 255 {
|
||
|
return nil, errCookieTooLong
|
||
|
}
|
||
|
|
||
|
out := make([]byte, handshakeMessageClientHelloVariableWidthStart)
|
||
|
out[0] = m.Version.Major
|
||
|
out[1] = m.Version.Minor
|
||
|
|
||
|
rand := m.Random.MarshalFixed()
|
||
|
copy(out[2:], rand[:])
|
||
|
|
||
|
out = append(out, 0x00) // SessionID
|
||
|
|
||
|
out = append(out, byte(len(m.Cookie)))
|
||
|
out = append(out, m.Cookie...)
|
||
|
out = append(out, encodeCipherSuiteIDs(m.CipherSuiteIDs)...)
|
||
|
out = append(out, protocol.EncodeCompressionMethods(m.CompressionMethods)...)
|
||
|
|
||
|
extensions, err := extension.Marshal(m.Extensions)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return append(out, extensions...), nil
|
||
|
}
|
||
|
|
||
|
// Unmarshal populates the message from encoded data
|
||
|
func (m *MessageClientHello) Unmarshal(data []byte) error {
|
||
|
if len(data) < 2+RandomLength {
|
||
|
return errBufferTooSmall
|
||
|
}
|
||
|
|
||
|
m.Version.Major = data[0]
|
||
|
m.Version.Minor = data[1]
|
||
|
|
||
|
var random [RandomLength]byte
|
||
|
copy(random[:], data[2:])
|
||
|
m.Random.UnmarshalFixed(random)
|
||
|
|
||
|
// rest of packet has variable width sections
|
||
|
currOffset := handshakeMessageClientHelloVariableWidthStart
|
||
|
currOffset += int(data[currOffset]) + 1 // SessionID
|
||
|
|
||
|
// TODO 添加SessionID
|
||
|
m.SessionID = data[handshakeMessageClientHelloVariableWidthStart+1 : currOffset]
|
||
|
|
||
|
currOffset++
|
||
|
if len(data) <= currOffset {
|
||
|
return errBufferTooSmall
|
||
|
}
|
||
|
n := int(data[currOffset-1])
|
||
|
if len(data) <= currOffset+n {
|
||
|
return errBufferTooSmall
|
||
|
}
|
||
|
m.Cookie = append([]byte{}, data[currOffset:currOffset+n]...)
|
||
|
currOffset += len(m.Cookie)
|
||
|
|
||
|
// Cipher Suites
|
||
|
if len(data) < currOffset {
|
||
|
return errBufferTooSmall
|
||
|
}
|
||
|
cipherSuiteIDs, err := decodeCipherSuiteIDs(data[currOffset:])
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
m.CipherSuiteIDs = cipherSuiteIDs
|
||
|
if len(data) < currOffset+2 {
|
||
|
return errBufferTooSmall
|
||
|
}
|
||
|
currOffset += int(binary.BigEndian.Uint16(data[currOffset:])) + 2
|
||
|
|
||
|
// Compression Methods
|
||
|
if len(data) < currOffset {
|
||
|
return errBufferTooSmall
|
||
|
}
|
||
|
compressionMethods, err := protocol.DecodeCompressionMethods(data[currOffset:])
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
m.CompressionMethods = compressionMethods
|
||
|
if len(data) < currOffset {
|
||
|
return errBufferTooSmall
|
||
|
}
|
||
|
currOffset += int(data[currOffset]) + 1
|
||
|
|
||
|
// Extensions
|
||
|
extensions, err := extension.Unmarshal(data[currOffset:])
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
m.Extensions = extensions
|
||
|
return nil
|
||
|
}
|