github.com/pion/dtls/v2@v2.2.12/pkg/protocol/handshake/handshake.go (about)

     1  // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
     2  // SPDX-License-Identifier: MIT
     3  
     4  // Package handshake provides the DTLS wire protocol for handshakes
     5  package handshake
     6  
     7  import (
     8  	"github.com/pion/dtls/v2/internal/ciphersuite/types"
     9  	"github.com/pion/dtls/v2/internal/util"
    10  	"github.com/pion/dtls/v2/pkg/protocol"
    11  )
    12  
    13  // Type is the unique identifier for each handshake message
    14  // https://tools.ietf.org/html/rfc5246#section-7.4
    15  type Type uint8
    16  
    17  // Types of DTLS Handshake messages we know about
    18  const (
    19  	TypeHelloRequest       Type = 0
    20  	TypeClientHello        Type = 1
    21  	TypeServerHello        Type = 2
    22  	TypeHelloVerifyRequest Type = 3
    23  	TypeCertificate        Type = 11
    24  	TypeServerKeyExchange  Type = 12
    25  	TypeCertificateRequest Type = 13
    26  	TypeServerHelloDone    Type = 14
    27  	TypeCertificateVerify  Type = 15
    28  	TypeClientKeyExchange  Type = 16
    29  	TypeFinished           Type = 20
    30  )
    31  
    32  // String returns the string representation of this type
    33  func (t Type) String() string {
    34  	switch t {
    35  	case TypeHelloRequest:
    36  		return "HelloRequest"
    37  	case TypeClientHello:
    38  		return "ClientHello"
    39  	case TypeServerHello:
    40  		return "ServerHello"
    41  	case TypeHelloVerifyRequest:
    42  		return "HelloVerifyRequest"
    43  	case TypeCertificate:
    44  		return "TypeCertificate"
    45  	case TypeServerKeyExchange:
    46  		return "ServerKeyExchange"
    47  	case TypeCertificateRequest:
    48  		return "CertificateRequest"
    49  	case TypeServerHelloDone:
    50  		return "ServerHelloDone"
    51  	case TypeCertificateVerify:
    52  		return "CertificateVerify"
    53  	case TypeClientKeyExchange:
    54  		return "ClientKeyExchange"
    55  	case TypeFinished:
    56  		return "Finished"
    57  	}
    58  	return ""
    59  }
    60  
    61  // Message is the body of a Handshake datagram
    62  type Message interface {
    63  	Marshal() ([]byte, error)
    64  	Unmarshal(data []byte) error
    65  	Type() Type
    66  }
    67  
    68  // Handshake protocol is responsible for selecting a cipher spec and
    69  // generating a master secret, which together comprise the primary
    70  // cryptographic parameters associated with a secure session.  The
    71  // handshake protocol can also optionally authenticate parties who have
    72  // certificates signed by a trusted certificate authority.
    73  // https://tools.ietf.org/html/rfc5246#section-7.3
    74  type Handshake struct {
    75  	Header  Header
    76  	Message Message
    77  
    78  	KeyExchangeAlgorithm types.KeyExchangeAlgorithm
    79  }
    80  
    81  // ContentType returns what kind of content this message is carying
    82  func (h Handshake) ContentType() protocol.ContentType {
    83  	return protocol.ContentTypeHandshake
    84  }
    85  
    86  // Marshal encodes a handshake into a binary message
    87  func (h *Handshake) Marshal() ([]byte, error) {
    88  	if h.Message == nil {
    89  		return nil, errHandshakeMessageUnset
    90  	} else if h.Header.FragmentOffset != 0 {
    91  		return nil, errUnableToMarshalFragmented
    92  	}
    93  
    94  	msg, err := h.Message.Marshal()
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  
    99  	h.Header.Length = uint32(len(msg))
   100  	h.Header.FragmentLength = h.Header.Length
   101  	h.Header.Type = h.Message.Type()
   102  	header, err := h.Header.Marshal()
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  
   107  	return append(header, msg...), nil
   108  }
   109  
   110  // Unmarshal decodes a handshake from a binary message
   111  func (h *Handshake) Unmarshal(data []byte) error {
   112  	if err := h.Header.Unmarshal(data); err != nil {
   113  		return err
   114  	}
   115  
   116  	reportedLen := util.BigEndianUint24(data[1:])
   117  	if uint32(len(data)-HeaderLength) != reportedLen {
   118  		return errLengthMismatch
   119  	} else if reportedLen != h.Header.FragmentLength {
   120  		return errLengthMismatch
   121  	}
   122  
   123  	switch Type(data[0]) {
   124  	case TypeHelloRequest:
   125  		return errNotImplemented
   126  	case TypeClientHello:
   127  		h.Message = &MessageClientHello{}
   128  	case TypeHelloVerifyRequest:
   129  		h.Message = &MessageHelloVerifyRequest{}
   130  	case TypeServerHello:
   131  		h.Message = &MessageServerHello{}
   132  	case TypeCertificate:
   133  		h.Message = &MessageCertificate{}
   134  	case TypeServerKeyExchange:
   135  		h.Message = &MessageServerKeyExchange{KeyExchangeAlgorithm: h.KeyExchangeAlgorithm}
   136  	case TypeCertificateRequest:
   137  		h.Message = &MessageCertificateRequest{}
   138  	case TypeServerHelloDone:
   139  		h.Message = &MessageServerHelloDone{}
   140  	case TypeClientKeyExchange:
   141  		h.Message = &MessageClientKeyExchange{KeyExchangeAlgorithm: h.KeyExchangeAlgorithm}
   142  	case TypeFinished:
   143  		h.Message = &MessageFinished{}
   144  	case TypeCertificateVerify:
   145  		h.Message = &MessageCertificateVerify{}
   146  	default:
   147  		return errNotImplemented
   148  	}
   149  	return h.Message.Unmarshal(data[HeaderLength:])
   150  }