From dcd6e447eba4f32f49c22c6196ed0e714cc522c1 Mon Sep 17 00:00:00 2001 From: Watson Ladd Date: Mon, 10 Aug 2020 15:12:45 -0400 Subject: [PATCH] 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 Commit-Queue: David Benjamin --- include/openssl/ssl.h | 12 ++++++++++++ include/openssl/tls1.h | 5 ++--- ssl/internal.h | 4 ++++ ssl/ssl_cert.cc | 9 +++------ ssl/ssl_lib.cc | 10 ++++++++++ ssl/t1_lib.cc | 18 ++++++++++-------- ssl/test/runner/common.go | 2 +- ssl/test/runner/handshake_messages.go | 6 +++++- ssl/test/runner/runner.go | 3 ++- 9 files changed, 49 insertions(+), 20 deletions(-) diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 07a39d28c..96ba53b61 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -953,6 +953,18 @@ OPENSSL_EXPORT size_t SSL_get0_certificate_types(const SSL *ssl, 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 64ed76221..13545dd25 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -232,9 +232,8 @@ extern "C" { // 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 2000409bf..e08505fc7 100644 --- a/ssl/internal.h +++ b/ssl/internal.h @@ -1650,6 +1650,10 @@ struct SSL_HANDSHAKE { // advertise this extension to the client. Array peer_supported_group_list; + // peer_delegated_credential_sigalgs are the signature algorithms the peer + // supports with delegated credentials. + Array peer_delegated_credential_sigalgs; + // peer_key is the peer's ECDH key for a TLS 1.2 client. Array peer_key; diff --git a/ssl/ssl_cert.cc b/ssl/ssl_cert.cc index 6bac3a970..c64303ab9 100644 --- a/ssl/ssl_cert.cc +++ b/ssl/ssl_cert.cc @@ -821,16 +821,13 @@ static bool ssl_can_serve_dc(const SSL_HANDSHAKE *hs) { } // Check that the DC signature algorithm is supported by the peer. - Span peer_sigalgs = tls1_get_peer_verify_algorithms(hs); - bool sigalg_found = false; + Span 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 90c265e71..10a97ea94 100644 --- a/ssl/ssl_lib.cc +++ b/ssl/ssl_lib.cc @@ -2360,6 +2360,16 @@ size_t SSL_get0_peer_verify_algorithms(const SSL *ssl, return sigalgs.size(); } +size_t SSL_get0_peer_delegation_algorithms(const SSL *ssl, + const uint16_t **out_sigalgs){ + Span 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 f274b11db..4a2bbcf86 100644 --- a/ssl/t1_lib.cc +++ b/ssl/t1_lib.cc @@ -2673,20 +2673,22 @@ static bool ext_delegated_credential_add_clienthello(SSL_HANDSHAKE *hs, 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 3a104d97f..6a744db85 100644 --- a/ssl/test/runner/common.go +++ b/ssl/test/runner/common.go @@ -124,7 +124,7 @@ const ( 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 a1ce42175..9d3b6bcbd 100644 --- a/ssl/test/runner/handshake_messages.go +++ b/ssl/test/runner/handshake_messages.go @@ -596,7 +596,11 @@ func (m *clientHelloMsg) marshal() []byte { } 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 5527f96e5..aac4567d7 100644 --- a/ssl/test/runner/runner.go +++ b/ssl/test/runner/runner.go @@ -9499,7 +9499,8 @@ func addSignatureAlgorithmTests() { signatureRSAPKCS1WithSHA1, }, Bugs: ProtocolBugs{ - NoSignatureAlgorithms: true, + NoSignatureAlgorithms: true, + DisableDelegatedCredentials: true, }, }, shouldFail: true,