Skip to content

crypto/tls: expose implemented cipher suites #30739

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 117 additions & 56 deletions src/crypto/tls/cipher_suites.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"crypto/sha256"
"crypto/x509"
"hash"
"errors"
"internal/x/crypto/chacha20poly1305"
)

Expand Down Expand Up @@ -42,80 +43,140 @@ const (
// 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
// suiteECDSA indicates that the cipher suite involves an ECDSA
SuiteECDHE = 1 << iota
// SuiteECDSA indicates that the cipher suite involves an ECDSA
// signature and therefore may only be selected when the server's
// certificate is ECDSA. If this is not set then the cipher suite is
// RSA based.
suiteECDSA
// suiteTLS12 indicates that the cipher suite should only be advertised
SuiteECDSA
// 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
SuiteTLS12
// SuiteSHA384 indicates that the cipher suite uses SHA384 as the
// handshake hash.
suiteSHA384
// suiteDefaultOff indicates that this cipher suite is not included by
SuiteSHA384
// SuiteDefaultOff indicates that this cipher suite is not included by
// default.
suiteDefaultOff
SuiteDefaultOff
)

// A cipherSuite is a specific combination of key agreement, cipher and MAC function.
type cipherSuite struct {
id uint16
// A CipherSuite is a specific combination of key agreement, cipher and MAC function.
type CipherSuite struct {
Id uint16
Name string
// the lengths, in bytes, of the key material needed for each component.
keyLen int
macLen int
ivLen int
KeyLen int
MacLen int
IvLen int
ka func(version uint16) keyAgreement
// flags is a bitmask of the suite* values, above.
flags int
// 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{
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 | suiteECDSA | 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 | suiteECDSA | 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 | suiteECDSA | 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 | suiteECDSA | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, 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 | suiteECDSA, 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},
{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", 32, 0, 12, ecdheRSAKA, SuiteECDHE | SuiteTLS12, nil, nil, aeadChaCha20Poly1305},
{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", 32, 0, 12, ecdheECDSAKA, SuiteECDHE | SuiteECDSA | SuiteTLS12, nil, nil, aeadChaCha20Poly1305},
{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, "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, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 16, 0, 4, ecdheECDSAKA, SuiteECDHE | SuiteECDSA | SuiteTLS12, nil, nil, aeadAESGCM},
{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "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, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 32, 0, 4, ecdheECDSAKA, SuiteECDHE | SuiteECDSA | SuiteTLS12 | SuiteSHA384, nil, nil, aeadAESGCM},
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, "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, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", 16, 20, 16, ecdheRSAKA, SuiteECDHE, cipherAES, macSHA1, nil},
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", 16, 32, 16, ecdheECDSAKA, SuiteECDHE | SuiteECDSA | SuiteTLS12 | SuiteDefaultOff, cipherAES, macSHA256, nil},
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", 16, 20, 16, ecdheECDSAKA, SuiteECDHE | SuiteECDSA, cipherAES, macSHA1, nil},
{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", 32, 20, 16, ecdheRSAKA, SuiteECDHE, cipherAES, macSHA1, nil},
{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", 32, 20, 16, ecdheECDSAKA, SuiteECDHE | SuiteECDSA, cipherAES, macSHA1, nil},
{TLS_RSA_WITH_AES_128_GCM_SHA256, "TLS_RSA_WITH_AES_128_GCM_SHA256", 16, 0, 4, rsaKA, SuiteTLS12, nil, nil, aeadAESGCM},
{TLS_RSA_WITH_AES_256_GCM_SHA384, "TLS_RSA_WITH_AES_256_GCM_SHA384", 32, 0, 4, rsaKA, SuiteTLS12 | SuiteSHA384, nil, nil, aeadAESGCM},
{TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256", 16, 32, 16, rsaKA, SuiteTLS12 | SuiteDefaultOff, cipherAES, macSHA256, nil},
{TLS_RSA_WITH_AES_128_CBC_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA", 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
{TLS_RSA_WITH_AES_256_CBC_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA,", 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", 24, 20, 8, ecdheRSAKA, SuiteECDHE, cipher3DES, macSHA1, nil},
{TLS_RSA_WITH_3DES_EDE_CBC_SHA, "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 | suiteECDSA | suiteDefaultOff, cipherRC4, macSHA1, nil},
{TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_RC4_128_SHA", 16, 20, 0, rsaKA, SuiteDefaultOff, cipherRC4, macSHA1, nil},
{TLS_ECDHE_RSA_WITH_RC4_128_SHA, "TLS_ECDHE_RSA_WITH_RC4_128_SHA", 16, 20, 0, ecdheRSAKA, SuiteECDHE | SuiteDefaultOff, cipherRC4, macSHA1, nil},
{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", 16, 20, 0, ecdheECDSAKA, SuiteECDHE | SuiteECDSA | SuiteDefaultOff, cipherRC4, macSHA1, nil},
}

// A cipherSuiteTLS13 defines only the pair of the AEAD algorithm and hash
// CipherSuites returns a copy of all available CipherSuites, including disabled by default ones
func CipherSuites() []CipherSuite {
var suites []CipherSuite
for _, cs := range cipherSuites {
suites = append(suites, CipherSuite(*cs))
}
return suites
}

// CipherSuite returns a copy of the CipherSuite struct given the ID
func CipherSuiteById(id uint16) (CipherSuite, error) {
for _, cs := range cipherSuites {
if cs.Id == id {
return CipherSuite(*cs), nil
}
}
return CipherSuite{}, errors.New("cipher id not existing")
}

// CipherSuite returns a copy of the CipherSuite struct given the name of the cipher suite.
func CipherSuiteByName(name string) (CipherSuite, error) {
for _, cs := range cipherSuites {
if cs.Name == name {
return CipherSuite(*cs), nil
}
}
return CipherSuite{}, errors.New("cipher name not existing")
}

// 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
type CipherSuiteTLS13 struct {
Id uint16
Name string
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},
var cipherSuitesTLS13 = []*CipherSuiteTLS13{
{TLS_AES_128_GCM_SHA256, "TLS_AES_128_GCM_SHA256", 16, aeadAESGCMTLS13, crypto.SHA256},
{TLS_CHACHA20_POLY1305_SHA256, "TLS_CHACHA20_POLY1305_SHA256", 32, aeadChaCha20Poly1305, crypto.SHA256},
{TLS_AES_256_GCM_SHA384, "TLS_AES_256_GCM_SHA384", 32, aeadAESGCMTLS13, crypto.SHA384},
}

// CipherSuitesTLS13 returns a copy of all available CipherSuiteTLS13, including disabled by default ones
func CipherSuitesTLS13() []CipherSuiteTLS13 {
var suites []CipherSuiteTLS13
for _, cs := range cipherSuitesTLS13 {
suites = append(suites, CipherSuiteTLS13(*cs))
}
return suites
}

// CipherSuite returns a copy of the CipherSuite struct given the ID
func CipherSuiteTLS13ById(id uint16) (CipherSuiteTLS13, error) {
for _, cs := range cipherSuitesTLS13 {
if cs.Id == id {
return CipherSuiteTLS13(*cs), nil
}
}
return CipherSuiteTLS13{}, errors.New("cipher id not existing")
}

// CipherSuite returns a copy of the CipherSuite struct given the name of the cipher suite.
func CipherSuiteTLS13ByName(name string) (CipherSuiteTLS13, error) {
for _, cs := range cipherSuitesTLS13 {
if cs.Name == name {
return CipherSuiteTLS13(*cs), nil
}
}
return CipherSuiteTLS13{}, errors.New("cipher name not existing")
}

func cipherRC4(key, iv []byte, isRead bool) interface{} {
Expand Down Expand Up @@ -394,9 +455,9 @@ func ecdheRSAKA(version uint16) keyAgreement {
}
}

// mutualCipherSuite returns a cipherSuite given a list of supported
// ciphersuites and the id requested by the peer.
func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
// 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)
Expand All @@ -405,16 +466,16 @@ func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
return nil
}

func cipherSuiteByID(id uint16) *cipherSuite {
func cipherSuiteByID(id uint16) *CipherSuite {
for _, cipherSuite := range cipherSuites {
if cipherSuite.id == id {
if cipherSuite.Id == id {
return cipherSuite
}
}
return nil
}

func mutualCipherSuiteTLS13(have []uint16, want uint16) *cipherSuiteTLS13 {
func mutualCipherSuiteTLS13(have []uint16, want uint16) *CipherSuiteTLS13 {
for _, id := range have {
if id == want {
return cipherSuiteTLS13ByID(id)
Expand All @@ -423,9 +484,9 @@ func mutualCipherSuiteTLS13(have []uint16, want uint16) *cipherSuiteTLS13 {
return nil
}

func cipherSuiteTLS13ByID(id uint16) *cipherSuiteTLS13 {
func cipherSuiteTLS13ByID(id uint16) *CipherSuiteTLS13 {
for _, cipherSuite := range cipherSuitesTLS13 {
if cipherSuite.id == id {
if cipherSuite.Id == id {
return cipherSuite
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/crypto/tls/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -1097,7 +1097,7 @@ func defaultCipherSuitesTLS13() []uint16 {
func initDefaultCipherSuites() {
var topCipherSuites []uint16

// Check the cpu flags for each platform that has optimized GCM implementations.
// Check the cpu Flags for each platform that has optimized GCM implementations.
// Worst case, these variables will just all be false.
var (
hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ
Expand Down Expand Up @@ -1147,15 +1147,15 @@ func initDefaultCipherSuites() {

NextCipherSuite:
for _, suite := range cipherSuites {
if suite.flags&suiteDefaultOff != 0 {
if suite.Flags&SuiteDefaultOff != 0 {
continue
}
for _, existing := range varDefaultCipherSuites {
if existing == suite.id {
if existing == suite.Id {
continue NextCipherSuite
}
}
varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id)
varDefaultCipherSuites = append(varDefaultCipherSuites, suite.Id)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/crypto/tls/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ func (hc *halfConn) changeCipherSpec() error {
return nil
}

func (hc *halfConn) setTrafficSecret(suite *cipherSuiteTLS13, secret []byte) {
func (hc *halfConn) setTrafficSecret(suite *CipherSuiteTLS13, secret []byte) {
hc.trafficSecret = secret
key, iv := suite.trafficKey(secret)
hc.cipher = suite.aead(key, iv)
Expand Down
14 changes: 7 additions & 7 deletions src/crypto/tls/handshake_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type clientHandshakeState struct {
c *Conn
serverHello *serverHelloMsg
hello *clientHelloMsg
suite *cipherSuite
suite *CipherSuite
finishedHash finishedHash
masterSecret []byte
session *ClientSessionState
Expand Down Expand Up @@ -87,12 +87,12 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {

for _, suiteId := range possibleCipherSuites {
for _, suite := range cipherSuites {
if suite.id != suiteId {
if suite.Id != suiteId {
continue
}
// Don't advertise TLS 1.2-only cipher suites unless
// we're attempting TLS 1.2.
if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 {
if hello.vers < VersionTLS12 && suite.Flags&SuiteTLS12 != 0 {
break
}
hello.cipherSuites = append(hello.cipherSuites, suiteId)
Expand Down Expand Up @@ -429,7 +429,7 @@ func (hs *clientHandshakeState) pickCipherSuite() error {
return errors.New("tls: server chose an unconfigured cipher suite")
}

hs.c.cipherSuite = hs.suite.id
hs.c.cipherSuite = hs.suite.Id
return nil
}

Expand Down Expand Up @@ -617,7 +617,7 @@ func (hs *clientHandshakeState) establishKeys() error {
c := hs.c

clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.MacLen, hs.suite.KeyLen, hs.suite.IvLen)
var clientCipher, serverCipher interface{}
var clientHash, serverHash macFunction
if hs.suite.cipher != nil {
Expand Down Expand Up @@ -707,7 +707,7 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
return false, errors.New("tls: server resumed a session with a different version")
}

if hs.session.cipherSuite != hs.suite.id {
if hs.session.cipherSuite != hs.suite.Id {
c.sendAlert(alertHandshakeFailure)
return false, errors.New("tls: server resumed a session with a different cipher suite")
}
Expand Down Expand Up @@ -767,7 +767,7 @@ func (hs *clientHandshakeState) readSessionTicket() error {
hs.session = &ClientSessionState{
sessionTicket: sessionTicketMsg.ticket,
vers: c.vers,
cipherSuite: hs.suite.id,
cipherSuite: hs.suite.Id,
masterSecret: hs.masterSecret,
serverCertificates: c.peerCertificates,
verifiedChains: c.verifiedChains,
Expand Down
4 changes: 2 additions & 2 deletions src/crypto/tls/handshake_client_tls13.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type clientHandshakeStateTLS13 struct {
certReq *certificateRequestMsgTLS13
usingPSK bool
sentDummyCCS bool
suite *cipherSuiteTLS13
suite *CipherSuiteTLS13
transcript hash.Hash
masterSecret []byte
trafficSecret []byte // client_application_traffic_secret_0
Expand Down Expand Up @@ -155,7 +155,7 @@ func (hs *clientHandshakeStateTLS13) checkServerHelloOrHRR() error {
return errors.New("tls: server chose an unconfigured cipher suite")
}
hs.suite = selectedSuite
c.cipherSuite = hs.suite.id
c.cipherSuite = hs.suite.Id

return nil
}
Expand Down
Loading