// 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 runner import ( "errors" "fmt" "golang.org/x/crypto/cryptobyte" ) func readUint8LengthPrefixedBytes(s *cryptobyte.String, out *[]byte) bool { var child cryptobyte.String if !s.ReadUint8LengthPrefixed(&child) { return false } *out = child return true } func readUint16LengthPrefixedBytes(s *cryptobyte.String, out *[]byte) bool { var child cryptobyte.String if !s.ReadUint16LengthPrefixed(&child) { return false } *out = child return true } func readUint24LengthPrefixedBytes(s *cryptobyte.String, out *[]byte) bool { var child cryptobyte.String if !s.ReadUint24LengthPrefixed(&child) { return false } *out = child return true } func addUint8LengthPrefixedBytes(b *cryptobyte.Builder, v []byte) { b.AddUint8LengthPrefixed(func(child *cryptobyte.Builder) { child.AddBytes(v) }) } func addUint16LengthPrefixedBytes(b *cryptobyte.Builder, v []byte) { b.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) { child.AddBytes(v) }) } func addUint24LengthPrefixedBytes(b *cryptobyte.Builder, v []byte) { b.AddUint24LengthPrefixed(func(child *cryptobyte.Builder) { child.AddBytes(v) }) } type keyShareEntry struct { group CurveID keyExchange []byte } type pskIdentity struct { ticket []uint8 obfuscatedTicketAge uint32 } type HPKECipherSuite struct { KDF uint16 AEAD uint16 } type ECHConfig struct { Raw []byte ConfigID uint8 KEM uint16 PublicKey []byte MaxNameLen uint8 PublicName string CipherSuites []HPKECipherSuite // The following fields are only used by CreateECHConfig(). UnsupportedExtension bool UnsupportedMandatoryExtension bool } func CreateECHConfig(template *ECHConfig) *ECHConfig { bb := cryptobyte.NewBuilder(nil) // ECHConfig reuses the encrypted_client_hello extension codepoint as a // version identifier. bb.AddUint16(extensionEncryptedClientHello) bb.AddUint16LengthPrefixed(func(contents *cryptobyte.Builder) { contents.AddUint8(template.ConfigID) contents.AddUint16(template.KEM) addUint16LengthPrefixedBytes(contents, template.PublicKey) contents.AddUint16LengthPrefixed(func(cipherSuites *cryptobyte.Builder) { for _, suite := range template.CipherSuites { cipherSuites.AddUint16(suite.KDF) cipherSuites.AddUint16(suite.AEAD) } }) contents.AddUint8(template.MaxNameLen) addUint8LengthPrefixedBytes(contents, []byte(template.PublicName)) contents.AddUint16LengthPrefixed(func(extensions *cryptobyte.Builder) { // Mandatory extensions have the high bit set. if template.UnsupportedExtension { extensions.AddUint16(0x1111) addUint16LengthPrefixedBytes(extensions, []byte("test")) } if template.UnsupportedMandatoryExtension { extensions.AddUint16(0xaaaa) addUint16LengthPrefixedBytes(extensions, []byte("test")) } }) }) // This ought to be a call to a function like ParseECHConfig(bb.BytesOrPanic()), // but this constrains us to constructing ECHConfigs we are willing to // support. We need to test the client's behavior in response to unparsable // or unsupported ECHConfigs, so populate fields from the template directly. ret := *template ret.Raw = bb.BytesOrPanic() return &ret } func CreateECHConfigList(configs ...[]byte) []byte { bb := cryptobyte.NewBuilder(nil) bb.AddUint16LengthPrefixed(func(list *cryptobyte.Builder) { for _, config := range configs { list.AddBytes(config) } }) return bb.BytesOrPanic() } type ServerECHConfig struct { ECHConfig *ECHConfig Key []byte } const ( echClientTypeOuter byte = 0 echClientTypeInner byte = 1 ) type echClientOuter struct { kdfID uint16 aeadID uint16 configID uint8 enc []byte payload []byte } type clientHelloMsg struct { raw []byte isDTLS bool isV2ClientHello bool vers uint16 random []byte v2Challenge []byte sessionID []byte cookie []byte cipherSuites []uint16 compressionMethods []uint8 nextProtoNeg bool serverName string echOuter *echClientOuter echInner bool invalidECHInner []byte ocspStapling bool supportedCurves []CurveID supportedPoints []uint8 hasKeyShares bool keyShares []keyShareEntry keySharesRaw []byte trailingKeyShareData bool pskIdentities []pskIdentity pskKEModes []byte pskBinders [][]uint8 hasEarlyData bool tls13Cookie []byte ticketSupported bool sessionTicket []uint8 signatureAlgorithms []signatureAlgorithm signatureAlgorithmsCert []signatureAlgorithm supportedVersions []uint16 secureRenegotiation []byte alpnProtocols []string quicTransportParams []byte quicTransportParamsLegacy []byte duplicateExtension bool channelIDSupported bool extendedMasterSecret bool srtpProtectionProfiles []uint16 srtpMasterKeyIdentifier string sctListSupported bool customExtension string hasGREASEExtension bool omitExtensions bool emptyExtensions bool pad int compressedCertAlgs []uint16 delegatedCredential []signatureAlgorithm alpsProtocols []string alpsProtocolsOld []string outerExtensions []uint16 reorderOuterExtensionsWithoutCompressing bool prefixExtensions []uint16 // The following fields are only filled in by |unmarshal| and ignored when // marshaling a new ClientHello. echPayloadStart int echPayloadEnd int rawExtensions []byte } func (m *clientHelloMsg) marshalKeyShares(bb *cryptobyte.Builder) { bb.AddUint16LengthPrefixed(func(keyShares *cryptobyte.Builder) { for _, keyShare := range m.keyShares { keyShares.AddUint16(uint16(keyShare.group)) addUint16LengthPrefixedBytes(keyShares, keyShare.keyExchange) } if m.trailingKeyShareData { keyShares.AddUint8(0) } }) } type clientHelloType int const ( clientHelloNormal clientHelloType = iota clientHelloEncodedInner ) func (m *clientHelloMsg) marshalBody(hello *cryptobyte.Builder, typ clientHelloType) { hello.AddUint16(m.vers) hello.AddBytes(m.random) hello.AddUint8LengthPrefixed(func(sessionID *cryptobyte.Builder) { if typ != clientHelloEncodedInner { sessionID.AddBytes(m.sessionID) } }) if m.isDTLS { hello.AddUint8LengthPrefixed(func(cookie *cryptobyte.Builder) { cookie.AddBytes(m.cookie) }) } hello.AddUint16LengthPrefixed(func(cipherSuites *cryptobyte.Builder) { for _, suite := range m.cipherSuites { cipherSuites.AddUint16(suite) } }) hello.AddUint8LengthPrefixed(func(compressionMethods *cryptobyte.Builder) { compressionMethods.AddBytes(m.compressionMethods) }) type extension struct { id uint16 body []byte } var extensions []extension if m.duplicateExtension { // Add a duplicate bogus extension at the beginning and end. extensions = append(extensions, extension{id: extensionDuplicate}) } if m.nextProtoNeg { extensions = append(extensions, extension{id: extensionNextProtoNeg}) } if len(m.serverName) > 0 { // 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; serverNameList := cryptobyte.NewBuilder(nil) serverNameList.AddUint16LengthPrefixed(func(serverName *cryptobyte.Builder) { serverName.AddUint8(0) // NameType host_name(0) addUint16LengthPrefixedBytes(serverName, []byte(m.serverName)) }) extensions = append(extensions, extension{ id: extensionServerName, body: serverNameList.BytesOrPanic(), }) } if m.echOuter != nil { body := cryptobyte.NewBuilder(nil) body.AddUint8(echClientTypeOuter) body.AddUint16(m.echOuter.kdfID) body.AddUint16(m.echOuter.aeadID) body.AddUint8(m.echOuter.configID) addUint16LengthPrefixedBytes(body, m.echOuter.enc) addUint16LengthPrefixedBytes(body, m.echOuter.payload) extensions = append(extensions, extension{ id: extensionEncryptedClientHello, body: body.BytesOrPanic(), }) } if m.echInner { body := cryptobyte.NewBuilder(nil) body.AddUint8(echClientTypeInner) // If unset, invalidECHInner is empty, which is the correct serialization. body.AddBytes(m.invalidECHInner) extensions = append(extensions, extension{ id: extensionEncryptedClientHello, body: body.BytesOrPanic(), }) } if m.ocspStapling { certificateStatusRequest := cryptobyte.NewBuilder(nil) // RFC 4366, section 3.6 certificateStatusRequest.AddUint8(1) // OCSP type // Two zero valued uint16s for the two lengths. certificateStatusRequest.AddUint16(0) // ResponderID length certificateStatusRequest.AddUint16(0) // Extensions length extensions = append(extensions, extension{ id: extensionStatusRequest, body: certificateStatusRequest.BytesOrPanic(), }) } if len(m.supportedCurves) > 0 { // http://tools.ietf.org/html/rfc4492#section-5.1.1 supportedCurvesList := cryptobyte.NewBuilder(nil) supportedCurvesList.AddUint16LengthPrefixed(func(supportedCurves *cryptobyte.Builder) { for _, curve := range m.supportedCurves { supportedCurves.AddUint16(uint16(curve)) } }) extensions = append(extensions, extension{ id: extensionSupportedCurves, body: supportedCurvesList.BytesOrPanic(), }) } if len(m.supportedPoints) > 0 { // http://tools.ietf.org/html/rfc4492#section-5.1.2 supportedPointsList := cryptobyte.NewBuilder(nil) addUint8LengthPrefixedBytes(supportedPointsList, m.supportedPoints) extensions = append(extensions, extension{ id: extensionSupportedPoints, body: supportedPointsList.BytesOrPanic(), }) } if m.hasKeyShares { keyShareList := cryptobyte.NewBuilder(nil) m.marshalKeyShares(keyShareList) extensions = append(extensions, extension{ id: extensionKeyShare, body: keyShareList.BytesOrPanic(), }) } if len(m.pskKEModes) > 0 { pskModesExtension := cryptobyte.NewBuilder(nil) addUint8LengthPrefixedBytes(pskModesExtension, m.pskKEModes) extensions = append(extensions, extension{ id: extensionPSKKeyExchangeModes, body: pskModesExtension.BytesOrPanic(), }) } if m.hasEarlyData { extensions = append(extensions, extension{id: extensionEarlyData}) } if len(m.tls13Cookie) > 0 { body := cryptobyte.NewBuilder(nil) addUint16LengthPrefixedBytes(body, m.tls13Cookie) extensions = append(extensions, extension{ id: extensionCookie, body: body.BytesOrPanic(), }) } if m.ticketSupported { // http://tools.ietf.org/html/rfc5077#section-3.2 extensions = append(extensions, extension{ id: extensionSessionTicket, body: m.sessionTicket, }) } if len(m.signatureAlgorithms) > 0 { // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 signatureAlgorithmsExtension := cryptobyte.NewBuilder(nil) signatureAlgorithmsExtension.AddUint16LengthPrefixed(func(signatureAlgorithms *cryptobyte.Builder) { for _, sigAlg := range m.signatureAlgorithms { signatureAlgorithms.AddUint16(uint16(sigAlg)) } }) extensions = append(extensions, extension{ id: extensionSignatureAlgorithms, body: signatureAlgorithmsExtension.BytesOrPanic(), }) } if len(m.signatureAlgorithmsCert) > 0 { signatureAlgorithmsCertExtension := cryptobyte.NewBuilder(nil) signatureAlgorithmsCertExtension.AddUint16LengthPrefixed(func(signatureAlgorithmsCert *cryptobyte.Builder) { for _, sigAlg := range m.signatureAlgorithmsCert { signatureAlgorithmsCert.AddUint16(uint16(sigAlg)) } }) extensions = append(extensions, extension{ id: extensionSignatureAlgorithmsCert, body: signatureAlgorithmsCertExtension.BytesOrPanic(), }) } if len(m.supportedVersions) > 0 { supportedVersionsExtension := cryptobyte.NewBuilder(nil) supportedVersionsExtension.AddUint8LengthPrefixed(func(supportedVersions *cryptobyte.Builder) { for _, version := range m.supportedVersions { supportedVersions.AddUint16(uint16(version)) } }) extensions = append(extensions, extension{ id: extensionSupportedVersions, body: supportedVersionsExtension.BytesOrPanic(), }) } if m.secureRenegotiation != nil { secureRenegoExt := cryptobyte.NewBuilder(nil) addUint8LengthPrefixedBytes(secureRenegoExt, m.secureRenegotiation) extensions = append(extensions, extension{ id: extensionRenegotiationInfo, body: secureRenegoExt.BytesOrPanic(), }) } if len(m.alpnProtocols) > 0 { // https://tools.ietf.org/html/rfc7301#section-3.1 alpnExtension := cryptobyte.NewBuilder(nil) alpnExtension.AddUint16LengthPrefixed(func(protocolNameList *cryptobyte.Builder) { for _, s := range m.alpnProtocols { addUint8LengthPrefixedBytes(protocolNameList, []byte(s)) } }) extensions = append(extensions, extension{ id: extensionALPN, body: alpnExtension.BytesOrPanic(), }) } if len(m.quicTransportParams) > 0 { extensions = append(extensions, extension{ id: extensionQUICTransportParams, body: m.quicTransportParams, }) } if len(m.quicTransportParamsLegacy) > 0 { extensions = append(extensions, extension{ id: extensionQUICTransportParamsLegacy, body: m.quicTransportParamsLegacy, }) } if m.channelIDSupported { extensions = append(extensions, extension{id: extensionChannelID}) } if m.duplicateExtension { // Add a duplicate bogus extension at the beginning and end. extensions = append(extensions, extension{id: extensionDuplicate}) } if m.extendedMasterSecret { // https://tools.ietf.org/html/rfc7627 extensions = append(extensions, extension{id: extensionExtendedMasterSecret}) } if len(m.srtpProtectionProfiles) > 0 { // https://tools.ietf.org/html/rfc5764#section-4.1.1 useSrtpExt := cryptobyte.NewBuilder(nil) useSrtpExt.AddUint16LengthPrefixed(func(srtpProtectionProfiles *cryptobyte.Builder) { for _, p := range m.srtpProtectionProfiles { srtpProtectionProfiles.AddUint16(p) } }) addUint8LengthPrefixedBytes(useSrtpExt, []byte(m.srtpMasterKeyIdentifier)) extensions = append(extensions, extension{ id: extensionUseSRTP, body: useSrtpExt.BytesOrPanic(), }) } if m.sctListSupported { extensions = append(extensions, extension{id: extensionSignedCertificateTimestamp}) } if len(m.customExtension) > 0 { extensions = append(extensions, extension{ id: extensionCustom, body: []byte(m.customExtension), }) } if len(m.compressedCertAlgs) > 0 { body := cryptobyte.NewBuilder(nil) body.AddUint8LengthPrefixed(func(algIDs *cryptobyte.Builder) { for _, v := range m.compressedCertAlgs { algIDs.AddUint16(v) } }) extensions = append(extensions, extension{ id: extensionCompressedCertAlgs, body: body.BytesOrPanic(), }) } if len(m.delegatedCredential) > 0 { body := cryptobyte.NewBuilder(nil) body.AddUint16LengthPrefixed(func(signatureSchemeList *cryptobyte.Builder) { for _, sigAlg := range m.delegatedCredential { signatureSchemeList.AddUint16(uint16(sigAlg)) } }) extensions = append(extensions, extension{ id: extensionDelegatedCredential, body: body.BytesOrPanic(), }) } if len(m.alpsProtocols) > 0 { body := cryptobyte.NewBuilder(nil) body.AddUint16LengthPrefixed(func(protocolNameList *cryptobyte.Builder) { for _, s := range m.alpsProtocols { addUint8LengthPrefixedBytes(protocolNameList, []byte(s)) } }) extensions = append(extensions, extension{ id: extensionApplicationSettings, body: body.BytesOrPanic(), }) } if len(m.alpsProtocolsOld) > 0 { body := cryptobyte.NewBuilder(nil) body.AddUint16LengthPrefixed(func(protocolNameList *cryptobyte.Builder) { for _, s := range m.alpsProtocolsOld { addUint8LengthPrefixedBytes(protocolNameList, []byte(s)) } }) extensions = append(extensions, extension{ id: extensionApplicationSettingsOld, body: body.BytesOrPanic(), }) } // The PSK extension must be last. See https://tools.ietf.org/html/rfc8446#section-4.2.11 if len(m.pskIdentities) > 0 { pskExtension := cryptobyte.NewBuilder(nil) pskExtension.AddUint16LengthPrefixed(func(pskIdentities *cryptobyte.Builder) { for _, psk := range m.pskIdentities { addUint16LengthPrefixedBytes(pskIdentities, psk.ticket) pskIdentities.AddUint32(psk.obfuscatedTicketAge) } }) pskExtension.AddUint16LengthPrefixed(func(pskBinders *cryptobyte.Builder) { for _, binder := range m.pskBinders { addUint8LengthPrefixedBytes(pskBinders, binder) } }) extensions = append(extensions, extension{ id: extensionPreSharedKey, body: pskExtension.BytesOrPanic(), }) } if m.omitExtensions { return } hello.AddUint16LengthPrefixed(func(extensionsBB *cryptobyte.Builder) { if m.emptyExtensions { return } extMap := make(map[uint16][]byte) extsWritten := make(map[uint16]struct{}) for _, ext := range extensions { extMap[ext.id] = ext.body } // Write each of the prefix extensions, if we have it. for _, extID := range m.prefixExtensions { if body, ok := extMap[extID]; ok { extensionsBB.AddUint16(extID) addUint16LengthPrefixedBytes(extensionsBB, body) extsWritten[extID] = struct{}{} } } // Write outer extensions, possibly in compressed form. if m.outerExtensions != nil { if typ == clientHelloEncodedInner && !m.reorderOuterExtensionsWithoutCompressing { extensionsBB.AddUint16(extensionECHOuterExtensions) extensionsBB.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) { child.AddUint8LengthPrefixed(func(list *cryptobyte.Builder) { for _, extID := range m.outerExtensions { list.AddUint16(extID) extsWritten[extID] = struct{}{} } }) }) } else { for _, extID := range m.outerExtensions { // m.outerExtensions may intentionally contain duplicates to test the // server's reaction. If m.reorderOuterExtensionsWithoutCompressing // is set, we are targetting the second ClientHello and wish to send a // valid first ClientHello. In that case, deduplicate so the error // only appears later. if _, written := extsWritten[extID]; m.reorderOuterExtensionsWithoutCompressing && written { continue } if body, ok := extMap[extID]; ok { extensionsBB.AddUint16(extID) addUint16LengthPrefixedBytes(extensionsBB, body) extsWritten[extID] = struct{}{} } } } } // Write each of the remaining extensions in their original order. for _, ext := range extensions { if _, written := extsWritten[ext.id]; !written { extensionsBB.AddUint16(ext.id) addUint16LengthPrefixedBytes(extensionsBB, ext.body) } } if m.pad != 0 && len(hello.BytesOrPanic())%m.pad != 0 { extensionsBB.AddUint16(extensionPadding) extensionsBB.AddUint16LengthPrefixed(func(padding *cryptobyte.Builder) { // Note hello.len() has changed at this point from the length // prefix. if l := len(hello.BytesOrPanic()) % m.pad; l != 0 { padding.AddBytes(make([]byte, m.pad-l)) } }) } }) } func (m *clientHelloMsg) marshalForEncodedInner() []byte { hello := cryptobyte.NewBuilder(nil) m.marshalBody(hello, clientHelloEncodedInner) return hello.BytesOrPanic() } func (m *clientHelloMsg) marshal() []byte { if m.raw != nil { return m.raw } if m.isV2ClientHello { v2Msg := cryptobyte.NewBuilder(nil) v2Msg.AddUint8(1) v2Msg.AddUint16(m.vers) v2Msg.AddUint16(uint16(len(m.cipherSuites) * 3)) v2Msg.AddUint16(uint16(len(m.sessionID))) v2Msg.AddUint16(uint16(len(m.v2Challenge))) for _, spec := range m.cipherSuites { v2Msg.AddUint24(uint32(spec)) } v2Msg.AddBytes(m.sessionID) v2Msg.AddBytes(m.v2Challenge) m.raw = v2Msg.BytesOrPanic() return m.raw } handshakeMsg := cryptobyte.NewBuilder(nil) handshakeMsg.AddUint8(typeClientHello) handshakeMsg.AddUint24LengthPrefixed(func(hello *cryptobyte.Builder) { m.marshalBody(hello, clientHelloNormal) }) m.raw = handshakeMsg.BytesOrPanic() // Sanity-check padding. if m.pad != 0 && (len(m.raw)-4)%m.pad != 0 { panic(fmt.Sprintf("%d is not a multiple of %d", len(m.raw)-4, m.pad)) } return m.raw } func parseSignatureAlgorithms(reader *cryptobyte.String, out *[]signatureAlgorithm, allowEmpty bool) bool { var sigAlgs cryptobyte.String if !reader.ReadUint16LengthPrefixed(&sigAlgs) { return false } if !allowEmpty && len(sigAlgs) == 0 { return false } *out = make([]signatureAlgorithm, 0, len(sigAlgs)/2) for len(sigAlgs) > 0 { var v uint16 if !sigAlgs.ReadUint16(&v) { return false } if signatureAlgorithm(v) == signatureRSAPKCS1WithMD5AndSHA1 { // signatureRSAPKCS1WithMD5AndSHA1 is an internal value BoringSSL // uses to represent the TLS 1.0 MD5/SHA-1 concatenation. It should // never appear on the wire. return false } *out = append(*out, signatureAlgorithm(v)) } return true } func checkDuplicateExtensions(extensions cryptobyte.String) bool { seen := make(map[uint16]struct{}) for len(extensions) > 0 { var extension uint16 var body cryptobyte.String if !extensions.ReadUint16(&extension) || !extensions.ReadUint16LengthPrefixed(&body) { return false } if _, ok := seen[extension]; ok { return false } seen[extension] = struct{}{} } return true } func (m *clientHelloMsg) unmarshal(data []byte) bool { m.raw = data reader := cryptobyte.String(data[4:]) if !reader.ReadUint16(&m.vers) || !reader.ReadBytes(&m.random, 32) || !readUint8LengthPrefixedBytes(&reader, &m.sessionID) || len(m.sessionID) > 32 { return false } if m.isDTLS && !readUint8LengthPrefixedBytes(&reader, &m.cookie) { return false } var cipherSuites cryptobyte.String if !reader.ReadUint16LengthPrefixed(&cipherSuites) || !readUint8LengthPrefixedBytes(&reader, &m.compressionMethods) { return false } m.cipherSuites = make([]uint16, 0, len(cipherSuites)/2) for len(cipherSuites) > 0 { var v uint16 if !cipherSuites.ReadUint16(&v) { return false } m.cipherSuites = append(m.cipherSuites, v) if v == scsvRenegotiation { m.secureRenegotiation = []byte{} } } m.nextProtoNeg = false m.serverName = "" m.ocspStapling = false m.keyShares = nil m.pskIdentities = nil m.hasEarlyData = false m.ticketSupported = false m.sessionTicket = nil m.signatureAlgorithms = nil m.signatureAlgorithmsCert = nil m.supportedVersions = nil m.alpnProtocols = nil m.extendedMasterSecret = false m.customExtension = "" m.delegatedCredential = nil m.alpsProtocols = nil m.alpsProtocolsOld = nil if len(reader) == 0 { // ClientHello is optionally followed by extension data return true } var extensions cryptobyte.String if !reader.ReadUint16LengthPrefixed(&extensions) || len(reader) != 0 || !checkDuplicateExtensions(extensions) { return false } m.rawExtensions = extensions for len(extensions) > 0 { var extension uint16 var body cryptobyte.String if !extensions.ReadUint16(&extension) || !extensions.ReadUint16LengthPrefixed(&body) { return false } switch extension { case extensionServerName: var names cryptobyte.String if !body.ReadUint16LengthPrefixed(&names) || len(body) != 0 { return false } for len(names) > 0 { var nameType byte var name []byte if !names.ReadUint8(&nameType) || !readUint16LengthPrefixedBytes(&names, &name) { return false } if nameType == 0 { m.serverName = string(name) } } case extensionEncryptedClientHello: var typ byte if !body.ReadUint8(&typ) { return false } switch typ { case echClientTypeOuter: var echOuter echClientOuter if !body.ReadUint16(&echOuter.kdfID) || !body.ReadUint16(&echOuter.aeadID) || !body.ReadUint8(&echOuter.configID) || !readUint16LengthPrefixedBytes(&body, &echOuter.enc) || !readUint16LengthPrefixedBytes(&body, &echOuter.payload) || len(echOuter.payload) == 0 || len(body) > 0 { return false } m.echOuter = &echOuter m.echPayloadEnd = len(data) - len(extensions) m.echPayloadStart = m.echPayloadEnd - len(echOuter.payload) case echClientTypeInner: if len(body) > 0 { return false } m.echInner = true default: return false } case extensionNextProtoNeg: if len(body) != 0 { return false } m.nextProtoNeg = true case extensionStatusRequest: // This parse is stricter than a production implementation would // use. The status_request extension has many layers of interior // extensibility, but we expect our client to only send empty // requests of type OCSP. var statusType uint8 var responderIDList, innerExtensions cryptobyte.String if !body.ReadUint8(&statusType) || statusType != statusTypeOCSP || !body.ReadUint16LengthPrefixed(&responderIDList) || !body.ReadUint16LengthPrefixed(&innerExtensions) || len(responderIDList) != 0 || len(innerExtensions) != 0 || len(body) != 0 { return false } m.ocspStapling = true case extensionSupportedCurves: // http://tools.ietf.org/html/rfc4492#section-5.5.1 var curves cryptobyte.String if !body.ReadUint16LengthPrefixed(&curves) || len(body) != 0 { return false } m.supportedCurves = make([]CurveID, 0, len(curves)/2) for len(curves) > 0 { var v uint16 if !curves.ReadUint16(&v) { return false } m.supportedCurves = append(m.supportedCurves, CurveID(v)) } case extensionSupportedPoints: // http://tools.ietf.org/html/rfc4492#section-5.1.2 if !readUint8LengthPrefixedBytes(&body, &m.supportedPoints) || len(m.supportedPoints) == 0 || len(body) != 0 { return false } case extensionSessionTicket: // http://tools.ietf.org/html/rfc5077#section-3.2 m.ticketSupported = true m.sessionTicket = []byte(body) case extensionKeyShare: // https://tools.ietf.org/html/rfc8446#section-4.2.8 m.hasKeyShares = true m.keySharesRaw = body var keyShares cryptobyte.String if !body.ReadUint16LengthPrefixed(&keyShares) || len(body) != 0 { return false } for len(keyShares) > 0 { var entry keyShareEntry var group uint16 if !keyShares.ReadUint16(&group) || !readUint16LengthPrefixedBytes(&keyShares, &entry.keyExchange) { return false } entry.group = CurveID(group) m.keyShares = append(m.keyShares, entry) } case extensionPreSharedKey: // https://tools.ietf.org/html/rfc8446#section-4.2.11 var psks, binders cryptobyte.String if !body.ReadUint16LengthPrefixed(&psks) || !body.ReadUint16LengthPrefixed(&binders) || len(body) != 0 { return false } for len(psks) > 0 { var psk pskIdentity if !readUint16LengthPrefixedBytes(&psks, &psk.ticket) || !psks.ReadUint32(&psk.obfuscatedTicketAge) { return false } m.pskIdentities = append(m.pskIdentities, psk) } for len(binders) > 0 { var binder []byte if !readUint8LengthPrefixedBytes(&binders, &binder) { return false } m.pskBinders = append(m.pskBinders, binder) } // There must be the same number of identities as binders. if len(m.pskIdentities) != len(m.pskBinders) { return false } case extensionPSKKeyExchangeModes: // https://tools.ietf.org/html/rfc8446#section-4.2.9 if !readUint8LengthPrefixedBytes(&body, &m.pskKEModes) || len(body) != 0 { return false } case extensionEarlyData: // https://tools.ietf.org/html/rfc8446#section-4.2.10 if len(body) != 0 { return false } m.hasEarlyData = true case extensionCookie: if !readUint16LengthPrefixedBytes(&body, &m.tls13Cookie) || len(body) != 0 { return false } case extensionSignatureAlgorithms: // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 if !parseSignatureAlgorithms(&body, &m.signatureAlgorithms, false) || len(body) != 0 { return false } case extensionSignatureAlgorithmsCert: if !parseSignatureAlgorithms(&body, &m.signatureAlgorithmsCert, false) || len(body) != 0 { return false } case extensionSupportedVersions: var versions cryptobyte.String if !body.ReadUint8LengthPrefixed(&versions) || len(body) != 0 { return false } m.supportedVersions = make([]uint16, 0, len(versions)/2) for len(versions) > 0 { var v uint16 if !versions.ReadUint16(&v) { return false } m.supportedVersions = append(m.supportedVersions, v) } case extensionRenegotiationInfo: if !readUint8LengthPrefixedBytes(&body, &m.secureRenegotiation) || len(body) != 0 { return false } case extensionALPN: var protocols cryptobyte.String if !body.ReadUint16LengthPrefixed(&protocols) || len(body) != 0 { return false } for len(protocols) > 0 { var protocol []byte if !readUint8LengthPrefixedBytes(&protocols, &protocol) || len(protocol) == 0 { return false } m.alpnProtocols = append(m.alpnProtocols, string(protocol)) } case extensionQUICTransportParams: m.quicTransportParams = body case extensionQUICTransportParamsLegacy: m.quicTransportParamsLegacy = body case extensionChannelID: if len(body) != 0 { return false } m.channelIDSupported = true case extensionExtendedMasterSecret: if len(body) != 0 { return false } m.extendedMasterSecret = true case extensionUseSRTP: var profiles cryptobyte.String var mki []byte if !body.ReadUint16LengthPrefixed(&profiles) || !readUint8LengthPrefixedBytes(&body, &mki) || len(body) != 0 { return false } m.srtpProtectionProfiles = make([]uint16, 0, len(profiles)/2) for len(profiles) > 0 { var v uint16 if !profiles.ReadUint16(&v) { return false } m.srtpProtectionProfiles = append(m.srtpProtectionProfiles, v) } m.srtpMasterKeyIdentifier = string(mki) case extensionSignedCertificateTimestamp: if len(body) != 0 { return false } m.sctListSupported = true case extensionCustom: m.customExtension = string(body) case extensionCompressedCertAlgs: var algIDs cryptobyte.String if !body.ReadUint8LengthPrefixed(&algIDs) { return false } seen := make(map[uint16]struct{}) for len(algIDs) > 0 { var algID uint16 if !algIDs.ReadUint16(&algID) { return false } if _, ok := seen[algID]; ok { return false } seen[algID] = struct{}{} m.compressedCertAlgs = append(m.compressedCertAlgs, algID) } case extensionPadding: // Padding bytes must be all zero. for _, b := range body { if b != 0 { return false } } case extensionDelegatedCredential: if !parseSignatureAlgorithms(&body, &m.delegatedCredential, false) || len(body) != 0 { return false } case extensionApplicationSettings: var protocols cryptobyte.String if !body.ReadUint16LengthPrefixed(&protocols) || len(body) != 0 { return false } for len(protocols) > 0 { var protocol []byte if !readUint8LengthPrefixedBytes(&protocols, &protocol) || len(protocol) == 0 { return false } m.alpsProtocols = append(m.alpsProtocols, string(protocol)) } case extensionApplicationSettingsOld: var protocols cryptobyte.String if !body.ReadUint16LengthPrefixed(&protocols) || len(body) != 0 { return false } for len(protocols) > 0 { var protocol []byte if !readUint8LengthPrefixedBytes(&protocols, &protocol) || len(protocol) == 0 { return false } m.alpsProtocolsOld = append(m.alpsProtocolsOld, string(protocol)) } } if isGREASEValue(extension) { m.hasGREASEExtension = true } } return true } func decodeClientHelloInner(config *Config, encoded []byte, helloOuter *clientHelloMsg) (*clientHelloMsg, error) { reader := cryptobyte.String(encoded) var versAndRandom, sessionID, cipherSuites, compressionMethods []byte var extensions cryptobyte.String if !reader.ReadBytes(&versAndRandom, 2+32) || !readUint8LengthPrefixedBytes(&reader, &sessionID) || len(sessionID) != 0 || // Copied from |helloOuter| !readUint16LengthPrefixedBytes(&reader, &cipherSuites) || !readUint8LengthPrefixedBytes(&reader, &compressionMethods) || !reader.ReadUint16LengthPrefixed(&extensions) { return nil, errors.New("tls: error parsing EncodedClientHelloInner") } // The remainder of the structure is padding. for _, padding := range reader { if padding != 0 { return nil, errors.New("tls: non-zero padding in EncodedClientHelloInner") } } copied := make(map[uint16]struct{}) builder := cryptobyte.NewBuilder(nil) builder.AddUint8(typeClientHello) builder.AddUint24LengthPrefixed(func(body *cryptobyte.Builder) { body.AddBytes(versAndRandom) addUint8LengthPrefixedBytes(body, helloOuter.sessionID) addUint16LengthPrefixedBytes(body, cipherSuites) addUint8LengthPrefixedBytes(body, compressionMethods) body.AddUint16LengthPrefixed(func(newExtensions *cryptobyte.Builder) { var seenOuterExtensions bool outerExtensions := cryptobyte.String(helloOuter.rawExtensions) for len(extensions) > 0 { var extType uint16 var extBody cryptobyte.String if !extensions.ReadUint16(&extType) || !extensions.ReadUint16LengthPrefixed(&extBody) { newExtensions.SetError(errors.New("tls: error parsing EncodedClientHelloInner")) return } if extType != extensionECHOuterExtensions { newExtensions.AddUint16(extType) addUint16LengthPrefixedBytes(newExtensions, extBody) continue } if seenOuterExtensions { newExtensions.SetError(errors.New("tls: duplicate ech_outer_extensions extension")) return } seenOuterExtensions = true var extList cryptobyte.String if !extBody.ReadUint8LengthPrefixed(&extList) || len(extList) == 0 || len(extBody) != 0 { newExtensions.SetError(errors.New("tls: error parsing ech_outer_extensions")) return } for len(extList) != 0 { var newExtType uint16 if !extList.ReadUint16(&newExtType) { newExtensions.SetError(errors.New("tls: error parsing ech_outer_extensions")) return } if newExtType == extensionEncryptedClientHello { newExtensions.SetError(errors.New("tls: error parsing ech_outer_extensions")) return } for { if len(outerExtensions) == 0 { newExtensions.SetError(fmt.Errorf("tls: extension %d not found in ClientHelloOuter", newExtType)) return } var foundExt uint16 var newExtBody []byte if !outerExtensions.ReadUint16(&foundExt) || !readUint16LengthPrefixedBytes(&outerExtensions, &newExtBody) { newExtensions.SetError(errors.New("tls: error parsing ClientHelloOuter")) return } if foundExt == newExtType { newExtensions.AddUint16(newExtType) addUint16LengthPrefixedBytes(newExtensions, newExtBody) copied[newExtType] = struct{}{} break } } } } }) }) bytes, err := builder.Bytes() if err != nil { return nil, err } for _, expected := range config.Bugs.ExpectECHOuterExtensions { if _, ok := copied[expected]; !ok { return nil, fmt.Errorf("tls: extension %d not found in ech_outer_extensions", expected) } } for _, expected := range config.Bugs.ExpectECHUncompressedExtensions { if _, ok := copied[expected]; ok { return nil, fmt.Errorf("tls: extension %d unexpectedly found in ech_outer_extensions", expected) } } ret := new(clientHelloMsg) if !ret.unmarshal(bytes) { return nil, errors.New("tls: error parsing reconstructed ClientHello") } return ret, nil } type serverHelloMsg struct { raw []byte isDTLS bool vers uint16 versOverride uint16 supportedVersOverride uint16 omitSupportedVers bool random []byte sessionID []byte cipherSuite uint16 hasKeyShare bool keyShare keyShareEntry hasPSKIdentity bool pskIdentity uint16 compressionMethod uint8 customExtension string unencryptedALPN string omitExtensions bool emptyExtensions bool extensions serverExtensions } func (m *serverHelloMsg) marshal() []byte { if m.raw != nil { return m.raw } handshakeMsg := cryptobyte.NewBuilder(nil) handshakeMsg.AddUint8(typeServerHello) handshakeMsg.AddUint24LengthPrefixed(func(hello *cryptobyte.Builder) { // m.vers is used both to determine the format of the rest of the // ServerHello and to override the value, so include a second version // field. vers, ok := wireToVersion(m.vers, m.isDTLS) if !ok { panic("unknown version") } if m.versOverride != 0 { hello.AddUint16(m.versOverride) } else if vers >= VersionTLS13 { hello.AddUint16(VersionTLS12) } else { hello.AddUint16(m.vers) } hello.AddBytes(m.random) addUint8LengthPrefixedBytes(hello, m.sessionID) hello.AddUint16(m.cipherSuite) hello.AddUint8(m.compressionMethod) hello.AddUint16LengthPrefixed(func(extensions *cryptobyte.Builder) { if vers >= VersionTLS13 { if m.hasKeyShare { extensions.AddUint16(extensionKeyShare) extensions.AddUint16LengthPrefixed(func(keyShare *cryptobyte.Builder) { keyShare.AddUint16(uint16(m.keyShare.group)) addUint16LengthPrefixedBytes(keyShare, m.keyShare.keyExchange) }) } if m.hasPSKIdentity { extensions.AddUint16(extensionPreSharedKey) extensions.AddUint16(2) // Length extensions.AddUint16(m.pskIdentity) } if !m.omitSupportedVers { extensions.AddUint16(extensionSupportedVersions) extensions.AddUint16(2) // Length if m.supportedVersOverride != 0 { extensions.AddUint16(m.supportedVersOverride) } else { extensions.AddUint16(m.vers) } } if len(m.customExtension) > 0 { extensions.AddUint16(extensionCustom) addUint16LengthPrefixedBytes(extensions, []byte(m.customExtension)) } if len(m.unencryptedALPN) > 0 { extensions.AddUint16(extensionALPN) extensions.AddUint16LengthPrefixed(func(extension *cryptobyte.Builder) { extension.AddUint16LengthPrefixed(func(protocolNameList *cryptobyte.Builder) { addUint8LengthPrefixedBytes(protocolNameList, []byte(m.unencryptedALPN)) }) }) } } else { m.extensions.marshal(extensions) } if m.omitExtensions || m.emptyExtensions { // Silently erasing server extensions will break the handshake. Instead, // assert that tests which use this field also disable all features which // would write an extension. Note the length includes the length prefix. if b := extensions.BytesOrPanic(); len(b) != 2 { panic(fmt.Sprintf("ServerHello unexpectedly contained extensions: %x, %+v", b, m)) } } }) // Remove the length prefix. if m.omitExtensions { hello.Unwrite(2) } }) m.raw = handshakeMsg.BytesOrPanic() return m.raw } func (m *serverHelloMsg) unmarshal(data []byte) bool { m.raw = data reader := cryptobyte.String(data[4:]) if !reader.ReadUint16(&m.vers) || !reader.ReadBytes(&m.random, 32) { return false } vers, ok := wireToVersion(m.vers, m.isDTLS) if !ok { return false } if !readUint8LengthPrefixedBytes(&reader, &m.sessionID) || !reader.ReadUint16(&m.cipherSuite) || !reader.ReadUint8(&m.compressionMethod) { return false } if len(reader) == 0 && m.vers < VersionTLS13 { // Extension data is optional before TLS 1.3. m.extensions = serverExtensions{} m.omitExtensions = true return true } var extensions cryptobyte.String if !reader.ReadUint16LengthPrefixed(&extensions) || len(reader) != 0 || !checkDuplicateExtensions(extensions) { return false } // Parse out the version from supported_versions if available. if m.vers == VersionTLS12 { extensionsCopy := extensions for len(extensionsCopy) > 0 { var extension uint16 var body cryptobyte.String if !extensionsCopy.ReadUint16(&extension) || !extensionsCopy.ReadUint16LengthPrefixed(&body) { return false } if extension == extensionSupportedVersions { if !body.ReadUint16(&m.vers) || len(body) != 0 { return false } vers, ok = wireToVersion(m.vers, m.isDTLS) if !ok { return false } } } } if vers >= VersionTLS13 { for len(extensions) > 0 { var extension uint16 var body cryptobyte.String if !extensions.ReadUint16(&extension) || !extensions.ReadUint16LengthPrefixed(&body) { return false } switch extension { case extensionKeyShare: m.hasKeyShare = true var group uint16 if !body.ReadUint16(&group) || !readUint16LengthPrefixedBytes(&body, &m.keyShare.keyExchange) || len(body) != 0 { return false } m.keyShare.group = CurveID(group) case extensionPreSharedKey: if !body.ReadUint16(&m.pskIdentity) || len(body) != 0 { return false } m.hasPSKIdentity = true case extensionSupportedVersions: // Parsed above. default: // Only allow the 3 extensions that are sent in // the clear in TLS 1.3. return false } } } else if !m.extensions.unmarshal(extensions, vers) { return false } return true } type encryptedExtensionsMsg struct { raw []byte extensions serverExtensions empty bool } func (m *encryptedExtensionsMsg) marshal() []byte { if m.raw != nil { return m.raw } encryptedExtensionsMsg := cryptobyte.NewBuilder(nil) encryptedExtensionsMsg.AddUint8(typeEncryptedExtensions) encryptedExtensionsMsg.AddUint24LengthPrefixed(func(encryptedExtensions *cryptobyte.Builder) { if !m.empty { encryptedExtensions.AddUint16LengthPrefixed(func(extensions *cryptobyte.Builder) { m.extensions.marshal(extensions) }) } }) m.raw = encryptedExtensionsMsg.BytesOrPanic() return m.raw } func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool { m.raw = data reader := cryptobyte.String(data[4:]) var extensions cryptobyte.String if !reader.ReadUint16LengthPrefixed(&extensions) || len(reader) != 0 { return false } return m.extensions.unmarshal(extensions, VersionTLS13) } type serverExtensions struct { nextProtoNeg bool nextProtos []string ocspStapling bool ticketSupported bool secureRenegotiation []byte alpnProtocol string alpnProtocolEmpty bool duplicateExtension bool channelIDRequested bool extendedMasterSecret bool srtpProtectionProfile uint16 srtpMasterKeyIdentifier string sctList []byte customExtension string npnAfterAlpn bool hasKeyShare bool hasEarlyData bool keyShare keyShareEntry supportedVersion uint16 supportedPoints []uint8 supportedCurves []CurveID quicTransportParams []byte quicTransportParamsLegacy []byte serverNameAck bool applicationSettings []byte hasApplicationSettings bool applicationSettingsOld []byte hasApplicationSettingsOld bool echRetryConfigs []byte } func (m *serverExtensions) marshal(extensions *cryptobyte.Builder) { if m.duplicateExtension { // Add a duplicate bogus extension at the beginning and end. extensions.AddUint16(extensionDuplicate) extensions.AddUint16(0) // length = 0 for empty extension } if m.nextProtoNeg && !m.npnAfterAlpn { extensions.AddUint16(extensionNextProtoNeg) extensions.AddUint16LengthPrefixed(func(extension *cryptobyte.Builder) { for _, v := range m.nextProtos { addUint8LengthPrefixedBytes(extension, []byte(v)) } }) } if m.ocspStapling { extensions.AddUint16(extensionStatusRequest) extensions.AddUint16(0) } if m.ticketSupported { extensions.AddUint16(extensionSessionTicket) extensions.AddUint16(0) } if m.secureRenegotiation != nil { extensions.AddUint16(extensionRenegotiationInfo) extensions.AddUint16LengthPrefixed(func(extension *cryptobyte.Builder) { addUint8LengthPrefixedBytes(extension, m.secureRenegotiation) }) } if len(m.alpnProtocol) > 0 || m.alpnProtocolEmpty { extensions.AddUint16(extensionALPN) extensions.AddUint16LengthPrefixed(func(extension *cryptobyte.Builder) { extension.AddUint16LengthPrefixed(func(protocolNameList *cryptobyte.Builder) { addUint8LengthPrefixedBytes(protocolNameList, []byte(m.alpnProtocol)) }) }) } if m.channelIDRequested { extensions.AddUint16(extensionChannelID) extensions.AddUint16(0) } if m.duplicateExtension { // Add a duplicate bogus extension at the beginning and end. extensions.AddUint16(extensionDuplicate) extensions.AddUint16(0) } if m.extendedMasterSecret { extensions.AddUint16(extensionExtendedMasterSecret) extensions.AddUint16(0) } if m.srtpProtectionProfile != 0 { extensions.AddUint16(extensionUseSRTP) extensions.AddUint16LengthPrefixed(func(extension *cryptobyte.Builder) { extension.AddUint16LengthPrefixed(func(srtpProtectionProfiles *cryptobyte.Builder) { srtpProtectionProfiles.AddUint16(m.srtpProtectionProfile) }) addUint8LengthPrefixedBytes(extension, []byte(m.srtpMasterKeyIdentifier)) }) } if m.sctList != nil { extensions.AddUint16(extensionSignedCertificateTimestamp) addUint16LengthPrefixedBytes(extensions, m.sctList) } if l := len(m.customExtension); l > 0 { extensions.AddUint16(extensionCustom) addUint16LengthPrefixedBytes(extensions, []byte(m.customExtension)) } if m.nextProtoNeg && m.npnAfterAlpn { extensions.AddUint16(extensionNextProtoNeg) extensions.AddUint16LengthPrefixed(func(extension *cryptobyte.Builder) { for _, v := range m.nextProtos { addUint8LengthPrefixedBytes(extension, []byte(v)) } }) } if m.hasKeyShare { extensions.AddUint16(extensionKeyShare) extensions.AddUint16LengthPrefixed(func(keyShare *cryptobyte.Builder) { keyShare.AddUint16(uint16(m.keyShare.group)) addUint16LengthPrefixedBytes(keyShare, m.keyShare.keyExchange) }) } if m.supportedVersion != 0 { extensions.AddUint16(extensionSupportedVersions) extensions.AddUint16(2) // Length extensions.AddUint16(m.supportedVersion) } if len(m.supportedPoints) > 0 { // http://tools.ietf.org/html/rfc4492#section-5.1.2 extensions.AddUint16(extensionSupportedPoints) extensions.AddUint16LengthPrefixed(func(supportedPointsList *cryptobyte.Builder) { addUint8LengthPrefixedBytes(supportedPointsList, m.supportedPoints) }) } if len(m.supportedCurves) > 0 { // https://tools.ietf.org/html/rfc8446#section-4.2.7 extensions.AddUint16(extensionSupportedCurves) extensions.AddUint16LengthPrefixed(func(supportedCurvesList *cryptobyte.Builder) { supportedCurvesList.AddUint16LengthPrefixed(func(supportedCurves *cryptobyte.Builder) { for _, curve := range m.supportedCurves { supportedCurves.AddUint16(uint16(curve)) } }) }) } if len(m.quicTransportParams) > 0 { extensions.AddUint16(extensionQUICTransportParams) addUint16LengthPrefixedBytes(extensions, m.quicTransportParams) } if len(m.quicTransportParamsLegacy) > 0 { extensions.AddUint16(extensionQUICTransportParamsLegacy) addUint16LengthPrefixedBytes(extensions, m.quicTransportParamsLegacy) } if m.hasEarlyData { extensions.AddUint16(extensionEarlyData) extensions.AddBytes([]byte{0, 0}) } if m.serverNameAck { extensions.AddUint16(extensionServerName) extensions.AddUint16(0) // zero length } if m.hasApplicationSettings { extensions.AddUint16(extensionApplicationSettings) addUint16LengthPrefixedBytes(extensions, m.applicationSettings) } if m.hasApplicationSettingsOld { extensions.AddUint16(extensionApplicationSettingsOld) addUint16LengthPrefixedBytes(extensions, m.applicationSettingsOld) } if len(m.echRetryConfigs) > 0 { extensions.AddUint16(extensionEncryptedClientHello) addUint16LengthPrefixedBytes(extensions, m.echRetryConfigs) } } func (m *serverExtensions) unmarshal(data cryptobyte.String, version uint16) bool { // Reset all fields. *m = serverExtensions{} if !checkDuplicateExtensions(data) { return false } for len(data) > 0 { var extension uint16 var body cryptobyte.String if !data.ReadUint16(&extension) || !data.ReadUint16LengthPrefixed(&body) { return false } switch extension { case extensionNextProtoNeg: m.nextProtoNeg = true for len(body) > 0 { var protocol []byte if !readUint8LengthPrefixedBytes(&body, &protocol) { return false } m.nextProtos = append(m.nextProtos, string(protocol)) } case extensionStatusRequest: if len(body) != 0 { return false } m.ocspStapling = true case extensionSessionTicket: if len(body) != 0 { return false } m.ticketSupported = true case extensionRenegotiationInfo: if !readUint8LengthPrefixedBytes(&body, &m.secureRenegotiation) || len(body) != 0 { return false } case extensionALPN: var protocols, protocol cryptobyte.String if !body.ReadUint16LengthPrefixed(&protocols) || len(body) != 0 || !protocols.ReadUint8LengthPrefixed(&protocol) || len(protocols) != 0 { return false } m.alpnProtocol = string(protocol) m.alpnProtocolEmpty = len(protocol) == 0 case extensionChannelID: if len(body) != 0 { return false } m.channelIDRequested = true case extensionExtendedMasterSecret: if len(body) != 0 { return false } m.extendedMasterSecret = true case extensionUseSRTP: var profiles, mki cryptobyte.String if !body.ReadUint16LengthPrefixed(&profiles) || !profiles.ReadUint16(&m.srtpProtectionProfile) || len(profiles) != 0 || !body.ReadUint8LengthPrefixed(&mki) || len(body) != 0 { return false } m.srtpMasterKeyIdentifier = string(mki) case extensionSignedCertificateTimestamp: m.sctList = []byte(body) case extensionCustom: m.customExtension = string(body) case extensionServerName: if len(body) != 0 { return false } m.serverNameAck = true case extensionSupportedPoints: // supported_points is illegal in TLS 1.3. if version >= VersionTLS13 { return false } // http://tools.ietf.org/html/rfc4492#section-5.5.2 if !readUint8LengthPrefixedBytes(&body, &m.supportedPoints) || len(body) != 0 { return false } case extensionSupportedCurves: // The server can only send supported_curves in TLS 1.3. if version < VersionTLS13 { return false } case extensionQUICTransportParams: m.quicTransportParams = body case extensionQUICTransportParamsLegacy: m.quicTransportParamsLegacy = body case extensionEarlyData: if version < VersionTLS13 || len(body) != 0 { return false } m.hasEarlyData = true case extensionApplicationSettings: m.hasApplicationSettings = true m.applicationSettings = body case extensionApplicationSettingsOld: m.hasApplicationSettingsOld = true m.applicationSettingsOld = body case extensionEncryptedClientHello: if version < VersionTLS13 { return false } m.echRetryConfigs = body // Validate the ECHConfig with a top-level parse. var echConfigs cryptobyte.String if !body.ReadUint16LengthPrefixed(&echConfigs) { return false } for len(echConfigs) > 0 { var version uint16 var contents cryptobyte.String if !echConfigs.ReadUint16(&version) || !echConfigs.ReadUint16LengthPrefixed(&contents) { return false } } if len(body) > 0 { return false } default: // Unknown extensions are illegal from the server. return false } } return true } type clientEncryptedExtensionsMsg struct { raw []byte applicationSettings []byte hasApplicationSettings bool applicationSettingsOld []byte hasApplicationSettingsOld bool customExtension []byte } func (m *clientEncryptedExtensionsMsg) marshal() (x []byte) { if m.raw != nil { return m.raw } builder := cryptobyte.NewBuilder(nil) builder.AddUint8(typeEncryptedExtensions) builder.AddUint24LengthPrefixed(func(body *cryptobyte.Builder) { body.AddUint16LengthPrefixed(func(extensions *cryptobyte.Builder) { if m.hasApplicationSettings { extensions.AddUint16(extensionApplicationSettings) addUint16LengthPrefixedBytes(extensions, m.applicationSettings) } if m.hasApplicationSettingsOld { extensions.AddUint16(extensionApplicationSettingsOld) addUint16LengthPrefixedBytes(extensions, m.applicationSettingsOld) } if len(m.customExtension) > 0 { extensions.AddUint16(extensionCustom) addUint16LengthPrefixedBytes(extensions, m.customExtension) } }) }) m.raw = builder.BytesOrPanic() return m.raw } func (m *clientEncryptedExtensionsMsg) unmarshal(data []byte) bool { m.raw = data reader := cryptobyte.String(data[4:]) var extensions cryptobyte.String if !reader.ReadUint16LengthPrefixed(&extensions) || len(reader) != 0 { return false } if !checkDuplicateExtensions(extensions) { return false } for len(extensions) > 0 { var extension uint16 var body cryptobyte.String if !extensions.ReadUint16(&extension) || !extensions.ReadUint16LengthPrefixed(&body) { return false } switch extension { case extensionApplicationSettings: m.hasApplicationSettings = true m.applicationSettings = body case extensionApplicationSettingsOld: m.hasApplicationSettingsOld = true m.applicationSettingsOld = body default: // Unknown extensions are illegal in EncryptedExtensions. return false } } return true } type helloRetryRequestMsg struct { raw []byte vers uint16 sessionID []byte cipherSuite uint16 compressionMethod uint8 hasSelectedGroup bool selectedGroup CurveID cookie []byte customExtension string echConfirmation []byte echConfirmationOffset int duplicateExtensions bool } func (m *helloRetryRequestMsg) marshal() []byte { if m.raw != nil { return m.raw } retryRequestMsg := cryptobyte.NewBuilder(nil) retryRequestMsg.AddUint8(typeServerHello) retryRequestMsg.AddUint24LengthPrefixed(func(retryRequest *cryptobyte.Builder) { retryRequest.AddUint16(VersionTLS12) retryRequest.AddBytes(tls13HelloRetryRequest) addUint8LengthPrefixedBytes(retryRequest, m.sessionID) retryRequest.AddUint16(m.cipherSuite) retryRequest.AddUint8(m.compressionMethod) retryRequest.AddUint16LengthPrefixed(func(extensions *cryptobyte.Builder) { count := 1 if m.duplicateExtensions { count = 2 } for i := 0; i < count; i++ { extensions.AddUint16(extensionSupportedVersions) extensions.AddUint16(2) // Length extensions.AddUint16(m.vers) if m.hasSelectedGroup { extensions.AddUint16(extensionKeyShare) extensions.AddUint16(2) // length extensions.AddUint16(uint16(m.selectedGroup)) } // m.cookie may be a non-nil empty slice for empty cookie tests. if m.cookie != nil { extensions.AddUint16(extensionCookie) extensions.AddUint16LengthPrefixed(func(body *cryptobyte.Builder) { addUint16LengthPrefixedBytes(body, m.cookie) }) } if len(m.customExtension) > 0 { extensions.AddUint16(extensionCustom) addUint16LengthPrefixedBytes(extensions, []byte(m.customExtension)) } if len(m.echConfirmation) > 0 { extensions.AddUint16(extensionEncryptedClientHello) addUint16LengthPrefixedBytes(extensions, m.echConfirmation) } } }) }) m.raw = retryRequestMsg.BytesOrPanic() return m.raw } func (m *helloRetryRequestMsg) unmarshal(data []byte) bool { m.raw = data reader := cryptobyte.String(data[4:]) var legacyVers uint16 var random []byte var compressionMethod byte var extensions cryptobyte.String if !reader.ReadUint16(&legacyVers) || legacyVers != VersionTLS12 || !reader.ReadBytes(&random, 32) || !readUint8LengthPrefixedBytes(&reader, &m.sessionID) || !reader.ReadUint16(&m.cipherSuite) || !reader.ReadUint8(&compressionMethod) || compressionMethod != 0 || !reader.ReadUint16LengthPrefixed(&extensions) || len(reader) != 0 { return false } for len(extensions) > 0 { var extension uint16 var body cryptobyte.String if !extensions.ReadUint16(&extension) || !extensions.ReadUint16LengthPrefixed(&body) { return false } switch extension { case extensionSupportedVersions: if !body.ReadUint16(&m.vers) || len(body) != 0 { return false } case extensionKeyShare: var v uint16 if !body.ReadUint16(&v) || len(body) != 0 { return false } m.hasSelectedGroup = true m.selectedGroup = CurveID(v) case extensionCookie: if !readUint16LengthPrefixedBytes(&body, &m.cookie) || len(m.cookie) == 0 || len(body) != 0 { return false } case extensionEncryptedClientHello: if len(body) != echAcceptConfirmationLength { return false } m.echConfirmation = body m.echConfirmationOffset = len(m.raw) - len(extensions) - len(body) default: // Unknown extensions are illegal from the server. return false } } return true } type certificateEntry struct { data []byte ocspResponse []byte sctList []byte duplicateExtensions bool extraExtension []byte delegatedCredential *delegatedCredential } type delegatedCredential struct { // https://www.rfc-editor.org/rfc/rfc9345.html#section-4 raw []byte signedBytes []byte lifetimeSecs uint32 dcCertVerifyAlgo signatureAlgorithm pkixPublicKey []byte algorithm signatureAlgorithm signature []byte } type certificateMsg struct { raw []byte hasRequestContext bool requestContext []byte certificates []certificateEntry } func (m *certificateMsg) marshal() (x []byte) { if m.raw != nil { return m.raw } certMsg := cryptobyte.NewBuilder(nil) certMsg.AddUint8(typeCertificate) certMsg.AddUint24LengthPrefixed(func(certificate *cryptobyte.Builder) { if m.hasRequestContext { addUint8LengthPrefixedBytes(certificate, m.requestContext) } certificate.AddUint24LengthPrefixed(func(certificateList *cryptobyte.Builder) { for _, cert := range m.certificates { addUint24LengthPrefixedBytes(certificateList, cert.data) if m.hasRequestContext { certificateList.AddUint16LengthPrefixed(func(extensions *cryptobyte.Builder) { count := 1 if cert.duplicateExtensions { count = 2 } for i := 0; i < count; i++ { if cert.ocspResponse != nil { extensions.AddUint16(extensionStatusRequest) extensions.AddUint16LengthPrefixed(func(body *cryptobyte.Builder) { body.AddUint8(statusTypeOCSP) addUint24LengthPrefixedBytes(body, cert.ocspResponse) }) } if cert.sctList != nil { extensions.AddUint16(extensionSignedCertificateTimestamp) addUint16LengthPrefixedBytes(extensions, cert.sctList) } } if cert.extraExtension != nil { extensions.AddBytes(cert.extraExtension) } }) } } }) }) m.raw = certMsg.BytesOrPanic() return m.raw } func (m *certificateMsg) unmarshal(data []byte) bool { m.raw = data reader := cryptobyte.String(data[4:]) if m.hasRequestContext && !readUint8LengthPrefixedBytes(&reader, &m.requestContext) { return false } var certs cryptobyte.String if !reader.ReadUint24LengthPrefixed(&certs) || len(reader) != 0 { return false } m.certificates = nil for len(certs) > 0 { var cert certificateEntry if !readUint24LengthPrefixedBytes(&certs, &cert.data) { return false } if m.hasRequestContext { var extensions cryptobyte.String if !certs.ReadUint16LengthPrefixed(&extensions) || !checkDuplicateExtensions(extensions) { return false } for len(extensions) > 0 { var extension uint16 var body cryptobyte.String if !extensions.ReadUint16(&extension) || !extensions.ReadUint16LengthPrefixed(&body) { return false } switch extension { case extensionStatusRequest: var statusType byte if !body.ReadUint8(&statusType) || statusType != statusTypeOCSP || !readUint24LengthPrefixedBytes(&body, &cert.ocspResponse) || len(body) != 0 { return false } case extensionSignedCertificateTimestamp: cert.sctList = []byte(body) case extensionDelegatedCredential: // https://www.rfc-editor.org/rfc/rfc9345.html#section-4 if cert.delegatedCredential != nil { return false } dc := new(delegatedCredential) origBody := body var dcCertVerifyAlgo, algorithm uint16 if !body.ReadUint32(&dc.lifetimeSecs) || !body.ReadUint16(&dcCertVerifyAlgo) || !readUint24LengthPrefixedBytes(&body, &dc.pkixPublicKey) || !body.ReadUint16(&algorithm) || !readUint16LengthPrefixedBytes(&body, &dc.signature) || len(body) != 0 { return false } dc.dcCertVerifyAlgo = signatureAlgorithm(dcCertVerifyAlgo) dc.algorithm = signatureAlgorithm(algorithm) dc.raw = origBody dc.signedBytes = []byte(origBody)[:4+2+3+len(dc.pkixPublicKey)] cert.delegatedCredential = dc default: return false } } } m.certificates = append(m.certificates, cert) } return true } type compressedCertificateMsg struct { raw []byte algID uint16 uncompressedLength uint32 compressed []byte } func (m *compressedCertificateMsg) marshal() (x []byte) { if m.raw != nil { return m.raw } certMsg := cryptobyte.NewBuilder(nil) certMsg.AddUint8(typeCompressedCertificate) certMsg.AddUint24LengthPrefixed(func(certificate *cryptobyte.Builder) { certificate.AddUint16(m.algID) certificate.AddUint24(m.uncompressedLength) addUint24LengthPrefixedBytes(certificate, m.compressed) }) m.raw = certMsg.BytesOrPanic() return m.raw } func (m *compressedCertificateMsg) unmarshal(data []byte) bool { m.raw = data reader := cryptobyte.String(data[4:]) if !reader.ReadUint16(&m.algID) || !reader.ReadUint24(&m.uncompressedLength) || !readUint24LengthPrefixedBytes(&reader, &m.compressed) || len(reader) != 0 { return false } if m.uncompressedLength >= 1<<17 { return false } return true } type serverKeyExchangeMsg struct { raw []byte key []byte } func (m *serverKeyExchangeMsg) marshal() []byte { if m.raw != nil { return m.raw } msg := cryptobyte.NewBuilder(nil) msg.AddUint8(typeServerKeyExchange) addUint24LengthPrefixedBytes(msg, m.key) m.raw = msg.BytesOrPanic() return m.raw } 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) marshal() []byte { if m.raw != nil { return m.raw } var x []byte if m.statusType == statusTypeOCSP { msg := cryptobyte.NewBuilder(nil) msg.AddUint8(typeCertificateStatus) msg.AddUint24LengthPrefixed(func(body *cryptobyte.Builder) { body.AddUint8(statusTypeOCSP) addUint24LengthPrefixedBytes(body, m.response) }) x = msg.BytesOrPanic() } else { x = []byte{typeCertificateStatus, 0, 0, 1, m.statusType} } m.raw = x return x } func (m *certificateStatusMsg) unmarshal(data []byte) bool { m.raw = data reader := cryptobyte.String(data[4:]) if !reader.ReadUint8(&m.statusType) || m.statusType != statusTypeOCSP || !readUint24LengthPrefixedBytes(&reader, &m.response) || len(reader) != 0 { return false } return true } type serverHelloDoneMsg struct{} 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) marshal() []byte { if m.raw != nil { return m.raw } msg := cryptobyte.NewBuilder(nil) msg.AddUint8(typeClientKeyExchange) addUint24LengthPrefixedBytes(msg, m.ciphertext) m.raw = msg.BytesOrPanic() return m.raw } 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) marshal() []byte { if m.raw != nil { return m.raw } msg := cryptobyte.NewBuilder(nil) msg.AddUint8(typeFinished) addUint24LengthPrefixedBytes(msg, m.verifyData) m.raw = msg.BytesOrPanic() return m.raw } 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) marshal() []byte { if m.raw != nil { return m.raw } padding := 32 - (len(m.proto)+2)%32 msg := cryptobyte.NewBuilder(nil) msg.AddUint8(typeNextProtocol) msg.AddUint24LengthPrefixed(func(body *cryptobyte.Builder) { addUint8LengthPrefixedBytes(body, []byte(m.proto)) addUint8LengthPrefixedBytes(body, make([]byte, padding)) }) m.raw = msg.BytesOrPanic() return m.raw } func (m *nextProtoMsg) unmarshal(data []byte) bool { m.raw = data reader := cryptobyte.String(data[4:]) var proto, padding []byte if !readUint8LengthPrefixedBytes(&reader, &proto) || !readUint8LengthPrefixedBytes(&reader, &padding) || len(reader) != 0 { return false } m.proto = string(proto) // Padding is not meant to be checked normally, but as this is a testing // implementation, we check the padding is as expected. if len(padding) != 32-(len(m.proto)+2)%32 { return false } for _, v := range padding { if v != 0 { return false } } return true } type certificateRequestMsg struct { raw []byte vers uint16 // hasSignatureAlgorithm indicates whether this message includes a list // of signature and hash functions. This change was introduced with TLS // 1.2. hasSignatureAlgorithm bool // hasRequestContext indicates whether this message includes a context // field instead of certificateTypes. This change was introduced with // TLS 1.3. hasRequestContext bool certificateTypes []byte requestContext []byte signatureAlgorithms []signatureAlgorithm signatureAlgorithmsCert []signatureAlgorithm certificateAuthorities [][]byte hasCAExtension bool customExtension uint16 } func (m *certificateRequestMsg) marshal() []byte { if m.raw != nil { return m.raw } // See http://tools.ietf.org/html/rfc4346#section-7.4.4 builder := cryptobyte.NewBuilder(nil) builder.AddUint8(typeCertificateRequest) builder.AddUint24LengthPrefixed(func(body *cryptobyte.Builder) { if m.hasRequestContext { addUint8LengthPrefixedBytes(body, m.requestContext) body.AddUint16LengthPrefixed(func(extensions *cryptobyte.Builder) { if m.hasSignatureAlgorithm { extensions.AddUint16(extensionSignatureAlgorithms) extensions.AddUint16LengthPrefixed(func(extension *cryptobyte.Builder) { extension.AddUint16LengthPrefixed(func(signatureAlgorithms *cryptobyte.Builder) { for _, sigAlg := range m.signatureAlgorithms { signatureAlgorithms.AddUint16(uint16(sigAlg)) } }) }) } if len(m.signatureAlgorithmsCert) > 0 { extensions.AddUint16(extensionSignatureAlgorithmsCert) extensions.AddUint16LengthPrefixed(func(extension *cryptobyte.Builder) { extension.AddUint16LengthPrefixed(func(signatureAlgorithmsCert *cryptobyte.Builder) { for _, sigAlg := range m.signatureAlgorithmsCert { signatureAlgorithmsCert.AddUint16(uint16(sigAlg)) } }) }) } if len(m.certificateAuthorities) > 0 { extensions.AddUint16(extensionCertificateAuthorities) extensions.AddUint16LengthPrefixed(func(extension *cryptobyte.Builder) { extension.AddUint16LengthPrefixed(func(certificateAuthorities *cryptobyte.Builder) { for _, ca := range m.certificateAuthorities { addUint16LengthPrefixedBytes(certificateAuthorities, ca) } }) }) } if m.customExtension > 0 { extensions.AddUint16(m.customExtension) extensions.AddUint16(0) // Empty extension } }) } else { addUint8LengthPrefixedBytes(body, m.certificateTypes) if m.hasSignatureAlgorithm { body.AddUint16LengthPrefixed(func(signatureAlgorithms *cryptobyte.Builder) { for _, sigAlg := range m.signatureAlgorithms { signatureAlgorithms.AddUint16(uint16(sigAlg)) } }) } body.AddUint16LengthPrefixed(func(certificateAuthorities *cryptobyte.Builder) { for _, ca := range m.certificateAuthorities { addUint16LengthPrefixedBytes(certificateAuthorities, ca) } }) } }) m.raw = builder.BytesOrPanic() return m.raw } func parseCAs(reader *cryptobyte.String, out *[][]byte) bool { var cas cryptobyte.String if !reader.ReadUint16LengthPrefixed(&cas) { return false } for len(cas) > 0 { var ca []byte if !readUint16LengthPrefixedBytes(&cas, &ca) { return false } *out = append(*out, ca) } return true } func (m *certificateRequestMsg) unmarshal(data []byte) bool { m.raw = data reader := cryptobyte.String(data[4:]) if m.hasRequestContext { var extensions cryptobyte.String if !readUint8LengthPrefixedBytes(&reader, &m.requestContext) || !reader.ReadUint16LengthPrefixed(&extensions) || len(reader) != 0 || !checkDuplicateExtensions(extensions) { return false } for len(extensions) > 0 { var extension uint16 var body cryptobyte.String if !extensions.ReadUint16(&extension) || !extensions.ReadUint16LengthPrefixed(&body) { return false } switch extension { case extensionSignatureAlgorithms: if !parseSignatureAlgorithms(&body, &m.signatureAlgorithms, false) || len(body) != 0 { return false } case extensionSignatureAlgorithmsCert: if !parseSignatureAlgorithms(&body, &m.signatureAlgorithmsCert, false) || len(body) != 0 { return false } case extensionCertificateAuthorities: if !parseCAs(&body, &m.certificateAuthorities) || len(body) != 0 { return false } m.hasCAExtension = true } } } else { if !readUint8LengthPrefixedBytes(&reader, &m.certificateTypes) { return false } // In TLS 1.2, the supported_signature_algorithms field in // CertificateRequest may be empty. if m.hasSignatureAlgorithm && !parseSignatureAlgorithms(&reader, &m.signatureAlgorithms, true) { return false } if !parseCAs(&reader, &m.certificateAuthorities) || len(reader) != 0 { return false } } return true } type certificateVerifyMsg struct { raw []byte hasSignatureAlgorithm bool signatureAlgorithm signatureAlgorithm signature []byte } 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.hasSignatureAlgorithm { 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.hasSignatureAlgorithm { y[0] = byte(m.signatureAlgorithm >> 8) y[1] = byte(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) 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.hasSignatureAlgorithm { m.signatureAlgorithm = signatureAlgorithm(data[0])<<8 | signatureAlgorithm(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 vers uint16 isDTLS bool ticketLifetime uint32 ticketAgeAdd uint32 ticketNonce []byte ticket []byte maxEarlyDataSize uint32 customExtension string duplicateEarlyDataExtension bool hasGREASEExtension bool } func (m *newSessionTicketMsg) marshal() []byte { if m.raw != nil { return m.raw } version, ok := wireToVersion(m.vers, m.isDTLS) if !ok { panic("unknown version") } // See http://tools.ietf.org/html/rfc5077#section-3.3 ticketMsg := cryptobyte.NewBuilder(nil) ticketMsg.AddUint8(typeNewSessionTicket) ticketMsg.AddUint24LengthPrefixed(func(body *cryptobyte.Builder) { body.AddUint32(m.ticketLifetime) if version >= VersionTLS13 { body.AddUint32(m.ticketAgeAdd) addUint8LengthPrefixedBytes(body, m.ticketNonce) } addUint16LengthPrefixedBytes(body, m.ticket) if version >= VersionTLS13 { body.AddUint16LengthPrefixed(func(extensions *cryptobyte.Builder) { if m.maxEarlyDataSize > 0 { extensions.AddUint16(extensionEarlyData) extensions.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) { child.AddUint32(m.maxEarlyDataSize) }) if m.duplicateEarlyDataExtension { extensions.AddUint16(extensionEarlyData) extensions.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) { child.AddUint32(m.maxEarlyDataSize) }) } } if len(m.customExtension) > 0 { extensions.AddUint16(extensionCustom) addUint16LengthPrefixedBytes(extensions, []byte(m.customExtension)) } }) } }) m.raw = ticketMsg.BytesOrPanic() return m.raw } func (m *newSessionTicketMsg) unmarshal(data []byte) bool { m.raw = data version, ok := wireToVersion(m.vers, m.isDTLS) if !ok { panic("unknown version") } if len(data) < 8 { return false } m.ticketLifetime = uint32(data[4])<<24 | uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7]) data = data[8:] if version >= VersionTLS13 { if len(data) < 4 { return false } m.ticketAgeAdd = uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) data = data[4:] nonceLen := int(data[0]) data = data[1:] if len(data) < nonceLen { return false } m.ticketNonce = data[:nonceLen] data = data[nonceLen:] } if len(data) < 2 { return false } ticketLen := int(data[0])<<8 + int(data[1]) data = data[2:] if len(data) < ticketLen { return false } if version >= VersionTLS13 && ticketLen == 0 { return false } m.ticket = data[:ticketLen] data = data[ticketLen:] if version >= VersionTLS13 { 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 extensionEarlyData: if length != 4 { return false } m.maxEarlyDataSize = uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) default: if isGREASEValue(extension) { m.hasGREASEExtension = true } } data = data[length:] } } if len(data) > 0 { return false } return true } type helloVerifyRequestMsg struct { raw []byte vers uint16 cookie []byte } func (m *helloVerifyRequestMsg) marshal() []byte { if m.raw != nil { return m.raw } length := 2 + 1 + len(m.cookie) x := make([]byte, 4+length) x[0] = typeHelloVerifyRequest x[1] = uint8(length >> 16) x[2] = uint8(length >> 8) x[3] = uint8(length) vers := m.vers x[4] = uint8(vers >> 8) x[5] = uint8(vers) x[6] = uint8(len(m.cookie)) copy(x[7:7+len(m.cookie)], m.cookie) return x } func (m *helloVerifyRequestMsg) unmarshal(data []byte) bool { if len(data) < 4+2+1 { return false } m.raw = data m.vers = uint16(data[4])<<8 | uint16(data[5]) cookieLen := int(data[6]) if cookieLen > 32 || len(data) != 7+cookieLen { return false } m.cookie = data[7 : 7+cookieLen] return true } type channelIDMsg struct { raw []byte channelID []byte } func (m *channelIDMsg) marshal() []byte { if m.raw != nil { return m.raw } length := 2 + 2 + len(m.channelID) x := make([]byte, 4+length) x[0] = typeChannelID x[1] = uint8(length >> 16) x[2] = uint8(length >> 8) x[3] = uint8(length) x[4] = uint8(extensionChannelID >> 8) x[5] = uint8(extensionChannelID & 0xff) x[6] = uint8(len(m.channelID) >> 8) x[7] = uint8(len(m.channelID) & 0xff) copy(x[8:], m.channelID) return x } func (m *channelIDMsg) unmarshal(data []byte) bool { if len(data) != 4+2+2+128 { return false } m.raw = data if (uint16(data[4])<<8)|uint16(data[5]) != extensionChannelID { return false } if int(data[6])<<8|int(data[7]) != 128 { return false } m.channelID = data[4+2+2:] 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 } type keyUpdateMsg struct { raw []byte keyUpdateRequest byte } func (m *keyUpdateMsg) marshal() []byte { if m.raw != nil { return m.raw } return []byte{typeKeyUpdate, 0, 0, 1, m.keyUpdateRequest} } func (m *keyUpdateMsg) unmarshal(data []byte) bool { m.raw = data if len(data) != 5 { return false } length := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) if len(data)-4 != length { return false } m.keyUpdateRequest = data[4] return m.keyUpdateRequest == keyUpdateNotRequested || m.keyUpdateRequest == keyUpdateRequested } type endOfEarlyDataMsg struct { nonEmpty bool } func (m *endOfEarlyDataMsg) marshal() []byte { if m.nonEmpty { return []byte{typeEndOfEarlyData, 0, 0, 1, 42} } return []byte{typeEndOfEarlyData, 0, 0, 0} } func (*endOfEarlyDataMsg) unmarshal(data []byte) bool { return len(data) == 4 }