github.com/pion/dtls/v2@v2.2.12/pkg/protocol/handshake/message_server_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 // MessageServerHello is sent in response to a ClientHello 14 // message when it was able to find an acceptable set of algorithms. 15 // If it cannot find such a match, it will respond with a handshake 16 // failure alert. 17 // 18 // https://tools.ietf.org/html/rfc5246#section-7.4.1.3 19 type MessageServerHello struct { 20 Version protocol.Version 21 Random Random 22 23 SessionID []byte 24 25 CipherSuiteID *uint16 26 CompressionMethod *protocol.CompressionMethod 27 Extensions []extension.Extension 28 } 29 30 const messageServerHelloVariableWidthStart = 2 + RandomLength 31 32 // Type returns the Handshake Type 33 func (m MessageServerHello) Type() Type { 34 return TypeServerHello 35 } 36 37 // Marshal encodes the Handshake 38 func (m *MessageServerHello) Marshal() ([]byte, error) { 39 if m.CipherSuiteID == nil { 40 return nil, errCipherSuiteUnset 41 } else if m.CompressionMethod == nil { 42 return nil, errCompressionMethodUnset 43 } 44 45 out := make([]byte, messageServerHelloVariableWidthStart) 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{0x00, 0x00}...) 56 binary.BigEndian.PutUint16(out[len(out)-2:], *m.CipherSuiteID) 57 58 out = append(out, byte(m.CompressionMethod.ID)) 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 *MessageServerHello) 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 currOffset := messageServerHelloVariableWidthStart 82 currOffset++ 83 if len(data) <= currOffset { 84 return errBufferTooSmall 85 } 86 87 n := int(data[currOffset-1]) 88 if len(data) <= currOffset+n { 89 return errBufferTooSmall 90 } 91 m.SessionID = append([]byte{}, data[currOffset:currOffset+n]...) 92 currOffset += len(m.SessionID) 93 94 if len(data) < currOffset+2 { 95 return errBufferTooSmall 96 } 97 m.CipherSuiteID = new(uint16) 98 *m.CipherSuiteID = binary.BigEndian.Uint16(data[currOffset:]) 99 currOffset += 2 100 101 if len(data) <= currOffset { 102 return errBufferTooSmall 103 } 104 if compressionMethod, ok := protocol.CompressionMethods()[protocol.CompressionMethodID(data[currOffset])]; ok { 105 m.CompressionMethod = compressionMethod 106 currOffset++ 107 } else { 108 return errInvalidCompressionMethod 109 } 110 111 if len(data) <= currOffset { 112 m.Extensions = []extension.Extension{} 113 return nil 114 } 115 116 extensions, err := extension.Unmarshal(data[currOffset:]) 117 if err != nil { 118 return err 119 } 120 m.Extensions = extensions 121 return nil 122 }