Implement client certificates for TLS 1.3 in Go.

Tested by having client and server talk to each other. This adds the
certificate_extensions field to CertificateRequest which I'd previously
missed. (We completely ignore the field, with the expectation that the C
code won't have anything useful to do with it either.)

Change-Id: I74f96acd36747d4b6a6f533535e36ea8e94d2be8
Reviewed-on: https://boringssl-review.googlesource.com/8710
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index a67b242..4ff7012 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -510,8 +510,7 @@
 	}
 
 	var chainToSend *Certificate
-	var certRequested bool
-	var certRequestContext []byte
+	var certReq *certificateRequestMsg
 	if hs.suite.flags&suitePSK != 0 {
 		if encryptedExtensions.extensions.ocspResponse != nil {
 			c.sendAlert(alertUnsupportedExtension)
@@ -530,11 +529,10 @@
 			return err
 		}
 
-		certReq, ok := msg.(*certificateRequestMsg)
+		var ok bool
+		certReq, ok = msg.(*certificateRequestMsg)
 		if ok {
 			hs.writeServerHash(certReq.marshal())
-			certRequested = true
-			certRequestContext = certReq.requestContext
 
 			chainToSend, err = selectClientCertificate(c, certReq)
 			if err != nil {
@@ -602,10 +600,42 @@
 	masterSecret := hs.finishedHash.extractKey(handshakeSecret, zeroSecret)
 	trafficSecret := hs.finishedHash.deriveSecret(masterSecret, applicationTrafficLabel)
 
-	if certRequested {
-		_ = chainToSend
-		_ = certRequestContext
-		return errors.New("tls: client auth not implemented.")
+	if certReq != nil {
+		certMsg := &certificateMsg{
+			hasRequestContext: true,
+			requestContext:    certReq.requestContext,
+		}
+		if chainToSend != nil {
+			certMsg.certificates = chainToSend.Certificate
+		}
+		hs.writeClientHash(certMsg.marshal())
+		c.writeRecord(recordTypeHandshake, certMsg.marshal())
+
+		if chainToSend != nil {
+			certVerify := &certificateVerifyMsg{
+				hasSignatureAlgorithm: true,
+			}
+
+			// Determine the hash to sign.
+			privKey := chainToSend.PrivateKey
+
+			var err error
+			certVerify.signatureAlgorithm, err = selectSignatureAlgorithm(c.vers, privKey, c.config, certReq.signatureAlgorithms)
+			if err != nil {
+				c.sendAlert(alertInternalError)
+				return err
+			}
+
+			input := hs.finishedHash.certificateVerifyInput(clientCertificateVerifyContextTLS13)
+			certVerify.signature, err = signMessage(c.vers, privKey, c.config, certVerify.signatureAlgorithm, input)
+			if err != nil {
+				c.sendAlert(alertInternalError)
+				return err
+			}
+
+			hs.writeClientHash(certVerify.marshal())
+			c.writeRecord(recordTypeHandshake, certVerify.marshal())
+		}
 	}
 
 	// Send a client Finished message.
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
index baa07bd..0df3be3 100644
--- a/ssl/test/runner/handshake_messages.go
+++ b/ssl/test/runner/handshake_messages.go
@@ -1461,6 +1461,11 @@
 		caEntry.addBytes(ca)
 	}
 
+	if m.hasRequestContext {
+		// Emit no certificate extensions.
+		body.addU16(0)
+	}
+
 	m.raw = builder.finish()
 	return m.raw
 }
@@ -1538,6 +1543,19 @@
 		m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen])
 		cas = cas[caLen:]
 	}
+
+	if m.hasRequestContext {
+		// Ignore certificate extensions.
+		if len(data) < 2 {
+			return false
+		}
+		extsLength := int(data[0])<<8 | int(data[1])
+		if len(data) < 2+extsLength {
+			return false
+		}
+		data = data[2+extsLength:]
+	}
+
 	if len(data) > 0 {
 		return false
 	}
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index db0b358..06823ed 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -406,8 +406,25 @@
 
 	if hs.suite.flags&suitePSK == 0 {
 		if config.ClientAuth >= RequestClientCert {
-			// TODO(davidben): Implement client auth.
-			return errors.New("tls: client auth not implemented")
+			// Request a client certificate
+			certReq := &certificateRequestMsg{
+				hasSignatureAlgorithm: true,
+				hasRequestContext:     true,
+			}
+			if !config.Bugs.NoSignatureAlgorithms {
+				certReq.signatureAlgorithms = config.signSignatureAlgorithms()
+			}
+
+			// An empty list of certificateAuthorities signals to
+			// the client that it may send any certificate in response
+			// to our request. When we know the CAs we trust, then
+			// we can send them down, so that the client can choose
+			// an appropriate certificate to give to us.
+			if config.ClientCAs != nil {
+				certReq.certificateAuthorities = config.ClientCAs.Subjects()
+			}
+			hs.writeServerHash(certReq.marshal())
+			c.writeRecord(recordTypeHandshake, certReq.marshal())
 		}
 
 		certMsg := &certificateMsg{
@@ -461,7 +478,51 @@
 	// If we requested a client certificate, then the client must send a
 	// certificate message, even if it's empty.
 	if config.ClientAuth >= RequestClientCert {
-		return errors.New("tls: client certificates not implemented")
+		msg, err := c.readHandshake()
+		if err != nil {
+			return err
+		}
+
+		certMsg, ok := msg.(*certificateMsg)
+		if !ok {
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(certMsg, msg)
+		}
+		hs.writeClientHash(certMsg.marshal())
+
+		if len(certMsg.certificates) == 0 {
+			// The client didn't actually send a certificate
+			switch config.ClientAuth {
+			case RequireAnyClientCert, RequireAndVerifyClientCert:
+				c.sendAlert(alertBadCertificate)
+				return errors.New("tls: client didn't provide a certificate")
+			}
+		}
+
+		pub, err := hs.processCertsFromClient(certMsg.certificates)
+		if err != nil {
+			return err
+		}
+
+		if len(c.peerCertificates) > 0 {
+			msg, err = c.readHandshake()
+			if err != nil {
+				return err
+			}
+
+			certVerify, ok := msg.(*certificateVerifyMsg)
+			if !ok {
+				c.sendAlert(alertUnexpectedMessage)
+				return unexpectedMessageError(certVerify, msg)
+			}
+
+			input := hs.finishedHash.certificateVerifyInput(clientCertificateVerifyContextTLS13)
+			if err := verifyMessage(c.vers, pub, config, certVerify.signatureAlgorithm, input, certVerify.signature); err != nil {
+				c.sendAlert(alertBadCertificate)
+				return err
+			}
+			hs.writeClientHash(certVerify.marshal())
+		}
 	}
 
 	// Read the client Finished message.