github.com/pion/dtls/v2@v2.2.12/pkg/protocol/handshake/message_certificate_request.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/crypto/clientcertificate"
    10  	"github.com/pion/dtls/v2/pkg/crypto/hash"
    11  	"github.com/pion/dtls/v2/pkg/crypto/signature"
    12  	"github.com/pion/dtls/v2/pkg/crypto/signaturehash"
    13  )
    14  
    15  /*
    16  MessageCertificateRequest is so a non-anonymous server can optionally
    17  request a certificate from the client, if appropriate for the selected cipher
    18  suite.  This message, if sent, will immediately follow the ServerKeyExchange
    19  message (if it is sent; otherwise, this message follows the
    20  server's Certificate message).
    21  
    22  https://tools.ietf.org/html/rfc5246#section-7.4.4
    23  */
    24  type MessageCertificateRequest struct {
    25  	CertificateTypes            []clientcertificate.Type
    26  	SignatureHashAlgorithms     []signaturehash.Algorithm
    27  	CertificateAuthoritiesNames [][]byte
    28  }
    29  
    30  const (
    31  	messageCertificateRequestMinLength = 5
    32  )
    33  
    34  // Type returns the Handshake Type
    35  func (m MessageCertificateRequest) Type() Type {
    36  	return TypeCertificateRequest
    37  }
    38  
    39  // Marshal encodes the Handshake
    40  func (m *MessageCertificateRequest) Marshal() ([]byte, error) {
    41  	out := []byte{byte(len(m.CertificateTypes))}
    42  	for _, v := range m.CertificateTypes {
    43  		out = append(out, byte(v))
    44  	}
    45  
    46  	out = append(out, []byte{0x00, 0x00}...)
    47  	binary.BigEndian.PutUint16(out[len(out)-2:], uint16(len(m.SignatureHashAlgorithms)*2))
    48  	for _, v := range m.SignatureHashAlgorithms {
    49  		out = append(out, byte(v.Hash))
    50  		out = append(out, byte(v.Signature))
    51  	}
    52  
    53  	// Distinguished Names
    54  	casLength := 0
    55  	for _, ca := range m.CertificateAuthoritiesNames {
    56  		casLength += len(ca) + 2
    57  	}
    58  	out = append(out, []byte{0x00, 0x00}...)
    59  	binary.BigEndian.PutUint16(out[len(out)-2:], uint16(casLength))
    60  	if casLength > 0 {
    61  		for _, ca := range m.CertificateAuthoritiesNames {
    62  			out = append(out, []byte{0x00, 0x00}...)
    63  			binary.BigEndian.PutUint16(out[len(out)-2:], uint16(len(ca)))
    64  			out = append(out, ca...)
    65  		}
    66  	}
    67  	return out, nil
    68  }
    69  
    70  // Unmarshal populates the message from encoded data
    71  func (m *MessageCertificateRequest) Unmarshal(data []byte) error {
    72  	if len(data) < messageCertificateRequestMinLength {
    73  		return errBufferTooSmall
    74  	}
    75  
    76  	offset := 0
    77  	certificateTypesLength := int(data[0])
    78  	offset++
    79  
    80  	if (offset + certificateTypesLength) > len(data) {
    81  		return errBufferTooSmall
    82  	}
    83  
    84  	for i := 0; i < certificateTypesLength; i++ {
    85  		certType := clientcertificate.Type(data[offset+i])
    86  		if _, ok := clientcertificate.Types()[certType]; ok {
    87  			m.CertificateTypes = append(m.CertificateTypes, certType)
    88  		}
    89  	}
    90  	offset += certificateTypesLength
    91  	if len(data) < offset+2 {
    92  		return errBufferTooSmall
    93  	}
    94  	signatureHashAlgorithmsLength := int(binary.BigEndian.Uint16(data[offset:]))
    95  	offset += 2
    96  
    97  	if (offset + signatureHashAlgorithmsLength) > len(data) {
    98  		return errBufferTooSmall
    99  	}
   100  
   101  	for i := 0; i < signatureHashAlgorithmsLength; i += 2 {
   102  		if len(data) < (offset + i + 2) {
   103  			return errBufferTooSmall
   104  		}
   105  		h := hash.Algorithm(data[offset+i])
   106  		s := signature.Algorithm(data[offset+i+1])
   107  
   108  		if _, ok := hash.Algorithms()[h]; !ok {
   109  			continue
   110  		} else if _, ok := signature.Algorithms()[s]; !ok {
   111  			continue
   112  		}
   113  		m.SignatureHashAlgorithms = append(m.SignatureHashAlgorithms, signaturehash.Algorithm{Signature: s, Hash: h})
   114  	}
   115  
   116  	offset += signatureHashAlgorithmsLength
   117  	if len(data) < offset+2 {
   118  		return errBufferTooSmall
   119  	}
   120  	casLength := int(binary.BigEndian.Uint16(data[offset:]))
   121  	offset += 2
   122  	if (offset + casLength) > len(data) {
   123  		return errBufferTooSmall
   124  	}
   125  	cas := make([]byte, casLength)
   126  	copy(cas, data[offset:offset+casLength])
   127  	m.CertificateAuthoritiesNames = nil
   128  	for len(cas) > 0 {
   129  		if len(cas) < 2 {
   130  			return errBufferTooSmall
   131  		}
   132  		caLen := binary.BigEndian.Uint16(cas)
   133  		cas = cas[2:]
   134  
   135  		if len(cas) < int(caLen) {
   136  			return errBufferTooSmall
   137  		}
   138  
   139  		m.CertificateAuthoritiesNames = append(m.CertificateAuthoritiesNames, cas[:caLen])
   140  		cas = cas[caLen:]
   141  	}
   142  
   143  	return nil
   144  }