This also serves as a certificate verification callback for CRYPTO_BUFFER-based consumers. Remove the silly SSL_CTX_i_promise_to_verify_certs_after_the_handshake placeholder. Bug: 54, chromium:347402 Change-Id: I4c6b445cb9cd7204218acb2e5d1625e6f37aff6f Reviewed-on: https://boringssl-review.googlesource.com/17964 Reviewed-by: David Benjamin <davidben@google.com>kris/onging/CECPQ3_patch15
@@ -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; | |||
@@ -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) | |||
@@ -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; | |||
@@ -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; | |||
} | |||
@@ -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 | |||
@@ -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; | |||
} |
@@ -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) { | |||
@@ -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<SSL> client, server; | |||
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(), | |||
@@ -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; | |||
} | |||
@@ -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<SSL_CTX> 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<SSL_SESSION> *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); | |||
@@ -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 | |||
@@ -129,6 +129,7 @@ const Flag<bool> 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<std::string> kStringFlags[] = { | |||
@@ -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, | |||
@@ -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: | |||
@@ -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)) { | |||
@@ -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)) { | |||
@@ -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) {} | |||