external/boringssl: Sync to 8ebeabf0e2e01b331e56d0a491c12539baa55d3d.
This includes the following changes:
https://boringssl.googlesource.com/boringssl/+log/be2ee342d3781ddb954f91f8a7e660c6f59e87e5..8ebeabf0e2e01b331e56d0a491c12539baa55d3d
Test: Libcore CTS presubmits.
Change-Id: I2fefc3e2bc2bbc3e3083668bd2a56d491520bc24
diff --git a/src/ssl/d1_lib.c b/src/ssl/d1_lib.c
index 258e9ab..ef15252 100644
--- a/src/ssl/d1_lib.c
+++ b/src/ssl/d1_lib.c
@@ -135,8 +135,6 @@
ssl->d1->next_timeout.tv_sec++;
ssl->d1->next_timeout.tv_usec -= 1000000;
}
- BIO_ctrl(ssl->rbio, BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
- &ssl->d1->next_timeout);
}
int DTLSv1_get_timeout(const SSL *ssl, struct timeval *out) {
@@ -149,32 +147,43 @@
return 0;
}
- struct timeval timenow;
+ struct OPENSSL_timeval timenow;
ssl_get_current_time(ssl, &timenow);
/* If timer already expired, set remaining time to 0 */
if (ssl->d1->next_timeout.tv_sec < timenow.tv_sec ||
(ssl->d1->next_timeout.tv_sec == timenow.tv_sec &&
ssl->d1->next_timeout.tv_usec <= timenow.tv_usec)) {
- OPENSSL_memset(out, 0, sizeof(struct timeval));
+ OPENSSL_memset(out, 0, sizeof(*out));
return 1;
}
/* Calculate time left until timer expires */
- OPENSSL_memcpy(out, &ssl->d1->next_timeout, sizeof(struct timeval));
- out->tv_sec -= timenow.tv_sec;
- out->tv_usec -= timenow.tv_usec;
- if (out->tv_usec < 0) {
- out->tv_sec--;
- out->tv_usec += 1000000;
+ struct OPENSSL_timeval ret;
+ OPENSSL_memcpy(&ret, &ssl->d1->next_timeout, sizeof(ret));
+ ret.tv_sec -= timenow.tv_sec;
+ if (ret.tv_usec >= timenow.tv_usec) {
+ ret.tv_usec -= timenow.tv_usec;
+ } else {
+ ret.tv_usec = 1000000 + ret.tv_usec - timenow.tv_usec;
+ ret.tv_sec--;
}
/* If remaining time is less than 15 ms, set it to 0 to prevent issues
- * because of small devergences with socket timeouts. */
- if (out->tv_sec == 0 && out->tv_usec < 15000) {
- OPENSSL_memset(out, 0, sizeof(struct timeval));
+ * because of small divergences with socket timeouts. */
+ if (ret.tv_sec == 0 && ret.tv_usec < 15000) {
+ OPENSSL_memset(&ret, 0, sizeof(ret));
}
+ /* Clamp the result in case of overflow. */
+ if (ret.tv_sec > INT_MAX) {
+ assert(0);
+ out->tv_sec = INT_MAX;
+ } else {
+ out->tv_sec = ret.tv_sec;
+ }
+
+ out->tv_usec = ret.tv_usec;
return 1;
}
@@ -206,10 +215,9 @@
void dtls1_stop_timer(SSL *ssl) {
/* Reset everything */
ssl->d1->num_timeouts = 0;
- OPENSSL_memset(&ssl->d1->next_timeout, 0, sizeof(struct timeval));
+ OPENSSL_memset(&ssl->d1->next_timeout, 0, sizeof(ssl->d1->next_timeout));
ssl->d1->timeout_duration_ms = ssl->initial_timeout_duration_ms;
- BIO_ctrl(ssl->rbio, BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
- &ssl->d1->next_timeout);
+
/* Clear retransmission buffer */
dtls_clear_outgoing_messages(ssl);
}
diff --git a/src/ssl/d1_pkt.c b/src/ssl/d1_pkt.c
index 27b2763..3444825 100644
--- a/src/ssl/d1_pkt.c
+++ b/src/ssl/d1_pkt.c
@@ -142,7 +142,11 @@
if (ssl_read_buffer_len(ssl) == 0) {
int read_ret = ssl_read_buffer_extend_to(ssl, 0 /* unused */);
if (read_ret < 0 && dtls1_is_timer_expired(ssl)) {
- /* For blocking BIOs, retransmits must be handled internally. */
+ /* Historically, timeouts were handled implicitly if the caller did not
+ * handle them.
+ *
+ * TODO(davidben): This was to support blocking sockets but affected
+ * non-blocking sockets. Can it be removed? */
int timeout_ret = DTLSv1_handle_timeout(ssl);
if (timeout_ret <= 0) {
return timeout_ret;
diff --git a/src/ssl/handshake_client.c b/src/ssl/handshake_client.c
index c4f5e8e..c457772 100644
--- a/src/ssl/handshake_client.c
+++ b/src/ssl/handshake_client.c
@@ -1057,6 +1057,33 @@
return -1;
}
+ /* Disallow the server certificate from changing during a renegotiation. See
+ * https://mitls.org/pages/attacks/3SHAKE. We never resume on renegotiation,
+ * so this check is sufficient. */
+ if (ssl->s3->established_session != NULL) {
+ if (sk_CRYPTO_BUFFER_num(ssl->s3->established_session->certs) !=
+ sk_CRYPTO_BUFFER_num(hs->new_session->certs)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SERVER_CERT_CHANGED);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return -1;
+ }
+
+ for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(hs->new_session->certs); i++) {
+ const CRYPTO_BUFFER *old_cert =
+ sk_CRYPTO_BUFFER_value(ssl->s3->established_session->certs, i);
+ const CRYPTO_BUFFER *new_cert =
+ sk_CRYPTO_BUFFER_value(hs->new_session->certs, i);
+ if (CRYPTO_BUFFER_len(old_cert) != CRYPTO_BUFFER_len(new_cert) ||
+ OPENSSL_memcmp(CRYPTO_BUFFER_data(old_cert),
+ CRYPTO_BUFFER_data(new_cert),
+ CRYPTO_BUFFER_len(old_cert)) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SERVER_CERT_CHANGED);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return -1;
+ }
+ }
+ }
+
return 1;
}
@@ -1108,8 +1135,7 @@
static int ssl3_verify_server_cert(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
- if (!ssl_verify_cert_chain(ssl, &hs->new_session->verify_result,
- hs->new_session->x509_chain)) {
+ if (!ssl->ctx->x509_method->session_verify_cert_chain(hs->new_session, ssl)) {
return -1;
}
@@ -1403,22 +1429,24 @@
}
uint8_t alert = SSL_AD_DECODE_ERROR;
- STACK_OF(X509_NAME) *ca_sk = ssl_parse_client_CA_list(ssl, &alert, &cbs);
- if (ca_sk == NULL) {
+ STACK_OF(CRYPTO_BUFFER) *ca_names =
+ ssl_parse_client_CA_list(ssl, &alert, &cbs);
+ if (ca_names == NULL) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
return -1;
}
if (CBS_len(&cbs) != 0) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- sk_X509_NAME_pop_free(ca_sk, X509_NAME_free);
+ sk_CRYPTO_BUFFER_pop_free(ca_names, CRYPTO_BUFFER_free);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
return -1;
}
hs->cert_request = 1;
- sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free);
- hs->ca_names = ca_sk;
+ sk_CRYPTO_BUFFER_pop_free(hs->ca_names, CRYPTO_BUFFER_free);
+ hs->ca_names = ca_names;
+ ssl->ctx->x509_method->hs_flush_cached_ca_names(hs);
return 1;
}
@@ -1474,7 +1502,7 @@
}
}
- if (!ssl_auto_chain_if_needed(ssl) ||
+ if (!ssl->ctx->x509_method->ssl_auto_chain_if_needed(ssl) ||
!ssl3_output_cert_chain(ssl)) {
return -1;
}
diff --git a/src/ssl/handshake_server.c b/src/ssl/handshake_server.c
index 51338e2..e3a4e51 100644
--- a/src/ssl/handshake_server.c
+++ b/src/ssl/handshake_server.c
@@ -877,7 +877,7 @@
}
}
- if (!ssl_auto_chain_if_needed(ssl)) {
+ if (!ssl->ctx->x509_method->ssl_auto_chain_if_needed(ssl)) {
return -1;
}
@@ -1058,7 +1058,7 @@
ssl->s3->tlsext_channel_id_valid = 0;
}
- struct timeval now;
+ struct OPENSSL_timeval now;
ssl_get_current_time(ssl, &now);
ssl->s3->server_random[0] = now.tv_sec >> 24;
ssl->s3->server_random[1] = now.tv_sec >> 16;
@@ -1481,10 +1481,10 @@
hs->new_session->peer_sha256_valid = 1;
}
- if (!ssl_verify_cert_chain(ssl, &hs->new_session->verify_result,
- hs->new_session->x509_chain)) {
+ if (!ssl->ctx->x509_method->session_verify_cert_chain(hs->new_session, ssl)) {
return -1;
}
+
return 1;
}
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index a6dfad5..caa9cd2 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -826,11 +826,6 @@
* empty certificate list. It returns one on success and zero on error. */
int ssl_add_cert_chain(SSL *ssl, CBB *cbb);
-/* ssl_auto_chain_if_needed runs the deprecated auto-chaining logic if
- * necessary. On success, it updates |ssl|'s certificate configuration as needed
- * and returns one. Otherwise, it returns zero. */
-int ssl_auto_chain_if_needed(SSL *ssl);
-
/* ssl_cert_check_digital_signature_key_usage parses the DER-encoded, X.509
* certificate in |in| and returns one if doesn't specify a key usage or, if it
* does, if it includes digitalSignature. Otherwise it pushes to the error
@@ -844,9 +839,9 @@
/* ssl_parse_client_CA_list parses a CA list from |cbs| in the format used by a
* TLS CertificateRequest message. On success, it returns a newly-allocated
- * |X509_NAME| list and advances |cbs|. Otherwise, it returns NULL and sets
+ * |CRYPTO_BUFFER| list and advances |cbs|. Otherwise, it returns NULL and sets
* |*out_alert| to an alert to send to the peer. */
-STACK_OF(X509_NAME) *
+STACK_OF(CRYPTO_BUFFER) *
ssl_parse_client_CA_list(SSL *ssl, uint8_t *out_alert, CBS *cbs);
/* ssl_add_client_CA_list adds the configured CA list to |cbb| in the format
@@ -1037,7 +1032,11 @@
/* ca_names, on the client, contains the list of CAs received in a
* CertificateRequest message. */
- STACK_OF(X509_NAME) *ca_names;
+ STACK_OF(CRYPTO_BUFFER) *ca_names;
+
+ /* cached_x509_ca_names contains a cache of parsed versions of the elements
+ * of |ca_names|. */
+ STACK_OF(X509_NAME) *cached_x509_ca_names;
/* certificate_types, on the client, contains the set of certificate types
* received in a CertificateRequest message. */
@@ -1442,10 +1441,19 @@
};
struct ssl_x509_method_st {
- /* cert_clear frees and NULLs all X509-related state. */
+ /* check_client_CA_list returns one if |names| is a good list of X.509
+ * distinguished names and zero otherwise. This is used to ensure that we can
+ * reject unparsable values at handshake time when using crypto/x509. */
+ int (*check_client_CA_list)(STACK_OF(CRYPTO_BUFFER) *names);
+
+ /* cert_clear frees and NULLs all X509 certificate-related state. */
void (*cert_clear)(CERT *cert);
+ /* cert_free frees all X509-related state. */
+ void (*cert_free)(CERT *cert);
/* cert_flush_cached_chain drops any cached |X509|-based certificate chain
* from |cert|. */
+ /* cert_dup duplicates any needed fields from |cert| to |new_cert|. */
+ void (*cert_dup)(CERT *new_cert, const CERT *cert);
void (*cert_flush_cached_chain)(CERT *cert);
/* cert_flush_cached_chain drops any cached |X509|-based leaf certificate
* from |cert|. */
@@ -1460,11 +1468,32 @@
int (*session_dup)(SSL_SESSION *new_session, const SSL_SESSION *session);
/* session_clear frees any X509-related state from |session|. */
void (*session_clear)(SSL_SESSION *session);
-};
+ /* 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);
-/* ssl_noop_x509_method is implements the |ssl_x509_method_st| functions by
- * doing nothing. */
-extern const struct ssl_x509_method_st ssl_noop_x509_method;
+ /* hs_flush_cached_ca_names drops any cached |X509_NAME|s from |hs|. */
+ void (*hs_flush_cached_ca_names)(SSL_HANDSHAKE *hs);
+ /* ssl_new does any neccessary initialisation of |ssl|. It returns one on
+ * success or zero on error. */
+ int (*ssl_new)(SSL *ssl);
+ /* ssl_free frees anything created by |ssl_new|. */
+ void (*ssl_free)(SSL *ssl);
+ /* ssl_flush_cached_client_CA drops any cached |X509_NAME|s from |ssl|. */
+ void (*ssl_flush_cached_client_CA)(SSL *ssl);
+ /* ssl_auto_chain_if_needed runs the deprecated auto-chaining logic if
+ * necessary. On success, it updates |ssl|'s certificate configuration as
+ * needed and returns one. Otherwise, it returns zero. */
+ int (*ssl_auto_chain_if_needed)(SSL *ssl);
+ /* ssl_ctx_new does any neccessary initialisation of |ctx|. It returns one on
+ * success or zero on error. */
+ int (*ssl_ctx_new)(SSL_CTX *ctx);
+ /* ssl_ctx_free frees anything created by |ssl_ctx_new|. */
+ void (*ssl_ctx_free)(SSL_CTX *ctx);
+ /* ssl_ctx_flush_cached_client_CA drops any cached |X509_NAME|s from |ctx|. */
+ void (*ssl_ctx_flush_cached_client_CA)(SSL_CTX *ssl);
+};
/* ssl_crypto_x509_method provides the |ssl_x509_method_st| functions using
* crypto/x509. */
@@ -1575,10 +1604,6 @@
* handshake. */
unsigned tlsext_channel_id_valid:1;
- /* short_header is one if https://github.com/tlswg/tls13-spec/pull/762 has
- * been negotiated. */
- unsigned short_header:1;
-
uint8_t send_alert[2];
/* pending_flight is the pending outgoing flight. This is used to flush each
@@ -1691,6 +1716,11 @@
uint8_t *reassembly;
} hm_fragment;
+struct OPENSSL_timeval {
+ uint64_t tv_sec;
+ uint32_t tv_usec;
+};
+
typedef struct dtls1_state_st {
/* send_cookie is true if we are resending the ClientHello
* with a cookie from a HelloVerifyRequest. */
@@ -1739,7 +1769,7 @@
/* Indicates when the last handshake msg or heartbeat sent will
* timeout. */
- struct timeval next_timeout;
+ struct OPENSSL_timeval next_timeout;
/* timeout_duration_ms is the timeout duration in milliseconds. */
unsigned timeout_duration_ms;
@@ -1832,7 +1862,11 @@
CRYPTO_EX_DATA ex_data;
/* for server side, keep the list of CA_dn we can use */
- STACK_OF(X509_NAME) *client_CA;
+ STACK_OF(CRYPTO_BUFFER) *client_CA;
+
+ /* cached_x509_client_CA is a cache of parsed versions of the elements of
+ * |client_CA|. */
+ STACK_OF(X509_NAME) *cached_x509_client_CA;
uint32_t options; /* protocol behaviour */
uint32_t mode; /* API behaviour */
@@ -1980,7 +2014,8 @@
/* ssl_session_renew_timeout calls |ssl_session_rebase_time| and renews
* |session|'s timeout to |timeout| (measured from the current time). The
* renewal is clamped to the session's auth_timeout. */
-void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session, long timeout);
+void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session,
+ uint32_t timeout);
void ssl_cipher_preference_list_free(
struct ssl_cipher_preference_list_st *cipher_list);
@@ -1990,8 +2025,6 @@
const struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(
const SSL *ssl);
-int ssl_verify_cert_chain(SSL *ssl, long *out_verify_result,
- STACK_OF(X509) *cert_chain);
void ssl_update_cache(SSL_HANDSHAKE *hs, int mode);
int ssl_verify_alarm_type(long type);
@@ -2172,7 +2205,7 @@
* call this function before the version is determined. */
uint16_t ssl3_protocol_version(const SSL *ssl);
-void ssl_get_current_time(const SSL *ssl, struct timeval *out_clock);
+void ssl_get_current_time(const SSL *ssl, struct OPENSSL_timeval *out_clock);
/* ssl_reset_error_state resets state for |SSL_get_error|. */
void ssl_reset_error_state(SSL *ssl);
diff --git a/src/ssl/s3_both.c b/src/ssl/s3_both.c
index 7fd09c6..6b03030 100644
--- a/src/ssl/s3_both.c
+++ b/src/ssl/s3_both.c
@@ -173,7 +173,8 @@
OPENSSL_free(hs->peer_key);
OPENSSL_free(hs->server_params);
OPENSSL_free(hs->peer_psk_identity_hint);
- sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free);
+ sk_CRYPTO_BUFFER_pop_free(hs->ca_names, CRYPTO_BUFFER_free);
+ hs->ssl->ctx->x509_method->hs_flush_cached_ca_names(hs);
OPENSSL_free(hs->certificate_types);
if (hs->key_block != NULL) {
diff --git a/src/ssl/ssl_asn1.c b/src/ssl/ssl_asn1.c
index 3533225..cfcc12a 100644
--- a/src/ssl/ssl_asn1.c
+++ b/src/ssl/ssl_asn1.c
@@ -210,28 +210,10 @@
!CBB_add_bytes(&child, in->session_id,
for_ticket ? 0 : in->session_id_length) ||
!CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
- !CBB_add_bytes(&child, in->master_key, in->master_key_length)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (in->time < 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
- goto err;
- }
-
- if (!CBB_add_asn1(&session, &child, kTimeTag) ||
- !CBB_add_asn1_uint64(&child, in->time)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (in->timeout < 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
- goto err;
- }
-
- if (!CBB_add_asn1(&session, &child, kTimeoutTag) ||
+ !CBB_add_bytes(&child, in->master_key, in->master_key_length) ||
+ !CBB_add_asn1(&session, &child, kTimeTag) ||
+ !CBB_add_asn1_uint64(&child, in->time) ||
+ !CBB_add_asn1(&session, &child, kTimeoutTag) ||
!CBB_add_asn1_uint64(&child, in->timeout)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
@@ -634,19 +616,17 @@
ret->master_key_length = CBS_len(&master_key);
CBS child;
- uint64_t time, timeout;
+ uint64_t timeout;
if (!CBS_get_asn1(&session, &child, kTimeTag) ||
- !CBS_get_asn1_uint64(&child, &time) ||
- time > LONG_MAX ||
+ !CBS_get_asn1_uint64(&child, &ret->time) ||
!CBS_get_asn1(&session, &child, kTimeoutTag) ||
!CBS_get_asn1_uint64(&child, &timeout) ||
- timeout > LONG_MAX) {
+ timeout > UINT32_MAX) {
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}
- ret->time = (long)time;
- ret->timeout = (long)timeout;
+ ret->timeout = (uint32_t)timeout;
CBS peer;
int has_peer;
@@ -811,8 +791,8 @@
kPeerSignatureAlgorithmTag, 0) ||
!SSL_SESSION_parse_u32(&session, &ret->ticket_max_early_data,
kTicketMaxEarlyDataTag, 0) ||
- !SSL_SESSION_parse_long(&session, &ret->auth_timeout, kAuthTimeoutTag,
- ret->timeout) ||
+ !SSL_SESSION_parse_u32(&session, &ret->auth_timeout, kAuthTimeoutTag,
+ ret->timeout) ||
!SSL_SESSION_parse_octet_string(&session, &ret->early_alpn,
&ret->early_alpn_len, kEarlyALPNTag) ||
CBS_len(&session) != 0) {
diff --git a/src/ssl/ssl_cert.c b/src/ssl/ssl_cert.c
index c60c6fa..1309a18 100644
--- a/src/ssl/ssl_cert.c
+++ b/src/ssl/ssl_cert.c
@@ -133,14 +133,6 @@
#include "internal.h"
-int SSL_get_ex_data_X509_STORE_CTX_idx(void) {
- /* The ex_data index to go from |X509_STORE_CTX| to |SSL| always uses the
- * reserved app_data slot. Before ex_data was introduced, app_data was used.
- * Avoid breaking any software which assumes |X509_STORE_CTX_get_app_data|
- * works. */
- return 0;
-}
-
CERT *ssl_cert_new(const SSL_X509_METHOD *x509_method) {
CERT *ret = OPENSSL_malloc(sizeof(CERT));
if (ret == NULL) {
@@ -198,10 +190,7 @@
ret->cert_cb = cert->cert_cb;
ret->cert_cb_arg = cert->cert_cb_arg;
- if (cert->verify_store != NULL) {
- X509_STORE_up_ref(cert->verify_store);
- ret->verify_store = cert->verify_store;
- }
+ ret->x509_method->cert_dup(ret, cert);
if (cert->signed_cert_timestamp_list != NULL) {
CRYPTO_BUFFER_up_ref(cert->signed_cert_timestamp_list);
@@ -246,8 +235,8 @@
DH_free(c->dh_tmp);
ssl_cert_clear_certs(c);
+ c->x509_method->cert_free(c);
OPENSSL_free(c->sigalgs);
- X509_STORE_free(c->verify_store);
CRYPTO_BUFFER_free(c->signed_cert_timestamp_list);
CRYPTO_BUFFER_free(c->ocsp_response);
@@ -347,155 +336,6 @@
return ok;
}
-int ssl_verify_cert_chain(SSL *ssl, long *out_verify_result,
- STACK_OF(X509) *cert_chain) {
- if (cert_chain == NULL || sk_X509_num(cert_chain) == 0) {
- return 0;
- }
-
- X509_STORE *verify_store = ssl->ctx->cert_store;
- if (ssl->cert->verify_store != NULL) {
- verify_store = ssl->cert->verify_store;
- }
-
- X509 *leaf = sk_X509_value(cert_chain, 0);
- int ret = 0;
- X509_STORE_CTX ctx;
- if (!X509_STORE_CTX_init(&ctx, verify_store, leaf, cert_chain)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
- return 0;
- }
- if (!X509_STORE_CTX_set_ex_data(&ctx, SSL_get_ex_data_X509_STORE_CTX_idx(),
- ssl)) {
- goto err;
- }
-
- /* We need to inherit the verify parameters. These can be determined by the
- * context: if its a server it will verify SSL client certificates or vice
- * versa. */
- X509_STORE_CTX_set_default(&ctx, ssl->server ? "ssl_client" : "ssl_server");
-
- /* Anything non-default in "param" should overwrite anything in the ctx. */
- X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), ssl->param);
-
- if (ssl->verify_callback) {
- X509_STORE_CTX_set_verify_cb(&ctx, ssl->verify_callback);
- }
-
- int verify_ret;
- if (ssl->ctx->app_verify_callback != NULL) {
- verify_ret = ssl->ctx->app_verify_callback(&ctx, ssl->ctx->app_verify_arg);
- } else {
- verify_ret = X509_verify_cert(&ctx);
- }
-
- *out_verify_result = ctx.error;
-
- /* 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);
- goto err;
- }
-
- ERR_clear_error();
- ret = 1;
-
-err:
- X509_STORE_CTX_cleanup(&ctx);
- return ret;
-}
-
-static void set_client_CA_list(STACK_OF(X509_NAME) **ca_list,
- STACK_OF(X509_NAME) *name_list) {
- sk_X509_NAME_pop_free(*ca_list, X509_NAME_free);
- *ca_list = name_list;
-}
-
-STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *list) {
- STACK_OF(X509_NAME) *ret = sk_X509_NAME_new_null();
- if (ret == NULL) {
- return NULL;
- }
-
- for (size_t i = 0; i < sk_X509_NAME_num(list); i++) {
- X509_NAME *name = X509_NAME_dup(sk_X509_NAME_value(list, i));
- if (name == NULL || !sk_X509_NAME_push(ret, name)) {
- X509_NAME_free(name);
- sk_X509_NAME_pop_free(ret, X509_NAME_free);
- return NULL;
- }
- }
-
- return ret;
-}
-
-void SSL_set_client_CA_list(SSL *ssl, STACK_OF(X509_NAME) *name_list) {
- set_client_CA_list(&ssl->client_CA, name_list);
-}
-
-void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list) {
- set_client_CA_list(&ctx->client_CA, name_list);
-}
-
-STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx) {
- return ctx->client_CA;
-}
-
-STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl) {
- /* For historical reasons, this function is used both to query configuration
- * state on a server as well as handshake state on a client. However, whether
- * |ssl| is a client or server is not known until explicitly configured with
- * |SSL_set_connect_state|. If |handshake_func| is NULL, |ssl| is in an
- * indeterminate mode and |ssl->server| is unset. */
- if (ssl->handshake_func != NULL && !ssl->server) {
- if (ssl->s3->hs != NULL) {
- return ssl->s3->hs->ca_names;
- }
-
- return NULL;
- }
-
- if (ssl->client_CA != NULL) {
- return ssl->client_CA;
- }
- return ssl->ctx->client_CA;
-}
-
-static int add_client_CA(STACK_OF(X509_NAME) **sk, X509 *x509) {
- X509_NAME *name;
-
- if (x509 == NULL) {
- return 0;
- }
- if (*sk == NULL) {
- *sk = sk_X509_NAME_new_null();
- if (*sk == NULL) {
- return 0;
- }
- }
-
- name = X509_NAME_dup(X509_get_subject_name(x509));
- if (name == NULL) {
- return 0;
- }
-
- if (!sk_X509_NAME_push(*sk, name)) {
- X509_NAME_free(name);
- return 0;
- }
-
- return 1;
-}
-
-int SSL_add_client_CA(SSL *ssl, X509 *x509) {
- return add_client_CA(&ssl->client_CA, x509);
-}
-
-int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x509) {
- return add_client_CA(&ctx->client_CA, x509);
-}
-
int ssl_has_certificate(const SSL *ssl) {
return ssl->cert->chain != NULL &&
sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0) != NULL &&
@@ -779,14 +619,11 @@
return 0;
}
-static int ca_dn_cmp(const X509_NAME **a, const X509_NAME **b) {
- return X509_NAME_cmp(*a, *b);
-}
-
-STACK_OF(X509_NAME) *
+STACK_OF(CRYPTO_BUFFER) *
ssl_parse_client_CA_list(SSL *ssl, uint8_t *out_alert, CBS *cbs) {
- STACK_OF(X509_NAME) *ret = sk_X509_NAME_new(ca_dn_cmp);
- X509_NAME *name = NULL;
+ CRYPTO_BUFFER_POOL *const pool = ssl->ctx->pool;
+
+ STACK_OF(CRYPTO_BUFFER) *ret = sk_CRYPTO_BUFFER_new_null();
if (ret == NULL) {
*out_alert = SSL_AD_INTERNAL_ERROR;
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
@@ -808,29 +645,27 @@
goto err;
}
- const uint8_t *ptr = CBS_data(&distinguished_name);
- /* A u16 length cannot overflow a long. */
- name = d2i_X509_NAME(NULL, &ptr, (long)CBS_len(&distinguished_name));
- if (name == NULL ||
- ptr != CBS_data(&distinguished_name) + CBS_len(&distinguished_name)) {
- *out_alert = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- goto err;
- }
-
- if (!sk_X509_NAME_push(ret, name)) {
+ CRYPTO_BUFFER *buffer =
+ CRYPTO_BUFFER_new_from_CBS(&distinguished_name, pool);
+ if (buffer == NULL ||
+ !sk_CRYPTO_BUFFER_push(ret, buffer)) {
+ CRYPTO_BUFFER_free(buffer);
*out_alert = SSL_AD_INTERNAL_ERROR;
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
- name = NULL;
+ }
+
+ if (!ssl->ctx->x509_method->check_client_CA_list(ret)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto err;
}
return ret;
err:
- X509_NAME_free(name);
- sk_X509_NAME_pop_free(ret, X509_NAME_free);
+ sk_CRYPTO_BUFFER_pop_free(ret, CRYPTO_BUFFER_free);
return NULL;
}
@@ -840,21 +675,20 @@
return 0;
}
- STACK_OF(X509_NAME) *sk = SSL_get_client_CA_list(ssl);
- if (sk == NULL) {
+ STACK_OF(CRYPTO_BUFFER) *names = ssl->client_CA;
+ if (names == NULL) {
+ names = ssl->ctx->client_CA;
+ }
+ if (names == NULL) {
return CBB_flush(cbb);
}
- for (size_t i = 0; i < sk_X509_NAME_num(sk); i++) {
- X509_NAME *name = sk_X509_NAME_value(sk, i);
- int len = i2d_X509_NAME(name, NULL);
- if (len < 0) {
- return 0;
- }
- uint8_t *ptr;
+ for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(names); i++) {
+ const CRYPTO_BUFFER *name = sk_CRYPTO_BUFFER_value(names, i);
+
if (!CBB_add_u16_length_prefixed(&child, &name_cbb) ||
- !CBB_add_space(&name_cbb, &ptr, (size_t)len) ||
- (len > 0 && i2d_X509_NAME(name, &ptr) < 0)) {
+ !CBB_add_bytes(&name_cbb, CRYPTO_BUFFER_data(name),
+ CRYPTO_BUFFER_len(name))) {
return 0;
}
}
@@ -862,33 +696,6 @@
return CBB_flush(cbb);
}
-static int set_cert_store(X509_STORE **store_ptr, X509_STORE *new_store, int take_ref) {
- X509_STORE_free(*store_ptr);
- *store_ptr = new_store;
-
- if (new_store != NULL && take_ref) {
- X509_STORE_up_ref(new_store);
- }
-
- return 1;
-}
-
-int SSL_CTX_set0_verify_cert_store(SSL_CTX *ctx, X509_STORE *store) {
- return set_cert_store(&ctx->cert->verify_store, store, 0);
-}
-
-int SSL_CTX_set1_verify_cert_store(SSL_CTX *ctx, X509_STORE *store) {
- return set_cert_store(&ctx->cert->verify_store, store, 1);
-}
-
-int SSL_set0_verify_cert_store(SSL *ssl, X509_STORE *store) {
- return set_cert_store(&ssl->cert->verify_store, store, 0);
-}
-
-int SSL_set1_verify_cert_store(SSL *ssl, X509_STORE *store) {
- return set_cert_store(&ssl->cert->verify_store, store, 1);
-}
-
void SSL_CTX_set_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, void *arg),
void *arg) {
ssl_cert_set_cert_cb(ctx->cert, cb, arg);
@@ -898,6 +705,22 @@
ssl_cert_set_cert_cb(ssl->cert, cb, arg);
}
+STACK_OF(CRYPTO_BUFFER) *SSL_get0_peer_certificates(const SSL *ssl) {
+ SSL_SESSION *session = SSL_get_session(ssl);
+ if (session == NULL) {
+ return NULL;
+ }
+
+ return session->certs;
+}
+
+STACK_OF(CRYPTO_BUFFER) *SSL_get0_server_requested_CAs(const SSL *ssl) {
+ if (ssl->s3->hs == NULL) {
+ return NULL;
+ }
+ return ssl->s3->hs->ca_names;
+}
+
int ssl_check_leaf_certificate(SSL_HANDSHAKE *hs, EVP_PKEY *pkey,
const CRYPTO_BUFFER *leaf) {
SSL *const ssl = hs->ssl;
@@ -940,38 +763,6 @@
return 1;
}
-static int do_client_cert_cb(SSL *ssl, void *arg) {
- if (ssl_has_certificate(ssl) || ssl->ctx->client_cert_cb == NULL) {
- return 1;
- }
-
- X509 *x509 = NULL;
- EVP_PKEY *pkey = NULL;
- int ret = ssl->ctx->client_cert_cb(ssl, &x509, &pkey);
- if (ret < 0) {
- return -1;
- }
-
- if (ret != 0) {
- if (!SSL_use_certificate(ssl, x509) ||
- !SSL_use_PrivateKey(ssl, pkey)) {
- return 0;
- }
- }
-
- X509_free(x509);
- EVP_PKEY_free(pkey);
- return 1;
-}
-
-void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl,
- X509 **out_x509,
- EVP_PKEY **out_pkey)) {
- /* Emulate the old client certificate callback with the new one. */
- SSL_CTX_set_cert_cb(ctx, do_client_cert_cb, NULL);
- ctx->client_cert_cb = cb;
-}
-
static int set_signed_cert_timestamp_list(CERT *cert, const uint8_t *list,
size_t list_len) {
CBS sct_list;
diff --git a/src/ssl/ssl_lib.c b/src/ssl/ssl_lib.c
index e37f9f9..7ead554 100644
--- a/src/ssl/ssl_lib.c
+++ b/src/ssl/ssl_lib.c
@@ -235,11 +235,6 @@
return NULL;
}
- if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS);
- goto err;
- }
-
ret = OPENSSL_malloc(sizeof(SSL_CTX));
if (ret == NULL) {
goto err;
@@ -271,8 +266,8 @@
if (ret->sessions == NULL) {
goto err;
}
- ret->cert_store = X509_STORE_new();
- if (ret->cert_store == NULL) {
+
+ if (!ret->x509_method->ssl_ctx_new(ret)) {
goto err;
}
@@ -284,12 +279,7 @@
goto err2;
}
- ret->param = X509_VERIFY_PARAM_new();
- if (!ret->param) {
- goto err;
- }
-
- ret->client_CA = sk_X509_NAME_new_null();
+ ret->client_CA = sk_CRYPTO_BUFFER_new_null();
if (ret->client_CA == NULL) {
goto err;
}
@@ -337,8 +327,6 @@
return;
}
- X509_VERIFY_PARAM_free(ctx->param);
-
/* Free internal session cache. However: the remove_cb() may reference the
* ex_data of SSL_CTX, thus the ex_data store can only be removed after the
* sessions were flushed. As the ex_data handling routines might also touch
@@ -351,14 +339,14 @@
CRYPTO_MUTEX_cleanup(&ctx->lock);
lh_SSL_SESSION_free(ctx->sessions);
- X509_STORE_free(ctx->cert_store);
ssl_cipher_preference_list_free(ctx->cipher_list);
ssl_cert_free(ctx->cert);
sk_SSL_CUSTOM_EXTENSION_pop_free(ctx->client_custom_extensions,
SSL_CUSTOM_EXTENSION_free);
sk_SSL_CUSTOM_EXTENSION_pop_free(ctx->server_custom_extensions,
SSL_CUSTOM_EXTENSION_free);
- sk_X509_NAME_pop_free(ctx->client_CA, X509_NAME_free);
+ sk_CRYPTO_BUFFER_pop_free(ctx->client_CA, CRYPTO_BUFFER_free);
+ ctx->x509_method->ssl_ctx_free(ctx);
sk_SRTP_PROTECTION_PROFILE_free(ctx->srtp_profiles);
OPENSSL_free(ctx->psk_identity_hint);
OPENSSL_free(ctx->supported_group_list);
@@ -407,11 +395,6 @@
ssl->retain_only_sha256_of_client_certs =
ctx->retain_only_sha256_of_client_certs;
- ssl->param = X509_VERIFY_PARAM_new();
- if (!ssl->param) {
- goto err;
- }
- X509_VERIFY_PARAM_inherit(ssl->param, ctx->param);
ssl->quiet_shutdown = ctx->quiet_shutdown;
ssl->max_send_fragment = ctx->max_send_fragment;
@@ -420,6 +403,10 @@
SSL_CTX_up_ref(ctx);
ssl->initial_ctx = ctx;
+ if (!ssl->ctx->x509_method->ssl_new(ssl)) {
+ goto err;
+ }
+
if (ctx->supported_group_list) {
ssl->supported_group_list = BUF_memdup(ctx->supported_group_list,
ctx->supported_group_list_len * 2);
@@ -481,8 +468,7 @@
return;
}
- X509_VERIFY_PARAM_free(ssl->param);
-
+ ssl->ctx->x509_method->ssl_free(ssl);
CRYPTO_free_ex_data(&g_ex_data_class_ssl, ssl, &ssl->ex_data);
BIO_free_all(ssl->rbio);
@@ -503,7 +489,7 @@
OPENSSL_free(ssl->alpn_client_proto_list);
EVP_PKEY_free(ssl->tlsext_channel_id_private);
OPENSSL_free(ssl->psk_identity_hint);
- sk_X509_NAME_pop_free(ssl->client_CA, X509_NAME_free);
+ sk_CRYPTO_BUFFER_pop_free(ssl->client_CA, CRYPTO_BUFFER_free);
sk_SRTP_PROTECTION_PROFILE_free(ssl->srtp_profiles);
if (ssl->method != NULL) {
@@ -1469,6 +1455,10 @@
return 1;
}
+OPENSSL_EXPORT STACK_OF(SSL_CIPHER) *SSL_CTX_get_ciphers(const SSL_CTX *ctx) {
+ return ctx->cipher_list->ciphers;
+}
+
STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *ssl) {
if (ssl == NULL) {
return NULL;
@@ -1484,19 +1474,16 @@
}
const char *SSL_get_cipher_list(const SSL *ssl, int n) {
- const SSL_CIPHER *c;
- STACK_OF(SSL_CIPHER) *sk;
-
if (ssl == NULL) {
return NULL;
}
- sk = SSL_get_ciphers(ssl);
+ STACK_OF(SSL_CIPHER) *sk = SSL_get_ciphers(ssl);
if (sk == NULL || n < 0 || (size_t)n >= sk_SSL_CIPHER_num(sk)) {
return NULL;
}
- c = sk_SSL_CIPHER_value(sk, n);
+ const SSL_CIPHER *c = sk_SSL_CIPHER_value(sk, n);
if (c == NULL) {
return NULL;
}
@@ -1902,9 +1889,9 @@
CRYPTO_MUTEX_unlock_write(&ctx->lock);
if (flush_cache) {
- struct timeval now;
+ struct OPENSSL_timeval now;
ssl_get_current_time(ssl, &now);
- SSL_CTX_flush_sessions(ctx, (long)now.tv_sec);
+ SSL_CTX_flush_sessions(ctx, now.tv_sec);
}
}
}
@@ -2566,10 +2553,6 @@
ctx->grease_enabled = !!enabled;
}
-void SSL_CTX_set_short_header_enabled(SSL_CTX *ctx, int enabled) {
- ctx->short_header_enabled = !!enabled;
-}
-
int SSL_clear(SSL *ssl) {
/* In OpenSSL, reusing a client |SSL| with |SSL_clear| causes the previously
* established session to be offered the next time around. wpa_supplicant
@@ -2700,9 +2683,20 @@
return SSL_set1_curves(ssl, &nid, 1);
}
-void ssl_get_current_time(const SSL *ssl, struct timeval *out_clock) {
+void ssl_get_current_time(const SSL *ssl, struct OPENSSL_timeval *out_clock) {
if (ssl->ctx->current_time_cb != NULL) {
- ssl->ctx->current_time_cb(ssl, out_clock);
+ /* TODO(davidben): Update current_time_cb to use OPENSSL_timeval. See
+ * https://crbug.com/boringssl/155. */
+ struct timeval clock;
+ ssl->ctx->current_time_cb(ssl, &clock);
+ if (clock.tv_sec < 0) {
+ assert(0);
+ out_clock->tv_sec = 0;
+ out_clock->tv_usec = 0;
+ } else {
+ out_clock->tv_sec = (uint64_t)clock.tv_sec;
+ out_clock->tv_usec = (uint32_t)clock.tv_usec;
+ }
return;
}
@@ -2712,10 +2706,25 @@
#elif defined(OPENSSL_WINDOWS)
struct _timeb time;
_ftime(&time);
- out_clock->tv_sec = time.time;
- out_clock->tv_usec = time.millitm * 1000;
+ if (time.time < 0) {
+ assert(0);
+ out_clock->tv_sec = 0;
+ out_clock->tv_usec = 0;
+ } else {
+ out_clock->tv_sec = time.time;
+ out_clock->tv_usec = time.millitm * 1000;
+ }
#else
- gettimeofday(out_clock, NULL);
+ struct timeval clock;
+ gettimeofday(&clock, NULL);
+ if (clock.tv_sec < 0) {
+ assert(0);
+ out_clock->tv_sec = 0;
+ out_clock->tv_usec = 0;
+ } else {
+ out_clock->tv_sec = (uint64_t)clock.tv_sec;
+ out_clock->tv_usec = (uint32_t)clock.tv_usec;
+ }
#endif
}
diff --git a/src/ssl/ssl_privkey.c b/src/ssl/ssl_privkey.c
index 7962247..c5441de 100644
--- a/src/ssl/ssl_privkey.c
+++ b/src/ssl/ssl_privkey.c
@@ -304,8 +304,7 @@
int ssl_is_ecdsa_key_type(int type) {
switch (type) {
- /* TODO(davidben): Remove support for |EVP_PKEY_EC| key types. */
- case EVP_PKEY_EC:
+ case NID_secp224r1:
case NID_X9_62_prime256v1:
case NID_secp384r1:
case NID_secp521r1:
diff --git a/src/ssl/ssl_session.c b/src/ssl/ssl_session.c
index bbe88c3..c9390d2 100644
--- a/src/ssl/ssl_session.c
+++ b/src/ssl/ssl_session.c
@@ -173,7 +173,7 @@
session->references = 1;
session->timeout = SSL_DEFAULT_SESSION_TIMEOUT;
session->auth_timeout = SSL_DEFAULT_SESSION_TIMEOUT;
- session->time = (long)time(NULL);
+ session->time = time(NULL);
CRYPTO_new_ex_data(&session->ex_data);
return session;
}
@@ -315,14 +315,12 @@
}
void ssl_session_rebase_time(SSL *ssl, SSL_SESSION *session) {
- struct timeval now;
+ struct OPENSSL_timeval now;
ssl_get_current_time(ssl, &now);
- /* To avoid overflows and underflows, if we've gone back in time or any value
- * is negative, update the time, but mark the session expired. */
- if (session->time > now.tv_sec ||
- session->time < 0 ||
- now.tv_sec < 0) {
+ /* To avoid overflows and underflows, if we've gone back in time, update the
+ * time, but mark the session expired. */
+ if (session->time > now.tv_sec) {
session->time = now.tv_sec;
session->timeout = 0;
session->auth_timeout = 0;
@@ -331,7 +329,7 @@
/* Adjust the session time and timeouts. If the session has already expired,
* clamp the timeouts at zero. */
- long delta = now.tv_sec - session->time;
+ uint64_t delta = now.tv_sec - session->time;
session->time = now.tv_sec;
if (session->timeout < delta) {
session->timeout = 0;
@@ -345,7 +343,8 @@
}
}
-void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session, long timeout) {
+void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session,
+ uint32_t timeout) {
/* Rebase the timestamp relative to the current time so |timeout| is measured
* correctly. */
ssl_session_rebase_time(ssl, session);
@@ -395,11 +394,11 @@
return session->session_id;
}
-long SSL_SESSION_get_timeout(const SSL_SESSION *session) {
+uint32_t SSL_SESSION_get_timeout(const SSL_SESSION *session) {
return session->timeout;
}
-long SSL_SESSION_get_time(const SSL_SESSION *session) {
+uint64_t SSL_SESSION_get_time(const SSL_SESSION *session) {
if (session == NULL) {
/* NULL should crash, but silently accept it here for compatibility. */
return 0;
@@ -424,7 +423,7 @@
return max_out;
}
-long SSL_SESSION_set_time(SSL_SESSION *session, long time) {
+uint64_t SSL_SESSION_set_time(SSL_SESSION *session, uint64_t time) {
if (session == NULL) {
return 0;
}
@@ -433,7 +432,7 @@
return time;
}
-long SSL_SESSION_set_timeout(SSL_SESSION *session, long timeout) {
+uint32_t SSL_SESSION_set_timeout(SSL_SESSION *session, uint32_t timeout) {
if (session == NULL) {
return 0;
}
@@ -528,7 +527,7 @@
session->ssl_version = ssl->version;
/* Fill in the time from the |SSL_CTX|'s clock. */
- struct timeval now;
+ struct OPENSSL_timeval now;
ssl_get_current_time(ssl, &now);
session->time = now.tv_sec;
@@ -689,15 +688,15 @@
return 0;
}
- struct timeval now;
+ struct OPENSSL_timeval now;
ssl_get_current_time(ssl, &now);
/* Reject tickets from the future to avoid underflow. */
- if ((long)now.tv_sec < session->time) {
+ if (now.tv_sec < session->time) {
return 0;
}
- return session->timeout > (long)now.tv_sec - session->time;
+ return session->timeout > now.tv_sec - session->time;
}
int ssl_session_is_resumable(const SSL_HANDSHAKE *hs,
@@ -933,7 +932,7 @@
}
}
-long SSL_CTX_set_timeout(SSL_CTX *ctx, long timeout) {
+uint32_t SSL_CTX_set_timeout(SSL_CTX *ctx, uint32_t timeout) {
if (ctx == NULL) {
return 0;
}
@@ -943,12 +942,12 @@
timeout = SSL_DEFAULT_SESSION_TIMEOUT;
}
- long old_timeout = ctx->session_timeout;
+ uint32_t old_timeout = ctx->session_timeout;
ctx->session_timeout = timeout;
return old_timeout;
}
-long SSL_CTX_get_timeout(const SSL_CTX *ctx) {
+uint32_t SSL_CTX_get_timeout(const SSL_CTX *ctx) {
if (ctx == NULL) {
return 0;
}
@@ -956,13 +955,13 @@
return ctx->session_timeout;
}
-void SSL_CTX_set_session_psk_dhe_timeout(SSL_CTX *ctx, long timeout) {
+void SSL_CTX_set_session_psk_dhe_timeout(SSL_CTX *ctx, uint32_t timeout) {
ctx->session_psk_dhe_timeout = timeout;
}
typedef struct timeout_param_st {
SSL_CTX *ctx;
- long time;
+ uint64_t time;
LHASH_OF(SSL_SESSION) *cache;
} TIMEOUT_PARAM;
@@ -970,6 +969,7 @@
TIMEOUT_PARAM *param = void_param;
if (param->time == 0 ||
+ session->time + session->timeout < session->time ||
param->time > (session->time + session->timeout)) {
/* timeout */
/* The reason we don't call SSL_CTX_remove_session() is to
@@ -984,7 +984,7 @@
}
}
-void SSL_CTX_flush_sessions(SSL_CTX *ctx, long time) {
+void SSL_CTX_flush_sessions(SSL_CTX *ctx, uint64_t time) {
TIMEOUT_PARAM tp;
tp.ctx = ctx;
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index 97bcab3..4180463 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -990,12 +990,25 @@
bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
ASSERT_TRUE(ssl);
- STACK_OF(X509_NAME) *stack = sk_X509_NAME_new_null();
- ASSERT_TRUE(stack);
- // |SSL_set_client_CA_list| takes ownership.
- SSL_set_client_CA_list(ssl.get(), stack);
+ bssl::UniquePtr<X509_NAME> name(X509_NAME_new());
+ ASSERT_TRUE(name);
- EXPECT_EQ(stack, SSL_get_client_CA_list(ssl.get()));
+ bssl::UniquePtr<X509_NAME> name_dup(X509_NAME_dup(name.get()));
+ ASSERT_TRUE(name_dup);
+
+ bssl::UniquePtr<STACK_OF(X509_NAME)> stack(sk_X509_NAME_new_null());
+ ASSERT_TRUE(stack);
+
+ ASSERT_TRUE(sk_X509_NAME_push(stack.get(), name_dup.get()));
+ name_dup.release();
+
+ // |SSL_set_client_CA_list| takes ownership.
+ SSL_set_client_CA_list(ssl.get(), stack.release());
+
+ STACK_OF(X509_NAME) *result = SSL_get_client_CA_list(ssl.get());
+ ASSERT_TRUE(result);
+ ASSERT_EQ(1u, sk_X509_NAME_num(result));
+ EXPECT_EQ(0, X509_NAME_cmp(sk_X509_NAME_value(result, 0), name.get()));
}
static void AppendSession(SSL_SESSION *session, void *arg) {
diff --git a/src/ssl/ssl_x509.c b/src/ssl/ssl_x509.c
index 2955c21..9a396d0 100644
--- a/src/ssl/ssl_x509.c
+++ b/src/ssl/ssl_x509.c
@@ -152,9 +152,24 @@
#include <openssl/x509_vfy.h>
#include "internal.h"
+#include "../crypto/internal.h"
+/* check_ssl_x509_method asserts that |ssl| has the X509-based method
+ * installed. Calling an X509-based method on an |ssl| with a different method
+ * will likely misbehave and possibly crash or leak memory. */
+static void check_ssl_x509_method(const SSL *ssl) {
+ assert(ssl == NULL || ssl->ctx->x509_method == &ssl_crypto_x509_method);
+}
+
+/* check_ssl_ctx_x509_method acts like |check_ssl_x509_method|, but for an
+ * |SSL_CTX|. */
+static void check_ssl_ctx_x509_method(const SSL_CTX *ctx) {
+ assert(ctx == NULL || ctx->x509_method == &ssl_crypto_x509_method);
+}
+
X509 *SSL_get_peer_certificate(const SSL *ssl) {
+ check_ssl_x509_method(ssl);
if (ssl == NULL) {
return NULL;
}
@@ -167,6 +182,7 @@
}
STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *ssl) {
+ check_ssl_x509_method(ssl);
if (ssl == NULL) {
return NULL;
}
@@ -203,6 +219,7 @@
}
STACK_OF(X509) *SSL_get_peer_full_cert_chain(const SSL *ssl) {
+ check_ssl_x509_method(ssl);
SSL_SESSION *session = SSL_get_session(ssl);
if (session == NULL) {
return NULL;
@@ -212,54 +229,74 @@
}
int SSL_CTX_set_purpose(SSL_CTX *ctx, int purpose) {
+ check_ssl_ctx_x509_method(ctx);
return X509_VERIFY_PARAM_set_purpose(ctx->param, purpose);
}
int SSL_set_purpose(SSL *ssl, int purpose) {
+ check_ssl_x509_method(ssl);
return X509_VERIFY_PARAM_set_purpose(ssl->param, purpose);
}
int SSL_CTX_set_trust(SSL_CTX *ctx, int trust) {
+ check_ssl_ctx_x509_method(ctx);
return X509_VERIFY_PARAM_set_trust(ctx->param, trust);
}
int SSL_set_trust(SSL *ssl, int trust) {
+ check_ssl_x509_method(ssl);
return X509_VERIFY_PARAM_set_trust(ssl->param, trust);
}
int SSL_CTX_set1_param(SSL_CTX *ctx, const X509_VERIFY_PARAM *param) {
+ check_ssl_ctx_x509_method(ctx);
return X509_VERIFY_PARAM_set1(ctx->param, param);
}
int SSL_set1_param(SSL *ssl, const X509_VERIFY_PARAM *param) {
+ check_ssl_x509_method(ssl);
return X509_VERIFY_PARAM_set1(ssl->param, param);
}
-X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx) { return ctx->param; }
+X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx) {
+ check_ssl_ctx_x509_method(ctx);
+ return ctx->param;
+}
-X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl) { return ssl->param; }
+X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl) {
+ check_ssl_x509_method(ssl);
+ return ssl->param;
+}
int SSL_get_verify_depth(const SSL *ssl) {
+ check_ssl_x509_method(ssl);
return X509_VERIFY_PARAM_get_depth(ssl->param);
}
int (*SSL_get_verify_callback(const SSL *ssl))(int, X509_STORE_CTX *) {
+ check_ssl_x509_method(ssl);
return ssl->verify_callback;
}
-int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) { return ctx->verify_mode; }
+int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) {
+ check_ssl_ctx_x509_method(ctx);
+ return ctx->verify_mode;
+}
int SSL_CTX_get_verify_depth(const SSL_CTX *ctx) {
+ check_ssl_ctx_x509_method(ctx);
return X509_VERIFY_PARAM_get_depth(ctx->param);
}
int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))(
int ok, X509_STORE_CTX *store_ctx) {
+ check_ssl_ctx_x509_method(ctx);
return ctx->default_verify_callback;
}
void SSL_set_verify(SSL *ssl, int mode,
int (*callback)(int ok, X509_STORE_CTX *store_ctx)) {
+ check_ssl_x509_method(ssl);
ssl->verify_mode = mode;
if (callback != NULL) {
ssl->verify_callback = callback;
@@ -267,6 +304,7 @@
}
void SSL_set_verify_depth(SSL *ssl, int depth) {
+ check_ssl_x509_method(ssl);
X509_VERIFY_PARAM_set_depth(ssl->param, depth);
}
@@ -274,36 +312,43 @@
int (*cb)(X509_STORE_CTX *store_ctx,
void *arg),
void *arg) {
+ check_ssl_ctx_x509_method(ctx);
ctx->app_verify_callback = cb;
ctx->app_verify_arg = arg;
}
void SSL_CTX_set_verify(SSL_CTX *ctx, int mode,
int (*cb)(int, X509_STORE_CTX *)) {
+ check_ssl_ctx_x509_method(ctx);
ctx->verify_mode = mode;
ctx->default_verify_callback = cb;
}
void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) {
+ check_ssl_ctx_x509_method(ctx);
X509_VERIFY_PARAM_set_depth(ctx->param, depth);
}
int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx) {
+ check_ssl_ctx_x509_method(ctx);
return X509_STORE_set_default_paths(ctx->cert_store);
}
int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *ca_file,
const char *ca_dir) {
+ check_ssl_ctx_x509_method(ctx);
return X509_STORE_load_locations(ctx->cert_store, ca_file, ca_dir);
}
void SSL_set_verify_result(SSL *ssl, long result) {
+ check_ssl_x509_method(ssl);
if (result != X509_V_OK) {
abort();
}
}
long SSL_get_verify_result(const SSL *ssl) {
+ check_ssl_x509_method(ssl);
SSL_SESSION *session = SSL_get_session(ssl);
if (session == NULL) {
return X509_V_ERR_INVALID_CALL;
@@ -312,32 +357,142 @@
}
X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) {
+ check_ssl_ctx_x509_method(ctx);
return ctx->cert_store;
}
void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store) {
+ check_ssl_ctx_x509_method(ctx);
X509_STORE_free(ctx->cert_store);
ctx->cert_store = store;
}
-static void ssl_crypto_x509_flush_cached_leaf(CERT *cert) {
+/* x509_to_buffer returns a |CRYPTO_BUFFER| that contains the serialised
+ * contents of |x509|. */
+static CRYPTO_BUFFER *x509_to_buffer(X509 *x509) {
+ uint8_t *buf = NULL;
+ int cert_len = i2d_X509(x509, &buf);
+ if (cert_len <= 0) {
+ return 0;
+ }
+
+ CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(buf, cert_len, NULL);
+ OPENSSL_free(buf);
+
+ return buffer;
+}
+
+/* new_leafless_chain returns a fresh stack of buffers set to {NULL}. */
+static STACK_OF(CRYPTO_BUFFER) *new_leafless_chain(void) {
+ STACK_OF(CRYPTO_BUFFER) *chain = sk_CRYPTO_BUFFER_new_null();
+ if (chain == NULL) {
+ return NULL;
+ }
+
+ if (!sk_CRYPTO_BUFFER_push(chain, NULL)) {
+ sk_CRYPTO_BUFFER_free(chain);
+ return NULL;
+ }
+
+ return chain;
+}
+
+/* ssl_cert_set_chain sets elements 1.. of |cert->chain| to the serialised
+ * forms of elements of |chain|. It returns one on success or zero on error, in
+ * which case no change to |cert->chain| is made. It preverses the existing
+ * leaf from |cert->chain|, if any. */
+static int ssl_cert_set_chain(CERT *cert, STACK_OF(X509) *chain) {
+ STACK_OF(CRYPTO_BUFFER) *new_chain = NULL;
+
+ if (cert->chain != NULL) {
+ new_chain = sk_CRYPTO_BUFFER_new_null();
+ if (new_chain == NULL) {
+ return 0;
+ }
+
+ CRYPTO_BUFFER *leaf = sk_CRYPTO_BUFFER_value(cert->chain, 0);
+ if (!sk_CRYPTO_BUFFER_push(new_chain, leaf)) {
+ goto err;
+ }
+ /* |leaf| might be NULL if it's a “leafless” chain. */
+ if (leaf != NULL) {
+ CRYPTO_BUFFER_up_ref(leaf);
+ }
+ }
+
+ for (size_t i = 0; i < sk_X509_num(chain); i++) {
+ if (new_chain == NULL) {
+ new_chain = new_leafless_chain();
+ if (new_chain == NULL) {
+ goto err;
+ }
+ }
+
+ CRYPTO_BUFFER *buffer = x509_to_buffer(sk_X509_value(chain, i));
+ if (buffer == NULL ||
+ !sk_CRYPTO_BUFFER_push(new_chain, buffer)) {
+ CRYPTO_BUFFER_free(buffer);
+ goto err;
+ }
+ }
+
+ sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free);
+ cert->chain = new_chain;
+
+ return 1;
+
+err:
+ sk_CRYPTO_BUFFER_pop_free(new_chain, CRYPTO_BUFFER_free);
+ return 0;
+}
+
+static void ssl_crypto_x509_cert_flush_cached_leaf(CERT *cert) {
X509_free(cert->x509_leaf);
cert->x509_leaf = NULL;
}
-static void ssl_crypto_x509_flush_cached_chain(CERT *cert) {
+static void ssl_crypto_x509_cert_flush_cached_chain(CERT *cert) {
sk_X509_pop_free(cert->x509_chain, X509_free);
cert->x509_chain = NULL;
}
-static void ssl_crypto_x509_clear(CERT *cert) {
- ssl_crypto_x509_flush_cached_leaf(cert);
- ssl_crypto_x509_flush_cached_chain(cert);
+static int ssl_crypto_x509_check_client_CA_list(
+ STACK_OF(CRYPTO_BUFFER) *names) {
+ for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(names); i++) {
+ const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(names, i);
+ const uint8_t *inp = CRYPTO_BUFFER_data(buffer);
+ X509_NAME *name = d2i_X509_NAME(NULL, &inp, CRYPTO_BUFFER_len(buffer));
+ const int ok = name != NULL && inp == CRYPTO_BUFFER_data(buffer) +
+ CRYPTO_BUFFER_len(buffer);
+ X509_NAME_free(name);
+ if (!ok) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void ssl_crypto_x509_cert_clear(CERT *cert) {
+ ssl_crypto_x509_cert_flush_cached_leaf(cert);
+ ssl_crypto_x509_cert_flush_cached_chain(cert);
X509_free(cert->x509_stash);
cert->x509_stash = NULL;
}
+static void ssl_crypto_x509_cert_free(CERT *cert) {
+ ssl_crypto_x509_cert_clear(cert);
+ X509_STORE_free(cert->verify_store);
+}
+
+static void ssl_crypto_x509_cert_dup(CERT *new_cert, const CERT *cert) {
+ if (cert->verify_store != NULL) {
+ X509_STORE_up_ref(cert->verify_store);
+ new_cert->verify_store = cert->verify_store;
+ }
+}
+
static int ssl_crypto_x509_session_cache_objects(SSL_SESSION *sess) {
STACK_OF(X509) *chain = NULL;
const size_t num_certs = sk_CRYPTO_BUFFER_num(sess->certs);
@@ -410,30 +565,171 @@
session->x509_chain_without_leaf = NULL;
}
-const SSL_X509_METHOD ssl_crypto_x509_method = {
- ssl_crypto_x509_clear,
- ssl_crypto_x509_flush_cached_chain,
- ssl_crypto_x509_flush_cached_leaf,
- ssl_crypto_x509_session_cache_objects,
- ssl_crypto_x509_session_dup,
- ssl_crypto_x509_session_clear,
-};
-
-/* x509_to_buffer returns a |CRYPTO_BUFFER| that contains the serialised
- * contents of |x509|. */
-static CRYPTO_BUFFER *x509_to_buffer(X509 *x509) {
- uint8_t *buf = NULL;
- int cert_len = i2d_X509(x509, &buf);
- if (cert_len <= 0) {
+static int ssl_crypto_x509_session_verify_cert_chain(SSL_SESSION *session,
+ SSL *ssl) {
+ STACK_OF(X509) *const cert_chain = session->x509_chain;
+ if (cert_chain == NULL || sk_X509_num(cert_chain) == 0) {
return 0;
}
- CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(buf, cert_len, NULL);
- OPENSSL_free(buf);
+ X509_STORE *verify_store = ssl->ctx->cert_store;
+ if (ssl->cert->verify_store != NULL) {
+ verify_store = ssl->cert->verify_store;
+ }
- return buffer;
+ X509 *leaf = sk_X509_value(cert_chain, 0);
+ int ret = 0;
+ X509_STORE_CTX ctx;
+ if (!X509_STORE_CTX_init(&ctx, verify_store, leaf, cert_chain)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
+ return 0;
+ }
+ if (!X509_STORE_CTX_set_ex_data(&ctx, SSL_get_ex_data_X509_STORE_CTX_idx(),
+ ssl)) {
+ goto err;
+ }
+
+ /* We need to inherit the verify parameters. These can be determined by the
+ * context: if its a server it will verify SSL client certificates or vice
+ * versa. */
+ X509_STORE_CTX_set_default(&ctx, ssl->server ? "ssl_client" : "ssl_server");
+
+ /* Anything non-default in "param" should overwrite anything in the ctx. */
+ X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), ssl->param);
+
+ if (ssl->verify_callback) {
+ X509_STORE_CTX_set_verify_cb(&ctx, ssl->verify_callback);
+ }
+
+ int verify_ret;
+ if (ssl->ctx->app_verify_callback != NULL) {
+ verify_ret = ssl->ctx->app_verify_callback(&ctx, ssl->ctx->app_verify_arg);
+ } else {
+ verify_ret = X509_verify_cert(&ctx);
+ }
+
+ session->verify_result = ctx.error;
+
+ /* 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);
+ goto err;
+ }
+
+ ERR_clear_error();
+ ret = 1;
+
+err:
+ X509_STORE_CTX_cleanup(&ctx);
+ return ret;
}
+static void ssl_crypto_x509_hs_flush_cached_ca_names(SSL_HANDSHAKE *hs) {
+ sk_X509_NAME_pop_free(hs->cached_x509_ca_names, X509_NAME_free);
+ hs->cached_x509_ca_names = NULL;
+}
+
+static int ssl_crypto_x509_ssl_new(SSL *ssl) {
+ ssl->param = X509_VERIFY_PARAM_new();
+ if (ssl->param == NULL) {
+ return 0;
+ }
+ X509_VERIFY_PARAM_inherit(ssl->param, ssl->ctx->param);
+ return 1;
+}
+
+static void ssl_crypto_x509_ssl_flush_cached_client_CA(SSL *ssl) {
+ sk_X509_NAME_pop_free(ssl->cached_x509_client_CA, X509_NAME_free);
+ ssl->cached_x509_client_CA = NULL;
+}
+
+static void ssl_crypto_x509_ssl_free(SSL *ssl) {
+ ssl_crypto_x509_ssl_flush_cached_client_CA(ssl);
+ X509_VERIFY_PARAM_free(ssl->param);
+}
+
+static int ssl_crypto_x509_ssl_auto_chain_if_needed(SSL *ssl) {
+ /* Only build a chain if there are no intermediates configured and the feature
+ * isn't disabled. */
+ if ((ssl->mode & SSL_MODE_NO_AUTO_CHAIN) ||
+ !ssl_has_certificate(ssl) ||
+ ssl->cert->chain == NULL ||
+ sk_CRYPTO_BUFFER_num(ssl->cert->chain) > 1) {
+ return 1;
+ }
+
+ X509 *leaf =
+ X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0));
+ if (!leaf) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
+ return 0;
+ }
+
+ X509_STORE_CTX ctx;
+ if (!X509_STORE_CTX_init(&ctx, ssl->ctx->cert_store, leaf, NULL)) {
+ X509_free(leaf);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
+ return 0;
+ }
+
+ /* Attempt to build a chain, ignoring the result. */
+ X509_verify_cert(&ctx);
+ X509_free(leaf);
+ ERR_clear_error();
+
+ /* Remove the leaf from the generated chain. */
+ X509_free(sk_X509_shift(ctx.chain));
+
+ const int ok = ssl_cert_set_chain(ssl->cert, ctx.chain);
+ X509_STORE_CTX_cleanup(&ctx);
+ if (!ok) {
+ return 0;
+ }
+
+ ssl_crypto_x509_cert_flush_cached_chain(ssl->cert);
+
+ return 1;
+}
+
+static void ssl_crypto_x509_ssl_ctx_flush_cached_client_CA(SSL_CTX *ctx) {
+ sk_X509_NAME_pop_free(ctx->cached_x509_client_CA, X509_NAME_free);
+ ctx->cached_x509_client_CA = NULL;
+}
+
+static int ssl_crypto_x509_ssl_ctx_new(SSL_CTX *ctx) {
+ ctx->cert_store = X509_STORE_new();
+ ctx->param = X509_VERIFY_PARAM_new();
+ return (ctx->cert_store != NULL && ctx->param != NULL);
+}
+
+static void ssl_crypto_x509_ssl_ctx_free(SSL_CTX *ctx) {
+ ssl_crypto_x509_ssl_ctx_flush_cached_client_CA(ctx);
+ X509_VERIFY_PARAM_free(ctx->param);
+ X509_STORE_free(ctx->cert_store);
+}
+
+const SSL_X509_METHOD ssl_crypto_x509_method = {
+ ssl_crypto_x509_check_client_CA_list,
+ ssl_crypto_x509_cert_clear,
+ ssl_crypto_x509_cert_free,
+ ssl_crypto_x509_cert_dup,
+ ssl_crypto_x509_cert_flush_cached_chain,
+ ssl_crypto_x509_cert_flush_cached_leaf,
+ ssl_crypto_x509_session_cache_objects,
+ ssl_crypto_x509_session_dup,
+ ssl_crypto_x509_session_clear,
+ ssl_crypto_x509_session_verify_cert_chain,
+ ssl_crypto_x509_hs_flush_cached_ca_names,
+ ssl_crypto_x509_ssl_new,
+ ssl_crypto_x509_ssl_free,
+ ssl_crypto_x509_ssl_flush_cached_client_CA,
+ ssl_crypto_x509_ssl_auto_chain_if_needed,
+ ssl_crypto_x509_ssl_ctx_new,
+ ssl_crypto_x509_ssl_ctx_free,
+ ssl_crypto_x509_ssl_ctx_flush_cached_client_CA,
+};
+
static int ssl_use_certificate(CERT *cert, X509 *x) {
if (x == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
@@ -451,10 +747,12 @@
}
int SSL_use_certificate(SSL *ssl, X509 *x) {
+ check_ssl_x509_method(ssl);
return ssl_use_certificate(ssl->cert, x);
}
int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) {
+ check_ssl_ctx_x509_method(ctx);
return ssl_use_certificate(ctx->cert, x);
}
@@ -487,75 +785,16 @@
}
X509 *SSL_get_certificate(const SSL *ssl) {
+ check_ssl_x509_method(ssl);
return ssl_cert_get0_leaf(ssl->cert);
}
X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) {
- return ssl_cert_get0_leaf(ctx->cert);
-}
-
-/* new_leafless_chain returns a fresh stack of buffers set to {NULL}. */
-static STACK_OF(CRYPTO_BUFFER) *new_leafless_chain(void) {
- STACK_OF(CRYPTO_BUFFER) *chain = sk_CRYPTO_BUFFER_new_null();
- if (chain == NULL) {
- return NULL;
- }
-
- if (!sk_CRYPTO_BUFFER_push(chain, NULL)) {
- sk_CRYPTO_BUFFER_free(chain);
- return NULL;
- }
-
- return chain;
-}
-
-/* ssl_cert_set_chain sets elements 1.. of |cert->chain| to the serialised
- * forms of elements of |chain|. It returns one on success or zero on error, in
- * which case no change to |cert->chain| is made. It preverses the existing
- * leaf from |cert->chain|, if any. */
-static int ssl_cert_set_chain(CERT *cert, STACK_OF(X509) *chain) {
- STACK_OF(CRYPTO_BUFFER) *new_chain = NULL;
-
- if (cert->chain != NULL) {
- new_chain = sk_CRYPTO_BUFFER_new_null();
- if (new_chain == NULL) {
- return 0;
- }
-
- CRYPTO_BUFFER *leaf = sk_CRYPTO_BUFFER_value(cert->chain, 0);
- if (!sk_CRYPTO_BUFFER_push(new_chain, leaf)) {
- goto err;
- }
- /* |leaf| might be NULL if it's a “leafless” chain. */
- if (leaf != NULL) {
- CRYPTO_BUFFER_up_ref(leaf);
- }
- }
-
- for (size_t i = 0; i < sk_X509_num(chain); i++) {
- if (new_chain == NULL) {
- new_chain = new_leafless_chain();
- if (new_chain == NULL) {
- goto err;
- }
- }
-
- CRYPTO_BUFFER *buffer = x509_to_buffer(sk_X509_value(chain, i));
- if (buffer == NULL ||
- !sk_CRYPTO_BUFFER_push(new_chain, buffer)) {
- CRYPTO_BUFFER_free(buffer);
- goto err;
- }
- }
-
- sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free);
- cert->chain = new_chain;
-
- return 1;
-
-err:
- sk_CRYPTO_BUFFER_pop_free(new_chain, CRYPTO_BUFFER_free);
- return 0;
+ check_ssl_ctx_x509_method(ctx);
+ CRYPTO_MUTEX_lock_write((CRYPTO_MUTEX *) &ctx->lock);
+ X509 *ret = ssl_cert_get0_leaf(ctx->cert);
+ CRYPTO_MUTEX_unlock_write((CRYPTO_MUTEX *) &ctx->lock);
+ return ret;
}
static int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain) {
@@ -564,7 +803,7 @@
}
sk_X509_pop_free(chain, X509_free);
- ssl_crypto_x509_flush_cached_chain(cert);
+ ssl_crypto_x509_cert_flush_cached_chain(cert);
return 1;
}
@@ -573,7 +812,7 @@
return 0;
}
- ssl_crypto_x509_flush_cached_chain(cert);
+ ssl_crypto_x509_cert_flush_cached_chain(cert);
return 1;
}
@@ -613,7 +852,7 @@
X509_free(cert->x509_stash);
cert->x509_stash = x509;
- ssl_crypto_x509_flush_cached_chain(cert);
+ ssl_crypto_x509_cert_flush_cached_chain(cert);
return 1;
}
@@ -622,101 +861,70 @@
return 0;
}
- ssl_crypto_x509_flush_cached_chain(cert);
+ ssl_crypto_x509_cert_flush_cached_chain(cert);
return 1;
}
int SSL_CTX_set0_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) {
+ check_ssl_ctx_x509_method(ctx);
return ssl_cert_set0_chain(ctx->cert, chain);
}
int SSL_CTX_set1_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) {
+ check_ssl_ctx_x509_method(ctx);
return ssl_cert_set1_chain(ctx->cert, chain);
}
int SSL_set0_chain(SSL *ssl, STACK_OF(X509) *chain) {
+ check_ssl_x509_method(ssl);
return ssl_cert_set0_chain(ssl->cert, chain);
}
int SSL_set1_chain(SSL *ssl, STACK_OF(X509) *chain) {
+ check_ssl_x509_method(ssl);
return ssl_cert_set1_chain(ssl->cert, chain);
}
int SSL_CTX_add0_chain_cert(SSL_CTX *ctx, X509 *x509) {
+ check_ssl_ctx_x509_method(ctx);
return ssl_cert_add0_chain_cert(ctx->cert, x509);
}
int SSL_CTX_add1_chain_cert(SSL_CTX *ctx, X509 *x509) {
+ check_ssl_ctx_x509_method(ctx);
return ssl_cert_add1_chain_cert(ctx->cert, x509);
}
int SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *x509) {
+ check_ssl_ctx_x509_method(ctx);
return SSL_CTX_add0_chain_cert(ctx, x509);
}
int SSL_add0_chain_cert(SSL *ssl, X509 *x509) {
+ check_ssl_x509_method(ssl);
return ssl_cert_add0_chain_cert(ssl->cert, x509);
}
int SSL_add1_chain_cert(SSL *ssl, X509 *x509) {
+ check_ssl_x509_method(ssl);
return ssl_cert_add1_chain_cert(ssl->cert, x509);
}
int SSL_CTX_clear_chain_certs(SSL_CTX *ctx) {
+ check_ssl_ctx_x509_method(ctx);
return SSL_CTX_set0_chain(ctx, NULL);
}
int SSL_CTX_clear_extra_chain_certs(SSL_CTX *ctx) {
+ check_ssl_ctx_x509_method(ctx);
return SSL_CTX_clear_chain_certs(ctx);
}
int SSL_clear_chain_certs(SSL *ssl) {
+ check_ssl_x509_method(ssl);
return SSL_set0_chain(ssl, NULL);
}
-int ssl_auto_chain_if_needed(SSL *ssl) {
- /* Only build a chain if there are no intermediates configured and the feature
- * isn't disabled. */
- if ((ssl->mode & SSL_MODE_NO_AUTO_CHAIN) ||
- !ssl_has_certificate(ssl) ||
- ssl->cert->chain == NULL ||
- sk_CRYPTO_BUFFER_num(ssl->cert->chain) > 1) {
- return 1;
- }
-
- X509 *leaf =
- X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0));
- if (!leaf) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
- return 0;
- }
-
- X509_STORE_CTX ctx;
- if (!X509_STORE_CTX_init(&ctx, ssl->ctx->cert_store, leaf, NULL)) {
- X509_free(leaf);
- OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
- return 0;
- }
-
- /* Attempt to build a chain, ignoring the result. */
- X509_verify_cert(&ctx);
- X509_free(leaf);
- ERR_clear_error();
-
- /* Remove the leaf from the generated chain. */
- X509_free(sk_X509_shift(ctx.chain));
-
- const int ok = ssl_cert_set_chain(ssl->cert, ctx.chain);
- X509_STORE_CTX_cleanup(&ctx);
- if (!ok) {
- return 0;
- }
-
- ssl_crypto_x509_flush_cached_chain(ssl->cert);
-
- return 1;
-}
-
/* ssl_cert_cache_chain_certs fills in |cert->x509_chain| from elements 1.. of
* |cert->chain|. */
static int ssl_cert_cache_chain_certs(CERT *cert) {
@@ -752,7 +960,12 @@
}
int SSL_CTX_get0_chain_certs(const SSL_CTX *ctx, STACK_OF(X509) **out_chain) {
- if (!ssl_cert_cache_chain_certs(ctx->cert)) {
+ check_ssl_ctx_x509_method(ctx);
+ CRYPTO_MUTEX_lock_write((CRYPTO_MUTEX *) &ctx->lock);
+ const int ret = ssl_cert_cache_chain_certs(ctx->cert);
+ CRYPTO_MUTEX_unlock_write((CRYPTO_MUTEX *) &ctx->lock);
+
+ if (!ret) {
*out_chain = NULL;
return 0;
}
@@ -767,6 +980,7 @@
}
int SSL_get0_chain_certs(const SSL *ssl, STACK_OF(X509) **out_chain) {
+ check_ssl_x509_method(ssl);
if (!ssl_cert_cache_chain_certs(ssl->cert)) {
*out_chain = NULL;
return 0;
@@ -813,3 +1027,258 @@
*pp = CBS_data(&cbs);
return ret;
}
+
+STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *list) {
+ return sk_X509_NAME_deep_copy(list, X509_NAME_dup, X509_NAME_free);
+}
+
+static void set_client_CA_list(STACK_OF(CRYPTO_BUFFER) **ca_list,
+ const STACK_OF(X509_NAME) *name_list,
+ CRYPTO_BUFFER_POOL *pool) {
+ STACK_OF(CRYPTO_BUFFER) *buffers = sk_CRYPTO_BUFFER_new_null();
+ if (buffers == NULL) {
+ return;
+ }
+
+ for (size_t i = 0; i < sk_X509_NAME_num(name_list); i++) {
+ X509_NAME *name = sk_X509_NAME_value(name_list, i);
+ uint8_t *outp = NULL;
+ int len = i2d_X509_NAME(name, &outp);
+ if (len < 0) {
+ goto err;
+ }
+
+ CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(outp, len, pool);
+ OPENSSL_free(outp);
+ if (buffer == NULL ||
+ !sk_CRYPTO_BUFFER_push(buffers, buffer)) {
+ CRYPTO_BUFFER_free(buffer);
+ goto err;
+ }
+ }
+
+ sk_CRYPTO_BUFFER_pop_free(*ca_list, CRYPTO_BUFFER_free);
+ *ca_list = buffers;
+ return;
+
+err:
+ sk_CRYPTO_BUFFER_pop_free(buffers, CRYPTO_BUFFER_free);
+}
+
+void SSL_set_client_CA_list(SSL *ssl, STACK_OF(X509_NAME) *name_list) {
+ check_ssl_x509_method(ssl);
+ ssl->ctx->x509_method->ssl_flush_cached_client_CA(ssl);
+ set_client_CA_list(&ssl->client_CA, name_list, ssl->ctx->pool);
+ sk_X509_NAME_pop_free(name_list, X509_NAME_free);
+}
+
+void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list) {
+ check_ssl_ctx_x509_method(ctx);
+ ctx->x509_method->ssl_ctx_flush_cached_client_CA(ctx);
+ set_client_CA_list(&ctx->client_CA, name_list, ctx->pool);
+ sk_X509_NAME_pop_free(name_list, X509_NAME_free);
+}
+
+static STACK_OF(X509_NAME) *
+ buffer_names_to_x509(const STACK_OF(CRYPTO_BUFFER) *names,
+ STACK_OF(X509_NAME) **cached) {
+ if (names == NULL) {
+ return NULL;
+ }
+
+ if (*cached != NULL) {
+ return *cached;
+ }
+
+ STACK_OF(X509_NAME) *new_cache = sk_X509_NAME_new_null();
+ if (new_cache == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(names); i++) {
+ const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(names, i);
+ const uint8_t *inp = CRYPTO_BUFFER_data(buffer);
+ X509_NAME *name = d2i_X509_NAME(NULL, &inp, CRYPTO_BUFFER_len(buffer));
+ if (name == NULL ||
+ inp != CRYPTO_BUFFER_data(buffer) + CRYPTO_BUFFER_len(buffer) ||
+ !sk_X509_NAME_push(new_cache, name)) {
+ X509_NAME_free(name);
+ goto err;
+ }
+ }
+
+ *cached = new_cache;
+ return new_cache;
+
+err:
+ sk_X509_NAME_pop_free(new_cache, X509_NAME_free);
+ return NULL;
+}
+
+STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl) {
+ check_ssl_x509_method(ssl);
+ /* For historical reasons, this function is used both to query configuration
+ * state on a server as well as handshake state on a client. However, whether
+ * |ssl| is a client or server is not known until explicitly configured with
+ * |SSL_set_connect_state|. If |handshake_func| is NULL, |ssl| is in an
+ * indeterminate mode and |ssl->server| is unset. */
+ if (ssl->handshake_func != NULL && !ssl->server) {
+ if (ssl->s3->hs != NULL) {
+ return buffer_names_to_x509(ssl->s3->hs->ca_names,
+ &ssl->s3->hs->cached_x509_ca_names);
+ }
+
+ return NULL;
+ }
+
+ if (ssl->client_CA != NULL) {
+ return buffer_names_to_x509(
+ ssl->client_CA, (STACK_OF(X509_NAME) **)&ssl->cached_x509_client_CA);
+ }
+ return buffer_names_to_x509(ssl->ctx->client_CA,
+ &ssl->ctx->cached_x509_client_CA);
+}
+
+STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx) {
+ check_ssl_ctx_x509_method(ctx);
+ CRYPTO_MUTEX_lock_write((CRYPTO_MUTEX *) &ctx->lock);
+ STACK_OF(X509_NAME) *ret = buffer_names_to_x509(
+ ctx->client_CA, (STACK_OF(X509_NAME) **)&ctx->cached_x509_client_CA);
+ CRYPTO_MUTEX_unlock_write((CRYPTO_MUTEX *) &ctx->lock);
+ return ret;
+}
+
+static int add_client_CA(STACK_OF(CRYPTO_BUFFER) **names, X509 *x509,
+ CRYPTO_BUFFER_POOL *pool) {
+ if (x509 == NULL) {
+ return 0;
+ }
+
+ uint8_t *outp = NULL;
+ int len = i2d_X509_NAME(X509_get_subject_name(x509), &outp);
+ if (len < 0) {
+ return 0;
+ }
+
+ CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(outp, len, pool);
+ OPENSSL_free(outp);
+ if (buffer == NULL) {
+ return 0;
+ }
+
+ int alloced = 0;
+ if (*names == NULL) {
+ *names = sk_CRYPTO_BUFFER_new_null();
+ alloced = 1;
+
+ if (*names == NULL) {
+ CRYPTO_BUFFER_free(buffer);
+ return 0;
+ }
+ }
+
+ if (!sk_CRYPTO_BUFFER_push(*names, buffer)) {
+ CRYPTO_BUFFER_free(buffer);
+ if (alloced) {
+ sk_CRYPTO_BUFFER_pop_free(*names, CRYPTO_BUFFER_free);
+ *names = NULL;
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+int SSL_add_client_CA(SSL *ssl, X509 *x509) {
+ check_ssl_x509_method(ssl);
+ if (!add_client_CA(&ssl->client_CA, x509, ssl->ctx->pool)) {
+ return 0;
+ }
+
+ ssl_crypto_x509_ssl_flush_cached_client_CA(ssl);
+ return 1;
+}
+
+int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x509) {
+ check_ssl_ctx_x509_method(ctx);
+ if (!add_client_CA(&ctx->client_CA, x509, ctx->pool)) {
+ return 0;
+ }
+
+ ssl_crypto_x509_ssl_ctx_flush_cached_client_CA(ctx);
+ return 1;
+}
+
+static int do_client_cert_cb(SSL *ssl, void *arg) {
+ if (ssl_has_certificate(ssl) || ssl->ctx->client_cert_cb == NULL) {
+ return 1;
+ }
+
+ X509 *x509 = NULL;
+ EVP_PKEY *pkey = NULL;
+ int ret = ssl->ctx->client_cert_cb(ssl, &x509, &pkey);
+ if (ret < 0) {
+ return -1;
+ }
+
+ if (ret != 0) {
+ if (!SSL_use_certificate(ssl, x509) ||
+ !SSL_use_PrivateKey(ssl, pkey)) {
+ return 0;
+ }
+ }
+
+ X509_free(x509);
+ EVP_PKEY_free(pkey);
+ return 1;
+}
+
+void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl,
+ X509 **out_x509,
+ EVP_PKEY **out_pkey)) {
+ check_ssl_ctx_x509_method(ctx);
+ /* Emulate the old client certificate callback with the new one. */
+ SSL_CTX_set_cert_cb(ctx, do_client_cert_cb, NULL);
+ ctx->client_cert_cb = cb;
+}
+
+static int set_cert_store(X509_STORE **store_ptr, X509_STORE *new_store,
+ int take_ref) {
+ X509_STORE_free(*store_ptr);
+ *store_ptr = new_store;
+
+ if (new_store != NULL && take_ref) {
+ X509_STORE_up_ref(new_store);
+ }
+
+ return 1;
+}
+
+int SSL_get_ex_data_X509_STORE_CTX_idx(void) {
+ /* The ex_data index to go from |X509_STORE_CTX| to |SSL| always uses the
+ * reserved app_data slot. Before ex_data was introduced, app_data was used.
+ * Avoid breaking any software which assumes |X509_STORE_CTX_get_app_data|
+ * works. */
+ return 0;
+}
+
+int SSL_CTX_set0_verify_cert_store(SSL_CTX *ctx, X509_STORE *store) {
+ check_ssl_ctx_x509_method(ctx);
+ return set_cert_store(&ctx->cert->verify_store, store, 0);
+}
+
+int SSL_CTX_set1_verify_cert_store(SSL_CTX *ctx, X509_STORE *store) {
+ check_ssl_ctx_x509_method(ctx);
+ return set_cert_store(&ctx->cert->verify_store, store, 1);
+}
+
+int SSL_set0_verify_cert_store(SSL *ssl, X509_STORE *store) {
+ check_ssl_x509_method(ssl);
+ return set_cert_store(&ssl->cert->verify_store, store, 0);
+}
+
+int SSL_set1_verify_cert_store(SSL *ssl, X509_STORE *store) {
+ check_ssl_x509_method(ssl);
+ return set_cert_store(&ssl->cert->verify_store, store, 1);
+}
diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c
index d6ef1ff..adc7344 100644
--- a/src/ssl/t1_lib.c
+++ b/src/ssl/t1_lib.c
@@ -1901,7 +1901,7 @@
return 1;
}
- struct timeval now;
+ struct OPENSSL_timeval now;
ssl_get_current_time(ssl, &now);
uint32_t ticket_age = 1000 * (now.tv_sec - ssl->session->time);
uint32_t obfuscated_ticket_age = ticket_age + ssl->session->ticket_age_add;
@@ -2403,46 +2403,6 @@
}
-/* Short record headers
- *
- * This is a non-standard extension which negotiates
- * https://github.com/tlswg/tls13-spec/pull/762 for experimenting. */
-
-static int ext_short_header_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
- SSL *const ssl = hs->ssl;
- uint16_t min_version, max_version;
- if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
- return 0;
- }
-
- if (max_version < TLS1_3_VERSION ||
- !ssl->ctx->short_header_enabled) {
- return 1;
- }
-
- return CBB_add_u16(out, TLSEXT_TYPE_short_header) &&
- CBB_add_u16(out, 0 /* empty extension */);
-}
-
-static int ext_short_header_parse_clienthello(SSL_HANDSHAKE *hs,
- uint8_t *out_alert,
- CBS *contents) {
- SSL *const ssl = hs->ssl;
- if (contents == NULL ||
- !ssl->ctx->short_header_enabled ||
- ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
- return 1;
- }
-
- if (CBS_len(contents) != 0) {
- return 0;
- }
-
- ssl->s3->short_header = 1;
- return 1;
-}
-
-
/* Negotiated Groups
*
* https://tools.ietf.org/html/rfc4492#section-5.1.2
@@ -2673,14 +2633,6 @@
ignore_parse_clienthello,
dont_add_serverhello,
},
- {
- TLSEXT_TYPE_short_header,
- NULL,
- ext_short_header_add_clienthello,
- forbid_parse_serverhello,
- ext_short_header_parse_clienthello,
- dont_add_serverhello,
- },
/* The final extension must be non-empty. WebSphere Application Server 7.0 is
* intolerant to the last extension being zero-length. See
* https://crbug.com/363583. */
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index 48d0538..984136c 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -191,6 +191,100 @@
PEM_read_bio_PrivateKey(bio.get(), NULL, NULL, NULL));
}
+static bool FromHexDigit(uint8_t *out, char c) {
+ if ('0' <= c && c <= '9') {
+ *out = c - '0';
+ return true;
+ }
+ if ('a' <= c && c <= 'f') {
+ *out = c - 'a' + 10;
+ return true;
+ }
+ if ('A' <= c && c <= 'F') {
+ *out = c - 'A' + 10;
+ return true;
+ }
+ return false;
+}
+
+static bool HexDecode(std::string *out, const std::string &in) {
+ if ((in.size() & 1) != 0) {
+ return false;
+ }
+
+ std::unique_ptr<uint8_t[]> buf(new uint8_t[in.size() / 2]);
+ for (size_t i = 0; i < in.size() / 2; i++) {
+ uint8_t high, low;
+ if (!FromHexDigit(&high, in[i*2]) ||
+ !FromHexDigit(&low, in[i*2+1])) {
+ return false;
+ }
+ buf[i] = (high << 4) | low;
+ }
+
+ out->assign(reinterpret_cast<const char *>(buf.get()), in.size() / 2);
+ return true;
+}
+
+static std::vector<std::string> SplitParts(const std::string &in,
+ const char delim) {
+ std::vector<std::string> ret;
+ size_t start = 0;
+
+ for (size_t i = 0; i < in.size(); i++) {
+ if (in[i] == delim) {
+ ret.push_back(in.substr(start, i - start));
+ start = i + 1;
+ }
+ }
+
+ ret.push_back(in.substr(start, std::string::npos));
+ return ret;
+}
+
+static std::vector<std::string> DecodeHexStrings(
+ const std::string &hex_strings) {
+ std::vector<std::string> ret;
+ const std::vector<std::string> parts = SplitParts(hex_strings, ',');
+
+ for (const auto &part : parts) {
+ std::string binary;
+ if (!HexDecode(&binary, part)) {
+ fprintf(stderr, "Bad hex string: %s\n", part.c_str());
+ return ret;
+ }
+
+ ret.push_back(binary);
+ }
+
+ return ret;
+}
+
+static bssl::UniquePtr<STACK_OF(X509_NAME)> DecodeHexX509Names(
+ const std::string &hex_names) {
+ const std::vector<std::string> der_names = DecodeHexStrings(hex_names);
+ bssl::UniquePtr<STACK_OF(X509_NAME)> ret(sk_X509_NAME_new_null());
+
+ for (const auto &der_name : der_names) {
+ const uint8_t *const data =
+ reinterpret_cast<const uint8_t *>(der_name.data());
+ const uint8_t *derp = data;
+ bssl::UniquePtr<X509_NAME> name(
+ d2i_X509_NAME(nullptr, &derp, der_name.size()));
+ if (!name || derp != data + der_name.size()) {
+ fprintf(stderr, "Failed to parse X509_NAME.\n");
+ return nullptr;
+ }
+
+ if (!sk_X509_NAME_push(ret.get(), name.get())) {
+ return nullptr;
+ }
+ name.release();
+ }
+
+ return ret;
+}
+
static int AsyncPrivateKeyType(SSL *ssl) {
EVP_PKEY *key = GetTestState(ssl)->private_key.get();
switch (EVP_PKEY_id(key)) {
@@ -509,7 +603,39 @@
}
}
- // TODO(davidben): Test |SSL_get_client_CA_list|.
+ if (!config->expected_client_ca_list.empty()) {
+ bssl::UniquePtr<STACK_OF(X509_NAME)> expected =
+ DecodeHexX509Names(config->expected_client_ca_list);
+ const size_t num_expected = sk_X509_NAME_num(expected.get());
+
+ const STACK_OF(X509_NAME) *received = SSL_get_client_CA_list(ssl);
+ const size_t num_received = sk_X509_NAME_num(received);
+
+ if (num_received != num_expected) {
+ fprintf(stderr, "expected %u names in CertificateRequest but got %u\n",
+ static_cast<unsigned>(num_expected),
+ static_cast<unsigned>(num_received));
+ return false;
+ }
+
+ for (size_t i = 0; i < num_received; i++) {
+ if (X509_NAME_cmp(sk_X509_NAME_value(received, i),
+ sk_X509_NAME_value(expected.get(), i)) != 0) {
+ fprintf(stderr, "names in CertificateRequest differ at index #%d\n",
+ static_cast<unsigned>(i));
+ return false;
+ }
+ }
+
+ STACK_OF(CRYPTO_BUFFER) *buffers = SSL_get0_server_requested_CAs(ssl);
+ if (sk_CRYPTO_BUFFER_num(buffers) != num_received) {
+ fprintf(stderr,
+ "Mismatch between SSL_get_server_requested_CAs and "
+ "SSL_get_client_CA_list.\n");
+ return false;
+ }
+ }
+
return true;
}
@@ -1026,8 +1152,14 @@
return nullptr;
}
- if (config->use_null_client_ca_list) {
- SSL_CTX_set_client_CA_list(ssl_ctx.get(), nullptr);
+ if (!config->use_client_ca_list.empty()) {
+ if (config->use_client_ca_list == "<NULL>") {
+ SSL_CTX_set_client_CA_list(ssl_ctx.get(), nullptr);
+ } else {
+ bssl::UniquePtr<STACK_OF(X509_NAME)> names =
+ DecodeHexX509Names(config->use_client_ca_list);
+ SSL_CTX_set_client_CA_list(ssl_ctx.get(), names.release());
+ }
}
if (config->enable_grease) {
@@ -1044,10 +1176,6 @@
return nullptr;
}
- if (config->enable_short_header) {
- SSL_CTX_set_short_header_enabled(ssl_ctx.get(), 1);
- }
-
if (config->enable_early_data) {
SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1);
}
@@ -1660,7 +1788,7 @@
return false;
}
if (config->is_dtls) {
- bssl::UniquePtr<BIO> packeted = PacketedBioCreate(&g_clock, !config->async);
+ bssl::UniquePtr<BIO> packeted = PacketedBioCreate(&g_clock);
if (!packeted) {
return false;
}
diff --git a/src/ssl/test/packeted_bio.cc b/src/ssl/test/packeted_bio.cc
index 835df0e..835dbfb 100644
--- a/src/ssl/test/packeted_bio.cc
+++ b/src/ssl/test/packeted_bio.cc
@@ -33,31 +33,17 @@
const uint8_t kOpcodeTimeoutAck = 't';
struct PacketedBio {
- PacketedBio(timeval *clock_arg, bool advance_clock_arg)
- : clock(clock_arg), advance_clock(advance_clock_arg) {
+ explicit PacketedBio(timeval *clock_arg)
+ : clock(clock_arg) {
OPENSSL_memset(&timeout, 0, sizeof(timeout));
- OPENSSL_memset(&read_deadline, 0, sizeof(read_deadline));
}
bool HasTimeout() const {
return timeout.tv_sec != 0 || timeout.tv_usec != 0;
}
- bool CanRead() const {
- if (read_deadline.tv_sec == 0 && read_deadline.tv_usec == 0) {
- return true;
- }
-
- if (clock->tv_sec == read_deadline.tv_sec) {
- return clock->tv_usec < read_deadline.tv_usec;
- }
- return clock->tv_sec < read_deadline.tv_sec;
- }
-
timeval timeout;
timeval *clock;
- timeval read_deadline;
- bool advance_clock;
};
PacketedBio *GetData(BIO *bio) {
@@ -123,109 +109,91 @@
BIO_clear_retry_flags(bio);
- for (;;) {
- // Check if the read deadline has passed.
- if (!data->CanRead()) {
- BIO_set_retry_read(bio);
- return -1;
- }
-
- // Read the opcode.
- uint8_t opcode;
- int ret = ReadAll(bio->next_bio, &opcode, sizeof(opcode));
- if (ret <= 0) {
- BIO_copy_next_retry(bio);
- return ret;
- }
-
- if (opcode == kOpcodeTimeout) {
- // The caller is required to advance any pending timeouts before
- // continuing.
- if (data->HasTimeout()) {
- fprintf(stderr, "Unprocessed timeout!\n");
- return -1;
- }
-
- // Process the timeout.
- uint8_t buf[8];
- ret = ReadAll(bio->next_bio, buf, sizeof(buf));
- if (ret <= 0) {
- BIO_copy_next_retry(bio);
- return ret;
- }
- uint64_t timeout = (static_cast<uint64_t>(buf[0]) << 56) |
- (static_cast<uint64_t>(buf[1]) << 48) |
- (static_cast<uint64_t>(buf[2]) << 40) |
- (static_cast<uint64_t>(buf[3]) << 32) |
- (static_cast<uint64_t>(buf[4]) << 24) |
- (static_cast<uint64_t>(buf[5]) << 16) |
- (static_cast<uint64_t>(buf[6]) << 8) |
- static_cast<uint64_t>(buf[7]);
- timeout /= 1000; // Convert nanoseconds to microseconds.
-
- data->timeout.tv_usec = timeout % 1000000;
- data->timeout.tv_sec = timeout / 1000000;
-
- // Send an ACK to the peer.
- ret = BIO_write(bio->next_bio, &kOpcodeTimeoutAck, 1);
- if (ret <= 0) {
- return ret;
- }
- assert(ret == 1);
-
- if (!data->advance_clock) {
- // Signal to the caller to retry the read, after advancing the clock.
- BIO_set_retry_read(bio);
- return -1;
- }
-
- PacketedBioAdvanceClock(bio);
- continue;
- }
-
- if (opcode != kOpcodePacket) {
- fprintf(stderr, "Unknown opcode, %u\n", opcode);
- return -1;
- }
-
- // Read the length prefix.
- uint8_t len_bytes[4];
- ret = ReadAll(bio->next_bio, len_bytes, sizeof(len_bytes));
- if (ret <= 0) {
- BIO_copy_next_retry(bio);
- return ret;
- }
-
- uint32_t len = (len_bytes[0] << 24) | (len_bytes[1] << 16) |
- (len_bytes[2] << 8) | len_bytes[3];
- uint8_t *buf = (uint8_t *)OPENSSL_malloc(len);
- if (buf == NULL) {
- return -1;
- }
- ret = ReadAll(bio->next_bio, buf, len);
- if (ret <= 0) {
- fprintf(stderr, "Packeted BIO was truncated\n");
- return -1;
- }
-
- if (outl > (int)len) {
- outl = len;
- }
- OPENSSL_memcpy(out, buf, outl);
- OPENSSL_free(buf);
- return outl;
+ // Read the opcode.
+ uint8_t opcode;
+ int ret = ReadAll(bio->next_bio, &opcode, sizeof(opcode));
+ if (ret <= 0) {
+ BIO_copy_next_retry(bio);
+ return ret;
}
+
+ if (opcode == kOpcodeTimeout) {
+ // The caller is required to advance any pending timeouts before continuing.
+ if (data->HasTimeout()) {
+ fprintf(stderr, "Unprocessed timeout!\n");
+ return -1;
+ }
+
+ // Process the timeout.
+ uint8_t buf[8];
+ ret = ReadAll(bio->next_bio, buf, sizeof(buf));
+ if (ret <= 0) {
+ BIO_copy_next_retry(bio);
+ return ret;
+ }
+ uint64_t timeout = (static_cast<uint64_t>(buf[0]) << 56) |
+ (static_cast<uint64_t>(buf[1]) << 48) |
+ (static_cast<uint64_t>(buf[2]) << 40) |
+ (static_cast<uint64_t>(buf[3]) << 32) |
+ (static_cast<uint64_t>(buf[4]) << 24) |
+ (static_cast<uint64_t>(buf[5]) << 16) |
+ (static_cast<uint64_t>(buf[6]) << 8) |
+ static_cast<uint64_t>(buf[7]);
+ timeout /= 1000; // Convert nanoseconds to microseconds.
+
+ data->timeout.tv_usec = timeout % 1000000;
+ data->timeout.tv_sec = timeout / 1000000;
+
+ // Send an ACK to the peer.
+ ret = BIO_write(bio->next_bio, &kOpcodeTimeoutAck, 1);
+ if (ret <= 0) {
+ return ret;
+ }
+ assert(ret == 1);
+
+ // Signal to the caller to retry the read, after advancing the clock.
+ BIO_set_retry_read(bio);
+ return -1;
+ }
+
+ if (opcode != kOpcodePacket) {
+ fprintf(stderr, "Unknown opcode, %u\n", opcode);
+ return -1;
+ }
+
+ // Read the length prefix.
+ uint8_t len_bytes[4];
+ ret = ReadAll(bio->next_bio, len_bytes, sizeof(len_bytes));
+ if (ret <= 0) {
+ BIO_copy_next_retry(bio);
+ return ret;
+ }
+
+ uint32_t len = (len_bytes[0] << 24) | (len_bytes[1] << 16) |
+ (len_bytes[2] << 8) | len_bytes[3];
+ uint8_t *buf = (uint8_t *)OPENSSL_malloc(len);
+ if (buf == NULL) {
+ return -1;
+ }
+ ret = ReadAll(bio->next_bio, buf, len);
+ if (ret <= 0) {
+ fprintf(stderr, "Packeted BIO was truncated\n");
+ return -1;
+ }
+
+ if (outl > (int)len) {
+ outl = len;
+ }
+ OPENSSL_memcpy(out, buf, outl);
+ OPENSSL_free(buf);
+ return outl;
}
static long PacketedCtrl(BIO *bio, int cmd, long num, void *ptr) {
- if (cmd == BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT) {
- OPENSSL_memcpy(&GetData(bio)->read_deadline, ptr, sizeof(timeval));
- return 1;
- }
-
if (bio->next_bio == NULL) {
return 0;
}
+
BIO_clear_retry_flags(bio);
int ret = BIO_ctrl(bio->next_bio, cmd, num, ptr);
BIO_copy_next_retry(bio);
@@ -269,12 +237,12 @@
} // namespace
-bssl::UniquePtr<BIO> PacketedBioCreate(timeval *clock, bool advance_clock) {
+bssl::UniquePtr<BIO> PacketedBioCreate(timeval *clock) {
bssl::UniquePtr<BIO> bio(BIO_new(&g_packeted_bio_method));
if (!bio) {
return nullptr;
}
- bio->ptr = new PacketedBio(clock, advance_clock);
+ bio->ptr = new PacketedBio(clock);
return bio;
}
diff --git a/src/ssl/test/packeted_bio.h b/src/ssl/test/packeted_bio.h
index 9d4cdcb..7f07fcb 100644
--- a/src/ssl/test/packeted_bio.h
+++ b/src/ssl/test/packeted_bio.h
@@ -28,15 +28,12 @@
// PacketedBioCreate creates a filter BIO which implements a reliable in-order
-// blocking datagram socket. It uses the value of |*clock| as the clock and
-// honors |BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT| based on it.
+// blocking datagram socket. It uses the value of |*clock| as the clock.
//
// During a |BIO_read|, the peer may signal the filter BIO to simulate a
-// timeout. If |advance_clock| is true, it automatically advances the clock and
-// continues reading, subject to the read deadline. Otherwise, it fails
-// immediately. The caller must then call |PacketedBioAdvanceClock| before
-// retrying |BIO_read|.
-bssl::UniquePtr<BIO> PacketedBioCreate(timeval *clock, bool advance_clock);
+// timeout. The operation will fail immediately. The caller must then call
+// |PacketedBioAdvanceClock| before retrying |BIO_read|.
+bssl::UniquePtr<BIO> PacketedBioCreate(timeval *clock);
// PacketedBioAdvanceClock advances |bio|'s clock and returns true if there is a
// pending timeout. Otherwise, it returns false.
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index 2e7b053..d316ddd 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -100,7 +100,6 @@
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
extensionRenegotiationInfo uint16 = 0xff01
extensionChannelID uint16 = 30032 // not IANA assigned
- extensionShortHeader uint16 = 27463 // not IANA assigned
)
// TLS signaling cipher suite values
@@ -223,7 +222,6 @@
SCTList []byte // signed certificate timestamp list
PeerSignatureAlgorithm signatureAlgorithm // algorithm used by the peer in the handshake
CurveID CurveID // the curve used in ECDHE
- ShortHeader bool // whether the short header extension was negotiated
}
// ClientAuthType declares the policy the server will follow for
@@ -1274,18 +1272,6 @@
// request signed certificate timestamps.
NoSignedCertificateTimestamps bool
- // EnableShortHeader, if true, causes the TLS 1.3 short header extension
- // to be enabled.
- EnableShortHeader bool
-
- // AlwaysNegotiateShortHeader, if true, causes the server to always
- // negotiate the short header extension in ServerHello.
- AlwaysNegotiateShortHeader bool
-
- // ClearShortHeaderBit, if true, causes the server to send short headers
- // without the high bit set.
- ClearShortHeaderBit bool
-
// SendSupportedPointFormats, if not nil, is the list of supported point
// formats to send in ClientHello or ServerHello. If set to a non-nil
// empty slice, no extension will be sent.
@@ -1302,6 +1288,14 @@
// SendServerNameAck, if true, causes the server to acknowledge the SNI
// extension.
SendServerNameAck bool
+
+ // ExpectCertificateReqNames, if not nil, contains the list of X.509
+ // names that must be sent in a CertificateRequest from the server.
+ ExpectCertificateReqNames [][]byte
+
+ // RenegotiationCertificate, if not nil, is the certificate to use on
+ // renegotiation handshakes.
+ RenegotiationCertificate *Certificate
}
func (c *Config) serverInit() {
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index a4cb573..1bdca84 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -167,8 +167,6 @@
trafficSecret []byte
- shortHeader bool
-
config *Config
}
@@ -315,17 +313,10 @@
copy(hc.outSeq[:], hc.seq[:])
}
-func (hc *halfConn) isShortHeader() bool {
- return hc.shortHeader && hc.cipher != nil
-}
-
func (hc *halfConn) recordHeaderLen() int {
if hc.isDTLS {
return dtlsRecordHeaderLen
}
- if hc.isShortHeader() {
- return 2
- }
return tlsRecordHeaderLen
}
@@ -629,9 +620,6 @@
n := len(b.data) - recordHeaderLen
b.data[recordHeaderLen-2] = byte(n >> 8)
b.data[recordHeaderLen-1] = byte(n)
- if hc.isShortHeader() && !hc.config.Bugs.ClearShortHeaderBit {
- b.data[0] |= 0x80
- }
hc.incSeq(true)
return true, 0
@@ -762,35 +750,20 @@
return 0, nil, err
}
- var typ recordType
- var vers uint16
- var n int
- if c.in.isShortHeader() {
- typ = recordTypeApplicationData
- vers = VersionTLS10
- n = int(b.data[0])<<8 | int(b.data[1])
- if n&0x8000 == 0 {
- c.sendAlert(alertDecodeError)
- return 0, nil, c.in.setErrorLocked(errors.New("tls: length did not have high bit set"))
- }
+ typ := recordType(b.data[0])
- n = n & 0x7fff
- } else {
- typ = recordType(b.data[0])
-
- // No valid TLS record has a type of 0x80, however SSLv2 handshakes
- // start with a uint16 length where the MSB is set and the first record
- // is always < 256 bytes long. Therefore typ == 0x80 strongly suggests
- // an SSLv2 client.
- if want == recordTypeHandshake && typ == 0x80 {
- c.sendAlert(alertProtocolVersion)
- return 0, nil, c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received"))
- }
-
- vers = uint16(b.data[1])<<8 | uint16(b.data[2])
- n = int(b.data[3])<<8 | int(b.data[4])
+ // No valid TLS record has a type of 0x80, however SSLv2 handshakes
+ // start with a uint16 length where the MSB is set and the first record
+ // is always < 256 bytes long. Therefore typ == 0x80 strongly suggests
+ // an SSLv2 client.
+ if want == recordTypeHandshake && typ == 0x80 {
+ c.sendAlert(alertProtocolVersion)
+ return 0, nil, c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received"))
}
+ vers := uint16(b.data[1])<<8 | uint16(b.data[2])
+ n := int(b.data[3])<<8 | int(b.data[4])
+
// Alerts sent near version negotiation do not have a well-defined
// record-layer version prior to TLS 1.3. (In TLS 1.3, the record-layer
// version is irrelevant.)
@@ -1118,36 +1091,32 @@
}
}
b.resize(recordHeaderLen + explicitIVLen + m)
- // If using a short record header, the length will be filled in
- // by encrypt.
- if !c.out.isShortHeader() {
- b.data[0] = byte(typ)
- if c.vers >= VersionTLS13 && c.out.cipher != nil {
- b.data[0] = byte(recordTypeApplicationData)
- if outerType := c.config.Bugs.OuterRecordType; outerType != 0 {
- b.data[0] = byte(outerType)
- }
+ b.data[0] = byte(typ)
+ if c.vers >= VersionTLS13 && c.out.cipher != nil {
+ b.data[0] = byte(recordTypeApplicationData)
+ if outerType := c.config.Bugs.OuterRecordType; outerType != 0 {
+ b.data[0] = byte(outerType)
}
- vers := c.vers
- if vers == 0 || vers >= VersionTLS13 {
- // Some TLS servers fail if the record version is
- // greater than TLS 1.0 for the initial ClientHello.
- //
- // TLS 1.3 fixes the version number in the record
- // layer to {3, 1}.
- vers = VersionTLS10
- }
- if c.config.Bugs.SendRecordVersion != 0 {
- vers = c.config.Bugs.SendRecordVersion
- }
- if c.vers == 0 && c.config.Bugs.SendInitialRecordVersion != 0 {
- vers = c.config.Bugs.SendInitialRecordVersion
- }
- b.data[1] = byte(vers >> 8)
- b.data[2] = byte(vers)
- b.data[3] = byte(m >> 8)
- b.data[4] = byte(m)
}
+ vers := c.vers
+ if vers == 0 || vers >= VersionTLS13 {
+ // Some TLS servers fail if the record version is
+ // greater than TLS 1.0 for the initial ClientHello.
+ //
+ // TLS 1.3 fixes the version number in the record
+ // layer to {3, 1}.
+ vers = VersionTLS10
+ }
+ if c.config.Bugs.SendRecordVersion != 0 {
+ vers = c.config.Bugs.SendRecordVersion
+ }
+ if c.vers == 0 && c.config.Bugs.SendInitialRecordVersion != 0 {
+ vers = c.config.Bugs.SendInitialRecordVersion
+ }
+ b.data[1] = byte(vers >> 8)
+ b.data[2] = byte(vers)
+ b.data[3] = byte(m >> 8)
+ b.data[4] = byte(m)
if explicitIVLen > 0 {
explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
if explicitIVIsSeq {
@@ -1705,7 +1674,6 @@
state.SCTList = c.sctList
state.PeerSignatureAlgorithm = c.peerSignatureAlgorithm
state.CurveID = c.curveID
- state.ShortHeader = c.in.shortHeader
}
return state
@@ -1873,8 +1841,3 @@
_, err := c.conn.Write(payload)
return err
}
-
-func (c *Conn) setShortHeader() {
- c.in.shortHeader = true
- c.out.shortHeader = true
-}
diff --git a/src/ssl/test/runner/ecdsa_p224_cert.pem b/src/ssl/test/runner/ecdsa_p224_cert.pem
new file mode 100644
index 0000000..29246a2
--- /dev/null
+++ b/src/ssl/test/runner/ecdsa_p224_cert.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBvjCCAWygAwIBAgIJAPlkrPTq4HgnMAoGCCqGSM49BAMCMEUxCzAJBgNVBAYT
+AkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn
+aXRzIFB0eSBMdGQwHhcNMTcwMjI3MjAxOTIzWhcNMTkwMjI3MjAxOTIzWjBFMQsw
+CQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJu
+ZXQgV2lkZ2l0cyBQdHkgTHRkME4wEAYHKoZIzj0CAQYFK4EEACEDOgAE6dul6dL0
++CyooFiKK4V+EYNYPbMZoLTxRcjRgrw3db6QzBAviDSxKADTVuyRmaVC74Mf6boB
+HDmjUDBOMB0GA1UdDgQWBBSMtlkUJ7SCZ4zRqkjXMWvOebSgpTAfBgNVHSMEGDAW
+gBSMtlkUJ7SCZ4zRqkjXMWvOebSgpTAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMC
+A0AAMD0CHHolWPktSLbVMy9ukQUb2E7+Jb3hcNFqAXh47pYCHQC+jv2EE6oOEZ9F
+tLkFLtap71+83P0NUEJX4Etu
+-----END CERTIFICATE-----
diff --git a/src/ssl/test/runner/ecdsa_p224_key.pem b/src/ssl/test/runner/ecdsa_p224_key.pem
new file mode 100644
index 0000000..cfe411b
--- /dev/null
+++ b/src/ssl/test/runner/ecdsa_p224_key.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MGgCAQEEHGi+rNLi+gHJqmRRtdlLBOw1WYv7H/VnlYGAZ0+gBwYFK4EEACGhPAM6
+AATp26Xp0vT4LKigWIorhX4Rg1g9sxmgtPFFyNGCvDd1vpDMEC+INLEoANNW7JGZ
+pULvgx/pugEcOQ==
+-----END EC PRIVATE KEY-----
diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go
index 162302e..eb072ad 100644
--- a/src/ssl/test/runner/handshake_client.go
+++ b/src/ssl/test/runner/handshake_client.go
@@ -81,7 +81,6 @@
srtpMasterKeyIdentifier: c.config.Bugs.SRTPMasterKeyIdentifer,
customExtension: c.config.Bugs.CustomExtension,
pskBinderFirst: c.config.Bugs.PSKBinderFirst,
- shortHeaderSupported: c.config.Bugs.EnableShortHeader,
}
disableEMS := c.config.Bugs.NoExtendedMasterSecret
@@ -717,18 +716,6 @@
hs.finishedHash.addEntropy(zeroSecret)
}
- if hs.serverHello.shortHeader && !hs.hello.shortHeaderSupported {
- return errors.New("tls: server sent unsolicited short header extension")
- }
-
- if hs.serverHello.shortHeader && hs.hello.hasEarlyData {
- return errors.New("tls: server sent short header extension in response to early data")
- }
-
- if hs.serverHello.shortHeader {
- c.setShortHeader()
- }
-
// Derive handshake traffic keys and switch read key to handshake
// traffic key.
clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel)
@@ -1363,10 +1350,6 @@
func (hs *clientHandshakeState) processServerHello() (bool, error) {
c := hs.c
- if hs.serverHello.shortHeader {
- return false, errors.New("tls: short header extension sent before TLS 1.3")
- }
-
if hs.serverResumedSession() {
// For test purposes, assert that the server never accepts the
// resumption offer on renegotiation.
@@ -1682,18 +1665,13 @@
}
}
- if len(certReq.certificateAuthorities) == 0 {
- // They gave us an empty list, so just take the
- // first certificate of valid type from
- // c.config.Certificates.
- return &chain, nil
- }
-
- for _, ca := range certReq.certificateAuthorities {
- if bytes.Equal(x509Cert.RawIssuer, ca) {
- return &chain, nil
+ if expected := c.config.Bugs.ExpectCertificateReqNames; expected != nil {
+ if !eqByteSlices(expected, certReq.certificateAuthorities) {
+ return nil, fmt.Errorf("tls: CertificateRequest names differed, got %#v but expected %#v", certReq.certificateAuthorities, expected)
}
}
+
+ return &chain, nil
}
}
diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go
index 4ecb3cb..86e2821 100644
--- a/src/ssl/test/runner/handshake_messages.go
+++ b/src/ssl/test/runner/handshake_messages.go
@@ -167,7 +167,6 @@
customExtension string
hasGREASEExtension bool
pskBinderFirst bool
- shortHeaderSupported bool
}
func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -213,8 +212,7 @@
m.sctListSupported == m1.sctListSupported &&
m.customExtension == m1.customExtension &&
m.hasGREASEExtension == m1.hasGREASEExtension &&
- m.pskBinderFirst == m1.pskBinderFirst &&
- m.shortHeaderSupported == m1.shortHeaderSupported
+ m.pskBinderFirst == m1.pskBinderFirst
}
func (m *clientHelloMsg) marshal() []byte {
@@ -430,10 +428,6 @@
customExt := extensions.addU16LengthPrefixed()
customExt.addBytes([]byte(m.customExtension))
}
- if m.shortHeaderSupported {
- extensions.addU16(extensionShortHeader)
- extensions.addU16(0) // Length is always 0
- }
// The PSK extension must be last (draft-ietf-tls-tls13-18 section 4.2.6).
if len(m.pskIdentities) > 0 && !m.pskBinderFirst {
extensions.addU16(extensionPreSharedKey)
@@ -805,11 +799,6 @@
return false
}
m.sctListSupported = true
- case extensionShortHeader:
- if length != 0 {
- return false
- }
- m.shortHeaderSupported = true
case extensionCustom:
m.customExtension = string(data[:length])
}
@@ -838,7 +827,6 @@
compressionMethod uint8
customExtension string
unencryptedALPN string
- shortHeader bool
extensions serverExtensions
}
@@ -876,11 +864,6 @@
extensions := hello.addU16LengthPrefixed()
- if m.shortHeader {
- extensions.addU16(extensionShortHeader)
- extensions.addU16(0) // Length
- }
-
if vers >= VersionTLS13 {
if m.hasKeyShare {
extensions.addU16(extensionKeyShare)
@@ -1000,11 +983,6 @@
}
m.pskIdentity = uint16(d[0])<<8 | uint16(d[1])
m.hasPSKIdentity = true
- case extensionShortHeader:
- if len(d) != 0 {
- return false
- }
- m.shortHeader = true
default:
// Only allow the 3 extensions that are sent in
// the clear in TLS 1.3.
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index 8aa1587..9b4bff8 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -365,15 +365,6 @@
versOverride: config.Bugs.SendServerHelloVersion,
customExtension: config.Bugs.CustomUnencryptedExtension,
unencryptedALPN: config.Bugs.SendUnencryptedALPN,
- shortHeader: hs.clientHello.shortHeaderSupported && config.Bugs.EnableShortHeader,
- }
-
- if config.Bugs.AlwaysNegotiateShortHeader {
- hs.hello.shortHeader = true
- }
-
- if hs.hello.shortHeader {
- c.setShortHeader()
}
hs.hello.random = make([]byte, 32)
@@ -1025,7 +1016,6 @@
vers: versionToWire(c.vers, c.isDTLS),
versOverride: config.Bugs.SendServerHelloVersion,
compressionMethod: compressionNone,
- shortHeader: config.Bugs.AlwaysNegotiateShortHeader,
}
hs.hello.random = make([]byte, 32)
@@ -1165,6 +1155,10 @@
return errors.New("tls: unexpected server name")
}
+ if cert := config.Bugs.RenegotiationCertificate; c.cipherSuite != nil && cert != nil {
+ hs.cert = cert
+ }
+
if len(hs.clientHello.alpnProtocols) > 0 {
if proto := c.config.Bugs.ALPNProtocol; proto != nil {
serverExtensions.alpnProtocol = *proto
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index d7bad5b..55685b0 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -22,6 +22,7 @@
"crypto/x509"
"crypto/x509/pkix"
"encoding/base64"
+ "encoding/hex"
"encoding/json"
"encoding/pem"
"errors"
@@ -91,6 +92,7 @@
testCertRSA testCert = iota
testCertRSA1024
testCertRSAChain
+ testCertECDSAP224
testCertECDSAP256
testCertECDSAP384
testCertECDSAP521
@@ -100,6 +102,7 @@
rsaCertificateFile = "cert.pem"
rsa1024CertificateFile = "rsa_1024_cert.pem"
rsaChainCertificateFile = "rsa_chain_cert.pem"
+ ecdsaP224CertificateFile = "ecdsa_p224_cert.pem"
ecdsaP256CertificateFile = "ecdsa_p256_cert.pem"
ecdsaP384CertificateFile = "ecdsa_p384_cert.pem"
ecdsaP521CertificateFile = "ecdsa_p521_cert.pem"
@@ -109,6 +112,7 @@
rsaKeyFile = "key.pem"
rsa1024KeyFile = "rsa_1024_key.pem"
rsaChainKeyFile = "rsa_chain_key.pem"
+ ecdsaP224KeyFile = "ecdsa_p224_key.pem"
ecdsaP256KeyFile = "ecdsa_p256_key.pem"
ecdsaP384KeyFile = "ecdsa_p384_key.pem"
ecdsaP521KeyFile = "ecdsa_p521_key.pem"
@@ -119,6 +123,7 @@
rsaCertificate Certificate
rsa1024Certificate Certificate
rsaChainCertificate Certificate
+ ecdsaP224Certificate Certificate
ecdsaP256Certificate Certificate
ecdsaP384Certificate Certificate
ecdsaP521Certificate Certificate
@@ -148,6 +153,12 @@
cert: &rsaChainCertificate,
},
{
+ id: testCertECDSAP224,
+ certFile: ecdsaP224CertificateFile,
+ keyFile: ecdsaP224KeyFile,
+ cert: &ecdsaP224Certificate,
+ },
+ {
id: testCertECDSAP256,
certFile: ecdsaP256CertificateFile,
keyFile: ecdsaP256KeyFile,
@@ -235,6 +246,19 @@
panic("Unknown test certificate")
}
+// encodeDERValues encodes a series of bytestrings in comma-separated-hex form.
+func encodeDERValues(values [][]byte) string {
+ var ret string
+ for i, v := range values {
+ if i > 0 {
+ ret += ","
+ }
+ ret += hex.EncodeToString(v)
+ }
+
+ return ret
+}
+
type testType int
const (
@@ -383,8 +407,6 @@
// expectPeerCertificate, if not nil, is the certificate chain the peer
// is expected to send.
expectPeerCertificate *Certificate
- // expectShortHeader is whether the short header extension should be negotiated.
- expectShortHeader bool
}
var testCases []testCase
@@ -613,10 +635,6 @@
}
}
- if test.expectShortHeader != connState.ShortHeader {
- return fmt.Errorf("ShortHeader is %t, but we expected the opposite", connState.ShortHeader)
- }
-
if test.exportKeyingMaterial > 0 {
actual := make([]byte, test.exportKeyingMaterial)
if _, err := io.ReadFull(tlsConn, actual); err != nil {
@@ -2662,27 +2680,6 @@
shouldFail: shouldFail,
expectedError: expectedError,
})
-
- if ver.version >= VersionTLS13 {
- testCases = append(testCases, testCase{
- protocol: protocol,
- name: prefix + ver.name + "-" + suite.name + "-ShortHeader",
- config: Config{
- MinVersion: ver.version,
- MaxVersion: ver.version,
- CipherSuites: []uint16{suite.id},
- Certificates: []Certificate{cert},
- PreSharedKey: []byte(psk),
- PreSharedKeyIdentity: pskIdentity,
- Bugs: ProtocolBugs{
- EnableShortHeader: true,
- },
- },
- flags: append([]string{"-enable-short-header"}, flags...),
- resumeSession: true,
- expectShortHeader: true,
- })
- }
}
func addCipherSuiteTests() {
@@ -2965,13 +2962,15 @@
func addClientAuthTests() {
// Add a dummy cert pool to stress certificate authority parsing.
- // TODO(davidben): Add tests that those values parse out correctly.
certPool := x509.NewCertPool()
- cert, err := x509.ParseCertificate(rsaCertificate.Certificate[0])
- if err != nil {
- panic(err)
+ for _, cert := range []Certificate{rsaCertificate, rsa1024Certificate} {
+ cert, err := x509.ParseCertificate(cert.Certificate[0])
+ if err != nil {
+ panic(err)
+ }
+ certPool.AddCert(cert)
}
- certPool.AddCert(cert)
+ caNames := certPool.Subjects()
for _, ver := range tlsVersions {
testCases = append(testCases, testCase{
@@ -3103,6 +3102,40 @@
expectedError: ":UNEXPECTED_MESSAGE:",
})
}
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: ver.name + "-Server-CertReq-CA-List",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Certificates: []Certificate{rsaCertificate},
+ Bugs: ProtocolBugs{
+ ExpectCertificateReqNames: caNames,
+ },
+ },
+ flags: []string{
+ "-require-any-client-certificate",
+ "-use-client-ca-list", encodeDERValues(caNames),
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: ver.name + "-Client-CertReq-CA-List",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Certificates: []Certificate{rsaCertificate},
+ ClientAuth: RequireAnyClientCert,
+ ClientCAs: certPool,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-expect-client-ca-list", encodeDERValues(caNames),
+ },
+ })
}
// Client auth is only legal in certificate-based ciphers.
@@ -3149,10 +3182,13 @@
config: Config{
MaxVersion: VersionTLS12,
Certificates: []Certificate{rsaCertificate},
+ Bugs: ProtocolBugs{
+ ExpectCertificateReqNames: [][]byte{},
+ },
},
flags: []string{
"-require-any-client-certificate",
- "-use-null-client-ca-list",
+ "-use-client-ca-list", "<NULL>",
},
})
}
@@ -6482,6 +6518,36 @@
"-expect-secure-renegotiation",
},
})
+
+ // Certificates may not change on renegotiation.
+ testCases = append(testCases, testCase{
+ name: "Renegotiation-CertificateChange",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Certificates: []Certificate{rsaCertificate},
+ Bugs: ProtocolBugs{
+ RenegotiationCertificate: &rsaChainCertificate,
+ },
+ },
+ renegotiate: 1,
+ flags: []string{"-renegotiate-freely"},
+ shouldFail: true,
+ expectedError: ":SERVER_CERT_CHANGED:",
+ })
+ testCases = append(testCases, testCase{
+ name: "Renegotiation-CertificateChange-2",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Certificates: []Certificate{rsaCertificate},
+ Bugs: ProtocolBugs{
+ RenegotiationCertificate: &rsa1024Certificate,
+ },
+ },
+ renegotiate: 1,
+ flags: []string{"-renegotiate-freely"},
+ shouldFail: true,
+ expectedError: ":SERVER_CERT_CHANGED:",
+ })
}
func addDTLSReplayTests() {
@@ -7354,6 +7420,31 @@
},
flags: []string{"-max-version", strconv.Itoa(VersionTLS12)},
})
+
+ // A server certificate with a P-224 key will only work up to TLS 1.2
+ // and we only test it with BoringSSL acting as a server because that's
+ // all Alphabet requires with it.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "P224-Server",
+ config: Config{
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ // TLS 1.2 does not require that the curve
+ // match the hash, thus P-256 with SHA-256 is
+ // the same signature algorithm value as P-224
+ // with SHA-256.
+ signatureECDSAWithP256AndSHA256,
+ },
+ // P-256 must be offered as well because ECDHE requires
+ // it.
+ CurvePreferences: []CurveID{CurveP224, CurveP256},
+ },
+ flags: []string{
+ "-max-version", strconv.Itoa(VersionTLS12),
+ "-cert-file", path.Join(*resourceDir, ecdsaP224CertificateFile),
+ "-key-file", path.Join(*resourceDir, ecdsaP224KeyFile),
+ },
+ })
}
// timeouts is the retransmit schedule for BoringSSL. It doubles and
@@ -7418,123 +7509,119 @@
// likely be more epochs to cross and the final message's retransmit may
// be more complex.
- for _, async := range []bool{true, false} {
- var tests []testCase
-
- // Test that this is indeed the timeout schedule. Stress all
- // four patterns of handshake.
- for i := 1; i < len(timeouts); i++ {
- number := strconv.Itoa(i)
- tests = append(tests, testCase{
- protocol: dtls,
- name: "DTLS-Retransmit-Client-" + number,
- config: Config{
- MaxVersion: VersionTLS12,
- Bugs: ProtocolBugs{
- TimeoutSchedule: timeouts[:i],
- },
- },
- resumeSession: true,
- })
- tests = append(tests, testCase{
- protocol: dtls,
- testType: serverTest,
- name: "DTLS-Retransmit-Server-" + number,
- config: Config{
- MaxVersion: VersionTLS12,
- Bugs: ProtocolBugs{
- TimeoutSchedule: timeouts[:i],
- },
- },
- resumeSession: true,
- })
- }
-
- // Test that exceeding the timeout schedule hits a read
- // timeout.
- tests = append(tests, testCase{
+ // Test that this is indeed the timeout schedule. Stress all
+ // four patterns of handshake.
+ for i := 1; i < len(timeouts); i++ {
+ number := strconv.Itoa(i)
+ testCases = append(testCases, testCase{
protocol: dtls,
- name: "DTLS-Retransmit-Timeout",
+ name: "DTLS-Retransmit-Client-" + number,
config: Config{
MaxVersion: VersionTLS12,
Bugs: ProtocolBugs{
- TimeoutSchedule: timeouts,
+ TimeoutSchedule: timeouts[:i],
},
},
resumeSession: true,
- shouldFail: true,
- expectedError: ":READ_TIMEOUT_EXPIRED:",
+ flags: []string{"-async"},
})
-
- if async {
- // Test that timeout handling has a fudge factor, due to API
- // problems.
- tests = append(tests, testCase{
- protocol: dtls,
- name: "DTLS-Retransmit-Fudge",
- config: Config{
- MaxVersion: VersionTLS12,
- Bugs: ProtocolBugs{
- TimeoutSchedule: []time.Duration{
- timeouts[0] - 10*time.Millisecond,
- },
- },
- },
- resumeSession: true,
- })
- }
-
- // Test that the final Finished retransmitting isn't
- // duplicated if the peer badly fragments everything.
- tests = append(tests, testCase{
- testType: serverTest,
- protocol: dtls,
- name: "DTLS-Retransmit-Fragmented",
- config: Config{
- MaxVersion: VersionTLS12,
- Bugs: ProtocolBugs{
- TimeoutSchedule: []time.Duration{timeouts[0]},
- MaxHandshakeRecordLength: 2,
- },
- },
- })
-
- // Test the timeout schedule when a shorter initial timeout duration is set.
- tests = append(tests, testCase{
- protocol: dtls,
- name: "DTLS-Retransmit-Short-Client",
- config: Config{
- MaxVersion: VersionTLS12,
- Bugs: ProtocolBugs{
- TimeoutSchedule: shortTimeouts[:len(shortTimeouts)-1],
- },
- },
- resumeSession: true,
- flags: []string{"-initial-timeout-duration-ms", "250"},
- })
- tests = append(tests, testCase{
+ testCases = append(testCases, testCase{
protocol: dtls,
testType: serverTest,
- name: "DTLS-Retransmit-Short-Server",
+ name: "DTLS-Retransmit-Server-" + number,
config: Config{
MaxVersion: VersionTLS12,
Bugs: ProtocolBugs{
- TimeoutSchedule: shortTimeouts[:len(shortTimeouts)-1],
+ TimeoutSchedule: timeouts[:i],
},
},
resumeSession: true,
- flags: []string{"-initial-timeout-duration-ms", "250"},
+ flags: []string{"-async"},
})
-
- for _, test := range tests {
- if async {
- test.name += "-Async"
- test.flags = append(test.flags, "-async")
- }
-
- testCases = append(testCases, test)
- }
}
+
+ // Test that exceeding the timeout schedule hits a read
+ // timeout.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "DTLS-Retransmit-Timeout",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: timeouts,
+ },
+ },
+ resumeSession: true,
+ flags: []string{"-async"},
+ shouldFail: true,
+ expectedError: ":READ_TIMEOUT_EXPIRED:",
+ })
+
+ // Test that timeout handling has a fudge factor, due to API
+ // problems.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "DTLS-Retransmit-Fudge",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: []time.Duration{
+ timeouts[0] - 10*time.Millisecond,
+ },
+ },
+ },
+ resumeSession: true,
+ flags: []string{"-async"},
+ })
+
+ // Test that the final Finished retransmitting isn't
+ // duplicated if the peer badly fragments everything.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ protocol: dtls,
+ name: "DTLS-Retransmit-Fragmented",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: []time.Duration{timeouts[0]},
+ MaxHandshakeRecordLength: 2,
+ },
+ },
+ flags: []string{"-async"},
+ })
+
+ // Test the timeout schedule when a shorter initial timeout duration is set.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "DTLS-Retransmit-Short-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: shortTimeouts[:len(shortTimeouts)-1],
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-async",
+ "-initial-timeout-duration-ms", "250",
+ },
+ })
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ testType: serverTest,
+ name: "DTLS-Retransmit-Short-Server",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: shortTimeouts[:len(shortTimeouts)-1],
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-async",
+ "-initial-timeout-duration-ms", "250",
+ },
+ })
}
func addExportKeyingMaterialTests() {
@@ -10130,150 +10217,6 @@
}
}
-func addShortHeaderTests() {
- // The short header extension may be negotiated as either client or
- // server.
- testCases = append(testCases, testCase{
- name: "ShortHeader-Client",
- config: Config{
- MaxVersion: VersionTLS13,
- Bugs: ProtocolBugs{
- EnableShortHeader: true,
- },
- },
- flags: []string{"-enable-short-header"},
- expectShortHeader: true,
- })
- testCases = append(testCases, testCase{
- testType: serverTest,
- name: "ShortHeader-Server",
- config: Config{
- MaxVersion: VersionTLS13,
- Bugs: ProtocolBugs{
- EnableShortHeader: true,
- },
- },
- flags: []string{"-enable-short-header"},
- expectShortHeader: true,
- })
-
- // If the peer doesn't support it, it will not be negotiated.
- testCases = append(testCases, testCase{
- name: "ShortHeader-No-Yes-Client",
- config: Config{
- MaxVersion: VersionTLS13,
- },
- flags: []string{"-enable-short-header"},
- })
- testCases = append(testCases, testCase{
- testType: serverTest,
- name: "ShortHeader-No-Yes-Server",
- config: Config{
- MaxVersion: VersionTLS13,
- },
- flags: []string{"-enable-short-header"},
- })
-
- // If we don't support it, it will not be negotiated.
- testCases = append(testCases, testCase{
- name: "ShortHeader-Yes-No-Client",
- config: Config{
- MaxVersion: VersionTLS13,
- Bugs: ProtocolBugs{
- EnableShortHeader: true,
- },
- },
- })
- testCases = append(testCases, testCase{
- testType: serverTest,
- name: "ShortHeader-Yes-No-Server",
- config: Config{
- MaxVersion: VersionTLS13,
- Bugs: ProtocolBugs{
- EnableShortHeader: true,
- },
- },
- })
-
- // It will not be negotiated at TLS 1.2.
- testCases = append(testCases, testCase{
- name: "ShortHeader-TLS12-Client",
- config: Config{
- MaxVersion: VersionTLS12,
- Bugs: ProtocolBugs{
- EnableShortHeader: true,
- },
- },
- flags: []string{"-enable-short-header"},
- })
- testCases = append(testCases, testCase{
- testType: serverTest,
- name: "ShortHeader-TLS12-Server",
- config: Config{
- MaxVersion: VersionTLS12,
- Bugs: ProtocolBugs{
- EnableShortHeader: true,
- },
- },
- flags: []string{"-enable-short-header"},
- })
-
- // Servers reject early data and short header sent together.
- testCases = append(testCases, testCase{
- testType: serverTest,
- name: "ShortHeader-EarlyData",
- config: Config{
- MaxVersion: VersionTLS13,
- Bugs: ProtocolBugs{
- EnableShortHeader: true,
- SendFakeEarlyDataLength: 1,
- },
- },
- flags: []string{"-enable-short-header"},
- shouldFail: true,
- expectedError: ":UNEXPECTED_EXTENSION:",
- })
-
- // Clients reject unsolicited short header extensions.
- testCases = append(testCases, testCase{
- name: "ShortHeader-Unsolicited",
- config: Config{
- MaxVersion: VersionTLS13,
- Bugs: ProtocolBugs{
- AlwaysNegotiateShortHeader: true,
- },
- },
- shouldFail: true,
- expectedError: ":UNEXPECTED_EXTENSION:",
- })
- testCases = append(testCases, testCase{
- name: "ShortHeader-Unsolicited-TLS12",
- config: Config{
- MaxVersion: VersionTLS12,
- Bugs: ProtocolBugs{
- AlwaysNegotiateShortHeader: true,
- },
- },
- shouldFail: true,
- expectedError: ":UNEXPECTED_EXTENSION:",
- })
-
- // The high bit must be checked in short headers.
- testCases = append(testCases, testCase{
- name: "ShortHeader-ClearShortHeaderBit",
- config: Config{
- Bugs: ProtocolBugs{
- EnableShortHeader: true,
- ClearShortHeaderBit: true,
- },
- },
- flags: []string{"-enable-short-header"},
- shouldFail: true,
- expectedError: ":DECODE_ERROR:",
- expectedLocalError: "remote error: error decoding message",
- })
-}
-
func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sync.WaitGroup) {
defer wg.Done()
@@ -10400,7 +10343,6 @@
addCertificateTests()
addRetainOnlySHA256ClientCertTests()
addECDSAKeyUsageTests()
- addShortHeaderTests()
var wg sync.WaitGroup
diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc
index b729f69..fefe376 100644
--- a/src/ssl/test/test_config.cc
+++ b/src/ssl/test/test_config.cc
@@ -104,7 +104,6 @@
{ "-use-sparse-dh-prime", &TestConfig::use_sparse_dh_prime },
{ "-use-old-client-cert-callback",
&TestConfig::use_old_client_cert_callback },
- { "-use-null-client-ca-list", &TestConfig::use_null_client_ca_list },
{ "-send-alert", &TestConfig::send_alert },
{ "-peek-then-read", &TestConfig::peek_then_read },
{ "-enable-grease", &TestConfig::enable_grease },
@@ -117,7 +116,6 @@
&TestConfig::expect_sha256_client_cert_initial },
{ "-expect-sha256-client-cert-resume",
&TestConfig::expect_sha256_client_cert_resume },
- { "-enable-short-header", &TestConfig::enable_short_header },
{ "-read-with-unfinished-write", &TestConfig::read_with_unfinished_write },
{ "-expect-secure-renegotiation",
&TestConfig::expect_secure_renegotiation },
@@ -148,6 +146,8 @@
{ "-export-label", &TestConfig::export_label },
{ "-export-context", &TestConfig::export_context },
{ "-expect-peer-cert-file", &TestConfig::expect_peer_cert_file },
+ { "-use-client-ca-list", &TestConfig::use_client_ca_list },
+ { "-expect-client-ca-list", &TestConfig::expected_client_ca_list },
};
const Flag<std::string> kBase64Flags[] = {
diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h
index 7122856..ee3d462 100644
--- a/src/ssl/test/test_config.h
+++ b/src/ssl/test/test_config.h
@@ -110,7 +110,8 @@
int expect_resume_curve_id = 0;
bool use_old_client_cert_callback = false;
int initial_timeout_duration_ms = 0;
- bool use_null_client_ca_list = false;
+ std::string use_client_ca_list;
+ std::string expected_client_ca_list;
bool send_alert = false;
bool peek_then_read = false;
bool enable_grease = false;
@@ -125,7 +126,6 @@
bool retain_only_sha256_client_cert_resume = false;
bool expect_sha256_client_cert_initial = false;
bool expect_sha256_client_cert_resume = false;
- bool enable_short_header = false;
bool read_with_unfinished_write = false;
bool expect_secure_renegotiation = false;
bool expect_no_secure_renegotiation = false;
diff --git a/src/ssl/tls13_both.c b/src/ssl/tls13_both.c
index 91cae9a..5bd58eb 100644
--- a/src/ssl/tls13_both.c
+++ b/src/ssl/tls13_both.c
@@ -330,8 +330,8 @@
hs->new_session->peer_sha256_valid = retain_sha256;
- if (!ssl_verify_cert_chain(ssl, &hs->new_session->verify_result,
- hs->new_session->x509_chain)) {
+ if (!ssl->ctx->x509_method->session_verify_cert_chain(hs->new_session,
+ ssl)) {
goto err;
}
diff --git a/src/ssl/tls13_client.c b/src/ssl/tls13_client.c
index 8e994e5..c0eb135 100644
--- a/src/ssl/tls13_client.c
+++ b/src/ssl/tls13_client.c
@@ -199,12 +199,11 @@
}
/* Parse out the extensions. */
- int have_key_share = 0, have_pre_shared_key = 0, have_short_header = 0;
- CBS key_share, pre_shared_key, short_header;
+ int have_key_share = 0, have_pre_shared_key = 0;
+ CBS key_share, pre_shared_key;
const SSL_EXTENSION_TYPE ext_types[] = {
{TLSEXT_TYPE_key_share, &have_key_share, &key_share},
{TLSEXT_TYPE_pre_shared_key, &have_pre_shared_key, &pre_shared_key},
- {TLSEXT_TYPE_short_header, &have_short_header, &short_header},
};
uint8_t alert = SSL_AD_DECODE_ERROR;
@@ -318,23 +317,6 @@
}
OPENSSL_free(dhe_secret);
- /* Negotiate short record headers. */
- if (have_short_header) {
- if (CBS_len(&short_header) != 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return ssl_hs_error;
- }
-
- if (!ssl->ctx->short_header_enabled) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
- return ssl_hs_error;
- }
-
- ssl->s3->short_header = 1;
- }
-
if (!ssl_hash_current_message(hs) ||
!tls13_derive_handshake_secrets(hs) ||
!tls13_set_traffic_key(ssl, evp_aead_open, hs->server_handshake_secret,
@@ -402,8 +384,9 @@
}
uint8_t alert = SSL_AD_DECODE_ERROR;
- STACK_OF(X509_NAME) *ca_sk = ssl_parse_client_CA_list(ssl, &alert, &cbs);
- if (ca_sk == NULL) {
+ STACK_OF(CRYPTO_BUFFER) *ca_names =
+ ssl_parse_client_CA_list(ssl, &alert, &cbs);
+ if (ca_names == NULL) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
return ssl_hs_error;
}
@@ -413,14 +396,15 @@
if (!CBS_get_u16_length_prefixed(&cbs, &extensions) ||
CBS_len(&cbs) != 0) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- sk_X509_NAME_pop_free(ca_sk, X509_NAME_free);
+ sk_CRYPTO_BUFFER_pop_free(ca_names, CRYPTO_BUFFER_free);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
return ssl_hs_error;
}
hs->cert_request = 1;
- sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free);
- hs->ca_names = ca_sk;
+ sk_CRYPTO_BUFFER_pop_free(hs->ca_names, CRYPTO_BUFFER_free);
+ hs->ca_names = ca_names;
+ ssl->ctx->x509_method->hs_flush_cached_ca_names(hs);
if (!ssl_hash_current_message(hs)) {
return ssl_hs_error;
@@ -493,7 +477,7 @@
}
}
- if (!ssl_auto_chain_if_needed(ssl) ||
+ if (!ssl->ctx->x509_method->ssl_auto_chain_if_needed(ssl) ||
!tls13_add_certificate(hs)) {
return ssl_hs_error;
}
@@ -648,18 +632,9 @@
}
/* Cap the renewable lifetime by the server advertised value. This avoids
- * wasting bandwidth on 0-RTT when we know the server will reject it.
- *
- * TODO(davidben): This dance where we're not sure if long or uint32_t is
- * bigger is silly. session->timeout should not be a long to begin with.
- * https://crbug.com/boringssl/155. */
-#if LONG_MAX < 0xffffffff
- if (server_timeout > LONG_MAX) {
- server_timeout = LONG_MAX;
- }
-#endif
- if (session->timeout > (long)server_timeout) {
- session->timeout = (long)server_timeout;
+ * wasting bandwidth on 0-RTT when we know the server will reject it. */
+ if (session->timeout > server_timeout) {
+ session->timeout = server_timeout;
}
/* Parse out the extensions. */
diff --git a/src/ssl/tls13_server.c b/src/ssl/tls13_server.c
index 402c234..e7cc296 100644
--- a/src/ssl/tls13_server.c
+++ b/src/ssl/tls13_server.c
@@ -135,11 +135,6 @@
static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
- /* The short record header extension is incompatible with early data. */
- if (ssl->s3->skip_early_data && ssl->s3->short_header) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
- return ssl_hs_error;
- }
SSL_CLIENT_HELLO client_hello;
if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
@@ -354,18 +349,8 @@
!CBB_add_u16(&body, ssl_cipher_get_value(hs->new_cipher)) ||
!CBB_add_u16_length_prefixed(&body, &extensions) ||
!ssl_ext_pre_shared_key_add_serverhello(hs, &extensions) ||
- !ssl_ext_key_share_add_serverhello(hs, &extensions)) {
- goto err;
- }
-
- if (ssl->s3->short_header) {
- if (!CBB_add_u16(&extensions, TLSEXT_TYPE_short_header) ||
- !CBB_add_u16(&extensions, 0 /* empty extension */)) {
- goto err;
- }
- }
-
- if (!ssl_add_message_cbb(ssl, &cbb)) {
+ !ssl_ext_key_share_add_serverhello(hs, &extensions) ||
+ !ssl_add_message_cbb(ssl, &cbb)) {
goto err;
}
diff --git a/src/ssl/tls_method.c b/src/ssl/tls_method.c
index eaad2ca..7778310 100644
--- a/src/ssl/tls_method.c
+++ b/src/ssl/tls_method.c
@@ -258,7 +258,14 @@
return TLS_method();
}
+static int ssl_noop_x509_check_client_CA_names(
+ STACK_OF(CRYPTO_BUFFER) *names) {
+ return 1;
+}
+
static void ssl_noop_x509_clear(CERT *cert) {}
+static void ssl_noop_x509_free(CERT *cert) {}
+static void ssl_noop_x509_dup(CERT *new_cert, const CERT *cert) {}
static void ssl_noop_x509_flush_cached_leaf(CERT *cert) {}
static void ssl_noop_x509_flush_cached_chain(CERT *cert) {}
static int ssl_noop_x509_session_cache_objects(SSL_SESSION *sess) {
@@ -269,12 +276,46 @@
return 1;
}
static void ssl_noop_x509_session_clear(SSL_SESSION *session) {}
+static int ssl_noop_x509_session_verify_cert_chain(SSL_SESSION *session,
+ SSL *ssl) {
+ return 0;
+}
-const SSL_X509_METHOD ssl_noop_x509_method = {
+static void ssl_noop_x509_hs_flush_cached_ca_names(SSL_HANDSHAKE *hs) {}
+static int ssl_noop_x509_ssl_new(SSL *ctx) { return 1; }
+static void ssl_noop_x509_ssl_free(SSL *ctx) { }
+static void ssl_noop_x509_ssl_flush_cached_client_CA(SSL *ssl) {}
+static int ssl_noop_x509_ssl_auto_chain_if_needed(SSL *ssl) { return 1; }
+static int ssl_noop_x509_ssl_ctx_new(SSL_CTX *ctx) { return 1; }
+static void ssl_noop_x509_ssl_ctx_free(SSL_CTX *ctx) { }
+static void ssl_noop_x509_ssl_ctx_flush_cached_client_CA(SSL_CTX *ctx) {}
+
+static const SSL_X509_METHOD ssl_noop_x509_method = {
+ ssl_noop_x509_check_client_CA_names,
ssl_noop_x509_clear,
+ ssl_noop_x509_free,
+ ssl_noop_x509_dup,
ssl_noop_x509_flush_cached_chain,
ssl_noop_x509_flush_cached_leaf,
ssl_noop_x509_session_cache_objects,
ssl_noop_x509_session_dup,
ssl_noop_x509_session_clear,
+ ssl_noop_x509_session_verify_cert_chain,
+ ssl_noop_x509_hs_flush_cached_ca_names,
+ ssl_noop_x509_ssl_new,
+ ssl_noop_x509_ssl_free,
+ ssl_noop_x509_ssl_flush_cached_client_CA,
+ ssl_noop_x509_ssl_auto_chain_if_needed,
+ ssl_noop_x509_ssl_ctx_new,
+ ssl_noop_x509_ssl_ctx_free,
+ ssl_noop_x509_ssl_ctx_flush_cached_client_CA,
};
+
+const SSL_METHOD *TLS_with_buffers_method(void) {
+ static const SSL_METHOD kMethod = {
+ 0,
+ &kTLSProtocolMethod,
+ &ssl_noop_x509_method,
+ };
+ return &kMethod;
+}
diff --git a/src/ssl/tls_record.c b/src/ssl/tls_record.c
index 6ff79c4..bf9735c 100644
--- a/src/ssl/tls_record.c
+++ b/src/ssl/tls_record.c
@@ -145,19 +145,6 @@
SSL_CIPHER_is_block_cipher(ssl->s3->aead_write_ctx->cipher);
}
-static int ssl_uses_short_header(const SSL *ssl,
- enum evp_aead_direction_t dir) {
- if (!ssl->s3->short_header) {
- return 0;
- }
-
- if (dir == evp_aead_open) {
- return ssl->s3->aead_read_ctx != NULL;
- }
-
- return ssl->s3->aead_write_ctx != NULL;
-}
-
int ssl_record_sequence_update(uint8_t *seq, size_t seq_len) {
for (size_t i = seq_len - 1; i < seq_len; i--) {
++seq[i];
@@ -173,8 +160,6 @@
size_t header_len;
if (SSL_is_dtls(ssl)) {
header_len = DTLS1_RT_HEADER_LENGTH;
- } else if (ssl_uses_short_header(ssl, evp_aead_open)) {
- header_len = 2;
} else {
header_len = SSL3_RT_HEADER_LENGTH;
}
@@ -188,17 +173,10 @@
SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx);
}
- size_t header_len;
- if (ssl_uses_short_header(ssl, evp_aead_seal)) {
- header_len = 2;
- } else {
- header_len = SSL3_RT_HEADER_LENGTH;
- }
-
- size_t ret =
- header_len + SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx);
+ size_t ret = SSL3_RT_HEADER_LENGTH +
+ SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx);
if (ssl_needs_record_splitting(ssl)) {
- ret += header_len;
+ ret += SSL3_RT_HEADER_LENGTH;
ret += ssl_cipher_get_record_split_len(ssl->s3->aead_write_ctx->cipher);
}
return ret;
@@ -209,8 +187,7 @@
return dtls_max_seal_overhead(ssl, dtls1_use_current_epoch);
}
- size_t ret =
- ssl_uses_short_header(ssl, evp_aead_seal) ? 2 : SSL3_RT_HEADER_LENGTH;
+ size_t ret = SSL3_RT_HEADER_LENGTH;
ret += SSL_AEAD_CTX_max_overhead(ssl->s3->aead_write_ctx);
/* TLS 1.3 needs an extra byte for the encrypted record type. */
if (ssl->s3->have_version &&
@@ -234,31 +211,11 @@
/* Decode the record header. */
uint8_t type;
uint16_t version, ciphertext_len;
- size_t header_len;
- if (ssl_uses_short_header(ssl, evp_aead_open)) {
- if (!CBS_get_u16(&cbs, &ciphertext_len)) {
- *out_consumed = 2;
- return ssl_open_record_partial;
- }
-
- if ((ciphertext_len & 0x8000) == 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- *out_alert = SSL_AD_DECODE_ERROR;
- return ssl_open_record_error;
- }
-
- ciphertext_len &= 0x7fff;
- type = SSL3_RT_APPLICATION_DATA;
- version = TLS1_VERSION;
- header_len = 2;
- } else {
- if (!CBS_get_u8(&cbs, &type) ||
- !CBS_get_u16(&cbs, &version) ||
- !CBS_get_u16(&cbs, &ciphertext_len)) {
- *out_consumed = SSL3_RT_HEADER_LENGTH;
- return ssl_open_record_partial;
- }
- header_len = SSL3_RT_HEADER_LENGTH;
+ if (!CBS_get_u8(&cbs, &type) ||
+ !CBS_get_u16(&cbs, &version) ||
+ !CBS_get_u16(&cbs, &ciphertext_len)) {
+ *out_consumed = SSL3_RT_HEADER_LENGTH;
+ return ssl_open_record_partial;
}
int version_ok;
@@ -290,11 +247,12 @@
/* Extract the body. */
CBS body;
if (!CBS_get_bytes(&cbs, &body, ciphertext_len)) {
- *out_consumed = header_len + (size_t)ciphertext_len;
+ *out_consumed = SSL3_RT_HEADER_LENGTH + (size_t)ciphertext_len;
return ssl_open_record_partial;
}
- ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER, in, header_len);
+ ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER, in,
+ SSL3_RT_HEADER_LENGTH);
*out_consumed = in_len - CBS_len(&cbs);
@@ -398,26 +356,24 @@
size_t in_len) {
assert(!buffers_alias(in, in_len, out, max_out));
- const int short_header = ssl_uses_short_header(ssl, evp_aead_seal);
- size_t header_len = short_header ? 2 : SSL3_RT_HEADER_LENGTH;
-
/* TLS 1.3 hides the actual record type inside the encrypted data. */
if (ssl->s3->have_version &&
ssl3_protocol_version(ssl) >= TLS1_3_VERSION &&
ssl->s3->aead_write_ctx != NULL) {
- if (in_len > in_len + header_len + 1 || max_out < in_len + header_len + 1) {
+ if (in_len > in_len + SSL3_RT_HEADER_LENGTH + 1 ||
+ max_out < in_len + SSL3_RT_HEADER_LENGTH + 1) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
return 0;
}
- OPENSSL_memcpy(out + header_len, in, in_len);
- out[header_len + in_len] = type;
- in = out + header_len;
+ OPENSSL_memcpy(out + SSL3_RT_HEADER_LENGTH, in, in_len);
+ out[SSL3_RT_HEADER_LENGTH + in_len] = type;
+ in = out + SSL3_RT_HEADER_LENGTH;
type = SSL3_RT_APPLICATION_DATA;
in_len++;
}
- if (max_out < header_len) {
+ if (max_out < SSL3_RT_HEADER_LENGTH) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
return 0;
}
@@ -433,13 +389,11 @@
}
/* Write the non-length portions of the header. */
- if (!short_header) {
- out[0] = type;
- out[1] = wire_version >> 8;
- out[2] = wire_version & 0xff;
- out += 3;
- max_out -= 3;
- }
+ out[0] = type;
+ out[1] = wire_version >> 8;
+ out[2] = wire_version & 0xff;
+ out += 3;
+ max_out -= 3;
/* Write the ciphertext, leaving two bytes for the length. */
size_t ciphertext_len;
@@ -457,13 +411,11 @@
}
out[0] = ciphertext_len >> 8;
out[1] = ciphertext_len & 0xff;
- if (short_header) {
- out[0] |= 0x80;
- }
- *out_len = header_len + ciphertext_len;
+ *out_len = SSL3_RT_HEADER_LENGTH + ciphertext_len;
- ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HEADER, out, header_len);
+ ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HEADER, out,
+ SSL3_RT_HEADER_LENGTH);
return 1;
}
@@ -485,7 +437,6 @@
out += frag_len;
max_out -= frag_len;
- assert(!ssl_uses_short_header(ssl, evp_aead_seal));
#if !defined(BORINGSSL_UNSAFE_FUZZER_MODE)
assert(SSL3_RT_HEADER_LENGTH + ssl_cipher_get_record_split_len(
ssl->s3->aead_write_ctx->cipher) ==