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  }