fix: backport legacy OCSP APIs in boringssl (#628)

One of Electron's tests exposed the fact that boringssl didn't support the OCSP stapling APIs that nodejs was calling. This backports a patch from boringssl that adds the APIs that nodejs expects, and causes the test to pass.
This commit is contained in:
Jeremy Apthorp 2018-08-02 18:11:38 -07:00 коммит произвёл Samuel Attard
Родитель ede7e31980
Коммит 714d2ea890
2 изменённых файлов: 747 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,6 @@
repo: src/third_party/boringssl/src
patches:
-
owners: nornagon
file: 0001-Implement-legacy-OCSP-APIs-for-libssl.patch
description: see patch header

Просмотреть файл

@ -0,0 +1,741 @@
From 81d4909d00c3628453a8712bc331304bd01d8eaf Mon Sep 17 00:00:00 2001
From: David Benjamin <davidben@google.com>
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 <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
---
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