diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 16aeaff0..328ec1c3 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -517,6 +517,13 @@ OPENSSL_EXPORT int SSL_get_error(const SSL *ssl, int ret_code); * used to reuse the underlying connection for the retry. */ #define SSL_ERROR_EARLY_DATA_REJECTED 15 +/* SSL_ERROR_WANT_CERTIFICATE_VERIFY indicates the operation failed because + * certificate verification was incomplete. The caller may retry the operation + * when certificate verification is complete. + * + * See also |SSL_CTX_set_custom_verify|. */ +#define SSL_ERROR_WANT_CERTIFICATE_VERIFY 16 + /* SSL_set_mtu sets the |ssl|'s MTU in DTLS to |mtu|. It returns one on success * and zero on failure. */ OPENSSL_EXPORT int SSL_set_mtu(SSL *ssl, unsigned mtu); @@ -2201,6 +2208,39 @@ OPENSSL_EXPORT void SSL_set_verify(SSL *ssl, int mode, int (*callback)(int ok, X509_STORE_CTX *store_ctx)); +enum ssl_verify_result_t { + ssl_verify_ok, + ssl_verify_invalid, + ssl_verify_retry, +}; + +/* SSL_CTX_set_custom_verify configures certificate verification. |mode| is one + * of the |SSL_VERIFY_*| values defined above. |callback| performs the + * certificate verification. + * + * The callback may call |SSL_get0_peer_certificates| for the certificate chain + * to validate. The callback should return |ssl_verify_ok| if the certificate is + * valid. If the certificate is invalid, the callback should return + * |ssl_verify_invalid| and optionally set |*out_alert| to an alert to send to + * the peer. Some useful alerts include |SSL_AD_CERTIFICATE_EXPIRED|, + * |SSL_AD_CERTIFICATE_REVOKED|, |SSL_AD_UNKNOWN_CA|, |SSL_AD_BAD_CERTIFICATE|, + * |SSL_AD_CERTIFICATE_UNKNOWN|, and |SSL_AD_INTERNAL_ERROR|. See RFC 5246 + * section 7.2.2 for their precise meanings. If unspecified, + * |SSL_AD_CERTIFICATE_UNKNOWN| will be sent by default. + * + * To verify a certificate asynchronously, the callback may return + * |ssl_verify_retry|. The handshake will then pause with |SSL_get_error| + * returning |SSL_ERROR_WANT_CERTIFICATE_VERIFY|. */ +OPENSSL_EXPORT void SSL_CTX_set_custom_verify( + SSL_CTX *ctx, int mode, + enum ssl_verify_result_t (*callback)(SSL *ssl, uint8_t *out_alert)); + +/* SSL_set_custom_verify behaves like |SSL_CTX_set_custom_verify| but configures + * an individual |SSL|. */ +OPENSSL_EXPORT void SSL_set_custom_verify( + SSL *ssl, int mode, + enum ssl_verify_result_t (*callback)(SSL *ssl, uint8_t *out_alert)); + /* SSL_CTX_get_verify_mode returns |ctx|'s verify mode, set by * |SSL_CTX_set_verify|. */ OPENSSL_EXPORT int SSL_CTX_get_verify_mode(const SSL_CTX *ctx); @@ -2320,13 +2360,6 @@ OPENSSL_EXPORT void SSL_CTX_set_cert_verify_callback( SSL_CTX *ctx, int (*callback)(X509_STORE_CTX *store_ctx, void *arg), void *arg); -/* SSL_CTX_i_promise_to_verify_certs_after_the_handshake indicates that the - * caller understands that the |CRYPTO_BUFFER|-based methods currently require - * post-handshake verification of certificates and thus it's ok to accept any - * certificates during the handshake. */ -OPENSSL_EXPORT void SSL_CTX_i_promise_to_verify_certs_after_the_handshake( - SSL_CTX *ctx); - /* SSL_enable_signed_cert_timestamps causes |ssl| (which must be the client end * of a connection) to request SCTs from the server. See * https://tools.ietf.org/html/rfc6962. @@ -3748,6 +3781,7 @@ OPENSSL_EXPORT void SSL_CTX_set_client_cert_cb( #define SSL_PRIVATE_KEY_OPERATION 9 #define SSL_PENDING_TICKET 10 #define SSL_EARLY_DATA_REJECTED 11 +#define SSL_CERTIFICATE_VERIFY 12 /* SSL_want returns one of the above values to determine what the most recent * operation on |ssl| was blocked on. Use |SSL_get_error| instead. */ @@ -4194,6 +4228,9 @@ struct ssl_ctx_st { int (*app_verify_callback)(X509_STORE_CTX *store_ctx, void *arg); void *app_verify_arg; + enum ssl_verify_result_t (*custom_verify_callback)(SSL *ssl, + uint8_t *out_alert); + /* Default password callback. */ pem_password_cb *default_passwd_callback; @@ -4374,12 +4411,6 @@ struct ssl_ctx_st { * otherwise. */ unsigned grease_enabled:1; - /* i_promise_to_verify_certs_after_the_handshake indicates that the - * application is using the |CRYPTO_BUFFER|-based methods and understands - * that this currently requires post-handshake verification of - * certificates. */ - unsigned i_promise_to_verify_certs_after_the_handshake:1; - /* allow_unknown_alpn_protos is one if the client allows unsolicited ALPN * protocols from the peer. */ unsigned allow_unknown_alpn_protos:1; diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h index 2b241ba8..39cd07b9 100644 --- a/include/openssl/ssl3.h +++ b/include/openssl/ssl3.h @@ -334,6 +334,7 @@ OPENSSL_COMPILE_ASSERT( /* server */ /* extra state */ #define SSL3_ST_SW_FLUSH (0x100 | SSL_ST_ACCEPT) +#define SSL3_ST_VERIFY_CLIENT_CERT (0x101 | SSL_ST_ACCEPT) /* read from client */ #define SSL3_ST_SR_CLNT_HELLO_A (0x110 | SSL_ST_ACCEPT) #define SSL3_ST_SR_CLNT_HELLO_B (0x111 | SSL_ST_ACCEPT) diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc index 9efbf0ad..10c10a25 100644 --- a/ssl/handshake_client.cc +++ b/ssl/handshake_client.cc @@ -173,7 +173,6 @@ static int dtls1_get_hello_verify_request(SSL_HANDSHAKE *hs); static int ssl3_get_server_hello(SSL_HANDSHAKE *hs); static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs); static int ssl3_get_cert_status(SSL_HANDSHAKE *hs); -static int ssl3_verify_server_cert(SSL_HANDSHAKE *hs); static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs); static int ssl3_get_certificate_request(SSL_HANDSHAKE *hs); static int ssl3_get_server_hello_done(SSL_HANDSHAKE *hs); @@ -292,9 +291,16 @@ int ssl3_connect(SSL_HANDSHAKE *hs) { case SSL3_ST_VERIFY_SERVER_CERT: if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) { - ret = ssl3_verify_server_cert(hs); - if (ret <= 0) { - goto end; + switch (ssl_verify_peer_cert(hs)) { + case ssl_verify_ok: + break; + case ssl_verify_invalid: + ret = -1; + goto end; + case ssl_verify_retry: + ssl->rwstate = SSL_CERTIFICATE_VERIFY; + ret = -1; + goto end; } } hs->state = SSL3_ST_CR_KEY_EXCH_A; @@ -1185,15 +1191,6 @@ static int ssl3_get_cert_status(SSL_HANDSHAKE *hs) { return 1; } -static int ssl3_verify_server_cert(SSL_HANDSHAKE *hs) { - SSL *const ssl = hs->ssl; - if (!ssl->ctx->x509_method->session_verify_cert_chain(hs->new_session, ssl)) { - return -1; - } - - return 1; -} - static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; EC_KEY *ecdh = NULL; diff --git a/ssl/handshake_server.cc b/ssl/handshake_server.cc index ee5358c4..00ac5491 100644 --- a/ssl/handshake_server.cc +++ b/ssl/handshake_server.cc @@ -282,6 +282,23 @@ int ssl3_accept(SSL_HANDSHAKE *hs) { goto end; } } + hs->state = SSL3_ST_VERIFY_CLIENT_CERT; + break; + + case SSL3_ST_VERIFY_CLIENT_CERT: + if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) > 0) { + switch (ssl_verify_peer_cert(hs)) { + case ssl_verify_ok: + break; + case ssl_verify_invalid: + ret = -1; + goto end; + case ssl_verify_retry: + ssl->rwstate = SSL_CERTIFICATE_VERIFY; + ret = -1; + goto end; + } + } hs->state = SSL3_ST_SR_KEY_EXCH_A; break; @@ -1264,10 +1281,6 @@ static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) { hs->new_session->peer_sha256_valid = 1; } - if (!ssl->ctx->x509_method->session_verify_cert_chain(hs->new_session, ssl)) { - return -1; - } - return 1; } diff --git a/ssl/internal.h b/ssl/internal.h index ba987837..e2a3af4f 100644 --- a/ssl/internal.h +++ b/ssl/internal.h @@ -1007,6 +1007,7 @@ enum ssl_hs_wait_t { ssl_hs_early_data_rejected, ssl_hs_read_end_of_early_data, ssl_hs_read_change_cipher_spec, + ssl_hs_certificate_verify, }; struct ssl_handshake_st { @@ -1341,6 +1342,9 @@ int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert, const SSL_EXTENSION_TYPE *ext_types, size_t num_ext_types, int ignore_unknown); +/* ssl_verify_peer_cert verifies the peer certificate for |hs|. */ +enum ssl_verify_result_t ssl_verify_peer_cert(SSL_HANDSHAKE *hs); + /* SSLKEYLOGFILE functions. */ @@ -1597,7 +1601,8 @@ struct ssl_x509_method_st { /* session_verify_cert_chain verifies the certificate chain in |session|, * sets |session->verify_result| and returns one on success or zero on * error. */ - int (*session_verify_cert_chain)(SSL_SESSION *session, SSL *ssl); + int (*session_verify_cert_chain)(SSL_SESSION *session, SSL *ssl, + uint8_t *out_alert); /* hs_flush_cached_ca_names drops any cached |X509_NAME|s from |hs|. */ void (*hs_flush_cached_ca_names)(SSL_HANDSHAKE *hs); @@ -1990,6 +1995,9 @@ struct ssl_st { int (*verify_callback)(int ok, X509_STORE_CTX *ctx); /* fail if callback returns 0 */ + enum ssl_verify_result_t (*custom_verify_callback)(SSL *ssl, + uint8_t *out_alert); + void (*info_callback)(const SSL *ssl, int type, int value); /* Server-only: psk_identity_hint is the identity hint to send in diff --git a/ssl/s3_both.cc b/ssl/s3_both.cc index 79f71faf..85de99cd 100644 --- a/ssl/s3_both.cc +++ b/ssl/s3_both.cc @@ -830,3 +830,34 @@ int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert, return 1; } + +enum ssl_verify_result_t ssl_verify_peer_cert(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + uint8_t alert = SSL_AD_CERTIFICATE_UNKNOWN; + enum ssl_verify_result_t ret; + if (ssl->custom_verify_callback != nullptr) { + ret = ssl->custom_verify_callback(ssl, &alert); + switch (ret) { + case ssl_verify_ok: + hs->new_session->verify_result = X509_V_OK; + break; + case ssl_verify_invalid: + hs->new_session->verify_result = X509_V_ERR_APPLICATION_VERIFICATION; + break; + case ssl_verify_retry: + break; + } + } else { + ret = ssl->ctx->x509_method->session_verify_cert_chain(hs->new_session, ssl, + &alert) + ? ssl_verify_ok + : ssl_verify_invalid; + } + + if (ret == ssl_verify_invalid) { + OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED); + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + } + + return ret; +} diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc index 74419252..b2d5f025 100644 --- a/ssl/ssl_lib.cc +++ b/ssl/ssl_lib.cc @@ -392,6 +392,7 @@ SSL *SSL_new(SSL_CTX *ctx) { ssl->msg_callback_arg = ctx->msg_callback_arg; ssl->verify_mode = ctx->verify_mode; ssl->verify_callback = ctx->default_verify_callback; + ssl->custom_verify_callback = ctx->custom_verify_callback; ssl->retain_only_sha256_of_client_certs = ctx->retain_only_sha256_of_client_certs; @@ -984,6 +985,9 @@ int SSL_get_error(const SSL *ssl, int ret_code) { case SSL_EARLY_DATA_REJECTED: return SSL_ERROR_EARLY_DATA_REJECTED; + + case SSL_CERTIFICATE_VERIFY: + return SSL_ERROR_WANT_CERTIFICATE_VERIFY; } return SSL_ERROR_SYSCALL; @@ -1554,12 +1558,22 @@ int SSL_get_servername_type(const SSL *ssl) { return TLSEXT_NAMETYPE_host_name; } -void SSL_CTX_enable_signed_cert_timestamps(SSL_CTX *ctx) { - ctx->signed_cert_timestamps_enabled = 1; +void SSL_CTX_set_custom_verify( + SSL_CTX *ctx, int mode, + enum ssl_verify_result_t (*callback)(SSL *ssl, uint8_t *out_alert)) { + ctx->verify_mode = mode; + ctx->custom_verify_callback = callback; } -void SSL_CTX_i_promise_to_verify_certs_after_the_handshake(SSL_CTX *ctx) { - ctx->i_promise_to_verify_certs_after_the_handshake = 1; +void SSL_set_custom_verify( + SSL *ssl, int mode, + enum ssl_verify_result_t (*callback)(SSL *ssl, uint8_t *out_alert)) { + ssl->verify_mode = mode; + ssl->custom_verify_callback = callback; +} + +void SSL_CTX_enable_signed_cert_timestamps(SSL_CTX *ctx) { + ctx->signed_cert_timestamps_enabled = 1; } void SSL_enable_signed_cert_timestamps(SSL *ssl) { diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc index 2c648acb..640718ae 100644 --- a/ssl/ssl_test.cc +++ b/ssl/ssl_test.cc @@ -3276,7 +3276,11 @@ TEST(SSLTest, SetChainAndKey) { ASSERT_TRUE(SSL_CTX_set_chain_and_key(server_ctx.get(), &chain[0], chain.size(), key.get(), nullptr)); - SSL_CTX_i_promise_to_verify_certs_after_the_handshake(client_ctx.get()); + SSL_CTX_set_custom_verify( + client_ctx.get(), SSL_VERIFY_PEER, + [](SSL *ssl, uint8_t *out_alert) -> ssl_verify_result_t { + return ssl_verify_ok; + }); bssl::UniquePtr client, server; ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(), diff --git a/ssl/ssl_x509.cc b/ssl/ssl_x509.cc index 77fc0e2a..125e1056 100644 --- a/ssl/ssl_x509.cc +++ b/ssl/ssl_x509.cc @@ -620,7 +620,9 @@ static int ssl_verify_alarm_type(long type) { } static int ssl_crypto_x509_session_verify_cert_chain(SSL_SESSION *session, - SSL *ssl) { + SSL *ssl, + uint8_t *out_alert) { + *out_alert = SSL_AD_INTERNAL_ERROR; STACK_OF(X509) *const cert_chain = session->x509_chain; if (cert_chain == NULL || sk_X509_num(cert_chain) == 0) { return 0; @@ -666,8 +668,7 @@ static int ssl_crypto_x509_session_verify_cert_chain(SSL_SESSION *session, /* If |SSL_VERIFY_NONE|, the error is non-fatal, but we keep the result. */ if (verify_ret <= 0 && ssl->verify_mode != SSL_VERIFY_NONE) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, ssl_verify_alarm_type(ctx.error)); - OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED); + *out_alert = ssl_verify_alarm_type(ctx.error); goto err; } diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc index cd846be4..2e987807 100644 --- a/ssl/test/bssl_shim.cc +++ b/ssl/test/bssl_shim.cc @@ -112,6 +112,7 @@ struct TestState { bool alpn_select_done = false; bool is_resume = false; bool early_callback_ready = false; + bool custom_verify_ready = false; }; static void TestStateExFree(void *parent, void *ptr, CRYPTO_EX_DATA *ad, @@ -684,27 +685,52 @@ static int CertCallback(SSL *ssl, void *arg) { return 1; } -static int VerifySucceed(X509_STORE_CTX *store_ctx, void *arg) { - SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(store_ctx, - SSL_get_ex_data_X509_STORE_CTX_idx()); +static bool CheckVerifyCallback(SSL *ssl) { const TestConfig *config = GetTestConfig(ssl); - if (!config->expected_ocsp_response.empty()) { const uint8_t *data; size_t len; SSL_get0_ocsp_response(ssl, &data, &len); if (len == 0) { fprintf(stderr, "OCSP response not available in verify callback\n"); - return 0; + return false; } } + return true; +} + +static int CertVerifyCallback(X509_STORE_CTX *store_ctx, void *arg) { + SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(store_ctx, + SSL_get_ex_data_X509_STORE_CTX_idx()); + const TestConfig *config = GetTestConfig(ssl); + if (!CheckVerifyCallback(ssl)) { + return 0; + } + + if (config->verify_fail) { + store_ctx->error = X509_V_ERR_APPLICATION_VERIFICATION; + return 0; + } + return 1; } -static int VerifyFail(X509_STORE_CTX *store_ctx, void *arg) { - store_ctx->error = X509_V_ERR_APPLICATION_VERIFICATION; - return 0; +static ssl_verify_result_t CustomVerifyCallback(SSL *ssl, uint8_t *out_alert) { + const TestConfig *config = GetTestConfig(ssl); + if (!CheckVerifyCallback(ssl)) { + return ssl_verify_invalid; + } + + if (config->async && !GetTestState(ssl)->custom_verify_ready) { + return ssl_verify_retry; + } + + if (config->verify_fail) { + return ssl_verify_invalid; + } + + return ssl_verify_ok; } static int NextProtosAdvertisedCallback(SSL *ssl, const uint8_t **out, @@ -1139,10 +1165,8 @@ static bssl::UniquePtr SetupCtx(SSL_CTX *old_ctx, return nullptr; } - if (config->verify_fail) { - SSL_CTX_set_cert_verify_callback(ssl_ctx.get(), VerifyFail, NULL); - } else { - SSL_CTX_set_cert_verify_callback(ssl_ctx.get(), VerifySucceed, NULL); + if (!config->use_custom_verify_callback) { + SSL_CTX_set_cert_verify_callback(ssl_ctx.get(), CertVerifyCallback, NULL); } if (!config->signed_cert_timestamps.empty() && @@ -1270,6 +1294,9 @@ static bool RetryAsync(SSL *ssl, int ret) { case SSL_ERROR_WANT_PRIVATE_KEY_OPERATION: test_state->private_key_retries++; return true; + case SSL_ERROR_WANT_CERTIFICATE_VERIFY: + test_state->custom_verify_ready = true; + return true; default: return false; } @@ -1763,20 +1790,23 @@ static bool DoConnection(bssl::UniquePtr *out_session, if (!config->use_old_client_cert_callback) { SSL_set_cert_cb(ssl.get(), CertCallback, nullptr); } + int mode = SSL_VERIFY_NONE; if (config->require_any_client_certificate) { - SSL_set_verify(ssl.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, - NULL); + mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; } if (config->verify_peer) { - SSL_set_verify(ssl.get(), SSL_VERIFY_PEER, NULL); + mode = SSL_VERIFY_PEER; } if (config->verify_peer_if_no_obc) { // Set SSL_VERIFY_FAIL_IF_NO_PEER_CERT so testing whether client // certificates were requested is easy. - SSL_set_verify(ssl.get(), - SSL_VERIFY_PEER | SSL_VERIFY_PEER_IF_NO_OBC | - SSL_VERIFY_FAIL_IF_NO_PEER_CERT, - NULL); + mode = SSL_VERIFY_PEER | SSL_VERIFY_PEER_IF_NO_OBC | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + } + if (config->use_custom_verify_callback) { + SSL_set_custom_verify(ssl.get(), mode, CustomVerifyCallback); + } else if (mode != SSL_VERIFY_NONE) { + SSL_set_verify(ssl.get(), mode, NULL); } if (config->false_start) { SSL_set_mode(ssl.get(), SSL_MODE_ENABLE_FALSE_START); diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go index e526576d..8ced44d4 100644 --- a/ssl/test/runner/runner.go +++ b/ssl/test/runner/runner.go @@ -4553,47 +4553,49 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { if config.protocol == dtls && !vers.hasDTLS { continue } - for _, testType := range []testType{clientTest, serverTest} { - suffix := "-Client" - if testType == serverTest { - suffix = "-Server" - } - suffix += "-" + vers.name + for _, useCustomCallback := range []bool{false, true} { + for _, testType := range []testType{clientTest, serverTest} { + suffix := "-Client" + if testType == serverTest { + suffix = "-Server" + } + suffix += "-" + vers.name + if useCustomCallback { + suffix += "-CustomCallback" + } - flag := "-verify-peer" - if testType == serverTest { - flag = "-require-any-client-certificate" - } + flags := []string{"-verify-peer"} + if testType == serverTest { + flags = append(flags, "-require-any-client-certificate") + } + if useCustomCallback { + flags = append(flags, "-use-custom-verify-callback") + } - tests = append(tests, testCase{ - testType: testType, - name: "CertificateVerificationSucceed" + suffix, - config: Config{ - MaxVersion: vers.version, - Certificates: []Certificate{rsaCertificate}, - }, - tls13Variant: vers.tls13Variant, - flags: []string{ - flag, - "-expect-verify-result", - }, - resumeSession: true, - }) - tests = append(tests, testCase{ - testType: testType, - name: "CertificateVerificationFail" + suffix, - config: Config{ - MaxVersion: vers.version, - Certificates: []Certificate{rsaCertificate}, - }, - tls13Variant: vers.tls13Variant, - flags: []string{ - flag, - "-verify-fail", - }, - shouldFail: true, - expectedError: ":CERTIFICATE_VERIFY_FAILED:", - }) + tests = append(tests, testCase{ + testType: testType, + name: "CertificateVerificationSucceed" + suffix, + config: Config{ + MaxVersion: vers.version, + Certificates: []Certificate{rsaCertificate}, + }, + tls13Variant: vers.tls13Variant, + flags: append([]string{"-expect-verify-result"}, flags...), + resumeSession: true, + }) + tests = append(tests, testCase{ + testType: testType, + name: "CertificateVerificationFail" + suffix, + config: Config{ + MaxVersion: vers.version, + Certificates: []Certificate{rsaCertificate}, + }, + tls13Variant: vers.tls13Variant, + flags: append([]string{"-verify-fail"}, flags...), + shouldFail: true, + expectedError: ":CERTIFICATE_VERIFY_FAILED:", + }) + } } // By default, the client is in a soft fail mode where the peer diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc index f925504d..fa7dfe18 100644 --- a/ssl/test/test_config.cc +++ b/ssl/test/test_config.cc @@ -129,6 +129,7 @@ const Flag kBoolFlags[] = { { "-handshake-twice", &TestConfig::handshake_twice }, { "-allow-unknown-alpn-protos", &TestConfig::allow_unknown_alpn_protos }, { "-enable-ed25519", &TestConfig::enable_ed25519 }, + { "-use-custom-verify-callback", &TestConfig::use_custom_verify_callback }, }; const Flag kStringFlags[] = { diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h index e157936d..1e5912e3 100644 --- a/ssl/test/test_config.h +++ b/ssl/test/test_config.h @@ -144,6 +144,7 @@ struct TestConfig { bool handshake_twice = false; bool allow_unknown_alpn_protos = false; bool enable_ed25519 = false; + bool use_custom_verify_callback = false; }; bool ParseConfig(int argc, char **argv, TestConfig *out_initial, diff --git a/ssl/tls13_both.cc b/ssl/tls13_both.cc index 83ff78a6..6a6c3c6a 100644 --- a/ssl/tls13_both.cc +++ b/ssl/tls13_both.cc @@ -102,6 +102,11 @@ int tls13_handshake(SSL_HANDSHAKE *hs, int *out_early_return) { hs->wait = ssl_hs_ok; return -1; + case ssl_hs_certificate_verify: + ssl->rwstate = SSL_CERTIFICATE_VERIFY; + hs->wait = ssl_hs_ok; + return -1; + case ssl_hs_early_data_rejected: ssl->rwstate = SSL_EARLY_DATA_REJECTED; /* Cause |SSL_write| to start failing immediately. */ @@ -357,12 +362,6 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) { } hs->new_session->peer_sha256_valid = retain_sha256; - - if (!ssl->ctx->x509_method->session_verify_cert_chain(hs->new_session, - ssl)) { - goto err; - } - ret = 1; err: diff --git a/ssl/tls13_client.cc b/ssl/tls13_client.cc index 7f961bff..9153dd71 100644 --- a/ssl/tls13_client.cc +++ b/ssl/tls13_client.cc @@ -494,6 +494,16 @@ static enum ssl_hs_wait_t do_process_server_certificate(SSL_HANDSHAKE *hs) { static enum ssl_hs_wait_t do_process_server_certificate_verify( SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; + switch (ssl_verify_peer_cert(hs)) { + case ssl_verify_ok: + break; + case ssl_verify_invalid: + return ssl_hs_error; + case ssl_verify_retry: + hs->tls13_state = state_process_server_certificate_verify; + return ssl_hs_certificate_verify; + } + if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) || !tls13_process_certificate_verify(hs) || !ssl_hash_current_message(hs)) { diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc index 4e66016f..dd7e86d1 100644 --- a/ssl/tls13_server.cc +++ b/ssl/tls13_server.cc @@ -766,6 +766,16 @@ static enum ssl_hs_wait_t do_process_client_certificate_verify( return ssl_hs_ok; } + switch (ssl_verify_peer_cert(hs)) { + case ssl_verify_ok: + break; + case ssl_verify_invalid: + return ssl_hs_error; + case ssl_verify_retry: + hs->tls13_state = state_process_client_certificate_verify; + return ssl_hs_certificate_verify; + } + if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) || !tls13_process_certificate_verify(hs) || !ssl_hash_current_message(hs)) { diff --git a/ssl/tls_method.cc b/ssl/tls_method.cc index d039b7db..0bcdf92a 100644 --- a/ssl/tls_method.cc +++ b/ssl/tls_method.cc @@ -240,15 +240,9 @@ static int ssl_noop_x509_session_dup(SSL_SESSION *new_session, } static void ssl_noop_x509_session_clear(SSL_SESSION *session) {} static int ssl_noop_x509_session_verify_cert_chain(SSL_SESSION *session, - SSL *ssl) { - if (!ssl->ctx->i_promise_to_verify_certs_after_the_handshake) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNKNOWN_CA); - OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED); - return 0; - } - - session->verify_result = X509_V_OK; - return 1; + SSL *ssl, + uint8_t *out_alert) { + return 0; } static void ssl_noop_x509_hs_flush_cached_ca_names(SSL_HANDSHAKE *hs) {}