github.com/pion/dtls/v2@v2.2.12/pkg/protocol/handshake/message_server_key_exchange.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/internal/ciphersuite/types"
    10  	"github.com/pion/dtls/v2/pkg/crypto/elliptic"
    11  	"github.com/pion/dtls/v2/pkg/crypto/hash"
    12  	"github.com/pion/dtls/v2/pkg/crypto/signature"
    13  )
    14  
    15  // MessageServerKeyExchange supports ECDH and PSK
    16  type MessageServerKeyExchange struct {
    17  	IdentityHint []byte
    18  
    19  	EllipticCurveType  elliptic.CurveType
    20  	NamedCurve         elliptic.Curve
    21  	PublicKey          []byte
    22  	HashAlgorithm      hash.Algorithm
    23  	SignatureAlgorithm signature.Algorithm
    24  	Signature          []byte
    25  
    26  	// for unmarshaling
    27  	KeyExchangeAlgorithm types.KeyExchangeAlgorithm
    28  }
    29  
    30  // Type returns the Handshake Type
    31  func (m MessageServerKeyExchange) Type() Type {
    32  	return TypeServerKeyExchange
    33  }
    34  
    35  // Marshal encodes the Handshake
    36  func (m *MessageServerKeyExchange) Marshal() ([]byte, error) {
    37  	var out []byte
    38  	if m.IdentityHint != nil {
    39  		out = append([]byte{0x00, 0x00}, m.IdentityHint...)
    40  		binary.BigEndian.PutUint16(out, uint16(len(out)-2))
    41  	}
    42  
    43  	if m.EllipticCurveType == 0 || len(m.PublicKey) == 0 {
    44  		return out, nil
    45  	}
    46  	out = append(out, byte(m.EllipticCurveType), 0x00, 0x00)
    47  	binary.BigEndian.PutUint16(out[len(out)-2:], uint16(m.NamedCurve))
    48  
    49  	out = append(out, byte(len(m.PublicKey)))
    50  	out = append(out, m.PublicKey...)
    51  	switch {
    52  	case m.HashAlgorithm != hash.None && len(m.Signature) == 0:
    53  		return nil, errInvalidHashAlgorithm
    54  	case m.HashAlgorithm == hash.None && len(m.Signature) > 0:
    55  		return nil, errInvalidHashAlgorithm
    56  	case m.SignatureAlgorithm == signature.Anonymous && (m.HashAlgorithm != hash.None || len(m.Signature) > 0):
    57  		return nil, errInvalidSignatureAlgorithm
    58  	case m.SignatureAlgorithm == signature.Anonymous:
    59  		return out, nil
    60  	}
    61  
    62  	out = append(out, []byte{byte(m.HashAlgorithm), byte(m.SignatureAlgorithm), 0x00, 0x00}...)
    63  	binary.BigEndian.PutUint16(out[len(out)-2:], uint16(len(m.Signature)))
    64  	out = append(out, m.Signature...)
    65  
    66  	return out, nil
    67  }
    68  
    69  // Unmarshal populates the message from encoded data
    70  func (m *MessageServerKeyExchange) Unmarshal(data []byte) error {
    71  	switch {
    72  	case len(data) < 2:
    73  		return errBufferTooSmall
    74  	case m.KeyExchangeAlgorithm == types.KeyExchangeAlgorithmNone:
    75  		return errCipherSuiteUnset
    76  	}
    77  
    78  	hintLength := binary.BigEndian.Uint16(data)
    79  	if int(hintLength) <= len(data)-2 && m.KeyExchangeAlgorithm.Has(types.KeyExchangeAlgorithmPsk) {
    80  		m.IdentityHint = append([]byte{}, data[2:2+hintLength]...)
    81  		data = data[2+hintLength:]
    82  	}
    83  	if m.KeyExchangeAlgorithm == types.KeyExchangeAlgorithmPsk {
    84  		if len(data) == 0 {
    85  			return nil
    86  		}
    87  		return errLengthMismatch
    88  	}
    89  
    90  	if !m.KeyExchangeAlgorithm.Has(types.KeyExchangeAlgorithmEcdhe) {
    91  		return errLengthMismatch
    92  	}
    93  
    94  	if _, ok := elliptic.CurveTypes()[elliptic.CurveType(data[0])]; ok {
    95  		m.EllipticCurveType = elliptic.CurveType(data[0])
    96  	} else {
    97  		return errInvalidEllipticCurveType
    98  	}
    99  
   100  	if len(data[1:]) < 2 {
   101  		return errBufferTooSmall
   102  	}
   103  	m.NamedCurve = elliptic.Curve(binary.BigEndian.Uint16(data[1:3]))
   104  	if _, ok := elliptic.Curves()[m.NamedCurve]; !ok {
   105  		return errInvalidNamedCurve
   106  	}
   107  	if len(data) < 4 {
   108  		return errBufferTooSmall
   109  	}
   110  
   111  	publicKeyLength := int(data[3])
   112  	offset := 4 + publicKeyLength
   113  	if len(data) < offset {
   114  		return errBufferTooSmall
   115  	}
   116  	m.PublicKey = append([]byte{}, data[4:offset]...)
   117  
   118  	// Anon connection doesn't contains hashAlgorithm, signatureAlgorithm, signature
   119  	if len(data) == offset {
   120  		return nil
   121  	} else if len(data) <= offset {
   122  		return errBufferTooSmall
   123  	}
   124  
   125  	m.HashAlgorithm = hash.Algorithm(data[offset])
   126  	if _, ok := hash.Algorithms()[m.HashAlgorithm]; !ok {
   127  		return errInvalidHashAlgorithm
   128  	}
   129  	offset++
   130  	if len(data) <= offset {
   131  		return errBufferTooSmall
   132  	}
   133  	m.SignatureAlgorithm = signature.Algorithm(data[offset])
   134  	if _, ok := signature.Algorithms()[m.SignatureAlgorithm]; !ok {
   135  		return errInvalidSignatureAlgorithm
   136  	}
   137  	offset++
   138  	if len(data) < offset+2 {
   139  		return errBufferTooSmall
   140  	}
   141  	signatureLength := int(binary.BigEndian.Uint16(data[offset:]))
   142  	offset += 2
   143  	if len(data) < offset+signatureLength {
   144  		return errBufferTooSmall
   145  	}
   146  	m.Signature = append([]byte{}, data[offset:offset+signatureLength]...)
   147  	return nil
   148  }