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 }