Skip to content

Commit 106db71

Browse files
committed
crypto/tls: implement TLS 1.3 client authentication
Note that the SignatureSchemes passed to GetClientCertificate in TLS 1.2 are now filtered by the requested certificate type. This feels like an improvement anyway, and the full list can be surfaced as well when support for signature_algorithms_cert is added, which actually matches the semantics of the CertificateRequest signature_algorithms in TLS 1.2. Also, note a subtle behavior change in server side resumption: if a certificate is requested but not required, and the resumed session did not include one, it used not to invoke VerifyPeerCertificate. However, if the resumed session did include a certificate, it would. (If a certificate was required but not in the session, the session is rejected in checkForResumption.) This inconsistency could be unexpected, even dangerous, so now VerifyPeerCertificate is always invoked. Still not consistent with the client behavior, which does not ever invoke VerifyPeerCertificate on resumption, but it felt too surprising to entirely change either. Updates #9671 Change-Id: Ib2b0dbc30e659208dca3ac07d6c687a407d7aaaf Reviewed-on: https://go-review.googlesource.com/c/147599 Reviewed-by: Adam Langley <[email protected]>
1 parent 6435d0c commit 106db71

16 files changed

+1581
-171
lines changed

src/crypto/tls/common.go

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ const (
9292
extensionSupportedVersions uint16 = 43
9393
extensionCookie uint16 = 44
9494
extensionPSKModes uint16 = 45
95+
extensionCertificateAuthorities uint16 = 47
9596
extensionSignatureAlgorithmsCert uint16 = 50
9697
extensionKeyShare uint16 = 51
9798
extensionNextProtoNeg uint16 = 13172 // not IANA assigned

src/crypto/tls/conn.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ type Conn struct {
5757
secureRenegotiation bool
5858
// ekm is a closure for exporting keying material.
5959
ekm func(label string, context []byte, length int) ([]byte, error)
60-
// resumptionSecret is the resumption_master_secret for generating or
61-
// handling NewSessionTicket messages. nil if config.SessionTicketsDisabled.
60+
// resumptionSecret is the resumption_master_secret for handling
61+
// NewSessionTicket messages. nil if config.SessionTicketsDisabled.
6262
resumptionSecret []byte
6363

6464
// clientFinishedIsFirst is true if the client sent the first Finished

src/crypto/tls/handshake_client.go

+66-63
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,8 @@ func (hs *clientHandshakeState) doFullHandshake() error {
519519
certRequested = true
520520
hs.finishedHash.Write(certReq.marshal())
521521

522-
if chainToSend, err = hs.getCertificate(certReq); err != nil {
522+
cri := certificateRequestInfoFromMsg(certReq)
523+
if chainToSend, err = c.getClientCertificate(cri); err != nil {
523524
c.sendAlert(alertInternalError)
524525
return err
525526
}
@@ -863,20 +864,15 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
863864

864865
// tls11SignatureSchemes contains the signature schemes that we synthesise for
865866
// a TLS <= 1.1 connection, based on the supported certificate types.
866-
var tls11SignatureSchemes = []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1}
867-
868-
const (
869-
// tls11SignatureSchemesNumECDSA is the number of initial elements of
870-
// tls11SignatureSchemes that use ECDSA.
871-
tls11SignatureSchemesNumECDSA = 3
872-
// tls11SignatureSchemesNumRSA is the number of trailing elements of
873-
// tls11SignatureSchemes that use RSA.
874-
tls11SignatureSchemesNumRSA = 4
867+
var (
868+
tls11SignatureSchemes = []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1}
869+
tls11SignatureSchemesECDSA = tls11SignatureSchemes[:3]
870+
tls11SignatureSchemesRSA = tls11SignatureSchemes[3:]
875871
)
876872

877-
func (hs *clientHandshakeState) getCertificate(certReq *certificateRequestMsg) (*Certificate, error) {
878-
c := hs.c
879-
873+
// certificateRequestInfoFromMsg generates a CertificateRequestInfo from a TLS
874+
// <= 1.2 CertificateRequest, making an effort to fill in missing information.
875+
func certificateRequestInfoFromMsg(certReq *certificateRequestMsg) *CertificateRequestInfo {
880876
var rsaAvail, ecdsaAvail bool
881877
for _, certType := range certReq.certificateTypes {
882878
switch certType {
@@ -887,77 +883,84 @@ func (hs *clientHandshakeState) getCertificate(certReq *certificateRequestMsg) (
887883
}
888884
}
889885

890-
if c.config.GetClientCertificate != nil {
891-
var signatureSchemes []SignatureScheme
892-
893-
if !certReq.hasSignatureAlgorithm {
894-
// Prior to TLS 1.2, the signature schemes were not
895-
// included in the certificate request message. In this
896-
// case we use a plausible list based on the acceptable
897-
// certificate types.
898-
signatureSchemes = tls11SignatureSchemes
899-
if !ecdsaAvail {
900-
signatureSchemes = signatureSchemes[tls11SignatureSchemesNumECDSA:]
886+
cri := &CertificateRequestInfo{
887+
AcceptableCAs: certReq.certificateAuthorities,
888+
}
889+
890+
if !certReq.hasSignatureAlgorithm {
891+
// Prior to TLS 1.2, the signature schemes were not
892+
// included in the certificate request message. In this
893+
// case we use a plausible list based on the acceptable
894+
// certificate types.
895+
switch {
896+
case rsaAvail && ecdsaAvail:
897+
cri.SignatureSchemes = tls11SignatureSchemes
898+
case rsaAvail:
899+
cri.SignatureSchemes = tls11SignatureSchemesRSA
900+
case ecdsaAvail:
901+
cri.SignatureSchemes = tls11SignatureSchemesECDSA
902+
}
903+
return cri
904+
}
905+
906+
// In TLS 1.2, the signature schemes apply to both the certificate chain and
907+
// the leaf key, while the certificate types only apply to the leaf key.
908+
// See RFC 5246, Section 7.4.4 (where it calls this "somewhat complicated").
909+
// Filter the signature schemes based on the certificate type.
910+
cri.SignatureSchemes = make([]SignatureScheme, 0, len(certReq.supportedSignatureAlgorithms))
911+
for _, sigScheme := range certReq.supportedSignatureAlgorithms {
912+
switch signatureFromSignatureScheme(sigScheme) {
913+
case signatureECDSA:
914+
if ecdsaAvail {
915+
cri.SignatureSchemes = append(cri.SignatureSchemes, sigScheme)
901916
}
902-
if !rsaAvail {
903-
signatureSchemes = signatureSchemes[:len(signatureSchemes)-tls11SignatureSchemesNumRSA]
917+
case signatureRSAPSS, signaturePKCS1v15:
918+
if rsaAvail {
919+
cri.SignatureSchemes = append(cri.SignatureSchemes, sigScheme)
904920
}
905-
} else {
906-
signatureSchemes = certReq.supportedSignatureAlgorithms
907921
}
908-
909-
return c.config.GetClientCertificate(&CertificateRequestInfo{
910-
AcceptableCAs: certReq.certificateAuthorities,
911-
SignatureSchemes: signatureSchemes,
912-
})
913922
}
914923

915-
// RFC 4346 on the certificateAuthorities field: A list of the
916-
// distinguished names of acceptable certificate authorities.
917-
// These distinguished names may specify a desired
918-
// distinguished name for a root CA or for a subordinate CA;
919-
// thus, this message can be used to describe both known roots
920-
// and a desired authorization space. If the
921-
// certificate_authorities list is empty then the client MAY
922-
// send any certificate of the appropriate
923-
// ClientCertificateType, unless there is some external
924-
// arrangement to the contrary.
924+
return cri
925+
}
926+
927+
func (c *Conn) getClientCertificate(cri *CertificateRequestInfo) (*Certificate, error) {
928+
if c.config.GetClientCertificate != nil {
929+
return c.config.GetClientCertificate(cri)
930+
}
925931

926932
// We need to search our list of client certs for one
927933
// where SignatureAlgorithm is acceptable to the server and the
928-
// Issuer is in certReq.certificateAuthorities
929-
findCert:
934+
// Issuer is in AcceptableCAs.
930935
for i, chain := range c.config.Certificates {
931-
if !rsaAvail && !ecdsaAvail {
936+
sigOK := false
937+
for _, alg := range signatureSchemesForCertificate(&chain) {
938+
if isSupportedSignatureAlgorithm(alg, cri.SignatureSchemes) {
939+
sigOK = true
940+
break
941+
}
942+
}
943+
if !sigOK {
932944
continue
933945
}
934946

947+
if len(cri.AcceptableCAs) == 0 {
948+
return &chain, nil
949+
}
950+
935951
for j, cert := range chain.Certificate {
936952
x509Cert := chain.Leaf
937-
// parse the certificate if this isn't the leaf
938-
// node, or if chain.Leaf was nil
953+
// Parse the certificate if this isn't the leaf node, or if
954+
// chain.Leaf was nil.
939955
if j != 0 || x509Cert == nil {
940956
var err error
941957
if x509Cert, err = x509.ParseCertificate(cert); err != nil {
942958
c.sendAlert(alertInternalError)
943-
return nil, errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error())
959+
return nil, errors.New("tls: failed to parse configured certificate chain #" + strconv.Itoa(i) + ": " + err.Error())
944960
}
945961
}
946962

947-
switch {
948-
case rsaAvail && x509Cert.PublicKeyAlgorithm == x509.RSA:
949-
case ecdsaAvail && x509Cert.PublicKeyAlgorithm == x509.ECDSA:
950-
default:
951-
continue findCert
952-
}
953-
954-
if len(certReq.certificateAuthorities) == 0 {
955-
// they gave us an empty list, so just take the
956-
// first cert from c.config.Certificates
957-
return &chain, nil
958-
}
959-
960-
for _, ca := range certReq.certificateAuthorities {
963+
for _, ca := range cri.AcceptableCAs {
961964
if bytes.Equal(x509Cert.RawIssuer, ca) {
962965
return &chain, nil
963966
}

src/crypto/tls/handshake_client_test.go

+31-21
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,7 @@ func TestHandshakeClientCertRSA(t *testing.T) {
777777

778778
runClientTestTLS10(t, test)
779779
runClientTestTLS12(t, test)
780+
runClientTestTLS13(t, test)
780781

781782
test = &clientTest{
782783
name: "ClientCert-RSA-AES256-GCM-SHA384",
@@ -802,6 +803,7 @@ func TestHandshakeClientCertECDSA(t *testing.T) {
802803

803804
runClientTestTLS10(t, test)
804805
runClientTestTLS12(t, test)
806+
runClientTestTLS13(t, test)
805807

806808
test = &clientTest{
807809
name: "ClientCert-ECDSA-ECDSA",
@@ -843,6 +845,7 @@ func TestHandshakeClientCertRSAPSS(t *testing.T) {
843845
}
844846

845847
runClientTestTLS12(t, test)
848+
runClientTestTLS13(t, test)
846849
}
847850

848851
func TestHandshakeClientCertRSAPKCS1v15(t *testing.T) {
@@ -917,6 +920,9 @@ func testResumption(t *testing.T, version uint16) {
917920
ticketKey := clientConfig.ClientSessionCache.(*lruSessionCache).q.Front().Value.(*lruSessionCacheEntry).sessionKey
918921
clientConfig.ClientSessionCache.Put(ticketKey, nil)
919922
}
923+
corruptTicket := func() {
924+
clientConfig.ClientSessionCache.(*lruSessionCache).q.Front().Value.(*lruSessionCacheEntry).state.masterSecret[0] ^= 0xff
925+
}
920926
randomKey := func() [32]byte {
921927
var k [32]byte
922928
if _, err := io.ReadFull(serverConfig.rand(), k[:]); err != nil {
@@ -978,21 +984,18 @@ func testResumption(t *testing.T, version uint16) {
978984
serverConfig.ClientAuth = RequireAndVerifyClientCert
979985
clientConfig.Certificates = serverConfig.Certificates
980986
testResumeState("InitialHandshake", false)
981-
if version != VersionTLS13 {
982-
// TODO(filippo): reenable when client authentication is implemented
983-
testResumeState("WithClientCertificates", true)
984-
985-
// Tickets should be removed from the session cache on TLS handshake failure
986-
farFuture := func() time.Time { return time.Unix(16725225600, 0) }
987-
serverConfig.Time = farFuture
988-
_, _, err = testHandshake(t, clientConfig, serverConfig)
989-
if err == nil {
990-
t.Fatalf("handshake did not fail after client certificate expiry")
991-
}
992-
serverConfig.Time = nil
993-
testResumeState("AfterHandshakeFailure", false)
994-
serverConfig.ClientAuth = NoClientCert
987+
testResumeState("WithClientCertificates", true)
988+
serverConfig.ClientAuth = NoClientCert
989+
990+
// Tickets should be removed from the session cache on TLS handshake
991+
// failure, and the client should recover from a corrupted PSK
992+
testResumeState("FetchTicketToCorrupt", false)
993+
corruptTicket()
994+
_, _, err = testHandshake(t, clientConfig, serverConfig)
995+
if err == nil {
996+
t.Fatalf("handshake did not fail with a corrupted client secret")
995997
}
998+
testResumeState("AfterHandshakeFailure", false)
996999

9971000
clientConfig.ClientSessionCache = nil
9981001
testResumeState("WithoutSessionCache", false)
@@ -1415,6 +1418,11 @@ func TestServerSelectingUnconfiguredCipherSuite(t *testing.T) {
14151418
}
14161419

14171420
func TestVerifyPeerCertificate(t *testing.T) {
1421+
t.Run("TLSv12", func(t *testing.T) { testVerifyPeerCertificate(t, VersionTLS12) })
1422+
t.Run("TLSv13", func(t *testing.T) { testVerifyPeerCertificate(t, VersionTLS13) })
1423+
}
1424+
1425+
func testVerifyPeerCertificate(t *testing.T, version uint16) {
14181426
issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
14191427
if err != nil {
14201428
panic(err)
@@ -1548,6 +1556,7 @@ func TestVerifyPeerCertificate(t *testing.T) {
15481556
config.ClientAuth = RequireAndVerifyClientCert
15491557
config.ClientCAs = rootCAs
15501558
config.Time = now
1559+
config.MaxVersion = version
15511560
test.configureServer(config, &serverCalled)
15521561

15531562
err = Server(s, config).Handshake()
@@ -1559,6 +1568,7 @@ func TestVerifyPeerCertificate(t *testing.T) {
15591568
config.ServerName = "example.golang"
15601569
config.RootCAs = rootCAs
15611570
config.Time = now
1571+
config.MaxVersion = version
15621572
test.configureClient(config, &clientCalled)
15631573
clientErr := Client(c, config).Handshake()
15641574
c.Close()
@@ -1757,13 +1767,6 @@ func TestHandshakeRace(t *testing.T) {
17571767
}
17581768
}
17591769

1760-
func TestTLS11SignatureSchemes(t *testing.T) {
1761-
expected := tls11SignatureSchemesNumECDSA + tls11SignatureSchemesNumRSA
1762-
if expected != len(tls11SignatureSchemes) {
1763-
t.Errorf("expected to find %d TLS 1.1 signature schemes, but found %d", expected, len(tls11SignatureSchemes))
1764-
}
1765-
}
1766-
17671770
var getClientCertificateTests = []struct {
17681771
setup func(*Config, *Config)
17691772
expectedClientError string
@@ -1846,6 +1849,11 @@ var getClientCertificateTests = []struct {
18461849
}
18471850

18481851
func TestGetClientCertificate(t *testing.T) {
1852+
t.Run("TLSv12", func(t *testing.T) { testGetClientCertificate(t, VersionTLS12) })
1853+
t.Run("TLSv13", func(t *testing.T) { testGetClientCertificate(t, VersionTLS13) })
1854+
}
1855+
1856+
func testGetClientCertificate(t *testing.T, version uint16) {
18491857
issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
18501858
if err != nil {
18511859
panic(err)
@@ -1858,8 +1866,10 @@ func TestGetClientCertificate(t *testing.T) {
18581866
serverConfig.RootCAs.AddCert(issuer)
18591867
serverConfig.ClientCAs = serverConfig.RootCAs
18601868
serverConfig.Time = func() time.Time { return time.Unix(1476984729, 0) }
1869+
serverConfig.MaxVersion = version
18611870

18621871
clientConfig := testConfig.Clone()
1872+
clientConfig.MaxVersion = version
18631873

18641874
test.setup(clientConfig, serverConfig)
18651875

0 commit comments

Comments
 (0)