github.com/pion/dtls/v2@v2.2.12/pkg/protocol/handshake/message_client_hello.go (about) 1 // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly> 2 // SPDX-License-Identifier: MIT 3 4 package handshake 5 6 import ( 7 "encoding/binary" 8 9 "github.com/pion/dtls/v2/pkg/protocol" 10 "github.com/pion/dtls/v2/pkg/protocol/extension" 11 ) 12 13 /* 14 MessageClientHello is for when a client first connects to a server it is 15 required to send the client hello as its first message. The client can also send a 16 client hello in response to a hello request or on its own 17 initiative in order to renegotiate the security parameters in an 18 existing connection. 19 */ 20 type MessageClientHello struct { 21 Version protocol.Version 22 Random Random 23 Cookie []byte 24 25 SessionID []byte 26 27 CipherSuiteIDs []uint16 28 CompressionMethods []*protocol.CompressionMethod 29 Extensions []extension.Extension 30 } 31 32 const handshakeMessageClientHelloVariableWidthStart = 34 33 34 // Type returns the Handshake Type 35 func (m MessageClientHello) Type() Type { 36 return TypeClientHello 37 } 38 39 // Marshal encodes the Handshake 40 func (m *MessageClientHello) Marshal() ([]byte, error) { 41 if len(m.Cookie) > 255 { 42 return nil, errCookieTooLong 43 } 44 45 out := make([]byte, handshakeMessageClientHelloVariableWidthStart) 46 out[0] = m.Version.Major 47 out[1] = m.Version.Minor 48 49 rand := m.Random.MarshalFixed() 50 copy(out[2:], rand[:]) 51 52 out = append(out, byte(len(m.SessionID))) 53 out = append(out, m.SessionID...) 54 55 out = append(out, byte(len(m.Cookie))) 56 out = append(out, m.Cookie...) 57 out = append(out, encodeCipherSuiteIDs(m.CipherSuiteIDs)...) 58 out = append(out, protocol.EncodeCompressionMethods(m.CompressionMethods)...) 59 60 extensions, err := extension.Marshal(m.Extensions) 61 if err != nil { 62 return nil, err 63 } 64 65 return append(out, extensions...), nil 66 } 67 68 // Unmarshal populates the message from encoded data 69 func (m *MessageClientHello) Unmarshal(data []byte) error { 70 if len(data) < 2+RandomLength { 71 return errBufferTooSmall 72 } 73 74 m.Version.Major = data[0] 75 m.Version.Minor = data[1] 76 77 var random [RandomLength]byte 78 copy(random[:], data[2:]) 79 m.Random.UnmarshalFixed(random) 80 81 // rest of packet has variable width sections 82 currOffset := handshakeMessageClientHelloVariableWidthStart 83 84 currOffset++ 85 if len(data) <= currOffset { 86 return errBufferTooSmall 87 } 88 n := int(data[currOffset-1]) 89 if len(data) <= currOffset+n { 90 return errBufferTooSmall 91 } 92 m.SessionID = append([]byte{}, data[currOffset:currOffset+n]...) 93 currOffset += len(m.SessionID) 94 95 currOffset++ 96 if len(data) <= currOffset { 97 return errBufferTooSmall 98 } 99 n = int(data[currOffset-1]) 100 if len(data) <= currOffset+n { 101 return errBufferTooSmall 102 } 103 m.Cookie = append([]byte{}, data[currOffset:currOffset+n]...) 104 currOffset += len(m.Cookie) 105 106 // Cipher Suites 107 if len(data) < currOffset { 108 return errBufferTooSmall 109 } 110 cipherSuiteIDs, err := decodeCipherSuiteIDs(data[currOffset:]) 111 if err != nil { 112 return err 113 } 114 m.CipherSuiteIDs = cipherSuiteIDs 115 if len(data) < currOffset+2 { 116 return errBufferTooSmall 117 } 118 currOffset += int(binary.BigEndian.Uint16(data[currOffset:])) + 2 119 120 // Compression Methods 121 if len(data) < currOffset { 122 return errBufferTooSmall 123 } 124 compressionMethods, err := protocol.DecodeCompressionMethods(data[currOffset:]) 125 if err != nil { 126 return err 127 } 128 m.CompressionMethods = compressionMethods 129 if len(data) < currOffset { 130 return errBufferTooSmall 131 } 132 currOffset += int(data[currOffset]) + 1 133 134 // Extensions 135 extensions, err := extension.Unmarshal(data[currOffset:]) 136 if err != nil { 137 return err 138 } 139 m.Extensions = extensions 140 return nil 141 }