Support delegated credentials verison 06

This version adds signature algorithms to the extension

Change-Id: I91dc78d33ee81cb7a6221c7bdeefc8ea460a2d6c
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/42424
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 07a39d2..96ba53b 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -953,6 +953,18 @@
 OPENSSL_EXPORT size_t
 SSL_get0_peer_verify_algorithms(const SSL *ssl, const uint16_t **out_sigalgs);
 
+// SSL_get0_peer_delegation_algorithms sets |*out_sigalgs| to an array
+// containing the signature algorithms the peer is willing to use with delegated
+// credentials.  It returns the length of the array. If not sent, the empty
+// array is returned.
+//
+// The behavior of this function is undefined except during the callbacks set by
+// by |SSL_CTX_set_cert_cb| and |SSL_CTX_set_client_cert_cb| or when the
+// handshake is paused because of them.
+OPENSSL_EXPORT size_t
+SSL_get0_peer_delegation_algorithms(const SSL *ssl,
+                                    const uint16_t **out_sigalgs);
+
 // SSL_certs_clear resets the private key, leaf certificate, and certificate
 // chain of |ssl|.
 OPENSSL_EXPORT void SSL_certs_clear(SSL *ssl);
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index 64ed762..13545dd 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -232,9 +232,8 @@
 // ExtensionType value from RFC5746
 #define TLSEXT_TYPE_renegotiate 0xff01
 
-// ExtensionType value from draft-ietf-tls-subcerts. This is not an IANA defined
-// extension number.
-#define TLSEXT_TYPE_delegated_credential 0xff02
+// ExtensionType value from draft-ietf-tls-subcerts.
+#define TLSEXT_TYPE_delegated_credential 0x22
 
 // ExtensionType value from RFC6962
 #define TLSEXT_TYPE_certificate_timestamp 18
diff --git a/ssl/internal.h b/ssl/internal.h
index 2000409..e08505f 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1650,6 +1650,10 @@
   // advertise this extension to the client.
   Array<uint16_t> peer_supported_group_list;
 
+  // peer_delegated_credential_sigalgs are the signature algorithms the peer
+  // supports with delegated credentials.
+  Array<uint16_t> peer_delegated_credential_sigalgs;
+
   // peer_key is the peer's ECDH key for a TLS 1.2 client.
   Array<uint8_t> peer_key;
 
diff --git a/ssl/ssl_cert.cc b/ssl/ssl_cert.cc
index 6bac3a9..c64303a 100644
--- a/ssl/ssl_cert.cc
+++ b/ssl/ssl_cert.cc
@@ -821,16 +821,13 @@
   }
 
   // Check that the DC signature algorithm is supported by the peer.
-  Span<const uint16_t> peer_sigalgs = tls1_get_peer_verify_algorithms(hs);
-  bool sigalg_found = false;
+  Span<const uint16_t> peer_sigalgs = hs->peer_delegated_credential_sigalgs;
   for (uint16_t peer_sigalg : peer_sigalgs) {
     if (dc->expected_cert_verify_algorithm == peer_sigalg) {
-      sigalg_found = true;
-      break;
+      return true;
     }
   }
-
-  return sigalg_found;
+  return false;
 }
 
 bool ssl_signing_with_dc(const SSL_HANDSHAKE *hs) {
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index 90c265e..10a97ea 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -2360,6 +2360,16 @@
   return sigalgs.size();
 }
 
+size_t SSL_get0_peer_delegation_algorithms(const SSL *ssl,
+                                           const uint16_t **out_sigalgs){
+  Span<const uint16_t> sigalgs;
+  if (ssl->s3->hs != nullptr) {
+    sigalgs = ssl->s3->hs->peer_delegated_credential_sigalgs;
+  }
+  *out_sigalgs = sigalgs.data();
+  return sigalgs.size();
+}
+
 EVP_PKEY *SSL_get_privatekey(const SSL *ssl) {
   if (!ssl->config) {
     assert(ssl->config);
diff --git a/ssl/t1_lib.cc b/ssl/t1_lib.cc
index f274b11..4a2bbcf 100644
--- a/ssl/t1_lib.cc
+++ b/ssl/t1_lib.cc
@@ -2673,20 +2673,22 @@
 static bool ext_delegated_credential_parse_clienthello(SSL_HANDSHAKE *hs,
                                                        uint8_t *out_alert,
                                                        CBS *contents) {
-  assert(TLSEXT_TYPE_delegated_credential == 0xff02);
-  // TODO: Check that the extension is empty.
-  //
-  // As of draft-03, the client sends an empty extension in order indicate
-  // support for delegated credentials. This could change, however, since the
-  // spec is not yet finalized. This assertion is here to remind us to enforce
-  // this check once the extension ID is assigned.
-
   if (contents == nullptr || ssl_protocol_version(hs->ssl) < TLS1_3_VERSION) {
     // Don't use delegated credentials unless we're negotiating TLS 1.3 or
     // higher.
     return true;
   }
 
+  // The contents of the extension are the signature algorithms the client will
+  // accept for a delegated credential.
+  CBS sigalg_list;
+  if (!CBS_get_u16_length_prefixed(contents, &sigalg_list) ||
+      CBS_len(&sigalg_list) == 0 ||
+      CBS_len(contents) != 0 ||
+      !parse_u16_array(&sigalg_list, &hs->peer_delegated_credential_sigalgs)) {
+    return false;
+  }
+
   hs->delegated_credential_requested = true;
   return true;
 }
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 3a104d9..6a744db 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -124,7 +124,7 @@
 	extensionRenegotiationInfo          uint16 = 0xff01
 	extensionQUICTransportParams        uint16 = 0xffa5 // draft-ietf-quic-tls-13
 	extensionChannelID                  uint16 = 30032  // not IANA assigned
-	extensionDelegatedCredentials       uint16 = 0xff02 // not IANA assigned
+	extensionDelegatedCredentials       uint16 = 0x22   // draft-ietf-tls-subcerts-06
 )
 
 // TLS signaling cipher suite values
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
index a1ce421..9d3b6bc 100644
--- a/ssl/test/runner/handshake_messages.go
+++ b/ssl/test/runner/handshake_messages.go
@@ -596,7 +596,11 @@
 	}
 	if m.delegatedCredentials {
 		extensions.addU16(extensionDelegatedCredentials)
-		extensions.addU16(0) // Length is always 0
+		body := extensions.addU16LengthPrefixed()
+		signatureSchemeList := body.addU16LengthPrefixed()
+		for _, sigAlg := range m.signatureAlgorithms {
+			signatureSchemeList.addU16(uint16(sigAlg))
+		}
 	}
 
 	// The PSK extension must be last. See https://tools.ietf.org/html/rfc8446#section-4.2.11
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 5527f96..aac4567 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -9499,7 +9499,8 @@
 				signatureRSAPKCS1WithSHA1,
 			},
 			Bugs: ProtocolBugs{
-				NoSignatureAlgorithms: true,
+				NoSignatureAlgorithms:       true,
+				DisableDelegatedCredentials: true,
 			},
 		},
 		shouldFail:    true,