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

     1  // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
     2  // SPDX-License-Identifier: MIT
     3  
     4  // Package extension implements the extension values in the ClientHello/ServerHello
     5  package extension
     6  
     7  import "encoding/binary"
     8  
     9  // TypeValue is the 2 byte value for a TLS Extension as registered in the IANA
    10  //
    11  // https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
    12  type TypeValue uint16
    13  
    14  // TypeValue constants
    15  const (
    16  	ServerNameTypeValue                   TypeValue = 0
    17  	SupportedEllipticCurvesTypeValue      TypeValue = 10
    18  	SupportedPointFormatsTypeValue        TypeValue = 11
    19  	SupportedSignatureAlgorithmsTypeValue TypeValue = 13
    20  	UseSRTPTypeValue                      TypeValue = 14
    21  	ALPNTypeValue                         TypeValue = 16
    22  	UseExtendedMasterSecretTypeValue      TypeValue = 23
    23  	RenegotiationInfoTypeValue            TypeValue = 65281
    24  )
    25  
    26  // Extension represents a single TLS extension
    27  type Extension interface {
    28  	Marshal() ([]byte, error)
    29  	Unmarshal(data []byte) error
    30  	TypeValue() TypeValue
    31  }
    32  
    33  // Unmarshal many extensions at once
    34  func Unmarshal(buf []byte) ([]Extension, error) {
    35  	switch {
    36  	case len(buf) == 0:
    37  		return []Extension{}, nil
    38  	case len(buf) < 2:
    39  		return nil, errBufferTooSmall
    40  	}
    41  
    42  	declaredLen := binary.BigEndian.Uint16(buf)
    43  	if len(buf)-2 != int(declaredLen) {
    44  		return nil, errLengthMismatch
    45  	}
    46  
    47  	extensions := []Extension{}
    48  	unmarshalAndAppend := func(data []byte, e Extension) error {
    49  		err := e.Unmarshal(data)
    50  		if err != nil {
    51  			return err
    52  		}
    53  		extensions = append(extensions, e)
    54  		return nil
    55  	}
    56  
    57  	for offset := 2; offset < len(buf); {
    58  		if len(buf) < (offset + 2) {
    59  			return nil, errBufferTooSmall
    60  		}
    61  		var err error
    62  		switch TypeValue(binary.BigEndian.Uint16(buf[offset:])) {
    63  		case ServerNameTypeValue:
    64  			err = unmarshalAndAppend(buf[offset:], &ServerName{})
    65  		case SupportedEllipticCurvesTypeValue:
    66  			err = unmarshalAndAppend(buf[offset:], &SupportedEllipticCurves{})
    67  		case UseSRTPTypeValue:
    68  			err = unmarshalAndAppend(buf[offset:], &UseSRTP{})
    69  		case ALPNTypeValue:
    70  			err = unmarshalAndAppend(buf[offset:], &ALPN{})
    71  		case UseExtendedMasterSecretTypeValue:
    72  			err = unmarshalAndAppend(buf[offset:], &UseExtendedMasterSecret{})
    73  		case RenegotiationInfoTypeValue:
    74  			err = unmarshalAndAppend(buf[offset:], &RenegotiationInfo{})
    75  		default:
    76  		}
    77  		if err != nil {
    78  			return nil, err
    79  		}
    80  		if len(buf) < (offset + 4) {
    81  			return nil, errBufferTooSmall
    82  		}
    83  		extensionLength := binary.BigEndian.Uint16(buf[offset+2:])
    84  		offset += (4 + int(extensionLength))
    85  	}
    86  	return extensions, nil
    87  }
    88  
    89  // Marshal many extensions at once
    90  func Marshal(e []Extension) ([]byte, error) {
    91  	extensions := []byte{}
    92  	for _, e := range e {
    93  		raw, err := e.Marshal()
    94  		if err != nil {
    95  			return nil, err
    96  		}
    97  		extensions = append(extensions, raw...)
    98  	}
    99  	out := []byte{0x00, 0x00}
   100  	binary.BigEndian.PutUint16(out, uint16(len(extensions)))
   101  	return append(out, extensions...), nil
   102  }