safing-portmaster/firewall/inspection/tls/tlslib/handshake_messages.go
2018-08-13 14:14:27 +02:00

1568 lines
33 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 tlslib
import (
"bytes"
"strings"
)
type ClientHelloMsg struct {
Raw []byte
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
SignatureAndHashes []signatureAndHash
SecureRenegotiation []byte
SecureRenegotiationSupported bool
AlpnProtocols []string
}
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) &&
eqSignatureAndHashes(m.SignatureAndHashes, m1.SignatureAndHashes) &&
m.SecureRenegotiationSupported == m1.SecureRenegotiationSupported &&
bytes.Equal(m.SecureRenegotiation, m1.SecureRenegotiation) &&
eqStrings(m.AlpnProtocols, m1.AlpnProtocols)
}
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.SignatureAndHashes) > 0 {
extensionsLength += 2 + 2*len(m.SignatureAndHashes)
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 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
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.SignatureAndHashes) > 0 {
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
z[0] = byte(extensionSignatureAlgorithms >> 8)
z[1] = byte(extensionSignatureAlgorithms)
l := 2 + 2*len(m.SignatureAndHashes)
z[2] = byte(l >> 8)
z[3] = byte(l)
z = z[4:]
l -= 2
z[0] = byte(l >> 8)
z[1] = byte(l)
z = z[2:]
for _, sigAndHash := range m.SignatureAndHashes {
z[0] = sigAndHash.hash
z[1] = sigAndHash.signature
z = z[2:]
}
}
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:]
}
m.Raw = x
return x
}
func (m *ClientHelloMsg) Unmarshal(data []byte) bool {
if len(data) < 42 {
return false
}
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 false
}
m.SessionId = data[39 : 39+sessionIdLen]
data = data[39+sessionIdLen:]
if len(data) < 2 {
return false
}
// 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 false
}
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:]
if len(data) < 1 {
return false
}
compressionMethodsLen := int(data[0])
if len(data) < 1+compressionMethodsLen {
return false
}
m.CompressionMethods = data[1 : 1+compressionMethodsLen]
data = data[1+compressionMethodsLen:]
m.NextProtoNeg = false
m.ServerName = ""
m.OcspStapling = false
m.TicketSupported = false
m.SessionTicket = nil
m.SignatureAndHashes = nil
m.AlpnProtocols = nil
m.Scts = false
if len(data) == 0 {
// ClientHello is optionally followed by extension data
return true
}
if len(data) < 2 {
return false
}
extensionsLength := int(data[0])<<8 | int(data[1])
data = data[2:]
if extensionsLength != len(data) {
return false
}
for len(data) != 0 {
if len(data) < 4 {
return false
}
extension := uint16(data[0])<<8 | uint16(data[1])
length := int(data[2])<<8 | int(data[3])
data = data[4:]
if len(data) < length {
return false
}
switch extension {
case extensionServerName:
d := data[:length]
if len(d) < 2 {
return false
}
namesLen := int(d[0])<<8 | int(d[1])
d = d[2:]
if len(d) != namesLen {
return false
}
for len(d) > 0 {
if len(d) < 3 {
return false
}
nameType := d[0]
nameLen := int(d[1])<<8 | int(d[2])
d = d[3:]
if len(d) < nameLen {
return false
}
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, ".") {
return false
}
break
}
d = d[nameLen:]
}
case extensionNextProtoNeg:
if length > 0 {
return false
}
m.NextProtoNeg = true
case extensionStatusRequest:
m.OcspStapling = length > 0 && data[0] == statusTypeOCSP
case extensionSupportedCurves:
// http://tools.ietf.org/html/rfc4492#section-5.5.1
if length < 2 {
return false
}
l := int(data[0])<<8 | int(data[1])
if l%2 == 1 || length != l+2 {
return false
}
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 false
}
l := int(data[0])
if length != l+1 {
return false
}
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
if length < 2 || length&1 != 0 {
return false
}
l := int(data[0])<<8 | int(data[1])
if l != length-2 {
return false
}
n := l / 2
d := data[2:]
m.SignatureAndHashes = make([]signatureAndHash, n)
for i := range m.SignatureAndHashes {
m.SignatureAndHashes[i].hash = d[0]
m.SignatureAndHashes[i].signature = d[1]
d = d[2:]
}
case extensionRenegotiationInfo:
if length == 0 {
return false
}
d := data[:length]
l := int(d[0])
d = d[1:]
if l != len(d) {
return false
}
m.SecureRenegotiation = d
m.SecureRenegotiationSupported = true
case extensionALPN:
if length < 2 {
return false
}
l := int(data[0])<<8 | int(data[1])
if l != length-2 {
return false
}
d := data[2:length]
for len(d) != 0 {
stringLen := int(d[0])
d = d[1:]
if stringLen == 0 || stringLen > len(d) {
return false
}
m.AlpnProtocols = append(m.AlpnProtocols, string(d[:stringLen]))
d = d[stringLen:]
}
case extensionSCT:
m.Scts = true
if length != 0 {
return false
}
}
data = data[length:]
}
return true
}
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
}
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
}
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 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 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)
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)
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.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:]
}
}
m.Raw = x
return x
}
func (m *ServerHelloMsg) Unmarshal(data []byte) bool {
if len(data) < 42 {
return false
}
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 false
}
m.SessionId = data[39 : 39+sessionIdLen]
data = data[39+sessionIdLen:]
if len(data) < 3 {
return false
}
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 = ""
if len(data) == 0 {
// ServerHello is optionally followed by extension data
return true
}
if len(data) < 2 {
return false
}
extensionsLength := int(data[0])<<8 | int(data[1])
data = data[2:]
if len(data) != extensionsLength {
return false
}
for len(data) != 0 {
if len(data) < 4 {
return false
}
extension := uint16(data[0])<<8 | uint16(data[1])
length := int(data[2])<<8 | int(data[3])
data = data[4:]
if len(data) < length {
return false
}
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 false
}
m.NextProtos = append(m.NextProtos, string(d[:l]))
d = d[l:]
}
case extensionStatusRequest:
if length > 0 {
return false
}
m.OcspStapling = true
case extensionSessionTicket:
if length > 0 {
return false
}
m.TicketSupported = true
case extensionRenegotiationInfo:
if length == 0 {
return false
}
d := data[:length]
l := int(d[0])
d = d[1:]
if l != len(d) {
return false
}
m.SecureRenegotiation = d
m.SecureRenegotiationSupported = true
case extensionALPN:
d := data[:length]
if len(d) < 3 {
return false
}
l := int(d[0])<<8 | int(d[1])
if l != len(d)-2 {
return false
}
d = d[2:]
l = int(d[0])
if l != len(d)-1 {
return false
}
d = d[1:]
if len(d) == 0 {
// ALPN protocols must not be empty.
return false
}
m.AlpnProtocol = string(d)
case extensionSCT:
d := data[:length]
if len(d) < 2 {
return false
}
l := int(d[0])<<8 | int(d[1])
d = d[2:]
if len(d) != l || l == 0 {
return false
}
m.Scts = make([][]byte, 0, 3)
for len(d) != 0 {
if len(d) < 2 {
return false
}
sctLen := int(d[0])<<8 | int(d[1])
d = d[2:]
if sctLen == 0 || len(d) < sctLen {
return false
}
m.Scts = append(m.Scts, d[:sctLen])
d = d[sctLen:]
}
}
data = data[length:]
}
return true
}
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) bool {
if len(data) < 7 {
return false
}
m.Raw = data
certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6])
if uint32(len(data)) != certsLen+7 {
return false
}
numCerts := 0
d := data[7:]
for certsLen > 0 {
if len(d) < 4 {
return false
}
certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
if uint32(len(d)) < 3+certLen {
return false
}
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 true
}
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) bool {
m.Raw = data
if len(data) < 4 {
return false
}
m.Key = data[4:]
return true
}
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) bool {
m.Raw = data
if len(data) < 5 {
return false
}
m.StatusType = data[4]
m.Response = nil
if m.StatusType == statusTypeOCSP {
if len(data) < 8 {
return false
}
respLen := uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7])
if uint32(len(data)) != 4+4+respLen {
return false
}
m.Response = data[8:]
}
return true
}
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) bool {
return len(data) == 4
}
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) bool {
m.Raw = data
if len(data) < 4 {
return false
}
l := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
if l != len(data)-4 {
return false
}
m.Ciphertext = data[4:]
return true
}
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) bool {
m.Raw = data
if len(data) < 4 {
return false
}
m.VerifyData = data[4:]
return true
}
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) bool {
m.Raw = data
if len(data) < 5 {
return false
}
data = data[4:]
protoLen := int(data[0])
data = data[1:]
if len(data) < protoLen {
return false
}
m.Proto = string(data[0:protoLen])
data = data[protoLen:]
if len(data) < 1 {
return false
}
paddingLen := int(data[0])
data = data[1:]
if len(data) != paddingLen {
return false
}
return true
}
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
SignatureAndHashes []signatureAndHash
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) &&
eqSignatureAndHashes(m.SignatureAndHashes, m1.SignatureAndHashes)
}
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.SignatureAndHashes)
}
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.SignatureAndHashes) * 2
y[0] = uint8(n >> 8)
y[1] = uint8(n)
y = y[2:]
for _, sigAndHash := range m.SignatureAndHashes {
y[0] = sigAndHash.hash
y[1] = sigAndHash.signature
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) bool {
m.Raw = data
if len(data) < 5 {
return false
}
length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
if uint32(len(data))-4 != length {
return false
}
numCertTypes := int(data[4])
data = data[5:]
if numCertTypes == 0 || len(data) <= numCertTypes {
return false
}
m.CertificateTypes = make([]byte, numCertTypes)
if copy(m.CertificateTypes, data) != numCertTypes {
return false
}
data = data[numCertTypes:]
if m.HasSignatureAndHash {
if len(data) < 2 {
return false
}
sigAndHashLen := uint16(data[0])<<8 | uint16(data[1])
data = data[2:]
if sigAndHashLen&1 != 0 {
return false
}
if len(data) < int(sigAndHashLen) {
return false
}
numSigAndHash := sigAndHashLen / 2
m.SignatureAndHashes = make([]signatureAndHash, numSigAndHash)
for i := range m.SignatureAndHashes {
m.SignatureAndHashes[i].hash = data[0]
m.SignatureAndHashes[i].signature = data[1]
data = data[2:]
}
}
if len(data) < 2 {
return false
}
casLength := uint16(data[0])<<8 | uint16(data[1])
data = data[2:]
if len(data) < int(casLength) {
return false
}
cas := make([]byte, casLength)
copy(cas, data)
data = data[casLength:]
m.CertificateAuthorities = nil
for len(cas) > 0 {
if len(cas) < 2 {
return false
}
caLen := uint16(cas[0])<<8 | uint16(cas[1])
cas = cas[2:]
if len(cas) < int(caLen) {
return false
}
m.CertificateAuthorities = append(m.CertificateAuthorities, cas[:caLen])
cas = cas[caLen:]
}
return len(data) == 0
}
type CertificateVerifyMsg struct {
Raw []byte
HasSignatureAndHash bool
SignatureAndHash signatureAndHash
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.SignatureAndHash.hash == m1.SignatureAndHash.hash &&
m.SignatureAndHash.signature == m1.SignatureAndHash.signature &&
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] = m.SignatureAndHash.hash
y[1] = m.SignatureAndHash.signature
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) bool {
m.Raw = data
if len(data) < 6 {
return false
}
length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
if uint32(len(data))-4 != length {
return false
}
data = data[4:]
if m.HasSignatureAndHash {
m.SignatureAndHash.hash = data[0]
m.SignatureAndHash.signature = data[1]
data = data[2:]
}
if len(data) < 2 {
return false
}
siglength := int(data[0])<<8 + int(data[1])
data = data[2:]
if len(data) != siglength {
return false
}
m.Signature = data
return true
}
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) bool {
m.Raw = data
if len(data) < 10 {
return false
}
length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
if uint32(len(data))-4 != length {
return false
}
ticketLen := int(data[8])<<8 + int(data[9])
if len(data)-10 != ticketLen {
return false
}
m.Ticket = data[10:]
return true
}
type HelloRequestMsg struct {
}
func (*HelloRequestMsg) marshal() []byte {
return []byte{TypeHelloRequest, 0, 0, 0}
}
func (*HelloRequestMsg) Unmarshal(data []byte) bool {
return len(data) == 4
}
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 eqSignatureAndHashes(x, y []signatureAndHash) bool {
if len(x) != len(y) {
return false
}
for i, v := range x {
v2 := y[i]
if v.hash != v2.hash || v.signature != v2.signature {
return false
}
}
return true
}