diff --git a/patches/common/boringssl/.patches.yaml b/patches/common/boringssl/.patches.yaml new file mode 100644 index 00000000..ae596337 --- /dev/null +++ b/patches/common/boringssl/.patches.yaml @@ -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 diff --git a/patches/common/boringssl/0001-Implement-legacy-OCSP-APIs-for-libssl.patch b/patches/common/boringssl/0001-Implement-legacy-OCSP-APIs-for-libssl.patch new file mode 100644 index 00000000..d1c0c0d2 --- /dev/null +++ b/patches/common/boringssl/0001-Implement-legacy-OCSP-APIs-for-libssl.patch @@ -0,0 +1,741 @@ +From 81d4909d00c3628453a8712bc331304bd01d8eaf Mon Sep 17 00:00:00 2001 +From: David Benjamin +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 +CQ-Verified: CQ bot account: commit-bot@chromium.org +Reviewed-by: Adam Langley +--- + 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 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(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 *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 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 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 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 +