cipher_suite.go 10 KB

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