th5/handshake_messages.go
Watson Ladd 7e1760cc7c Add EMS support to tls-tris
see RFC7627
2018-09-07 15:16:11 +01:00

2723 wiersze
62 KiB
Go

// Copyright 2009 The Go Authors. 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 (
"bytes"
"encoding/binary"
"strings"
)
// signAlgosCertList helper function returns either list of signature algorithms in case
// signature_algorithms_cert extension should be marshalled or nil in the other case.
// signAlgos is a list of algorithms from signature_algorithms extension. signAlgosCert is a list
// of algorithms from signature_algorithms_cert extension.
func signAlgosCertList(signAlgos, signAlgosCert []SignatureScheme) []SignatureScheme {
if eqSignatureAlgorithms(signAlgos, signAlgosCert) {
// ensure that only supported_algorithms extension is send if supported_algorithms_cert
// has identical content
return nil
}
return signAlgosCert
}
type clientHelloMsg struct {
raw []byte
rawTruncated []byte // for PSK binding
vers uint16
random []byte
sessionId []byte
cipherSuites []uint16
compressionMethods []uint8
nextProtoNeg bool
serverName string
ocspStapling bool
scts bool
supportedCurves []CurveID
supportedPoints []uint8
ticketSupported bool
sessionTicket []uint8
supportedSignatureAlgorithms []SignatureScheme
supportedSignatureAlgorithmsCert []SignatureScheme
secureRenegotiation []byte
secureRenegotiationSupported bool
alpnProtocols []string
keyShares []keyShare
supportedVersions []uint16
psks []psk
pskKeyExchangeModes []uint8
earlyData bool
delegatedCredential bool
extendedMSSupported bool // RFC7627
}
// Function used for signature_algorithms and signature_algorithrms_cert
// extensions only (for more details, see TLS 1.3 draft 28, 4.2.3).
//
// It advances data slice and returns it, so that it can be used for further
// processing
func marshalExtensionSignatureAlgorithms(extension uint16, data []byte, schemes []SignatureScheme) []byte {
algNum := uint16(len(schemes))
if algNum == 0 {
return data
}
binary.BigEndian.PutUint16(data, extension)
data = data[2:]
binary.BigEndian.PutUint16(data, (2*algNum)+2) // +1 for length
data = data[2:]
binary.BigEndian.PutUint16(data, (2 * algNum))
data = data[2:]
for _, algo := range schemes {
binary.BigEndian.PutUint16(data, uint16(algo))
data = data[2:]
}
return data
}
// Function used for unmarshalling signature_algorithms or signature_algorithms_cert extensions only
// (for more details, see TLS 1.3 draft 28, 4.2.3)
// In case of error function returns alertDecoderError otherwise filled SignatureScheme slice and alertSuccess
func unmarshalExtensionSignatureAlgorithms(data []byte, length int) ([]SignatureScheme, alert) {
if length < 2 || length&1 != 0 {
return nil, alertDecodeError
}
algLen := binary.BigEndian.Uint16(data)
idx := 2
if int(algLen) != length-2 {
return nil, alertDecodeError
}
schemes := make([]SignatureScheme, algLen/2)
for i := range schemes {
schemes[i] = SignatureScheme(binary.BigEndian.Uint16(data[idx:]))
idx += 2
}
return schemes, alertSuccess
}
func (m *clientHelloMsg) equal(i interface{}) bool {
m1, ok := i.(*clientHelloMsg)
if !ok {
return false
}
return bytes.Equal(m.raw, m1.raw) &&
m.vers == m1.vers &&
bytes.Equal(m.random, m1.random) &&
bytes.Equal(m.sessionId, m1.sessionId) &&
eqUint16s(m.cipherSuites, m1.cipherSuites) &&
bytes.Equal(m.compressionMethods, m1.compressionMethods) &&
m.nextProtoNeg == m1.nextProtoNeg &&
m.serverName == m1.serverName &&
m.ocspStapling == m1.ocspStapling &&
m.scts == m1.scts &&
eqCurveIDs(m.supportedCurves, m1.supportedCurves) &&
bytes.Equal(m.supportedPoints, m1.supportedPoints) &&
m.ticketSupported == m1.ticketSupported &&
bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms) &&
eqSignatureAlgorithms(m.supportedSignatureAlgorithmsCert, m1.supportedSignatureAlgorithmsCert) &&
m.secureRenegotiationSupported == m1.secureRenegotiationSupported &&
bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
eqStrings(m.alpnProtocols, m1.alpnProtocols) &&
eqKeyShares(m.keyShares, m1.keyShares) &&
eqUint16s(m.supportedVersions, m1.supportedVersions) &&
m.earlyData == m1.earlyData &&
m.delegatedCredential == m1.delegatedCredential &&
m.extendedMSSupported == m1.extendedMSSupported
}
func (m *clientHelloMsg) marshal() []byte {
if m.raw != nil {
return m.raw
}
length := 2 + 32 + 1 + len(m.sessionId) + 2 + len(m.cipherSuites)*2 + 1 + len(m.compressionMethods)
numExtensions := 0
extensionsLength := 0
if m.nextProtoNeg {
numExtensions++
}
if m.ocspStapling {
extensionsLength += 1 + 2 + 2
numExtensions++
}
if len(m.serverName) > 0 {
extensionsLength += 5 + len(m.serverName)
numExtensions++
}
if len(m.supportedCurves) > 0 {
extensionsLength += 2 + 2*len(m.supportedCurves)
numExtensions++
}
if len(m.supportedPoints) > 0 {
extensionsLength += 1 + len(m.supportedPoints)
numExtensions++
}
if m.ticketSupported {
extensionsLength += len(m.sessionTicket)
numExtensions++
}
if len(m.supportedSignatureAlgorithms) > 0 {
extensionsLength += 2 + 2*len(m.supportedSignatureAlgorithms)
numExtensions++
}
if m.getSignatureAlgorithmsCert() != nil {
extensionsLength += 2 + 2*len(m.getSignatureAlgorithmsCert())
numExtensions++
}
if m.secureRenegotiationSupported {
extensionsLength += 1 + len(m.secureRenegotiation)
numExtensions++
}
if len(m.alpnProtocols) > 0 {
extensionsLength += 2
for _, s := range m.alpnProtocols {
if l := len(s); l == 0 || l > 255 {
panic("invalid ALPN protocol")
}
extensionsLength++
extensionsLength += len(s)
}
numExtensions++
}
if m.scts {
numExtensions++
}
if len(m.keyShares) > 0 {
extensionsLength += 2
for _, k := range m.keyShares {
extensionsLength += 4 + len(k.data)
}
numExtensions++
}
if len(m.supportedVersions) > 0 {
extensionsLength += 1 + 2*len(m.supportedVersions)
numExtensions++
}
if m.earlyData {
numExtensions++
}
if m.delegatedCredential {
numExtensions++
}
if m.extendedMSSupported {
numExtensions++
}
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
}
x := make([]byte, 4+length)
x[0] = typeClientHello
x[1] = uint8(length >> 16)
x[2] = uint8(length >> 8)
x[3] = uint8(length)
x[4] = uint8(m.vers >> 8)
x[5] = uint8(m.vers)
copy(x[6:38], m.random)
x[38] = uint8(len(m.sessionId))
copy(x[39:39+len(m.sessionId)], m.sessionId)
y := x[39+len(m.sessionId):]
y[0] = uint8(len(m.cipherSuites) >> 7)
y[1] = uint8(len(m.cipherSuites) << 1)
for i, suite := range m.cipherSuites {
y[2+i*2] = uint8(suite >> 8)
y[3+i*2] = uint8(suite)
}
z := y[2+len(m.cipherSuites)*2:]
z[0] = uint8(len(m.compressionMethods))
copy(z[1:], m.compressionMethods)
z = z[1+len(m.compressionMethods):]
if numExtensions > 0 {
z[0] = byte(extensionsLength >> 8)
z[1] = byte(extensionsLength)
z = z[2:]
}
if m.nextProtoNeg {
z[0] = byte(extensionNextProtoNeg >> 8)
z[1] = byte(extensionNextProtoNeg & 0xff)
// The length is always 0
z = z[4:]
}
if len(m.serverName) > 0 {
z[0] = byte(extensionServerName >> 8)
z[1] = byte(extensionServerName & 0xff)
l := len(m.serverName) + 5
z[2] = byte(l >> 8)
z[3] = byte(l)
z = z[4:]
// RFC 3546, section 3.1
//
// struct {
// NameType name_type;
// select (name_type) {
// case host_name: HostName;
// } name;
// } ServerName;
//
// enum {
// host_name(0), (255)
// } NameType;
//
// opaque HostName<1..2^16-1>;
//
// struct {
// ServerName server_name_list<1..2^16-1>
// } ServerNameList;
z[0] = byte((len(m.serverName) + 3) >> 8)
z[1] = byte(len(m.serverName) + 3)
z[3] = byte(len(m.serverName) >> 8)
z[4] = byte(len(m.serverName))
copy(z[5:], []byte(m.serverName))
z = z[l:]
}
if m.ocspStapling {
// RFC 4366, section 3.6
z[0] = byte(extensionStatusRequest >> 8)
z[1] = byte(extensionStatusRequest)
z[2] = 0
z[3] = 5
z[4] = 1 // OCSP type
// Two zero valued uint16s for the two lengths.
z = z[9:]
}
if len(m.supportedCurves) > 0 {
// http://tools.ietf.org/html/rfc4492#section-5.5.1
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.4
z[0] = byte(extensionSupportedCurves >> 8)
z[1] = byte(extensionSupportedCurves)
l := 2 + 2*len(m.supportedCurves)
z[2] = byte(l >> 8)
z[3] = byte(l)
l -= 2
z[4] = byte(l >> 8)
z[5] = byte(l)
z = z[6:]
for _, curve := range m.supportedCurves {
z[0] = byte(curve >> 8)
z[1] = byte(curve)
z = z[2:]
}
}
if len(m.supportedPoints) > 0 {
// http://tools.ietf.org/html/rfc4492#section-5.5.2
z[0] = byte(extensionSupportedPoints >> 8)
z[1] = byte(extensionSupportedPoints)
l := 1 + len(m.supportedPoints)
z[2] = byte(l >> 8)
z[3] = byte(l)
l--
z[4] = byte(l)
z = z[5:]
for _, pointFormat := range m.supportedPoints {
z[0] = pointFormat
z = z[1:]
}
}
if m.ticketSupported {
// http://tools.ietf.org/html/rfc5077#section-3.2
z[0] = byte(extensionSessionTicket >> 8)
z[1] = byte(extensionSessionTicket)
l := len(m.sessionTicket)
z[2] = byte(l >> 8)
z[3] = byte(l)
z = z[4:]
copy(z, m.sessionTicket)
z = z[len(m.sessionTicket):]
}
if len(m.supportedSignatureAlgorithms) > 0 {
z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithms, z, m.supportedSignatureAlgorithms)
}
if m.getSignatureAlgorithmsCert() != nil {
// Ensure only one list of algorithms is sent if supported_algorithms and supported_algorithms_cert are the same
z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithmsCert, z, m.getSignatureAlgorithmsCert())
}
if m.secureRenegotiationSupported {
z[0] = byte(extensionRenegotiationInfo >> 8)
z[1] = byte(extensionRenegotiationInfo & 0xff)
z[2] = 0
z[3] = byte(len(m.secureRenegotiation) + 1)
z[4] = byte(len(m.secureRenegotiation))
z = z[5:]
copy(z, m.secureRenegotiation)
z = z[len(m.secureRenegotiation):]
}
if len(m.alpnProtocols) > 0 {
z[0] = byte(extensionALPN >> 8)
z[1] = byte(extensionALPN & 0xff)
lengths := z[2:]
z = z[6:]
stringsLength := 0
for _, s := range m.alpnProtocols {
l := len(s)
z[0] = byte(l)
copy(z[1:], s)
z = z[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)
}
if m.scts {
// https://tools.ietf.org/html/rfc6962#section-3.3.1
z[0] = byte(extensionSCT >> 8)
z[1] = byte(extensionSCT)
// zero uint16 for the zero-length extension_data
z = z[4:]
}
if len(m.keyShares) > 0 {
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.5
z[0] = byte(extensionKeyShare >> 8)
z[1] = byte(extensionKeyShare)
lengths := z[2:]
z = z[6:]
totalLength := 0
for _, ks := range m.keyShares {
z[0] = byte(ks.group >> 8)
z[1] = byte(ks.group)
z[2] = byte(len(ks.data) >> 8)
z[3] = byte(len(ks.data))
copy(z[4:], ks.data)
z = z[4+len(ks.data):]
totalLength += 4 + len(ks.data)
}
lengths[2] = byte(totalLength >> 8)
lengths[3] = byte(totalLength)
totalLength += 2
lengths[0] = byte(totalLength >> 8)
lengths[1] = byte(totalLength)
}
if len(m.supportedVersions) > 0 {
z[0] = byte(extensionSupportedVersions >> 8)
z[1] = byte(extensionSupportedVersions)
l := 1 + 2*len(m.supportedVersions)
z[2] = byte(l >> 8)
z[3] = byte(l)
l -= 1
z[4] = byte(l)
z = z[5:]
for _, v := range m.supportedVersions {
z[0] = byte(v >> 8)
z[1] = byte(v)
z = z[2:]
}
}
if m.earlyData {
z[0] = byte(extensionEarlyData >> 8)
z[1] = byte(extensionEarlyData)
z = z[4:]
}
if m.delegatedCredential {
binary.BigEndian.PutUint16(z, extensionDelegatedCredential)
z = z[4:]
}
if m.extendedMSSupported {
binary.BigEndian.PutUint16(z, extensionEMS)
z = z[4:]
}
m.raw = x
return x
}
func (m *clientHelloMsg) unmarshal(data []byte) alert {
if len(data) < 42 {
return alertDecodeError
}
m.raw = data
m.vers = uint16(data[4])<<8 | uint16(data[5])
m.random = data[6:38]
sessionIdLen := int(data[38])
if sessionIdLen > 32 || len(data) < 39+sessionIdLen {
return alertDecodeError
}
m.sessionId = data[39 : 39+sessionIdLen]
data = data[39+sessionIdLen:]
bindersOffset := 39 + sessionIdLen
if len(data) < 2 {
return alertDecodeError
}
// cipherSuiteLen is the number of bytes of cipher suite numbers. Since
// they are uint16s, the number must be even.
cipherSuiteLen := int(data[0])<<8 | int(data[1])
if cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen {
return alertDecodeError
}
numCipherSuites := cipherSuiteLen / 2
m.cipherSuites = make([]uint16, numCipherSuites)
for i := 0; i < numCipherSuites; i++ {
m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
if m.cipherSuites[i] == scsvRenegotiation {
m.secureRenegotiationSupported = true
}
}
data = data[2+cipherSuiteLen:]
bindersOffset += 2 + cipherSuiteLen
if len(data) < 1 {
return alertDecodeError
}
compressionMethodsLen := int(data[0])
if len(data) < 1+compressionMethodsLen {
return alertDecodeError
}
m.compressionMethods = data[1 : 1+compressionMethodsLen]
data = data[1+compressionMethodsLen:]
bindersOffset += 1 + compressionMethodsLen
m.nextProtoNeg = false
m.serverName = ""
m.ocspStapling = false
m.ticketSupported = false
m.sessionTicket = nil
m.supportedSignatureAlgorithms = nil
m.alpnProtocols = nil
m.scts = false
m.keyShares = nil
m.supportedVersions = nil
m.psks = nil
m.pskKeyExchangeModes = nil
m.earlyData = false
m.delegatedCredential = false
m.extendedMSSupported = false
if len(data) == 0 {
// ClientHello is optionally followed by extension data
return alertSuccess
}
if len(data) < 2 {
return alertDecodeError
}
extensionsLength := int(data[0])<<8 | int(data[1])
data = data[2:]
bindersOffset += 2
if extensionsLength != len(data) {
return alertDecodeError
}
for len(data) != 0 {
if len(data) < 4 {
return alertDecodeError
}
extension := uint16(data[0])<<8 | uint16(data[1])
length := int(data[2])<<8 | int(data[3])
data = data[4:]
bindersOffset += 4
if len(data) < length {
return alertDecodeError
}
switch extension {
case extensionServerName:
d := data[:length]
if len(d) < 2 {
return alertDecodeError
}
namesLen := int(d[0])<<8 | int(d[1])
d = d[2:]
if len(d) != namesLen {
return alertDecodeError
}
for len(d) > 0 {
if len(d) < 3 {
return alertDecodeError
}
nameType := d[0]
nameLen := int(d[1])<<8 | int(d[2])
d = d[3:]
if len(d) < nameLen {
return alertDecodeError
}
if nameType == 0 {
m.serverName = string(d[:nameLen])
// An SNI value may not include a
// trailing dot. See
// https://tools.ietf.org/html/rfc6066#section-3.
if strings.HasSuffix(m.serverName, ".") {
// TODO use alertDecodeError?
return alertUnexpectedMessage
}
break
}
d = d[nameLen:]
}
case extensionNextProtoNeg:
if length > 0 {
return alertDecodeError
}
m.nextProtoNeg = true
case extensionStatusRequest:
m.ocspStapling = length > 0 && data[0] == statusTypeOCSP
case extensionSupportedCurves:
// http://tools.ietf.org/html/rfc4492#section-5.5.1
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.4
if length < 2 {
return alertDecodeError
}
l := int(data[0])<<8 | int(data[1])
if l%2 == 1 || length != l+2 {
return alertDecodeError
}
numCurves := l / 2
m.supportedCurves = make([]CurveID, numCurves)
d := data[2:]
for i := 0; i < numCurves; i++ {
m.supportedCurves[i] = CurveID(d[0])<<8 | CurveID(d[1])
d = d[2:]
}
case extensionSupportedPoints:
// http://tools.ietf.org/html/rfc4492#section-5.5.2
if length < 1 {
return alertDecodeError
}
l := int(data[0])
if length != l+1 {
return alertDecodeError
}
m.supportedPoints = make([]uint8, l)
copy(m.supportedPoints, data[1:])
case extensionSessionTicket:
// http://tools.ietf.org/html/rfc5077#section-3.2
m.ticketSupported = true
m.sessionTicket = data[:length]
case extensionSignatureAlgorithms:
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.3
if length < 2 || length&1 != 0 {
return alertDecodeError
}
l := int(data[0])<<8 | int(data[1])
if l != length-2 {
return alertDecodeError
}
n := l / 2
d := data[2:]
m.supportedSignatureAlgorithms = make([]SignatureScheme, n)
for i := range m.supportedSignatureAlgorithms {
m.supportedSignatureAlgorithms[i] = SignatureScheme(d[0])<<8 | SignatureScheme(d[1])
d = d[2:]
}
case extensionRenegotiationInfo:
if length == 0 {
return alertDecodeError
}
d := data[:length]
l := int(d[0])
d = d[1:]
if l != len(d) {
return alertDecodeError
}
m.secureRenegotiation = d
m.secureRenegotiationSupported = true
case extensionALPN:
if length < 2 {
return alertDecodeError
}
l := int(data[0])<<8 | int(data[1])
if l != length-2 {
return alertDecodeError
}
d := data[2:length]
for len(d) != 0 {
stringLen := int(d[0])
d = d[1:]
if stringLen == 0 || stringLen > len(d) {
return alertDecodeError
}
m.alpnProtocols = append(m.alpnProtocols, string(d[:stringLen]))
d = d[stringLen:]
}
case extensionSCT:
m.scts = true
if length != 0 {
return alertDecodeError
}
case extensionKeyShare:
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.5
if length < 2 {
return alertDecodeError
}
l := int(data[0])<<8 | int(data[1])
if l != length-2 {
return alertDecodeError
}
d := data[2:length]
for len(d) != 0 {
if len(d) < 4 {
return alertDecodeError
}
dataLen := int(d[2])<<8 | int(d[3])
if dataLen == 0 || 4+dataLen > len(d) {
return alertDecodeError
}
m.keyShares = append(m.keyShares, keyShare{
group: CurveID(d[0])<<8 | CurveID(d[1]),
data: d[4 : 4+dataLen],
})
d = d[4+dataLen:]
}
case extensionSupportedVersions:
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.1
if length < 1 {
return alertDecodeError
}
l := int(data[0])
if l%2 == 1 || length != l+1 {
return alertDecodeError
}
n := l / 2
d := data[1:]
for i := 0; i < n; i++ {
v := uint16(d[0])<<8 + uint16(d[1])
m.supportedVersions = append(m.supportedVersions, v)
d = d[2:]
}
case extensionPreSharedKey:
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.6
if length < 2 {
return alertDecodeError
}
// Ensure this extension is the last one in the Client Hello
if len(data) != length {
return alertIllegalParameter
}
li := int(data[0])<<8 | int(data[1])
if 2+li+2 > length {
return alertDecodeError
}
d := data[2 : 2+li]
bindersOffset += 2 + li
for len(d) > 0 {
if len(d) < 6 {
return alertDecodeError
}
l := int(d[0])<<8 | int(d[1])
if len(d) < 2+l+4 {
return alertDecodeError
}
m.psks = append(m.psks, psk{
identity: d[2 : 2+l],
obfTicketAge: uint32(d[l+2])<<24 | uint32(d[l+3])<<16 |
uint32(d[l+4])<<8 | uint32(d[l+5]),
})
d = d[2+l+4:]
}
lb := int(data[li+2])<<8 | int(data[li+3])
d = data[2+li+2:]
if lb != len(d) || lb == 0 {
return alertDecodeError
}
i := 0
for len(d) > 0 {
if i >= len(m.psks) {
return alertIllegalParameter
}
if len(d) < 1 {
return alertDecodeError
}
l := int(d[0])
if l > len(d)-1 {
return alertDecodeError
}
if i >= len(m.psks) {
return alertIllegalParameter
}
m.psks[i].binder = d[1 : 1+l]
d = d[1+l:]
i++
}
if i != len(m.psks) {
return alertIllegalParameter
}
m.rawTruncated = m.raw[:bindersOffset]
case extensionPSKKeyExchangeModes:
if length < 2 {
return alertDecodeError
}
l := int(data[0])
if length != l+1 {
return alertDecodeError
}
m.pskKeyExchangeModes = data[1:length]
case extensionEarlyData:
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.8
m.earlyData = true
case extensionDelegatedCredential:
// https://tools.ietf.org/html/draft-ietf-tls-subcerts-02
m.delegatedCredential = true
case extensionEMS:
// RFC 7627
m.extendedMSSupported = true
if length != 0 {
return alertDecodeError
}
}
data = data[length:]
bindersOffset += length
}
return alertSuccess
}
func (m *clientHelloMsg) getSignatureAlgorithmsCert() []SignatureScheme {
return signAlgosCertList(m.supportedSignatureAlgorithms, m.supportedSignatureAlgorithmsCert)
}
type serverHelloMsg struct {
raw []byte
vers uint16
random []byte
sessionId []byte
cipherSuite uint16
compressionMethod uint8
nextProtoNeg bool
nextProtos []string
ocspStapling bool
scts [][]byte
ticketSupported bool
secureRenegotiation []byte
secureRenegotiationSupported bool
alpnProtocol string
// TLS 1.3
keyShare keyShare
psk bool
pskIdentity uint16
// RFC7627
extendedMSSupported bool
}
func (m *serverHelloMsg) equal(i interface{}) bool {
m1, ok := i.(*serverHelloMsg)
if !ok {
return false
}
if len(m.scts) != len(m1.scts) {
return false
}
for i, sct := range m.scts {
if !bytes.Equal(sct, m1.scts[i]) {
return false
}
}
return bytes.Equal(m.raw, m1.raw) &&
m.vers == m1.vers &&
bytes.Equal(m.random, m1.random) &&
bytes.Equal(m.sessionId, m1.sessionId) &&
m.cipherSuite == m1.cipherSuite &&
m.compressionMethod == m1.compressionMethod &&
m.nextProtoNeg == m1.nextProtoNeg &&
eqStrings(m.nextProtos, m1.nextProtos) &&
m.ocspStapling == m1.ocspStapling &&
m.ticketSupported == m1.ticketSupported &&
m.secureRenegotiationSupported == m1.secureRenegotiationSupported &&
bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
m.alpnProtocol == m1.alpnProtocol &&
m.keyShare.group == m1.keyShare.group &&
bytes.Equal(m.keyShare.data, m1.keyShare.data) &&
m.psk == m1.psk &&
m.pskIdentity == m1.pskIdentity &&
m.extendedMSSupported == m1.extendedMSSupported
}
func (m *serverHelloMsg) marshal() []byte {
if m.raw != nil {
return m.raw
}
length := 38 + len(m.sessionId)
numExtensions := 0
extensionsLength := 0
nextProtoLen := 0
if m.nextProtoNeg {
numExtensions++
for _, v := range m.nextProtos {
nextProtoLen += len(v)
}
nextProtoLen += len(m.nextProtos)
extensionsLength += nextProtoLen
}
if m.ocspStapling {
numExtensions++
}
if m.ticketSupported {
numExtensions++
}
if m.secureRenegotiationSupported {
extensionsLength += 1 + len(m.secureRenegotiation)
numExtensions++
}
if m.extendedMSSupported {
numExtensions++
}
if alpnLen := len(m.alpnProtocol); alpnLen > 0 {
if alpnLen >= 256 {
panic("invalid ALPN protocol")
}
extensionsLength += 2 + 1 + alpnLen
numExtensions++
}
sctLen := 0
if len(m.scts) > 0 {
for _, sct := range m.scts {
sctLen += len(sct) + 2
}
extensionsLength += 2 + sctLen
numExtensions++
}
if m.keyShare.group != 0 {
extensionsLength += 4 + len(m.keyShare.data)
numExtensions++
}
if m.psk {
extensionsLength += 2
numExtensions++
}
// supported_versions extension
if m.vers >= VersionTLS13 {
extensionsLength += 2
numExtensions++
}
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
}
x := make([]byte, 4+length)
x[0] = typeServerHello
x[1] = uint8(length >> 16)
x[2] = uint8(length >> 8)
x[3] = uint8(length)
if m.vers >= VersionTLS13 {
x[4] = 3
x[5] = 3
} else {
x[4] = uint8(m.vers >> 8)
x[5] = uint8(m.vers)
}
copy(x[6:38], m.random)
z := x[38:]
x[38] = uint8(len(m.sessionId))
copy(x[39:39+len(m.sessionId)], m.sessionId)
z = x[39+len(m.sessionId):]
z[0] = uint8(m.cipherSuite >> 8)
z[1] = uint8(m.cipherSuite)
z[2] = m.compressionMethod
z = z[3:]
if numExtensions > 0 {
z[0] = byte(extensionsLength >> 8)
z[1] = byte(extensionsLength)
z = z[2:]
}
if m.vers >= VersionTLS13 {
z[0] = byte(extensionSupportedVersions >> 8)
z[1] = byte(extensionSupportedVersions)
z[3] = 2
z[4] = uint8(m.vers >> 8)
z[5] = uint8(m.vers)
z = z[6:]
}
if m.nextProtoNeg {
z[0] = byte(extensionNextProtoNeg >> 8)
z[1] = byte(extensionNextProtoNeg & 0xff)
z[2] = byte(nextProtoLen >> 8)
z[3] = byte(nextProtoLen)
z = z[4:]
for _, v := range m.nextProtos {
l := len(v)
if l > 255 {
l = 255
}
z[0] = byte(l)
copy(z[1:], []byte(v[0:l]))
z = z[1+l:]
}
}
if m.ocspStapling {
z[0] = byte(extensionStatusRequest >> 8)
z[1] = byte(extensionStatusRequest)
z = z[4:]
}
if m.ticketSupported {
z[0] = byte(extensionSessionTicket >> 8)
z[1] = byte(extensionSessionTicket)
z = z[4:]
}
if m.secureRenegotiationSupported {
z[0] = byte(extensionRenegotiationInfo >> 8)
z[1] = byte(extensionRenegotiationInfo & 0xff)
z[2] = 0
z[3] = byte(len(m.secureRenegotiation) + 1)
z[4] = byte(len(m.secureRenegotiation))
z = z[5:]
copy(z, m.secureRenegotiation)
z = z[len(m.secureRenegotiation):]
}
if alpnLen := len(m.alpnProtocol); alpnLen > 0 {
z[0] = byte(extensionALPN >> 8)
z[1] = byte(extensionALPN & 0xff)
l := 2 + 1 + alpnLen
z[2] = byte(l >> 8)
z[3] = byte(l)
l -= 2
z[4] = byte(l >> 8)
z[5] = byte(l)
l -= 1
z[6] = byte(l)
copy(z[7:], []byte(m.alpnProtocol))
z = z[7+alpnLen:]
}
if sctLen > 0 {
z[0] = byte(extensionSCT >> 8)
z[1] = byte(extensionSCT)
l := sctLen + 2
z[2] = byte(l >> 8)
z[3] = byte(l)
z[4] = byte(sctLen >> 8)
z[5] = byte(sctLen)
z = z[6:]
for _, sct := range m.scts {
z[0] = byte(len(sct) >> 8)
z[1] = byte(len(sct))
copy(z[2:], sct)
z = z[len(sct)+2:]
}
}
if m.keyShare.group != 0 {
z[0] = uint8(extensionKeyShare >> 8)
z[1] = uint8(extensionKeyShare)
l := 4 + len(m.keyShare.data)
z[2] = uint8(l >> 8)
z[3] = uint8(l)
z[4] = uint8(m.keyShare.group >> 8)
z[5] = uint8(m.keyShare.group)
l -= 4
z[6] = uint8(l >> 8)
z[7] = uint8(l)
copy(z[8:], m.keyShare.data)
z = z[8+l:]
}
if m.psk {
z[0] = byte(extensionPreSharedKey >> 8)
z[1] = byte(extensionPreSharedKey)
z[3] = 2
z[4] = byte(m.pskIdentity >> 8)
z[5] = byte(m.pskIdentity)
z = z[6:]
}
if m.extendedMSSupported {
binary.BigEndian.PutUint16(z, extensionEMS)
z = z[4:]
}
m.raw = x
return x
}
func (m *serverHelloMsg) unmarshal(data []byte) alert {
if len(data) < 42 {
return alertDecodeError
}
m.raw = data
m.vers = uint16(data[4])<<8 | uint16(data[5])
m.random = data[6:38]
sessionIdLen := int(data[38])
if sessionIdLen > 32 || len(data) < 39+sessionIdLen {
return alertDecodeError
}
m.sessionId = data[39 : 39+sessionIdLen]
data = data[39+sessionIdLen:]
if len(data) < 3 {
return alertDecodeError
}
m.cipherSuite = uint16(data[0])<<8 | uint16(data[1])
m.compressionMethod = data[2]
data = data[3:]
m.nextProtoNeg = false
m.nextProtos = nil
m.ocspStapling = false
m.scts = nil
m.ticketSupported = false
m.alpnProtocol = ""
m.keyShare.group = 0
m.keyShare.data = nil
m.psk = false
m.pskIdentity = 0
m.extendedMSSupported = false
if len(data) == 0 {
// ServerHello is optionally followed by extension data
return alertSuccess
}
if len(data) < 2 {
return alertDecodeError
}
extensionsLength := int(data[0])<<8 | int(data[1])
data = data[2:]
if len(data) != extensionsLength {
return alertDecodeError
}
svData := findExtension(data, extensionSupportedVersions)
if svData != nil {
if len(svData) != 2 {
return alertDecodeError
}
if m.vers != VersionTLS12 {
return alertDecodeError
}
rcvVer := binary.BigEndian.Uint16(svData[0:])
if rcvVer < VersionTLS13 {
return alertIllegalParameter
}
m.vers = rcvVer
}
for len(data) != 0 {
if len(data) < 4 {
return alertDecodeError
}
extension := uint16(data[0])<<8 | uint16(data[1])
length := int(data[2])<<8 | int(data[3])
data = data[4:]
if len(data) < length {
return alertDecodeError
}
switch extension {
case extensionNextProtoNeg:
m.nextProtoNeg = true
d := data[:length]
for len(d) > 0 {
l := int(d[0])
d = d[1:]
if l == 0 || l > len(d) {
return alertDecodeError
}
m.nextProtos = append(m.nextProtos, string(d[:l]))
d = d[l:]
}
case extensionStatusRequest:
if length > 0 {
return alertDecodeError
}
m.ocspStapling = true
case extensionSessionTicket:
if length > 0 {
return alertDecodeError
}
m.ticketSupported = true
case extensionRenegotiationInfo:
if length == 0 {
return alertDecodeError
}
d := data[:length]
l := int(d[0])
d = d[1:]
if l != len(d) {
return alertDecodeError
}
m.secureRenegotiation = d
m.secureRenegotiationSupported = true
case extensionALPN:
d := data[:length]
if len(d) < 3 {
return alertDecodeError
}
l := int(d[0])<<8 | int(d[1])
if l != len(d)-2 {
return alertDecodeError
}
d = d[2:]
l = int(d[0])
if l != len(d)-1 {
return alertDecodeError
}
d = d[1:]
if len(d) == 0 {
// ALPN protocols must not be empty.
return alertDecodeError
}
m.alpnProtocol = string(d)
case extensionSCT:
d := data[:length]
if len(d) < 2 {
return alertDecodeError
}
l := int(d[0])<<8 | int(d[1])
d = d[2:]
if len(d) != l || l == 0 {
return alertDecodeError
}
m.scts = make([][]byte, 0, 3)
for len(d) != 0 {
if len(d) < 2 {
return alertDecodeError
}
sctLen := int(d[0])<<8 | int(d[1])
d = d[2:]
if sctLen == 0 || len(d) < sctLen {
return alertDecodeError
}
m.scts = append(m.scts, d[:sctLen])
d = d[sctLen:]
}
case extensionKeyShare:
d := data[:length]
if len(d) < 4 {
return alertDecodeError
}
m.keyShare.group = CurveID(d[0])<<8 | CurveID(d[1])
l := int(d[2])<<8 | int(d[3])
d = d[4:]
if len(d) != l {
return alertDecodeError
}
m.keyShare.data = d[:l]
case extensionPreSharedKey:
if length != 2 {
return alertDecodeError
}
m.psk = true
m.pskIdentity = uint16(data[0])<<8 | uint16(data[1])
case extensionEMS:
m.extendedMSSupported = true
}
data = data[length:]
}
return alertSuccess
}
type encryptedExtensionsMsg struct {
raw []byte
alpnProtocol string
earlyData bool
}
func (m *encryptedExtensionsMsg) equal(i interface{}) bool {
m1, ok := i.(*encryptedExtensionsMsg)
if !ok {
return false
}
return bytes.Equal(m.raw, m1.raw) &&
m.alpnProtocol == m1.alpnProtocol &&
m.earlyData == m1.earlyData
}
func (m *encryptedExtensionsMsg) marshal() []byte {
if m.raw != nil {
return m.raw
}
length := 2
if m.earlyData {
length += 4
}
alpnLen := len(m.alpnProtocol)
if alpnLen > 0 {
if alpnLen >= 256 {
panic("invalid ALPN protocol")
}
length += 2 + 2 + 2 + 1 + alpnLen
}
x := make([]byte, 4+length)
x[0] = typeEncryptedExtensions
x[1] = uint8(length >> 16)
x[2] = uint8(length >> 8)
x[3] = uint8(length)
length -= 2
x[4] = uint8(length >> 8)
x[5] = uint8(length)
z := x[6:]
if alpnLen > 0 {
z[0] = byte(extensionALPN >> 8)
z[1] = byte(extensionALPN)
l := 2 + 1 + alpnLen
z[2] = byte(l >> 8)
z[3] = byte(l)
l -= 2
z[4] = byte(l >> 8)
z[5] = byte(l)
l -= 1
z[6] = byte(l)
copy(z[7:], []byte(m.alpnProtocol))
z = z[7+alpnLen:]
}
if m.earlyData {
z[0] = byte(extensionEarlyData >> 8)
z[1] = byte(extensionEarlyData)
z = z[4:]
}
m.raw = x
return x
}
func (m *encryptedExtensionsMsg) unmarshal(data []byte) alert {
if len(data) < 6 {
return alertDecodeError
}
m.raw = data
m.alpnProtocol = ""
m.earlyData = false
extensionsLength := int(data[4])<<8 | int(data[5])
data = data[6:]
if len(data) != extensionsLength {
return alertDecodeError
}
for len(data) != 0 {
if len(data) < 4 {
return alertDecodeError
}
extension := uint16(data[0])<<8 | uint16(data[1])
length := int(data[2])<<8 | int(data[3])
data = data[4:]
if len(data) < length {
return alertDecodeError
}
switch extension {
case extensionALPN:
d := data[:length]
if len(d) < 3 {
return alertDecodeError
}
l := int(d[0])<<8 | int(d[1])
if l != len(d)-2 {
return alertDecodeError
}
d = d[2:]
l = int(d[0])
if l != len(d)-1 {
return alertDecodeError
}
d = d[1:]
if len(d) == 0 {
// ALPN protocols must not be empty.
return alertDecodeError
}
m.alpnProtocol = string(d)
case extensionEarlyData:
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.8
m.earlyData = true
}
data = data[length:]
}
return alertSuccess
}
type certificateMsg struct {
raw []byte
certificates [][]byte
}
func (m *certificateMsg) equal(i interface{}) bool {
m1, ok := i.(*certificateMsg)
if !ok {
return false
}
return bytes.Equal(m.raw, m1.raw) &&
eqByteSlices(m.certificates, m1.certificates)
}
func (m *certificateMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
}
var i int
for _, slice := range m.certificates {
i += len(slice)
}
length := 3 + 3*len(m.certificates) + i
x = make([]byte, 4+length)
x[0] = typeCertificate
x[1] = uint8(length >> 16)
x[2] = uint8(length >> 8)
x[3] = uint8(length)
certificateOctets := length - 3
x[4] = uint8(certificateOctets >> 16)
x[5] = uint8(certificateOctets >> 8)
x[6] = uint8(certificateOctets)
y := x[7:]
for _, slice := range m.certificates {
y[0] = uint8(len(slice) >> 16)
y[1] = uint8(len(slice) >> 8)
y[2] = uint8(len(slice))
copy(y[3:], slice)
y = y[3+len(slice):]
}
m.raw = x
return
}
func (m *certificateMsg) unmarshal(data []byte) alert {
if len(data) < 7 {
return alertDecodeError
}
m.raw = data
certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6])
if uint32(len(data)) != certsLen+7 {
return alertDecodeError
}
numCerts := 0
d := data[7:]
for certsLen > 0 {
if len(d) < 4 {
return alertDecodeError
}
certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
if uint32(len(d)) < 3+certLen {
return alertDecodeError
}
d = d[3+certLen:]
certsLen -= 3 + certLen
numCerts++
}
m.certificates = make([][]byte, numCerts)
d = data[7:]
for i := 0; i < numCerts; i++ {
certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
m.certificates[i] = d[3 : 3+certLen]
d = d[3+certLen:]
}
return alertSuccess
}
type certificateEntry struct {
data []byte
ocspStaple []byte
sctList [][]byte
delegatedCredential []byte
}
type certificateMsg13 struct {
raw []byte
requestContext []byte
certificates []certificateEntry
}
func (m *certificateMsg13) equal(i interface{}) bool {
m1, ok := i.(*certificateMsg13)
if !ok {
return false
}
if len(m.certificates) != len(m1.certificates) {
return false
}
for i, _ := range m.certificates {
ok := bytes.Equal(m.certificates[i].data, m1.certificates[i].data)
ok = ok && bytes.Equal(m.certificates[i].ocspStaple, m1.certificates[i].ocspStaple)
ok = ok && eqByteSlices(m.certificates[i].sctList, m1.certificates[i].sctList)
ok = ok && bytes.Equal(m.certificates[i].delegatedCredential, m1.certificates[i].delegatedCredential)
if !ok {
return false
}
}
return bytes.Equal(m.raw, m1.raw) &&
bytes.Equal(m.requestContext, m1.requestContext)
}
func (m *certificateMsg13) marshal() (x []byte) {
if m.raw != nil {
return m.raw
}
var i int
for _, cert := range m.certificates {
i += len(cert.data)
if len(cert.ocspStaple) != 0 {
i += 8 + len(cert.ocspStaple)
}
if len(cert.sctList) != 0 {
i += 6
for _, sct := range cert.sctList {
i += 2 + len(sct)
}
}
if len(cert.delegatedCredential) != 0 {
i += 4 + len(cert.delegatedCredential)
}
}
length := 3 + 3*len(m.certificates) + i
length += 2 * len(m.certificates) // extensions
length += 1 + len(m.requestContext)
x = make([]byte, 4+length)
x[0] = typeCertificate
x[1] = uint8(length >> 16)
x[2] = uint8(length >> 8)
x[3] = uint8(length)
z := x[4:]
z[0] = byte(len(m.requestContext))
copy(z[1:], m.requestContext)
z = z[1+len(m.requestContext):]
certificateOctets := len(z) - 3
z[0] = uint8(certificateOctets >> 16)
z[1] = uint8(certificateOctets >> 8)
z[2] = uint8(certificateOctets)
z = z[3:]
for _, cert := range m.certificates {
z[0] = uint8(len(cert.data) >> 16)
z[1] = uint8(len(cert.data) >> 8)
z[2] = uint8(len(cert.data))
copy(z[3:], cert.data)
z = z[3+len(cert.data):]
extLenPos := z[:2]
z = z[2:]
extensionLen := 0
if len(cert.ocspStaple) != 0 {
stapleLen := 4 + len(cert.ocspStaple)
z[0] = uint8(extensionStatusRequest >> 8)
z[1] = uint8(extensionStatusRequest)
z[2] = uint8(stapleLen >> 8)
z[3] = uint8(stapleLen)
stapleLen -= 4
z[4] = statusTypeOCSP
z[5] = uint8(stapleLen >> 16)
z[6] = uint8(stapleLen >> 8)
z[7] = uint8(stapleLen)
copy(z[8:], cert.ocspStaple)
z = z[8+stapleLen:]
extensionLen += 8 + stapleLen
}
if len(cert.sctList) != 0 {
z[0] = uint8(extensionSCT >> 8)
z[1] = uint8(extensionSCT)
sctLenPos := z[2:6]
z = z[6:]
extensionLen += 6
sctLen := 2
for _, sct := range cert.sctList {
z[0] = uint8(len(sct) >> 8)
z[1] = uint8(len(sct))
copy(z[2:], sct)
z = z[2+len(sct):]
extensionLen += 2 + len(sct)
sctLen += 2 + len(sct)
}
sctLenPos[0] = uint8(sctLen >> 8)
sctLenPos[1] = uint8(sctLen)
sctLen -= 2
sctLenPos[2] = uint8(sctLen >> 8)
sctLenPos[3] = uint8(sctLen)
}
if len(cert.delegatedCredential) != 0 {
binary.BigEndian.PutUint16(z, extensionDelegatedCredential)
binary.BigEndian.PutUint16(z[2:], uint16(len(cert.delegatedCredential)))
z = z[4:]
copy(z, cert.delegatedCredential)
z = z[len(cert.delegatedCredential):]
extensionLen += 4 + len(cert.delegatedCredential)
}
extLenPos[0] = uint8(extensionLen >> 8)
extLenPos[1] = uint8(extensionLen)
}
m.raw = x
return
}
func (m *certificateMsg13) unmarshal(data []byte) alert {
if len(data) < 5 {
return alertDecodeError
}
m.raw = data
ctxLen := data[4]
if len(data) < int(ctxLen)+5+3 {
return alertDecodeError
}
m.requestContext = data[5 : 5+ctxLen]
d := data[5+ctxLen:]
certsLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
if uint32(len(d)) != certsLen+3 {
return alertDecodeError
}
numCerts := 0
d = d[3:]
for certsLen > 0 {
if len(d) < 4 {
return alertDecodeError
}
certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
if uint32(len(d)) < 3+certLen {
return alertDecodeError
}
d = d[3+certLen:]
if len(d) < 2 {
return alertDecodeError
}
extLen := uint16(d[0])<<8 | uint16(d[1])
if uint16(len(d)) < 2+extLen {
return alertDecodeError
}
d = d[2+extLen:]
certsLen -= 3 + certLen + 2 + uint32(extLen)
numCerts++
}
m.certificates = make([]certificateEntry, numCerts)
d = data[8+ctxLen:]
for i := 0; i < numCerts; i++ {
certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
m.certificates[i].data = d[3 : 3+certLen]
d = d[3+certLen:]
extLen := uint16(d[0])<<8 | uint16(d[1])
d = d[2:]
for extLen > 0 {
if extLen < 4 {
return alertDecodeError
}
typ := uint16(d[0])<<8 | uint16(d[1])
bodyLen := uint16(d[2])<<8 | uint16(d[3])
if extLen < 4+bodyLen {
return alertDecodeError
}
body := d[4 : 4+bodyLen]
d = d[4+bodyLen:]
extLen -= 4 + bodyLen
switch typ {
case extensionStatusRequest:
if len(body) < 4 || body[0] != 0x01 {
return alertDecodeError
}
ocspLen := int(body[1])<<16 | int(body[2])<<8 | int(body[3])
if len(body) != 4+ocspLen {
return alertDecodeError
}
m.certificates[i].ocspStaple = body[4:]
case extensionSCT:
if len(body) < 2 {
return alertDecodeError
}
listLen := int(body[0])<<8 | int(body[1])
body = body[2:]
if len(body) != listLen {
return alertDecodeError
}
for len(body) > 0 {
if len(body) < 2 {
return alertDecodeError
}
sctLen := int(body[0])<<8 | int(body[1])
if len(body) < 2+sctLen {
return alertDecodeError
}
m.certificates[i].sctList = append(m.certificates[i].sctList, body[2:2+sctLen])
body = body[2+sctLen:]
}
case extensionDelegatedCredential:
m.certificates[i].delegatedCredential = body
}
}
}
return alertSuccess
}
type serverKeyExchangeMsg struct {
raw []byte
key []byte
}
func (m *serverKeyExchangeMsg) equal(i interface{}) bool {
m1, ok := i.(*serverKeyExchangeMsg)
if !ok {
return false
}
return bytes.Equal(m.raw, m1.raw) &&
bytes.Equal(m.key, m1.key)
}
func (m *serverKeyExchangeMsg) marshal() []byte {
if m.raw != nil {
return m.raw
}
length := len(m.key)
x := make([]byte, length+4)
x[0] = typeServerKeyExchange
x[1] = uint8(length >> 16)
x[2] = uint8(length >> 8)
x[3] = uint8(length)
copy(x[4:], m.key)
m.raw = x
return x
}
func (m *serverKeyExchangeMsg) unmarshal(data []byte) alert {
m.raw = data
if len(data) < 4 {
return alertDecodeError
}
m.key = data[4:]
return alertSuccess
}
type certificateStatusMsg struct {
raw []byte
statusType uint8
response []byte
}
func (m *certificateStatusMsg) equal(i interface{}) bool {
m1, ok := i.(*certificateStatusMsg)
if !ok {
return false
}
return bytes.Equal(m.raw, m1.raw) &&
m.statusType == m1.statusType &&
bytes.Equal(m.response, m1.response)
}
func (m *certificateStatusMsg) marshal() []byte {
if m.raw != nil {
return m.raw
}
var x []byte
if m.statusType == statusTypeOCSP {
x = make([]byte, 4+4+len(m.response))
x[0] = typeCertificateStatus
l := len(m.response) + 4
x[1] = byte(l >> 16)
x[2] = byte(l >> 8)
x[3] = byte(l)
x[4] = statusTypeOCSP
l -= 4
x[5] = byte(l >> 16)
x[6] = byte(l >> 8)
x[7] = byte(l)
copy(x[8:], m.response)
} else {
x = []byte{typeCertificateStatus, 0, 0, 1, m.statusType}
}
m.raw = x
return x
}
func (m *certificateStatusMsg) unmarshal(data []byte) alert {
m.raw = data
if len(data) < 5 {
return alertDecodeError
}
m.statusType = data[4]
m.response = nil
if m.statusType == statusTypeOCSP {
if len(data) < 8 {
return alertDecodeError
}
respLen := uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7])
if uint32(len(data)) != 4+4+respLen {
return alertDecodeError
}
m.response = data[8:]
}
return alertSuccess
}
type serverHelloDoneMsg struct{}
func (m *serverHelloDoneMsg) equal(i interface{}) bool {
_, ok := i.(*serverHelloDoneMsg)
return ok
}
func (m *serverHelloDoneMsg) marshal() []byte {
x := make([]byte, 4)
x[0] = typeServerHelloDone
return x
}
func (m *serverHelloDoneMsg) unmarshal(data []byte) alert {
if len(data) != 4 {
return alertDecodeError
}
return alertSuccess
}
type clientKeyExchangeMsg struct {
raw []byte
ciphertext []byte
}
func (m *clientKeyExchangeMsg) equal(i interface{}) bool {
m1, ok := i.(*clientKeyExchangeMsg)
if !ok {
return false
}
return bytes.Equal(m.raw, m1.raw) &&
bytes.Equal(m.ciphertext, m1.ciphertext)
}
func (m *clientKeyExchangeMsg) marshal() []byte {
if m.raw != nil {
return m.raw
}
length := len(m.ciphertext)
x := make([]byte, length+4)
x[0] = typeClientKeyExchange
x[1] = uint8(length >> 16)
x[2] = uint8(length >> 8)
x[3] = uint8(length)
copy(x[4:], m.ciphertext)
m.raw = x
return x
}
func (m *clientKeyExchangeMsg) unmarshal(data []byte) alert {
m.raw = data
if len(data) < 4 {
return alertDecodeError
}
l := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
if l != len(data)-4 {
return alertDecodeError
}
m.ciphertext = data[4:]
return alertSuccess
}
type finishedMsg struct {
raw []byte
verifyData []byte
}
func (m *finishedMsg) equal(i interface{}) bool {
m1, ok := i.(*finishedMsg)
if !ok {
return false
}
return bytes.Equal(m.raw, m1.raw) &&
bytes.Equal(m.verifyData, m1.verifyData)
}
func (m *finishedMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
}
x = make([]byte, 4+len(m.verifyData))
x[0] = typeFinished
x[3] = byte(len(m.verifyData))
copy(x[4:], m.verifyData)
m.raw = x
return
}
func (m *finishedMsg) unmarshal(data []byte) alert {
m.raw = data
if len(data) < 4 {
return alertDecodeError
}
m.verifyData = data[4:]
return alertSuccess
}
type nextProtoMsg struct {
raw []byte
proto string
}
func (m *nextProtoMsg) equal(i interface{}) bool {
m1, ok := i.(*nextProtoMsg)
if !ok {
return false
}
return bytes.Equal(m.raw, m1.raw) &&
m.proto == m1.proto
}
func (m *nextProtoMsg) marshal() []byte {
if m.raw != nil {
return m.raw
}
l := len(m.proto)
if l > 255 {
l = 255
}
padding := 32 - (l+2)%32
length := l + padding + 2
x := make([]byte, length+4)
x[0] = typeNextProtocol
x[1] = uint8(length >> 16)
x[2] = uint8(length >> 8)
x[3] = uint8(length)
y := x[4:]
y[0] = byte(l)
copy(y[1:], []byte(m.proto[0:l]))
y = y[1+l:]
y[0] = byte(padding)
m.raw = x
return x
}
func (m *nextProtoMsg) unmarshal(data []byte) alert {
m.raw = data
if len(data) < 5 {
return alertDecodeError
}
data = data[4:]
protoLen := int(data[0])
data = data[1:]
if len(data) < protoLen {
return alertDecodeError
}
m.proto = string(data[0:protoLen])
data = data[protoLen:]
if len(data) < 1 {
return alertDecodeError
}
paddingLen := int(data[0])
data = data[1:]
if len(data) != paddingLen {
return alertDecodeError
}
return alertSuccess
}
type certificateRequestMsg struct {
raw []byte
// hasSignatureAndHash indicates whether this message includes a list
// of signature and hash functions. This change was introduced with TLS
// 1.2.
hasSignatureAndHash bool
certificateTypes []byte
supportedSignatureAlgorithms []SignatureScheme
certificateAuthorities [][]byte
}
func (m *certificateRequestMsg) equal(i interface{}) bool {
m1, ok := i.(*certificateRequestMsg)
if !ok {
return false
}
return bytes.Equal(m.raw, m1.raw) &&
bytes.Equal(m.certificateTypes, m1.certificateTypes) &&
eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities) &&
eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms)
}
func (m *certificateRequestMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
}
// See http://tools.ietf.org/html/rfc4346#section-7.4.4
length := 1 + len(m.certificateTypes) + 2
casLength := 0
for _, ca := range m.certificateAuthorities {
casLength += 2 + len(ca)
}
length += casLength
if m.hasSignatureAndHash {
length += 2 + 2*len(m.supportedSignatureAlgorithms)
}
x = make([]byte, 4+length)
x[0] = typeCertificateRequest
x[1] = uint8(length >> 16)
x[2] = uint8(length >> 8)
x[3] = uint8(length)
x[4] = uint8(len(m.certificateTypes))
copy(x[5:], m.certificateTypes)
y := x[5+len(m.certificateTypes):]
if m.hasSignatureAndHash {
n := len(m.supportedSignatureAlgorithms) * 2
y[0] = uint8(n >> 8)
y[1] = uint8(n)
y = y[2:]
for _, sigAlgo := range m.supportedSignatureAlgorithms {
y[0] = uint8(sigAlgo >> 8)
y[1] = uint8(sigAlgo)
y = y[2:]
}
}
y[0] = uint8(casLength >> 8)
y[1] = uint8(casLength)
y = y[2:]
for _, ca := range m.certificateAuthorities {
y[0] = uint8(len(ca) >> 8)
y[1] = uint8(len(ca))
y = y[2:]
copy(y, ca)
y = y[len(ca):]
}
m.raw = x
return
}
func (m *certificateRequestMsg) unmarshal(data []byte) alert {
m.raw = data
if len(data) < 5 {
return alertDecodeError
}
length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
if uint32(len(data))-4 != length {
return alertDecodeError
}
numCertTypes := int(data[4])
data = data[5:]
if numCertTypes == 0 || len(data) <= numCertTypes {
return alertDecodeError
}
m.certificateTypes = make([]byte, numCertTypes)
if copy(m.certificateTypes, data) != numCertTypes {
return alertDecodeError
}
data = data[numCertTypes:]
if m.hasSignatureAndHash {
if len(data) < 2 {
return alertDecodeError
}
sigAndHashLen := uint16(data[0])<<8 | uint16(data[1])
data = data[2:]
if sigAndHashLen&1 != 0 {
return alertDecodeError
}
if len(data) < int(sigAndHashLen) {
return alertDecodeError
}
numSigAlgos := sigAndHashLen / 2
m.supportedSignatureAlgorithms = make([]SignatureScheme, numSigAlgos)
for i := range m.supportedSignatureAlgorithms {
m.supportedSignatureAlgorithms[i] = SignatureScheme(data[0])<<8 | SignatureScheme(data[1])
data = data[2:]
}
}
if len(data) < 2 {
return alertDecodeError
}
casLength := uint16(data[0])<<8 | uint16(data[1])
data = data[2:]
if len(data) < int(casLength) {
return alertDecodeError
}
cas := make([]byte, casLength)
copy(cas, data)
data = data[casLength:]
m.certificateAuthorities = nil
for len(cas) > 0 {
if len(cas) < 2 {
return alertDecodeError
}
caLen := uint16(cas[0])<<8 | uint16(cas[1])
cas = cas[2:]
if len(cas) < int(caLen) {
return alertDecodeError
}
m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen])
cas = cas[caLen:]
}
if len(data) != 0 {
return alertDecodeError
}
return alertSuccess
}
type certificateRequestMsg13 struct {
raw []byte
requestContext []byte
supportedSignatureAlgorithms []SignatureScheme
supportedSignatureAlgorithmsCert []SignatureScheme
certificateAuthorities [][]byte
}
func (m *certificateRequestMsg13) equal(i interface{}) bool {
m1, ok := i.(*certificateRequestMsg13)
return ok &&
bytes.Equal(m.raw, m1.raw) &&
bytes.Equal(m.requestContext, m1.requestContext) &&
eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities) &&
eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms) &&
eqSignatureAlgorithms(m.supportedSignatureAlgorithmsCert, m1.supportedSignatureAlgorithmsCert)
}
func (m *certificateRequestMsg13) marshal() (x []byte) {
if m.raw != nil {
return m.raw
}
// See https://tools.ietf.org/html/draft-ietf-tls-tls13-21#section-4.3.2
length := 1 + len(m.requestContext)
numExtensions := 1
extensionsLength := 2 + 2*len(m.supportedSignatureAlgorithms)
if m.getSignatureAlgorithmsCert() != nil {
numExtensions += 1
extensionsLength += 2 + 2*len(m.getSignatureAlgorithmsCert())
}
casLength := 0
if len(m.certificateAuthorities) > 0 {
for _, ca := range m.certificateAuthorities {
casLength += 2 + len(ca)
}
extensionsLength += 2 + casLength
numExtensions++
}
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
x = make([]byte, 4+length)
x[0] = typeCertificateRequest
x[1] = uint8(length >> 16)
x[2] = uint8(length >> 8)
x[3] = uint8(length)
x[4] = uint8(len(m.requestContext))
copy(x[5:], m.requestContext)
z := x[5+len(m.requestContext):]
z[0] = byte(extensionsLength >> 8)
z[1] = byte(extensionsLength)
z = z[2:]
// TODO: this function should be reused by CH
z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithms, z, m.supportedSignatureAlgorithms)
if m.getSignatureAlgorithmsCert() != nil {
z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithmsCert, z, m.getSignatureAlgorithmsCert())
}
// certificate_authorities
if casLength > 0 {
z[0] = byte(extensionCAs >> 8)
z[1] = byte(extensionCAs)
l := 2 + casLength
z[2] = byte(l >> 8)
z[3] = byte(l)
z = z[4:]
z[0] = uint8(casLength >> 8)
z[1] = uint8(casLength)
z = z[2:]
for _, ca := range m.certificateAuthorities {
z[0] = uint8(len(ca) >> 8)
z[1] = uint8(len(ca))
z = z[2:]
copy(z, ca)
z = z[len(ca):]
}
}
m.raw = x
return
}
func (m *certificateRequestMsg13) unmarshal(data []byte) alert {
m.raw = data
m.supportedSignatureAlgorithms = nil
m.certificateAuthorities = nil
if len(data) < 5 {
return alertDecodeError
}
length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
if uint32(len(data))-4 != length {
return alertDecodeError
}
ctxLen := data[4]
if len(data) < 5+int(ctxLen)+2 {
return alertDecodeError
}
m.requestContext = data[5 : 5+ctxLen]
data = data[5+ctxLen:]
extensionsLength := int(data[0])<<8 | int(data[1])
data = data[2:]
if len(data) != extensionsLength {
return alertDecodeError
}
for len(data) != 0 {
if len(data) < 4 {
return alertDecodeError
}
extension := uint16(data[0])<<8 | uint16(data[1])
length := int(data[2])<<8 | int(data[3])
data = data[4:]
if len(data) < length {
return alertDecodeError
}
switch extension {
case extensionSignatureAlgorithms:
// TODO: unmarshalExtensionSignatureAlgorithms should be shared with CH and pre-1.3 CV
// https://tools.ietf.org/html/draft-ietf-tls-tls13-21#section-4.2.3
var err alert
m.supportedSignatureAlgorithms, err = unmarshalExtensionSignatureAlgorithms(data, length)
if err != alertSuccess {
return err
}
case extensionSignatureAlgorithmsCert:
var err alert
m.supportedSignatureAlgorithmsCert, err = unmarshalExtensionSignatureAlgorithms(data, length)
if err != alertSuccess {
return err
}
case extensionCAs:
// TODO DRY: share code with CH
if length < 2 {
return alertDecodeError
}
l := int(data[0])<<8 | int(data[1])
if l != length-2 || l < 3 {
return alertDecodeError
}
cas := make([]byte, l)
copy(cas, data[2:])
m.certificateAuthorities = nil
for len(cas) > 0 {
if len(cas) < 2 {
return alertDecodeError
}
caLen := uint16(cas[0])<<8 | uint16(cas[1])
cas = cas[2:]
if len(cas) < int(caLen) {
return alertDecodeError
}
m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen])
cas = cas[caLen:]
}
}
data = data[length:]
}
if len(m.supportedSignatureAlgorithms) == 0 {
return alertDecodeError
}
return alertSuccess
}
func (m *certificateRequestMsg13) getSignatureAlgorithmsCert() []SignatureScheme {
return signAlgosCertList(m.supportedSignatureAlgorithms, m.supportedSignatureAlgorithmsCert)
}
type certificateVerifyMsg struct {
raw []byte
hasSignatureAndHash bool
signatureAlgorithm SignatureScheme
signature []byte
}
func (m *certificateVerifyMsg) equal(i interface{}) bool {
m1, ok := i.(*certificateVerifyMsg)
if !ok {
return false
}
return bytes.Equal(m.raw, m1.raw) &&
m.hasSignatureAndHash == m1.hasSignatureAndHash &&
m.signatureAlgorithm == m1.signatureAlgorithm &&
bytes.Equal(m.signature, m1.signature)
}
func (m *certificateVerifyMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
}
// See http://tools.ietf.org/html/rfc4346#section-7.4.8
siglength := len(m.signature)
length := 2 + siglength
if m.hasSignatureAndHash {
length += 2
}
x = make([]byte, 4+length)
x[0] = typeCertificateVerify
x[1] = uint8(length >> 16)
x[2] = uint8(length >> 8)
x[3] = uint8(length)
y := x[4:]
if m.hasSignatureAndHash {
y[0] = uint8(m.signatureAlgorithm >> 8)
y[1] = uint8(m.signatureAlgorithm)
y = y[2:]
}
y[0] = uint8(siglength >> 8)
y[1] = uint8(siglength)
copy(y[2:], m.signature)
m.raw = x
return
}
func (m *certificateVerifyMsg) unmarshal(data []byte) alert {
m.raw = data
if len(data) < 6 {
return alertDecodeError
}
length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
if uint32(len(data))-4 != length {
return alertDecodeError
}
data = data[4:]
if m.hasSignatureAndHash {
m.signatureAlgorithm = SignatureScheme(data[0])<<8 | SignatureScheme(data[1])
data = data[2:]
}
if len(data) < 2 {
return alertDecodeError
}
siglength := int(data[0])<<8 + int(data[1])
data = data[2:]
if len(data) != siglength {
return alertDecodeError
}
m.signature = data
return alertSuccess
}
type newSessionTicketMsg struct {
raw []byte
ticket []byte
}
func (m *newSessionTicketMsg) equal(i interface{}) bool {
m1, ok := i.(*newSessionTicketMsg)
if !ok {
return false
}
return bytes.Equal(m.raw, m1.raw) &&
bytes.Equal(m.ticket, m1.ticket)
}
func (m *newSessionTicketMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
}
// See http://tools.ietf.org/html/rfc5077#section-3.3
ticketLen := len(m.ticket)
length := 2 + 4 + ticketLen
x = make([]byte, 4+length)
x[0] = typeNewSessionTicket
x[1] = uint8(length >> 16)
x[2] = uint8(length >> 8)
x[3] = uint8(length)
x[8] = uint8(ticketLen >> 8)
x[9] = uint8(ticketLen)
copy(x[10:], m.ticket)
m.raw = x
return
}
func (m *newSessionTicketMsg) unmarshal(data []byte) alert {
m.raw = data
if len(data) < 10 {
return alertDecodeError
}
length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
if uint32(len(data))-4 != length {
return alertDecodeError
}
ticketLen := int(data[8])<<8 + int(data[9])
if len(data)-10 != ticketLen {
return alertDecodeError
}
m.ticket = data[10:]
return alertSuccess
}
type newSessionTicketMsg13 struct {
raw []byte
lifetime uint32
ageAdd uint32
nonce []byte
ticket []byte
withEarlyDataInfo bool
maxEarlyDataLength uint32
}
func (m *newSessionTicketMsg13) equal(i interface{}) bool {
m1, ok := i.(*newSessionTicketMsg13)
if !ok {
return false
}
return bytes.Equal(m.raw, m1.raw) &&
m.lifetime == m1.lifetime &&
m.ageAdd == m1.ageAdd &&
bytes.Equal(m.nonce, m1.nonce) &&
bytes.Equal(m.ticket, m1.ticket) &&
m.withEarlyDataInfo == m1.withEarlyDataInfo &&
m.maxEarlyDataLength == m1.maxEarlyDataLength
}
func (m *newSessionTicketMsg13) marshal() (x []byte) {
if m.raw != nil {
return m.raw
}
// See https://tools.ietf.org/html/draft-ietf-tls-tls13-21#section-4.6.1
nonceLen := len(m.nonce)
ticketLen := len(m.ticket)
length := 13 + nonceLen + ticketLen
if m.withEarlyDataInfo {
length += 8
}
x = make([]byte, 4+length)
x[0] = typeNewSessionTicket
x[1] = uint8(length >> 16)
x[2] = uint8(length >> 8)
x[3] = uint8(length)
x[4] = uint8(m.lifetime >> 24)
x[5] = uint8(m.lifetime >> 16)
x[6] = uint8(m.lifetime >> 8)
x[7] = uint8(m.lifetime)
x[8] = uint8(m.ageAdd >> 24)
x[9] = uint8(m.ageAdd >> 16)
x[10] = uint8(m.ageAdd >> 8)
x[11] = uint8(m.ageAdd)
x[12] = uint8(nonceLen)
copy(x[13:13+nonceLen], m.nonce)
y := x[13+nonceLen:]
y[0] = uint8(ticketLen >> 8)
y[1] = uint8(ticketLen)
copy(y[2:2+ticketLen], m.ticket)
if m.withEarlyDataInfo {
z := y[2+ticketLen:]
// z[0] is already 0, this is the extensions vector length.
z[1] = 8
z[2] = uint8(extensionEarlyData >> 8)
z[3] = uint8(extensionEarlyData)
z[5] = 4
z[6] = uint8(m.maxEarlyDataLength >> 24)
z[7] = uint8(m.maxEarlyDataLength >> 16)
z[8] = uint8(m.maxEarlyDataLength >> 8)
z[9] = uint8(m.maxEarlyDataLength)
}
m.raw = x
return
}
func (m *newSessionTicketMsg13) unmarshal(data []byte) alert {
m.raw = data
m.maxEarlyDataLength = 0
m.withEarlyDataInfo = false
if len(data) < 17 {
return alertDecodeError
}
length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
if uint32(len(data))-4 != length {
return alertDecodeError
}
m.lifetime = uint32(data[4])<<24 | uint32(data[5])<<16 |
uint32(data[6])<<8 | uint32(data[7])
m.ageAdd = uint32(data[8])<<24 | uint32(data[9])<<16 |
uint32(data[10])<<8 | uint32(data[11])
nonceLen := int(data[12])
if nonceLen == 0 || 13+nonceLen+2 > len(data) {
return alertDecodeError
}
m.nonce = data[13 : 13+nonceLen]
data = data[13+nonceLen:]
ticketLen := int(data[0])<<8 + int(data[1])
if ticketLen == 0 || 2+ticketLen+2 > len(data) {
return alertDecodeError
}
m.ticket = data[2 : 2+ticketLen]
data = data[2+ticketLen:]
extLen := int(data[0])<<8 + int(data[1])
if extLen != len(data)-2 {
return alertDecodeError
}
data = data[2:]
for len(data) > 0 {
if len(data) < 4 {
return alertDecodeError
}
extType := uint16(data[0])<<8 + uint16(data[1])
length := int(data[2])<<8 + int(data[3])
data = data[4:]
switch extType {
case extensionEarlyData:
if length != 4 {
return alertDecodeError
}
m.withEarlyDataInfo = true
m.maxEarlyDataLength = uint32(data[0])<<24 | uint32(data[1])<<16 |
uint32(data[2])<<8 | uint32(data[3])
}
data = data[length:]
}
return alertSuccess
}
type endOfEarlyDataMsg struct {
}
func (*endOfEarlyDataMsg) marshal() []byte {
return []byte{typeEndOfEarlyData, 0, 0, 0}
}
func (*endOfEarlyDataMsg) unmarshal(data []byte) alert {
if len(data) != 4 {
return alertDecodeError
}
return alertSuccess
}
type helloRequestMsg struct {
}
func (*helloRequestMsg) marshal() []byte {
return []byte{typeHelloRequest, 0, 0, 0}
}
func (*helloRequestMsg) unmarshal(data []byte) alert {
if len(data) != 4 {
return alertDecodeError
}
return alertSuccess
}
func eqUint16s(x, y []uint16) bool {
if len(x) != len(y) {
return false
}
for i, v := range x {
if y[i] != v {
return false
}
}
return true
}
func eqCurveIDs(x, y []CurveID) bool {
if len(x) != len(y) {
return false
}
for i, v := range x {
if y[i] != v {
return false
}
}
return true
}
func eqStrings(x, y []string) bool {
if len(x) != len(y) {
return false
}
for i, v := range x {
if y[i] != v {
return false
}
}
return true
}
func eqByteSlices(x, y [][]byte) bool {
if len(x) != len(y) {
return false
}
for i, v := range x {
if !bytes.Equal(v, y[i]) {
return false
}
}
return true
}
func eqSignatureAlgorithms(x, y []SignatureScheme) bool {
if len(x) != len(y) {
return false
}
for i, v := range x {
if v != y[i] {
return false
}
}
return true
}
func eqKeyShares(x, y []keyShare) bool {
if len(x) != len(y) {
return false
}
for i := range x {
if x[i].group != y[i].group {
return false
}
if !bytes.Equal(x[i].data, y[i].data) {
return false
}
}
return true
}
func findExtension(data []byte, extensionType uint16) []byte {
for len(data) != 0 {
if len(data) < 4 {
return nil
}
extension := uint16(data[0])<<8 | uint16(data[1])
length := int(data[2])<<8 | int(data[3])
data = data[4:]
if len(data) < length {
return nil
}
if extension == extensionType {
return data[:length]
}
data = data[length:]
}
return nil
}