|  | // Copyright 2009 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package tls | 
|  |  | 
|  | import ( | 
|  | "fmt" | 
|  | "strings" | 
|  |  | 
|  | "golang.org/x/crypto/cryptobyte" | 
|  | ) | 
|  |  | 
|  | // The marshalingFunction type is an adapter to allow the use of ordinary | 
|  | // functions as cryptobyte.MarshalingValue. | 
|  | type marshalingFunction func(b *cryptobyte.Builder) error | 
|  |  | 
|  | func (f marshalingFunction) Marshal(b *cryptobyte.Builder) error { | 
|  | return f(b) | 
|  | } | 
|  |  | 
|  | // addBytesWithLength appends a sequence of bytes to the cryptobyte.Builder. If | 
|  | // the length of the sequence is not the value specified, it produces an error. | 
|  | func addBytesWithLength(b *cryptobyte.Builder, v []byte, n int) { | 
|  | b.AddValue(marshalingFunction(func(b *cryptobyte.Builder) error { | 
|  | if len(v) != n { | 
|  | return fmt.Errorf("invalid value length: expected %d, got %d", n, len(v)) | 
|  | } | 
|  | b.AddBytes(v) | 
|  | return nil | 
|  | })) | 
|  | } | 
|  |  | 
|  | // addUint64 appends a big-endian, 64-bit value to the cryptobyte.Builder. | 
|  | func addUint64(b *cryptobyte.Builder, v uint64) { | 
|  | b.AddUint32(uint32(v >> 32)) | 
|  | b.AddUint32(uint32(v)) | 
|  | } | 
|  |  | 
|  | // readUint64 decodes a big-endian, 64-bit value into out and advances over it. | 
|  | // It reports whether the read was successful. | 
|  | func readUint64(s *cryptobyte.String, out *uint64) bool { | 
|  | var hi, lo uint32 | 
|  | if !s.ReadUint32(&hi) || !s.ReadUint32(&lo) { | 
|  | return false | 
|  | } | 
|  | *out = uint64(hi)<<32 | uint64(lo) | 
|  | return true | 
|  | } | 
|  |  | 
|  | // readUint8LengthPrefixed acts like s.ReadUint8LengthPrefixed, but targets a | 
|  | // []byte instead of a cryptobyte.String. | 
|  | func readUint8LengthPrefixed(s *cryptobyte.String, out *[]byte) bool { | 
|  | return s.ReadUint8LengthPrefixed((*cryptobyte.String)(out)) | 
|  | } | 
|  |  | 
|  | // readUint16LengthPrefixed acts like s.ReadUint16LengthPrefixed, but targets a | 
|  | // []byte instead of a cryptobyte.String. | 
|  | func readUint16LengthPrefixed(s *cryptobyte.String, out *[]byte) bool { | 
|  | return s.ReadUint16LengthPrefixed((*cryptobyte.String)(out)) | 
|  | } | 
|  |  | 
|  | // readUint24LengthPrefixed acts like s.ReadUint24LengthPrefixed, but targets a | 
|  | // []byte instead of a cryptobyte.String. | 
|  | func readUint24LengthPrefixed(s *cryptobyte.String, out *[]byte) bool { | 
|  | return s.ReadUint24LengthPrefixed((*cryptobyte.String)(out)) | 
|  | } | 
|  |  | 
|  | type clientHelloMsg struct { | 
|  | raw                              []byte | 
|  | vers                             uint16 | 
|  | random                           []byte | 
|  | sessionId                        []byte | 
|  | cipherSuites                     []uint16 | 
|  | compressionMethods               []uint8 | 
|  | serverName                       string | 
|  | ocspStapling                     bool | 
|  | supportedCurves                  []CurveID | 
|  | supportedPoints                  []uint8 | 
|  | ticketSupported                  bool | 
|  | sessionTicket                    []uint8 | 
|  | supportedSignatureAlgorithms     []SignatureScheme | 
|  | supportedSignatureAlgorithmsCert []SignatureScheme | 
|  | secureRenegotiationSupported     bool | 
|  | secureRenegotiation              []byte | 
|  | alpnProtocols                    []string | 
|  | scts                             bool | 
|  | supportedVersions                []uint16 | 
|  | cookie                           []byte | 
|  | keyShares                        []keyShare | 
|  | earlyData                        bool | 
|  | pskModes                         []uint8 | 
|  | pskIdentities                    []pskIdentity | 
|  | pskBinders                       [][]byte | 
|  | } | 
|  |  | 
|  | func (m *clientHelloMsg) marshal() []byte { | 
|  | if m.raw != nil { | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | var b cryptobyte.Builder | 
|  | b.AddUint8(typeClientHello) | 
|  | b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16(m.vers) | 
|  | addBytesWithLength(b, m.random, 32) | 
|  | b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(m.sessionId) | 
|  | }) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | for _, suite := range m.cipherSuites { | 
|  | b.AddUint16(suite) | 
|  | } | 
|  | }) | 
|  | b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(m.compressionMethods) | 
|  | }) | 
|  |  | 
|  | // If extensions aren't present, omit them. | 
|  | var extensionsPresent bool | 
|  | bWithoutExtensions := *b | 
|  |  | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | if len(m.serverName) > 0 { | 
|  | // RFC 6066, Section 3 | 
|  | b.AddUint16(extensionServerName) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint8(0) // name_type = host_name | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes([]byte(m.serverName)) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if m.ocspStapling { | 
|  | // RFC 4366, Section 3.6 | 
|  | b.AddUint16(extensionStatusRequest) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint8(1)  // status_type = ocsp | 
|  | b.AddUint16(0) // empty responder_id_list | 
|  | b.AddUint16(0) // empty request_extensions | 
|  | }) | 
|  | } | 
|  | if len(m.supportedCurves) > 0 { | 
|  | // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7 | 
|  | b.AddUint16(extensionSupportedCurves) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | for _, curve := range m.supportedCurves { | 
|  | b.AddUint16(uint16(curve)) | 
|  | } | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if len(m.supportedPoints) > 0 { | 
|  | // RFC 4492, Section 5.1.2 | 
|  | b.AddUint16(extensionSupportedPoints) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(m.supportedPoints) | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if m.ticketSupported { | 
|  | // RFC 5077, Section 3.2 | 
|  | b.AddUint16(extensionSessionTicket) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(m.sessionTicket) | 
|  | }) | 
|  | } | 
|  | if len(m.supportedSignatureAlgorithms) > 0 { | 
|  | // RFC 5246, Section 7.4.1.4.1 | 
|  | b.AddUint16(extensionSignatureAlgorithms) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | for _, sigAlgo := range m.supportedSignatureAlgorithms { | 
|  | b.AddUint16(uint16(sigAlgo)) | 
|  | } | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if len(m.supportedSignatureAlgorithmsCert) > 0 { | 
|  | // RFC 8446, Section 4.2.3 | 
|  | b.AddUint16(extensionSignatureAlgorithmsCert) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | for _, sigAlgo := range m.supportedSignatureAlgorithmsCert { | 
|  | b.AddUint16(uint16(sigAlgo)) | 
|  | } | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if m.secureRenegotiationSupported { | 
|  | // RFC 5746, Section 3.2 | 
|  | b.AddUint16(extensionRenegotiationInfo) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(m.secureRenegotiation) | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if len(m.alpnProtocols) > 0 { | 
|  | // RFC 7301, Section 3.1 | 
|  | b.AddUint16(extensionALPN) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | for _, proto := range m.alpnProtocols { | 
|  | b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes([]byte(proto)) | 
|  | }) | 
|  | } | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if m.scts { | 
|  | // RFC 6962, Section 3.3.1 | 
|  | b.AddUint16(extensionSCT) | 
|  | b.AddUint16(0) // empty extension_data | 
|  | } | 
|  | if len(m.supportedVersions) > 0 { | 
|  | // RFC 8446, Section 4.2.1 | 
|  | b.AddUint16(extensionSupportedVersions) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | for _, vers := range m.supportedVersions { | 
|  | b.AddUint16(vers) | 
|  | } | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if len(m.cookie) > 0 { | 
|  | // RFC 8446, Section 4.2.2 | 
|  | b.AddUint16(extensionCookie) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(m.cookie) | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if len(m.keyShares) > 0 { | 
|  | // RFC 8446, Section 4.2.8 | 
|  | b.AddUint16(extensionKeyShare) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | for _, ks := range m.keyShares { | 
|  | b.AddUint16(uint16(ks.group)) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(ks.data) | 
|  | }) | 
|  | } | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if m.earlyData { | 
|  | // RFC 8446, Section 4.2.10 | 
|  | b.AddUint16(extensionEarlyData) | 
|  | b.AddUint16(0) // empty extension_data | 
|  | } | 
|  | if len(m.pskModes) > 0 { | 
|  | // RFC 8446, Section 4.2.9 | 
|  | b.AddUint16(extensionPSKModes) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(m.pskModes) | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if len(m.pskIdentities) > 0 { // pre_shared_key must be the last extension | 
|  | // RFC 8446, Section 4.2.11 | 
|  | b.AddUint16(extensionPreSharedKey) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | for _, psk := range m.pskIdentities { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(psk.label) | 
|  | }) | 
|  | b.AddUint32(psk.obfuscatedTicketAge) | 
|  | } | 
|  | }) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | for _, binder := range m.pskBinders { | 
|  | b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(binder) | 
|  | }) | 
|  | } | 
|  | }) | 
|  | }) | 
|  | } | 
|  |  | 
|  | extensionsPresent = len(b.BytesOrPanic()) > 2 | 
|  | }) | 
|  |  | 
|  | if !extensionsPresent { | 
|  | *b = bWithoutExtensions | 
|  | } | 
|  | }) | 
|  |  | 
|  | m.raw = b.BytesOrPanic() | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | // marshalWithoutBinders returns the ClientHello through the | 
|  | // PreSharedKeyExtension.identities field, according to RFC 8446, Section | 
|  | // 4.2.11.2. Note that m.pskBinders must be set to slices of the correct length. | 
|  | func (m *clientHelloMsg) marshalWithoutBinders() []byte { | 
|  | bindersLen := 2 // uint16 length prefix | 
|  | for _, binder := range m.pskBinders { | 
|  | bindersLen += 1 // uint8 length prefix | 
|  | bindersLen += len(binder) | 
|  | } | 
|  |  | 
|  | fullMessage := m.marshal() | 
|  | return fullMessage[:len(fullMessage)-bindersLen] | 
|  | } | 
|  |  | 
|  | // updateBinders updates the m.pskBinders field, if necessary updating the | 
|  | // cached marshaled representation. The supplied binders must have the same | 
|  | // length as the current m.pskBinders. | 
|  | func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) { | 
|  | if len(pskBinders) != len(m.pskBinders) { | 
|  | panic("tls: internal error: pskBinders length mismatch") | 
|  | } | 
|  | for i := range m.pskBinders { | 
|  | if len(pskBinders[i]) != len(m.pskBinders[i]) { | 
|  | panic("tls: internal error: pskBinders length mismatch") | 
|  | } | 
|  | } | 
|  | m.pskBinders = pskBinders | 
|  | if m.raw != nil { | 
|  | lenWithoutBinders := len(m.marshalWithoutBinders()) | 
|  | // TODO(filippo): replace with NewFixedBuilder once CL 148882 is imported. | 
|  | b := cryptobyte.NewBuilder(m.raw[:lenWithoutBinders]) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | for _, binder := range m.pskBinders { | 
|  | b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(binder) | 
|  | }) | 
|  | } | 
|  | }) | 
|  | if len(b.BytesOrPanic()) != len(m.raw) { | 
|  | panic("tls: internal error: failed to update binders") | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func (m *clientHelloMsg) unmarshal(data []byte) bool { | 
|  | *m = clientHelloMsg{raw: data} | 
|  | s := cryptobyte.String(data) | 
|  |  | 
|  | if !s.Skip(4) || // message type and uint24 length field | 
|  | !s.ReadUint16(&m.vers) || !s.ReadBytes(&m.random, 32) || | 
|  | !readUint8LengthPrefixed(&s, &m.sessionId) { | 
|  | return false | 
|  | } | 
|  |  | 
|  | var cipherSuites cryptobyte.String | 
|  | if !s.ReadUint16LengthPrefixed(&cipherSuites) { | 
|  | return false | 
|  | } | 
|  | m.cipherSuites = []uint16{} | 
|  | m.secureRenegotiationSupported = false | 
|  | for !cipherSuites.Empty() { | 
|  | var suite uint16 | 
|  | if !cipherSuites.ReadUint16(&suite) { | 
|  | return false | 
|  | } | 
|  | if suite == scsvRenegotiation { | 
|  | m.secureRenegotiationSupported = true | 
|  | } | 
|  | m.cipherSuites = append(m.cipherSuites, suite) | 
|  | } | 
|  |  | 
|  | if !readUint8LengthPrefixed(&s, &m.compressionMethods) { | 
|  | return false | 
|  | } | 
|  |  | 
|  | if s.Empty() { | 
|  | // ClientHello is optionally followed by extension data | 
|  | return true | 
|  | } | 
|  |  | 
|  | var extensions cryptobyte.String | 
|  | if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() { | 
|  | return false | 
|  | } | 
|  |  | 
|  | for !extensions.Empty() { | 
|  | var extension uint16 | 
|  | var extData cryptobyte.String | 
|  | if !extensions.ReadUint16(&extension) || | 
|  | !extensions.ReadUint16LengthPrefixed(&extData) { | 
|  | return false | 
|  | } | 
|  |  | 
|  | switch extension { | 
|  | case extensionServerName: | 
|  | // RFC 6066, Section 3 | 
|  | var nameList cryptobyte.String | 
|  | if !extData.ReadUint16LengthPrefixed(&nameList) || nameList.Empty() { | 
|  | return false | 
|  | } | 
|  | for !nameList.Empty() { | 
|  | var nameType uint8 | 
|  | var serverName cryptobyte.String | 
|  | if !nameList.ReadUint8(&nameType) || | 
|  | !nameList.ReadUint16LengthPrefixed(&serverName) || | 
|  | serverName.Empty() { | 
|  | return false | 
|  | } | 
|  | if nameType != 0 { | 
|  | continue | 
|  | } | 
|  | if len(m.serverName) != 0 { | 
|  | // Multiple names of the same name_type are prohibited. | 
|  | return false | 
|  | } | 
|  | m.serverName = string(serverName) | 
|  | // An SNI value may not include a trailing dot. | 
|  | if strings.HasSuffix(m.serverName, ".") { | 
|  | return false | 
|  | } | 
|  | } | 
|  | case extensionStatusRequest: | 
|  | // RFC 4366, Section 3.6 | 
|  | var statusType uint8 | 
|  | var ignored cryptobyte.String | 
|  | if !extData.ReadUint8(&statusType) || | 
|  | !extData.ReadUint16LengthPrefixed(&ignored) || | 
|  | !extData.ReadUint16LengthPrefixed(&ignored) { | 
|  | return false | 
|  | } | 
|  | m.ocspStapling = statusType == statusTypeOCSP | 
|  | case extensionSupportedCurves: | 
|  | // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7 | 
|  | var curves cryptobyte.String | 
|  | if !extData.ReadUint16LengthPrefixed(&curves) || curves.Empty() { | 
|  | return false | 
|  | } | 
|  | for !curves.Empty() { | 
|  | var curve uint16 | 
|  | if !curves.ReadUint16(&curve) { | 
|  | return false | 
|  | } | 
|  | m.supportedCurves = append(m.supportedCurves, CurveID(curve)) | 
|  | } | 
|  | case extensionSupportedPoints: | 
|  | // RFC 4492, Section 5.1.2 | 
|  | if !readUint8LengthPrefixed(&extData, &m.supportedPoints) || | 
|  | len(m.supportedPoints) == 0 { | 
|  | return false | 
|  | } | 
|  | case extensionSessionTicket: | 
|  | // RFC 5077, Section 3.2 | 
|  | m.ticketSupported = true | 
|  | extData.ReadBytes(&m.sessionTicket, len(extData)) | 
|  | case extensionSignatureAlgorithms: | 
|  | // RFC 5246, Section 7.4.1.4.1 | 
|  | var sigAndAlgs cryptobyte.String | 
|  | if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() { | 
|  | return false | 
|  | } | 
|  | for !sigAndAlgs.Empty() { | 
|  | var sigAndAlg uint16 | 
|  | if !sigAndAlgs.ReadUint16(&sigAndAlg) { | 
|  | return false | 
|  | } | 
|  | m.supportedSignatureAlgorithms = append( | 
|  | m.supportedSignatureAlgorithms, SignatureScheme(sigAndAlg)) | 
|  | } | 
|  | case extensionSignatureAlgorithmsCert: | 
|  | // RFC 8446, Section 4.2.3 | 
|  | var sigAndAlgs cryptobyte.String | 
|  | if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() { | 
|  | return false | 
|  | } | 
|  | for !sigAndAlgs.Empty() { | 
|  | var sigAndAlg uint16 | 
|  | if !sigAndAlgs.ReadUint16(&sigAndAlg) { | 
|  | return false | 
|  | } | 
|  | m.supportedSignatureAlgorithmsCert = append( | 
|  | m.supportedSignatureAlgorithmsCert, SignatureScheme(sigAndAlg)) | 
|  | } | 
|  | case extensionRenegotiationInfo: | 
|  | // RFC 5746, Section 3.2 | 
|  | if !readUint8LengthPrefixed(&extData, &m.secureRenegotiation) { | 
|  | return false | 
|  | } | 
|  | m.secureRenegotiationSupported = true | 
|  | case extensionALPN: | 
|  | // RFC 7301, Section 3.1 | 
|  | var protoList cryptobyte.String | 
|  | if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() { | 
|  | return false | 
|  | } | 
|  | for !protoList.Empty() { | 
|  | var proto cryptobyte.String | 
|  | if !protoList.ReadUint8LengthPrefixed(&proto) || proto.Empty() { | 
|  | return false | 
|  | } | 
|  | m.alpnProtocols = append(m.alpnProtocols, string(proto)) | 
|  | } | 
|  | case extensionSCT: | 
|  | // RFC 6962, Section 3.3.1 | 
|  | m.scts = true | 
|  | case extensionSupportedVersions: | 
|  | // RFC 8446, Section 4.2.1 | 
|  | var versList cryptobyte.String | 
|  | if !extData.ReadUint8LengthPrefixed(&versList) || versList.Empty() { | 
|  | return false | 
|  | } | 
|  | for !versList.Empty() { | 
|  | var vers uint16 | 
|  | if !versList.ReadUint16(&vers) { | 
|  | return false | 
|  | } | 
|  | m.supportedVersions = append(m.supportedVersions, vers) | 
|  | } | 
|  | case extensionCookie: | 
|  | // RFC 8446, Section 4.2.2 | 
|  | if !readUint16LengthPrefixed(&extData, &m.cookie) || | 
|  | len(m.cookie) == 0 { | 
|  | return false | 
|  | } | 
|  | case extensionKeyShare: | 
|  | // RFC 8446, Section 4.2.8 | 
|  | var clientShares cryptobyte.String | 
|  | if !extData.ReadUint16LengthPrefixed(&clientShares) { | 
|  | return false | 
|  | } | 
|  | for !clientShares.Empty() { | 
|  | var ks keyShare | 
|  | if !clientShares.ReadUint16((*uint16)(&ks.group)) || | 
|  | !readUint16LengthPrefixed(&clientShares, &ks.data) || | 
|  | len(ks.data) == 0 { | 
|  | return false | 
|  | } | 
|  | m.keyShares = append(m.keyShares, ks) | 
|  | } | 
|  | case extensionEarlyData: | 
|  | // RFC 8446, Section 4.2.10 | 
|  | m.earlyData = true | 
|  | case extensionPSKModes: | 
|  | // RFC 8446, Section 4.2.9 | 
|  | if !readUint8LengthPrefixed(&extData, &m.pskModes) { | 
|  | return false | 
|  | } | 
|  | case extensionPreSharedKey: | 
|  | // RFC 8446, Section 4.2.11 | 
|  | if !extensions.Empty() { | 
|  | return false // pre_shared_key must be the last extension | 
|  | } | 
|  | var identities cryptobyte.String | 
|  | if !extData.ReadUint16LengthPrefixed(&identities) || identities.Empty() { | 
|  | return false | 
|  | } | 
|  | for !identities.Empty() { | 
|  | var psk pskIdentity | 
|  | if !readUint16LengthPrefixed(&identities, &psk.label) || | 
|  | !identities.ReadUint32(&psk.obfuscatedTicketAge) || | 
|  | len(psk.label) == 0 { | 
|  | return false | 
|  | } | 
|  | m.pskIdentities = append(m.pskIdentities, psk) | 
|  | } | 
|  | var binders cryptobyte.String | 
|  | if !extData.ReadUint16LengthPrefixed(&binders) || binders.Empty() { | 
|  | return false | 
|  | } | 
|  | for !binders.Empty() { | 
|  | var binder []byte | 
|  | if !readUint8LengthPrefixed(&binders, &binder) || | 
|  | len(binder) == 0 { | 
|  | return false | 
|  | } | 
|  | m.pskBinders = append(m.pskBinders, binder) | 
|  | } | 
|  | default: | 
|  | // Ignore unknown extensions. | 
|  | continue | 
|  | } | 
|  |  | 
|  | if !extData.Empty() { | 
|  | return false | 
|  | } | 
|  | } | 
|  |  | 
|  | return true | 
|  | } | 
|  |  | 
|  | type serverHelloMsg struct { | 
|  | raw                          []byte | 
|  | vers                         uint16 | 
|  | random                       []byte | 
|  | sessionId                    []byte | 
|  | cipherSuite                  uint16 | 
|  | compressionMethod            uint8 | 
|  | ocspStapling                 bool | 
|  | ticketSupported              bool | 
|  | secureRenegotiationSupported bool | 
|  | secureRenegotiation          []byte | 
|  | alpnProtocol                 string | 
|  | scts                         [][]byte | 
|  | supportedVersion             uint16 | 
|  | serverShare                  keyShare | 
|  | selectedIdentityPresent      bool | 
|  | selectedIdentity             uint16 | 
|  | supportedPoints              []uint8 | 
|  |  | 
|  | // HelloRetryRequest extensions | 
|  | cookie        []byte | 
|  | selectedGroup CurveID | 
|  | } | 
|  |  | 
|  | func (m *serverHelloMsg) marshal() []byte { | 
|  | if m.raw != nil { | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | var b cryptobyte.Builder | 
|  | b.AddUint8(typeServerHello) | 
|  | b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16(m.vers) | 
|  | addBytesWithLength(b, m.random, 32) | 
|  | b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(m.sessionId) | 
|  | }) | 
|  | b.AddUint16(m.cipherSuite) | 
|  | b.AddUint8(m.compressionMethod) | 
|  |  | 
|  | // If extensions aren't present, omit them. | 
|  | var extensionsPresent bool | 
|  | bWithoutExtensions := *b | 
|  |  | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | if m.ocspStapling { | 
|  | b.AddUint16(extensionStatusRequest) | 
|  | b.AddUint16(0) // empty extension_data | 
|  | } | 
|  | if m.ticketSupported { | 
|  | b.AddUint16(extensionSessionTicket) | 
|  | b.AddUint16(0) // empty extension_data | 
|  | } | 
|  | if m.secureRenegotiationSupported { | 
|  | b.AddUint16(extensionRenegotiationInfo) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(m.secureRenegotiation) | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if len(m.alpnProtocol) > 0 { | 
|  | b.AddUint16(extensionALPN) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes([]byte(m.alpnProtocol)) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if len(m.scts) > 0 { | 
|  | b.AddUint16(extensionSCT) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | for _, sct := range m.scts { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(sct) | 
|  | }) | 
|  | } | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if m.supportedVersion != 0 { | 
|  | b.AddUint16(extensionSupportedVersions) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16(m.supportedVersion) | 
|  | }) | 
|  | } | 
|  | if m.serverShare.group != 0 { | 
|  | b.AddUint16(extensionKeyShare) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16(uint16(m.serverShare.group)) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(m.serverShare.data) | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if m.selectedIdentityPresent { | 
|  | b.AddUint16(extensionPreSharedKey) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16(m.selectedIdentity) | 
|  | }) | 
|  | } | 
|  |  | 
|  | if len(m.cookie) > 0 { | 
|  | b.AddUint16(extensionCookie) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(m.cookie) | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if m.selectedGroup != 0 { | 
|  | b.AddUint16(extensionKeyShare) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16(uint16(m.selectedGroup)) | 
|  | }) | 
|  | } | 
|  | if len(m.supportedPoints) > 0 { | 
|  | b.AddUint16(extensionSupportedPoints) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(m.supportedPoints) | 
|  | }) | 
|  | }) | 
|  | } | 
|  |  | 
|  | extensionsPresent = len(b.BytesOrPanic()) > 2 | 
|  | }) | 
|  |  | 
|  | if !extensionsPresent { | 
|  | *b = bWithoutExtensions | 
|  | } | 
|  | }) | 
|  |  | 
|  | m.raw = b.BytesOrPanic() | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | func (m *serverHelloMsg) unmarshal(data []byte) bool { | 
|  | *m = serverHelloMsg{raw: data} | 
|  | s := cryptobyte.String(data) | 
|  |  | 
|  | if !s.Skip(4) || // message type and uint24 length field | 
|  | !s.ReadUint16(&m.vers) || !s.ReadBytes(&m.random, 32) || | 
|  | !readUint8LengthPrefixed(&s, &m.sessionId) || | 
|  | !s.ReadUint16(&m.cipherSuite) || | 
|  | !s.ReadUint8(&m.compressionMethod) { | 
|  | return false | 
|  | } | 
|  |  | 
|  | if s.Empty() { | 
|  | // ServerHello is optionally followed by extension data | 
|  | return true | 
|  | } | 
|  |  | 
|  | var extensions cryptobyte.String | 
|  | if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() { | 
|  | return false | 
|  | } | 
|  |  | 
|  | for !extensions.Empty() { | 
|  | var extension uint16 | 
|  | var extData cryptobyte.String | 
|  | if !extensions.ReadUint16(&extension) || | 
|  | !extensions.ReadUint16LengthPrefixed(&extData) { | 
|  | return false | 
|  | } | 
|  |  | 
|  | switch extension { | 
|  | case extensionStatusRequest: | 
|  | m.ocspStapling = true | 
|  | case extensionSessionTicket: | 
|  | m.ticketSupported = true | 
|  | case extensionRenegotiationInfo: | 
|  | if !readUint8LengthPrefixed(&extData, &m.secureRenegotiation) { | 
|  | return false | 
|  | } | 
|  | m.secureRenegotiationSupported = true | 
|  | case extensionALPN: | 
|  | var protoList cryptobyte.String | 
|  | if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() { | 
|  | return false | 
|  | } | 
|  | var proto cryptobyte.String | 
|  | if !protoList.ReadUint8LengthPrefixed(&proto) || | 
|  | proto.Empty() || !protoList.Empty() { | 
|  | return false | 
|  | } | 
|  | m.alpnProtocol = string(proto) | 
|  | case extensionSCT: | 
|  | var sctList cryptobyte.String | 
|  | if !extData.ReadUint16LengthPrefixed(&sctList) || sctList.Empty() { | 
|  | return false | 
|  | } | 
|  | for !sctList.Empty() { | 
|  | var sct []byte | 
|  | if !readUint16LengthPrefixed(&sctList, &sct) || | 
|  | len(sct) == 0 { | 
|  | return false | 
|  | } | 
|  | m.scts = append(m.scts, sct) | 
|  | } | 
|  | case extensionSupportedVersions: | 
|  | if !extData.ReadUint16(&m.supportedVersion) { | 
|  | return false | 
|  | } | 
|  | case extensionCookie: | 
|  | if !readUint16LengthPrefixed(&extData, &m.cookie) || | 
|  | len(m.cookie) == 0 { | 
|  | return false | 
|  | } | 
|  | case extensionKeyShare: | 
|  | // This extension has different formats in SH and HRR, accept either | 
|  | // and let the handshake logic decide. See RFC 8446, Section 4.2.8. | 
|  | if len(extData) == 2 { | 
|  | if !extData.ReadUint16((*uint16)(&m.selectedGroup)) { | 
|  | return false | 
|  | } | 
|  | } else { | 
|  | if !extData.ReadUint16((*uint16)(&m.serverShare.group)) || | 
|  | !readUint16LengthPrefixed(&extData, &m.serverShare.data) { | 
|  | return false | 
|  | } | 
|  | } | 
|  | case extensionPreSharedKey: | 
|  | m.selectedIdentityPresent = true | 
|  | if !extData.ReadUint16(&m.selectedIdentity) { | 
|  | return false | 
|  | } | 
|  | case extensionSupportedPoints: | 
|  | // RFC 4492, Section 5.1.2 | 
|  | if !readUint8LengthPrefixed(&extData, &m.supportedPoints) || | 
|  | len(m.supportedPoints) == 0 { | 
|  | return false | 
|  | } | 
|  | default: | 
|  | // Ignore unknown extensions. | 
|  | continue | 
|  | } | 
|  |  | 
|  | if !extData.Empty() { | 
|  | return false | 
|  | } | 
|  | } | 
|  |  | 
|  | return true | 
|  | } | 
|  |  | 
|  | type encryptedExtensionsMsg struct { | 
|  | raw          []byte | 
|  | alpnProtocol string | 
|  | } | 
|  |  | 
|  | func (m *encryptedExtensionsMsg) marshal() []byte { | 
|  | if m.raw != nil { | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | var b cryptobyte.Builder | 
|  | b.AddUint8(typeEncryptedExtensions) | 
|  | b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | if len(m.alpnProtocol) > 0 { | 
|  | b.AddUint16(extensionALPN) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes([]byte(m.alpnProtocol)) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  | } | 
|  | }) | 
|  | }) | 
|  |  | 
|  | m.raw = b.BytesOrPanic() | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool { | 
|  | *m = encryptedExtensionsMsg{raw: data} | 
|  | s := cryptobyte.String(data) | 
|  |  | 
|  | var extensions cryptobyte.String | 
|  | if !s.Skip(4) || // message type and uint24 length field | 
|  | !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() { | 
|  | return false | 
|  | } | 
|  |  | 
|  | for !extensions.Empty() { | 
|  | var extension uint16 | 
|  | var extData cryptobyte.String | 
|  | if !extensions.ReadUint16(&extension) || | 
|  | !extensions.ReadUint16LengthPrefixed(&extData) { | 
|  | return false | 
|  | } | 
|  |  | 
|  | switch extension { | 
|  | case extensionALPN: | 
|  | var protoList cryptobyte.String | 
|  | if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() { | 
|  | return false | 
|  | } | 
|  | var proto cryptobyte.String | 
|  | if !protoList.ReadUint8LengthPrefixed(&proto) || | 
|  | proto.Empty() || !protoList.Empty() { | 
|  | return false | 
|  | } | 
|  | m.alpnProtocol = string(proto) | 
|  | default: | 
|  | // Ignore unknown extensions. | 
|  | continue | 
|  | } | 
|  |  | 
|  | if !extData.Empty() { | 
|  | return false | 
|  | } | 
|  | } | 
|  |  | 
|  | return true | 
|  | } | 
|  |  | 
|  | type endOfEarlyDataMsg struct{} | 
|  |  | 
|  | func (m *endOfEarlyDataMsg) marshal() []byte { | 
|  | x := make([]byte, 4) | 
|  | x[0] = typeEndOfEarlyData | 
|  | return x | 
|  | } | 
|  |  | 
|  | func (m *endOfEarlyDataMsg) unmarshal(data []byte) bool { | 
|  | return len(data) == 4 | 
|  | } | 
|  |  | 
|  | type keyUpdateMsg struct { | 
|  | raw             []byte | 
|  | updateRequested bool | 
|  | } | 
|  |  | 
|  | func (m *keyUpdateMsg) marshal() []byte { | 
|  | if m.raw != nil { | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | var b cryptobyte.Builder | 
|  | b.AddUint8(typeKeyUpdate) | 
|  | b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | if m.updateRequested { | 
|  | b.AddUint8(1) | 
|  | } else { | 
|  | b.AddUint8(0) | 
|  | } | 
|  | }) | 
|  |  | 
|  | m.raw = b.BytesOrPanic() | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | func (m *keyUpdateMsg) unmarshal(data []byte) bool { | 
|  | m.raw = data | 
|  | s := cryptobyte.String(data) | 
|  |  | 
|  | var updateRequested uint8 | 
|  | if !s.Skip(4) || // message type and uint24 length field | 
|  | !s.ReadUint8(&updateRequested) || !s.Empty() { | 
|  | return false | 
|  | } | 
|  | switch updateRequested { | 
|  | case 0: | 
|  | m.updateRequested = false | 
|  | case 1: | 
|  | m.updateRequested = true | 
|  | default: | 
|  | return false | 
|  | } | 
|  | return true | 
|  | } | 
|  |  | 
|  | type newSessionTicketMsgTLS13 struct { | 
|  | raw          []byte | 
|  | lifetime     uint32 | 
|  | ageAdd       uint32 | 
|  | nonce        []byte | 
|  | label        []byte | 
|  | maxEarlyData uint32 | 
|  | } | 
|  |  | 
|  | func (m *newSessionTicketMsgTLS13) marshal() []byte { | 
|  | if m.raw != nil { | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | var b cryptobyte.Builder | 
|  | b.AddUint8(typeNewSessionTicket) | 
|  | b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint32(m.lifetime) | 
|  | b.AddUint32(m.ageAdd) | 
|  | b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(m.nonce) | 
|  | }) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(m.label) | 
|  | }) | 
|  |  | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | if m.maxEarlyData > 0 { | 
|  | b.AddUint16(extensionEarlyData) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint32(m.maxEarlyData) | 
|  | }) | 
|  | } | 
|  | }) | 
|  | }) | 
|  |  | 
|  | m.raw = b.BytesOrPanic() | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | func (m *newSessionTicketMsgTLS13) unmarshal(data []byte) bool { | 
|  | *m = newSessionTicketMsgTLS13{raw: data} | 
|  | s := cryptobyte.String(data) | 
|  |  | 
|  | var extensions cryptobyte.String | 
|  | if !s.Skip(4) || // message type and uint24 length field | 
|  | !s.ReadUint32(&m.lifetime) || | 
|  | !s.ReadUint32(&m.ageAdd) || | 
|  | !readUint8LengthPrefixed(&s, &m.nonce) || | 
|  | !readUint16LengthPrefixed(&s, &m.label) || | 
|  | !s.ReadUint16LengthPrefixed(&extensions) || | 
|  | !s.Empty() { | 
|  | return false | 
|  | } | 
|  |  | 
|  | for !extensions.Empty() { | 
|  | var extension uint16 | 
|  | var extData cryptobyte.String | 
|  | if !extensions.ReadUint16(&extension) || | 
|  | !extensions.ReadUint16LengthPrefixed(&extData) { | 
|  | return false | 
|  | } | 
|  |  | 
|  | switch extension { | 
|  | case extensionEarlyData: | 
|  | if !extData.ReadUint32(&m.maxEarlyData) { | 
|  | return false | 
|  | } | 
|  | default: | 
|  | // Ignore unknown extensions. | 
|  | continue | 
|  | } | 
|  |  | 
|  | if !extData.Empty() { | 
|  | return false | 
|  | } | 
|  | } | 
|  |  | 
|  | return true | 
|  | } | 
|  |  | 
|  | type certificateRequestMsgTLS13 struct { | 
|  | raw                              []byte | 
|  | ocspStapling                     bool | 
|  | scts                             bool | 
|  | supportedSignatureAlgorithms     []SignatureScheme | 
|  | supportedSignatureAlgorithmsCert []SignatureScheme | 
|  | certificateAuthorities           [][]byte | 
|  | } | 
|  |  | 
|  | func (m *certificateRequestMsgTLS13) marshal() []byte { | 
|  | if m.raw != nil { | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | var b cryptobyte.Builder | 
|  | b.AddUint8(typeCertificateRequest) | 
|  | b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | // certificate_request_context (SHALL be zero length unless used for | 
|  | // post-handshake authentication) | 
|  | b.AddUint8(0) | 
|  |  | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | if m.ocspStapling { | 
|  | b.AddUint16(extensionStatusRequest) | 
|  | b.AddUint16(0) // empty extension_data | 
|  | } | 
|  | if m.scts { | 
|  | // RFC 8446, Section 4.4.2.1 makes no mention of | 
|  | // signed_certificate_timestamp in CertificateRequest, but | 
|  | // "Extensions in the Certificate message from the client MUST | 
|  | // correspond to extensions in the CertificateRequest message | 
|  | // from the server." and it appears in the table in Section 4.2. | 
|  | b.AddUint16(extensionSCT) | 
|  | b.AddUint16(0) // empty extension_data | 
|  | } | 
|  | if len(m.supportedSignatureAlgorithms) > 0 { | 
|  | b.AddUint16(extensionSignatureAlgorithms) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | for _, sigAlgo := range m.supportedSignatureAlgorithms { | 
|  | b.AddUint16(uint16(sigAlgo)) | 
|  | } | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if len(m.supportedSignatureAlgorithmsCert) > 0 { | 
|  | b.AddUint16(extensionSignatureAlgorithmsCert) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | for _, sigAlgo := range m.supportedSignatureAlgorithmsCert { | 
|  | b.AddUint16(uint16(sigAlgo)) | 
|  | } | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if len(m.certificateAuthorities) > 0 { | 
|  | b.AddUint16(extensionCertificateAuthorities) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | for _, ca := range m.certificateAuthorities { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(ca) | 
|  | }) | 
|  | } | 
|  | }) | 
|  | }) | 
|  | } | 
|  | }) | 
|  | }) | 
|  |  | 
|  | m.raw = b.BytesOrPanic() | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | func (m *certificateRequestMsgTLS13) unmarshal(data []byte) bool { | 
|  | *m = certificateRequestMsgTLS13{raw: data} | 
|  | s := cryptobyte.String(data) | 
|  |  | 
|  | var context, extensions cryptobyte.String | 
|  | if !s.Skip(4) || // message type and uint24 length field | 
|  | !s.ReadUint8LengthPrefixed(&context) || !context.Empty() || | 
|  | !s.ReadUint16LengthPrefixed(&extensions) || | 
|  | !s.Empty() { | 
|  | return false | 
|  | } | 
|  |  | 
|  | for !extensions.Empty() { | 
|  | var extension uint16 | 
|  | var extData cryptobyte.String | 
|  | if !extensions.ReadUint16(&extension) || | 
|  | !extensions.ReadUint16LengthPrefixed(&extData) { | 
|  | return false | 
|  | } | 
|  |  | 
|  | switch extension { | 
|  | case extensionStatusRequest: | 
|  | m.ocspStapling = true | 
|  | case extensionSCT: | 
|  | m.scts = true | 
|  | case extensionSignatureAlgorithms: | 
|  | var sigAndAlgs cryptobyte.String | 
|  | if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() { | 
|  | return false | 
|  | } | 
|  | for !sigAndAlgs.Empty() { | 
|  | var sigAndAlg uint16 | 
|  | if !sigAndAlgs.ReadUint16(&sigAndAlg) { | 
|  | return false | 
|  | } | 
|  | m.supportedSignatureAlgorithms = append( | 
|  | m.supportedSignatureAlgorithms, SignatureScheme(sigAndAlg)) | 
|  | } | 
|  | case extensionSignatureAlgorithmsCert: | 
|  | var sigAndAlgs cryptobyte.String | 
|  | if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() { | 
|  | return false | 
|  | } | 
|  | for !sigAndAlgs.Empty() { | 
|  | var sigAndAlg uint16 | 
|  | if !sigAndAlgs.ReadUint16(&sigAndAlg) { | 
|  | return false | 
|  | } | 
|  | m.supportedSignatureAlgorithmsCert = append( | 
|  | m.supportedSignatureAlgorithmsCert, SignatureScheme(sigAndAlg)) | 
|  | } | 
|  | case extensionCertificateAuthorities: | 
|  | var auths cryptobyte.String | 
|  | if !extData.ReadUint16LengthPrefixed(&auths) || auths.Empty() { | 
|  | return false | 
|  | } | 
|  | for !auths.Empty() { | 
|  | var ca []byte | 
|  | if !readUint16LengthPrefixed(&auths, &ca) || len(ca) == 0 { | 
|  | return false | 
|  | } | 
|  | m.certificateAuthorities = append(m.certificateAuthorities, ca) | 
|  | } | 
|  | default: | 
|  | // Ignore unknown extensions. | 
|  | continue | 
|  | } | 
|  |  | 
|  | if !extData.Empty() { | 
|  | return false | 
|  | } | 
|  | } | 
|  |  | 
|  | return true | 
|  | } | 
|  |  | 
|  | type certificateMsg struct { | 
|  | raw          []byte | 
|  | certificates [][]byte | 
|  | } | 
|  |  | 
|  | func (m *certificateMsg) marshal() (x []byte) { | 
|  | if m.raw != nil { | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | var i int | 
|  | for _, slice := range m.certificates { | 
|  | i += len(slice) | 
|  | } | 
|  |  | 
|  | length := 3 + 3*len(m.certificates) + i | 
|  | x = make([]byte, 4+length) | 
|  | x[0] = typeCertificate | 
|  | x[1] = uint8(length >> 16) | 
|  | x[2] = uint8(length >> 8) | 
|  | x[3] = uint8(length) | 
|  |  | 
|  | certificateOctets := length - 3 | 
|  | x[4] = uint8(certificateOctets >> 16) | 
|  | x[5] = uint8(certificateOctets >> 8) | 
|  | x[6] = uint8(certificateOctets) | 
|  |  | 
|  | y := x[7:] | 
|  | for _, slice := range m.certificates { | 
|  | y[0] = uint8(len(slice) >> 16) | 
|  | y[1] = uint8(len(slice) >> 8) | 
|  | y[2] = uint8(len(slice)) | 
|  | copy(y[3:], slice) | 
|  | y = y[3+len(slice):] | 
|  | } | 
|  |  | 
|  | m.raw = x | 
|  | return | 
|  | } | 
|  |  | 
|  | func (m *certificateMsg) unmarshal(data []byte) bool { | 
|  | if len(data) < 7 { | 
|  | return false | 
|  | } | 
|  |  | 
|  | m.raw = data | 
|  | certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6]) | 
|  | if uint32(len(data)) != certsLen+7 { | 
|  | return false | 
|  | } | 
|  |  | 
|  | numCerts := 0 | 
|  | d := data[7:] | 
|  | for certsLen > 0 { | 
|  | if len(d) < 4 { | 
|  | return false | 
|  | } | 
|  | certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2]) | 
|  | if uint32(len(d)) < 3+certLen { | 
|  | return false | 
|  | } | 
|  | d = d[3+certLen:] | 
|  | certsLen -= 3 + certLen | 
|  | numCerts++ | 
|  | } | 
|  |  | 
|  | m.certificates = make([][]byte, numCerts) | 
|  | d = data[7:] | 
|  | for i := 0; i < numCerts; i++ { | 
|  | certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2]) | 
|  | m.certificates[i] = d[3 : 3+certLen] | 
|  | d = d[3+certLen:] | 
|  | } | 
|  |  | 
|  | return true | 
|  | } | 
|  |  | 
|  | type certificateMsgTLS13 struct { | 
|  | raw          []byte | 
|  | certificate  Certificate | 
|  | ocspStapling bool | 
|  | scts         bool | 
|  | } | 
|  |  | 
|  | func (m *certificateMsgTLS13) marshal() []byte { | 
|  | if m.raw != nil { | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | var b cryptobyte.Builder | 
|  | b.AddUint8(typeCertificate) | 
|  | b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint8(0) // certificate_request_context | 
|  |  | 
|  | certificate := m.certificate | 
|  | if !m.ocspStapling { | 
|  | certificate.OCSPStaple = nil | 
|  | } | 
|  | if !m.scts { | 
|  | certificate.SignedCertificateTimestamps = nil | 
|  | } | 
|  | marshalCertificate(b, certificate) | 
|  | }) | 
|  |  | 
|  | m.raw = b.BytesOrPanic() | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | func marshalCertificate(b *cryptobyte.Builder, certificate Certificate) { | 
|  | b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | for i, cert := range certificate.Certificate { | 
|  | b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(cert) | 
|  | }) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | if i > 0 { | 
|  | // This library only supports OCSP and SCT for leaf certificates. | 
|  | return | 
|  | } | 
|  | if certificate.OCSPStaple != nil { | 
|  | b.AddUint16(extensionStatusRequest) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint8(statusTypeOCSP) | 
|  | b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(certificate.OCSPStaple) | 
|  | }) | 
|  | }) | 
|  | } | 
|  | if certificate.SignedCertificateTimestamps != nil { | 
|  | b.AddUint16(extensionSCT) | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | for _, sct := range certificate.SignedCertificateTimestamps { | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(sct) | 
|  | }) | 
|  | } | 
|  | }) | 
|  | }) | 
|  | } | 
|  | }) | 
|  | } | 
|  | }) | 
|  | } | 
|  |  | 
|  | func (m *certificateMsgTLS13) unmarshal(data []byte) bool { | 
|  | *m = certificateMsgTLS13{raw: data} | 
|  | s := cryptobyte.String(data) | 
|  |  | 
|  | var context cryptobyte.String | 
|  | if !s.Skip(4) || // message type and uint24 length field | 
|  | !s.ReadUint8LengthPrefixed(&context) || !context.Empty() || | 
|  | !unmarshalCertificate(&s, &m.certificate) || | 
|  | !s.Empty() { | 
|  | return false | 
|  | } | 
|  |  | 
|  | m.scts = m.certificate.SignedCertificateTimestamps != nil | 
|  | m.ocspStapling = m.certificate.OCSPStaple != nil | 
|  |  | 
|  | return true | 
|  | } | 
|  |  | 
|  | func unmarshalCertificate(s *cryptobyte.String, certificate *Certificate) bool { | 
|  | var certList cryptobyte.String | 
|  | if !s.ReadUint24LengthPrefixed(&certList) { | 
|  | return false | 
|  | } | 
|  | for !certList.Empty() { | 
|  | var cert []byte | 
|  | var extensions cryptobyte.String | 
|  | if !readUint24LengthPrefixed(&certList, &cert) || | 
|  | !certList.ReadUint16LengthPrefixed(&extensions) { | 
|  | return false | 
|  | } | 
|  | certificate.Certificate = append(certificate.Certificate, cert) | 
|  | for !extensions.Empty() { | 
|  | var extension uint16 | 
|  | var extData cryptobyte.String | 
|  | if !extensions.ReadUint16(&extension) || | 
|  | !extensions.ReadUint16LengthPrefixed(&extData) { | 
|  | return false | 
|  | } | 
|  | if len(certificate.Certificate) > 1 { | 
|  | // This library only supports OCSP and SCT for leaf certificates. | 
|  | continue | 
|  | } | 
|  |  | 
|  | switch extension { | 
|  | case extensionStatusRequest: | 
|  | var statusType uint8 | 
|  | if !extData.ReadUint8(&statusType) || statusType != statusTypeOCSP || | 
|  | !readUint24LengthPrefixed(&extData, &certificate.OCSPStaple) || | 
|  | len(certificate.OCSPStaple) == 0 { | 
|  | return false | 
|  | } | 
|  | case extensionSCT: | 
|  | var sctList cryptobyte.String | 
|  | if !extData.ReadUint16LengthPrefixed(&sctList) || sctList.Empty() { | 
|  | return false | 
|  | } | 
|  | for !sctList.Empty() { | 
|  | var sct []byte | 
|  | if !readUint16LengthPrefixed(&sctList, &sct) || | 
|  | len(sct) == 0 { | 
|  | return false | 
|  | } | 
|  | certificate.SignedCertificateTimestamps = append( | 
|  | certificate.SignedCertificateTimestamps, sct) | 
|  | } | 
|  | default: | 
|  | // Ignore unknown extensions. | 
|  | continue | 
|  | } | 
|  |  | 
|  | if !extData.Empty() { | 
|  | return false | 
|  | } | 
|  | } | 
|  | } | 
|  | return true | 
|  | } | 
|  |  | 
|  | type serverKeyExchangeMsg struct { | 
|  | raw []byte | 
|  | key []byte | 
|  | } | 
|  |  | 
|  | func (m *serverKeyExchangeMsg) marshal() []byte { | 
|  | if m.raw != nil { | 
|  | return m.raw | 
|  | } | 
|  | length := len(m.key) | 
|  | x := make([]byte, length+4) | 
|  | x[0] = typeServerKeyExchange | 
|  | x[1] = uint8(length >> 16) | 
|  | x[2] = uint8(length >> 8) | 
|  | x[3] = uint8(length) | 
|  | copy(x[4:], m.key) | 
|  |  | 
|  | m.raw = x | 
|  | return x | 
|  | } | 
|  |  | 
|  | func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool { | 
|  | m.raw = data | 
|  | if len(data) < 4 { | 
|  | return false | 
|  | } | 
|  | m.key = data[4:] | 
|  | return true | 
|  | } | 
|  |  | 
|  | type certificateStatusMsg struct { | 
|  | raw      []byte | 
|  | response []byte | 
|  | } | 
|  |  | 
|  | func (m *certificateStatusMsg) marshal() []byte { | 
|  | if m.raw != nil { | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | var b cryptobyte.Builder | 
|  | b.AddUint8(typeCertificateStatus) | 
|  | b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddUint8(statusTypeOCSP) | 
|  | b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(m.response) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | m.raw = b.BytesOrPanic() | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | func (m *certificateStatusMsg) unmarshal(data []byte) bool { | 
|  | m.raw = data | 
|  | s := cryptobyte.String(data) | 
|  |  | 
|  | var statusType uint8 | 
|  | if !s.Skip(4) || // message type and uint24 length field | 
|  | !s.ReadUint8(&statusType) || statusType != statusTypeOCSP || | 
|  | !readUint24LengthPrefixed(&s, &m.response) || | 
|  | len(m.response) == 0 || !s.Empty() { | 
|  | 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 | 
|  | } | 
|  | length := len(m.ciphertext) | 
|  | x := make([]byte, length+4) | 
|  | x[0] = typeClientKeyExchange | 
|  | x[1] = uint8(length >> 16) | 
|  | x[2] = uint8(length >> 8) | 
|  | x[3] = uint8(length) | 
|  | copy(x[4:], m.ciphertext) | 
|  |  | 
|  | m.raw = x | 
|  | return x | 
|  | } | 
|  |  | 
|  | func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool { | 
|  | m.raw = data | 
|  | if len(data) < 4 { | 
|  | return false | 
|  | } | 
|  | l := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) | 
|  | if l != len(data)-4 { | 
|  | return false | 
|  | } | 
|  | m.ciphertext = data[4:] | 
|  | return true | 
|  | } | 
|  |  | 
|  | type finishedMsg struct { | 
|  | raw        []byte | 
|  | verifyData []byte | 
|  | } | 
|  |  | 
|  | func (m *finishedMsg) marshal() []byte { | 
|  | if m.raw != nil { | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | var b cryptobyte.Builder | 
|  | b.AddUint8(typeFinished) | 
|  | b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(m.verifyData) | 
|  | }) | 
|  |  | 
|  | m.raw = b.BytesOrPanic() | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | func (m *finishedMsg) unmarshal(data []byte) bool { | 
|  | m.raw = data | 
|  | s := cryptobyte.String(data) | 
|  | return s.Skip(1) && | 
|  | readUint24LengthPrefixed(&s, &m.verifyData) && | 
|  | s.Empty() | 
|  | } | 
|  |  | 
|  | type certificateRequestMsg struct { | 
|  | raw []byte | 
|  | // hasSignatureAlgorithm indicates whether this message includes a list of | 
|  | // supported signature algorithms. This change was introduced with TLS 1.2. | 
|  | hasSignatureAlgorithm bool | 
|  |  | 
|  | certificateTypes             []byte | 
|  | supportedSignatureAlgorithms []SignatureScheme | 
|  | certificateAuthorities       [][]byte | 
|  | } | 
|  |  | 
|  | func (m *certificateRequestMsg) marshal() (x []byte) { | 
|  | if m.raw != nil { | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | // See RFC 4346, 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.hasSignatureAlgorithm { | 
|  | 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.hasSignatureAlgorithm { | 
|  | 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) bool { | 
|  | m.raw = data | 
|  |  | 
|  | if len(data) < 5 { | 
|  | return false | 
|  | } | 
|  |  | 
|  | length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) | 
|  | if uint32(len(data))-4 != length { | 
|  | return false | 
|  | } | 
|  |  | 
|  | numCertTypes := int(data[4]) | 
|  | data = data[5:] | 
|  | if numCertTypes == 0 || len(data) <= numCertTypes { | 
|  | return false | 
|  | } | 
|  |  | 
|  | m.certificateTypes = make([]byte, numCertTypes) | 
|  | if copy(m.certificateTypes, data) != numCertTypes { | 
|  | return false | 
|  | } | 
|  |  | 
|  | data = data[numCertTypes:] | 
|  |  | 
|  | if m.hasSignatureAlgorithm { | 
|  | if len(data) < 2 { | 
|  | return false | 
|  | } | 
|  | sigAndHashLen := uint16(data[0])<<8 | uint16(data[1]) | 
|  | data = data[2:] | 
|  | if sigAndHashLen&1 != 0 { | 
|  | return false | 
|  | } | 
|  | if len(data) < int(sigAndHashLen) { | 
|  | return false | 
|  | } | 
|  | 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 false | 
|  | } | 
|  | casLength := uint16(data[0])<<8 | uint16(data[1]) | 
|  | data = data[2:] | 
|  | if len(data) < int(casLength) { | 
|  | return false | 
|  | } | 
|  | cas := make([]byte, casLength) | 
|  | copy(cas, data) | 
|  | data = data[casLength:] | 
|  |  | 
|  | m.certificateAuthorities = nil | 
|  | for len(cas) > 0 { | 
|  | if len(cas) < 2 { | 
|  | return false | 
|  | } | 
|  | caLen := uint16(cas[0])<<8 | uint16(cas[1]) | 
|  | cas = cas[2:] | 
|  |  | 
|  | if len(cas) < int(caLen) { | 
|  | return false | 
|  | } | 
|  |  | 
|  | m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen]) | 
|  | cas = cas[caLen:] | 
|  | } | 
|  |  | 
|  | return len(data) == 0 | 
|  | } | 
|  |  | 
|  | type certificateVerifyMsg struct { | 
|  | raw                   []byte | 
|  | hasSignatureAlgorithm bool // format change introduced in TLS 1.2 | 
|  | signatureAlgorithm    SignatureScheme | 
|  | signature             []byte | 
|  | } | 
|  |  | 
|  | func (m *certificateVerifyMsg) marshal() (x []byte) { | 
|  | if m.raw != nil { | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | var b cryptobyte.Builder | 
|  | b.AddUint8(typeCertificateVerify) | 
|  | b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | if m.hasSignatureAlgorithm { | 
|  | b.AddUint16(uint16(m.signatureAlgorithm)) | 
|  | } | 
|  | b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | 
|  | b.AddBytes(m.signature) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | m.raw = b.BytesOrPanic() | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | func (m *certificateVerifyMsg) unmarshal(data []byte) bool { | 
|  | m.raw = data | 
|  | s := cryptobyte.String(data) | 
|  |  | 
|  | if !s.Skip(4) { // message type and uint24 length field | 
|  | return false | 
|  | } | 
|  | if m.hasSignatureAlgorithm { | 
|  | if !s.ReadUint16((*uint16)(&m.signatureAlgorithm)) { | 
|  | return false | 
|  | } | 
|  | } | 
|  | return readUint16LengthPrefixed(&s, &m.signature) && s.Empty() | 
|  | } | 
|  |  | 
|  | type newSessionTicketMsg struct { | 
|  | raw    []byte | 
|  | ticket []byte | 
|  | } | 
|  |  | 
|  | func (m *newSessionTicketMsg) marshal() (x []byte) { | 
|  | if m.raw != nil { | 
|  | return m.raw | 
|  | } | 
|  |  | 
|  | // See RFC 5077, Section 3.3. | 
|  | ticketLen := len(m.ticket) | 
|  | length := 2 + 4 + ticketLen | 
|  | x = make([]byte, 4+length) | 
|  | x[0] = typeNewSessionTicket | 
|  | x[1] = uint8(length >> 16) | 
|  | x[2] = uint8(length >> 8) | 
|  | x[3] = uint8(length) | 
|  | x[8] = uint8(ticketLen >> 8) | 
|  | x[9] = uint8(ticketLen) | 
|  | copy(x[10:], m.ticket) | 
|  |  | 
|  | m.raw = x | 
|  |  | 
|  | return | 
|  | } | 
|  |  | 
|  | func (m *newSessionTicketMsg) unmarshal(data []byte) bool { | 
|  | m.raw = data | 
|  |  | 
|  | if len(data) < 10 { | 
|  | return false | 
|  | } | 
|  |  | 
|  | length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) | 
|  | if uint32(len(data))-4 != length { | 
|  | return false | 
|  | } | 
|  |  | 
|  | ticketLen := int(data[8])<<8 + int(data[9]) | 
|  | if len(data)-10 != ticketLen { | 
|  | return false | 
|  | } | 
|  |  | 
|  | m.ticket = data[10:] | 
|  |  | 
|  | return true | 
|  | } | 
|  |  | 
|  | type helloRequestMsg struct { | 
|  | } | 
|  |  | 
|  | func (*helloRequestMsg) marshal() []byte { | 
|  | return []byte{typeHelloRequest, 0, 0, 0} | 
|  | } | 
|  |  | 
|  | func (*helloRequestMsg) unmarshal(data []byte) bool { | 
|  | return len(data) == 4 | 
|  | } |