external/boringssl: Sync to 8ca0b41.
This includes the following changes:
https://boringssl.googlesource.com/boringssl/+log/9d908ba519f2cfe5e21561bdee3e224b94d14a89..8ca0b4127da11d766067ea6ec4122017ba0edb0e
Change-Id: I732653bc8fcba70707c615f8731ca75397a08736
diff --git a/src/ssl/d1_both.c b/src/ssl/d1_both.c
index cc95a70..8d8784b 100644
--- a/src/ssl/d1_both.c
+++ b/src/ssl/d1_both.c
@@ -249,12 +249,12 @@
/* TODO(davidben): What is this code doing and do we need it? */
if (ssl->d1->mtu < dtls1_min_mtu() &&
!(SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) {
- long mtu = BIO_ctrl(SSL_get_wbio(ssl), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
+ long mtu = BIO_ctrl(ssl->wbio, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
if (mtu >= 0 && mtu <= (1 << 30) && (unsigned)mtu >= dtls1_min_mtu()) {
ssl->d1->mtu = (unsigned)mtu;
} else {
ssl->d1->mtu = kDefaultMTU;
- BIO_ctrl(SSL_get_wbio(ssl), BIO_CTRL_DGRAM_SET_MTU, ssl->d1->mtu, NULL);
+ BIO_ctrl(ssl->wbio, BIO_CTRL_DGRAM_SET_MTU, ssl->d1->mtu, NULL);
}
}
@@ -274,7 +274,7 @@
}
ret -= overhead;
- size_t pending = BIO_wpending(SSL_get_wbio(ssl));
+ size_t pending = BIO_wpending(ssl->wbio);
if (ret <= pending) {
return 0;
}
@@ -290,7 +290,7 @@
/* During the handshake, wbio is buffered to pack messages together. Flush the
* buffer if the ChangeCipherSpec would not fit in a packet. */
if (dtls1_max_record_size(ssl) == 0) {
- int ret = BIO_flush(SSL_get_wbio(ssl));
+ int ret = BIO_flush(ssl->wbio);
if (ret <= 0) {
ssl->rwstate = SSL_WRITING;
return ret;
@@ -339,13 +339,13 @@
/* During the handshake, wbio is buffered to pack messages together. Flush
* the buffer if there isn't enough room to make progress. */
if (dtls1_max_record_size(ssl) < DTLS1_HM_HEADER_LENGTH + 1) {
- int flush_ret = BIO_flush(SSL_get_wbio(ssl));
+ int flush_ret = BIO_flush(ssl->wbio);
if (flush_ret <= 0) {
ssl->rwstate = SSL_WRITING;
ret = flush_ret;
goto err;
}
- assert(BIO_wpending(SSL_get_wbio(ssl)) == 0);
+ assert(BIO_wpending(ssl->wbio) == 0);
}
size_t todo = dtls1_max_record_size(ssl);
@@ -483,17 +483,6 @@
return frag;
}
-/* dtls1_max_handshake_message_len returns the maximum number of bytes
- * permitted in a DTLS handshake message for |ssl|. The minimum is 16KB, but may
- * be greater if the maximum certificate list size requires it. */
-static size_t dtls1_max_handshake_message_len(const SSL *ssl) {
- size_t max_len = DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH;
- if (max_len < ssl->max_cert_list) {
- return ssl->max_cert_list;
- }
- return max_len;
-}
-
/* dtls1_process_fragment reads a handshake fragment and processes it. It
* returns one if a fragment was successfully processed and 0 or -1 on error. */
static int dtls1_process_fragment(SSL *ssl) {
@@ -521,7 +510,7 @@
const size_t msg_len = msg_hdr.msg_len;
if (frag_off > msg_len || frag_off + frag_len < frag_off ||
frag_off + frag_len > msg_len ||
- msg_len > dtls1_max_handshake_message_len(ssl) ||
+ msg_len > ssl_max_handshake_message_len(ssl) ||
frag_len > ssl->s3->rrec.length) {
OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
@@ -567,9 +556,9 @@
}
/* dtls1_get_message reads a handshake message of message type |msg_type| (any
- * if |msg_type| == -1), maximum acceptable body length |max|. Read an entire
- * handshake message. Handshake messages arrive in fragments. */
-long dtls1_get_message(SSL *ssl, int st1, int stn, int msg_type, long max,
+ * if |msg_type| == -1). Read an entire handshake message. Handshake messages
+ * arrive in fragments. */
+long dtls1_get_message(SSL *ssl, int msg_type,
enum ssl_hash_message_t hash_message, int *ok) {
pitem *item = NULL;
hm_fragment *frag = NULL;
@@ -589,8 +578,9 @@
goto f_err;
}
*ok = 1;
+ assert(ssl->init_buf->length >= DTLS1_HM_HEADER_LENGTH);
ssl->init_msg = (uint8_t *)ssl->init_buf->data + DTLS1_HM_HEADER_LENGTH;
- ssl->init_num = (int)ssl->s3->tmp.message_size;
+ ssl->init_num = (int)ssl->init_buf->length - DTLS1_HM_HEADER_LENGTH;
return ssl->init_num;
}
@@ -610,17 +600,11 @@
assert(ssl->d1->handshake_read_seq == frag->msg_header.seq);
assert(frag->reassembly == NULL);
- if (frag->msg_header.msg_len > (size_t)max) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
- goto err;
- }
-
/* Reconstruct the assembled message. */
- size_t len;
CBB cbb;
CBB_zero(&cbb);
- if (!BUF_MEM_grow(ssl->init_buf, (size_t)frag->msg_header.msg_len +
- DTLS1_HM_HEADER_LENGTH) ||
+ if (!BUF_MEM_reserve(ssl->init_buf, (size_t)frag->msg_header.msg_len +
+ DTLS1_HM_HEADER_LENGTH) ||
!CBB_init_fixed(&cbb, (uint8_t *)ssl->init_buf->data,
ssl->init_buf->max) ||
!CBB_add_u8(&cbb, frag->msg_header.type) ||
@@ -629,19 +613,19 @@
!CBB_add_u24(&cbb, 0 /* frag_off */) ||
!CBB_add_u24(&cbb, frag->msg_header.msg_len) ||
!CBB_add_bytes(&cbb, frag->fragment, frag->msg_header.msg_len) ||
- !CBB_finish(&cbb, NULL, &len)) {
+ !CBB_finish(&cbb, NULL, &ssl->init_buf->length)) {
CBB_cleanup(&cbb);
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
- assert(len == (size_t)frag->msg_header.msg_len + DTLS1_HM_HEADER_LENGTH);
+ assert(ssl->init_buf->length ==
+ (size_t)frag->msg_header.msg_len + DTLS1_HM_HEADER_LENGTH);
ssl->d1->handshake_read_seq++;
/* TODO(davidben): This function has a lot of implicit outputs. Simplify the
* |ssl_get_message| API. */
ssl->s3->tmp.message_type = frag->msg_header.type;
- ssl->s3->tmp.message_size = frag->msg_header.msg_len;
ssl->init_msg = (uint8_t *)ssl->init_buf->data + DTLS1_HM_HEADER_LENGTH;
ssl->init_num = frag->msg_header.msg_len;
@@ -662,7 +646,6 @@
pitem_free(item);
dtls1_hm_fragment_free(frag);
- ssl->state = stn;
*ok = 1;
return ssl->init_num;
@@ -689,7 +672,7 @@
if (!SSL_in_init(ssl)) {
/* done, no need to send a retransmit */
- BIO_set_flags(SSL_get_rbio(ssl), BIO_FLAGS_READ);
+ BIO_set_flags(ssl->rbio, BIO_FLAGS_READ);
return code;
}
@@ -737,25 +720,39 @@
ret = dtls1_do_handshake_write(ssl, use_epoch);
}
- /* TODO(davidben): Check return value? */
- (void)BIO_flush(SSL_get_wbio(ssl));
return ret;
}
-
int dtls1_retransmit_buffered_messages(SSL *ssl) {
- pqueue sent = ssl->d1->sent_messages;
- piterator iter = pqueue_iterator(sent);
- pitem *item;
+ /* Ensure we are packing handshake messages. */
+ const int was_buffered = ssl_is_wbio_buffered(ssl);
+ assert(was_buffered == SSL_in_init(ssl));
+ if (!was_buffered && !ssl_init_wbio_buffer(ssl)) {
+ return -1;
+ }
+ assert(ssl_is_wbio_buffered(ssl));
+ int ret = -1;
+ piterator iter = pqueue_iterator(ssl->d1->sent_messages);
+ pitem *item;
for (item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter)) {
hm_fragment *frag = (hm_fragment *)item->data;
if (dtls1_retransmit_message(ssl, frag) <= 0) {
- return -1;
+ goto err;
}
}
- return 1;
+ ret = BIO_flush(ssl->wbio);
+ if (ret <= 0) {
+ ssl->rwstate = SSL_WRITING;
+ goto err;
+ }
+
+err:
+ if (!was_buffered) {
+ ssl_free_wbio_buffer(ssl);
+ }
+ return ret;
}
/* dtls1_buffer_change_cipher_spec adds a ChangeCipherSpec to the current
diff --git a/src/ssl/d1_clnt.c b/src/ssl/d1_clnt.c
index 2fc9094..19ad1f8 100644
--- a/src/ssl/d1_clnt.c
+++ b/src/ssl/d1_clnt.c
@@ -161,30 +161,27 @@
if (ssl->init_buf == NULL) {
buf = BUF_MEM_new();
if (buf == NULL ||
- !BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
+ !BUF_MEM_reserve(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
ret = -1;
goto end;
}
ssl->init_buf = buf;
buf = NULL;
}
+ ssl->init_num = 0;
- if (!ssl_init_wbio_buffer(ssl, 0)) {
+ if (!ssl_init_wbio_buffer(ssl)) {
ret = -1;
goto end;
}
- /* don't push the buffering BIO quite yet */
-
ssl->state = SSL3_ST_CW_CLNT_HELLO_A;
- ssl->init_num = 0;
ssl->d1->send_cookie = 0;
ssl->hit = 0;
break;
case SSL3_ST_CW_CLNT_HELLO_A:
case SSL3_ST_CW_CLNT_HELLO_B:
- ssl->shutdown = 0;
dtls1_start_timer(ssl);
ret = ssl3_send_client_hello(ssl);
if (ret <= 0) {
@@ -192,22 +189,14 @@
}
if (ssl->d1->send_cookie) {
- ssl->state = SSL3_ST_CW_FLUSH;
ssl->s3->tmp.next_state = SSL3_ST_CR_SRVR_HELLO_A;
} else {
- ssl->state = DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A;
+ ssl->s3->tmp.next_state = DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A;
}
-
- ssl->init_num = 0;
- /* turn on buffering for the next lot of output */
- if (ssl->bbio != ssl->wbio) {
- ssl->wbio = BIO_push(ssl->bbio, ssl->wbio);
- }
-
+ ssl->state = SSL3_ST_CW_FLUSH;
break;
case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
- case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B:
ret = dtls1_get_hello_verify(ssl);
if (ret <= 0) {
goto end;
@@ -219,11 +208,9 @@
} else {
ssl->state = SSL3_ST_CR_SRVR_HELLO_A;
}
- ssl->init_num = 0;
break;
case SSL3_ST_CR_SRVR_HELLO_A:
- case SSL3_ST_CR_SRVR_HELLO_B:
ret = ssl3_get_server_hello(ssl);
if (ret <= 0) {
goto end;
@@ -238,12 +225,10 @@
} else {
ssl->state = SSL3_ST_CR_CERT_A;
}
- ssl->init_num = 0;
break;
case SSL3_ST_CR_CERT_A:
- case SSL3_ST_CR_CERT_B:
- if (ssl_cipher_has_server_public_key(ssl->s3->tmp.new_cipher)) {
+ if (ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
ret = ssl3_get_server_certificate(ssl);
if (ret <= 0) {
goto end;
@@ -257,7 +242,6 @@
skip = 1;
ssl->state = SSL3_ST_CR_KEY_EXCH_A;
}
- ssl->init_num = 0;
break;
case SSL3_ST_VERIFY_SERVER_CERT:
@@ -267,31 +251,29 @@
}
ssl->state = SSL3_ST_CR_KEY_EXCH_A;
- ssl->init_num = 0;
break;
case SSL3_ST_CR_KEY_EXCH_A:
- case SSL3_ST_CR_KEY_EXCH_B:
ret = ssl3_get_server_key_exchange(ssl);
if (ret <= 0) {
goto end;
}
- ssl->state = SSL3_ST_CR_CERT_REQ_A;
- ssl->init_num = 0;
+ if (ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
+ ssl->state = SSL3_ST_CR_CERT_REQ_A;
+ } else {
+ ssl->state = SSL3_ST_CR_SRVR_DONE_A;
+ }
break;
case SSL3_ST_CR_CERT_REQ_A:
- case SSL3_ST_CR_CERT_REQ_B:
ret = ssl3_get_certificate_request(ssl);
if (ret <= 0) {
goto end;
}
ssl->state = SSL3_ST_CR_SRVR_DONE_A;
- ssl->init_num = 0;
break;
case SSL3_ST_CR_SRVR_DONE_A:
- case SSL3_ST_CR_SRVR_DONE_B:
ret = ssl3_get_server_done(ssl);
if (ret <= 0) {
goto end;
@@ -302,7 +284,6 @@
} else {
ssl->s3->tmp.next_state = SSL3_ST_CW_KEY_EXCH_A;
}
- ssl->init_num = 0;
ssl->state = ssl->s3->tmp.next_state;
break;
@@ -316,7 +297,6 @@
goto end;
}
ssl->state = SSL3_ST_CW_KEY_EXCH_A;
- ssl->init_num = 0;
break;
case SSL3_ST_CW_KEY_EXCH_A:
@@ -333,8 +313,6 @@
} else {
ssl->state = SSL3_ST_CW_CHANGE_A;
}
-
- ssl->init_num = 0;
break;
case SSL3_ST_CW_CERT_VRFY_A:
@@ -346,7 +324,6 @@
goto end;
}
ssl->state = SSL3_ST_CW_CHANGE_A;
- ssl->init_num = 0;
break;
case SSL3_ST_CW_CHANGE_A:
@@ -361,7 +338,6 @@
}
ssl->state = SSL3_ST_CW_FINISHED_A;
- ssl->init_num = 0;
if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
ret = -1;
@@ -392,27 +368,22 @@
ssl->s3->tmp.next_state = SSL3_ST_CR_CHANGE;
}
}
- ssl->init_num = 0;
break;
case SSL3_ST_CR_SESSION_TICKET_A:
- case SSL3_ST_CR_SESSION_TICKET_B:
ret = ssl3_get_new_session_ticket(ssl);
if (ret <= 0) {
goto end;
}
ssl->state = SSL3_ST_CR_CHANGE;
- ssl->init_num = 0;
break;
case SSL3_ST_CR_CERT_STATUS_A:
- case SSL3_ST_CR_CERT_STATUS_B:
ret = ssl3_get_cert_status(ssl);
if (ret <= 0) {
goto end;
}
ssl->state = SSL3_ST_VERIFY_SERVER_CERT;
- ssl->init_num = 0;
break;
case SSL3_ST_CR_CHANGE:
@@ -429,9 +400,7 @@
break;
case SSL3_ST_CR_FINISHED_A:
- case SSL3_ST_CR_FINISHED_B:
- ret =
- ssl3_get_finished(ssl, SSL3_ST_CR_FINISHED_A, SSL3_ST_CR_FINISHED_B);
+ ret = ssl3_get_finished(ssl);
if (ret <= 0) {
goto end;
}
@@ -443,7 +412,6 @@
ssl->state = SSL_ST_OK;
}
- ssl->init_num = 0;
break;
case SSL3_ST_CW_FLUSH:
@@ -462,6 +430,10 @@
/* Remove write buffering now. */
ssl_free_wbio_buffer(ssl);
+ /* |init_buf| cannot be released because post-handshake retransmit
+ * relies on that buffer being available as scratch space.
+ *
+ * TODO(davidben): Fix this. */
ssl->init_num = 0;
ssl->s3->initial_handshake_complete = 1;
@@ -510,11 +482,7 @@
CBS hello_verify_request, cookie;
uint16_t server_version;
- n = ssl->method->ssl_get_message(
- ssl, DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A,
- DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B, -1,
- /* Use the same maximum size as ssl3_get_server_hello. */
- 20000, ssl_hash_message, &ok);
+ n = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message, &ok);
if (!ok) {
return n;
diff --git a/src/ssl/d1_lib.c b/src/ssl/d1_lib.c
index e48fbf1..c1c9f91 100644
--- a/src/ssl/d1_lib.c
+++ b/src/ssl/d1_lib.c
@@ -157,18 +157,27 @@
return cipher->algorithm_enc != SSL_RC4 && cipher->algorithm_enc != SSL_eNULL;
}
+void DTLSv1_set_initial_timeout_duration(SSL *ssl, unsigned int duration_ms) {
+ ssl->initial_timeout_duration_ms = duration_ms;
+}
+
void dtls1_start_timer(SSL *ssl) {
- /* If timer is not set, initialize duration with 1 second */
+ /* If timer is not set, initialize duration (by default, 1 second) */
if (ssl->d1->next_timeout.tv_sec == 0 && ssl->d1->next_timeout.tv_usec == 0) {
- ssl->d1->timeout_duration = 1;
+ ssl->d1->timeout_duration_ms = ssl->initial_timeout_duration_ms;
}
/* Set timeout to current time */
get_current_time(ssl, &ssl->d1->next_timeout);
/* Add duration to current time */
- ssl->d1->next_timeout.tv_sec += ssl->d1->timeout_duration;
- BIO_ctrl(SSL_get_rbio(ssl), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
+ ssl->d1->next_timeout.tv_sec += ssl->d1->timeout_duration_ms / 1000;
+ ssl->d1->next_timeout.tv_usec += (ssl->d1->timeout_duration_ms % 1000) * 1000;
+ if (ssl->d1->next_timeout.tv_usec >= 1000000) {
+ 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);
}
@@ -230,9 +239,9 @@
}
void dtls1_double_timeout(SSL *ssl) {
- ssl->d1->timeout_duration *= 2;
- if (ssl->d1->timeout_duration > 60) {
- ssl->d1->timeout_duration = 60;
+ ssl->d1->timeout_duration_ms *= 2;
+ if (ssl->d1->timeout_duration_ms > 60000) {
+ ssl->d1->timeout_duration_ms = 60000;
}
dtls1_start_timer(ssl);
}
@@ -241,8 +250,8 @@
/* Reset everything */
ssl->d1->num_timeouts = 0;
memset(&ssl->d1->next_timeout, 0, sizeof(struct timeval));
- ssl->d1->timeout_duration = 1;
- BIO_ctrl(SSL_get_rbio(ssl), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
+ 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 */
dtls1_clear_record_buffer(ssl);
@@ -254,8 +263,7 @@
/* Reduce MTU after 2 unsuccessful retransmissions */
if (ssl->d1->num_timeouts > DTLS1_MTU_TIMEOUTS &&
!(SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) {
- long mtu = BIO_ctrl(SSL_get_wbio(ssl), BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0,
- NULL);
+ long mtu = BIO_ctrl(ssl->wbio, BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0, NULL);
if (mtu >= 0 && mtu <= (1 << 30) && (unsigned)mtu >= dtls1_min_mtu()) {
ssl->d1->mtu = (unsigned)mtu;
}
diff --git a/src/ssl/d1_pkt.c b/src/ssl/d1_pkt.c
index 4690486..34eeddb 100644
--- a/src/ssl/d1_pkt.c
+++ b/src/ssl/d1_pkt.c
@@ -131,6 +131,16 @@
* more data is needed. */
static int dtls1_get_record(SSL *ssl) {
again:
+ switch (ssl->s3->recv_shutdown) {
+ case ssl_shutdown_none:
+ break;
+ case ssl_shutdown_fatal_alert:
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
+ return -1;
+ case ssl_shutdown_close_notify:
+ return 0;
+ }
+
/* Read a new packet if there is no unconsumed one. */
if (ssl_read_buffer_len(ssl) == 0) {
int ret = ssl_read_buffer_extend_to(ssl, 0 /* unused */);
@@ -217,7 +227,9 @@
* alerts also aren't delivered reliably, so we may even time out because the
* peer never received our close_notify. Report to the caller that the channel
* has fully shut down. */
- ssl->shutdown |= SSL_RECEIVED_SHUTDOWN;
+ if (ssl->s3->recv_shutdown == ssl_shutdown_none) {
+ ssl->s3->recv_shutdown = ssl_shutdown_close_notify;
+ }
}
/* Return up to 'len' payload bytes received in 'type' records.
@@ -273,26 +285,7 @@
/* we now have a packet which can be read and processed */
- /* If the other end has shut down, throw anything we read away (even in
- * 'peek' mode) */
- if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) {
- rr->length = 0;
- return 0;
- }
-
-
if (type == rr->type) {
- /* Make sure that we are not getting application data when we
- * are doing a handshake for the first time. */
- if (SSL_in_init(ssl) && (type == SSL3_RT_APPLICATION_DATA) &&
- (ssl->s3->aead_read_ctx == NULL)) {
- /* TODO(davidben): Is this check redundant with the handshake_func
- * check? */
- al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, SSL_R_APP_DATA_IN_HANDSHAKE);
- goto f_err;
- }
-
/* Discard empty records. */
if (rr->length == 0) {
goto start;
@@ -354,8 +347,7 @@
if (alert_level == SSL3_AL_WARNING) {
if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
- ssl->s3->clean_shutdown = 1;
- ssl->shutdown |= SSL_RECEIVED_SHUTDOWN;
+ ssl->s3->recv_shutdown = ssl_shutdown_close_notify;
return 0;
}
} else if (alert_level == SSL3_AL_FATAL) {
@@ -364,7 +356,7 @@
OPENSSL_PUT_ERROR(SSL, SSL_AD_REASON_OFFSET + alert_descr);
BIO_snprintf(tmp, sizeof tmp, "%d", alert_descr);
ERR_add_error_data(2, "SSL alert number ", tmp);
- ssl->shutdown |= SSL_RECEIVED_SHUTDOWN;
+ ssl->s3->recv_shutdown = ssl_shutdown_fatal_alert;
SSL_CTX_remove_session(ssl->ctx, ssl->session);
return 0;
} else {
diff --git a/src/ssl/d1_srtp.c b/src/ssl/d1_srtp.c
index e7b1607..324bff7 100644
--- a/src/ssl/d1_srtp.c
+++ b/src/ssl/d1_srtp.c
@@ -124,7 +124,7 @@
#include "internal.h"
-const SRTP_PROTECTION_PROFILE kSRTPProfiles[] = {
+static const SRTP_PROTECTION_PROFILE kSRTPProfiles[] = {
{
"SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80,
},
@@ -188,6 +188,7 @@
}
} while (col);
+ sk_SRTP_PROTECTION_PROFILE_free(*out);
*out = profiles;
return 1;
diff --git a/src/ssl/d1_srvr.c b/src/ssl/d1_srvr.c
index d353281..9913e73 100644
--- a/src/ssl/d1_srvr.c
+++ b/src/ssl/d1_srvr.c
@@ -158,7 +158,7 @@
if (ssl->init_buf == NULL) {
buf = BUF_MEM_new();
- if (buf == NULL || !BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
+ if (buf == NULL || !BUF_MEM_reserve(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
ret = -1;
goto end;
}
@@ -168,7 +168,7 @@
ssl->init_num = 0;
- if (!ssl_init_wbio_buffer(ssl, 1)) {
+ if (!ssl_init_wbio_buffer(ssl)) {
ret = -1;
goto end;
}
@@ -185,15 +185,12 @@
case SSL3_ST_SR_CLNT_HELLO_A:
case SSL3_ST_SR_CLNT_HELLO_B:
case SSL3_ST_SR_CLNT_HELLO_C:
- case SSL3_ST_SR_CLNT_HELLO_D:
- ssl->shutdown = 0;
ret = ssl3_get_client_hello(ssl);
if (ret <= 0) {
goto end;
}
dtls1_stop_timer(ssl);
ssl->state = SSL3_ST_SW_SRVR_HELLO_A;
- ssl->init_num = 0;
break;
case SSL3_ST_SW_SRVR_HELLO_A:
@@ -213,12 +210,11 @@
} else {
ssl->state = SSL3_ST_SW_CERT_A;
}
- ssl->init_num = 0;
break;
case SSL3_ST_SW_CERT_A:
case SSL3_ST_SW_CERT_B:
- if (ssl_cipher_has_server_public_key(ssl->s3->tmp.new_cipher)) {
+ if (ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
dtls1_start_timer(ssl);
ret = ssl3_send_server_certificate(ssl);
if (ret <= 0) {
@@ -233,7 +229,6 @@
skip = 1;
ssl->state = SSL3_ST_SW_KEY_EXCH_A;
}
- ssl->init_num = 0;
break;
case SSL3_ST_SW_CERT_STATUS_A:
@@ -243,7 +238,6 @@
goto end;
}
ssl->state = SSL3_ST_SW_KEY_EXCH_A;
- ssl->init_num = 0;
break;
case SSL3_ST_SW_KEY_EXCH_A:
@@ -271,7 +265,6 @@
}
ssl->state = SSL3_ST_SW_CERT_REQ_A;
- ssl->init_num = 0;
break;
case SSL3_ST_SW_CERT_REQ_A:
@@ -286,7 +279,6 @@
skip = 1;
}
ssl->state = SSL3_ST_SW_SRVR_DONE_A;
- ssl->init_num = 0;
break;
case SSL3_ST_SW_SRVR_DONE_A:
@@ -298,7 +290,6 @@
}
ssl->s3->tmp.next_state = SSL3_ST_SR_CERT_A;
ssl->state = SSL3_ST_SW_FLUSH;
- ssl->init_num = 0;
break;
case SSL3_ST_SW_FLUSH:
@@ -311,36 +302,30 @@
break;
case SSL3_ST_SR_CERT_A:
- case SSL3_ST_SR_CERT_B:
if (ssl->s3->tmp.cert_request) {
ret = ssl3_get_client_certificate(ssl);
if (ret <= 0) {
goto end;
}
}
- ssl->init_num = 0;
ssl->state = SSL3_ST_SR_KEY_EXCH_A;
break;
case SSL3_ST_SR_KEY_EXCH_A:
case SSL3_ST_SR_KEY_EXCH_B:
- case SSL3_ST_SR_KEY_EXCH_C:
ret = ssl3_get_client_key_exchange(ssl);
if (ret <= 0) {
goto end;
}
ssl->state = SSL3_ST_SR_CERT_VRFY_A;
- ssl->init_num = 0;
break;
case SSL3_ST_SR_CERT_VRFY_A:
- case SSL3_ST_SR_CERT_VRFY_B:
ret = ssl3_get_cert_verify(ssl);
if (ret <= 0) {
goto end;
}
ssl->state = SSL3_ST_SR_CHANGE;
- ssl->init_num = 0;
break;
case SSL3_ST_SR_CHANGE:
@@ -358,9 +343,7 @@
break;
case SSL3_ST_SR_FINISHED_A:
- case SSL3_ST_SR_FINISHED_B:
- ret = ssl3_get_finished(ssl, SSL3_ST_SR_FINISHED_A,
- SSL3_ST_SR_FINISHED_B);
+ ret = ssl3_get_finished(ssl);
if (ret <= 0) {
goto end;
}
@@ -372,7 +355,6 @@
} else {
ssl->state = SSL3_ST_SW_CHANGE_A;
}
- ssl->init_num = 0;
break;
case SSL3_ST_SW_SESSION_TICKET_A:
@@ -382,7 +364,6 @@
goto end;
}
ssl->state = SSL3_ST_SW_CHANGE_A;
- ssl->init_num = 0;
break;
case SSL3_ST_SW_CHANGE_A:
@@ -395,7 +376,6 @@
}
ssl->state = SSL3_ST_SW_FINISHED_A;
- ssl->init_num = 0;
if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_SERVER_WRITE)) {
ret = -1;
@@ -416,7 +396,6 @@
} else {
ssl->s3->tmp.next_state = SSL_ST_OK;
}
- ssl->init_num = 0;
break;
case SSL_ST_OK:
@@ -425,6 +404,10 @@
/* remove buffering on output */
ssl_free_wbio_buffer(ssl);
+ /* |init_buf| cannot be released because post-handshake retransmit
+ * relies on that buffer being available as scratch space.
+ *
+ * TODO(davidben): Fix this. */
ssl->init_num = 0;
ssl->s3->initial_handshake_complete = 1;
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index 982f304..3b56e78 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -167,6 +167,7 @@
#define SSL_kECDHE 0x00000004L
/* SSL_kPSK is only set for plain PSK, not ECDHE_PSK. */
#define SSL_kPSK 0x00000008L
+#define SSL_kCECPQ1 0x00000010L
/* Bits for |algorithm_auth| (server authentication). */
#define SSL_aRSA 0x00000001L
@@ -174,6 +175,8 @@
/* SSL_aPSK is set for both PSK and ECDHE_PSK. */
#define SSL_aPSK 0x00000004L
+#define SSL_aCERT (SSL_aRSA | SSL_aECDSA)
+
/* Bits for |algorithm_enc| (symmetric encryption). */
#define SSL_3DES 0x00000001L
#define SSL_RC4 0x00000002L
@@ -239,17 +242,16 @@
* server key used in |cipher| or |EVP_PKEY_NONE| if there is none. */
int ssl_cipher_get_key_type(const SSL_CIPHER *cipher);
-/* ssl_cipher_has_server_public_key returns 1 if |cipher| involves a server
- * public key in the key exchange, sent in a server Certificate message.
- * Otherwise it returns 0. */
-int ssl_cipher_has_server_public_key(const SSL_CIPHER *cipher);
+/* ssl_cipher_uses_certificate_auth returns one if |cipher| authenticates the
+ * server and, optionally, the client with a certificate. Otherwise it returns
+ * zero. */
+int ssl_cipher_uses_certificate_auth(const SSL_CIPHER *cipher);
/* ssl_cipher_requires_server_key_exchange returns 1 if |cipher| requires a
* ServerKeyExchange message. Otherwise it returns 0.
*
- * Unlike |ssl_cipher_has_server_public_key|, this function may return zero
- * while still allowing |cipher| an optional ServerKeyExchange. This is the
- * case for plain PSK ciphers. */
+ * This function may return zero while still allowing |cipher| an optional
+ * ServerKeyExchange. This is the case for plain PSK ciphers. */
int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher);
/* ssl_cipher_get_record_split_len, for TLS 1.0 CBC mode ciphers, returns the
@@ -282,6 +284,8 @@
/* omit_version_in_ad is non-zero if the version should be omitted
* in the AEAD's ad parameter. */
char omit_version_in_ad;
+ /* omit_ad is non-zero if the AEAD's ad parameter should be omitted. */
+ char omit_ad;
/* xor_fixed_nonce is non-zero if the fixed nonce should be XOR'd into the
* variable nonce rather than prepended. */
char xor_fixed_nonce;
@@ -526,45 +530,66 @@
int ssl3_update_handshake_hash(SSL *ssl, const uint8_t *in, size_t in_len);
-/* ECDH curves. */
+/* ECDH groups. */
-#define SSL_CURVE_SECP256R1 23
-#define SSL_CURVE_SECP384R1 24
-#define SSL_CURVE_SECP521R1 25
-#define SSL_CURVE_X25519 29
+#define SSL_GROUP_SECP256R1 23
+#define SSL_GROUP_SECP384R1 24
+#define SSL_GROUP_SECP521R1 25
+#define SSL_GROUP_X25519 29
+#define SSL_GROUP_CECPQ1 65165
/* An SSL_ECDH_METHOD is an implementation of ECDH-like key exchanges for
* TLS. */
struct ssl_ecdh_method_st {
int nid;
- uint16_t curve_id;
+ uint16_t group_id;
const char name[8];
/* cleanup releases state in |ctx|. */
void (*cleanup)(SSL_ECDH_CTX *ctx);
- /* generate_keypair generates a keypair and writes the public value to
+ /* offer generates a keypair and writes the public value to
* |out_public_key|. It returns one on success and zero on error. */
- int (*generate_keypair)(SSL_ECDH_CTX *ctx, CBB *out_public_key);
+ int (*offer)(SSL_ECDH_CTX *ctx, CBB *out_public_key);
- /* compute_secret performs a key exchange against |peer_key| and, on
- * success, returns one and sets |*out_secret| and |*out_secret_len| to
- * a newly-allocated buffer containing the shared secret. The caller must
- * release this buffer with |OPENSSL_free|. Otherwise, it returns zero and
- * sets |*out_alert| to an alert to send to the peer. */
- int (*compute_secret)(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
- size_t *out_secret_len, uint8_t *out_alert,
- const uint8_t *peer_key, size_t peer_key_len);
+ /* accept performs a key exchange against the |peer_key| generated by |offer|.
+ * On success, it returns one, writes the public value to |out_public_key|,
+ * and sets |*out_secret| and |*out_secret_len| to a newly-allocated buffer
+ * containing the shared secret. The caller must release this buffer with
+ * |OPENSSL_free|. On failure, it returns zero and sets |*out_alert| to an
+ * alert to send to the peer. */
+ int (*accept)(SSL_ECDH_CTX *ctx, CBB *out_public_key, uint8_t **out_secret,
+ size_t *out_secret_len, uint8_t *out_alert,
+ const uint8_t *peer_key, size_t peer_key_len);
+
+ /* finish performs a key exchange against the |peer_key| generated by
+ * |accept|. On success, it returns one and sets |*out_secret| and
+ * |*out_secret_len| to a newly-allocated buffer containing the shared
+ * secret. The caller must release this buffer with |OPENSSL_free|. On
+ * failure, it returns zero and sets |*out_alert| to an alert to send to the
+ * peer. */
+ int (*finish)(SSL_ECDH_CTX *ctx, uint8_t **out_secret, size_t *out_secret_len,
+ uint8_t *out_alert, const uint8_t *peer_key,
+ size_t peer_key_len);
+
+ /* get_key initializes |out| with a length-prefixed key from |cbs|. It returns
+ * one on success and zero on error. */
+ int (*get_key)(CBS *cbs, CBS *out);
+
+ /* add_key initializes |out_contents| to receive a key. Typically it will then
+ * be passed to |offer| or |accept|. It returns one on success and zero on
+ * error. */
+ int (*add_key)(CBB *cbb, CBB *out_contents);
} /* SSL_ECDH_METHOD */;
-/* ssl_nid_to_curve_id looks up the curve corresponding to |nid|. On success, it
- * sets |*out_curve_id| to the curve ID and returns one. Otherwise, it returns
+/* ssl_nid_to_group_id looks up the group corresponding to |nid|. On success, it
+ * sets |*out_group_id| to the group ID and returns one. Otherwise, it returns
* zero. */
-int ssl_nid_to_curve_id(uint16_t *out_curve_id, int nid);
+int ssl_nid_to_group_id(uint16_t *out_group_id, int nid);
-/* SSL_ECDH_CTX_init sets up |ctx| for use with curve |curve_id|. It returns one
+/* SSL_ECDH_CTX_init sets up |ctx| for use with curve |group_id|. It returns one
* on success and zero on error. */
-int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t curve_id);
+int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t group_id);
/* SSL_ECDH_CTX_init_for_dhe sets up |ctx| for use with legacy DHE-based ciphers
* where the server specifies a group. It takes ownership of |params|. */
@@ -574,12 +599,31 @@
* call it in the zero state. */
void SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX *ctx);
-/* The following functions call the corresponding method of
- * |SSL_ECDH_METHOD|. */
-int SSL_ECDH_CTX_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out_public_key);
-int SSL_ECDH_CTX_compute_secret(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
- size_t *out_secret_len, uint8_t *out_alert,
- const uint8_t *peer_key, size_t peer_key_len);
+/* SSL_ECDH_CTX_get_key calls the |get_key| method of |SSL_ECDH_METHOD|. */
+int SSL_ECDH_CTX_get_key(SSL_ECDH_CTX *ctx, CBS *cbs, CBS *out);
+
+/* SSL_ECDH_CTX_add_key calls the |add_key| method of |SSL_ECDH_METHOD|. */
+int SSL_ECDH_CTX_add_key(SSL_ECDH_CTX *ctx, CBB *cbb, CBB *out_contents);
+
+/* SSL_ECDH_CTX_offer calls the |offer| method of |SSL_ECDH_METHOD|. */
+int SSL_ECDH_CTX_offer(SSL_ECDH_CTX *ctx, CBB *out_public_key);
+
+/* SSL_ECDH_CTX_accept calls the |accept| method of |SSL_ECDH_METHOD|. */
+int SSL_ECDH_CTX_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
+ uint8_t **out_secret, size_t *out_secret_len,
+ uint8_t *out_alert, const uint8_t *peer_key,
+ size_t peer_key_len);
+
+/* SSL_ECDH_CTX_finish the |finish| method of |SSL_ECDH_METHOD|. */
+int SSL_ECDH_CTX_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
+ size_t *out_secret_len, uint8_t *out_alert,
+ const uint8_t *peer_key, size_t peer_key_len);
+
+/* Handshake messages. */
+
+/* ssl_max_handshake_message_len returns the maximum number of bytes permitted
+ * in a handshake message for |ssl|. */
+size_t ssl_max_handshake_message_len(const SSL *ssl);
/* Transport buffers. */
@@ -828,8 +872,7 @@
void (*ssl_free)(SSL *ssl);
int (*ssl_accept)(SSL *ssl);
int (*ssl_connect)(SSL *ssl);
- long (*ssl_get_message)(SSL *ssl, int header_state, int body_state,
- int msg_type, long max,
+ long (*ssl_get_message)(SSL *ssl, int msg_type,
enum ssl_hash_message_t hash_message, int *ok);
int (*ssl_read_app_data)(SSL *ssl, uint8_t *buf, int len, int peek);
int (*ssl_read_change_cipher_spec)(SSL *ssl);
@@ -956,13 +999,12 @@
* timeout. */
struct timeval next_timeout;
- /* Timeout duration */
- unsigned short timeout_duration;
+ /* timeout_duration_ms is the timeout duration in milliseconds. */
+ unsigned timeout_duration_ms;
} DTLS1_STATE;
extern const SSL3_ENC_METHOD TLSv1_enc_data;
extern const SSL3_ENC_METHOD SSLv3_enc_data;
-extern const SRTP_PROTECTION_PROFILE kSRTPProfiles[];
int ssl_clear_bad_session(SSL *ssl);
CERT *ssl_cert_new(void);
@@ -1020,14 +1062,14 @@
int ssl3_send_server_certificate(SSL *ssl);
int ssl3_send_new_session_ticket(SSL *ssl);
int ssl3_send_certificate_status(SSL *ssl);
-int ssl3_get_finished(SSL *ssl, int state_a, int state_b);
+int ssl3_get_finished(SSL *ssl);
int ssl3_send_change_cipher_spec(SSL *ssl, int state_a, int state_b);
void ssl3_cleanup_key_block(SSL *ssl);
int ssl3_do_write(SSL *ssl, int type);
int ssl3_send_alert(SSL *ssl, int level, int desc);
int ssl3_get_req_cert_type(SSL *ssl, uint8_t *p);
-long ssl3_get_message(SSL *ssl, int header_state, int body_state, int msg_type,
- long max, enum ssl_hash_message_t hash_message, int *ok);
+long ssl3_get_message(SSL *ssl, int msg_type,
+ enum ssl_hash_message_t hash_message, int *ok);
/* ssl3_hash_current_message incorporates the current handshake message into the
* handshake hash. It returns one on success and zero on allocation failure. */
@@ -1132,11 +1174,15 @@
int dtls1_connect(SSL *ssl);
void dtls1_free(SSL *ssl);
-long dtls1_get_message(SSL *ssl, int st1, int stn, int mt, long max,
- enum ssl_hash_message_t hash_message, int *ok);
+long dtls1_get_message(SSL *ssl, int mt, enum ssl_hash_message_t hash_message,
+ int *ok);
int dtls1_dispatch_alert(SSL *ssl);
-int ssl_init_wbio_buffer(SSL *ssl, int push);
+/* ssl_is_wbio_buffered returns one if |ssl|'s write BIO is buffered and zero
+ * otherwise. */
+int ssl_is_wbio_buffered(const SSL *ssl);
+
+int ssl_init_wbio_buffer(SSL *ssl);
void ssl_free_wbio_buffer(SSL *ssl);
int tls1_change_cipher_state(SSL *ssl, int which);
@@ -1147,21 +1193,21 @@
char ssl_early_callback_init(struct ssl_early_callback_ctx *ctx);
-/* tls1_check_curve_id returns one if |curve_id| is consistent with both our
- * and the peer's curve preferences. Note: if called as the client, only our
+/* tls1_check_group_id returns one if |group_id| is consistent with both our
+ * and the peer's group preferences. Note: if called as the client, only our
* preferences are checked; the peer (the server) does not send preferences. */
-int tls1_check_curve_id(SSL *ssl, uint16_t curve_id);
+int tls1_check_group_id(SSL *ssl, uint16_t group_id);
-/* tls1_get_shared_curve sets |*out_curve_id| to the first preferred shared
- * curve between client and server preferences and returns one. If none may be
+/* tls1_get_shared_group sets |*out_group_id| to the first preferred shared
+ * group between client and server preferences and returns one. If none may be
* found, it returns zero. */
-int tls1_get_shared_curve(SSL *ssl, uint16_t *out_curve_id);
+int tls1_get_shared_group(SSL *ssl, uint16_t *out_group_id);
/* tls1_set_curves converts the array of |ncurves| NIDs pointed to by |curves|
- * into a newly allocated array of TLS curve IDs. On success, the function
- * returns one and writes the array to |*out_curve_ids| and its size to
- * |*out_curve_ids_len|. Otherwise, it returns zero. */
-int tls1_set_curves(uint16_t **out_curve_ids, size_t *out_curve_ids_len,
+ * into a newly allocated array of TLS group IDs. On success, the function
+ * returns one and writes the array to |*out_group_ids| and its size to
+ * |*out_group_ids_len|. Otherwise, it returns zero. */
+int tls1_set_curves(uint16_t **out_group_ids, size_t *out_group_ids_len,
const int *curves, size_t ncurves);
/* tls1_check_ec_cert returns one if |x| is an ECC certificate with curve and
diff --git a/src/ssl/s3_both.c b/src/ssl/s3_both.c
index 5d364ab..d5e304d 100644
--- a/src/ssl/s3_both.c
+++ b/src/ssl/s3_both.c
@@ -211,13 +211,13 @@
ssl, !ssl->server, ssl->s3->tmp.peer_finish_md);
}
-int ssl3_get_finished(SSL *ssl, int a, int b) {
+int ssl3_get_finished(SSL *ssl) {
int al, finished_len, ok;
long message_len;
uint8_t *p;
- message_len = ssl->method->ssl_get_message(
- ssl, a, b, SSL3_MT_FINISHED, EVP_MAX_MD_SIZE, ssl_dont_hash_message, &ok);
+ message_len = ssl->method->ssl_get_message(ssl, SSL3_MT_FINISHED,
+ ssl_dont_hash_message, &ok);
if (!ok) {
return message_len;
@@ -298,125 +298,122 @@
return ssl_set_handshake_header(ssl, SSL3_MT_CERTIFICATE, l);
}
-/* Obtain handshake message of message type |msg_type| (any if |msg_type| == -1),
- * maximum acceptable body length |max|. The first four bytes (msg_type and
- * length) are read in state |header_state|, the body is read in state
- * |body_state|. */
-long ssl3_get_message(SSL *ssl, int header_state, int body_state, int msg_type,
- long max, enum ssl_hash_message_t hash_message, int *ok) {
- uint8_t *p;
- unsigned long l;
- long n;
- int al;
+size_t ssl_max_handshake_message_len(const SSL *ssl) {
+ /* kMaxMessageLen is the default maximum message size for handshakes which do
+ * not accept peer certificate chains. */
+ static const size_t kMaxMessageLen = 16384;
+
+ if ((!ssl->server || (ssl->verify_mode & SSL_VERIFY_PEER)) &&
+ kMaxMessageLen < ssl->max_cert_list) {
+ return ssl->max_cert_list;
+ }
+ return kMaxMessageLen;
+}
+
+static int extend_handshake_buffer(SSL *ssl, size_t length) {
+ if (!BUF_MEM_reserve(ssl->init_buf, length)) {
+ return -1;
+ }
+ while (ssl->init_buf->length < length) {
+ int ret =
+ ssl3_read_bytes(ssl, SSL3_RT_HANDSHAKE,
+ (uint8_t *)ssl->init_buf->data + ssl->init_buf->length,
+ length - ssl->init_buf->length, 0);
+ if (ret <= 0) {
+ return ret;
+ }
+ ssl->init_buf->length += (size_t)ret;
+ }
+ return 1;
+}
+
+/* Obtain handshake message of message type |msg_type| (any if |msg_type| ==
+ * -1). */
+long ssl3_get_message(SSL *ssl, int msg_type,
+ enum ssl_hash_message_t hash_message, int *ok) {
+ *ok = 0;
if (ssl->s3->tmp.reuse_message) {
/* A ssl_dont_hash_message call cannot be combined with reuse_message; the
* ssl_dont_hash_message would have to have been applied to the previous
* call. */
assert(hash_message == ssl_hash_message);
+ assert(ssl->s3->tmp.message_complete);
ssl->s3->tmp.reuse_message = 0;
if (msg_type >= 0 && ssl->s3->tmp.message_type != msg_type) {
- al = SSL_AD_UNEXPECTED_MESSAGE;
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
- goto f_err;
+ return -1;
}
*ok = 1;
- ssl->state = body_state;
+ assert(ssl->init_buf->length >= 4);
ssl->init_msg = (uint8_t *)ssl->init_buf->data + 4;
- ssl->init_num = (int)ssl->s3->tmp.message_size;
+ ssl->init_num = (int)ssl->init_buf->length - 4;
return ssl->init_num;
}
- p = (uint8_t *)ssl->init_buf->data;
-
- if (ssl->state == header_state) {
- assert(ssl->init_num < 4);
-
- for (;;) {
- while (ssl->init_num < 4) {
- int bytes_read = ssl3_read_bytes(
- ssl, SSL3_RT_HANDSHAKE, &p[ssl->init_num], 4 - ssl->init_num, 0);
- if (bytes_read <= 0) {
- *ok = 0;
- return bytes_read;
- }
- ssl->init_num += bytes_read;
- }
-
- static const uint8_t kHelloRequest[4] = {SSL3_MT_HELLO_REQUEST, 0, 0, 0};
- if (ssl->server || memcmp(p, kHelloRequest, sizeof(kHelloRequest)) != 0) {
- break;
- }
-
- /* The server may always send 'Hello Request' messages -- we are doing
- * a handshake anyway now, so ignore them if their format is correct.
- * Does not count for 'Finished' MAC. */
- ssl->init_num = 0;
-
- if (ssl->msg_callback) {
- ssl->msg_callback(0, ssl->version, SSL3_RT_HANDSHAKE, p, 4, ssl,
- ssl->msg_callback_arg);
- }
- }
-
- /* ssl->init_num == 4 */
-
- if (msg_type >= 0 && *p != msg_type) {
- al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
- goto f_err;
- }
- ssl->s3->tmp.message_type = *(p++);
-
- n2l3(p, l);
- if (l > (unsigned long)max) {
- al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
- goto f_err;
- }
-
- if (l && !BUF_MEM_grow_clean(ssl->init_buf, l + 4)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
- goto err;
- }
- ssl->s3->tmp.message_size = l;
- ssl->state = body_state;
-
- ssl->init_msg = (uint8_t *)ssl->init_buf->data + 4;
- ssl->init_num = 0;
+again:
+ if (ssl->s3->tmp.message_complete) {
+ ssl->s3->tmp.message_complete = 0;
+ ssl->init_buf->length = 0;
}
- /* next state (body_state) */
- p = ssl->init_msg;
- n = ssl->s3->tmp.message_size - ssl->init_num;
- while (n > 0) {
- int bytes_read =
- ssl3_read_bytes(ssl, SSL3_RT_HANDSHAKE, &p[ssl->init_num], n, 0);
- if (bytes_read <= 0) {
- *ok = 0;
- return bytes_read;
- }
- ssl->init_num += bytes_read;
- n -= bytes_read;
+ /* Read the message header, if we haven't yet. */
+ int ret = extend_handshake_buffer(ssl, 4);
+ if (ret <= 0) {
+ return ret;
}
+ /* Parse out the length. Cap it so the peer cannot force us to buffer up to
+ * 2^24 bytes. */
+ const uint8_t *p = (uint8_t *)ssl->init_buf->data;
+ size_t msg_len = (((uint32_t)p[1]) << 16) | (((uint32_t)p[2]) << 8) | p[3];
+ if (msg_len > ssl_max_handshake_message_len(ssl)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ return -1;
+ }
+
+ /* Read the message body, if we haven't yet. */
+ ret = extend_handshake_buffer(ssl, 4 + msg_len);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ /* We have now received a complete message. */
+ ssl->s3->tmp.message_complete = 1;
+ if (ssl->msg_callback) {
+ ssl->msg_callback(0, ssl->version, SSL3_RT_HANDSHAKE, ssl->init_buf->data,
+ ssl->init_buf->length, ssl, ssl->msg_callback_arg);
+ }
+
+ static const uint8_t kHelloRequest[4] = {SSL3_MT_HELLO_REQUEST, 0, 0, 0};
+ if (!ssl->server && ssl->init_buf->length == sizeof(kHelloRequest) &&
+ memcmp(kHelloRequest, ssl->init_buf->data, sizeof(kHelloRequest)) == 0) {
+ /* The server may always send 'Hello Request' messages -- we are doing a
+ * handshake anyway now, so ignore them if their format is correct. Does
+ * not count for 'Finished' MAC. */
+ goto again;
+ }
+
+ uint8_t actual_type = ((const uint8_t *)ssl->init_buf->data)[0];
+ if (msg_type >= 0 && actual_type != msg_type) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+ ssl->s3->tmp.message_type = actual_type;
+
+ ssl->init_msg = (uint8_t*)ssl->init_buf->data + 4;
+ ssl->init_num = ssl->init_buf->length - 4;
+
/* Feed this message into MAC computation. */
if (hash_message == ssl_hash_message && !ssl3_hash_current_message(ssl)) {
- goto err;
+ return -1;
}
- if (ssl->msg_callback) {
- ssl->msg_callback(0, ssl->version, SSL3_RT_HANDSHAKE, ssl->init_buf->data,
- (size_t)ssl->init_num + 4, ssl, ssl->msg_callback_arg);
- }
+
*ok = 1;
return ssl->init_num;
-
-f_err:
- ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
-
-err:
- *ok = 0;
- return -1;
}
int ssl3_hash_current_message(SSL *ssl) {
diff --git a/src/ssl/s3_clnt.c b/src/ssl/s3_clnt.c
index 6f381cf..2665f15 100644
--- a/src/ssl/s3_clnt.c
+++ b/src/ssl/s3_clnt.c
@@ -200,7 +200,7 @@
if (ssl->init_buf == NULL) {
buf = BUF_MEM_new();
if (buf == NULL ||
- !BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
+ !BUF_MEM_reserve(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
ret = -1;
goto end;
}
@@ -208,14 +208,13 @@
ssl->init_buf = buf;
buf = NULL;
}
+ ssl->init_num = 0;
- if (!ssl_init_wbio_buffer(ssl, 0)) {
+ if (!ssl_init_wbio_buffer(ssl)) {
ret = -1;
goto end;
}
- /* don't push the buffering BIO quite yet */
-
if (!ssl3_init_handshake_buffer(ssl)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
ret = -1;
@@ -223,28 +222,19 @@
}
ssl->state = SSL3_ST_CW_CLNT_HELLO_A;
- ssl->init_num = 0;
break;
case SSL3_ST_CW_CLNT_HELLO_A:
case SSL3_ST_CW_CLNT_HELLO_B:
- ssl->shutdown = 0;
ret = ssl3_send_client_hello(ssl);
if (ret <= 0) {
goto end;
}
- ssl->state = SSL3_ST_CR_SRVR_HELLO_A;
- ssl->init_num = 0;
-
- /* turn on buffering for the next lot of output */
- if (ssl->bbio != ssl->wbio) {
- ssl->wbio = BIO_push(ssl->bbio, ssl->wbio);
- }
-
+ ssl->s3->tmp.next_state = SSL3_ST_CR_SRVR_HELLO_A;
+ ssl->state = SSL3_ST_CW_FLUSH;
break;
case SSL3_ST_CR_SRVR_HELLO_A:
- case SSL3_ST_CR_SRVR_HELLO_B:
ret = ssl3_get_server_hello(ssl);
if (ret <= 0) {
goto end;
@@ -259,12 +249,10 @@
} else {
ssl->state = SSL3_ST_CR_CERT_A;
}
- ssl->init_num = 0;
break;
case SSL3_ST_CR_CERT_A:
- case SSL3_ST_CR_CERT_B:
- if (ssl_cipher_has_server_public_key(ssl->s3->tmp.new_cipher)) {
+ if (ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
ret = ssl3_get_server_certificate(ssl);
if (ret <= 0) {
goto end;
@@ -278,7 +266,6 @@
skip = 1;
ssl->state = SSL3_ST_CR_KEY_EXCH_A;
}
- ssl->init_num = 0;
break;
case SSL3_ST_VERIFY_SERVER_CERT:
@@ -288,31 +275,29 @@
}
ssl->state = SSL3_ST_CR_KEY_EXCH_A;
- ssl->init_num = 0;
break;
case SSL3_ST_CR_KEY_EXCH_A:
- case SSL3_ST_CR_KEY_EXCH_B:
ret = ssl3_get_server_key_exchange(ssl);
if (ret <= 0) {
goto end;
}
- ssl->state = SSL3_ST_CR_CERT_REQ_A;
- ssl->init_num = 0;
+ if (ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
+ ssl->state = SSL3_ST_CR_CERT_REQ_A;
+ } else {
+ ssl->state = SSL3_ST_CR_SRVR_DONE_A;
+ }
break;
case SSL3_ST_CR_CERT_REQ_A:
- case SSL3_ST_CR_CERT_REQ_B:
ret = ssl3_get_certificate_request(ssl);
if (ret <= 0) {
goto end;
}
ssl->state = SSL3_ST_CR_SRVR_DONE_A;
- ssl->init_num = 0;
break;
case SSL3_ST_CR_SRVR_DONE_A:
- case SSL3_ST_CR_SRVR_DONE_B:
ret = ssl3_get_server_done(ssl);
if (ret <= 0) {
goto end;
@@ -322,7 +307,6 @@
} else {
ssl->state = SSL3_ST_CW_KEY_EXCH_A;
}
- ssl->init_num = 0;
break;
@@ -335,7 +319,6 @@
goto end;
}
ssl->state = SSL3_ST_CW_KEY_EXCH_A;
- ssl->init_num = 0;
break;
case SSL3_ST_CW_KEY_EXCH_A:
@@ -351,8 +334,6 @@
} else {
ssl->state = SSL3_ST_CW_CHANGE_A;
}
-
- ssl->init_num = 0;
break;
case SSL3_ST_CW_CERT_VRFY_A:
@@ -363,7 +344,6 @@
goto end;
}
ssl->state = SSL3_ST_CW_CHANGE_A;
- ssl->init_num = 0;
break;
case SSL3_ST_CW_CHANGE_A:
@@ -381,7 +361,6 @@
if (ssl->s3->next_proto_neg_seen) {
ssl->state = SSL3_ST_CW_NEXT_PROTO_A;
}
- ssl->init_num = 0;
if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
ret = -1;
@@ -448,27 +427,22 @@
}
}
}
- ssl->init_num = 0;
break;
case SSL3_ST_CR_SESSION_TICKET_A:
- case SSL3_ST_CR_SESSION_TICKET_B:
ret = ssl3_get_new_session_ticket(ssl);
if (ret <= 0) {
goto end;
}
ssl->state = SSL3_ST_CR_CHANGE;
- ssl->init_num = 0;
break;
case SSL3_ST_CR_CERT_STATUS_A:
- case SSL3_ST_CR_CERT_STATUS_B:
ret = ssl3_get_cert_status(ssl);
if (ret <= 0) {
goto end;
}
ssl->state = SSL3_ST_VERIFY_SERVER_CERT;
- ssl->init_num = 0;
break;
case SSL3_ST_CR_CHANGE:
@@ -485,9 +459,7 @@
break;
case SSL3_ST_CR_FINISHED_A:
- case SSL3_ST_CR_FINISHED_B:
- ret = ssl3_get_finished(ssl, SSL3_ST_CR_FINISHED_A,
- SSL3_ST_CR_FINISHED_B);
+ ret = ssl3_get_finished(ssl);
if (ret <= 0) {
goto end;
}
@@ -497,7 +469,6 @@
} else {
ssl->state = SSL_ST_OK;
}
- ssl->init_num = 0;
break;
case SSL3_ST_CW_FLUSH:
@@ -528,13 +499,13 @@
BUF_MEM_free(ssl->init_buf);
ssl->init_buf = NULL;
+ ssl->init_num = 0;
/* Remove write buffering now. */
ssl_free_wbio_buffer(ssl);
const int is_initial_handshake = !ssl->s3->initial_handshake_complete;
- ssl->init_num = 0;
ssl->s3->tmp.in_false_start = 0;
ssl->s3->initial_handshake_complete = 1;
@@ -733,10 +704,8 @@
uint16_t server_version, cipher_suite;
uint8_t compression_method;
- n = ssl->method->ssl_get_message(ssl, SSL3_ST_CR_SRVR_HELLO_A,
- SSL3_ST_CR_SRVR_HELLO_B, SSL3_MT_SERVER_HELLO,
- 20000, /* ?? */
- ssl_hash_message, &ok);
+ n = ssl->method->ssl_get_message(ssl, SSL3_MT_SERVER_HELLO, ssl_hash_message,
+ &ok);
if (!ok) {
uint32_t err = ERR_peek_error();
@@ -866,7 +835,8 @@
/* If doing a full handshake with TLS 1.2, the server may request a client
* certificate which requires hashing the handshake transcript under a
* different hash. Otherwise, the handshake buffer may be released. */
- if (ssl->hit || ssl3_protocol_version(ssl) < TLS1_2_VERSION) {
+ if (ssl->hit || ssl3_protocol_version(ssl) < TLS1_2_VERSION ||
+ !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
ssl3_free_handshake_buffer(ssl);
}
@@ -963,9 +933,8 @@
CBS cbs, certificate_list;
const uint8_t *data;
- n = ssl->method->ssl_get_message(ssl, SSL3_ST_CR_CERT_A, SSL3_ST_CR_CERT_B,
- SSL3_MT_CERTIFICATE, (long)ssl->max_cert_list,
- ssl_hash_message, &ok);
+ n = ssl->method->ssl_get_message(ssl, SSL3_MT_CERTIFICATE, ssl_hash_message,
+ &ok);
if (!ok) {
return n;
@@ -1053,11 +1022,7 @@
EC_KEY *ecdh = NULL;
EC_POINT *srvr_ecpoint = NULL;
- /* use same message size as in ssl3_get_certificate_request() as
- * ServerKeyExchange message may be skipped */
- long n = ssl->method->ssl_get_message(
- ssl, SSL3_ST_CR_KEY_EXCH_A, SSL3_ST_CR_KEY_EXCH_B, -1, ssl->max_cert_list,
- ssl_hash_message, &ok);
+ long n = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message, &ok);
if (!ok) {
return n;
}
@@ -1167,26 +1132,27 @@
if (!CBS_stow(&dh_Ys, &ssl->s3->tmp.peer_key, &peer_key_len)) {
goto err;
}
- /* |dh_Ys| has a u16 length prefix, so this fits in a |uint16_t|. */
+ /* |dh_Ys| was initialized with CBS_get_u16_length_prefixed, so peer_key_len
+ * fits in a uint16_t. */
assert(sizeof(ssl->s3->tmp.peer_key_len) == 2 && peer_key_len <= 0xffff);
ssl->s3->tmp.peer_key_len = (uint16_t)peer_key_len;
} else if (alg_k & SSL_kECDHE) {
/* Parse the server parameters. */
- uint8_t curve_type;
- uint16_t curve_id;
+ uint8_t group_type;
+ uint16_t group_id;
CBS point;
- if (!CBS_get_u8(&server_key_exchange, &curve_type) ||
- curve_type != NAMED_CURVE_TYPE ||
- !CBS_get_u16(&server_key_exchange, &curve_id) ||
+ if (!CBS_get_u8(&server_key_exchange, &group_type) ||
+ group_type != NAMED_CURVE_TYPE ||
+ !CBS_get_u16(&server_key_exchange, &group_id) ||
!CBS_get_u8_length_prefixed(&server_key_exchange, &point)) {
al = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
- ssl->session->key_exchange_info = curve_id;
+ ssl->session->key_exchange_info = group_id;
- /* Ensure the curve is consistent with preferences. */
- if (!tls1_check_curve_id(ssl, curve_id)) {
+ /* Ensure the group is consistent with preferences. */
+ if (!tls1_check_group_id(ssl, group_id)) {
al = SSL_AD_ILLEGAL_PARAMETER;
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
goto f_err;
@@ -1194,11 +1160,31 @@
/* Initialize ECDH and save the peer public key for later. */
size_t peer_key_len;
- if (!SSL_ECDH_CTX_init(&ssl->s3->tmp.ecdh_ctx, curve_id) ||
+ if (!SSL_ECDH_CTX_init(&ssl->s3->tmp.ecdh_ctx, group_id) ||
!CBS_stow(&point, &ssl->s3->tmp.peer_key, &peer_key_len)) {
goto err;
}
- /* |point| has a u8 length prefix, so this fits in a |uint16_t|. */
+ /* |point| was initialized with CBS_get_u8_length_prefixed, so peer_key_len
+ * fits in a uint16_t. */
+ assert(sizeof(ssl->s3->tmp.peer_key_len) == 2 && peer_key_len <= 0xffff);
+ ssl->s3->tmp.peer_key_len = (uint16_t)peer_key_len;
+ } else if (alg_k & SSL_kCECPQ1) {
+ if (!SSL_ECDH_CTX_init(&ssl->s3->tmp.ecdh_ctx, SSL_GROUP_CECPQ1)) {
+ goto err;
+ }
+ CBS key;
+ if (!CBS_get_u16_length_prefixed(&server_key_exchange, &key)) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+
+ size_t peer_key_len;
+ if (!CBS_stow(&key, &ssl->s3->tmp.peer_key, &peer_key_len)) {
+ goto err;
+ }
+ /* |key| was initialized with CBS_get_u16_length_prefixed, so peer_key_len
+ * fits in a uint16_t. */
assert(sizeof(ssl->s3->tmp.peer_key_len) == 2 && peer_key_len <= 0xffff);
ssl->s3->tmp.peer_key_len = (uint16_t)peer_key_len;
} else if (!(alg_k & SSL_kPSK)) {
@@ -1215,7 +1201,7 @@
CBS_len(&server_key_exchange_orig) - CBS_len(&server_key_exchange));
/* ServerKeyExchange should be signed by the server's public key. */
- if (ssl_cipher_has_server_public_key(ssl->s3->tmp.new_cipher)) {
+ if (ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
pkey = X509_get_pubkey(ssl->session->peer);
if (pkey == NULL) {
goto err;
@@ -1302,9 +1288,7 @@
X509_NAME *xn = NULL;
STACK_OF(X509_NAME) *ca_sk = NULL;
- long n = ssl->method->ssl_get_message(
- ssl, SSL3_ST_CR_CERT_REQ_A, SSL3_ST_CR_CERT_REQ_B, -1, ssl->max_cert_list,
- ssl_hash_message, &ok);
+ long n = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message, &ok);
if (!ok) {
return n;
@@ -1409,9 +1393,8 @@
int ssl3_get_new_session_ticket(SSL *ssl) {
int ok, al;
- long n = ssl->method->ssl_get_message(
- ssl, SSL3_ST_CR_SESSION_TICKET_A, SSL3_ST_CR_SESSION_TICKET_B,
- SSL3_MT_NEWSESSION_TICKET, 16384, ssl_hash_message, &ok);
+ long n = ssl->method->ssl_get_message(ssl, SSL3_MT_NEW_SESSION_TICKET,
+ ssl_hash_message, &ok);
if (!ok) {
return n;
@@ -1487,9 +1470,7 @@
CBS certificate_status, ocsp_response;
uint8_t status_type;
- n = ssl->method->ssl_get_message(
- ssl, SSL3_ST_CR_CERT_STATUS_A, SSL3_ST_CR_CERT_STATUS_B,
- -1, 16384, ssl_hash_message, &ok);
+ n = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message, &ok);
if (!ok) {
return n;
@@ -1530,10 +1511,8 @@
int ok;
long n;
- n = ssl->method->ssl_get_message(ssl, SSL3_ST_CR_SRVR_DONE_A,
- SSL3_ST_CR_SRVR_DONE_B, SSL3_MT_SERVER_DONE,
- 30, /* should be very small, like 0 :-) */
- ssl_hash_message, &ok);
+ n = ssl->method->ssl_get_message(ssl, SSL3_MT_SERVER_DONE, ssl_hash_message,
+ &ok);
if (!ok) {
return n;
@@ -1657,31 +1636,24 @@
!CBB_flush(&cbb)) {
goto err;
}
- } else if (alg_k & (SSL_kECDHE|SSL_kDHE)) {
- /* Generate a keypair and serialize the public half. ECDHE uses a u8 length
- * prefix while DHE uses u16. */
+ } else if (alg_k & (SSL_kECDHE|SSL_kDHE|SSL_kCECPQ1)) {
+ /* Generate a keypair and serialize the public half. */
CBB child;
- int child_ok;
- if (alg_k & SSL_kECDHE) {
- child_ok = CBB_add_u8_length_prefixed(&cbb, &child);
- } else {
- child_ok = CBB_add_u16_length_prefixed(&cbb, &child);
- }
-
- if (!child_ok ||
- !SSL_ECDH_CTX_generate_keypair(&ssl->s3->tmp.ecdh_ctx, &child) ||
- !CBB_flush(&cbb)) {
+ if (!SSL_ECDH_CTX_add_key(&ssl->s3->tmp.ecdh_ctx, &cbb, &child)) {
goto err;
}
/* Compute the premaster. */
uint8_t alert;
- if (!SSL_ECDH_CTX_compute_secret(&ssl->s3->tmp.ecdh_ctx, &pms, &pms_len,
- &alert, ssl->s3->tmp.peer_key,
- ssl->s3->tmp.peer_key_len)) {
+ if (!SSL_ECDH_CTX_accept(&ssl->s3->tmp.ecdh_ctx, &child, &pms, &pms_len,
+ &alert, ssl->s3->tmp.peer_key,
+ ssl->s3->tmp.peer_key_len)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
goto err;
}
+ if (!CBB_flush(&cbb)) {
+ goto err;
+ }
/* The key exchange state may now be discarded. */
SSL_ECDH_CTX_cleanup(&ssl->s3->tmp.ecdh_ctx);
@@ -2020,7 +1992,8 @@
!BN_bn2cbb_padded(&child, 32, sig->r) ||
!BN_bn2cbb_padded(&child, 32, sig->s) ||
!CBB_finish(&cbb, NULL, &length) ||
- !ssl_set_handshake_header(ssl, SSL3_MT_ENCRYPTED_EXTENSIONS, length)) {
+ !ssl_set_handshake_header(ssl, SSL3_MT_CHANNEL_ID_ENCRYPTED_EXTENSIONS,
+ length)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
CBB_cleanup(&cbb);
goto err;
diff --git a/src/ssl/s3_lib.c b/src/ssl/s3_lib.c
index 7df046f..4cf5aa3 100644
--- a/src/ssl/s3_lib.c
+++ b/src/ssl/s3_lib.c
@@ -220,7 +220,7 @@
sk_X509_NAME_pop_free(ssl->s3->tmp.ca_names, X509_NAME_free);
OPENSSL_free(ssl->s3->tmp.certificate_types);
- OPENSSL_free(ssl->s3->tmp.peer_ellipticcurvelist);
+ OPENSSL_free(ssl->s3->tmp.peer_supported_group_list);
OPENSSL_free(ssl->s3->tmp.peer_psk_identity_hint);
ssl3_free_handshake_buffer(ssl);
ssl3_free_handshake_hash(ssl);
@@ -382,14 +382,14 @@
}
int SSL_CTX_set1_curves(SSL_CTX *ctx, const int *curves, size_t curves_len) {
- return tls1_set_curves(&ctx->tlsext_ellipticcurvelist,
- &ctx->tlsext_ellipticcurvelist_length, curves,
+ return tls1_set_curves(&ctx->supported_group_list,
+ &ctx->supported_group_list_len, curves,
curves_len);
}
int SSL_set1_curves(SSL *ssl, const int *curves, size_t curves_len) {
- return tls1_set_curves(&ssl->tlsext_ellipticcurvelist,
- &ssl->tlsext_ellipticcurvelist_length, curves,
+ return tls1_set_curves(&ssl->supported_group_list,
+ &ssl->supported_group_list_len, curves,
curves_len);
}
diff --git a/src/ssl/s3_pkt.c b/src/ssl/s3_pkt.c
index d9c21d4..c54c10b 100644
--- a/src/ssl/s3_pkt.c
+++ b/src/ssl/s3_pkt.c
@@ -133,6 +133,16 @@
static int ssl3_get_record(SSL *ssl) {
int ret;
again:
+ switch (ssl->s3->recv_shutdown) {
+ case ssl_shutdown_none:
+ break;
+ case ssl_shutdown_fatal_alert:
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
+ return -1;
+ case ssl_shutdown_close_notify:
+ return 0;
+ }
+
/* Ensure the buffer is large enough to decrypt in-place. */
ret = ssl_read_buffer_extend_to(ssl, ssl_record_prefix_len(ssl));
if (ret <= 0) {
@@ -393,27 +403,9 @@
/* we now have a packet which can be read and processed */
- /* If the other end has shut down, throw anything we read away (even in
- * 'peek' mode) */
- if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) {
- rr->length = 0;
- return 0;
- }
-
if (type != 0 && type == rr->type) {
ssl->s3->warning_alert_count = 0;
- /* Make sure that we are not getting application data when we are doing a
- * handshake for the first time. */
- if (SSL_in_init(ssl) && type == SSL3_RT_APPLICATION_DATA &&
- ssl->s3->aead_read_ctx == NULL) {
- /* TODO(davidben): Is this check redundant with the handshake_func
- * check? */
- al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, SSL_R_APP_DATA_IN_HANDSHAKE);
- goto f_err;
- }
-
/* Discard empty records. */
if (rr->length == 0) {
goto start;
@@ -546,8 +538,7 @@
if (alert_level == SSL3_AL_WARNING) {
if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
- ssl->s3->clean_shutdown = 1;
- ssl->shutdown |= SSL_RECEIVED_SHUTDOWN;
+ ssl->s3->recv_shutdown = ssl_shutdown_close_notify;
return 0;
}
@@ -563,7 +554,7 @@
OPENSSL_PUT_ERROR(SSL, SSL_AD_REASON_OFFSET + alert_descr);
BIO_snprintf(tmp, sizeof(tmp), "%d", alert_descr);
ERR_add_error_data(2, "SSL alert number ", tmp);
- ssl->shutdown |= SSL_RECEIVED_SHUTDOWN;
+ ssl->s3->recv_shutdown = ssl_shutdown_fatal_alert;
SSL_CTX_remove_session(ssl->ctx, ssl->session);
return 0;
} else {
@@ -575,7 +566,9 @@
goto start;
}
- if (ssl->shutdown & SSL_SENT_SHUTDOWN) {
+ if (type == 0) {
+ /* This may only occur from read_close_notify. */
+ assert(ssl->s3->send_shutdown == ssl_shutdown_close_notify);
/* close_notify has been sent, so discard all records other than alerts. */
rr->length = 0;
goto start;
@@ -591,9 +584,19 @@
}
int ssl3_send_alert(SSL *ssl, int level, int desc) {
- /* If a fatal one, remove from cache */
- if (level == 2 && ssl->session != NULL) {
- SSL_CTX_remove_session(ssl->ctx, ssl->session);
+ /* It is illegal to send an alert when we've already sent a closing one. */
+ if (ssl->s3->send_shutdown != ssl_shutdown_none) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
+ return -1;
+ }
+
+ if (level == SSL3_AL_FATAL) {
+ if (ssl->session != NULL) {
+ SSL_CTX_remove_session(ssl->ctx, ssl->session);
+ }
+ ssl->s3->send_shutdown = ssl_shutdown_fatal_alert;
+ } else if (level == SSL3_AL_WARNING && desc == SSL_AD_CLOSE_NOTIFY) {
+ ssl->s3->send_shutdown = ssl_shutdown_close_notify;
}
ssl->s3->alert_dispatch = 1;
@@ -605,8 +608,7 @@
return ssl->method->ssl_dispatch_alert(ssl);
}
- /* else data is still being written out, we will get written some time in the
- * future */
+ /* The alert will be dispatched later. */
return -1;
}
diff --git a/src/ssl/s3_srvr.c b/src/ssl/s3_srvr.c
index f06ee56..50007eb 100644
--- a/src/ssl/s3_srvr.c
+++ b/src/ssl/s3_srvr.c
@@ -208,7 +208,7 @@
if (ssl->init_buf == NULL) {
buf = BUF_MEM_new();
- if (!buf || !BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
+ if (!buf || !BUF_MEM_reserve(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
ret = -1;
goto end;
}
@@ -219,7 +219,7 @@
/* Enable a write buffer. This groups handshake messages within a flight
* into a single write. */
- if (!ssl_init_wbio_buffer(ssl, 1)) {
+ if (!ssl_init_wbio_buffer(ssl)) {
ret = -1;
goto end;
}
@@ -257,14 +257,11 @@
case SSL3_ST_SR_CLNT_HELLO_A:
case SSL3_ST_SR_CLNT_HELLO_B:
case SSL3_ST_SR_CLNT_HELLO_C:
- case SSL3_ST_SR_CLNT_HELLO_D:
- ssl->shutdown = 0;
ret = ssl3_get_client_hello(ssl);
if (ret <= 0) {
goto end;
}
ssl->state = SSL3_ST_SW_SRVR_HELLO_A;
- ssl->init_num = 0;
break;
case SSL3_ST_SW_SRVR_HELLO_A:
@@ -282,12 +279,11 @@
} else {
ssl->state = SSL3_ST_SW_CERT_A;
}
- ssl->init_num = 0;
break;
case SSL3_ST_SW_CERT_A:
case SSL3_ST_SW_CERT_B:
- if (ssl_cipher_has_server_public_key(ssl->s3->tmp.new_cipher)) {
+ if (ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
ret = ssl3_send_server_certificate(ssl);
if (ret <= 0) {
goto end;
@@ -301,7 +297,6 @@
skip = 1;
ssl->state = SSL3_ST_SW_KEY_EXCH_A;
}
- ssl->init_num = 0;
break;
case SSL3_ST_SW_CERT_STATUS_A:
@@ -311,7 +306,6 @@
goto end;
}
ssl->state = SSL3_ST_SW_KEY_EXCH_A;
- ssl->init_num = 0;
break;
case SSL3_ST_SW_KEY_EXCH_A:
@@ -337,7 +331,6 @@
}
ssl->state = SSL3_ST_SW_CERT_REQ_A;
- ssl->init_num = 0;
break;
case SSL3_ST_SW_CERT_REQ_A:
@@ -351,7 +344,6 @@
skip = 1;
}
ssl->state = SSL3_ST_SW_SRVR_DONE_A;
- ssl->init_num = 0;
break;
case SSL3_ST_SW_SRVR_DONE_A:
@@ -362,7 +354,6 @@
}
ssl->s3->tmp.next_state = SSL3_ST_SR_CERT_A;
ssl->state = SSL3_ST_SW_FLUSH;
- ssl->init_num = 0;
break;
case SSL3_ST_SW_FLUSH:
@@ -381,37 +372,31 @@
break;
case SSL3_ST_SR_CERT_A:
- case SSL3_ST_SR_CERT_B:
if (ssl->s3->tmp.cert_request) {
ret = ssl3_get_client_certificate(ssl);
if (ret <= 0) {
goto end;
}
}
- ssl->init_num = 0;
ssl->state = SSL3_ST_SR_KEY_EXCH_A;
break;
case SSL3_ST_SR_KEY_EXCH_A:
case SSL3_ST_SR_KEY_EXCH_B:
- case SSL3_ST_SR_KEY_EXCH_C:
ret = ssl3_get_client_key_exchange(ssl);
if (ret <= 0) {
goto end;
}
ssl->state = SSL3_ST_SR_CERT_VRFY_A;
- ssl->init_num = 0;
break;
case SSL3_ST_SR_CERT_VRFY_A:
- case SSL3_ST_SR_CERT_VRFY_B:
ret = ssl3_get_cert_verify(ssl);
if (ret <= 0) {
goto end;
}
ssl->state = SSL3_ST_SR_CHANGE;
- ssl->init_num = 0;
break;
case SSL3_ST_SR_CHANGE:
@@ -435,12 +420,10 @@
break;
case SSL3_ST_SR_NEXT_PROTO_A:
- case SSL3_ST_SR_NEXT_PROTO_B:
ret = ssl3_get_next_proto(ssl);
if (ret <= 0) {
goto end;
}
- ssl->init_num = 0;
if (ssl->s3->tlsext_channel_id_valid) {
ssl->state = SSL3_ST_SR_CHANNEL_ID_A;
} else {
@@ -449,19 +432,15 @@
break;
case SSL3_ST_SR_CHANNEL_ID_A:
- case SSL3_ST_SR_CHANNEL_ID_B:
ret = ssl3_get_channel_id(ssl);
if (ret <= 0) {
goto end;
}
- ssl->init_num = 0;
ssl->state = SSL3_ST_SR_FINISHED_A;
break;
case SSL3_ST_SR_FINISHED_A:
- case SSL3_ST_SR_FINISHED_B:
- ret = ssl3_get_finished(ssl, SSL3_ST_SR_FINISHED_A,
- SSL3_ST_SR_FINISHED_B);
+ ret = ssl3_get_finished(ssl);
if (ret <= 0) {
goto end;
}
@@ -482,7 +461,6 @@
goto end;
}
}
- ssl->init_num = 0;
break;
case SSL3_ST_SW_SESSION_TICKET_A:
@@ -492,7 +470,6 @@
goto end;
}
ssl->state = SSL3_ST_SW_CHANGE_A;
- ssl->init_num = 0;
break;
case SSL3_ST_SW_CHANGE_A:
@@ -503,7 +480,6 @@
goto end;
}
ssl->state = SSL3_ST_SW_FINISHED_A;
- ssl->init_num = 0;
if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_SERVER_WRITE)) {
ret = -1;
@@ -524,7 +500,6 @@
} else {
ssl->s3->tmp.next_state = SSL_ST_OK;
}
- ssl->init_num = 0;
break;
case SSL_ST_OK:
@@ -533,11 +508,11 @@
BUF_MEM_free(ssl->init_buf);
ssl->init_buf = NULL;
+ ssl->init_num = 0;
/* remove buffering on output */
ssl_free_wbio_buffer(ssl);
- ssl->init_num = 0;
/* If we aren't retaining peer certificates then we can discard it
* now. */
@@ -626,7 +601,7 @@
const uint8_t *p;
int ret;
CBS v2_client_hello, cipher_specs, session_id, challenge;
- size_t msg_length, rand_len, len;
+ size_t msg_length, rand_len;
uint8_t msg_type;
uint16_t version, cipher_spec_length, session_id_length, challenge_length;
CBB client_hello, hello_body, cipher_suites;
@@ -731,7 +706,7 @@
/* Add the null compression scheme and finish. */
if (!CBB_add_u8(&hello_body, 1) || !CBB_add_u8(&hello_body, 0) ||
- !CBB_finish(&client_hello, NULL, &len)) {
+ !CBB_finish(&client_hello, NULL, &ssl->init_buf->length)) {
CBB_cleanup(&client_hello);
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
@@ -740,8 +715,7 @@
/* Mark the message for "re"-use by the version-specific method. */
ssl->s3->tmp.reuse_message = 1;
ssl->s3->tmp.message_type = SSL3_MT_CLIENT_HELLO;
- /* The handshake message header is 4 bytes. */
- ssl->s3->tmp.message_size = len - 4;
+ ssl->s3->tmp.message_complete = 1;
/* Consume and discard the V2ClientHello. */
ssl_read_buffer_consume(ssl, 2 + msg_length);
@@ -767,20 +741,17 @@
* SSLv3, even if prompted with TLSv1. */
switch (ssl->state) {
case SSL3_ST_SR_CLNT_HELLO_A:
- case SSL3_ST_SR_CLNT_HELLO_B:
- n = ssl->method->ssl_get_message(
- ssl, SSL3_ST_SR_CLNT_HELLO_A, SSL3_ST_SR_CLNT_HELLO_B,
- SSL3_MT_CLIENT_HELLO, SSL3_RT_MAX_PLAIN_LENGTH,
- ssl_hash_message, &ok);
+ n = ssl->method->ssl_get_message(ssl, SSL3_MT_CLIENT_HELLO,
+ ssl_hash_message, &ok);
if (!ok) {
return n;
}
- ssl->state = SSL3_ST_SR_CLNT_HELLO_C;
+ ssl->state = SSL3_ST_SR_CLNT_HELLO_B;
/* fallthrough */
+ case SSL3_ST_SR_CLNT_HELLO_B:
case SSL3_ST_SR_CLNT_HELLO_C:
- case SSL3_ST_SR_CLNT_HELLO_D:
/* We have previously parsed the ClientHello message, and can't call
* ssl_get_message again without hashing the message into the Finished
* digest again. */
@@ -796,9 +767,9 @@
goto f_err;
}
- if (ssl->state == SSL3_ST_SR_CLNT_HELLO_C &&
+ if (ssl->state == SSL3_ST_SR_CLNT_HELLO_B &&
ssl->ctx->select_certificate_cb != NULL) {
- ssl->state = SSL3_ST_SR_CLNT_HELLO_D;
+ ssl->state = SSL3_ST_SR_CLNT_HELLO_C;
switch (ssl->ctx->select_certificate_cb(&early_ctx)) {
case 0:
ssl->rwstate = SSL_CERTIFICATE_SELECTION_PENDING;
@@ -814,7 +785,7 @@
/* fallthrough */;
}
}
- ssl->state = SSL3_ST_SR_CLNT_HELLO_D;
+ ssl->state = SSL3_ST_SR_CLNT_HELLO_C;
break;
default:
@@ -1053,8 +1024,8 @@
ssl->s3->tlsext_channel_id_valid) {
ssl->s3->tmp.cert_request = 0;
}
- /* Plain PSK forbids Certificate and CertificateRequest. */
- if (ssl->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK) {
+ /* CertificateRequest may only be sent in certificate-based ciphers. */
+ if (!ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
ssl->s3->tmp.cert_request = 0;
}
} else {
@@ -1239,25 +1210,31 @@
!CBB_add_u16_length_prefixed(&cbb, &child) ||
!BN_bn2cbb_padded(&child, BN_num_bytes(params->g), params->g) ||
!CBB_add_u16_length_prefixed(&cbb, &child) ||
- !SSL_ECDH_CTX_generate_keypair(&ssl->s3->tmp.ecdh_ctx, &child)) {
+ !SSL_ECDH_CTX_offer(&ssl->s3->tmp.ecdh_ctx, &child)) {
goto err;
}
} else if (alg_k & SSL_kECDHE) {
- /* Determine the curve to use. */
- uint16_t curve_id;
- if (!tls1_get_shared_curve(ssl, &curve_id)) {
+ /* Determine the group to use. */
+ uint16_t group_id;
+ if (!tls1_get_shared_group(ssl, &group_id)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_TMP_ECDH_KEY);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
goto err;
}
- ssl->session->key_exchange_info = curve_id;
+ ssl->session->key_exchange_info = group_id;
/* Set up ECDH, generate a key, and emit the public half. */
- if (!SSL_ECDH_CTX_init(&ssl->s3->tmp.ecdh_ctx, curve_id) ||
+ if (!SSL_ECDH_CTX_init(&ssl->s3->tmp.ecdh_ctx, group_id) ||
!CBB_add_u8(&cbb, NAMED_CURVE_TYPE) ||
- !CBB_add_u16(&cbb, curve_id) ||
+ !CBB_add_u16(&cbb, group_id) ||
!CBB_add_u8_length_prefixed(&cbb, &child) ||
- !SSL_ECDH_CTX_generate_keypair(&ssl->s3->tmp.ecdh_ctx, &child)) {
+ !SSL_ECDH_CTX_offer(&ssl->s3->tmp.ecdh_ctx, &child)) {
+ goto err;
+ }
+ } else if (alg_k & SSL_kCECPQ1) {
+ if (!SSL_ECDH_CTX_init(&ssl->s3->tmp.ecdh_ctx, SSL_GROUP_CECPQ1) ||
+ !CBB_add_u16_length_prefixed(&cbb, &child) ||
+ !SSL_ECDH_CTX_offer(&ssl->s3->tmp.ecdh_ctx, &child)) {
goto err;
}
} else {
@@ -1272,7 +1249,7 @@
}
/* Add a signature. */
- if (ssl_cipher_has_server_public_key(ssl->s3->tmp.new_cipher)) {
+ if (ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
if (!ssl_has_private_key(ssl)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
goto err;
@@ -1449,12 +1426,10 @@
unsigned psk_len = 0;
uint8_t psk[PSK_MAX_PSK_LEN];
- if (ssl->state == SSL3_ST_SR_KEY_EXCH_A ||
- ssl->state == SSL3_ST_SR_KEY_EXCH_B) {
+ if (ssl->state == SSL3_ST_SR_KEY_EXCH_A) {
int ok;
const long n = ssl->method->ssl_get_message(
- ssl, SSL3_ST_SR_KEY_EXCH_A, SSL3_ST_SR_KEY_EXCH_B,
- SSL3_MT_CLIENT_KEY_EXCHANGE, 2048 /* ??? */, ssl_hash_message, &ok);
+ ssl, SSL3_MT_CLIENT_KEY_EXCHANGE, ssl_hash_message, &ok);
if (!ok) {
return n;
}
@@ -1524,7 +1499,7 @@
enum ssl_private_key_result_t decrypt_result;
size_t decrypt_len;
- if (ssl->state == SSL3_ST_SR_KEY_EXCH_B) {
+ if (ssl->state == SSL3_ST_SR_KEY_EXCH_A) {
if (!ssl_has_private_key(ssl) ||
ssl_private_key_type(ssl) != EVP_PKEY_RSA) {
al = SSL_AD_HANDSHAKE_FAILURE;
@@ -1552,7 +1527,7 @@
CBS_data(&encrypted_premaster_secret),
CBS_len(&encrypted_premaster_secret));
} else {
- assert(ssl->state == SSL3_ST_SR_KEY_EXCH_C);
+ assert(ssl->state == SSL3_ST_SR_KEY_EXCH_B);
/* Complete async decrypt. */
decrypt_result = ssl_private_key_decrypt_complete(
ssl, decrypt_buf, &decrypt_len, rsa_size);
@@ -1565,7 +1540,7 @@
goto err;
case ssl_private_key_retry:
ssl->rwstate = SSL_PRIVATE_KEY_OPERATION;
- ssl->state = SSL3_ST_SR_KEY_EXCH_C;
+ ssl->state = SSL3_ST_SR_KEY_EXCH_B;
goto err;
}
@@ -1621,19 +1596,12 @@
OPENSSL_free(decrypt_buf);
decrypt_buf = NULL;
- } else if (alg_k & (SSL_kECDHE|SSL_kDHE)) {
- /* Parse the ClientKeyExchange. ECDHE uses a u8 length prefix while DHE uses
- * u16. */
+ } else if (alg_k & (SSL_kECDHE|SSL_kDHE|SSL_kCECPQ1)) {
+ /* Parse the ClientKeyExchange. */
CBS peer_key;
- int peer_key_ok;
- if (alg_k & SSL_kECDHE) {
- peer_key_ok = CBS_get_u8_length_prefixed(&client_key_exchange, &peer_key);
- } else {
- peer_key_ok =
- CBS_get_u16_length_prefixed(&client_key_exchange, &peer_key);
- }
-
- if (!peer_key_ok || CBS_len(&client_key_exchange) != 0) {
+ if (!SSL_ECDH_CTX_get_key(&ssl->s3->tmp.ecdh_ctx, &client_key_exchange,
+ &peer_key) ||
+ CBS_len(&client_key_exchange) != 0) {
al = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
@@ -1641,9 +1609,9 @@
/* Compute the premaster. */
uint8_t alert;
- if (!SSL_ECDH_CTX_compute_secret(&ssl->s3->tmp.ecdh_ctx, &premaster_secret,
- &premaster_secret_len, &alert,
- CBS_data(&peer_key), CBS_len(&peer_key))) {
+ if (!SSL_ECDH_CTX_finish(&ssl->s3->tmp.ecdh_ctx, &premaster_secret,
+ &premaster_secret_len, &alert, CBS_data(&peer_key),
+ CBS_len(&peer_key))) {
al = alert;
goto f_err;
}
@@ -1734,10 +1702,8 @@
return 1;
}
- n = ssl->method->ssl_get_message(
- ssl, SSL3_ST_SR_CERT_VRFY_A, SSL3_ST_SR_CERT_VRFY_B,
- SSL3_MT_CERTIFICATE_VERIFY, SSL3_RT_MAX_PLAIN_LENGTH,
- ssl_dont_hash_message, &ok);
+ n = ssl->method->ssl_get_message(ssl, SSL3_MT_CERTIFICATE_VERIFY,
+ ssl_dont_hash_message, &ok);
if (!ok) {
return n;
@@ -1833,9 +1799,7 @@
int is_first_certificate = 1;
assert(ssl->s3->tmp.cert_request);
- n = ssl->method->ssl_get_message(ssl, SSL3_ST_SR_CERT_A, SSL3_ST_SR_CERT_B,
- -1, (long)ssl->max_cert_list,
- ssl_hash_message, &ok);
+ n = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message, &ok);
if (!ok) {
return n;
@@ -2023,7 +1987,7 @@
p += placeholder_len;
len = p - ssl_handshake_start(ssl);
- if (!ssl_set_handshake_header(ssl, SSL3_MT_NEWSESSION_TICKET, len)) {
+ if (!ssl_set_handshake_header(ssl, SSL3_MT_NEW_SESSION_TICKET, len)) {
goto err;
}
ssl->state = SSL3_ST_SW_SESSION_TICKET_B;
@@ -2092,7 +2056,7 @@
/* Skip ticket lifetime hint */
p = ssl_handshake_start(ssl) + 4;
s2n(len - 6, p);
- if (!ssl_set_handshake_header(ssl, SSL3_MT_NEWSESSION_TICKET, len)) {
+ if (!ssl_set_handshake_header(ssl, SSL3_MT_NEW_SESSION_TICKET, len)) {
goto err;
}
ssl->state = SSL3_ST_SW_SESSION_TICKET_B;
@@ -2122,10 +2086,8 @@
return -1;
}
- n = ssl->method->ssl_get_message(ssl, SSL3_ST_SR_NEXT_PROTO_A,
- SSL3_ST_SR_NEXT_PROTO_B, SSL3_MT_NEXT_PROTO,
- 514, /* See the payload format below */
- ssl_hash_message, &ok);
+ n = ssl->method->ssl_get_message(ssl, SSL3_MT_NEXT_PROTO, ssl_hash_message,
+ &ok);
if (!ok) {
return n;
@@ -2164,10 +2126,8 @@
BIGNUM x, y;
CBS encrypted_extensions, extension;
- n = ssl->method->ssl_get_message(
- ssl, SSL3_ST_SR_CHANNEL_ID_A, SSL3_ST_SR_CHANNEL_ID_B,
- SSL3_MT_ENCRYPTED_EXTENSIONS, 2 + 2 + TLSEXT_CHANNEL_ID_SIZE,
- ssl_dont_hash_message, &ok);
+ n = ssl->method->ssl_get_message(ssl, SSL3_MT_CHANNEL_ID_ENCRYPTED_EXTENSIONS,
+ ssl_dont_hash_message, &ok);
if (!ok) {
return n;
diff --git a/src/ssl/ssl_aead_ctx.c b/src/ssl/ssl_aead_ctx.c
index 4de9d45..1e549ea 100644
--- a/src/ssl/ssl_aead_ctx.c
+++ b/src/ssl/ssl_aead_ctx.c
@@ -92,6 +92,15 @@
if (cipher->algorithm_enc & (SSL_AES128GCM | SSL_AES256GCM)) {
aead_ctx->variable_nonce_included_in_record = 1;
}
+
+ /* The TLS 1.3 construction XORs the fixed nonce into the sequence number
+ * and omits the additional data. */
+ if (version >= TLS1_3_VERSION) {
+ aead_ctx->xor_fixed_nonce = 1;
+ aead_ctx->variable_nonce_len = 8;
+ aead_ctx->variable_nonce_included_in_record = 0;
+ aead_ctx->omit_ad = 1;
+ }
} else {
aead_ctx->variable_nonce_included_in_record = 1;
aead_ctx->random_variable_nonce = 1;
@@ -139,6 +148,10 @@
uint8_t type, uint16_t wire_version,
const uint8_t seqnum[8],
size_t plaintext_len) {
+ if (aead->omit_ad) {
+ return 0;
+ }
+
memcpy(out, seqnum, 8);
size_t len = 8;
out[len++] = type;
diff --git a/src/ssl/ssl_cipher.c b/src/ssl/ssl_cipher.c
index 58ce582..dcee293 100644
--- a/src/ssl/ssl_cipher.c
+++ b/src/ssl/ssl_cipher.c
@@ -375,6 +375,52 @@
SSL_HANDSHAKE_MAC_SHA384,
},
+ /* CECPQ1 (combined elliptic curve + post-quantum) suites. */
+
+ /* Cipher 16B7 */
+ {
+ TLS1_TXT_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ TLS1_CK_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ SSL_kCECPQ1,
+ SSL_aRSA,
+ SSL_CHACHA20POLY1305,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+ /* Cipher 16B8 */
+ {
+ TLS1_TXT_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+ TLS1_CK_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+ SSL_kCECPQ1,
+ SSL_aECDSA,
+ SSL_CHACHA20POLY1305,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+ /* Cipher 16B9 */
+ {
+ TLS1_TXT_CECPQ1_RSA_WITH_AES_256_GCM_SHA384,
+ TLS1_CK_CECPQ1_RSA_WITH_AES_256_GCM_SHA384,
+ SSL_kCECPQ1,
+ SSL_aRSA,
+ SSL_AES256GCM,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA384,
+ },
+
+ /* Cipher 16BA */
+ {
+ TLS1_TXT_CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS1_CK_CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384,
+ SSL_kCECPQ1,
+ SSL_aECDSA,
+ SSL_AES256GCM,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA384,
+ },
+
/* Cipher C007 */
{
TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA,
@@ -615,6 +661,7 @@
SSL_AEAD,
SSL_HANDSHAKE_MAC_SHA256,
},
+
};
static const size_t kCiphersLen = sizeof(kCiphers) / sizeof(kCiphers[0]);
@@ -651,8 +698,9 @@
} CIPHER_ALIAS;
static const CIPHER_ALIAS kCipherAliases[] = {
- /* "ALL" doesn't include eNULL (must be specifically enabled) */
- {"ALL", ~0u, ~0u, ~SSL_eNULL, ~0u, 0},
+ /* "ALL" doesn't include eNULL nor kCECPQ1. These must be explicitly
+ * enabled. */
+ {"ALL", ~SSL_kCECPQ1, ~0u, ~SSL_eNULL, ~0u, 0},
/* The "COMPLEMENTOFDEFAULT" rule is omitted. It matches nothing. */
@@ -667,15 +715,16 @@
{"DH", SSL_kDHE, ~0u, ~0u, ~0u, 0},
{"kECDHE", SSL_kECDHE, ~0u, ~0u, ~0u, 0},
+ {"kCECPQ1", SSL_kCECPQ1, ~0u, ~0u, ~0u, 0},
{"kEECDH", SSL_kECDHE, ~0u, ~0u, ~0u, 0},
{"ECDH", SSL_kECDHE, ~0u, ~0u, ~0u, 0},
{"kPSK", SSL_kPSK, ~0u, ~0u, ~0u, 0},
/* server authentication aliases */
- {"aRSA", ~0u, SSL_aRSA, ~SSL_eNULL, ~0u, 0},
- {"aECDSA", ~0u, SSL_aECDSA, ~0u, ~0u, 0},
- {"ECDSA", ~0u, SSL_aECDSA, ~0u, ~0u, 0},
+ {"aRSA", ~SSL_kCECPQ1, SSL_aRSA, ~SSL_eNULL, ~0u, 0},
+ {"aECDSA", ~SSL_kCECPQ1, SSL_aECDSA, ~0u, ~0u, 0},
+ {"ECDSA", ~SSL_kCECPQ1, SSL_aECDSA, ~0u, ~0u, 0},
{"aPSK", ~0u, SSL_aPSK, ~0u, ~0u, 0},
/* aliases combining key exchange and server authentication */
@@ -690,29 +739,29 @@
{"3DES", ~0u, ~0u, SSL_3DES, ~0u, 0},
{"RC4", ~0u, ~0u, SSL_RC4, ~0u, 0},
{"AES128", ~0u, ~0u, SSL_AES128 | SSL_AES128GCM, ~0u, 0},
- {"AES256", ~0u, ~0u, SSL_AES256 | SSL_AES256GCM, ~0u, 0},
- {"AES", ~0u, ~0u, SSL_AES, ~0u, 0},
- {"AESGCM", ~0u, ~0u, SSL_AES128GCM | SSL_AES256GCM, ~0u, 0},
- {"CHACHA20", ~0u, ~0u, SSL_CHACHA20POLY1305 | SSL_CHACHA20POLY1305_OLD, ~0u,
+ {"AES256", ~SSL_kCECPQ1, ~0u, SSL_AES256 | SSL_AES256GCM, ~0u, 0},
+ {"AES", ~SSL_kCECPQ1, ~0u, SSL_AES, ~0u, 0},
+ {"AESGCM", ~SSL_kCECPQ1, ~0u, SSL_AES128GCM | SSL_AES256GCM, ~0u, 0},
+ {"CHACHA20", ~SSL_kCECPQ1, ~0u, SSL_CHACHA20POLY1305 | SSL_CHACHA20POLY1305_OLD, ~0u,
0},
/* MAC aliases */
{"MD5", ~0u, ~0u, ~0u, SSL_MD5, 0},
{"SHA1", ~0u, ~0u, ~SSL_eNULL, SSL_SHA1, 0},
{"SHA", ~0u, ~0u, ~SSL_eNULL, SSL_SHA1, 0},
- {"SHA256", ~0u, ~0u, ~0u, SSL_SHA256, 0},
- {"SHA384", ~0u, ~0u, ~0u, SSL_SHA384, 0},
+ {"SHA256", ~SSL_kCECPQ1, ~0u, ~0u, SSL_SHA256, 0},
+ {"SHA384", ~SSL_kCECPQ1, ~0u, ~0u, SSL_SHA384, 0},
/* Legacy protocol minimum version aliases. "TLSv1" is intentionally the
* same as "SSLv3". */
- {"SSLv3", ~0u, ~0u, ~SSL_eNULL, ~0u, SSL3_VERSION},
- {"TLSv1", ~0u, ~0u, ~SSL_eNULL, ~0u, SSL3_VERSION},
- {"TLSv1.2", ~0u, ~0u, ~SSL_eNULL, ~0u, TLS1_2_VERSION},
+ {"SSLv3", ~SSL_kCECPQ1, ~0u, ~SSL_eNULL, ~0u, SSL3_VERSION},
+ {"TLSv1", ~SSL_kCECPQ1, ~0u, ~SSL_eNULL, ~0u, SSL3_VERSION},
+ {"TLSv1.2", ~SSL_kCECPQ1, ~0u, ~SSL_eNULL, ~0u, TLS1_2_VERSION},
/* Legacy strength classes. */
{"MEDIUM", ~0u, ~0u, SSL_RC4, ~0u, 0},
- {"HIGH", ~0u, ~0u, ~(SSL_eNULL|SSL_RC4), ~0u, 0},
- {"FIPS", ~0u, ~0u, ~(SSL_eNULL|SSL_RC4), ~0u, 0},
+ {"HIGH", ~SSL_kCECPQ1, ~0u, ~(SSL_eNULL|SSL_RC4), ~0u, 0},
+ {"FIPS", ~SSL_kCECPQ1, ~0u, ~(SSL_eNULL|SSL_RC4), ~0u, 0},
};
static const size_t kCipherAliasesLen =
@@ -1404,6 +1453,7 @@
/* Everything else being equal, prefer ECDHE_ECDSA then ECDHE_RSA over other
* key exchange mechanisms */
+
ssl_cipher_apply_rule(0, SSL_kECDHE, SSL_aECDSA, ~0u, ~0u, 0, CIPHER_ADD, -1,
0, &head, &tail);
ssl_cipher_apply_rule(0, SSL_kECDHE, ~0u, ~0u, ~0u, 0, CIPHER_ADD, -1, 0,
@@ -1623,6 +1673,10 @@
return (cipher->algorithm_mkey & SSL_kECDHE) != 0;
}
+int SSL_CIPHER_is_CECPQ1(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_mkey & SSL_kCECPQ1) != 0;
+}
+
uint16_t SSL_CIPHER_get_min_version(const SSL_CIPHER *cipher) {
if (cipher->algorithm_prf != SSL_HANDSHAKE_MAC_DEFAULT) {
/* Cipher suites before TLS 1.2 use the default PRF, while all those added
@@ -1672,6 +1726,17 @@
return "UNKNOWN";
}
+ case SSL_kCECPQ1:
+ switch (cipher->algorithm_auth) {
+ case SSL_aECDSA:
+ return "CECPQ1_ECDSA";
+ case SSL_aRSA:
+ return "CECPQ1_RSA";
+ default:
+ assert(0);
+ return "UNKNOWN";
+ }
+
case SSL_kPSK:
assert(cipher->algorithm_auth == SSL_aPSK);
return "PSK";
@@ -1826,6 +1891,10 @@
kx = "ECDH";
break;
+ case SSL_kCECPQ1:
+ kx = "CECPQ1";
+ break;
+
case SSL_kPSK:
kx = "PSK";
break;
@@ -1957,20 +2026,15 @@
return EVP_PKEY_NONE;
}
-int ssl_cipher_has_server_public_key(const SSL_CIPHER *cipher) {
- /* PSK-authenticated ciphers do not use a certificate. (RSA_PSK is not
- * supported.) */
- if (cipher->algorithm_auth & SSL_aPSK) {
- return 0;
- }
-
- /* All other ciphers include it. */
- return 1;
+int ssl_cipher_uses_certificate_auth(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_auth & SSL_aCERT) != 0;
}
int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher) {
/* Ephemeral Diffie-Hellman key exchanges require a ServerKeyExchange. */
- if (cipher->algorithm_mkey & SSL_kDHE || cipher->algorithm_mkey & SSL_kECDHE) {
+ if (cipher->algorithm_mkey & SSL_kDHE ||
+ cipher->algorithm_mkey & SSL_kECDHE ||
+ cipher->algorithm_mkey & SSL_kCECPQ1) {
return 1;
}
diff --git a/src/ssl/ssl_ecdh.c b/src/ssl/ssl_ecdh.c
index d48c93f..1236cd3 100644
--- a/src/ssl/ssl_ecdh.c
+++ b/src/ssl/ssl_ecdh.c
@@ -23,6 +23,7 @@
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/mem.h>
+#include <openssl/newhope.h>
#include <openssl/nid.h>
#include "internal.h"
@@ -35,7 +36,7 @@
BN_clear_free(private_key);
}
-static int ssl_ec_point_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out) {
+static int ssl_ec_point_offer(SSL_ECDH_CTX *ctx, CBB *out) {
assert(ctx->data == NULL);
BIGNUM *private_key = BN_new();
if (private_key == NULL) {
@@ -84,12 +85,9 @@
return ret;
}
-static int ssl_ec_point_compute_secret(SSL_ECDH_CTX *ctx,
- uint8_t **out_secret,
- size_t *out_secret_len,
- uint8_t *out_alert,
- const uint8_t *peer_key,
- size_t peer_key_len) {
+static int ssl_ec_point_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
+ size_t *out_secret_len, uint8_t *out_alert,
+ const uint8_t *peer_key, size_t peer_key_len) {
BIGNUM *private_key = (BIGNUM *)ctx->data;
assert(private_key != NULL);
*out_alert = SSL_AD_INTERNAL_ERROR;
@@ -150,6 +148,18 @@
return ret;
}
+static int ssl_ec_point_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
+ uint8_t **out_secret, size_t *out_secret_len,
+ uint8_t *out_alert, const uint8_t *peer_key,
+ size_t peer_key_len) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ if (!ssl_ec_point_offer(ctx, out_public_key) ||
+ !ssl_ec_point_finish(ctx, out_secret, out_secret_len, out_alert, peer_key,
+ peer_key_len)) {
+ return 0;
+ }
+ return 1;
+}
/* X25119 implementation. */
@@ -161,7 +171,7 @@
OPENSSL_free(ctx->data);
}
-static int ssl_x25519_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out) {
+static int ssl_x25519_offer(SSL_ECDH_CTX *ctx, CBB *out) {
assert(ctx->data == NULL);
ctx->data = OPENSSL_malloc(32);
@@ -174,10 +184,9 @@
return CBB_add_bytes(out, public_key, sizeof(public_key));
}
-static int ssl_x25519_compute_secret(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
- size_t *out_secret_len, uint8_t *out_alert,
- const uint8_t *peer_key,
- size_t peer_key_len) {
+static int ssl_x25519_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
+ size_t *out_secret_len, uint8_t *out_alert,
+ const uint8_t *peer_key, size_t peer_key_len) {
assert(ctx->data != NULL);
*out_alert = SSL_AD_INTERNAL_ERROR;
@@ -199,6 +208,166 @@
return 1;
}
+static int ssl_x25519_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
+ uint8_t **out_secret, size_t *out_secret_len,
+ uint8_t *out_alert, const uint8_t *peer_key,
+ size_t peer_key_len) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ if (!ssl_x25519_offer(ctx, out_public_key) ||
+ !ssl_x25519_finish(ctx, out_secret, out_secret_len, out_alert, peer_key,
+ peer_key_len)) {
+ return 0;
+ }
+ return 1;
+}
+
+
+/* Combined X25119 + New Hope (post-quantum) implementation. */
+
+typedef struct {
+ uint8_t x25519_key[32];
+ NEWHOPE_POLY *newhope_sk;
+} cecpq1_data;
+
+#define CECPQ1_OFFERMSG_LENGTH (32 + NEWHOPE_OFFERMSG_LENGTH)
+#define CECPQ1_ACCEPTMSG_LENGTH (32 + NEWHOPE_ACCEPTMSG_LENGTH)
+#define CECPQ1_SECRET_LENGTH (32 + SHA256_DIGEST_LENGTH)
+
+static void ssl_cecpq1_cleanup(SSL_ECDH_CTX *ctx) {
+ if (ctx->data == NULL) {
+ return;
+ }
+ cecpq1_data *data = ctx->data;
+ NEWHOPE_POLY_free(data->newhope_sk);
+ OPENSSL_cleanse(data, sizeof(cecpq1_data));
+ OPENSSL_free(data);
+}
+
+static int ssl_cecpq1_offer(SSL_ECDH_CTX *ctx, CBB *out) {
+ assert(ctx->data == NULL);
+ cecpq1_data *data = OPENSSL_malloc(sizeof(cecpq1_data));
+ if (data == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ ctx->data = data;
+ data->newhope_sk = NEWHOPE_POLY_new();
+ if (data->newhope_sk == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ uint8_t x25519_public_key[32];
+ X25519_keypair(x25519_public_key, data->x25519_key);
+
+ uint8_t newhope_offermsg[NEWHOPE_OFFERMSG_LENGTH];
+ NEWHOPE_offer(newhope_offermsg, data->newhope_sk);
+
+ if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) ||
+ !CBB_add_bytes(out, newhope_offermsg, sizeof(newhope_offermsg))) {
+ return 0;
+ }
+ return 1;
+}
+
+static int ssl_cecpq1_accept(SSL_ECDH_CTX *ctx, CBB *cbb, uint8_t **out_secret,
+ size_t *out_secret_len, uint8_t *out_alert,
+ const uint8_t *peer_key, size_t peer_key_len) {
+ if (peer_key_len != CECPQ1_OFFERMSG_LENGTH) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+
+ assert(ctx->data == NULL);
+ cecpq1_data *data = OPENSSL_malloc(sizeof(cecpq1_data));
+ if (data == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ data->newhope_sk = NULL;
+ ctx->data = data;
+
+ uint8_t *secret = OPENSSL_malloc(CECPQ1_SECRET_LENGTH);
+ if (secret == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ /* Generate message to server, and secret key, at once. */
+
+ uint8_t x25519_public_key[32];
+ X25519_keypair(x25519_public_key, data->x25519_key);
+ if (!X25519(secret, data->x25519_key, peer_key)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
+ goto err;
+ }
+
+ uint8_t newhope_acceptmsg[NEWHOPE_ACCEPTMSG_LENGTH];
+ if (!NEWHOPE_accept(secret + 32, newhope_acceptmsg, peer_key + 32,
+ NEWHOPE_OFFERMSG_LENGTH)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ goto err;
+ }
+
+ if (!CBB_add_bytes(cbb, x25519_public_key, sizeof(x25519_public_key)) ||
+ !CBB_add_bytes(cbb, newhope_acceptmsg, sizeof(newhope_acceptmsg))) {
+ goto err;
+ }
+
+ *out_secret = secret;
+ *out_secret_len = CECPQ1_SECRET_LENGTH;
+ return 1;
+
+ err:
+ OPENSSL_cleanse(secret, CECPQ1_SECRET_LENGTH);
+ OPENSSL_free(secret);
+ return 0;
+}
+
+static int ssl_cecpq1_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
+ size_t *out_secret_len, uint8_t *out_alert,
+ const uint8_t *peer_key, size_t peer_key_len) {
+ if (peer_key_len != CECPQ1_ACCEPTMSG_LENGTH) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+
+ assert(ctx->data != NULL);
+ cecpq1_data *data = ctx->data;
+
+ uint8_t *secret = OPENSSL_malloc(CECPQ1_SECRET_LENGTH);
+ if (secret == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ if (!X25519(secret, data->x25519_key, peer_key)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
+ goto err;
+ }
+
+ if (!NEWHOPE_finish(secret + 32, data->newhope_sk, peer_key + 32,
+ NEWHOPE_ACCEPTMSG_LENGTH)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ goto err;
+ }
+
+ *out_secret = secret;
+ *out_secret_len = CECPQ1_SECRET_LENGTH;
+ return 1;
+
+ err:
+ OPENSSL_cleanse(secret, CECPQ1_SECRET_LENGTH);
+ OPENSSL_free(secret);
+ return 0;
+}
+
/* Legacy DHE-based implementation. */
@@ -206,7 +375,7 @@
DH_free((DH *)ctx->data);
}
-static int ssl_dhe_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out) {
+static int ssl_dhe_offer(SSL_ECDH_CTX *ctx, CBB *out) {
DH *dh = (DH *)ctx->data;
/* The group must have been initialized already, but not the key. */
assert(dh != NULL);
@@ -218,10 +387,9 @@
BN_bn2cbb_padded(out, BN_num_bytes(dh->p), dh->pub_key);
}
-static int ssl_dhe_compute_secret(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
- size_t *out_secret_len, uint8_t *out_alert,
- const uint8_t *peer_key,
- size_t peer_key_len) {
+static int ssl_dhe_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
+ size_t *out_secret_len, uint8_t *out_alert,
+ const uint8_t *peer_key, size_t peer_key_len) {
DH *dh = (DH *)ctx->data;
assert(dh != NULL);
assert(dh->priv_key != NULL);
@@ -257,53 +425,91 @@
return 0;
}
+static int ssl_dhe_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
+ uint8_t **out_secret, size_t *out_secret_len,
+ uint8_t *out_alert, const uint8_t *peer_key,
+ size_t peer_key_len) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ if (!ssl_dhe_offer(ctx, out_public_key) ||
+ !ssl_dhe_finish(ctx, out_secret, out_secret_len, out_alert, peer_key,
+ peer_key_len)) {
+ return 0;
+ }
+ return 1;
+}
+
static const SSL_ECDH_METHOD kDHEMethod = {
NID_undef, 0, "",
ssl_dhe_cleanup,
- ssl_dhe_generate_keypair,
- ssl_dhe_compute_secret,
+ ssl_dhe_offer,
+ ssl_dhe_accept,
+ ssl_dhe_finish,
+ CBS_get_u16_length_prefixed,
+ CBB_add_u16_length_prefixed,
};
-
static const SSL_ECDH_METHOD kMethods[] = {
{
NID_X9_62_prime256v1,
- SSL_CURVE_SECP256R1,
+ SSL_GROUP_SECP256R1,
"P-256",
ssl_ec_point_cleanup,
- ssl_ec_point_generate_keypair,
- ssl_ec_point_compute_secret,
+ ssl_ec_point_offer,
+ ssl_ec_point_accept,
+ ssl_ec_point_finish,
+ CBS_get_u8_length_prefixed,
+ CBB_add_u8_length_prefixed,
},
{
NID_secp384r1,
- SSL_CURVE_SECP384R1,
+ SSL_GROUP_SECP384R1,
"P-384",
ssl_ec_point_cleanup,
- ssl_ec_point_generate_keypair,
- ssl_ec_point_compute_secret,
+ ssl_ec_point_offer,
+ ssl_ec_point_accept,
+ ssl_ec_point_finish,
+ CBS_get_u8_length_prefixed,
+ CBB_add_u8_length_prefixed,
},
{
NID_secp521r1,
- SSL_CURVE_SECP521R1,
+ SSL_GROUP_SECP521R1,
"P-521",
ssl_ec_point_cleanup,
- ssl_ec_point_generate_keypair,
- ssl_ec_point_compute_secret,
+ ssl_ec_point_offer,
+ ssl_ec_point_accept,
+ ssl_ec_point_finish,
+ CBS_get_u8_length_prefixed,
+ CBB_add_u8_length_prefixed,
},
{
NID_X25519,
- SSL_CURVE_X25519,
+ SSL_GROUP_X25519,
"X25519",
ssl_x25519_cleanup,
- ssl_x25519_generate_keypair,
- ssl_x25519_compute_secret,
+ ssl_x25519_offer,
+ ssl_x25519_accept,
+ ssl_x25519_finish,
+ CBS_get_u8_length_prefixed,
+ CBB_add_u8_length_prefixed,
+ },
+ {
+ NID_cecpq1,
+ SSL_GROUP_CECPQ1,
+ "CECPQ1",
+ ssl_cecpq1_cleanup,
+ ssl_cecpq1_offer,
+ ssl_cecpq1_accept,
+ ssl_cecpq1_finish,
+ CBS_get_u16_length_prefixed,
+ CBB_add_u16_length_prefixed,
},
};
-static const SSL_ECDH_METHOD *method_from_curve_id(uint16_t curve_id) {
+static const SSL_ECDH_METHOD *method_from_group_id(uint16_t group_id) {
size_t i;
for (i = 0; i < sizeof(kMethods) / sizeof(kMethods[0]); i++) {
- if (kMethods[i].curve_id == curve_id) {
+ if (kMethods[i].group_id == group_id) {
return &kMethods[i];
}
}
@@ -320,27 +526,27 @@
return NULL;
}
-const char* SSL_get_curve_name(uint16_t curve_id) {
- const SSL_ECDH_METHOD *method = method_from_curve_id(curve_id);
+const char* SSL_get_curve_name(uint16_t group_id) {
+ const SSL_ECDH_METHOD *method = method_from_group_id(group_id);
if (method == NULL) {
return NULL;
}
return method->name;
}
-int ssl_nid_to_curve_id(uint16_t *out_curve_id, int nid) {
+int ssl_nid_to_group_id(uint16_t *out_group_id, int nid) {
const SSL_ECDH_METHOD *method = method_from_nid(nid);
if (method == NULL) {
return 0;
}
- *out_curve_id = method->curve_id;
+ *out_group_id = method->group_id;
return 1;
}
-int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t curve_id) {
+int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t group_id) {
SSL_ECDH_CTX_cleanup(ctx);
- const SSL_ECDH_METHOD *method = method_from_curve_id(curve_id);
+ const SSL_ECDH_METHOD *method = method_from_group_id(group_id);
if (method == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
return 0;
@@ -356,6 +562,20 @@
ctx->data = params;
}
+int SSL_ECDH_CTX_get_key(SSL_ECDH_CTX *ctx, CBS *cbs, CBS *out) {
+ if (ctx->method == NULL) {
+ return 0;
+ }
+ return ctx->method->get_key(cbs, out);
+}
+
+int SSL_ECDH_CTX_add_key(SSL_ECDH_CTX *ctx, CBB *cbb, CBB *out_contents) {
+ if (ctx->method == NULL) {
+ return 0;
+ }
+ return ctx->method->add_key(cbb, out_contents);
+}
+
void SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX *ctx) {
if (ctx->method == NULL) {
return;
@@ -365,13 +585,21 @@
ctx->data = NULL;
}
-int SSL_ECDH_CTX_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out_public_key) {
- return ctx->method->generate_keypair(ctx, out_public_key);
+int SSL_ECDH_CTX_offer(SSL_ECDH_CTX *ctx, CBB *out_public_key) {
+ return ctx->method->offer(ctx, out_public_key);
}
-int SSL_ECDH_CTX_compute_secret(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
- size_t *out_secret_len, uint8_t *out_alert,
- const uint8_t *peer_key, size_t peer_key_len) {
- return ctx->method->compute_secret(ctx, out_secret, out_secret_len, out_alert,
- peer_key, peer_key_len);
+int SSL_ECDH_CTX_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
+ uint8_t **out_secret, size_t *out_secret_len,
+ uint8_t *out_alert, const uint8_t *peer_key,
+ size_t peer_key_len) {
+ return ctx->method->accept(ctx, out_public_key, out_secret, out_secret_len,
+ out_alert, peer_key, peer_key_len);
+}
+
+int SSL_ECDH_CTX_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
+ size_t *out_secret_len, uint8_t *out_alert,
+ const uint8_t *peer_key, size_t peer_key_len) {
+ return ctx->method->finish(ctx, out_secret, out_secret_len, out_alert,
+ peer_key, peer_key_len);
}
diff --git a/src/ssl/ssl_lib.c b/src/ssl/ssl_lib.c
index 84047b2..8e9b196 100644
--- a/src/ssl/ssl_lib.c
+++ b/src/ssl/ssl_lib.c
@@ -297,6 +297,9 @@
if (method->version != 0) {
SSL_CTX_set_max_version(ret, method->version);
SSL_CTX_set_min_version(ret, method->version);
+ } else if (!method->method->is_dtls) {
+ /* TODO(svaldez): Enable TLS 1.3 once implemented. */
+ SSL_CTX_set_max_version(ret, TLS1_2_VERSION);
}
return ret;
@@ -341,7 +344,7 @@
sk_X509_NAME_pop_free(ctx->client_CA, X509_NAME_free);
sk_SRTP_PROTECTION_PROFILE_free(ctx->srtp_profiles);
OPENSSL_free(ctx->psk_identity_hint);
- OPENSSL_free(ctx->tlsext_ellipticcurvelist);
+ OPENSSL_free(ctx->supported_group_list);
OPENSSL_free(ctx->alpn_client_proto_list);
OPENSSL_free(ctx->ocsp_response);
OPENSSL_free(ctx->signed_cert_timestamp_list);
@@ -369,6 +372,10 @@
ssl->min_version = ctx->min_version;
ssl->max_version = ctx->max_version;
+ /* RFC 6347 states that implementations SHOULD use an initial timer value of
+ * 1 second. */
+ ssl->initial_timeout_duration_ms = 1000;
+
ssl->options = ctx->options;
ssl->mode = ctx->mode;
ssl->max_cert_list = ctx->max_cert_list;
@@ -399,14 +406,14 @@
CRYPTO_refcount_inc(&ctx->references);
ssl->initial_ctx = ctx;
- if (ctx->tlsext_ellipticcurvelist) {
- ssl->tlsext_ellipticcurvelist =
- BUF_memdup(ctx->tlsext_ellipticcurvelist,
- ctx->tlsext_ellipticcurvelist_length * 2);
- if (!ssl->tlsext_ellipticcurvelist) {
+ if (ctx->supported_group_list) {
+ ssl->supported_group_list =
+ BUF_memdup(ctx->supported_group_list,
+ ctx->supported_group_list_len * 2);
+ if (!ssl->supported_group_list) {
goto err;
}
- ssl->tlsext_ellipticcurvelist_length = ctx->tlsext_ellipticcurvelist_length;
+ ssl->supported_group_list_len = ctx->supported_group_list_len;
}
if (ssl->ctx->alpn_client_proto_list) {
@@ -467,14 +474,8 @@
CRYPTO_free_ex_data(&g_ex_data_class_ssl, ssl, &ssl->ex_data);
- if (ssl->bbio != NULL) {
- /* If the buffering BIO is in place, pop it off */
- if (ssl->bbio == ssl->wbio) {
- ssl->wbio = BIO_pop(ssl->wbio);
- }
- BIO_free(ssl->bbio);
- ssl->bbio = NULL;
- }
+ ssl_free_wbio_buffer(ssl);
+ assert(ssl->bbio == NULL);
int free_wbio = ssl->wbio != ssl->rbio;
BIO_free_all(ssl->rbio);
@@ -495,7 +496,7 @@
OPENSSL_free(ssl->tlsext_hostname);
SSL_CTX_free(ssl->initial_ctx);
- OPENSSL_free(ssl->tlsext_ellipticcurvelist);
+ OPENSSL_free(ssl->supported_group_list);
OPENSSL_free(ssl->alpn_client_proto_list);
EVP_PKEY_free(ssl->tlsext_channel_id_private);
OPENSSL_free(ssl->psk_identity_hint);
@@ -512,14 +513,12 @@
void SSL_set_connect_state(SSL *ssl) {
ssl->server = 0;
- ssl->shutdown = 0;
ssl->state = SSL_ST_CONNECT;
ssl->handshake_func = ssl->method->ssl_connect;
}
void SSL_set_accept_state(SSL *ssl) {
ssl->server = 1;
- ssl->shutdown = 0;
ssl->state = SSL_ST_ACCEPT;
ssl->handshake_func = ssl->method->ssl_accept;
}
@@ -527,10 +526,7 @@
void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio) {
/* If the output buffering BIO is still in place, remove it. */
if (ssl->bbio != NULL) {
- if (ssl->wbio == ssl->bbio) {
- ssl->wbio = ssl->wbio->next_bio;
- ssl->bbio->next_bio = NULL;
- }
+ ssl->wbio = BIO_pop(ssl->wbio);
}
if (ssl->rbio != rbio) {
@@ -541,11 +537,23 @@
}
ssl->rbio = rbio;
ssl->wbio = wbio;
+
+ /* Re-attach |bbio| to the new |wbio|. */
+ if (ssl->bbio != NULL) {
+ ssl->wbio = BIO_push(ssl->bbio, ssl->wbio);
+ }
}
BIO *SSL_get_rbio(const SSL *ssl) { return ssl->rbio; }
-BIO *SSL_get_wbio(const SSL *ssl) { return ssl->wbio; }
+BIO *SSL_get_wbio(const SSL *ssl) {
+ if (ssl->bbio != NULL) {
+ /* If |bbio| is active, the true caller-configured BIO is its |next_bio|. */
+ assert(ssl->bbio == ssl->wbio);
+ return ssl->bbio->next_bio;
+ }
+ return ssl->wbio;
+}
int SSL_do_handshake(SSL *ssl) {
ssl->rwstate = SSL_NOTHING;
@@ -597,10 +605,6 @@
return -1;
}
- if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) {
- return 0;
- }
-
/* This may require multiple iterations. False Start will cause
* |ssl->handshake_func| to signal success one step early, but the handshake
* must be completely finished before other modes are accepted. */
@@ -637,7 +641,7 @@
return -1;
}
- if (ssl->shutdown & SSL_SENT_SHUTDOWN) {
+ if (ssl->s3->send_shutdown != ssl_shutdown_none) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
return -1;
}
@@ -662,11 +666,6 @@
/* Functions which use SSL_get_error must clear the error queue on entry. */
ERR_clear_error();
- /* Note that this function behaves differently from what one might expect.
- * Return values are 0 for no success (yet), 1 for success; but calling it
- * once is usually not enough, even if blocking I/O is used (see
- * ssl3_shutdown). */
-
if (ssl->handshake_func == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
return -1;
@@ -678,44 +677,37 @@
return -1;
}
- /* Do nothing if configured not to send a close_notify. */
if (ssl->quiet_shutdown) {
- ssl->shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN;
+ /* Do nothing if configured not to send a close_notify. */
+ ssl->s3->send_shutdown = ssl_shutdown_close_notify;
+ ssl->s3->recv_shutdown = ssl_shutdown_close_notify;
return 1;
}
- if (!(ssl->shutdown & SSL_SENT_SHUTDOWN)) {
- ssl->shutdown |= SSL_SENT_SHUTDOWN;
- ssl3_send_alert(ssl, SSL3_AL_WARNING, SSL_AD_CLOSE_NOTIFY);
+ /* This function completes in two stages. It sends a close_notify and then it
+ * waits for a close_notify to come in. Perform exactly one action and return
+ * whether or not it succeeds. */
- /* our shutdown alert has been sent now, and if it still needs to be
- * written, ssl->s3->alert_dispatch will be true */
- if (ssl->s3->alert_dispatch) {
- return -1; /* return WANT_WRITE */
+ if (ssl->s3->send_shutdown != ssl_shutdown_close_notify) {
+ /* Send a close_notify. */
+ if (ssl3_send_alert(ssl, SSL3_AL_WARNING, SSL_AD_CLOSE_NOTIFY) <= 0) {
+ return -1;
}
} else if (ssl->s3->alert_dispatch) {
- /* resend it if not sent */
- int ret = ssl->method->ssl_dispatch_alert(ssl);
- if (ret == -1) {
- /* we only get to return -1 here the 2nd/Nth invocation, we must have
- * already signalled return 0 upon a previous invoation, return
- * WANT_WRITE */
- return ret;
+ /* Finish sending the close_notify. */
+ if (ssl->method->ssl_dispatch_alert(ssl) <= 0) {
+ return -1;
}
- } else if (!(ssl->shutdown & SSL_RECEIVED_SHUTDOWN)) {
- /* If we are waiting for a close from our peer, we are closed */
+ } else if (ssl->s3->recv_shutdown != ssl_shutdown_close_notify) {
+ /* Wait for the peer's close_notify. */
ssl->method->ssl_read_close_notify(ssl);
- if (!(ssl->shutdown & SSL_RECEIVED_SHUTDOWN)) {
- return -1; /* return WANT_READ */
+ if (ssl->s3->recv_shutdown != ssl_shutdown_close_notify) {
+ return -1;
}
}
- if (ssl->shutdown == (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN) &&
- !ssl->s3->alert_dispatch) {
- return 1;
- } else {
- return 0;
- }
+ /* Return 0 for unidirectional shutdown and 1 for bidirectional shutdown. */
+ return ssl->s3->recv_shutdown == ssl_shutdown_close_notify;
}
int SSL_get_error(const SSL *ssl, int ret_code) {
@@ -738,8 +730,7 @@
}
if (ret_code == 0) {
- if ((ssl->shutdown & SSL_RECEIVED_SHUTDOWN) && ssl->s3->clean_shutdown) {
- /* The socket was cleanly shut down with a close_notify. */
+ if (ssl->s3->recv_shutdown == ssl_shutdown_close_notify) {
return SSL_ERROR_ZERO_RETURN;
}
/* An EOF was observed which violates the protocol, and the underlying
@@ -1035,35 +1026,36 @@
}
int SSL_set_wfd(SSL *ssl, int fd) {
- if (ssl->rbio == NULL ||
- BIO_method_type(ssl->rbio) != BIO_TYPE_SOCKET ||
- BIO_get_fd(ssl->rbio, NULL) != fd) {
+ BIO *rbio = SSL_get_rbio(ssl);
+ if (rbio == NULL || BIO_method_type(rbio) != BIO_TYPE_SOCKET ||
+ BIO_get_fd(rbio, NULL) != fd) {
BIO *bio = BIO_new(BIO_s_socket());
if (bio == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
return 0;
}
BIO_set_fd(bio, fd, BIO_NOCLOSE);
- SSL_set_bio(ssl, SSL_get_rbio(ssl), bio);
+ SSL_set_bio(ssl, rbio, bio);
} else {
- SSL_set_bio(ssl, SSL_get_rbio(ssl), SSL_get_rbio(ssl));
+ SSL_set_bio(ssl, rbio, rbio);
}
return 1;
}
int SSL_set_rfd(SSL *ssl, int fd) {
- if (ssl->wbio == NULL || BIO_method_type(ssl->wbio) != BIO_TYPE_SOCKET ||
- BIO_get_fd(ssl->wbio, NULL) != fd) {
+ BIO *wbio = SSL_get_wbio(ssl);
+ if (wbio == NULL || BIO_method_type(wbio) != BIO_TYPE_SOCKET ||
+ BIO_get_fd(wbio, NULL) != fd) {
BIO *bio = BIO_new(BIO_s_socket());
if (bio == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
return 0;
}
BIO_set_fd(bio, fd, BIO_NOCLOSE);
- SSL_set_bio(ssl, bio, SSL_get_wbio(ssl));
+ SSL_set_bio(ssl, bio, wbio);
} else {
- SSL_set_bio(ssl, SSL_get_wbio(ssl), SSL_get_wbio(ssl));
+ SSL_set_bio(ssl, wbio, wbio);
}
return 1;
}
@@ -1710,7 +1702,7 @@
mask_a |= SSL_aRSA;
} else if (ssl_private_key_type(ssl) == EVP_PKEY_EC) {
/* An ECC certificate may be usable for ECDSA cipher suites depending on
- * the key usage extension and on the client's curve preferences. */
+ * the key usage extension and on the client's group preferences. */
X509 *x = ssl->cert->x509;
/* This call populates extension flags (ex_flags). */
X509_check_purpose(x, -1, 0);
@@ -1727,12 +1719,15 @@
mask_k |= SSL_kDHE;
}
- /* Check for a shared curve to consider ECDHE ciphers. */
+ /* Check for a shared group to consider ECDHE ciphers. */
uint16_t unused;
- if (tls1_get_shared_curve(ssl, &unused)) {
+ if (tls1_get_shared_group(ssl, &unused)) {
mask_k |= SSL_kECDHE;
}
+ /* CECPQ1 ciphers are always acceptable if supported by both sides. */
+ mask_k |= SSL_kCECPQ1;
+
/* PSK requires a server callback. */
if (ssl->psk_server_callback != NULL) {
mask_k |= SSL_kPSK;
@@ -1779,7 +1774,7 @@
flush_cache = 1;
ctx->handshakes_since_cache_flush = 0;
}
- CRYPTO_MUTEX_unlock(&ctx->lock);
+ CRYPTO_MUTEX_unlock_write(&ctx->lock);
if (flush_cache) {
SSL_CTX_flush_sessions(ctx, (unsigned long)time(NULL));
@@ -1789,6 +1784,9 @@
static const char *ssl_get_version(int version) {
switch (version) {
+ case TLS1_3_VERSION:
+ return "TLSv1.3";
+
case TLS1_2_VERSION:
return "TLSv1.2";
@@ -1865,38 +1863,26 @@
int *SSL_get_server_tmp_key(SSL *ssl, EVP_PKEY **out_key) { return 0; }
-int ssl_init_wbio_buffer(SSL *ssl, int push) {
- BIO *bbio;
+int ssl_is_wbio_buffered(const SSL *ssl) {
+ return ssl->bbio != NULL;
+}
- if (ssl->bbio == NULL) {
- bbio = BIO_new(BIO_f_buffer());
- if (bbio == NULL) {
- return 0;
- }
- ssl->bbio = bbio;
- } else {
- bbio = ssl->bbio;
- if (ssl->bbio == ssl->wbio) {
- ssl->wbio = BIO_pop(ssl->wbio);
- }
+int ssl_init_wbio_buffer(SSL *ssl) {
+ if (ssl->bbio != NULL) {
+ /* Already buffered. */
+ assert(ssl->bbio == ssl->wbio);
+ return 1;
}
- BIO_reset(bbio);
- if (!BIO_set_read_buffer_size(bbio, 1)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ BIO *bbio = BIO_new(BIO_f_buffer());
+ if (bbio == NULL ||
+ !BIO_set_read_buffer_size(bbio, 1)) {
+ BIO_free(bbio);
return 0;
}
- if (push) {
- if (ssl->wbio != bbio) {
- ssl->wbio = BIO_push(bbio, ssl->wbio);
- }
- } else {
- if (ssl->wbio == bbio) {
- ssl->wbio = BIO_pop(bbio);
- }
- }
-
+ ssl->bbio = bbio;
+ ssl->wbio = BIO_push(bbio, ssl->wbio);
return 1;
}
@@ -1905,11 +1891,9 @@
return;
}
- if (ssl->bbio == ssl->wbio) {
- /* remove buffering */
- ssl->wbio = BIO_pop(ssl->wbio);
- }
+ assert(ssl->bbio == ssl->wbio);
+ ssl->wbio = BIO_pop(ssl->wbio);
BIO_free(ssl->bbio);
ssl->bbio = NULL;
}
@@ -1931,12 +1915,32 @@
void SSL_set_shutdown(SSL *ssl, int mode) {
/* It is an error to clear any bits that have already been set. (We can't try
* to get a second close_notify or send two.) */
- assert((ssl->shutdown & mode) == ssl->shutdown);
+ assert((SSL_get_shutdown(ssl) & mode) == SSL_get_shutdown(ssl));
- ssl->shutdown |= mode;
+ if (mode & SSL_RECEIVED_SHUTDOWN &&
+ ssl->s3->recv_shutdown == ssl_shutdown_none) {
+ ssl->s3->recv_shutdown = ssl_shutdown_close_notify;
+ }
+
+ if (mode & SSL_SENT_SHUTDOWN &&
+ ssl->s3->send_shutdown == ssl_shutdown_none) {
+ ssl->s3->send_shutdown = ssl_shutdown_close_notify;
+ }
}
-int SSL_get_shutdown(const SSL *ssl) { return ssl->shutdown; }
+int SSL_get_shutdown(const SSL *ssl) {
+ int ret = 0;
+ if (ssl->s3->recv_shutdown != ssl_shutdown_none) {
+ /* Historically, OpenSSL set |SSL_RECEIVED_SHUTDOWN| on both close_notify
+ * and fatal alert. */
+ ret |= SSL_RECEIVED_SHUTDOWN;
+ }
+ if (ssl->s3->send_shutdown == ssl_shutdown_close_notify) {
+ /* Historically, OpenSSL set |SSL_SENT_SHUTDOWN| on only close_notify. */
+ ret |= SSL_SENT_SHUTDOWN;
+ }
+ return ret;
+}
int SSL_version(const SSL *ssl) { return ssl->version; }
@@ -2293,7 +2297,7 @@
/* False Start only for TLS 1.2 with an ECDHE+AEAD cipher and ALPN or NPN. */
return !SSL_IS_DTLS(ssl) &&
- SSL_version(ssl) >= TLS1_2_VERSION &&
+ SSL_version(ssl) == TLS1_2_VERSION &&
(ssl->s3->alpn_selected || ssl->s3->next_proto_neg_seen) &&
cipher != NULL &&
cipher->algorithm_mkey == SSL_kECDHE &&
@@ -2308,6 +2312,7 @@
case TLS1_VERSION:
case TLS1_1_VERSION:
case TLS1_2_VERSION:
+ case TLS1_3_VERSION:
case DTLS1_VERSION:
case DTLS1_2_VERSION:
return &TLSv1_enc_data;
@@ -2332,7 +2337,10 @@
return 0;
}
- max_version = (ssl->max_version != 0) ? ssl->max_version : TLS1_2_VERSION;
+ max_version = (ssl->max_version != 0) ? ssl->max_version : TLS1_3_VERSION;
+ if (!(ssl->options & SSL_OP_NO_TLSv1_3) && TLS1_3_VERSION <= max_version) {
+ return TLS1_3_VERSION;
+ }
if (!(ssl->options & SSL_OP_NO_TLSv1_2) && TLS1_2_VERSION <= max_version) {
return TLS1_2_VERSION;
}
@@ -2376,8 +2384,11 @@
client_version = ssl->max_version;
}
- if (client_version >= TLS1_2_VERSION &&
- !(ssl->options & SSL_OP_NO_TLSv1_2)) {
+ if (client_version >= TLS1_3_VERSION &&
+ !(ssl->options & SSL_OP_NO_TLSv1_3)) {
+ version = TLS1_3_VERSION;
+ } else if (client_version >= TLS1_2_VERSION &&
+ !(ssl->options & SSL_OP_NO_TLSv1_2)) {
version = TLS1_2_VERSION;
} else if (client_version >= TLS1_1_VERSION &&
!(ssl->options & SSL_OP_NO_TLSv1_1)) {
@@ -2426,7 +2437,10 @@
version = ssl->max_version;
}
} else {
- if (!(options & SSL_OP_NO_TLSv1_2)) {
+ if (!(options & SSL_OP_NO_TLSv1_3)) {
+ version = TLS1_3_VERSION;
+ }
+ if (!(options & SSL_OP_NO_TLSv1_2) && (options & SSL_OP_NO_TLSv1_3)) {
version = TLS1_2_VERSION;
}
if (!(options & SSL_OP_NO_TLSv1_1) && (options & SSL_OP_NO_TLSv1_2)) {
@@ -2486,6 +2500,9 @@
case TLS1_2_VERSION:
return !(ssl->options & SSL_OP_NO_TLSv1_2);
+ case TLS1_3_VERSION:
+ return !(ssl->options & SSL_OP_NO_TLSv1_3);
+
default:
return 0;
}
@@ -2644,7 +2661,6 @@
}
ssl->hit = 0;
- ssl->shutdown = 0;
/* SSL_clear may be called before or after the |ssl| is initialized in either
* accept or connect state. In the latter case, SSL_clear should preserve the
diff --git a/src/ssl/ssl_session.c b/src/ssl/ssl_session.c
index 12d065e..8e51a6a 100644
--- a/src/ssl/ssl_session.c
+++ b/src/ssl/ssl_session.c
@@ -396,7 +396,7 @@
SSL_SESSION_up_ref(session);
}
/* TODO(davidben): This should probably move it to the front of the list. */
- CRYPTO_MUTEX_unlock(&ssl->initial_ctx->lock);
+ CRYPTO_MUTEX_unlock_read(&ssl->initial_ctx->lock);
if (session != NULL) {
*out_session = session;
@@ -517,7 +517,7 @@
SSL_SESSION *old_session;
CRYPTO_MUTEX_lock_write(&ctx->lock);
if (!lh_SSL_SESSION_insert(ctx->sessions, &old_session, session)) {
- CRYPTO_MUTEX_unlock(&ctx->lock);
+ CRYPTO_MUTEX_unlock_write(&ctx->lock);
SSL_SESSION_free(session);
return 0;
}
@@ -525,7 +525,7 @@
if (old_session != NULL) {
if (old_session == session) {
/* |session| was already in the cache. */
- CRYPTO_MUTEX_unlock(&ctx->lock);
+ CRYPTO_MUTEX_unlock_write(&ctx->lock);
SSL_SESSION_free(old_session);
return 0;
}
@@ -547,7 +547,7 @@
}
}
- CRYPTO_MUTEX_unlock(&ctx->lock);
+ CRYPTO_MUTEX_unlock_write(&ctx->lock);
return 1;
}
@@ -571,7 +571,7 @@
}
if (lock) {
- CRYPTO_MUTEX_unlock(&ctx->lock);
+ CRYPTO_MUTEX_unlock_write(&ctx->lock);
}
if (ret) {
@@ -654,11 +654,12 @@
tp.time = time;
CRYPTO_MUTEX_lock_write(&ctx->lock);
lh_SSL_SESSION_doall_arg(tp.cache, timeout_doall_arg, &tp);
- CRYPTO_MUTEX_unlock(&ctx->lock);
+ CRYPTO_MUTEX_unlock_write(&ctx->lock);
}
int ssl_clear_bad_session(SSL *ssl) {
- if (ssl->session != NULL && !(ssl->shutdown & SSL_SENT_SHUTDOWN) &&
+ if (ssl->session != NULL &&
+ ssl->s3->send_shutdown != ssl_shutdown_close_notify &&
!SSL_in_init(ssl)) {
SSL_CTX_remove_session(ssl->ctx, ssl->session);
return 1;
diff --git a/src/ssl/ssl_stat.c b/src/ssl/ssl_stat.c
index 8fa197d..15d1270 100644
--- a/src/ssl/ssl_stat.c
+++ b/src/ssl/ssl_stat.c
@@ -110,39 +110,21 @@
case SSL3_ST_CR_SRVR_HELLO_A:
return "SSLv3 read server hello A";
- case SSL3_ST_CR_SRVR_HELLO_B:
- return "SSLv3 read server hello B";
-
case SSL3_ST_CR_CERT_A:
return "SSLv3 read server certificate A";
- case SSL3_ST_CR_CERT_B:
- return "SSLv3 read server certificate B";
-
case SSL3_ST_CR_KEY_EXCH_A:
return "SSLv3 read server key exchange A";
- case SSL3_ST_CR_KEY_EXCH_B:
- return "SSLv3 read server key exchange B";
-
case SSL3_ST_CR_CERT_REQ_A:
return "SSLv3 read server certificate request A";
- case SSL3_ST_CR_CERT_REQ_B:
- return "SSLv3 read server certificate request B";
-
case SSL3_ST_CR_SESSION_TICKET_A:
return "SSLv3 read server session ticket A";
- case SSL3_ST_CR_SESSION_TICKET_B:
- return "SSLv3 read server session ticket B";
-
case SSL3_ST_CR_SRVR_DONE_A:
return "SSLv3 read server done A";
- case SSL3_ST_CR_SRVR_DONE_B:
- return "SSLv3 read server done B";
-
case SSL3_ST_CW_CERT_A:
return "SSLv3 write client certificate A";
@@ -191,10 +173,6 @@
case SSL3_ST_SR_FINISHED_A:
return "SSLv3 read finished A";
- case SSL3_ST_CR_FINISHED_B:
- case SSL3_ST_SR_FINISHED_B:
- return "SSLv3 read finished B";
-
case SSL3_ST_CW_FLUSH:
case SSL3_ST_SW_FLUSH:
return "SSLv3 flush data";
@@ -208,9 +186,6 @@
case SSL3_ST_SR_CLNT_HELLO_C:
return "SSLv3 read client hello C";
- case SSL3_ST_SR_CLNT_HELLO_D:
- return "SSLv3 read client hello D";
-
case SSL3_ST_SW_HELLO_REQ_A:
return "SSLv3 write hello request A";
@@ -259,9 +234,6 @@
case SSL3_ST_SR_CERT_A:
return "SSLv3 read client certificate A";
- case SSL3_ST_SR_CERT_B:
- return "SSLv3 read client certificate B";
-
case SSL3_ST_SR_KEY_EXCH_A:
return "SSLv3 read client key exchange A";
@@ -271,16 +243,10 @@
case SSL3_ST_SR_CERT_VRFY_A:
return "SSLv3 read certificate verify A";
- case SSL3_ST_SR_CERT_VRFY_B:
- return "SSLv3 read certificate verify B";
-
/* DTLS */
case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
return "DTLS1 read hello verify request A";
- case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B:
- return "DTLS1 read hello verify request B";
-
default:
return "unknown state";
}
@@ -311,33 +277,18 @@
case SSL3_ST_CR_SRVR_HELLO_A:
return "3RSH_A";
- case SSL3_ST_CR_SRVR_HELLO_B:
- return "3RSH_B";
-
case SSL3_ST_CR_CERT_A:
return "3RSC_A";
- case SSL3_ST_CR_CERT_B:
- return "3RSC_B";
-
case SSL3_ST_CR_KEY_EXCH_A:
return "3RSKEA";
- case SSL3_ST_CR_KEY_EXCH_B:
- return "3RSKEB";
-
case SSL3_ST_CR_CERT_REQ_A:
return "3RCR_A";
- case SSL3_ST_CR_CERT_REQ_B:
- return "3RCR_B";
-
case SSL3_ST_CR_SRVR_DONE_A:
return "3RSD_A";
- case SSL3_ST_CR_SRVR_DONE_B:
- return "3RSD_B";
-
case SSL3_ST_CW_CERT_A:
return "3WCC_A";
@@ -386,10 +337,6 @@
case SSL3_ST_CR_FINISHED_A:
return "3RFINA";
- case SSL3_ST_SR_FINISHED_B:
- case SSL3_ST_CR_FINISHED_B:
- return "3RFINB";
-
case SSL3_ST_SW_HELLO_REQ_A:
return "3WHR_A";
@@ -408,9 +355,6 @@
case SSL3_ST_SR_CLNT_HELLO_C:
return "3RCH_C";
- case SSL3_ST_SR_CLNT_HELLO_D:
- return "3RCH_D";
-
case SSL3_ST_SW_SRVR_HELLO_A:
return "3WSH_A";
@@ -444,28 +388,16 @@
case SSL3_ST_SR_CERT_A:
return "3RCC_A";
- case SSL3_ST_SR_CERT_B:
- return "3RCC_B";
-
case SSL3_ST_SR_KEY_EXCH_A:
return "3RCKEA";
- case SSL3_ST_SR_KEY_EXCH_B:
- return "3RCKEB";
-
case SSL3_ST_SR_CERT_VRFY_A:
return "3RCV_A";
- case SSL3_ST_SR_CERT_VRFY_B:
- return "3RCV_B";
-
/* DTLS */
case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
return "DRCHVA";
- case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B:
- return "DRCHVB";
-
default:
return "UNKWN ";
}
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index 590a2c1..ef38902 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -254,6 +254,31 @@
"TLSv1.2",
};
+static const char *kMustNotIncludeCECPQ1[] = {
+ "ALL",
+ "DEFAULT",
+ "MEDIUM",
+ "HIGH",
+ "FIPS",
+ "SHA",
+ "SHA1",
+ "SHA256",
+ "SHA384",
+ "RSA",
+ "SSLv3",
+ "TLSv1",
+ "TLSv1.2",
+ "aRSA",
+ "RSA",
+ "aECDSA",
+ "ECDSA",
+ "AES",
+ "AES128",
+ "AES256",
+ "AESGCM",
+ "CHACHA20",
+};
+
static void PrintCipherPreferenceList(ssl_cipher_preference_list_st *list) {
bool in_group = false;
for (size_t i = 0; i < sk_SSL_CIPHER_num(list->ciphers); i++) {
@@ -324,6 +349,24 @@
return true;
}
+static bool TestRuleDoesNotIncludeCECPQ1(const char *rule) {
+ ScopedSSL_CTX ctx(SSL_CTX_new(TLS_method()));
+ if (!ctx) {
+ return false;
+ }
+ if (!SSL_CTX_set_cipher_list(ctx.get(), rule)) {
+ fprintf(stderr, "Error: cipher rule '%s' failed\n", rule);
+ return false;
+ }
+ for (size_t i = 0; i < sk_SSL_CIPHER_num(ctx->cipher_list->ciphers); i++) {
+ if (SSL_CIPHER_is_CECPQ1(sk_SSL_CIPHER_value(ctx->cipher_list->ciphers, i))) {
+ fprintf(stderr, "Error: cipher rule '%s' includes CECPQ1\n",rule);
+ return false;
+ }
+ }
+ return true;
+}
+
static bool TestCipherRules() {
for (const CipherTest &test : kCipherTests) {
if (!TestCipherRule(test)) {
@@ -349,6 +392,12 @@
}
}
+ for (const char *rule : kMustNotIncludeCECPQ1) {
+ if (!TestRuleDoesNotIncludeCECPQ1(rule)) {
+ return false;
+ }
+ }
+
return true;
}
@@ -646,7 +695,10 @@
if (!ctx) {
return false;
}
- return ctx->min_version == version && ctx->max_version == version;
+ // TODO(svaldez): Remove TLS1_2_VERSION fallback upon implementing TLS 1.3.
+ return ctx->min_version == version &&
+ (ctx->max_version == version ||
+ (version == 0 && ctx->max_version == TLS1_2_VERSION));
}
static bool CipherGetRFCName(std::string *out, uint16_t value) {
@@ -1027,23 +1079,9 @@
PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
}
-static bool TestSequenceNumber(bool dtls) {
- ScopedSSL_CTX client_ctx(SSL_CTX_new(dtls ? DTLS_method() : TLS_method()));
- ScopedSSL_CTX server_ctx(SSL_CTX_new(dtls ? DTLS_method() : TLS_method()));
- if (!client_ctx || !server_ctx) {
- return false;
- }
-
- ScopedX509 cert = GetTestCertificate();
- ScopedEVP_PKEY key = GetTestKey();
- if (!cert || !key ||
- !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
- !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) {
- return false;
- }
-
- // Create a client and server connected to each other.
- ScopedSSL client(SSL_new(client_ctx.get())), server(SSL_new(server_ctx.get()));
+static bool ConnectClientAndServer(ScopedSSL *out_client, ScopedSSL *out_server,
+ SSL_CTX *client_ctx, SSL_CTX *server_ctx) {
+ ScopedSSL client(SSL_new(client_ctx)), server(SSL_new(server_ctx));
if (!client || !server) {
return false;
}
@@ -1083,6 +1121,32 @@
}
}
+ *out_client = std::move(client);
+ *out_server = std::move(server);
+ return true;
+}
+
+static bool TestSequenceNumber(bool dtls) {
+ ScopedSSL_CTX client_ctx(SSL_CTX_new(dtls ? DTLS_method() : TLS_method()));
+ ScopedSSL_CTX server_ctx(SSL_CTX_new(dtls ? DTLS_method() : TLS_method()));
+ if (!client_ctx || !server_ctx) {
+ return false;
+ }
+
+ ScopedX509 cert = GetTestCertificate();
+ ScopedEVP_PKEY key = GetTestKey();
+ if (!cert || !key ||
+ !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) {
+ return false;
+ }
+
+ ScopedSSL client, server;
+ if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get())) {
+ return false;
+ }
+
uint64_t client_read_seq = SSL_get_read_sequence(client.get());
uint64_t client_write_seq = SSL_get_write_sequence(client.get());
uint64_t server_read_seq = SSL_get_read_sequence(server.get());
@@ -1131,6 +1195,62 @@
return true;
}
+static bool TestOneSidedShutdown() {
+ ScopedSSL_CTX client_ctx(SSL_CTX_new(TLS_method()));
+ ScopedSSL_CTX server_ctx(SSL_CTX_new(TLS_method()));
+ if (!client_ctx || !server_ctx) {
+ return false;
+ }
+
+ ScopedX509 cert = GetTestCertificate();
+ ScopedEVP_PKEY key = GetTestKey();
+ if (!cert || !key ||
+ !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) {
+ return false;
+ }
+
+ ScopedSSL client, server;
+ if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get())) {
+ return false;
+ }
+
+ // Shut down half the connection. SSL_shutdown will return 0 to signal only
+ // one side has shut down.
+ if (SSL_shutdown(client.get()) != 0) {
+ fprintf(stderr, "Could not shutdown.\n");
+ return false;
+ }
+
+ // Reading from the server should consume the EOF.
+ uint8_t byte;
+ if (SSL_read(server.get(), &byte, 1) != 0 ||
+ SSL_get_error(server.get(), 0) != SSL_ERROR_ZERO_RETURN) {
+ fprintf(stderr, "Connection was not shut down cleanly.\n");
+ return false;
+ }
+
+ // However, the server may continue to write data and then shut down the
+ // connection.
+ byte = 42;
+ if (SSL_write(server.get(), &byte, 1) != 1 ||
+ SSL_read(client.get(), &byte, 1) != 1 ||
+ byte != 42) {
+ fprintf(stderr, "Could not send byte.\n");
+ return false;
+ }
+
+ // The server may then shutdown the connection.
+ if (SSL_shutdown(server.get()) != 1 ||
+ SSL_shutdown(client.get()) != 1) {
+ fprintf(stderr, "Could not complete shutdown.\n");
+ return false;
+ }
+
+ return true;
+}
+
int main() {
CRYPTO_library_init();
@@ -1154,7 +1274,8 @@
!TestClientCAList() ||
!TestInternalSessionCache() ||
!TestSequenceNumber(false /* TLS */) ||
- !TestSequenceNumber(true /* DTLS */)) {
+ !TestSequenceNumber(true /* DTLS */) ||
+ !TestOneSidedShutdown()) {
ERR_print_errors_fp(stderr);
return 1;
}
diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c
index eac9579..16cac15 100644
--- a/src/ssl/t1_lib.c
+++ b/src/ssl/t1_lib.c
@@ -291,77 +291,77 @@
return 0;
}
-static const uint16_t eccurves_default[] = {
- SSL_CURVE_X25519,
- SSL_CURVE_SECP256R1,
- SSL_CURVE_SECP384R1,
+static const uint16_t kDefaultGroups[] = {
+ SSL_GROUP_X25519,
+ SSL_GROUP_SECP256R1,
+ SSL_GROUP_SECP384R1,
#if defined(BORINGSSL_ANDROID_SYSTEM)
- SSL_CURVE_SECP521R1,
+ SSL_GROUP_SECP521R1,
#endif
};
-/* tls1_get_curvelist sets |*out_curve_ids| and |*out_curve_ids_len| to the
- * list of allowed curve IDs. If |get_peer_curves| is non-zero, return the
- * peer's curve list. Otherwise, return the preferred list. */
-static void tls1_get_curvelist(SSL *ssl, int get_peer_curves,
- const uint16_t **out_curve_ids,
- size_t *out_curve_ids_len) {
- if (get_peer_curves) {
- /* Only clients send a curve list, so this function is only called
- * on the server. */
+/* tls1_get_grouplist sets |*out_group_ids| and |*out_group_ids_len| to the
+ * list of allowed group IDs. If |get_peer_groups| is non-zero, return the
+ * peer's group list. Otherwise, return the preferred list. */
+static void tls1_get_grouplist(SSL *ssl, int get_peer_groups,
+ const uint16_t **out_group_ids,
+ size_t *out_group_ids_len) {
+ if (get_peer_groups) {
+ /* Only clients send a supported group list, so this function is only
+ * called on the server. */
assert(ssl->server);
- *out_curve_ids = ssl->s3->tmp.peer_ellipticcurvelist;
- *out_curve_ids_len = ssl->s3->tmp.peer_ellipticcurvelist_length;
+ *out_group_ids = ssl->s3->tmp.peer_supported_group_list;
+ *out_group_ids_len = ssl->s3->tmp.peer_supported_group_list_len;
return;
}
- *out_curve_ids = ssl->tlsext_ellipticcurvelist;
- *out_curve_ids_len = ssl->tlsext_ellipticcurvelist_length;
- if (!*out_curve_ids) {
- *out_curve_ids = eccurves_default;
- *out_curve_ids_len = sizeof(eccurves_default) / sizeof(eccurves_default[0]);
+ *out_group_ids = ssl->supported_group_list;
+ *out_group_ids_len = ssl->supported_group_list_len;
+ if (!*out_group_ids) {
+ *out_group_ids = kDefaultGroups;
+ *out_group_ids_len = sizeof(kDefaultGroups) / sizeof(kDefaultGroups[0]);
}
}
-int tls1_get_shared_curve(SSL *ssl, uint16_t *out_curve_id) {
- const uint16_t *curves, *peer_curves, *pref, *supp;
- size_t curves_len, peer_curves_len, pref_len, supp_len, i, j;
+int tls1_get_shared_group(SSL *ssl, uint16_t *out_group_id) {
+ const uint16_t *groups, *peer_groups, *pref, *supp;
+ size_t groups_len, peer_groups_len, pref_len, supp_len, i, j;
/* Can't do anything on client side */
if (ssl->server == 0) {
return 0;
}
- tls1_get_curvelist(ssl, 0 /* local curves */, &curves, &curves_len);
- tls1_get_curvelist(ssl, 1 /* peer curves */, &peer_curves, &peer_curves_len);
+ tls1_get_grouplist(ssl, 0 /* local groups */, &groups, &groups_len);
+ tls1_get_grouplist(ssl, 1 /* peer groups */, &peer_groups, &peer_groups_len);
- if (peer_curves_len == 0) {
- /* Clients are not required to send a supported_curves extension. In this
- * case, the server is free to pick any curve it likes. See RFC 4492,
+ if (peer_groups_len == 0) {
+ /* Clients are not required to send a supported_groups extension. In this
+ * case, the server is free to pick any group it likes. See RFC 4492,
* section 4, paragraph 3.
*
* However, in the interests of compatibility, we will skip ECDH if the
* client didn't send an extension because we can't be sure that they'll
- * support our favoured curve. */
+ * support our favoured group. */
return 0;
}
if (ssl->options & SSL_OP_CIPHER_SERVER_PREFERENCE) {
- pref = curves;
- pref_len = curves_len;
- supp = peer_curves;
- supp_len = peer_curves_len;
+ pref = groups;
+ pref_len = groups_len;
+ supp = peer_groups;
+ supp_len = peer_groups_len;
} else {
- pref = peer_curves;
- pref_len = peer_curves_len;
- supp = curves;
- supp_len = curves_len;
+ pref = peer_groups;
+ pref_len = peer_groups_len;
+ supp = groups;
+ supp_len = groups_len;
}
for (i = 0; i < pref_len; i++) {
for (j = 0; j < supp_len; j++) {
if (pref[i] == supp[j]) {
- *out_curve_id = pref[i];
+ *out_group_id = pref[i];
return 1;
}
}
@@ -370,34 +370,34 @@
return 0;
}
-int tls1_set_curves(uint16_t **out_curve_ids, size_t *out_curve_ids_len,
+int tls1_set_curves(uint16_t **out_group_ids, size_t *out_group_ids_len,
const int *curves, size_t ncurves) {
- uint16_t *curve_ids;
+ uint16_t *group_ids;
size_t i;
- curve_ids = OPENSSL_malloc(ncurves * sizeof(uint16_t));
- if (curve_ids == NULL) {
+ group_ids = OPENSSL_malloc(ncurves * sizeof(uint16_t));
+ if (group_ids == NULL) {
return 0;
}
for (i = 0; i < ncurves; i++) {
- if (!ssl_nid_to_curve_id(&curve_ids[i], curves[i])) {
- OPENSSL_free(curve_ids);
+ if (!ssl_nid_to_group_id(&group_ids[i], curves[i])) {
+ OPENSSL_free(group_ids);
return 0;
}
}
- OPENSSL_free(*out_curve_ids);
- *out_curve_ids = curve_ids;
- *out_curve_ids_len = ncurves;
+ OPENSSL_free(*out_group_ids);
+ *out_group_ids = group_ids;
+ *out_group_ids_len = ncurves;
return 1;
}
-/* tls1_curve_params_from_ec_key sets |*out_curve_id| and |*out_comp_id| to the
- * TLS curve ID and point format, respectively, for |ec|. It returns one on
+/* tls1_curve_params_from_ec_key sets |*out_group_id| and |*out_comp_id| to the
+ * TLS group ID and point format, respectively, for |ec|. It returns one on
* success and zero on failure. */
-static int tls1_curve_params_from_ec_key(uint16_t *out_curve_id,
+static int tls1_curve_params_from_ec_key(uint16_t *out_group_id,
uint8_t *out_comp_id, EC_KEY *ec) {
int nid;
uint16_t id;
@@ -412,14 +412,14 @@
return 0;
}
- /* Determine curve ID */
+ /* Determine group ID */
nid = EC_GROUP_get_curve_name(grp);
- if (!ssl_nid_to_curve_id(&id, nid)) {
+ if (!ssl_nid_to_group_id(&id, nid)) {
return 0;
}
- /* Set the named curve ID. Arbitrary explicit curves are not supported. */
- *out_curve_id = id;
+ /* Set the named group ID. Arbitrary explicit groups are not supported. */
+ *out_group_id = id;
if (out_comp_id) {
if (EC_KEY_get0_public_key(ec) == NULL) {
@@ -435,35 +435,35 @@
return 1;
}
-/* tls1_check_curve_id returns one if |curve_id| is consistent with both our
- * and the peer's curve preferences. Note: if called as the client, only our
+/* tls1_check_group_id returns one if |group_id| is consistent with both our
+ * and the peer's group preferences. Note: if called as the client, only our
* preferences are checked; the peer (the server) does not send preferences. */
-int tls1_check_curve_id(SSL *ssl, uint16_t curve_id) {
- const uint16_t *curves;
- size_t curves_len, i, get_peer_curves;
+int tls1_check_group_id(SSL *ssl, uint16_t group_id) {
+ const uint16_t *groups;
+ size_t groups_len, i, get_peer_groups;
/* Check against our list, then the peer's list. */
- for (get_peer_curves = 0; get_peer_curves <= 1; get_peer_curves++) {
- if (get_peer_curves && !ssl->server) {
+ for (get_peer_groups = 0; get_peer_groups <= 1; get_peer_groups++) {
+ if (get_peer_groups && !ssl->server) {
/* Servers do not present a preference list so, if we are a client, only
* check our list. */
continue;
}
- tls1_get_curvelist(ssl, get_peer_curves, &curves, &curves_len);
- if (get_peer_curves && curves_len == 0) {
- /* Clients are not required to send a supported_curves extension. In this
- * case, the server is free to pick any curve it likes. See RFC 4492,
+ tls1_get_grouplist(ssl, get_peer_groups, &groups, &groups_len);
+ if (get_peer_groups && groups_len == 0) {
+ /* Clients are not required to send a supported_groups extension. In this
+ * case, the server is free to pick any group it likes. See RFC 4492,
* section 4, paragraph 3. */
continue;
}
- for (i = 0; i < curves_len; i++) {
- if (curves[i] == curve_id) {
+ for (i = 0; i < groups_len; i++) {
+ if (groups[i] == group_id) {
break;
}
}
- if (i == curves_len) {
+ if (i == groups_len) {
return 0;
}
}
@@ -474,7 +474,7 @@
int tls1_check_ec_cert(SSL *ssl, X509 *x) {
int ret = 0;
EVP_PKEY *pkey = X509_get_pubkey(x);
- uint16_t curve_id;
+ uint16_t group_id;
uint8_t comp_id;
if (!pkey) {
@@ -482,8 +482,8 @@
}
EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(pkey);
if (ec_key == NULL ||
- !tls1_curve_params_from_ec_key(&curve_id, &comp_id, ec_key) ||
- !tls1_check_curve_id(ssl, curve_id) ||
+ !tls1_curve_params_from_ec_key(&group_id, &comp_id, ec_key) ||
+ !tls1_check_group_id(ssl, group_id) ||
comp_id != TLSEXT_ECPOINTFORMAT_uncompressed) {
goto done;
}
@@ -1809,35 +1809,36 @@
}
-/* EC supported curves.
+/* Negotiated Groups
*
- * https://tools.ietf.org/html/rfc4492#section-5.1.2 */
+ * https://tools.ietf.org/html/rfc4492#section-5.1.2
+ * https://tools.ietf.org/html/draft-ietf-tls-tls13-12#section-6.3.2.2 */
-static void ext_ec_curves_init(SSL *ssl) {
- OPENSSL_free(ssl->s3->tmp.peer_ellipticcurvelist);
- ssl->s3->tmp.peer_ellipticcurvelist = NULL;
- ssl->s3->tmp.peer_ellipticcurvelist_length = 0;
+static void ext_supported_groups_init(SSL *ssl) {
+ OPENSSL_free(ssl->s3->tmp.peer_supported_group_list);
+ ssl->s3->tmp.peer_supported_group_list = NULL;
+ ssl->s3->tmp.peer_supported_group_list_len = 0;
}
-static int ext_ec_curves_add_clienthello(SSL *ssl, CBB *out) {
+static int ext_supported_groups_add_clienthello(SSL *ssl, CBB *out) {
if (!ssl_any_ec_cipher_suites_enabled(ssl)) {
return 1;
}
- CBB contents, curves_bytes;
- if (!CBB_add_u16(out, TLSEXT_TYPE_elliptic_curves) ||
+ CBB contents, groups_bytes;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_supported_groups) ||
!CBB_add_u16_length_prefixed(out, &contents) ||
- !CBB_add_u16_length_prefixed(&contents, &curves_bytes)) {
+ !CBB_add_u16_length_prefixed(&contents, &groups_bytes)) {
return 0;
}
- const uint16_t *curves;
- size_t curves_len;
- tls1_get_curvelist(ssl, 0, &curves, &curves_len);
+ const uint16_t *groups;
+ size_t groups_len;
+ tls1_get_grouplist(ssl, 0, &groups, &groups_len);
size_t i;
- for (i = 0; i < curves_len; i++) {
- if (!CBB_add_u16(&curves_bytes, curves[i])) {
+ for (i = 0; i < groups_len; i++) {
+ if (!CBB_add_u16(&groups_bytes, groups[i])) {
return 0;
}
}
@@ -1845,54 +1846,55 @@
return CBB_flush(out);
}
-static int ext_ec_curves_parse_serverhello(SSL *ssl, uint8_t *out_alert,
- CBS *contents) {
+static int ext_supported_groups_parse_serverhello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
/* This extension is not expected to be echoed by servers and is ignored. */
return 1;
}
-static int ext_ec_curves_parse_clienthello(SSL *ssl, uint8_t *out_alert,
- CBS *contents) {
+static int ext_supported_groups_parse_clienthello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
if (contents == NULL) {
return 1;
}
- CBS elliptic_curve_list;
- if (!CBS_get_u16_length_prefixed(contents, &elliptic_curve_list) ||
- CBS_len(&elliptic_curve_list) == 0 ||
- (CBS_len(&elliptic_curve_list) & 1) != 0 ||
+ CBS supported_group_list;
+ if (!CBS_get_u16_length_prefixed(contents, &supported_group_list) ||
+ CBS_len(&supported_group_list) == 0 ||
+ (CBS_len(&supported_group_list) & 1) != 0 ||
CBS_len(contents) != 0) {
return 0;
}
- ssl->s3->tmp.peer_ellipticcurvelist = OPENSSL_malloc(CBS_len(&elliptic_curve_list));
- if (ssl->s3->tmp.peer_ellipticcurvelist == NULL) {
+ ssl->s3->tmp.peer_supported_group_list = OPENSSL_malloc(
+ CBS_len(&supported_group_list));
+ if (ssl->s3->tmp.peer_supported_group_list == NULL) {
*out_alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
- const size_t num_curves = CBS_len(&elliptic_curve_list) / 2;
+ const size_t num_groups = CBS_len(&supported_group_list) / 2;
size_t i;
- for (i = 0; i < num_curves; i++) {
- if (!CBS_get_u16(&elliptic_curve_list,
- &ssl->s3->tmp.peer_ellipticcurvelist[i])) {
+ for (i = 0; i < num_groups; i++) {
+ if (!CBS_get_u16(&supported_group_list,
+ &ssl->s3->tmp.peer_supported_group_list[i])) {
goto err;
}
}
- assert(CBS_len(&elliptic_curve_list) == 0);
- ssl->s3->tmp.peer_ellipticcurvelist_length = num_curves;
+ assert(CBS_len(&supported_group_list) == 0);
+ ssl->s3->tmp.peer_supported_group_list_len = num_groups;
return 1;
err:
- OPENSSL_free(ssl->s3->tmp.peer_ellipticcurvelist);
- ssl->s3->tmp.peer_ellipticcurvelist = NULL;
+ OPENSSL_free(ssl->s3->tmp.peer_supported_group_list);
+ ssl->s3->tmp.peer_supported_group_list = NULL;
*out_alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
-static int ext_ec_curves_add_serverhello(SSL *ssl, CBB *out) {
+static int ext_supported_groups_add_serverhello(SSL *ssl, CBB *out) {
/* Servers don't echo this extension. */
return 1;
}
@@ -2003,12 +2005,12 @@
* intolerant to the last extension being zero-length. See
* https://crbug.com/363583. */
{
- TLSEXT_TYPE_elliptic_curves,
- ext_ec_curves_init,
- ext_ec_curves_add_clienthello,
- ext_ec_curves_parse_serverhello,
- ext_ec_curves_parse_clienthello,
- ext_ec_curves_add_serverhello,
+ TLSEXT_TYPE_supported_groups,
+ ext_supported_groups_init,
+ ext_supported_groups_add_clienthello,
+ ext_supported_groups_parse_serverhello,
+ ext_supported_groups_parse_clienthello,
+ ext_supported_groups_add_serverhello,
},
};
diff --git a/src/ssl/test/README.md b/src/ssl/test/README.md
new file mode 100644
index 0000000..7a46c32
--- /dev/null
+++ b/src/ssl/test/README.md
@@ -0,0 +1,35 @@
+# BoringSSL SSL Tests
+
+This directory contains BoringSSL's protocol-level test suite.
+
+Testing a TLS implementation can be difficult. We need to produce invalid but
+sufficiently correct handshakes to get our implementation close to its edge
+cases. TLS's cryptographic steps mean we cannot use a transcript and effectively
+need a TLS implementation on the other end. But we do not wish to litter
+BoringSSL with options for bugs to test against.
+
+Instead, we use a fork of the Go `crypto/tls` package, heavily patched with
+configurable bugs. This code, along with a test suite and harness written in Go,
+lives in the `runner` directory. The harness runs BoringSSL via a C/C++ shim
+binary which lives in this directory. All communication with the shim binary
+occurs with command-line flags, sockets, and standard I/O.
+
+This strategy also ensures we always test against a second implementation. All
+features should be implemented twice, once in C for BoringSSL and once in Go for
+testing. If possible, the Go code should be suitable for potentially
+upstreaming. However, sometimes test code has different needs. For example, our
+test DTLS code enforces strict ordering on sequence numbers and has controlled
+packet drop simulation.
+
+To run the tests manually, run `go test` from the `runner` directory. It takes
+command-line flags found at the top of `runner/runner.go`. The `-help` option
+also works after using `go test -c` to make a `runner.test` binary first.
+
+If adding a new test, these files may be a good starting point:
+
+ * `runner/runner.go`: the test harness and all the individual tests.
+ * `runner/common.go`: contains the `Config` and `ProtocolBugs` struct which
+ control the Go TLS implementation's behavior.
+ * `test_config.h`, `test_config.cc`: the command-line flags which control the
+ shim's behavior.
+ * `bssl_shim.cc`: the shim binary itself.
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index 5effa58..519736d 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -117,11 +117,11 @@
static int g_config_index = 0;
static int g_state_index = 0;
-static bool SetConfigPtr(SSL *ssl, const TestConfig *config) {
+static bool SetTestConfig(SSL *ssl, const TestConfig *config) {
return SSL_set_ex_data(ssl, g_config_index, (void *)config) == 1;
}
-static const TestConfig *GetConfigPtr(const SSL *ssl) {
+static const TestConfig *GetTestConfig(const SSL *ssl) {
return (const TestConfig *)SSL_get_ex_data(ssl, g_config_index);
}
@@ -300,7 +300,7 @@
static bool GetCertificate(SSL *ssl, ScopedX509 *out_x509,
ScopedEVP_PKEY *out_pkey) {
- const TestConfig *config = GetConfigPtr(ssl);
+ const TestConfig *config = GetTestConfig(ssl);
if (!config->digest_prefs.empty()) {
std::unique_ptr<char, Free<char>> digest_prefs(
@@ -353,7 +353,7 @@
if (pkey) {
TestState *test_state = GetTestState(ssl);
- const TestConfig *config = GetConfigPtr(ssl);
+ const TestConfig *config = GetTestConfig(ssl);
if (config->async) {
test_state->private_key = std::move(pkey);
SSL_set_private_key_method(ssl, &g_async_private_key_method);
@@ -370,7 +370,7 @@
}
static int SelectCertificateCallback(const struct ssl_early_callback_ctx *ctx) {
- const TestConfig *config = GetConfigPtr(ctx->ssl);
+ const TestConfig *config = GetTestConfig(ctx->ssl);
GetTestState(ctx->ssl)->early_callback_called = true;
if (!config->expected_server_name.empty()) {
@@ -422,7 +422,7 @@
}
static int ClientCertCallback(SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey) {
- if (GetConfigPtr(ssl)->async && !GetTestState(ssl)->cert_ready) {
+ if (GetTestConfig(ssl)->async && !GetTestState(ssl)->cert_ready) {
return -1;
}
@@ -446,7 +446,7 @@
static int VerifySucceed(X509_STORE_CTX *store_ctx, void *arg) {
SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(store_ctx,
SSL_get_ex_data_X509_STORE_CTX_idx());
- const TestConfig *config = GetConfigPtr(ssl);
+ const TestConfig *config = GetTestConfig(ssl);
if (!config->expected_ocsp_response.empty()) {
const uint8_t *data;
@@ -468,7 +468,7 @@
static int NextProtosAdvertisedCallback(SSL *ssl, const uint8_t **out,
unsigned int *out_len, void *arg) {
- const TestConfig *config = GetConfigPtr(ssl);
+ const TestConfig *config = GetTestConfig(ssl);
if (config->advertise_npn.empty()) {
return SSL_TLSEXT_ERR_NOACK;
}
@@ -480,7 +480,7 @@
static int NextProtoSelectCallback(SSL* ssl, uint8_t** out, uint8_t* outlen,
const uint8_t* in, unsigned inlen, void* arg) {
- const TestConfig *config = GetConfigPtr(ssl);
+ const TestConfig *config = GetTestConfig(ssl);
if (config->select_next_proto.empty()) {
return SSL_TLSEXT_ERR_NOACK;
}
@@ -492,7 +492,7 @@
static int AlpnSelectCallback(SSL* ssl, const uint8_t** out, uint8_t* outlen,
const uint8_t* in, unsigned inlen, void* arg) {
- const TestConfig *config = GetConfigPtr(ssl);
+ const TestConfig *config = GetTestConfig(ssl);
if (config->decline_alpn) {
return SSL_TLSEXT_ERR_NOACK;
}
@@ -514,7 +514,7 @@
char *out_identity,
unsigned max_identity_len,
uint8_t *out_psk, unsigned max_psk_len) {
- const TestConfig *config = GetConfigPtr(ssl);
+ const TestConfig *config = GetTestConfig(ssl);
if (strcmp(hint ? hint : "", config->psk_identity.c_str()) != 0) {
fprintf(stderr, "Server PSK hint did not match.\n");
@@ -536,7 +536,7 @@
static unsigned PskServerCallback(SSL *ssl, const char *identity,
uint8_t *out_psk, unsigned max_psk_len) {
- const TestConfig *config = GetConfigPtr(ssl);
+ const TestConfig *config = GetTestConfig(ssl);
if (strcmp(identity, config->psk_identity.c_str()) != 0) {
fprintf(stderr, "Client PSK identity did not match.\n");
@@ -584,7 +584,7 @@
}
static int DDoSCallback(const struct ssl_early_callback_ctx *early_context) {
- const TestConfig *config = GetConfigPtr(early_context->ssl);
+ const TestConfig *config = GetTestConfig(early_context->ssl);
static int callback_num = 0;
callback_num++;
@@ -597,7 +597,7 @@
static void InfoCallback(const SSL *ssl, int type, int val) {
if (type == SSL_CB_HANDSHAKE_DONE) {
- if (GetConfigPtr(ssl)->handshake_never_done) {
+ if (GetTestConfig(ssl)->handshake_never_done) {
fprintf(stderr, "handshake completed\n");
// Abort before any expected error code is printed, to ensure the overall
// test fails.
@@ -633,7 +633,7 @@
}
if (!encrypt) {
- return GetConfigPtr(ssl)->renew_ticket ? 2 : 1;
+ return GetTestConfig(ssl)->renew_ticket ? 2 : 1;
}
return 1;
}
@@ -655,10 +655,10 @@
abort();
}
- if (GetConfigPtr(ssl)->custom_extension_skip) {
+ if (GetTestConfig(ssl)->custom_extension_skip) {
return 0;
}
- if (GetConfigPtr(ssl)->custom_extension_fail_add) {
+ if (GetTestConfig(ssl)->custom_extension_fail_add) {
return -1;
}
@@ -888,7 +888,7 @@
return false;
}
- const TestConfig *config = GetConfigPtr(ssl);
+ const TestConfig *config = GetTestConfig(ssl);
TestState *test_state = GetTestState(ssl);
if (test_state->clock_delta.tv_usec != 0 ||
test_state->clock_delta.tv_sec != 0) {
@@ -926,7 +926,7 @@
AsyncBioAllowWrite(test_state->async_bio, 1);
return true;
case SSL_ERROR_WANT_CHANNEL_ID_LOOKUP: {
- ScopedEVP_PKEY pkey = LoadPrivateKey(GetConfigPtr(ssl)->send_channel_id);
+ ScopedEVP_PKEY pkey = LoadPrivateKey(GetTestConfig(ssl)->send_channel_id);
if (!pkey) {
return false;
}
@@ -953,7 +953,7 @@
// DoRead reads from |ssl|, resolving any asynchronous operations. It returns
// the result value of the final |SSL_read| call.
static int DoRead(SSL *ssl, uint8_t *out, size_t max_out) {
- const TestConfig *config = GetConfigPtr(ssl);
+ const TestConfig *config = GetTestConfig(ssl);
TestState *test_state = GetTestState(ssl);
int ret;
do {
@@ -974,7 +974,7 @@
// WriteAll writes |in_len| bytes from |in| to |ssl|, resolving any asynchronous
// operations. It returns the result of the final |SSL_write| call.
static int WriteAll(SSL *ssl, const uint8_t *in, size_t in_len) {
- const TestConfig *config = GetConfigPtr(ssl);
+ const TestConfig *config = GetTestConfig(ssl);
int ret;
do {
ret = SSL_write(ssl, in, in_len);
@@ -989,7 +989,7 @@
// DoShutdown calls |SSL_shutdown|, resolving any asynchronous operations. It
// returns the result of the final |SSL_shutdown| call.
static int DoShutdown(SSL *ssl) {
- const TestConfig *config = GetConfigPtr(ssl);
+ const TestConfig *config = GetTestConfig(ssl);
int ret;
do {
ret = SSL_shutdown(ssl);
@@ -1001,7 +1001,7 @@
// initial handshake (or False Starts), whether all the properties are
// consistent with the test configuration and invariants.
static bool CheckHandshakeProperties(SSL *ssl, bool is_resume) {
- const TestConfig *config = GetConfigPtr(ssl);
+ const TestConfig *config = GetTestConfig(ssl);
if (SSL_get_current_cipher(ssl) == nullptr) {
fprintf(stderr, "null cipher after handshake\n");
@@ -1187,7 +1187,7 @@
return false;
}
- if (!SetConfigPtr(ssl.get(), config) ||
+ if (!SetTestConfig(ssl.get(), config) ||
!SetTestState(ssl.get(), std::unique_ptr<TestState>(new TestState))) {
return false;
}
@@ -1219,6 +1219,9 @@
if (config->partial_write) {
SSL_set_mode(ssl.get(), SSL_MODE_ENABLE_PARTIAL_WRITE);
}
+ if (config->no_tls13) {
+ SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1_3);
+ }
if (config->no_tls12) {
SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1_2);
}
@@ -1310,13 +1313,17 @@
}
if (config->enable_all_curves) {
static const int kAllCurves[] = {
- NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, NID_X25519,
+ NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, NID_X25519,
};
if (!SSL_set1_curves(ssl.get(), kAllCurves,
sizeof(kAllCurves) / sizeof(kAllCurves[0]))) {
return false;
}
}
+ if (config->initial_timeout_duration_ms > 0) {
+ DTLSv1_set_initial_timeout_duration(ssl.get(),
+ config->initial_timeout_duration_ms);
+ }
int sock = Connect(config->port);
if (sock == -1) {
diff --git a/src/ssl/test/runner/chacha20_poly1305.go b/src/ssl/test/runner/chacha20_poly1305.go
index 3c6ad82..8b97545 100644
--- a/src/ssl/test/runner/chacha20_poly1305.go
+++ b/src/ssl/test/runner/chacha20_poly1305.go
@@ -1,3 +1,17 @@
+// Copyright (c) 2016, Google Inc.
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
package runner
import (
diff --git a/src/ssl/test/runner/chacha20_poly1305_test.go b/src/ssl/test/runner/chacha20_poly1305_test.go
index 4d19b8c..8cecb5c 100644
--- a/src/ssl/test/runner/chacha20_poly1305_test.go
+++ b/src/ssl/test/runner/chacha20_poly1305_test.go
@@ -1,3 +1,17 @@
+// Copyright (c) 2016, Google Inc.
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
package runner
import (
diff --git a/src/ssl/test/runner/cipher_suites.go b/src/ssl/test/runner/cipher_suites.go
index bfd31a5..799f2d5 100644
--- a/src/ssl/test/runner/cipher_suites.go
+++ b/src/ssl/test/runner/cipher_suites.go
@@ -43,6 +43,9 @@
// client indicates that it supports ECC with a curve and point format
// that we're happy with.
suiteECDHE = 1 << iota
+ // suiteCECPQ1 indicates that the cipher suite uses the
+ // experimental, temporary, and non-standard CECPQ1 key agreement.
+ suiteCECPQ1
// suiteECDSA indicates that the cipher suite involves an ECDSA
// signature and therefore may only be selected when the server's
// certificate is ECDSA. If this is not set then the cipher suite is
@@ -104,6 +107,10 @@
{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, 32, 48, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, cipherAES, macSHA384, nil},
{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
+ {TLS_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 12, cecpq1RSAKA, suiteCECPQ1 | suiteTLS12, nil, nil, aeadCHACHA20POLY1305},
+ {TLS_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 12, cecpq1ECDSAKA, suiteCECPQ1 | suiteECDSA | suiteTLS12, nil, nil, aeadCHACHA20POLY1305},
+ {TLS_CECPQ1_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, cecpq1RSAKA, suiteCECPQ1 | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+ {TLS_CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, cecpq1ECDSAKA, suiteCECPQ1 | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, dheRSAKA, suiteTLS12, nil, nil, aeadAESGCM},
{TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, dheRSAKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
{TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, dheRSAKA, suiteTLS12, cipherAES, macSHA256, nil},
@@ -373,6 +380,15 @@
}
}
+func cecpq1ECDSAKA(version uint16) keyAgreement {
+ return &cecpq1KeyAgreement{
+ auth: &signedKeyAgreement{
+ sigType: signatureECDSA,
+ version: version,
+ },
+ }
+}
+
func ecdheRSAKA(version uint16) keyAgreement {
return &ecdheKeyAgreement{
auth: &signedKeyAgreement{
@@ -382,6 +398,15 @@
}
}
+func cecpq1RSAKA(version uint16) keyAgreement {
+ return &cecpq1KeyAgreement{
+ auth: &signedKeyAgreement{
+ sigType: signatureRSA,
+ version: version,
+ },
+ }
+}
+
func dheRSAKA(version uint16) keyAgreement {
return &dheKeyAgreement{
auth: &signedKeyAgreement{
@@ -472,4 +497,8 @@
const (
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256_OLD uint16 = 0xcc13
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256_OLD uint16 = 0xcc14
+ TLS_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0x16b7
+ TLS_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0x16b8
+ TLS_CECPQ1_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x16b9
+ TLS_CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0x16ba
)
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index 2e9ce04..57b7b29 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -787,6 +787,10 @@
// on connection shutdown.
NoCloseNotify bool
+ // SendAlertOnShutdown, if non-zero, is the alert to send instead of
+ // close_notify on shutdown.
+ SendAlertOnShutdown alert
+
// ExpectCloseNotify, if true, requires a close_notify from the peer on
// shutdown. Records from the peer received after close_notify is sent
// are not discard.
@@ -834,6 +838,10 @@
// NullAllCiphers, if true, causes every cipher to behave like the null
// cipher.
NullAllCiphers bool
+
+ // SendSCTListOnResume, if not nil, causes the server to send the
+ // supplied SCT list in resumption handshakes.
+ SendSCTListOnResume []byte
}
func (c *Config) serverInit() {
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index 43548e8..3913995 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -1292,7 +1292,16 @@
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
if c.handshakeComplete && !c.config.Bugs.NoCloseNotify {
- alertErr = c.sendAlert(alertCloseNotify)
+ alert := alertCloseNotify
+ if c.config.Bugs.SendAlertOnShutdown != 0 {
+ alert = c.config.Bugs.SendAlertOnShutdown
+ }
+ alertErr = c.sendAlert(alert)
+ // Clear local alerts when sending alerts so we continue to wait
+ // for the peer rather than closing the socket early.
+ if opErr, ok := alertErr.(*net.OpError); ok && opErr.Op == "local error" {
+ alertErr = nil
+ }
}
// Consume a close_notify from the peer if one hasn't been received
diff --git a/src/ssl/test/runner/dtls.go b/src/ssl/test/runner/dtls.go
index c3ee521..a31dfc0 100644
--- a/src/ssl/test/runner/dtls.go
+++ b/src/ssl/test/runner/dtls.go
@@ -46,6 +46,7 @@
b := c.rawInput
// Read a new packet only if the current one is empty.
+ var newPacket bool
if len(b.data) == 0 {
// Pick some absurdly large buffer size.
b.resize(maxCiphertext + recordHeaderLen)
@@ -57,6 +58,7 @@
return 0, nil, fmt.Errorf("dtls: exceeded maximum packet length")
}
c.rawInput.resize(n)
+ newPacket = true
}
// Read out one record.
@@ -108,6 +110,13 @@
c.in.setErrorLocked(c.sendAlert(err))
}
b.off = off
+
+ // Require that ChangeCipherSpec always share a packet with either the
+ // previous or next handshake message.
+ if newPacket && typ == recordTypeChangeCipherSpec && c.rawInput == nil {
+ return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: ChangeCipherSpec not packed together with Finished"))
+ }
+
return typ, b, nil
}
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index d2cac98..72d1eb9 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -488,6 +488,10 @@
hs.hello.sessionId = hs.clientHello.sessionId
hs.hello.ticketSupported = c.config.Bugs.RenewTicketOnResume
+ if c.config.Bugs.SendSCTListOnResume != nil {
+ hs.hello.sctList = c.config.Bugs.SendSCTListOnResume
+ }
+
hs.finishedHash = newFinishedHash(c.vers, hs.suite)
hs.finishedHash.discardHandshakeBuffer()
hs.writeClientHash(hs.clientHello.marshal())
diff --git a/src/ssl/test/runner/key_agreement.go b/src/ssl/test/runner/key_agreement.go
index 54aa3d3..9a9962b 100644
--- a/src/ssl/test/runner/key_agreement.go
+++ b/src/ssl/test/runner/key_agreement.go
@@ -21,6 +21,7 @@
"math/big"
"./curve25519"
+ "./newhope"
)
var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
@@ -252,13 +253,16 @@
// A ecdhCurve is an instance of ECDH-style key agreement for TLS.
type ecdhCurve interface {
- // generateKeypair generates a keypair using rand. It returns the
- // encoded public key.
- generateKeypair(rand io.Reader) (publicKey []byte, err error)
+ // offer generates a keypair using rand. It returns the encoded |publicKey|.
+ offer(rand io.Reader) (publicKey []byte, err error)
- // computeSecret performs a key exchange against peerKey and returns
- // the resulting shared secret.
- computeSecret(peerKey []byte) (preMasterSecret []byte, err error)
+ // accept responds to the |peerKey| generated by |offer| with the acceptor's
+ // |publicKey|, and returns agreed-upon |preMasterSecret| to the acceptor.
+ accept(rand io.Reader, peerKey []byte) (publicKey []byte, preMasterSecret []byte, err error)
+
+ // finish returns the computed |preMasterSecret|, given the |peerKey|
+ // generated by |accept|.
+ finish(peerKey []byte) (preMasterSecret []byte, err error)
}
// ellipticECDHCurve implements ecdhCurve with an elliptic.Curve.
@@ -267,7 +271,7 @@
privateKey []byte
}
-func (e *ellipticECDHCurve) generateKeypair(rand io.Reader) (publicKey []byte, err error) {
+func (e *ellipticECDHCurve) offer(rand io.Reader) (publicKey []byte, err error) {
var x, y *big.Int
e.privateKey, x, y, err = elliptic.GenerateKey(e.curve, rand)
if err != nil {
@@ -276,7 +280,19 @@
return elliptic.Marshal(e.curve, x, y), nil
}
-func (e *ellipticECDHCurve) computeSecret(peerKey []byte) (preMasterSecret []byte, err error) {
+func (e *ellipticECDHCurve) accept(rand io.Reader, peerKey []byte) (publicKey []byte, preMasterSecret []byte, err error) {
+ publicKey, err = e.offer(rand)
+ if err != nil {
+ return nil, nil, err
+ }
+ preMasterSecret, err = e.finish(peerKey)
+ if err != nil {
+ return nil, nil, err
+ }
+ return
+}
+
+func (e *ellipticECDHCurve) finish(peerKey []byte) (preMasterSecret []byte, err error) {
x, y := elliptic.Unmarshal(e.curve, peerKey)
if x == nil {
return nil, errors.New("tls: invalid peer key")
@@ -294,7 +310,7 @@
privateKey [32]byte
}
-func (e *x25519ECDHCurve) generateKeypair(rand io.Reader) (publicKey []byte, err error) {
+func (e *x25519ECDHCurve) offer(rand io.Reader) (publicKey []byte, err error) {
_, err = io.ReadFull(rand, e.privateKey[:])
if err != nil {
return
@@ -304,7 +320,19 @@
return out[:], nil
}
-func (e *x25519ECDHCurve) computeSecret(peerKey []byte) (preMasterSecret []byte, err error) {
+func (e *x25519ECDHCurve) accept(rand io.Reader, peerKey []byte) (publicKey []byte, preMasterSecret []byte, err error) {
+ publicKey, err = e.offer(rand)
+ if err != nil {
+ return nil, nil, err
+ }
+ preMasterSecret, err = e.finish(peerKey)
+ if err != nil {
+ return nil, nil, err
+ }
+ return
+}
+
+func (e *x25519ECDHCurve) finish(peerKey []byte) (preMasterSecret []byte, err error) {
if len(peerKey) != 32 {
return nil, errors.New("tls: invalid peer key")
}
@@ -321,6 +349,66 @@
return out[:], nil
}
+// cecpq1Curve is combined elliptic curve (X25519) and post-quantum (new hope) key
+// agreement.
+type cecpq1Curve struct {
+ x25519 *x25519ECDHCurve
+ newhope *newhope.Poly
+}
+
+func (e *cecpq1Curve) offer(rand io.Reader) (publicKey []byte, err error) {
+ var x25519OfferMsg, newhopeOfferMsg []byte
+
+ e.x25519 = new(x25519ECDHCurve)
+ if x25519OfferMsg, err = e.x25519.offer(rand); err != nil {
+ return nil, err
+ }
+
+ newhopeOfferMsg, e.newhope = newhope.Offer(rand)
+
+ return append(x25519OfferMsg, newhopeOfferMsg[:]...), nil
+}
+
+func (e *cecpq1Curve) accept(rand io.Reader, peerKey []byte) (publicKey []byte, preMasterSecret []byte, err error) {
+ if len(peerKey) != 32+newhope.OfferMsgLen {
+ return nil, nil, errors.New("cecpq1: invalid offer message")
+ }
+
+ var x25519AcceptMsg, newhopeAcceptMsg []byte
+ var x25519Secret []byte
+ var newhopeSecret newhope.Key
+
+ x25519 := new(x25519ECDHCurve)
+ if x25519AcceptMsg, x25519Secret, err = x25519.accept(rand, peerKey[:32]); err != nil {
+ return nil, nil, err
+ }
+
+ if newhopeSecret, newhopeAcceptMsg, err = newhope.Accept(rand, peerKey[32:]); err != nil {
+ return nil, nil, err
+ }
+
+ return append(x25519AcceptMsg, newhopeAcceptMsg[:]...), append(x25519Secret, newhopeSecret[:]...), nil
+}
+
+func (e *cecpq1Curve) finish(peerKey []byte) (preMasterSecret []byte, err error) {
+ if len(peerKey) != 32+newhope.AcceptMsgLen {
+ return nil, errors.New("cecpq1: invalid accept message")
+ }
+
+ var x25519Secret []byte
+ var newhopeSecret newhope.Key
+
+ if x25519Secret, err = e.x25519.finish(peerKey[:32]); err != nil {
+ return nil, err
+ }
+
+ if newhopeSecret, err = e.newhope.Finish(peerKey[32:]); err != nil {
+ return nil, err
+ }
+
+ return append(x25519Secret, newhopeSecret[:]...), nil
+}
+
func curveForCurveID(id CurveID) (ecdhCurve, bool) {
switch id {
case CurveP224:
@@ -551,7 +639,7 @@
return nil, errors.New("tls: preferredCurves includes unsupported curve")
}
- publicKey, err := ka.curve.generateKeypair(config.rand())
+ publicKey, err := ka.curve.offer(config.rand())
if err != nil {
return nil, err
}
@@ -577,7 +665,7 @@
if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
return nil, errClientKeyExchange
}
- return ka.curve.computeSecret(ckx.ciphertext[1:])
+ return ka.curve.finish(ckx.ciphertext[1:])
}
func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
@@ -612,11 +700,7 @@
return nil, nil, errors.New("missing ServerKeyExchange message")
}
- publicKey, err := ka.curve.generateKeypair(config.rand())
- if err != nil {
- return nil, nil, err
- }
- preMasterSecret, err := ka.curve.computeSecret(ka.peerKey)
+ publicKey, preMasterSecret, err := ka.curve.accept(config.rand(), ka.peerKey)
if err != nil {
return nil, nil, err
}
@@ -632,6 +716,77 @@
return preMasterSecret, ckx, nil
}
+// cecpq1RSAKeyAgreement is like an ecdheKeyAgreement, but using the cecpq1Curve
+// pseudo-curve, and without any parameters (e.g. curve name) other than the
+// keys being exchanged. The signature may either be ECDSA or RSA.
+type cecpq1KeyAgreement struct {
+ auth keyAgreementAuthentication
+ curve ecdhCurve
+ peerKey []byte
+}
+
+func (ka *cecpq1KeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+ ka.curve = &cecpq1Curve{}
+ publicKey, err := ka.curve.offer(config.rand())
+ if err != nil {
+ return nil, err
+ }
+
+ var params []byte
+ params = append(params, byte(len(publicKey)>>8))
+ params = append(params, byte(len(publicKey)&0xff))
+ params = append(params, publicKey[:]...)
+
+ return ka.auth.signParameters(config, cert, clientHello, hello, params)
+}
+
+func (ka *cecpq1KeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+ if len(ckx.ciphertext) < 2 {
+ return nil, errClientKeyExchange
+ }
+ peerKeyLen := int(ckx.ciphertext[0])<<8 + int(ckx.ciphertext[1])
+ peerKey := ckx.ciphertext[2:]
+ if peerKeyLen != len(peerKey) {
+ return nil, errClientKeyExchange
+ }
+ return ka.curve.finish(peerKey)
+}
+
+func (ka *cecpq1KeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+ if len(skx.key) < 2 {
+ return errServerKeyExchange
+ }
+ peerKeyLen := int(skx.key[0])<<8 + int(skx.key[1])
+ // Save the peer key for later.
+ if len(skx.key) < 2+peerKeyLen {
+ return errServerKeyExchange
+ }
+ ka.peerKey = skx.key[2 : 2+peerKeyLen]
+ if peerKeyLen != len(ka.peerKey) {
+ return errServerKeyExchange
+ }
+
+ // Check the signature.
+ params := skx.key[:2+peerKeyLen]
+ sig := skx.key[2+peerKeyLen:]
+ return ka.auth.verifyParameters(config, clientHello, serverHello, cert, params, sig)
+}
+
+func (ka *cecpq1KeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+ curve := &cecpq1Curve{}
+ publicKey, preMasterSecret, err := curve.accept(config.rand(), ka.peerKey)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ ckx := new(clientKeyExchangeMsg)
+ ckx.ciphertext = append(ckx.ciphertext, byte(len(publicKey)>>8))
+ ckx.ciphertext = append(ckx.ciphertext, byte(len(publicKey)&0xff))
+ ckx.ciphertext = append(ckx.ciphertext, publicKey[:]...)
+
+ return preMasterSecret, ckx, nil
+}
+
// dheRSAKeyAgreement implements a TLS key agreement where the server generates
// an ephemeral Diffie-Hellman public/private key pair and signs it. The
// pre-master secret is then calculated using Diffie-Hellman.
diff --git a/src/ssl/test/runner/newhope/newhope.go b/src/ssl/test/runner/newhope/newhope.go
new file mode 100644
index 0000000..36c2c85
--- /dev/null
+++ b/src/ssl/test/runner/newhope/newhope.go
@@ -0,0 +1,319 @@
+// Copyright (c) 2016, Google Inc.
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+// package newhope contains a post-quantum key agreement algorithm,
+// reimplemented from the reference implementation at
+// https://github.com/tpoeppelmann/newhope.
+//
+// Note that this package does not interoperate with the reference
+// implementation.
+package newhope
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "errors"
+ "io"
+)
+
+const (
+ // q is the prime that defines the field.
+ q = 12289
+ // n is the number of coefficients in polynomials.
+ n = 1024
+ // k is the width of the noise distribution.
+ k = 16
+
+ // These values are used in the NTT calculation. See the paper for
+ // details about their origins.
+ omega = 49
+ invOmega = 1254
+ sqrtOmega = 7
+ invSqrtOmega = 8778
+ invN = 12277
+
+ // encodedPolyLen is the length, in bytes, of an encoded polynomial. The
+ // encoding uses 14 bits per coefficient.
+ encodedPolyLen = (n * 14) / 8
+
+ // offerMsgLen is the length, in bytes, of the offering (first) message of
+ // the key exchange.
+ OfferMsgLen = encodedPolyLen + 32
+
+ // acceptMsgLen is the length, in bytes, of the accepting (second) message
+ // of the key exchange.
+ AcceptMsgLen = encodedPolyLen + 256
+)
+
+// count16Bits returns the number of '1' bits in v.
+func count16Bits(v uint16) (sum uint16) {
+ for i := 0; i < 16; i++ {
+ sum += v & 1
+ v >>= 1
+ }
+
+ return sum
+}
+
+// Poly is a polynomial of n coefficients.
+type Poly [n]uint16
+
+// Key is the result of a key agreement.
+type Key [32]uint8
+
+// sampleNoise returns a random polynomial where the coefficients are
+// drawn from the noise distribution.
+func sampleNoise(rand io.Reader) *Poly {
+ poly := new(Poly)
+ buf := make([]byte, 4)
+
+ for i := range poly {
+ if _, err := io.ReadFull(rand, buf); err != nil {
+ panic(err)
+ }
+ a := count16Bits(uint16(buf[0])<<8 | uint16(buf[1]))
+ b := count16Bits(uint16(buf[2])<<8 | uint16(buf[3]))
+ poly[i] = (q + a - b) % q
+ }
+
+ return poly
+}
+
+// randomPolynomial returns a random polynomial where the coefficients are
+// drawn uniformly at random from the underlying field.
+func randomPolynomial(rand io.Reader) *Poly {
+ poly := new(Poly)
+
+ buf := make([]byte, 2)
+ for i := range poly {
+ for {
+ if _, err := io.ReadFull(rand, buf); err != nil {
+ panic(err)
+ }
+
+ v := uint16(buf[1])<<8 | uint16(buf[0])
+ v &= 0x3fff
+
+ if v < q {
+ poly[i] = v
+ break
+ }
+ }
+ }
+
+ return poly
+}
+
+type zeroReader struct {
+ io.Reader
+}
+
+func (z *zeroReader) Read(dst []byte) (n int, err error) {
+ for i := range dst {
+ dst[i] = 0
+ }
+ return len(dst), nil
+}
+
+// seedToPolynomial uses AES-CTR to generate a pseudo-random polynomial given a
+// 32-byte seed.
+func seedToPolynomial(seed []byte) *Poly {
+ aes, err := aes.NewCipher(seed[0:16])
+ if err != nil {
+ panic(err)
+ }
+ stream := cipher.NewCTR(aes, seed[16:32])
+ reader := &cipher.StreamReader{S: stream, R: &zeroReader{}}
+ return randomPolynomial(reader)
+}
+
+// forwardNTT converts |in| into the frequency domain.
+func forwardNTT(in *Poly) *Poly {
+ return ntt(in, omega, sqrtOmega, 1, 1)
+}
+
+// inverseNTT converts |in| into the time domain.
+func inverseNTT(in *Poly) *Poly {
+ return ntt(in, invOmega, 1, invSqrtOmega, invN)
+}
+
+// ntt performs the number-theoretic transform (a discrete Fourier transform in
+// a field) on in. Significant magic is in effect here. See the paper for the
+// details of how this works.
+func ntt(in *Poly, omega, preScaleBase, postScaleBase, postScale uint16) *Poly {
+ out := new(Poly)
+ omega_to_the_i := 1
+
+ for i := range out {
+ omegaToTheIJ := 1
+ preScale := int(1)
+ sum := 0
+
+ for j := range in {
+ t := (int(in[j]) * preScale) % q
+ sum += (t * omegaToTheIJ) % q
+ omegaToTheIJ = (omegaToTheIJ * omega_to_the_i) % q
+ preScale = (int(preScaleBase) * preScale) % q
+ }
+
+ out[i] = uint16((sum * int(postScale)) % q)
+
+ omega_to_the_i = (omega_to_the_i * int(omega)) % q
+ postScale = uint16((int(postScale) * int(postScaleBase)) % q)
+ }
+
+ return out
+}
+
+// encodeRec encodes the reconciliation data compactly, for use in the accept
+// message.
+func encodeRec(rec *reconciliationData) []byte {
+ var ret [n / 4]byte
+
+ for i := 0; i < n/4; i++ {
+ ret[i] = rec[4*i] | rec[4*i+1]<<2 | rec[4*i+2]<<4 | rec[4*i+3]<<6
+ }
+
+ return ret[:]
+}
+
+// decodeRec decodes reconciliation data from the accept message.
+func decodeRec(message []byte) (rec *reconciliationData) {
+ rec = new(reconciliationData)
+
+ for i, b := range message {
+ rec[4*i] = b & 0x03
+ rec[4*i+1] = (b >> 2) & 0x3
+ rec[4*i+2] = (b >> 4) & 0x3
+ rec[4*i+3] = b >> 6
+ }
+
+ return rec
+}
+
+// encodePoly returns a byte array that encodes a polynomial compactly, with 14
+// bits per coefficient.
+func encodePoly(poly *Poly) []byte {
+ ret := make([]byte, encodedPolyLen)
+
+ for i := 0; i < n/4; i++ {
+ t0 := poly[4*i]
+ t1 := poly[4*i+1]
+ t2 := poly[4*i+2]
+ t3 := poly[4*i+3]
+
+ ret[7*i] = byte(t0)
+ ret[7*i+1] = byte(t0>>8) | byte(t1<<6)
+ ret[7*i+2] = byte(t1 >> 2)
+ ret[7*i+3] = byte(t1>>10) | byte(t2<<4)
+ ret[7*i+4] = byte(t2 >> 4)
+ ret[7*i+5] = byte(t2>>12) | byte(t3<<2)
+ ret[7*i+6] = byte(t3 >> 6)
+ }
+
+ return ret
+}
+
+// decodePoly inverts encodePoly.
+func decodePoly(encoded []byte) *Poly {
+ ret := new(Poly)
+
+ for i := 0; i < n/4; i++ {
+ ret[4*i] = uint16(encoded[7*i]) | uint16(encoded[7*i+1]&0x3f)<<8
+ ret[4*i+1] = uint16(encoded[7*i+1])>>6 | uint16(encoded[7*i+2])<<2 | uint16(encoded[7*i+3]&0x0f)<<10
+ ret[4*i+2] = uint16(encoded[7*i+3])>>4 | uint16(encoded[7*i+4])<<4 | uint16(encoded[7*i+5]&0x03)<<12
+ ret[4*i+3] = uint16(encoded[7*i+5])>>2 | uint16(encoded[7*i+6])<<6
+ }
+
+ return ret
+}
+
+// Offer starts a new key exchange. It returns a message that should be
+// transmitted to the peer, and a polynomial that must be retained in order to
+// complete the exchange.
+func Offer(rand io.Reader) (offerMsg []byte, sFreq *Poly) {
+ seed := make([]byte, 32)
+
+ if _, err := io.ReadFull(rand, seed); err != nil {
+ panic(err)
+ }
+
+ aFreq := seedToPolynomial(seed)
+ sFreq = forwardNTT(sampleNoise(rand))
+ eFreq := forwardNTT(sampleNoise(rand))
+
+ bFreq := new(Poly)
+ for i := range bFreq {
+ bFreq[i] = uint16((int(sFreq[i])*int(aFreq[i]) + int(eFreq[i])) % q)
+ }
+
+ offerMsg = encodePoly(bFreq)
+ offerMsg = append(offerMsg, seed[:]...)
+ return offerMsg, sFreq
+}
+
+// Accept processes a message generated by |Offer| and returns a reply message
+// and the shared key.
+func Accept(rand io.Reader, offerMsg []byte) (sharedKey Key, acceptMsg []byte, err error) {
+ if len(offerMsg) != OfferMsgLen {
+ return sharedKey, nil, errors.New("newhope: offer message has incorrect length")
+ }
+
+ bFreq := decodePoly(offerMsg)
+ seed := offerMsg[encodedPolyLen:]
+
+ aFreq := seedToPolynomial(seed)
+ sPrimeFreq := forwardNTT(sampleNoise(rand))
+ ePrimeFreq := forwardNTT(sampleNoise(rand))
+
+ uFreq := new(Poly)
+ for i := range uFreq {
+ uFreq[i] = uint16((int(sPrimeFreq[i])*int(aFreq[i]) + int(ePrimeFreq[i])) % q)
+ }
+
+ vFreq := new(Poly)
+ for i := range vFreq {
+ vFreq[i] = uint16((int(sPrimeFreq[i]) * int(bFreq[i])) % q)
+ }
+
+ v := inverseNTT(vFreq)
+ ePrimePrime := sampleNoise(rand)
+ for i := range v {
+ v[i] = uint16((int(v[i]) + int(ePrimePrime[i])) % q)
+ }
+
+ rec := helprec(rand, v)
+
+ sharedKey = reconcile(v, rec)
+ acceptMsg = encodePoly(uFreq)
+ acceptMsg = append(acceptMsg, encodeRec(rec)[:]...)
+ return sharedKey, acceptMsg, nil
+}
+
+// Finish processes the reply from the peer and returns the shared key.
+func (sk *Poly) Finish(acceptMsg []byte) (sharedKey Key, err error) {
+ if len(acceptMsg) != AcceptMsgLen {
+ return sharedKey, errors.New("newhope: accept message has incorrect length")
+ }
+
+ uFreq := decodePoly(acceptMsg[:encodedPolyLen])
+ rec := decodeRec(acceptMsg[encodedPolyLen:])
+
+ for i, u := range uFreq {
+ uFreq[i] = uint16((int(u) * int(sk[i])) % q)
+ }
+ u := inverseNTT(uFreq)
+
+ return reconcile(u, rec), nil
+}
diff --git a/src/ssl/test/runner/newhope/newhope_test.go b/src/ssl/test/runner/newhope/newhope_test.go
new file mode 100644
index 0000000..31e95c7
--- /dev/null
+++ b/src/ssl/test/runner/newhope/newhope_test.go
@@ -0,0 +1,154 @@
+// Copyright (c) 2016, Google Inc.
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+package newhope
+
+import (
+ "bytes"
+ "crypto/rand"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "testing"
+)
+
+func TestNTTRoundTrip(t *testing.T) {
+ var a Poly
+ for i := range a {
+ a[i] = uint16(i)
+ }
+
+ frequency := forwardNTT(&a)
+ original := inverseNTT(frequency)
+
+ for i, v := range a {
+ if v != original[i] {
+ t.Errorf("NTT didn't invert correctly: original[%d] = %d", i, original[i])
+ break
+ }
+ }
+}
+
+func TestNTTInv(t *testing.T) {
+ var a Poly
+ for i := range a {
+ a[i] = uint16(i)
+ }
+
+ result := ntt(&a, invOmega, 1, invSqrtOmega, invN)
+ if result[0] != 6656 || result[1] != 1792 || result[2] != 1234 {
+ t.Errorf("NTT^-1 gave bad result: %v", result[:8])
+ }
+}
+
+func disabledTestNoise(t *testing.T) {
+ var buckets [1 + 2*k]int
+ numSamples := 100
+
+ for i := 0; i < numSamples; i++ {
+ noise := sampleNoise(rand.Reader)
+ for _, v := range noise {
+ value := (int(v) + k) % q
+ buckets[value]++
+ }
+ }
+
+ sum := 0
+ squareSum := 0
+
+ for i, count := range buckets {
+ sum += (i - k) * count
+ squareSum += (i - k) * (i - k) * count
+ }
+
+ mean := float64(sum) / float64(n*numSamples)
+ if mean < -0.5 || 0.5 < mean {
+ t.Errorf("mean out of range: %f", mean)
+ }
+
+ expectedVariance := 0.5 * 0.5 * float64(k*2) // I think?
+ variance := float64(squareSum)/float64(n*numSamples) - mean*mean
+
+ if variance < expectedVariance-1.0 || expectedVariance+1.0 < variance {
+ t.Errorf("variance out of range: got %f, want %f", variance, expectedVariance)
+ }
+
+ file, err := ioutil.TempFile("", "noise")
+ fmt.Printf("writing noise to %s\n", file.Name())
+ if err != nil {
+ t.Fatal(err)
+ }
+ for i, count := range buckets {
+ dots := ""
+ for i := 0; i < count/(3*numSamples); i++ {
+ dots += "++"
+ }
+ fmt.Fprintf(file, "%+d\t%d\t%s\n", i-k, count, dots)
+ }
+ file.Close()
+}
+
+func TestSeedToPolynomial(t *testing.T) {
+ seed := make([]byte, 32)
+ seed[0] = 1
+ seed[31] = 2
+
+ poly := seedToPolynomial(seed)
+ if poly[0] != 3313 || poly[1] != 9277 || poly[2] != 11020 {
+ t.Errorf("bad result: %v", poly[:3])
+ }
+}
+
+func TestEncodeDecodePoly(t *testing.T) {
+ poly := randomPolynomial(rand.Reader)
+ poly2 := decodePoly(encodePoly(poly))
+ if *poly != *poly2 {
+ t.Errorf("decodePoly(encodePoly) isn't the identity function")
+ }
+}
+
+func TestEncodeDecodeRec(t *testing.T) {
+ var r reconciliationData
+ if _, err := io.ReadFull(rand.Reader, r[:]); err != nil {
+ panic(err)
+ }
+ for i := range r {
+ r[i] &= 3
+ }
+
+ encoded := encodeRec(&r)
+ decoded := decodeRec(encoded)
+
+ if *decoded != r {
+ t.Errorf("bad decode of rec")
+ }
+}
+
+func TestExchange(t *testing.T) {
+ for count := 0; count < 64; count++ {
+ offerMsg, state := Offer(rand.Reader)
+ sharedKey1, acceptMsg, err := Accept(rand.Reader, offerMsg)
+ if err != nil {
+ t.Errorf("Accept: %v", err)
+ }
+ sharedKey2, err := state.Finish(acceptMsg)
+ if err != nil {
+ t.Fatal("Finish: %v", err)
+ }
+
+ if !bytes.Equal(sharedKey1[:], sharedKey2[:]) {
+ t.Fatalf("keys mismatched on iteration %d: %x vs %x", count, sharedKey1, sharedKey2)
+ }
+ }
+}
diff --git a/src/ssl/test/runner/newhope/reconciliation.go b/src/ssl/test/runner/newhope/reconciliation.go
new file mode 100644
index 0000000..07479fe
--- /dev/null
+++ b/src/ssl/test/runner/newhope/reconciliation.go
@@ -0,0 +1,132 @@
+// Copyright (c) 2016, Google Inc.
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+package newhope
+
+// This file contains the reconciliation algorithm for NewHope. This is simply a
+// monkey-see-monkey-do version of the reference code, with the exception that
+// the key resulting from reconciliation is whitened with SHA2 rather than SHA3.
+//
+// Thanks to the authors of the reference code for allowing us to release this
+// under the BoringSSL license.
+
+import (
+ "crypto/sha256"
+ "io"
+)
+
+func abs(v int32) int32 {
+ mask := v >> 31
+ return (v ^ mask) - mask
+}
+
+func f(x int32) (v0, v1, k int32) {
+ // Next 6 lines compute t = x/q;
+ b := x * 2730
+ t := b >> 25
+ b = x - t*12289
+ b = 12288 - b
+ b >>= 31
+ t -= b
+
+ r := t & 1
+ xit := (t >> 1)
+ v0 = xit + r // v0 = round(x/(2*q))
+
+ t -= 1
+ r = t & 1
+ v1 = (t >> 1) + r
+
+ k = abs(x - (v0 * 2 * q))
+ return
+}
+
+// reconciliationData is the data needed for reconciliation. There are 2 bits
+// per coefficient; this is the unpacked form.
+type reconciliationData [n]uint8
+
+func helprec(rand io.Reader, v *Poly) *reconciliationData {
+ var randBits [n / (4 * 8)]byte
+ if _, err := io.ReadFull(rand, randBits[:]); err != nil {
+ panic(err)
+ }
+
+ ret := new(reconciliationData)
+
+ for i := uint(0); i < n/4; i++ {
+ rbit := int32((randBits[i>>3] >> (i & 7)) & 1)
+
+ a0, b0, k0 := f(8*int32(v[i]) + 4*rbit)
+ a1, b1, k1 := f(8*int32(v[256+i]) + 4*rbit)
+ a2, b2, k2 := f(8*int32(v[512+i]) + 4*rbit)
+ a3, b3, k3 := f(8*int32(v[768+i]) + 4*rbit)
+
+ k := (2*q - 1 - (k0 + k1 + k2 + k3)) >> 31
+
+ v0 := ((^k) & a0) ^ (k & b0)
+ v1 := ((^k) & a1) ^ (k & b1)
+ v2 := ((^k) & a2) ^ (k & b2)
+ v3 := ((^k) & a3) ^ (k & b3)
+
+ ret[i] = uint8((v0 - v3) & 3)
+ ret[i+256] = uint8((v1 - v3) & 3)
+ ret[i+512] = uint8((v2 - v3) & 3)
+ ret[i+768] = uint8((-k + 2*v3) & 3)
+ }
+
+ return ret
+}
+
+func g(x int32) int32 {
+ // Next 6 lines compute t = x/(4*q);
+ b := x * 2730
+ t := b >> 27
+ b = x - t*49156
+ b = 49155 - b
+ b >>= 31
+ t -= b
+
+ c := t & 1
+ t = (t >> 1) + c // t = round(x/(8*q))
+
+ t *= 8 * q
+
+ return abs(t - x)
+}
+
+func ldDecode(xi0, xi1, xi2, xi3 int32) uint8 {
+ t := g(xi0)
+ t += g(xi1)
+ t += g(xi2)
+ t += g(xi3)
+
+ t -= 8 * q
+ t >>= 31
+ return uint8(t & 1)
+}
+
+func reconcile(v *Poly, reconciliation *reconciliationData) Key {
+ key := new(Key)
+
+ for i := uint(0); i < n/4; i++ {
+ t0 := 16*q + 8*int32(v[i]) - q*(2*int32(reconciliation[i])+int32(reconciliation[i+768]))
+ t1 := 16*q + 8*int32(v[i+256]) - q*(2*int32(reconciliation[256+i])+int32(reconciliation[i+768]))
+ t2 := 16*q + 8*int32(v[i+512]) - q*(2*int32(reconciliation[512+i])+int32(reconciliation[i+768]))
+ t3 := 16*q + 8*int32(v[i+768]) - q*int32(reconciliation[i+768])
+
+ key[i>>3] |= ldDecode(t0, t1, t2, t3) << (i & 7)
+ }
+
+ return sha256.Sum256(key[:])
+}
diff --git a/src/ssl/test/runner/recordingconn.go b/src/ssl/test/runner/recordingconn.go
index 752610e..dfc10c7 100644
--- a/src/ssl/test/runner/recordingconn.go
+++ b/src/ssl/test/runner/recordingconn.go
@@ -1,3 +1,17 @@
+// Copyright (c) 2016, Google Inc.
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
package runner
import (
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index 5b746c6..c10987e 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -1,3 +1,17 @@
+// Copyright (c) 2016, Google Inc.
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
package runner
import (
@@ -901,6 +915,10 @@
{"ECDHE-RSA-CHACHA20-POLY1305", TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
{"ECDHE-RSA-CHACHA20-POLY1305-OLD", TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256_OLD},
{"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+ {"CECPQ1-RSA-CHACHA20-POLY1305-SHA256", TLS_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256},
+ {"CECPQ1-ECDSA-CHACHA20-POLY1305-SHA256", TLS_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256},
+ {"CECPQ1-RSA-AES256-GCM-SHA384", TLS_CECPQ1_RSA_WITH_AES_256_GCM_SHA384},
+ {"CECPQ1-ECDSA-AES256-GCM-SHA384", TLS_CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384},
{"PSK-AES128-CBC-SHA", TLS_PSK_WITH_AES_128_CBC_SHA},
{"PSK-AES256-CBC-SHA", TLS_PSK_WITH_AES_256_CBC_SHA},
{"ECDHE-PSK-AES128-CBC-SHA", TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA},
@@ -1391,7 +1409,7 @@
},
{
name: "DisableEverything",
- flags: []string{"-no-tls12", "-no-tls11", "-no-tls1", "-no-ssl3"},
+ flags: []string{"-no-tls13", "-no-tls12", "-no-tls11", "-no-tls1", "-no-ssl3"},
shouldFail: true,
expectedError: ":WRONG_SSL_VERSION:",
},
@@ -2061,6 +2079,19 @@
shimShutsDown: true,
},
{
+ name: "Unclean-Shutdown-Alert",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendAlertOnShutdown: alertDecompressionFailure,
+ ExpectCloseNotify: true,
+ },
+ },
+ shimShutsDown: true,
+ flags: []string{"-check-close-notify"},
+ shouldFail: true,
+ expectedError: ":SSLV3_ALERT_DECOMPRESSION_FAILURE:",
+ },
+ {
name: "LargePlaintext",
config: Config{
Bugs: ProtocolBugs{
@@ -2268,6 +2299,10 @@
// NULL ciphers must be explicitly enabled.
flags = append(flags, "-cipher", "DEFAULT:NULL-SHA")
}
+ if hasComponent(suite.name, "CECPQ1") {
+ // CECPQ1 ciphers must be explicitly enabled.
+ flags = append(flags, "-cipher", "DEFAULT:kCECPQ1")
+ }
for _, ver := range tlsVersions {
if ver.version < VersionTLS12 && isTLS12Only(suite.name) {
@@ -2714,6 +2749,40 @@
shouldFail: true,
expectedError: ":UNEXPECTED_MESSAGE:",
})
+
+ // Client auth is only legal in certificate-based ciphers.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ClientAuth-PSK",
+ config: Config{
+ CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
+ PreSharedKey: []byte("secret"),
+ ClientAuth: RequireAnyClientCert,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-psk", "secret",
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ClientAuth-ECDHE_PSK",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA},
+ PreSharedKey: []byte("secret"),
+ ClientAuth: RequireAnyClientCert,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-psk", "secret",
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ })
}
func addExtendedMasterSecretTests() {
@@ -3879,6 +3948,20 @@
resumeSession: true,
})
testCases = append(testCases, testCase{
+ name: "SendSCTListOnResume",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSCTListOnResume: []byte("bogus"),
+ },
+ },
+ flags: []string{
+ "-enable-signed-cert-timestamps",
+ "-expect-signed-cert-timestamps",
+ base64.StdEncoding.EncodeToString(testSCTList),
+ },
+ resumeSession: true,
+ })
+ testCases = append(testCases, testCase{
name: "SignedCertificateTimestampList-Server",
testType: serverTest,
flags: []string{
@@ -4583,6 +4666,24 @@
60 * time.Second,
}
+// shortTimeouts is an alternate set of timeouts which would occur if the
+// initial timeout duration was set to 250ms.
+var shortTimeouts = []time.Duration{
+ 250 * time.Millisecond,
+ 500 * time.Millisecond,
+ 1 * time.Second,
+ 2 * time.Second,
+ 4 * time.Second,
+ 8 * time.Second,
+ 16 * time.Second,
+ 32 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+}
+
func addDTLSRetransmitTests() {
// Test that this is indeed the timeout schedule. Stress all
// four patterns of handshake.
@@ -4659,6 +4760,31 @@
},
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{
+ 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{
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: shortTimeouts[:len(shortTimeouts)-1],
+ },
+ },
+ resumeSession: true,
+ flags: []string{"-async", "-initial-timeout-duration-ms", "250"},
+ })
}
func addExportKeyingMaterialTests() {
diff --git a/src/ssl/test/runner/runner_test.go b/src/ssl/test/runner/runner_test.go
index 320ff52..1ba28e0 100644
--- a/src/ssl/test/runner/runner_test.go
+++ b/src/ssl/test/runner/runner_test.go
@@ -1,3 +1,17 @@
+// Copyright (c) 2016, Google Inc.
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
package runner
import "testing"
diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc
index 67a017d..536978b 100644
--- a/src/ssl/test/test_config.cc
+++ b/src/ssl/test/test_config.cc
@@ -56,6 +56,7 @@
&TestConfig::write_different_record_sizes },
{ "-cbc-record-splitting", &TestConfig::cbc_record_splitting },
{ "-partial-write", &TestConfig::partial_write },
+ { "-no-tls13", &TestConfig::no_tls13 },
{ "-no-tls12", &TestConfig::no_tls12 },
{ "-no-tls11", &TestConfig::no_tls11 },
{ "-no-tls1", &TestConfig::no_tls1 },
@@ -148,6 +149,7 @@
&TestConfig::expect_server_key_exchange_hash },
{ "-expect-key-exchange-info",
&TestConfig::expect_key_exchange_info },
+ { "-initial-timeout-duration-ms", &TestConfig::initial_timeout_duration_ms },
};
} // namespace
diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h
index fe117d8..aff194e 100644
--- a/src/ssl/test/test_config.h
+++ b/src/ssl/test/test_config.h
@@ -38,6 +38,7 @@
bool write_different_record_sizes = false;
bool cbc_record_splitting = false;
bool partial_write = false;
+ bool no_tls13 = false;
bool no_tls12 = false;
bool no_tls11 = false;
bool no_tls1 = false;
@@ -104,6 +105,7 @@
bool use_sparse_dh_prime = false;
int expect_key_exchange_info = 0;
bool use_old_client_cert_callback = false;
+ int initial_timeout_duration_ms = 0;
};
bool ParseConfig(int argc, char **argv, TestConfig *out_config);