mirror of
https://github.com/v2fly/v2ray-core.git
synced 2024-11-19 19:06:43 -05:00
689 lines
16 KiB
Go
689 lines
16 KiB
Go
// Copyright 2017 Google Inc. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package tls
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
)
|
|
|
|
type TLSExtension interface {
|
|
writeToUConn(*UConn) error
|
|
|
|
Len() int // includes header
|
|
|
|
// Read reads up to len(p) bytes into p.
|
|
// It returns the number of bytes read (0 <= n <= len(p)) and any error encountered.
|
|
Read(p []byte) (n int, err error) // implements io.Reader
|
|
}
|
|
|
|
type NPNExtension struct {
|
|
NextProtos []string
|
|
}
|
|
|
|
func (e *NPNExtension) writeToUConn(uc *UConn) error {
|
|
uc.config.NextProtos = e.NextProtos
|
|
uc.HandshakeState.Hello.NextProtoNeg = true
|
|
return nil
|
|
}
|
|
|
|
func (e *NPNExtension) Len() int {
|
|
return 4
|
|
}
|
|
|
|
func (e *NPNExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
b[0] = byte(extensionNextProtoNeg >> 8)
|
|
b[1] = byte(extensionNextProtoNeg & 0xff)
|
|
// The length is always 0
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
type SNIExtension struct {
|
|
ServerName string // not an array because go crypto/tls doesn't support multiple SNIs
|
|
}
|
|
|
|
func (e *SNIExtension) writeToUConn(uc *UConn) error {
|
|
uc.config.ServerName = e.ServerName
|
|
uc.HandshakeState.Hello.ServerName = e.ServerName
|
|
return nil
|
|
}
|
|
|
|
func (e *SNIExtension) Len() int {
|
|
return 4 + 2 + 1 + 2 + len(e.ServerName)
|
|
}
|
|
|
|
func (e *SNIExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// RFC 3546, section 3.1
|
|
b[0] = byte(extensionServerName >> 8)
|
|
b[1] = byte(extensionServerName)
|
|
b[2] = byte((len(e.ServerName) + 5) >> 8)
|
|
b[3] = byte((len(e.ServerName) + 5))
|
|
b[4] = byte((len(e.ServerName) + 3) >> 8)
|
|
b[5] = byte(len(e.ServerName) + 3)
|
|
// b[6] Server Name Type: host_name (0)
|
|
b[7] = byte(len(e.ServerName) >> 8)
|
|
b[8] = byte(len(e.ServerName))
|
|
copy(b[9:], []byte(e.ServerName))
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
type StatusRequestExtension struct {
|
|
}
|
|
|
|
func (e *StatusRequestExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.OcspStapling = true
|
|
return nil
|
|
}
|
|
|
|
func (e *StatusRequestExtension) Len() int {
|
|
return 9
|
|
}
|
|
|
|
func (e *StatusRequestExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// RFC 4366, section 3.6
|
|
b[0] = byte(extensionStatusRequest >> 8)
|
|
b[1] = byte(extensionStatusRequest)
|
|
b[2] = 0
|
|
b[3] = 5
|
|
b[4] = 1 // OCSP type
|
|
// Two zero valued uint16s for the two lengths.
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
type SupportedCurvesExtension struct {
|
|
Curves []CurveID
|
|
}
|
|
|
|
func (e *SupportedCurvesExtension) writeToUConn(uc *UConn) error {
|
|
uc.config.CurvePreferences = e.Curves
|
|
uc.HandshakeState.Hello.SupportedCurves = e.Curves
|
|
return nil
|
|
}
|
|
|
|
func (e *SupportedCurvesExtension) Len() int {
|
|
return 6 + 2*len(e.Curves)
|
|
}
|
|
|
|
func (e *SupportedCurvesExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// http://tools.ietf.org/html/rfc4492#section-5.5.1
|
|
b[0] = byte(extensionSupportedCurves >> 8)
|
|
b[1] = byte(extensionSupportedCurves)
|
|
b[2] = byte((2 + 2*len(e.Curves)) >> 8)
|
|
b[3] = byte((2 + 2*len(e.Curves)))
|
|
b[4] = byte((2 * len(e.Curves)) >> 8)
|
|
b[5] = byte((2 * len(e.Curves)))
|
|
for i, curve := range e.Curves {
|
|
b[6+2*i] = byte(curve >> 8)
|
|
b[7+2*i] = byte(curve)
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
type SupportedPointsExtension struct {
|
|
SupportedPoints []uint8
|
|
}
|
|
|
|
func (e *SupportedPointsExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.SupportedPoints = e.SupportedPoints
|
|
return nil
|
|
}
|
|
|
|
func (e *SupportedPointsExtension) Len() int {
|
|
return 5 + len(e.SupportedPoints)
|
|
}
|
|
|
|
func (e *SupportedPointsExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// http://tools.ietf.org/html/rfc4492#section-5.5.2
|
|
b[0] = byte(extensionSupportedPoints >> 8)
|
|
b[1] = byte(extensionSupportedPoints)
|
|
b[2] = byte((1 + len(e.SupportedPoints)) >> 8)
|
|
b[3] = byte((1 + len(e.SupportedPoints)))
|
|
b[4] = byte((len(e.SupportedPoints)))
|
|
for i, pointFormat := range e.SupportedPoints {
|
|
b[5+i] = pointFormat
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
type SignatureAlgorithmsExtension struct {
|
|
SupportedSignatureAlgorithms []SignatureScheme
|
|
}
|
|
|
|
func (e *SignatureAlgorithmsExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.SupportedSignatureAlgorithms = e.SupportedSignatureAlgorithms
|
|
return nil
|
|
}
|
|
|
|
func (e *SignatureAlgorithmsExtension) Len() int {
|
|
return 6 + 2*len(e.SupportedSignatureAlgorithms)
|
|
}
|
|
|
|
func (e *SignatureAlgorithmsExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
|
|
b[0] = byte(extensionSignatureAlgorithms >> 8)
|
|
b[1] = byte(extensionSignatureAlgorithms)
|
|
b[2] = byte((2 + 2*len(e.SupportedSignatureAlgorithms)) >> 8)
|
|
b[3] = byte((2 + 2*len(e.SupportedSignatureAlgorithms)))
|
|
b[4] = byte((2 * len(e.SupportedSignatureAlgorithms)) >> 8)
|
|
b[5] = byte((2 * len(e.SupportedSignatureAlgorithms)))
|
|
for i, sigAndHash := range e.SupportedSignatureAlgorithms {
|
|
b[6+2*i] = byte(sigAndHash >> 8)
|
|
b[7+2*i] = byte(sigAndHash)
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
type RenegotiationInfoExtension struct {
|
|
renegotiation RenegotiationSupport
|
|
SecureRenegotiation []byte // if empty, default []byte{0} is assumed
|
|
}
|
|
|
|
func (e *RenegotiationInfoExtension) writeToUConn(uc *UConn) error {
|
|
uc.config.Renegotiation = e.renegotiation
|
|
switch e.renegotiation {
|
|
case RenegotiateOnceAsClient:
|
|
fallthrough
|
|
case RenegotiateFreelyAsClient:
|
|
uc.HandshakeState.Hello.SecureRenegotiationSupported = true
|
|
// Note that if we manage to use this in renegotiation(currently only in initial handshake), we'd have to point
|
|
// uc.ClientHelloMsg.SecureRenegotiation = chs.C.clientFinished
|
|
// and probably do something else. It's a mess.
|
|
case RenegotiateNever:
|
|
default:
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (e *RenegotiationInfoExtension) Len() int {
|
|
switch e.renegotiation {
|
|
case RenegotiateOnceAsClient:
|
|
fallthrough
|
|
case RenegotiateFreelyAsClient:
|
|
extBodyLen := len(e.SecureRenegotiation)
|
|
if extBodyLen == 0 {
|
|
extBodyLen = 1
|
|
}
|
|
return 4 + extBodyLen
|
|
case RenegotiateNever:
|
|
default:
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (e *RenegotiationInfoExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
switch e.renegotiation {
|
|
case RenegotiateOnceAsClient:
|
|
fallthrough
|
|
case RenegotiateFreelyAsClient:
|
|
secureRenegBody := e.SecureRenegotiation
|
|
if len(secureRenegBody) == 0 {
|
|
secureRenegBody = []byte{0}
|
|
}
|
|
extBodyLen := len(secureRenegBody)
|
|
|
|
b[0] = byte(extensionRenegotiationInfo >> 8)
|
|
b[1] = byte(extensionRenegotiationInfo & 0xff)
|
|
b[2] = byte(extBodyLen >> 8)
|
|
b[3] = byte(extBodyLen)
|
|
copy(b[4:], secureRenegBody)
|
|
|
|
if len(e.SecureRenegotiation) != 0 {
|
|
copy(b[5:], e.SecureRenegotiation)
|
|
}
|
|
case RenegotiateNever:
|
|
default:
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
type ALPNExtension struct {
|
|
AlpnProtocols []string
|
|
}
|
|
|
|
func (e *ALPNExtension) writeToUConn(uc *UConn) error {
|
|
uc.config.NextProtos = e.AlpnProtocols
|
|
uc.HandshakeState.Hello.AlpnProtocols = e.AlpnProtocols
|
|
return nil
|
|
}
|
|
|
|
func (e *ALPNExtension) Len() int {
|
|
bLen := 2 + 2 + 2
|
|
for _, s := range e.AlpnProtocols {
|
|
bLen += 1 + len(s)
|
|
}
|
|
return bLen
|
|
}
|
|
|
|
func (e *ALPNExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
|
|
b[0] = byte(extensionALPN >> 8)
|
|
b[1] = byte(extensionALPN & 0xff)
|
|
lengths := b[2:]
|
|
b = b[6:]
|
|
|
|
stringsLength := 0
|
|
for _, s := range e.AlpnProtocols {
|
|
l := len(s)
|
|
b[0] = byte(l)
|
|
copy(b[1:], s)
|
|
b = b[1+l:]
|
|
stringsLength += 1 + l
|
|
}
|
|
|
|
lengths[2] = byte(stringsLength >> 8)
|
|
lengths[3] = byte(stringsLength)
|
|
stringsLength += 2
|
|
lengths[0] = byte(stringsLength >> 8)
|
|
lengths[1] = byte(stringsLength)
|
|
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
type SCTExtension struct {
|
|
}
|
|
|
|
func (e *SCTExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.Scts = true
|
|
return nil
|
|
}
|
|
|
|
func (e *SCTExtension) Len() int {
|
|
return 4
|
|
}
|
|
|
|
func (e *SCTExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// https://tools.ietf.org/html/rfc6962#section-3.3.1
|
|
b[0] = byte(extensionSCT >> 8)
|
|
b[1] = byte(extensionSCT)
|
|
// zero uint16 for the zero-length extension_data
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
type SessionTicketExtension struct {
|
|
Session *ClientSessionState
|
|
}
|
|
|
|
func (e *SessionTicketExtension) writeToUConn(uc *UConn) error {
|
|
if e.Session != nil {
|
|
uc.HandshakeState.Session = e.Session
|
|
uc.HandshakeState.Hello.SessionTicket = e.Session.sessionTicket
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (e *SessionTicketExtension) Len() int {
|
|
if e.Session != nil {
|
|
return 4 + len(e.Session.sessionTicket)
|
|
}
|
|
return 4
|
|
}
|
|
|
|
func (e *SessionTicketExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
|
|
extBodyLen := e.Len() - 4
|
|
|
|
b[0] = byte(extensionSessionTicket >> 8)
|
|
b[1] = byte(extensionSessionTicket)
|
|
b[2] = byte(extBodyLen >> 8)
|
|
b[3] = byte(extBodyLen)
|
|
if extBodyLen > 0 {
|
|
copy(b[4:], e.Session.sessionTicket)
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
type GenericExtension struct {
|
|
id uint16
|
|
data []byte
|
|
}
|
|
|
|
func (e *GenericExtension) writeToUConn(uc *UConn) error {
|
|
return nil
|
|
}
|
|
|
|
func (e *GenericExtension) Len() int {
|
|
return 4 + len(e.data)
|
|
}
|
|
|
|
func (e *GenericExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
|
|
b[0] = byte(e.id >> 8)
|
|
b[1] = byte(e.id)
|
|
b[2] = byte(len(e.data) >> 8)
|
|
b[3] = byte(len(e.data))
|
|
if len(e.data) > 0 {
|
|
copy(b[4:], e.data)
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
/*
|
|
FAKE EXTENSIONS
|
|
*/
|
|
|
|
type FakeChannelIDExtension struct {
|
|
}
|
|
|
|
func (e *FakeChannelIDExtension) writeToUConn(uc *UConn) error {
|
|
return nil
|
|
}
|
|
|
|
func (e *FakeChannelIDExtension) Len() int {
|
|
return 4
|
|
}
|
|
|
|
func (e *FakeChannelIDExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// https://tools.ietf.org/html/draft-balfanz-tls-channelid-00
|
|
b[0] = byte(fakeExtensionChannelID >> 8)
|
|
b[1] = byte(fakeExtensionChannelID & 0xff)
|
|
// The length is 0
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
type UtlsExtendedMasterSecretExtension struct {
|
|
}
|
|
|
|
// TODO: update when this extension is implemented in crypto/tls
|
|
// but we probably won't have to enable it in Config
|
|
func (e *UtlsExtendedMasterSecretExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.Ems = true
|
|
return nil
|
|
}
|
|
|
|
func (e *UtlsExtendedMasterSecretExtension) Len() int {
|
|
return 4
|
|
}
|
|
|
|
func (e *UtlsExtendedMasterSecretExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// https://tools.ietf.org/html/rfc7627
|
|
b[0] = byte(utlsExtensionExtendedMasterSecret >> 8)
|
|
b[1] = byte(utlsExtensionExtendedMasterSecret)
|
|
// The length is 0
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
var extendedMasterSecretLabel = []byte("extended master secret")
|
|
|
|
// extendedMasterFromPreMasterSecret generates the master secret from the pre-master
|
|
// secret and session hash. See https://tools.ietf.org/html/rfc7627#section-4
|
|
func extendedMasterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret []byte, fh finishedHash) []byte {
|
|
sessionHash := fh.Sum()
|
|
masterSecret := make([]byte, masterSecretLength)
|
|
prfForVersion(version, suite)(masterSecret, preMasterSecret, extendedMasterSecretLabel, sessionHash)
|
|
return masterSecret
|
|
}
|
|
|
|
// GREASE stinks with dead parrots, have to be super careful, and, if possible, not include GREASE
|
|
// https://github.com/google/boringssl/blob/1c68fa2350936ca5897a66b430ebaf333a0e43f5/ssl/internal.h
|
|
const (
|
|
ssl_grease_cipher = iota
|
|
ssl_grease_group
|
|
ssl_grease_extension1
|
|
ssl_grease_extension2
|
|
ssl_grease_version
|
|
ssl_grease_ticket_extension
|
|
ssl_grease_last_index = ssl_grease_ticket_extension
|
|
)
|
|
|
|
// it is responsibility of user not to generate multiple grease extensions with same value
|
|
type UtlsGREASEExtension struct {
|
|
Value uint16
|
|
Body []byte // in Chrome first grease has empty body, second grease has a single zero byte
|
|
}
|
|
|
|
func (e *UtlsGREASEExtension) writeToUConn(uc *UConn) error {
|
|
return nil
|
|
}
|
|
|
|
// will panic if ssl_grease_last_index[index] is out of bounds.
|
|
func GetBoringGREASEValue(greaseSeed [ssl_grease_last_index]uint16, index int) uint16 {
|
|
// GREASE value is back from deterministic to random.
|
|
// https://github.com/google/boringssl/blob/a365138ac60f38b64bfc608b493e0f879845cb88/ssl/handshake_client.c#L530
|
|
ret := uint16(greaseSeed[index])
|
|
/* This generates a random value of the form 0xωaωa, for all 0 ≤ ω < 16. */
|
|
ret = (ret & 0xf0) | 0x0a
|
|
ret |= ret << 8
|
|
return ret
|
|
}
|
|
|
|
func (e *UtlsGREASEExtension) Len() int {
|
|
return 4 + len(e.Body)
|
|
}
|
|
|
|
func (e *UtlsGREASEExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
|
|
b[0] = byte(e.Value >> 8)
|
|
b[1] = byte(e.Value)
|
|
b[2] = byte(len(e.Body) >> 8)
|
|
b[3] = byte(len(e.Body))
|
|
if len(e.Body) > 0 {
|
|
copy(b[4:], e.Body)
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
type UtlsPaddingExtension struct {
|
|
PaddingLen int
|
|
WillPad bool // set to false to disable extension
|
|
|
|
// Functor for deciding on padding length based on unpadded ClientHello length.
|
|
// If willPad is false, then this extension should not be included.
|
|
GetPaddingLen func(clientHelloUnpaddedLen int) (paddingLen int, willPad bool)
|
|
}
|
|
|
|
func (e *UtlsPaddingExtension) writeToUConn(uc *UConn) error {
|
|
return nil
|
|
}
|
|
|
|
func (e *UtlsPaddingExtension) Len() int {
|
|
if e.WillPad {
|
|
return 4 + e.PaddingLen
|
|
} else {
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func (e *UtlsPaddingExtension) Update(clientHelloUnpaddedLen int) {
|
|
if e.GetPaddingLen != nil {
|
|
e.PaddingLen, e.WillPad = e.GetPaddingLen(clientHelloUnpaddedLen)
|
|
}
|
|
}
|
|
|
|
func (e *UtlsPaddingExtension) Read(b []byte) (int, error) {
|
|
if !e.WillPad {
|
|
return 0, io.EOF
|
|
}
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// https://tools.ietf.org/html/rfc7627
|
|
b[0] = byte(utlsExtensionPadding >> 8)
|
|
b[1] = byte(utlsExtensionPadding)
|
|
b[2] = byte(e.PaddingLen >> 8)
|
|
b[3] = byte(e.PaddingLen)
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
// https://github.com/google/boringssl/blob/7d7554b6b3c79e707e25521e61e066ce2b996e4c/ssl/t1_lib.c#L2803
|
|
func BoringPaddingStyle(unpaddedLen int) (int, bool) {
|
|
if unpaddedLen > 0xff && unpaddedLen < 0x200 {
|
|
paddingLen := 0x200 - unpaddedLen
|
|
if paddingLen >= 4+1 {
|
|
paddingLen -= 4
|
|
} else {
|
|
paddingLen = 1
|
|
}
|
|
return paddingLen, true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
/* TLS 1.3 */
|
|
type KeyShareExtension struct {
|
|
KeyShares []KeyShare
|
|
}
|
|
|
|
func (e *KeyShareExtension) Len() int {
|
|
return 4 + 2 + e.keySharesLen()
|
|
}
|
|
|
|
func (e *KeyShareExtension) keySharesLen() int {
|
|
extLen := 0
|
|
for _, ks := range e.KeyShares {
|
|
extLen += 4 + len(ks.Data)
|
|
}
|
|
return extLen
|
|
}
|
|
|
|
func (e *KeyShareExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
|
|
b[0] = byte(extensionKeyShare >> 8)
|
|
b[1] = byte(extensionKeyShare)
|
|
keySharesLen := e.keySharesLen()
|
|
b[2] = byte((keySharesLen + 2) >> 8)
|
|
b[3] = byte((keySharesLen + 2))
|
|
b[4] = byte((keySharesLen) >> 8)
|
|
b[5] = byte((keySharesLen))
|
|
|
|
i := 6
|
|
for _, ks := range e.KeyShares {
|
|
b[i] = byte(ks.Group >> 8)
|
|
b[i+1] = byte(ks.Group)
|
|
b[i+2] = byte(len(ks.Data) >> 8)
|
|
b[i+3] = byte(len(ks.Data))
|
|
copy(b[i+4:], ks.Data)
|
|
i += 4 + len(ks.Data)
|
|
}
|
|
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *KeyShareExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.KeyShares = e.KeyShares
|
|
return nil
|
|
}
|
|
|
|
type PSKKeyExchangeModesExtension struct {
|
|
Modes []uint8
|
|
}
|
|
|
|
func (e *PSKKeyExchangeModesExtension) Len() int {
|
|
return 4 + 1 + len(e.Modes)
|
|
}
|
|
|
|
func (e *PSKKeyExchangeModesExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
|
|
if len(e.Modes) > 255 {
|
|
return 0, errors.New("too many PSK Key Exchange modes")
|
|
}
|
|
|
|
b[0] = byte(extensionPSKModes >> 8)
|
|
b[1] = byte(extensionPSKModes)
|
|
|
|
modesLen := len(e.Modes)
|
|
b[2] = byte((modesLen + 1) >> 8)
|
|
b[3] = byte((modesLen + 1))
|
|
b[4] = byte(modesLen)
|
|
|
|
if len(e.Modes) > 0 {
|
|
copy(b[5:], e.Modes)
|
|
}
|
|
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *PSKKeyExchangeModesExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.PskModes = e.Modes
|
|
return nil
|
|
}
|
|
|
|
type SupportedVersionsExtension struct {
|
|
Versions []uint16
|
|
}
|
|
|
|
func (e *SupportedVersionsExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.SupportedVersions = e.Versions
|
|
return nil
|
|
}
|
|
|
|
func (e *SupportedVersionsExtension) Len() int {
|
|
return 4 + 1 + (2 * len(e.Versions))
|
|
}
|
|
|
|
func (e *SupportedVersionsExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
extLen := 2 * len(e.Versions)
|
|
if extLen > 255 {
|
|
return 0, errors.New("too many supported versions")
|
|
}
|
|
|
|
b[0] = byte(extensionSupportedVersions >> 8)
|
|
b[1] = byte(extensionSupportedVersions)
|
|
b[2] = byte((extLen + 1) >> 8)
|
|
b[3] = byte((extLen + 1))
|
|
b[4] = byte(extLen)
|
|
|
|
i := 5
|
|
for _, sv := range e.Versions {
|
|
b[i] = byte(sv >> 8)
|
|
b[i+1] = byte(sv)
|
|
i += 2
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
// TODO: FakeCertificateCompressionAlgorithmsExtension
|
|
// TODO: FakeRecordSizeLimitExtension
|