github.com/pion/dtls/v2@v2.2.12/cipher_suite.go (about) 1 // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly> 2 // SPDX-License-Identifier: MIT 3 4 package dtls 5 6 import ( 7 "crypto/ecdsa" 8 "crypto/ed25519" 9 "crypto/rsa" 10 "crypto/tls" 11 "fmt" 12 "hash" 13 14 "github.com/pion/dtls/v2/internal/ciphersuite" 15 "github.com/pion/dtls/v2/pkg/crypto/clientcertificate" 16 "github.com/pion/dtls/v2/pkg/protocol/recordlayer" 17 ) 18 19 // CipherSuiteID is an ID for our supported CipherSuites 20 type CipherSuiteID = ciphersuite.ID 21 22 // Supported Cipher Suites 23 const ( 24 // AES-128-CCM 25 TLS_ECDHE_ECDSA_WITH_AES_128_CCM CipherSuiteID = ciphersuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM //nolint:revive,stylecheck 26 TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 CipherSuiteID = ciphersuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 //nolint:revive,stylecheck 27 28 // AES-128-GCM-SHA256 29 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 CipherSuiteID = ciphersuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 //nolint:revive,stylecheck 30 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 CipherSuiteID = ciphersuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 //nolint:revive,stylecheck 31 32 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 CipherSuiteID = ciphersuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 //nolint:revive,stylecheck 33 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 CipherSuiteID = ciphersuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 //nolint:revive,stylecheck 34 35 // AES-256-CBC-SHA 36 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA CipherSuiteID = ciphersuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA //nolint:revive,stylecheck 37 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA CipherSuiteID = ciphersuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA //nolint:revive,stylecheck 38 39 TLS_PSK_WITH_AES_128_CCM CipherSuiteID = ciphersuite.TLS_PSK_WITH_AES_128_CCM //nolint:revive,stylecheck 40 TLS_PSK_WITH_AES_128_CCM_8 CipherSuiteID = ciphersuite.TLS_PSK_WITH_AES_128_CCM_8 //nolint:revive,stylecheck 41 TLS_PSK_WITH_AES_256_CCM_8 CipherSuiteID = ciphersuite.TLS_PSK_WITH_AES_256_CCM_8 //nolint:revive,stylecheck 42 TLS_PSK_WITH_AES_128_GCM_SHA256 CipherSuiteID = ciphersuite.TLS_PSK_WITH_AES_128_GCM_SHA256 //nolint:revive,stylecheck 43 TLS_PSK_WITH_AES_128_CBC_SHA256 CipherSuiteID = ciphersuite.TLS_PSK_WITH_AES_128_CBC_SHA256 //nolint:revive,stylecheck 44 45 TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 CipherSuiteID = ciphersuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 //nolint:revive,stylecheck 46 ) 47 48 // CipherSuiteAuthenticationType controls what authentication method is using during the handshake for a CipherSuite 49 type CipherSuiteAuthenticationType = ciphersuite.AuthenticationType 50 51 // AuthenticationType Enums 52 const ( 53 CipherSuiteAuthenticationTypeCertificate CipherSuiteAuthenticationType = ciphersuite.AuthenticationTypeCertificate 54 CipherSuiteAuthenticationTypePreSharedKey CipherSuiteAuthenticationType = ciphersuite.AuthenticationTypePreSharedKey 55 CipherSuiteAuthenticationTypeAnonymous CipherSuiteAuthenticationType = ciphersuite.AuthenticationTypeAnonymous 56 ) 57 58 // CipherSuiteKeyExchangeAlgorithm controls what exchange algorithm is using during the handshake for a CipherSuite 59 type CipherSuiteKeyExchangeAlgorithm = ciphersuite.KeyExchangeAlgorithm 60 61 // CipherSuiteKeyExchangeAlgorithm Bitmask 62 const ( 63 CipherSuiteKeyExchangeAlgorithmNone CipherSuiteKeyExchangeAlgorithm = ciphersuite.KeyExchangeAlgorithmNone 64 CipherSuiteKeyExchangeAlgorithmPsk CipherSuiteKeyExchangeAlgorithm = ciphersuite.KeyExchangeAlgorithmPsk 65 CipherSuiteKeyExchangeAlgorithmEcdhe CipherSuiteKeyExchangeAlgorithm = ciphersuite.KeyExchangeAlgorithmEcdhe 66 ) 67 68 var _ = allCipherSuites() // Necessary until this function isn't only used by Go 1.14 69 70 // CipherSuite is an interface that all DTLS CipherSuites must satisfy 71 type CipherSuite interface { 72 // String of CipherSuite, only used for logging 73 String() string 74 75 // ID of CipherSuite. 76 ID() CipherSuiteID 77 78 // What type of Certificate does this CipherSuite use 79 CertificateType() clientcertificate.Type 80 81 // What Hash function is used during verification 82 HashFunc() func() hash.Hash 83 84 // AuthenticationType controls what authentication method is using during the handshake 85 AuthenticationType() CipherSuiteAuthenticationType 86 87 // KeyExchangeAlgorithm controls what exchange algorithm is using during the handshake 88 KeyExchangeAlgorithm() CipherSuiteKeyExchangeAlgorithm 89 90 // ECC (Elliptic Curve Cryptography) determines whether ECC extesions will be send during handshake. 91 // https://datatracker.ietf.org/doc/html/rfc4492#page-10 92 ECC() bool 93 94 // Called when keying material has been generated, should initialize the internal cipher 95 Init(masterSecret, clientRandom, serverRandom []byte, isClient bool) error 96 IsInitialized() bool 97 Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error) 98 Decrypt(in []byte) ([]byte, error) 99 } 100 101 // CipherSuiteName provides the same functionality as tls.CipherSuiteName 102 // that appeared first in Go 1.14. 103 // 104 // Our implementation differs slightly in that it takes in a CiperSuiteID, 105 // like the rest of our library, instead of a uint16 like crypto/tls. 106 func CipherSuiteName(id CipherSuiteID) string { 107 suite := cipherSuiteForID(id, nil) 108 if suite != nil { 109 return suite.String() 110 } 111 return fmt.Sprintf("0x%04X", uint16(id)) 112 } 113 114 // Taken from https://www.iana.org/assignments/tls-parameters/tls-parameters.xml 115 // A cipherSuite is a specific combination of key agreement, cipher and MAC 116 // function. 117 func cipherSuiteForID(id CipherSuiteID, customCiphers func() []CipherSuite) CipherSuite { 118 switch id { //nolint:exhaustive 119 case TLS_ECDHE_ECDSA_WITH_AES_128_CCM: 120 return ciphersuite.NewTLSEcdheEcdsaWithAes128Ccm() 121 case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: 122 return ciphersuite.NewTLSEcdheEcdsaWithAes128Ccm8() 123 case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: 124 return &ciphersuite.TLSEcdheEcdsaWithAes128GcmSha256{} 125 case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: 126 return &ciphersuite.TLSEcdheRsaWithAes128GcmSha256{} 127 case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: 128 return &ciphersuite.TLSEcdheEcdsaWithAes256CbcSha{} 129 case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: 130 return &ciphersuite.TLSEcdheRsaWithAes256CbcSha{} 131 case TLS_PSK_WITH_AES_128_CCM: 132 return ciphersuite.NewTLSPskWithAes128Ccm() 133 case TLS_PSK_WITH_AES_128_CCM_8: 134 return ciphersuite.NewTLSPskWithAes128Ccm8() 135 case TLS_PSK_WITH_AES_256_CCM_8: 136 return ciphersuite.NewTLSPskWithAes256Ccm8() 137 case TLS_PSK_WITH_AES_128_GCM_SHA256: 138 return &ciphersuite.TLSPskWithAes128GcmSha256{} 139 case TLS_PSK_WITH_AES_128_CBC_SHA256: 140 return &ciphersuite.TLSPskWithAes128CbcSha256{} 141 case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: 142 return &ciphersuite.TLSEcdheEcdsaWithAes256GcmSha384{} 143 case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: 144 return &ciphersuite.TLSEcdheRsaWithAes256GcmSha384{} 145 case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256: 146 return ciphersuite.NewTLSEcdhePskWithAes128CbcSha256() 147 } 148 149 if customCiphers != nil { 150 for _, c := range customCiphers() { 151 if c.ID() == id { 152 return c 153 } 154 } 155 } 156 157 return nil 158 } 159 160 // CipherSuites we support in order of preference 161 func defaultCipherSuites() []CipherSuite { 162 return []CipherSuite{ 163 &ciphersuite.TLSEcdheEcdsaWithAes128GcmSha256{}, 164 &ciphersuite.TLSEcdheRsaWithAes128GcmSha256{}, 165 &ciphersuite.TLSEcdheEcdsaWithAes256CbcSha{}, 166 &ciphersuite.TLSEcdheRsaWithAes256CbcSha{}, 167 &ciphersuite.TLSEcdheEcdsaWithAes256GcmSha384{}, 168 &ciphersuite.TLSEcdheRsaWithAes256GcmSha384{}, 169 } 170 } 171 172 func allCipherSuites() []CipherSuite { 173 return []CipherSuite{ 174 ciphersuite.NewTLSEcdheEcdsaWithAes128Ccm(), 175 ciphersuite.NewTLSEcdheEcdsaWithAes128Ccm8(), 176 &ciphersuite.TLSEcdheEcdsaWithAes128GcmSha256{}, 177 &ciphersuite.TLSEcdheRsaWithAes128GcmSha256{}, 178 &ciphersuite.TLSEcdheEcdsaWithAes256CbcSha{}, 179 &ciphersuite.TLSEcdheRsaWithAes256CbcSha{}, 180 ciphersuite.NewTLSPskWithAes128Ccm(), 181 ciphersuite.NewTLSPskWithAes128Ccm8(), 182 ciphersuite.NewTLSPskWithAes256Ccm8(), 183 &ciphersuite.TLSPskWithAes128GcmSha256{}, 184 &ciphersuite.TLSEcdheEcdsaWithAes256GcmSha384{}, 185 &ciphersuite.TLSEcdheRsaWithAes256GcmSha384{}, 186 } 187 } 188 189 func cipherSuiteIDs(cipherSuites []CipherSuite) []uint16 { 190 rtrn := []uint16{} 191 for _, c := range cipherSuites { 192 rtrn = append(rtrn, uint16(c.ID())) 193 } 194 return rtrn 195 } 196 197 func parseCipherSuites(userSelectedSuites []CipherSuiteID, customCipherSuites func() []CipherSuite, includeCertificateSuites, includePSKSuites bool) ([]CipherSuite, error) { 198 cipherSuitesForIDs := func(ids []CipherSuiteID) ([]CipherSuite, error) { 199 cipherSuites := []CipherSuite{} 200 for _, id := range ids { 201 c := cipherSuiteForID(id, nil) 202 if c == nil { 203 return nil, &invalidCipherSuiteError{id} 204 } 205 cipherSuites = append(cipherSuites, c) 206 } 207 return cipherSuites, nil 208 } 209 210 var ( 211 cipherSuites []CipherSuite 212 err error 213 i int 214 ) 215 if userSelectedSuites != nil { 216 cipherSuites, err = cipherSuitesForIDs(userSelectedSuites) 217 if err != nil { 218 return nil, err 219 } 220 } else { 221 cipherSuites = defaultCipherSuites() 222 } 223 224 // Put CustomCipherSuites before ID selected suites 225 if customCipherSuites != nil { 226 cipherSuites = append(customCipherSuites(), cipherSuites...) 227 } 228 229 var foundCertificateSuite, foundPSKSuite, foundAnonymousSuite bool 230 for _, c := range cipherSuites { 231 switch { 232 case includeCertificateSuites && c.AuthenticationType() == CipherSuiteAuthenticationTypeCertificate: 233 foundCertificateSuite = true 234 case includePSKSuites && c.AuthenticationType() == CipherSuiteAuthenticationTypePreSharedKey: 235 foundPSKSuite = true 236 case c.AuthenticationType() == CipherSuiteAuthenticationTypeAnonymous: 237 foundAnonymousSuite = true 238 default: 239 continue 240 } 241 cipherSuites[i] = c 242 i++ 243 } 244 245 switch { 246 case includeCertificateSuites && !foundCertificateSuite && !foundAnonymousSuite: 247 return nil, errNoAvailableCertificateCipherSuite 248 case includePSKSuites && !foundPSKSuite: 249 return nil, errNoAvailablePSKCipherSuite 250 case i == 0: 251 return nil, errNoAvailableCipherSuites 252 } 253 254 return cipherSuites[:i], nil 255 } 256 257 func filterCipherSuitesForCertificate(cert *tls.Certificate, cipherSuites []CipherSuite) []CipherSuite { 258 if cert == nil || cert.PrivateKey == nil { 259 return cipherSuites 260 } 261 var certType clientcertificate.Type 262 switch cert.PrivateKey.(type) { 263 case ed25519.PrivateKey, *ecdsa.PrivateKey: 264 certType = clientcertificate.ECDSASign 265 case *rsa.PrivateKey: 266 certType = clientcertificate.RSASign 267 } 268 269 filtered := []CipherSuite{} 270 for _, c := range cipherSuites { 271 if c.AuthenticationType() != CipherSuiteAuthenticationTypeCertificate || certType == c.CertificateType() { 272 filtered = append(filtered, c) 273 } 274 } 275 return filtered 276 }