mirror of
https://github.com/refraction-networking/utls.git
synced 2025-04-03 20:17:36 +03:00
This refactors a lot of the certificate support logic to make it cleaner and reusable where possible. These changes will make the following CLs much simpler. In particular, the heavily overloaded pickSignatureAlgorithm is gone. That function used to cover both signing and verifying side, would work both for pre-signature_algorithms TLS 1.0/1.1 and TLS 1.2, and returned sigalg, type and hash. Now, TLS 1.0/1.1 and 1.2 are differentiated at the caller, as they have effectively completely different logic. TLS 1.0/1.1 simply use legacyTypeAndHashFromPublicKey as they employ a fixed hash function and signature algorithm for each public key type. TLS 1.2 is instead routed through selectSignatureScheme (on the signing side) or isSupportedSignatureAlgorithm (on the verifying side) and typeAndHashFromSignatureScheme, like TLS 1.3. On the signing side, signatureSchemesForCertificate was already version aware (for PKCS#1 v1.5 vs PSS support), so selectSignatureScheme just had to learn the Section 7.4.1.4.1 defaults for a missing signature_algorithms to replace pickSignatureAlgorithm. On the verifying side, pickSignatureAlgorithm was also checking the public key type, while isSupportedSignatureAlgorithm + typeAndHashFromSignatureScheme are not, but that check was redundant with the one in verifyHandshakeSignature. There should be no major change in behavior so far. A few minor changes came from the refactor: we now correctly require signature_algorithms in TLS 1.3 when using a certificate; we won't use Ed25519 in TLS 1.2 if the client didn't send signature_algorithms; and we don't send ec_points_format in the ServerHello (a compatibility measure) if we are not doing ECDHE anyway because there are no mutually supported curves. The tests also got simpler because they test simpler functions. The caller logic switching between TLS 1.0/1.1 and 1.2 is tested by the transcript tests. Updates #32426 Change-Id: Ice9dcaea78d204718f661f8d60efdb408ba41577 Reviewed-on: https://go-review.googlesource.com/c/go/+/205061 Reviewed-by: Katie Hockman <katie@golang.org>
442 lines
15 KiB
Go
442 lines
15 KiB
Go
// Copyright 2010 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package tls
|
|
|
|
import (
|
|
"crypto"
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"crypto/des"
|
|
"crypto/hmac"
|
|
"crypto/rc4"
|
|
"crypto/sha1"
|
|
"crypto/sha256"
|
|
"crypto/x509"
|
|
"golang.org/x/crypto/chacha20poly1305"
|
|
"hash"
|
|
)
|
|
|
|
// a keyAgreement implements the client and server side of a TLS key agreement
|
|
// protocol by generating and processing key exchange messages.
|
|
type keyAgreement interface {
|
|
// On the server side, the first two methods are called in order.
|
|
|
|
// In the case that the key agreement protocol doesn't use a
|
|
// ServerKeyExchange message, generateServerKeyExchange can return nil,
|
|
// nil.
|
|
generateServerKeyExchange(*Config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error)
|
|
processClientKeyExchange(*Config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error)
|
|
|
|
// On the client side, the next two methods are called in order.
|
|
|
|
// This method may not be called if the server doesn't send a
|
|
// ServerKeyExchange message.
|
|
processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error
|
|
generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error)
|
|
}
|
|
|
|
const (
|
|
// suiteECDHE indicates that the cipher suite involves elliptic curve
|
|
// Diffie-Hellman. This means that it should only be selected when the
|
|
// client indicates that it supports ECC with a curve and point format
|
|
// that we're happy with.
|
|
suiteECDHE = 1 << iota
|
|
// suiteECSign indicates that the cipher suite involves an ECDSA or
|
|
// EdDSA signature and therefore may only be selected when the server's
|
|
// certificate is ECDSA or EdDSA. If this is not set then the cipher suite
|
|
// is RSA based.
|
|
suiteECSign
|
|
// suiteTLS12 indicates that the cipher suite should only be advertised
|
|
// and accepted when using TLS 1.2.
|
|
suiteTLS12
|
|
// suiteSHA384 indicates that the cipher suite uses SHA384 as the
|
|
// handshake hash.
|
|
suiteSHA384
|
|
// suiteDefaultOff indicates that this cipher suite is not included by
|
|
// default.
|
|
suiteDefaultOff
|
|
)
|
|
|
|
// A cipherSuite is a specific combination of key agreement, cipher and MAC function.
|
|
type cipherSuite struct {
|
|
id uint16
|
|
// the lengths, in bytes, of the key material needed for each component.
|
|
keyLen int
|
|
macLen int
|
|
ivLen int
|
|
ka func(version uint16) keyAgreement
|
|
// flags is a bitmask of the suite* values, above.
|
|
flags int
|
|
cipher func(key, iv []byte, isRead bool) interface{}
|
|
mac func(version uint16, macKey []byte) macFunction
|
|
aead func(key, fixedNonce []byte) aead
|
|
}
|
|
|
|
var cipherSuites = []*cipherSuite{
|
|
// Ciphersuite order is chosen so that ECDHE comes before plain RSA and
|
|
// AEADs are the top preference.
|
|
{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
|
|
{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
|
|
{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM},
|
|
{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadAESGCM},
|
|
{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
|
|
{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
|
|
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
|
|
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
|
|
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
|
|
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherAES, macSHA1, nil},
|
|
{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
|
|
{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherAES, macSHA1, nil},
|
|
{TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM},
|
|
{TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
|
|
{TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
|
|
{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
|
|
{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
|
|
{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
|
|
{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil},
|
|
|
|
// RC4-based cipher suites are disabled by default.
|
|
{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil},
|
|
{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil},
|
|
{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteDefaultOff, cipherRC4, macSHA1, nil},
|
|
}
|
|
|
|
// selectCipherSuite returns the first cipher suite from ids which is also in
|
|
// supportedIDs and passes the ok filter.
|
|
func selectCipherSuite(ids, supportedIDs []uint16, ok func(*cipherSuite) bool) *cipherSuite {
|
|
for _, id := range ids {
|
|
candidate := cipherSuiteByID(id)
|
|
if candidate == nil || !ok(candidate) {
|
|
continue
|
|
}
|
|
|
|
for _, suppID := range supportedIDs {
|
|
if id == suppID {
|
|
return candidate
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// A cipherSuiteTLS13 defines only the pair of the AEAD algorithm and hash
|
|
// algorithm to be used with HKDF. See RFC 8446, Appendix B.4.
|
|
type cipherSuiteTLS13 struct {
|
|
id uint16
|
|
keyLen int
|
|
aead func(key, fixedNonce []byte) aead
|
|
hash crypto.Hash
|
|
}
|
|
|
|
var cipherSuitesTLS13 = []*cipherSuiteTLS13{
|
|
{TLS_AES_128_GCM_SHA256, 16, aeadAESGCMTLS13, crypto.SHA256},
|
|
{TLS_CHACHA20_POLY1305_SHA256, 32, aeadChaCha20Poly1305, crypto.SHA256},
|
|
{TLS_AES_256_GCM_SHA384, 32, aeadAESGCMTLS13, crypto.SHA384},
|
|
}
|
|
|
|
func cipherRC4(key, iv []byte, isRead bool) interface{} {
|
|
cipher, _ := rc4.NewCipher(key)
|
|
return cipher
|
|
}
|
|
|
|
func cipher3DES(key, iv []byte, isRead bool) interface{} {
|
|
block, _ := des.NewTripleDESCipher(key)
|
|
if isRead {
|
|
return cipher.NewCBCDecrypter(block, iv)
|
|
}
|
|
return cipher.NewCBCEncrypter(block, iv)
|
|
}
|
|
|
|
func cipherAES(key, iv []byte, isRead bool) interface{} {
|
|
block, _ := aes.NewCipher(key)
|
|
if isRead {
|
|
return cipher.NewCBCDecrypter(block, iv)
|
|
}
|
|
return cipher.NewCBCEncrypter(block, iv)
|
|
}
|
|
|
|
// macSHA1 returns a macFunction for the given protocol version.
|
|
func macSHA1(version uint16, key []byte) macFunction {
|
|
return tls10MAC{h: hmac.New(newConstantTimeHash(sha1.New), key)}
|
|
}
|
|
|
|
// macSHA256 returns a SHA-256 based MAC. These are only supported in TLS 1.2
|
|
// so the given version is ignored.
|
|
func macSHA256(version uint16, key []byte) macFunction {
|
|
return tls10MAC{h: hmac.New(sha256.New, key)}
|
|
}
|
|
|
|
type macFunction interface {
|
|
// Size returns the length of the MAC.
|
|
Size() int
|
|
// MAC appends the MAC of (seq, header, data) to out. The extra data is fed
|
|
// into the MAC after obtaining the result to normalize timing. The result
|
|
// is only valid until the next invocation of MAC as the buffer is reused.
|
|
MAC(seq, header, data, extra []byte) []byte
|
|
}
|
|
|
|
type aead interface {
|
|
cipher.AEAD
|
|
|
|
// explicitNonceLen returns the number of bytes of explicit nonce
|
|
// included in each record. This is eight for older AEADs and
|
|
// zero for modern ones.
|
|
explicitNonceLen() int
|
|
}
|
|
|
|
const (
|
|
aeadNonceLength = 12
|
|
noncePrefixLength = 4
|
|
)
|
|
|
|
// prefixNonceAEAD wraps an AEAD and prefixes a fixed portion of the nonce to
|
|
// each call.
|
|
type prefixNonceAEAD struct {
|
|
// nonce contains the fixed part of the nonce in the first four bytes.
|
|
nonce [aeadNonceLength]byte
|
|
aead cipher.AEAD
|
|
}
|
|
|
|
func (f *prefixNonceAEAD) NonceSize() int { return aeadNonceLength - noncePrefixLength }
|
|
func (f *prefixNonceAEAD) Overhead() int { return f.aead.Overhead() }
|
|
func (f *prefixNonceAEAD) explicitNonceLen() int { return f.NonceSize() }
|
|
|
|
func (f *prefixNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
|
|
copy(f.nonce[4:], nonce)
|
|
return f.aead.Seal(out, f.nonce[:], plaintext, additionalData)
|
|
}
|
|
|
|
func (f *prefixNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
|
copy(f.nonce[4:], nonce)
|
|
return f.aead.Open(out, f.nonce[:], ciphertext, additionalData)
|
|
}
|
|
|
|
// xoredNonceAEAD wraps an AEAD by XORing in a fixed pattern to the nonce
|
|
// before each call.
|
|
type xorNonceAEAD struct {
|
|
nonceMask [aeadNonceLength]byte
|
|
aead cipher.AEAD
|
|
}
|
|
|
|
func (f *xorNonceAEAD) NonceSize() int { return 8 } // 64-bit sequence number
|
|
func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead() }
|
|
func (f *xorNonceAEAD) explicitNonceLen() int { return 0 }
|
|
|
|
func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
|
|
for i, b := range nonce {
|
|
f.nonceMask[4+i] ^= b
|
|
}
|
|
result := f.aead.Seal(out, f.nonceMask[:], plaintext, additionalData)
|
|
for i, b := range nonce {
|
|
f.nonceMask[4+i] ^= b
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (f *xorNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
|
for i, b := range nonce {
|
|
f.nonceMask[4+i] ^= b
|
|
}
|
|
result, err := f.aead.Open(out, f.nonceMask[:], ciphertext, additionalData)
|
|
for i, b := range nonce {
|
|
f.nonceMask[4+i] ^= b
|
|
}
|
|
|
|
return result, err
|
|
}
|
|
|
|
func aeadAESGCM(key, noncePrefix []byte) aead {
|
|
if len(noncePrefix) != noncePrefixLength {
|
|
panic("tls: internal error: wrong nonce length")
|
|
}
|
|
aes, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
aead, err := cipher.NewGCM(aes)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
ret := &prefixNonceAEAD{aead: aead}
|
|
copy(ret.nonce[:], noncePrefix)
|
|
return ret
|
|
}
|
|
|
|
func aeadAESGCMTLS13(key, nonceMask []byte) aead {
|
|
if len(nonceMask) != aeadNonceLength {
|
|
panic("tls: internal error: wrong nonce length")
|
|
}
|
|
aes, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
aead, err := cipher.NewGCM(aes)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
ret := &xorNonceAEAD{aead: aead}
|
|
copy(ret.nonceMask[:], nonceMask)
|
|
return ret
|
|
}
|
|
|
|
func aeadChaCha20Poly1305(key, nonceMask []byte) aead {
|
|
if len(nonceMask) != aeadNonceLength {
|
|
panic("tls: internal error: wrong nonce length")
|
|
}
|
|
aead, err := chacha20poly1305.New(key)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
ret := &xorNonceAEAD{aead: aead}
|
|
copy(ret.nonceMask[:], nonceMask)
|
|
return ret
|
|
}
|
|
|
|
type constantTimeHash interface {
|
|
hash.Hash
|
|
ConstantTimeSum(b []byte) []byte
|
|
}
|
|
|
|
// cthWrapper wraps any hash.Hash that implements ConstantTimeSum, and replaces
|
|
// with that all calls to Sum. It's used to obtain a ConstantTimeSum-based HMAC.
|
|
type cthWrapper struct {
|
|
h constantTimeHash
|
|
}
|
|
|
|
func (c *cthWrapper) Size() int { return c.h.Size() }
|
|
func (c *cthWrapper) BlockSize() int { return c.h.BlockSize() }
|
|
func (c *cthWrapper) Reset() { c.h.Reset() }
|
|
func (c *cthWrapper) Write(p []byte) (int, error) { return c.h.Write(p) }
|
|
func (c *cthWrapper) Sum(b []byte) []byte { return c.h.ConstantTimeSum(b) }
|
|
|
|
func newConstantTimeHash(h func() hash.Hash) func() hash.Hash {
|
|
return func() hash.Hash {
|
|
return &cthWrapper{h().(constantTimeHash)}
|
|
}
|
|
}
|
|
|
|
// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, Section 6.2.3.
|
|
type tls10MAC struct {
|
|
h hash.Hash
|
|
buf []byte
|
|
}
|
|
|
|
func (s tls10MAC) Size() int {
|
|
return s.h.Size()
|
|
}
|
|
|
|
// MAC is guaranteed to take constant time, as long as
|
|
// len(seq)+len(header)+len(data)+len(extra) is constant. extra is not fed into
|
|
// the MAC, but is only provided to make the timing profile constant.
|
|
func (s tls10MAC) MAC(seq, header, data, extra []byte) []byte {
|
|
s.h.Reset()
|
|
s.h.Write(seq)
|
|
s.h.Write(header)
|
|
s.h.Write(data)
|
|
res := s.h.Sum(s.buf[:0])
|
|
if extra != nil {
|
|
s.h.Write(extra)
|
|
}
|
|
return res
|
|
}
|
|
|
|
func rsaKA(version uint16) keyAgreement {
|
|
return rsaKeyAgreement{}
|
|
}
|
|
|
|
func ecdheECDSAKA(version uint16) keyAgreement {
|
|
return &ecdheKeyAgreement{
|
|
isRSA: false,
|
|
version: version,
|
|
}
|
|
}
|
|
|
|
func ecdheRSAKA(version uint16) keyAgreement {
|
|
return &ecdheKeyAgreement{
|
|
isRSA: true,
|
|
version: version,
|
|
}
|
|
}
|
|
|
|
// mutualCipherSuite returns a cipherSuite given a list of supported
|
|
// ciphersuites and the id requested by the peer.
|
|
func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
|
|
for _, id := range have {
|
|
if id == want {
|
|
return cipherSuiteByID(id)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func cipherSuiteByID(id uint16) *cipherSuite {
|
|
for _, cipherSuite := range cipherSuites {
|
|
if cipherSuite.id == id {
|
|
return cipherSuite
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func mutualCipherSuiteTLS13(have []uint16, want uint16) *cipherSuiteTLS13 {
|
|
for _, id := range have {
|
|
if id == want {
|
|
return cipherSuiteTLS13ByID(id)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func cipherSuiteTLS13ByID(id uint16) *cipherSuiteTLS13 {
|
|
for _, cipherSuite := range cipherSuitesTLS13 {
|
|
if cipherSuite.id == id {
|
|
return cipherSuite
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// A list of cipher suite IDs that are, or have been, implemented by this
|
|
// package.
|
|
//
|
|
// Taken from https://www.iana.org/assignments/tls-parameters/tls-parameters.xml
|
|
const (
|
|
// TLS 1.0 - 1.2 cipher suites.
|
|
TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
|
|
TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a
|
|
TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f
|
|
TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035
|
|
TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003c
|
|
TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c
|
|
TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009d
|
|
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xc007
|
|
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xc009
|
|
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xc00a
|
|
TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011
|
|
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012
|
|
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013
|
|
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014
|
|
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc023
|
|
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc027
|
|
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02f
|
|
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b
|
|
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030
|
|
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c
|
|
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 uint16 = 0xcca8
|
|
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 uint16 = 0xcca9
|
|
|
|
// TLS 1.3 cipher suites.
|
|
TLS_AES_128_GCM_SHA256 uint16 = 0x1301
|
|
TLS_AES_256_GCM_SHA384 uint16 = 0x1302
|
|
TLS_CHACHA20_POLY1305_SHA256 uint16 = 0x1303
|
|
|
|
// TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator
|
|
// that the client is doing version fallback. See RFC 7507.
|
|
TLS_FALLBACK_SCSV uint16 = 0x5600
|
|
)
|