// 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 trs 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/rfc8446#section-4.2.8 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 }