|
@@ -0,0 +1,741 @@
|
|
|
+From 81d4909d00c3628453a8712bc331304bd01d8eaf Mon Sep 17 00:00:00 2001
|
|
|
+From: David Benjamin <[email protected]>
|
|
|
+Date: Thu, 10 May 2018 19:55:02 -0400
|
|
|
+Subject: [PATCH] Implement legacy OCSP APIs for libssl.
|
|
|
+
|
|
|
+Previously, we'd omitted OpenSSL's OCSP APIs because they depend on a
|
|
|
+complex OCSP mechanism and encourage the the unreliable server behavior
|
|
|
+that hampers using OCSP stapling to fix revocation today. (OCSP
|
|
|
+responses should not be fetched on-demand on a callback. They should be
|
|
|
+managed like other server credentials and refreshed eagerly, so
|
|
|
+temporary CA outage does not translate to loss of OCSP.)
|
|
|
+
|
|
|
+But most of the APIs are byte-oriented anyway, so they're easy to
|
|
|
+support. Intentionally omit the one that takes a bunch of OCSP_RESPIDs.
|
|
|
+
|
|
|
+The callback is benign on the client (an artifact of OpenSSL reading
|
|
|
+OCSP and verifying certificates in the wrong order). On the server, it
|
|
|
+encourages unreliability, but pyOpenSSL/cryptography.io depends on this.
|
|
|
+Dcument that this is only for compatibility with legacy software.
|
|
|
+
|
|
|
+Also tweak a few things for compatilibility. cryptography.io expects
|
|
|
+SSL_CTX_set_read_ahead to return something, SSL_get_server_tmp_key's
|
|
|
+signature was wrong, and cryptography.io tries to redefine
|
|
|
+SSL_get_server_tmp_key if SSL_CTRL_GET_SERVER_TMP_KEY is missing.
|
|
|
+
|
|
|
+Change-Id: I2f99711783456bfb7324e9ad972510be8a95e845
|
|
|
+Reviewed-on: https://boringssl-review.googlesource.com/28404
|
|
|
+Commit-Queue: David Benjamin <[email protected]>
|
|
|
+CQ-Verified: CQ bot account: [email protected] <[email protected]>
|
|
|
+Reviewed-by: Adam Langley <[email protected]>
|
|
|
+---
|
|
|
+ crypto/err/ssl.errordata | 1 +
|
|
|
+ include/openssl/ssl.h | 64 +++++++++++++--
|
|
|
+ include/openssl/tls1.h | 1 +
|
|
|
+ ssl/handshake.cc | 16 ++++
|
|
|
+ ssl/handshake_server.cc | 16 ++++
|
|
|
+ ssl/internal.h | 5 ++
|
|
|
+ ssl/ssl_lib.cc | 39 ++++++++-
|
|
|
+ ssl/test/bssl_shim.cc | 26 ++++++
|
|
|
+ ssl/test/runner/alert.go | 122 +++++++++++++--------------
|
|
|
+ ssl/test/runner/runner.go | 205 ++++++++++++++++++++++++++++++++++------------
|
|
|
+ ssl/test/test_config.cc | 4 +
|
|
|
+ ssl/test/test_config.h | 4 +
|
|
|
+ 12 files changed, 381 insertions(+), 122 deletions(-)
|
|
|
+
|
|
|
+diff --git a/crypto/err/ssl.errordata b/crypto/err/ssl.errordata
|
|
|
+index 7b63bc8..375df9a 100644
|
|
|
+--- a/crypto/err/ssl.errordata
|
|
|
++++ b/crypto/err/ssl.errordata
|
|
|
+@@ -108,6 +108,7 @@ SSL,266,NO_SHARED_GROUP
|
|
|
+ SSL,280,NO_SUPPORTED_VERSIONS_ENABLED
|
|
|
+ SSL,185,NULL_SSL_CTX
|
|
|
+ SSL,186,NULL_SSL_METHOD_PASSED
|
|
|
++SSL,289,OCSP_CB_ERROR
|
|
|
+ SSL,187,OLD_SESSION_CIPHER_NOT_RETURNED
|
|
|
+ SSL,268,OLD_SESSION_PRF_HASH_MISMATCH
|
|
|
+ SSL,188,OLD_SESSION_VERSION_NOT_RETURNED
|
|
|
+diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
|
|
|
+index 35506f7..d46a5af 100644
|
|
|
+--- a/include/openssl/ssl.h
|
|
|
++++ b/include/openssl/ssl.h
|
|
|
+@@ -3715,14 +3715,14 @@ OPENSSL_EXPORT int SSL_set_tmp_rsa(SSL *ssl, const RSA *rsa);
|
|
|
+ // SSL_CTX_get_read_ahead returns zero.
|
|
|
+ OPENSSL_EXPORT int SSL_CTX_get_read_ahead(const SSL_CTX *ctx);
|
|
|
+
|
|
|
+-// SSL_CTX_set_read_ahead does nothing.
|
|
|
+-OPENSSL_EXPORT void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes);
|
|
|
++// SSL_CTX_set_read_ahead returns one.
|
|
|
++OPENSSL_EXPORT int SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes);
|
|
|
+
|
|
|
+ // SSL_get_read_ahead returns zero.
|
|
|
+ OPENSSL_EXPORT int SSL_get_read_ahead(const SSL *ssl);
|
|
|
+
|
|
|
+-// SSL_set_read_ahead does nothing.
|
|
|
+-OPENSSL_EXPORT void SSL_set_read_ahead(SSL *ssl, int yes);
|
|
|
++// SSL_set_read_ahead returns one.
|
|
|
++OPENSSL_EXPORT int SSL_set_read_ahead(SSL *ssl, int yes);
|
|
|
+
|
|
|
+ // SSL_renegotiate put an error on the error queue and returns zero.
|
|
|
+ OPENSSL_EXPORT int SSL_renegotiate(SSL *ssl);
|
|
|
+@@ -3793,7 +3793,7 @@ OPENSSL_EXPORT const COMP_METHOD *SSL_get_current_compression(SSL *ssl);
|
|
|
+ OPENSSL_EXPORT const COMP_METHOD *SSL_get_current_expansion(SSL *ssl);
|
|
|
+
|
|
|
+ // SSL_get_server_tmp_key returns zero.
|
|
|
+-OPENSSL_EXPORT int *SSL_get_server_tmp_key(SSL *ssl, EVP_PKEY **out_key);
|
|
|
++OPENSSL_EXPORT int SSL_get_server_tmp_key(SSL *ssl, EVP_PKEY **out_key);
|
|
|
+
|
|
|
+ // SSL_CTX_set_tmp_dh returns 1.
|
|
|
+ OPENSSL_EXPORT int SSL_CTX_set_tmp_dh(SSL_CTX *ctx, const DH *dh);
|
|
|
+@@ -4108,6 +4108,58 @@ extern "C++" OPENSSL_EXPORT void SSL_CTX_sess_set_get_cb(
|
|
|
+ int id_len, int *out_copy));
|
|
|
+ #endif
|
|
|
+
|
|
|
++// SSL_set_tlsext_status_type configures a client to request OCSP stapling if
|
|
|
++// |type| is |TLSEXT_STATUSTYPE_ocsp| and disables it otherwise. It returns one
|
|
|
++// on success and zero if handshake configuration has already been shed.
|
|
|
++//
|
|
|
++// Use |SSL_enable_ocsp_stapling| instead.
|
|
|
++OPENSSL_EXPORT int SSL_set_tlsext_status_type(SSL *ssl, int type);
|
|
|
++
|
|
|
++// SSL_set_tlsext_status_ocsp_resp sets the OCSP response. It returns one on
|
|
|
++// success and zero on error. On success, |ssl| takes ownership of |resp|, which
|
|
|
++// must have been allocated by |OPENSSL_malloc|.
|
|
|
++//
|
|
|
++// Use |SSL_set_ocsp_response| instead.
|
|
|
++OPENSSL_EXPORT int SSL_set_tlsext_status_ocsp_resp(SSL *ssl, uint8_t *resp,
|
|
|
++ size_t resp_len);
|
|
|
++
|
|
|
++// SSL_get_tlsext_status_ocsp_resp sets |*out| to point to the OCSP response
|
|
|
++// from the server. It returns the length of the response. If there was no
|
|
|
++// response, it sets |*out| to NULL and returns zero.
|
|
|
++//
|
|
|
++// Use |SSL_get0_ocsp_response| instead.
|
|
|
++//
|
|
|
++// WARNING: the returned data is not guaranteed to be well formed.
|
|
|
++OPENSSL_EXPORT size_t SSL_get_tlsext_status_ocsp_resp(const SSL *ssl,
|
|
|
++ const uint8_t **out);
|
|
|
++
|
|
|
++// SSL_CTX_set_tlsext_status_cb configures the legacy OpenSSL OCSP callback and
|
|
|
++// returns one. Though the type signature is the same, this callback has
|
|
|
++// different behavior for client and server connections:
|
|
|
++//
|
|
|
++// For clients, the callback is called after certificate verification. It should
|
|
|
++// return one for success, zero for a bad OCSP response, and a negative number
|
|
|
++// for internal error. Instead, handle this as part of certificate verification.
|
|
|
++// (Historically, OpenSSL verified certificates just before parsing stapled OCSP
|
|
|
++// responses, but BoringSSL fixes this ordering. All server credentials are
|
|
|
++// available during verification.)
|
|
|
++//
|
|
|
++// Do not use this callback as a server. It is provided for compatibility
|
|
|
++// purposes only. For servers, it is called to configure server credentials. It
|
|
|
++// should return |SSL_TLSEXT_ERR_OK| on success, |SSL_TLSEXT_ERR_NOACK| to
|
|
|
++// ignore OCSP requests, or |SSL_TLSEXT_ERR_ALERT_FATAL| on error. It is usually
|
|
|
++// used to fetch OCSP responses on demand, which is not ideal. Instead, treat
|
|
|
++// OCSP responses like other server credentials, such as certificates or SCT
|
|
|
++// lists. Configure, store, and refresh them eagerly. This avoids downtime if
|
|
|
++// the CA's OCSP responder is briefly offline.
|
|
|
++OPENSSL_EXPORT int SSL_CTX_set_tlsext_status_cb(SSL_CTX *ctx,
|
|
|
++ int (*callback)(SSL *ssl,
|
|
|
++ void *arg));
|
|
|
++
|
|
|
++// SSL_CTX_set_tlsext_status_arg sets additional data for
|
|
|
++// |SSL_CTX_set_tlsext_status_cb|'s callback and returns one.
|
|
|
++OPENSSL_EXPORT int SSL_CTX_set_tlsext_status_arg(SSL_CTX *ctx, void *arg);
|
|
|
++
|
|
|
+
|
|
|
+ // Private structures.
|
|
|
+ //
|
|
|
+@@ -4285,6 +4337,7 @@ struct ssl_session_st {
|
|
|
+ #define SSL_CTRL_GET_NUM_RENEGOTIATIONS doesnt_exist
|
|
|
+ #define SSL_CTRL_GET_READ_AHEAD doesnt_exist
|
|
|
+ #define SSL_CTRL_GET_RI_SUPPORT doesnt_exist
|
|
|
++#define SSL_CTRL_GET_SERVER_TMP_KEY doesnt_exist
|
|
|
+ #define SSL_CTRL_GET_SESSION_REUSED doesnt_exist
|
|
|
+ #define SSL_CTRL_GET_SESS_CACHE_MODE doesnt_exist
|
|
|
+ #define SSL_CTRL_GET_SESS_CACHE_SIZE doesnt_exist
|
|
|
+@@ -4698,6 +4751,7 @@ OPENSSL_EXPORT bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback);
|
|
|
+ #define SSL_R_NEGOTIATED_TB_WITHOUT_EMS_OR_RI 285
|
|
|
+ #define SSL_R_SERVER_ECHOED_INVALID_SESSION_ID 286
|
|
|
+ #define SSL_R_PRIVATE_KEY_OPERATION_FAILED 287
|
|
|
++#define SSL_R_OCSP_CB_ERROR 289
|
|
|
+ #define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000
|
|
|
+ #define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
|
|
|
+ #define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
|
|
|
+diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
|
|
|
+index 3424f3d..7a05969 100644
|
|
|
+--- a/include/openssl/tls1.h
|
|
|
++++ b/include/openssl/tls1.h
|
|
|
+@@ -237,6 +237,7 @@ extern "C" {
|
|
|
+ #define TLSEXT_TYPE_dummy_pq_padding 54537
|
|
|
+
|
|
|
+ // status request value from RFC 3546
|
|
|
++#define TLSEXT_STATUSTYPE_nothing (-1)
|
|
|
+ #define TLSEXT_STATUSTYPE_ocsp 1
|
|
|
+
|
|
|
+ // ECPointFormat values from RFC 4492
|
|
|
+diff --git a/ssl/handshake.cc b/ssl/handshake.cc
|
|
|
+index 6432424..0a90b9f 100644
|
|
|
+--- a/ssl/handshake.cc
|
|
|
++++ b/ssl/handshake.cc
|
|
|
+@@ -356,6 +356,22 @@ enum ssl_verify_result_t ssl_verify_peer_cert(SSL_HANDSHAKE *hs) {
|
|
|
+ ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
|
|
|
+ }
|
|
|
+
|
|
|
++ // Emulate OpenSSL's client OCSP callback. OpenSSL verifies certificates
|
|
|
++ // before it receives the OCSP, so it needs a second callback for OCSP.
|
|
|
++ if (ret == ssl_verify_ok && !ssl->server &&
|
|
|
++ hs->new_session->ocsp_response != nullptr &&
|
|
|
++ ssl->ctx->legacy_ocsp_callback != nullptr) {
|
|
|
++ int cb_ret =
|
|
|
++ ssl->ctx->legacy_ocsp_callback(ssl, ssl->ctx->legacy_ocsp_callback_arg);
|
|
|
++ if (cb_ret <= 0) {
|
|
|
++ OPENSSL_PUT_ERROR(SSL, SSL_R_OCSP_CB_ERROR);
|
|
|
++ ssl_send_alert(ssl, SSL3_AL_FATAL,
|
|
|
++ cb_ret == 0 ? SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE
|
|
|
++ : SSL_AD_INTERNAL_ERROR);
|
|
|
++ ret = ssl_verify_invalid;
|
|
|
++ }
|
|
|
++ }
|
|
|
++
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+diff --git a/ssl/handshake_server.cc b/ssl/handshake_server.cc
|
|
|
+index fa8a241..7a96767 100644
|
|
|
+--- a/ssl/handshake_server.cc
|
|
|
++++ b/ssl/handshake_server.cc
|
|
|
+@@ -534,6 +534,22 @@ static enum ssl_hs_wait_t do_select_certificate(SSL_HANDSHAKE *hs) {
|
|
|
+ return ssl_hs_error;
|
|
|
+ }
|
|
|
+
|
|
|
++ if (hs->ocsp_stapling_requested &&
|
|
|
++ ssl->ctx->legacy_ocsp_callback != nullptr) {
|
|
|
++ switch (ssl->ctx->legacy_ocsp_callback(
|
|
|
++ ssl, ssl->ctx->legacy_ocsp_callback_arg)) {
|
|
|
++ case SSL_TLSEXT_ERR_OK:
|
|
|
++ break;
|
|
|
++ case SSL_TLSEXT_ERR_NOACK:
|
|
|
++ hs->ocsp_stapling_requested = false;
|
|
|
++ break;
|
|
|
++ default:
|
|
|
++ OPENSSL_PUT_ERROR(SSL, SSL_R_OCSP_CB_ERROR);
|
|
|
++ ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
|
|
|
++ return ssl_hs_error;
|
|
|
++ }
|
|
|
++ }
|
|
|
++
|
|
|
+ if (ssl_protocol_version(ssl) >= TLS1_3_VERSION) {
|
|
|
+ // Jump to the TLS 1.3 state machine.
|
|
|
+ hs->state = state_tls13;
|
|
|
+diff --git a/ssl/internal.h b/ssl/internal.h
|
|
|
+index d13d5f2..1cdfb8e 100644
|
|
|
+--- a/ssl/internal.h
|
|
|
++++ b/ssl/internal.h
|
|
|
+@@ -2140,6 +2140,11 @@ struct SSLContext {
|
|
|
+ // session tickets.
|
|
|
+ const SSL_TICKET_AEAD_METHOD *ticket_aead_method;
|
|
|
+
|
|
|
++ // legacy_ocsp_callback implements an OCSP-related callback for OpenSSL
|
|
|
++ // compatibility.
|
|
|
++ int (*legacy_ocsp_callback)(SSL *ssl, void *arg);
|
|
|
++ void *legacy_ocsp_callback_arg;
|
|
|
++
|
|
|
+ // verify_sigalgs, if not empty, is the set of signature algorithms
|
|
|
+ // accepted from the peer in decreasing order of preference.
|
|
|
+ uint16_t *verify_sigalgs;
|
|
|
+diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
|
|
|
+index 9f56d54..50608e9 100644
|
|
|
+--- a/ssl/ssl_lib.cc
|
|
|
++++ b/ssl/ssl_lib.cc
|
|
|
+@@ -1591,9 +1591,9 @@ int SSL_CTX_get_read_ahead(const SSL_CTX *ctx) { return 0; }
|
|
|
+
|
|
|
+ int SSL_get_read_ahead(const SSL *ssl) { return 0; }
|
|
|
+
|
|
|
+-void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes) { }
|
|
|
++int SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes) { return 1; }
|
|
|
+
|
|
|
+-void SSL_set_read_ahead(SSL *ssl, int yes) { }
|
|
|
++int SSL_set_read_ahead(SSL *ssl, int yes) { return 1; }
|
|
|
+
|
|
|
+ int SSL_pending(const SSL *ssl) {
|
|
|
+ return static_cast<int>(ssl->s3->pending_app_data.size());
|
|
|
+@@ -2205,7 +2205,7 @@ const COMP_METHOD *SSL_get_current_compression(SSL *ssl) { return NULL; }
|
|
|
+
|
|
|
+ const COMP_METHOD *SSL_get_current_expansion(SSL *ssl) { return NULL; }
|
|
|
+
|
|
|
+-int *SSL_get_server_tmp_key(SSL *ssl, EVP_PKEY **out_key) { return 0; }
|
|
|
++int SSL_get_server_tmp_key(SSL *ssl, EVP_PKEY **out_key) { return 0; }
|
|
|
+
|
|
|
+ void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx, int mode) {
|
|
|
+ ctx->quiet_shutdown = (mode != 0);
|
|
|
+@@ -2717,3 +2717,33 @@ void SSL_CTX_set_ticket_aead_method(SSL_CTX *ctx,
|
|
|
+ const SSL_TICKET_AEAD_METHOD *aead_method) {
|
|
|
+ ctx->ticket_aead_method = aead_method;
|
|
|
+ }
|
|
|
++
|
|
|
++int SSL_set_tlsext_status_type(SSL *ssl, int type) {
|
|
|
++ ssl->ocsp_stapling_enabled = type == TLSEXT_STATUSTYPE_ocsp;
|
|
|
++ return 1;
|
|
|
++}
|
|
|
++
|
|
|
++int SSL_set_tlsext_status_ocsp_resp(SSL *ssl, uint8_t *resp, size_t resp_len) {
|
|
|
++ if (SSL_set_ocsp_response(ssl, resp, resp_len)) {
|
|
|
++ OPENSSL_free(resp);
|
|
|
++ return 1;
|
|
|
++ }
|
|
|
++ return 0;
|
|
|
++}
|
|
|
++
|
|
|
++size_t SSL_get_tlsext_status_ocsp_resp(const SSL *ssl, const uint8_t **out) {
|
|
|
++ size_t ret;
|
|
|
++ SSL_get0_ocsp_response(ssl, out, &ret);
|
|
|
++ return ret;
|
|
|
++}
|
|
|
++
|
|
|
++int SSL_CTX_set_tlsext_status_cb(SSL_CTX *ctx,
|
|
|
++ int (*callback)(SSL *ssl, void *arg)) {
|
|
|
++ ctx->legacy_ocsp_callback = callback;
|
|
|
++ return 1;
|
|
|
++}
|
|
|
++
|
|
|
++int SSL_CTX_set_tlsext_status_arg(SSL_CTX *ctx, void *arg) {
|
|
|
++ ctx->legacy_ocsp_callback_arg = arg;
|
|
|
++ return 1;
|
|
|
++}
|
|
|
+diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
|
|
|
+index ae26ded..3a33d60 100644
|
|
|
+--- a/ssl/test/bssl_shim.cc
|
|
|
++++ b/ssl/test/bssl_shim.cc
|
|
|
+@@ -495,6 +495,7 @@ static bool GetCertificate(SSL *ssl, bssl::UniquePtr<X509> *out_x509,
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (!config->ocsp_response.empty() &&
|
|
|
++ !config->set_ocsp_in_callback &&
|
|
|
+ !SSL_set_ocsp_response(ssl, (const uint8_t *)config->ocsp_response.data(),
|
|
|
+ config->ocsp_response.size())) {
|
|
|
+ return false;
|
|
|
+@@ -1100,6 +1101,27 @@ static void MessageCallback(int is_write, int version, int content_type,
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
++static int LegacyOCSPCallback(SSL *ssl, void *arg) {
|
|
|
++ const TestConfig *config = GetTestConfig(ssl);
|
|
|
++ if (!SSL_is_server(ssl)) {
|
|
|
++ return !config->fail_ocsp_callback;
|
|
|
++ }
|
|
|
++
|
|
|
++ if (!config->ocsp_response.empty() &&
|
|
|
++ config->set_ocsp_in_callback &&
|
|
|
++ !SSL_set_ocsp_response(ssl, (const uint8_t *)config->ocsp_response.data(),
|
|
|
++ config->ocsp_response.size())) {
|
|
|
++ return SSL_TLSEXT_ERR_ALERT_FATAL;
|
|
|
++ }
|
|
|
++ if (config->fail_ocsp_callback) {
|
|
|
++ return SSL_TLSEXT_ERR_ALERT_FATAL;
|
|
|
++ }
|
|
|
++ if (config->decline_ocsp_callback) {
|
|
|
++ return SSL_TLSEXT_ERR_NOACK;
|
|
|
++ }
|
|
|
++ return SSL_TLSEXT_ERR_OK;
|
|
|
++}
|
|
|
++
|
|
|
+ // Connect returns a new socket connected to localhost on |port| or -1 on
|
|
|
+ // error.
|
|
|
+ static int Connect(uint16_t port) {
|
|
|
+@@ -1334,6 +1356,10 @@ static bssl::UniquePtr<SSL_CTX> SetupCtx(SSL_CTX *old_ctx,
|
|
|
+ SSL_CTX_set_false_start_allowed_without_alpn(ssl_ctx.get(), 1);
|
|
|
+ }
|
|
|
+
|
|
|
++ if (config->use_ocsp_callback) {
|
|
|
++ SSL_CTX_set_tlsext_status_cb(ssl_ctx.get(), LegacyOCSPCallback);
|
|
|
++ }
|
|
|
++
|
|
|
+ if (old_ctx) {
|
|
|
+ uint8_t keys[48];
|
|
|
+ if (!SSL_CTX_get_tlsext_ticket_keys(old_ctx, &keys, sizeof(keys)) ||
|
|
|
+diff --git a/ssl/test/runner/alert.go b/ssl/test/runner/alert.go
|
|
|
+index 652e9ee..c79725e 100644
|
|
|
+--- a/ssl/test/runner/alert.go
|
|
|
++++ b/ssl/test/runner/alert.go
|
|
|
+@@ -15,69 +15,71 @@ const (
|
|
|
+ )
|
|
|
+
|
|
|
+ const (
|
|
|
+- alertCloseNotify alert = 0
|
|
|
+- alertEndOfEarlyData alert = 1
|
|
|
+- alertUnexpectedMessage alert = 10
|
|
|
+- alertBadRecordMAC alert = 20
|
|
|
+- alertDecryptionFailed alert = 21
|
|
|
+- alertRecordOverflow alert = 22
|
|
|
+- alertDecompressionFailure alert = 30
|
|
|
+- alertHandshakeFailure alert = 40
|
|
|
+- alertNoCertificate alert = 41
|
|
|
+- alertBadCertificate alert = 42
|
|
|
+- alertUnsupportedCertificate alert = 43
|
|
|
+- alertCertificateRevoked alert = 44
|
|
|
+- alertCertificateExpired alert = 45
|
|
|
+- alertCertificateUnknown alert = 46
|
|
|
+- alertIllegalParameter alert = 47
|
|
|
+- alertUnknownCA alert = 48
|
|
|
+- alertAccessDenied alert = 49
|
|
|
+- alertDecodeError alert = 50
|
|
|
+- alertDecryptError alert = 51
|
|
|
+- alertProtocolVersion alert = 70
|
|
|
+- alertInsufficientSecurity alert = 71
|
|
|
+- alertInternalError alert = 80
|
|
|
+- alertInappropriateFallback alert = 86
|
|
|
+- alertUserCanceled alert = 90
|
|
|
+- alertNoRenegotiation alert = 100
|
|
|
+- alertMissingExtension alert = 109
|
|
|
+- alertUnsupportedExtension alert = 110
|
|
|
+- alertUnrecognizedName alert = 112
|
|
|
+- alertUnknownPSKIdentity alert = 115
|
|
|
+- alertCertificateRequired alert = 116
|
|
|
++ alertCloseNotify alert = 0
|
|
|
++ alertEndOfEarlyData alert = 1
|
|
|
++ alertUnexpectedMessage alert = 10
|
|
|
++ alertBadRecordMAC alert = 20
|
|
|
++ alertDecryptionFailed alert = 21
|
|
|
++ alertRecordOverflow alert = 22
|
|
|
++ alertDecompressionFailure alert = 30
|
|
|
++ alertHandshakeFailure alert = 40
|
|
|
++ alertNoCertificate alert = 41
|
|
|
++ alertBadCertificate alert = 42
|
|
|
++ alertUnsupportedCertificate alert = 43
|
|
|
++ alertCertificateRevoked alert = 44
|
|
|
++ alertCertificateExpired alert = 45
|
|
|
++ alertCertificateUnknown alert = 46
|
|
|
++ alertIllegalParameter alert = 47
|
|
|
++ alertUnknownCA alert = 48
|
|
|
++ alertAccessDenied alert = 49
|
|
|
++ alertDecodeError alert = 50
|
|
|
++ alertDecryptError alert = 51
|
|
|
++ alertProtocolVersion alert = 70
|
|
|
++ alertInsufficientSecurity alert = 71
|
|
|
++ alertInternalError alert = 80
|
|
|
++ alertInappropriateFallback alert = 86
|
|
|
++ alertUserCanceled alert = 90
|
|
|
++ alertNoRenegotiation alert = 100
|
|
|
++ alertMissingExtension alert = 109
|
|
|
++ alertUnsupportedExtension alert = 110
|
|
|
++ alertUnrecognizedName alert = 112
|
|
|
++ alertBadCertificateStatusResponse alert = 113
|
|
|
++ alertUnknownPSKIdentity alert = 115
|
|
|
++ alertCertificateRequired alert = 116
|
|
|
+ )
|
|
|
+
|
|
|
+ var alertText = map[alert]string{
|
|
|
+- alertCloseNotify: "close notify",
|
|
|
+- alertEndOfEarlyData: "end of early data",
|
|
|
+- alertUnexpectedMessage: "unexpected message",
|
|
|
+- alertBadRecordMAC: "bad record MAC",
|
|
|
+- alertDecryptionFailed: "decryption failed",
|
|
|
+- alertRecordOverflow: "record overflow",
|
|
|
+- alertDecompressionFailure: "decompression failure",
|
|
|
+- alertHandshakeFailure: "handshake failure",
|
|
|
+- alertNoCertificate: "no certificate",
|
|
|
+- alertBadCertificate: "bad certificate",
|
|
|
+- alertUnsupportedCertificate: "unsupported certificate",
|
|
|
+- alertCertificateRevoked: "revoked certificate",
|
|
|
+- alertCertificateExpired: "expired certificate",
|
|
|
+- alertCertificateUnknown: "unknown certificate",
|
|
|
+- alertIllegalParameter: "illegal parameter",
|
|
|
+- alertUnknownCA: "unknown certificate authority",
|
|
|
+- alertAccessDenied: "access denied",
|
|
|
+- alertDecodeError: "error decoding message",
|
|
|
+- alertDecryptError: "error decrypting message",
|
|
|
+- alertProtocolVersion: "protocol version not supported",
|
|
|
+- alertInsufficientSecurity: "insufficient security level",
|
|
|
+- alertInternalError: "internal error",
|
|
|
+- alertInappropriateFallback: "inappropriate fallback",
|
|
|
+- alertUserCanceled: "user canceled",
|
|
|
+- alertNoRenegotiation: "no renegotiation",
|
|
|
+- alertMissingExtension: "missing extension",
|
|
|
+- alertUnsupportedExtension: "unsupported extension",
|
|
|
+- alertUnrecognizedName: "unrecognized name",
|
|
|
+- alertUnknownPSKIdentity: "unknown PSK identity",
|
|
|
+- alertCertificateRequired: "certificate required",
|
|
|
++ alertCloseNotify: "close notify",
|
|
|
++ alertEndOfEarlyData: "end of early data",
|
|
|
++ alertUnexpectedMessage: "unexpected message",
|
|
|
++ alertBadRecordMAC: "bad record MAC",
|
|
|
++ alertDecryptionFailed: "decryption failed",
|
|
|
++ alertRecordOverflow: "record overflow",
|
|
|
++ alertDecompressionFailure: "decompression failure",
|
|
|
++ alertHandshakeFailure: "handshake failure",
|
|
|
++ alertNoCertificate: "no certificate",
|
|
|
++ alertBadCertificate: "bad certificate",
|
|
|
++ alertUnsupportedCertificate: "unsupported certificate",
|
|
|
++ alertCertificateRevoked: "revoked certificate",
|
|
|
++ alertCertificateExpired: "expired certificate",
|
|
|
++ alertCertificateUnknown: "unknown certificate",
|
|
|
++ alertIllegalParameter: "illegal parameter",
|
|
|
++ alertUnknownCA: "unknown certificate authority",
|
|
|
++ alertAccessDenied: "access denied",
|
|
|
++ alertDecodeError: "error decoding message",
|
|
|
++ alertDecryptError: "error decrypting message",
|
|
|
++ alertProtocolVersion: "protocol version not supported",
|
|
|
++ alertInsufficientSecurity: "insufficient security level",
|
|
|
++ alertInternalError: "internal error",
|
|
|
++ alertInappropriateFallback: "inappropriate fallback",
|
|
|
++ alertUserCanceled: "user canceled",
|
|
|
++ alertNoRenegotiation: "no renegotiation",
|
|
|
++ alertMissingExtension: "missing extension",
|
|
|
++ alertUnsupportedExtension: "unsupported extension",
|
|
|
++ alertBadCertificateStatusResponse: "bad certificate status response",
|
|
|
++ alertUnrecognizedName: "unrecognized name",
|
|
|
++ alertUnknownPSKIdentity: "unknown PSK identity",
|
|
|
++ alertCertificateRequired: "certificate required",
|
|
|
+ }
|
|
|
+
|
|
|
+ func (e alert) String() string {
|
|
|
+diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
|
|
|
+index 510a48b..1a6d0f9 100644
|
|
|
+--- a/ssl/test/runner/runner.go
|
|
|
++++ b/ssl/test/runner/runner.go
|
|
|
+@@ -4744,60 +4744,157 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
|
|
|
+ })
|
|
|
+
|
|
|
+ // OCSP stapling tests.
|
|
|
+- tests = append(tests, testCase{
|
|
|
+- testType: clientTest,
|
|
|
+- name: "OCSPStapling-Client",
|
|
|
+- config: Config{
|
|
|
+- MaxVersion: VersionTLS12,
|
|
|
+- },
|
|
|
+- flags: []string{
|
|
|
+- "-enable-ocsp-stapling",
|
|
|
+- "-expect-ocsp-response",
|
|
|
+- base64.StdEncoding.EncodeToString(testOCSPResponse),
|
|
|
+- "-verify-peer",
|
|
|
+- },
|
|
|
+- resumeSession: true,
|
|
|
+- })
|
|
|
+- tests = append(tests, testCase{
|
|
|
+- testType: serverTest,
|
|
|
+- name: "OCSPStapling-Server",
|
|
|
+- config: Config{
|
|
|
+- MaxVersion: VersionTLS12,
|
|
|
+- },
|
|
|
+- expectedOCSPResponse: testOCSPResponse,
|
|
|
+- flags: []string{
|
|
|
+- "-ocsp-response",
|
|
|
+- base64.StdEncoding.EncodeToString(testOCSPResponse),
|
|
|
+- },
|
|
|
+- resumeSession: true,
|
|
|
+- })
|
|
|
+- tests = append(tests, testCase{
|
|
|
+- testType: clientTest,
|
|
|
+- name: "OCSPStapling-Client-TLS13",
|
|
|
+- config: Config{
|
|
|
+- MaxVersion: VersionTLS13,
|
|
|
+- },
|
|
|
+- flags: []string{
|
|
|
+- "-enable-ocsp-stapling",
|
|
|
+- "-expect-ocsp-response",
|
|
|
+- base64.StdEncoding.EncodeToString(testOCSPResponse),
|
|
|
+- "-verify-peer",
|
|
|
+- },
|
|
|
+- resumeSession: true,
|
|
|
+- })
|
|
|
+- tests = append(tests, testCase{
|
|
|
+- testType: serverTest,
|
|
|
+- name: "OCSPStapling-Server-TLS13",
|
|
|
+- config: Config{
|
|
|
+- MaxVersion: VersionTLS13,
|
|
|
+- },
|
|
|
+- expectedOCSPResponse: testOCSPResponse,
|
|
|
+- flags: []string{
|
|
|
+- "-ocsp-response",
|
|
|
+- base64.StdEncoding.EncodeToString(testOCSPResponse),
|
|
|
+- },
|
|
|
+- resumeSession: true,
|
|
|
+- })
|
|
|
++ for _, vers := range tlsVersions {
|
|
|
++ if config.protocol == dtls && !vers.hasDTLS {
|
|
|
++ continue
|
|
|
++ }
|
|
|
++ if vers.version == VersionSSL30 {
|
|
|
++ continue
|
|
|
++ }
|
|
|
++ tests = append(tests, testCase{
|
|
|
++ testType: clientTest,
|
|
|
++ name: "OCSPStapling-Client-" + vers.name,
|
|
|
++ config: Config{
|
|
|
++ MaxVersion: vers.version,
|
|
|
++ },
|
|
|
++ tls13Variant: vers.tls13Variant,
|
|
|
++ flags: []string{
|
|
|
++ "-enable-ocsp-stapling",
|
|
|
++ "-expect-ocsp-response",
|
|
|
++ base64.StdEncoding.EncodeToString(testOCSPResponse),
|
|
|
++ "-verify-peer",
|
|
|
++ },
|
|
|
++ resumeSession: true,
|
|
|
++ })
|
|
|
++ tests = append(tests, testCase{
|
|
|
++ testType: serverTest,
|
|
|
++ name: "OCSPStapling-Server-" + vers.name,
|
|
|
++ config: Config{
|
|
|
++ MaxVersion: vers.version,
|
|
|
++ },
|
|
|
++ tls13Variant: vers.tls13Variant,
|
|
|
++ expectedOCSPResponse: testOCSPResponse,
|
|
|
++ flags: []string{
|
|
|
++ "-ocsp-response",
|
|
|
++ base64.StdEncoding.EncodeToString(testOCSPResponse),
|
|
|
++ },
|
|
|
++ resumeSession: true,
|
|
|
++ })
|
|
|
++
|
|
|
++ // The client OCSP callback is an alternate certificate
|
|
|
++ // verification callback.
|
|
|
++ tests = append(tests, testCase{
|
|
|
++ testType: clientTest,
|
|
|
++ name: "ClientOCSPCallback-Pass-" + vers.name,
|
|
|
++ config: Config{
|
|
|
++ MaxVersion: vers.version,
|
|
|
++ Certificates: []Certificate{rsaCertificate},
|
|
|
++ },
|
|
|
++ tls13Variant: vers.tls13Variant,
|
|
|
++ flags: []string{
|
|
|
++ "-enable-ocsp-stapling",
|
|
|
++ "-use-ocsp-callback",
|
|
|
++ },
|
|
|
++ })
|
|
|
++ var expectedLocalError string
|
|
|
++ if !config.async {
|
|
|
++ // TODO(davidben): Asynchronous fatal alerts are never
|
|
|
++ // sent. https://crbug.com/boringssl/130.
|
|
|
++ expectedLocalError = "remote error: bad certificate status response"
|
|
|
++ }
|
|
|
++ tests = append(tests, testCase{
|
|
|
++ testType: clientTest,
|
|
|
++ name: "ClientOCSPCallback-Fail-" + vers.name,
|
|
|
++ config: Config{
|
|
|
++ MaxVersion: vers.version,
|
|
|
++ Certificates: []Certificate{rsaCertificate},
|
|
|
++ },
|
|
|
++ tls13Variant: vers.tls13Variant,
|
|
|
++ flags: []string{
|
|
|
++ "-enable-ocsp-stapling",
|
|
|
++ "-use-ocsp-callback",
|
|
|
++ "-fail-ocsp-callback",
|
|
|
++ },
|
|
|
++ shouldFail: true,
|
|
|
++ expectedLocalError: expectedLocalError,
|
|
|
++ expectedError: ":OCSP_CB_ERROR:",
|
|
|
++ })
|
|
|
++ // The callback does not run if the server does not send an
|
|
|
++ // OCSP response.
|
|
|
++ certNoStaple := rsaCertificate
|
|
|
++ certNoStaple.OCSPStaple = nil
|
|
|
++ tests = append(tests, testCase{
|
|
|
++ testType: clientTest,
|
|
|
++ name: "ClientOCSPCallback-FailNoStaple-" + vers.name,
|
|
|
++ config: Config{
|
|
|
++ MaxVersion: vers.version,
|
|
|
++ Certificates: []Certificate{certNoStaple},
|
|
|
++ },
|
|
|
++ tls13Variant: vers.tls13Variant,
|
|
|
++ flags: []string{
|
|
|
++ "-enable-ocsp-stapling",
|
|
|
++ "-use-ocsp-callback",
|
|
|
++ "-fail-ocsp-callback",
|
|
|
++ },
|
|
|
++ })
|
|
|
++
|
|
|
++ // The server OCSP callback is a legacy mechanism for
|
|
|
++ // configuring OCSP, used by unreliable server software.
|
|
|
++ tests = append(tests, testCase{
|
|
|
++ testType: serverTest,
|
|
|
++ name: "ServerOCSPCallback-SetInCallback-" + vers.name,
|
|
|
++ config: Config{
|
|
|
++ MaxVersion: vers.version,
|
|
|
++ },
|
|
|
++ tls13Variant: vers.tls13Variant,
|
|
|
++ expectedOCSPResponse: testOCSPResponse,
|
|
|
++ flags: []string{
|
|
|
++ "-use-ocsp-callback",
|
|
|
++ "-set-ocsp-in-callback",
|
|
|
++ "-ocsp-response",
|
|
|
++ base64.StdEncoding.EncodeToString(testOCSPResponse),
|
|
|
++ },
|
|
|
++ resumeSession: true,
|
|
|
++ })
|
|
|
++
|
|
|
++ // The callback may decline OCSP, in which case we act as if
|
|
|
++ // the client did not support it, even if a response was
|
|
|
++ // configured.
|
|
|
++ tests = append(tests, testCase{
|
|
|
++ testType: serverTest,
|
|
|
++ name: "ServerOCSPCallback-Decline-" + vers.name,
|
|
|
++ config: Config{
|
|
|
++ MaxVersion: vers.version,
|
|
|
++ },
|
|
|
++ tls13Variant: vers.tls13Variant,
|
|
|
++ expectedOCSPResponse: []byte{},
|
|
|
++ flags: []string{
|
|
|
++ "-use-ocsp-callback",
|
|
|
++ "-decline-ocsp-callback",
|
|
|
++ "-ocsp-response",
|
|
|
++ base64.StdEncoding.EncodeToString(testOCSPResponse),
|
|
|
++ },
|
|
|
++ resumeSession: true,
|
|
|
++ })
|
|
|
++
|
|
|
++ // The callback may also signal an internal error.
|
|
|
++ tests = append(tests, testCase{
|
|
|
++ testType: serverTest,
|
|
|
++ name: "ServerOCSPCallback-Fail-" + vers.name,
|
|
|
++ config: Config{
|
|
|
++ MaxVersion: vers.version,
|
|
|
++ },
|
|
|
++ tls13Variant: vers.tls13Variant,
|
|
|
++ flags: []string{
|
|
|
++ "-use-ocsp-callback",
|
|
|
++ "-fail-ocsp-callback",
|
|
|
++ "-ocsp-response",
|
|
|
++ base64.StdEncoding.EncodeToString(testOCSPResponse),
|
|
|
++ },
|
|
|
++ shouldFail: true,
|
|
|
++ expectedError: ":OCSP_CB_ERROR:",
|
|
|
++ })
|
|
|
++ }
|
|
|
+
|
|
|
+ // Certificate verification tests.
|
|
|
+ for _, vers := range tlsVersions {
|
|
|
+diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
|
|
|
+index f50251d..3afb01b 100644
|
|
|
+--- a/ssl/test/test_config.cc
|
|
|
++++ b/ssl/test/test_config.cc
|
|
|
+@@ -133,6 +133,10 @@ const Flag<bool> kBoolFlags[] = {
|
|
|
+ { "-expect-draft-downgrade", &TestConfig::expect_draft_downgrade },
|
|
|
+ { "-handoff", &TestConfig::handoff },
|
|
|
+ { "-expect-dummy-pq-padding", &TestConfig::expect_dummy_pq_padding },
|
|
|
++ { "-use-ocsp-callback", &TestConfig::use_ocsp_callback },
|
|
|
++ { "-set-ocsp-in-callback", &TestConfig::set_ocsp_in_callback },
|
|
|
++ { "-decline-ocsp-callback", &TestConfig::decline_ocsp_callback },
|
|
|
++ { "-fail-ocsp-callback", &TestConfig::fail_ocsp_callback },
|
|
|
+ };
|
|
|
+
|
|
|
+ const Flag<std::string> kStringFlags[] = {
|
|
|
+diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
|
|
|
+index fb479d1..a9eec62 100644
|
|
|
+--- a/ssl/test/test_config.h
|
|
|
++++ b/ssl/test/test_config.h
|
|
|
+@@ -154,6 +154,10 @@ struct TestConfig {
|
|
|
+ int dummy_pq_padding_len = 0;
|
|
|
+ bool handoff = false;
|
|
|
+ bool expect_dummy_pq_padding = false;
|
|
|
++ bool use_ocsp_callback = false;
|
|
|
++ bool set_ocsp_in_callback = false;
|
|
|
++ bool decline_ocsp_callback = false;
|
|
|
++ bool fail_ocsp_callback = false;
|
|
|
+ };
|
|
|
+
|
|
|
+ bool ParseConfig(int argc, char **argv, TestConfig *out_initial,
|
|
|
+--
|
|
|
+2.7.4
|
|
|
+
|