diff options
Diffstat (limited to 'src/ssl')
46 files changed, 8841 insertions, 10093 deletions
diff --git a/src/ssl/CMakeLists.txt b/src/ssl/CMakeLists.txt index 2785dcf..cf5a29d 100644 --- a/src/ssl/CMakeLists.txt +++ b/src/ssl/CMakeLists.txt @@ -1,11 +1,10 @@ -include_directories(../include) +include_directories(. .. ../include) add_subdirectory(pqueue) add_library( ssl - custom_extensions.c d1_both.c d1_clnt.c d1_lib.c @@ -13,7 +12,6 @@ add_library( d1_pkt.c d1_srtp.c d1_srvr.c - dtls_record.c s3_both.c s3_clnt.c s3_enc.c @@ -22,19 +20,18 @@ add_library( s3_pkt.c s3_srvr.c ssl_aead_ctx.c + ssl_algs.c ssl_asn1.c - ssl_buffer.c ssl_cert.c ssl_cipher.c - ssl_file.c ssl_lib.c ssl_rsa.c - ssl_session.c + ssl_sess.c ssl_stat.c ssl_txt.c t1_enc.c t1_lib.c - tls_record.c + t1_reneg.c $<TARGET_OBJECTS:pqueue> ) diff --git a/src/ssl/custom_extensions.c b/src/ssl/custom_extensions.c deleted file mode 100644 index c94543d..0000000 --- a/src/ssl/custom_extensions.c +++ /dev/null @@ -1,257 +0,0 @@ -/* Copyright (c) 2014, 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. */ - -#include <openssl/ssl.h> - -#include <assert.h> -#include <string.h> - -#include <openssl/bytestring.h> -#include <openssl/err.h> -#include <openssl/mem.h> -#include <openssl/stack.h> - -#include "internal.h" - - -void SSL_CUSTOM_EXTENSION_free(SSL_CUSTOM_EXTENSION *custom_extension) { - OPENSSL_free(custom_extension); -} - -static const SSL_CUSTOM_EXTENSION *custom_ext_find( - STACK_OF(SSL_CUSTOM_EXTENSION) *stack, - unsigned *out_index, uint16_t value) { - size_t i; - for (i = 0; i < sk_SSL_CUSTOM_EXTENSION_num(stack); i++) { - const SSL_CUSTOM_EXTENSION *ext = sk_SSL_CUSTOM_EXTENSION_value(stack, i); - if (ext->value == value) { - if (out_index != NULL) { - *out_index = i; - } - return ext; - } - } - - return NULL; -} - -/* default_add_callback is used as the |add_callback| when the user doesn't - * provide one. For servers, it does nothing while, for clients, it causes an - * empty extension to be included. */ -static int default_add_callback(SSL *ssl, unsigned extension_value, - const uint8_t **out, size_t *out_len, - int *out_alert_value, void *add_arg) { - if (ssl->server) { - return 0; - } - *out_len = 0; - return 1; -} - -static int custom_ext_add_hello(SSL *ssl, CBB *extensions) { - STACK_OF(SSL_CUSTOM_EXTENSION) *stack = ssl->ctx->client_custom_extensions; - if (ssl->server) { - stack = ssl->ctx->server_custom_extensions; - } - - if (stack == NULL) { - return 1; - } - - size_t i; - for (i = 0; i < sk_SSL_CUSTOM_EXTENSION_num(stack); i++) { - const SSL_CUSTOM_EXTENSION *ext = sk_SSL_CUSTOM_EXTENSION_value(stack, i); - - if (ssl->server && - !(ssl->s3->tmp.custom_extensions.received & (1u << i))) { - /* Servers cannot echo extensions that the client didn't send. */ - continue; - } - - const uint8_t *contents; - size_t contents_len; - int alert = SSL_AD_DECODE_ERROR; - CBB contents_cbb; - - switch (ext->add_callback(ssl, ext->value, &contents, &contents_len, &alert, - ext->add_arg)) { - case 1: - if (!CBB_add_u16(extensions, ext->value) || - !CBB_add_u16_length_prefixed(extensions, &contents_cbb) || - !CBB_add_bytes(&contents_cbb, contents, contents_len) || - !CBB_flush(extensions)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - ERR_add_error_dataf("extension: %u", (unsigned) ext->value); - if (ext->free_callback && 0 < contents_len) { - ext->free_callback(ssl, ext->value, contents, ext->add_arg); - } - return 0; - } - - if (ext->free_callback && 0 < contents_len) { - ext->free_callback(ssl, ext->value, contents, ext->add_arg); - } - - if (!ssl->server) { - assert((ssl->s3->tmp.custom_extensions.sent & (1u << i)) == 0); - ssl->s3->tmp.custom_extensions.sent |= (1u << i); - } - break; - - case 0: - break; - - default: - ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); - OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR); - ERR_add_error_dataf("extension: %u", (unsigned) ext->value); - return 0; - } - } - - return 1; -} - -int custom_ext_add_clienthello(SSL *ssl, CBB *extensions) { - return custom_ext_add_hello(ssl, extensions); -} - -int custom_ext_parse_serverhello(SSL *ssl, int *out_alert, uint16_t value, - const CBS *extension) { - unsigned index; - const SSL_CUSTOM_EXTENSION *ext = - custom_ext_find(ssl->ctx->client_custom_extensions, &index, value); - - if (/* Unknown extensions are not allowed in a ServerHello. */ - ext == NULL || - /* Also, if we didn't send the extension, that's also unacceptable. */ - !(ssl->s3->tmp.custom_extensions.sent & (1u << index))) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)value); - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } - - if (ext->parse_callback != NULL && - !ext->parse_callback(ssl, value, CBS_data(extension), CBS_len(extension), - out_alert, ext->parse_arg)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR); - ERR_add_error_dataf("extension: %u", (unsigned)ext->value); - return 0; - } - - return 1; -} - -int custom_ext_parse_clienthello(SSL *ssl, int *out_alert, uint16_t value, - const CBS *extension) { - unsigned index; - const SSL_CUSTOM_EXTENSION *ext = - custom_ext_find(ssl->ctx->server_custom_extensions, &index, value); - - if (ext == NULL) { - return 1; - } - - assert((ssl->s3->tmp.custom_extensions.received & (1u << index)) == 0); - ssl->s3->tmp.custom_extensions.received |= (1u << index); - - if (ext->parse_callback && - !ext->parse_callback(ssl, value, CBS_data(extension), CBS_len(extension), - out_alert, ext->parse_arg)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR); - ERR_add_error_dataf("extension: %u", (unsigned)ext->value); - return 0; - } - - return 1; -} - -int custom_ext_add_serverhello(SSL *ssl, CBB *extensions) { - return custom_ext_add_hello(ssl, extensions); -} - -/* MAX_NUM_CUSTOM_EXTENSIONS is the maximum number of custom extensions that - * can be set on an |SSL_CTX|. It's determined by the size of the bitset used - * to track when an extension has been sent. */ -#define MAX_NUM_CUSTOM_EXTENSIONS \ - (sizeof(((struct ssl3_state_st *)NULL)->tmp.custom_extensions.sent) * 8) - -static int custom_ext_append(STACK_OF(SSL_CUSTOM_EXTENSION) **stack, - unsigned extension_value, - SSL_custom_ext_add_cb add_cb, - SSL_custom_ext_free_cb free_cb, void *add_arg, - SSL_custom_ext_parse_cb parse_cb, - void *parse_arg) { - if (add_cb == NULL || - 0xffff < extension_value || - SSL_extension_supported(extension_value) || - /* Specifying a free callback without an add callback is nonsensical - * and an error. */ - (*stack != NULL && - (MAX_NUM_CUSTOM_EXTENSIONS <= sk_SSL_CUSTOM_EXTENSION_num(*stack) || - custom_ext_find(*stack, NULL, extension_value) != NULL))) { - return 0; - } - - SSL_CUSTOM_EXTENSION *ext = OPENSSL_malloc(sizeof(SSL_CUSTOM_EXTENSION)); - if (ext == NULL) { - return 0; - } - ext->add_callback = add_cb; - ext->add_arg = add_arg; - ext->free_callback = free_cb; - ext->parse_callback = parse_cb; - ext->parse_arg = parse_arg; - ext->value = extension_value; - - if (*stack == NULL) { - *stack = sk_SSL_CUSTOM_EXTENSION_new_null(); - if (*stack == NULL) { - SSL_CUSTOM_EXTENSION_free(ext); - return 0; - } - } - - if (!sk_SSL_CUSTOM_EXTENSION_push(*stack, ext)) { - SSL_CUSTOM_EXTENSION_free(ext); - if (sk_SSL_CUSTOM_EXTENSION_num(*stack) == 0) { - sk_SSL_CUSTOM_EXTENSION_free(*stack); - *stack = NULL; - } - return 0; - } - - return 1; -} - -int SSL_CTX_add_client_custom_ext(SSL_CTX *ctx, unsigned extension_value, - SSL_custom_ext_add_cb add_cb, - SSL_custom_ext_free_cb free_cb, void *add_arg, - SSL_custom_ext_parse_cb parse_cb, - void *parse_arg) { - return custom_ext_append(&ctx->client_custom_extensions, extension_value, - add_cb ? add_cb : default_add_callback, free_cb, - add_arg, parse_cb, parse_arg); -} - -int SSL_CTX_add_server_custom_ext(SSL_CTX *ctx, unsigned extension_value, - SSL_custom_ext_add_cb add_cb, - SSL_custom_ext_free_cb free_cb, void *add_arg, - SSL_custom_ext_parse_cb parse_cb, - void *parse_arg) { - return custom_ext_append(&ctx->server_custom_extensions, extension_value, - add_cb ? add_cb : default_add_callback, free_cb, - add_arg, parse_cb, parse_arg); -} diff --git a/src/ssl/d1_both.c b/src/ssl/d1_both.c index 1acb3ce..ac35a66 100644 --- a/src/ssl/d1_both.c +++ b/src/ssl/d1_both.c @@ -111,8 +111,6 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ -#include <openssl/ssl.h> - #include <assert.h> #include <limits.h> #include <stdio.h> @@ -149,44 +147,52 @@ static void dtls1_fix_message_header(SSL *s, unsigned long frag_off, unsigned long frag_len); static unsigned char *dtls1_write_message_header(SSL *s, unsigned char *p); -static hm_fragment *dtls1_hm_fragment_new(size_t frag_len, int reassembly) { - hm_fragment *frag = OPENSSL_malloc(sizeof(hm_fragment)); +static hm_fragment *dtls1_hm_fragment_new(unsigned long frag_len, + int reassembly) { + hm_fragment *frag = NULL; + uint8_t *buf = NULL; + uint8_t *bitmask = NULL; + + frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment)); if (frag == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, dtls1_hm_fragment_new, ERR_R_MALLOC_FAILURE); return NULL; } - memset(frag, 0, sizeof(hm_fragment)); - /* If the handshake message is empty, |frag->fragment| and |frag->reassembly| - * are NULL. */ - if (frag_len > 0) { - frag->fragment = OPENSSL_malloc(frag_len); - if (frag->fragment == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + if (frag_len) { + buf = (uint8_t *)OPENSSL_malloc(frag_len); + if (buf == NULL) { + OPENSSL_PUT_ERROR(SSL, dtls1_hm_fragment_new, ERR_R_MALLOC_FAILURE); + OPENSSL_free(frag); + return NULL; } + } - if (reassembly) { - /* Initialize reassembly bitmask. */ - if (frag_len + 7 < frag_len) { - OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); - goto err; - } - size_t bitmask_len = (frag_len + 7) / 8; - frag->reassembly = OPENSSL_malloc(bitmask_len); - if (frag->reassembly == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + /* zero length fragment gets zero frag->fragment */ + frag->fragment = buf; + + /* Initialize reassembly bitmask if necessary */ + if (reassembly && frag_len > 0) { + if (frag_len + 7 < frag_len) { + OPENSSL_PUT_ERROR(SSL, dtls1_hm_fragment_new, ERR_R_OVERFLOW); + return NULL; + } + size_t bitmask_len = (frag_len + 7) / 8; + bitmask = (uint8_t *)OPENSSL_malloc(bitmask_len); + if (bitmask == NULL) { + OPENSSL_PUT_ERROR(SSL, dtls1_hm_fragment_new, ERR_R_MALLOC_FAILURE); + if (buf != NULL) { + OPENSSL_free(buf); } - memset(frag->reassembly, 0, bitmask_len); + OPENSSL_free(frag); + return NULL; } + memset(bitmask, 0, bitmask_len); } - return frag; + frag->reassembly = bitmask; -err: - dtls1_hm_fragment_free(frag); - return NULL; + return frag; } void dtls1_hm_fragment_free(hm_fragment *frag) { @@ -320,7 +326,7 @@ int dtls1_do_write(SSL *s, int type, enum dtls1_use_epoch_t use_epoch) { if (curr_mtu <= DTLS1_HM_HEADER_LENGTH) { /* To make forward progress, the MTU must, at minimum, fit the handshake * header and one byte of handshake body. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_MTU_TOO_SMALL); + OPENSSL_PUT_ERROR(SSL, dtls1_do_write, SSL_R_MTU_TOO_SMALL); return -1; } @@ -338,7 +344,7 @@ int dtls1_do_write(SSL *s, int type, enum dtls1_use_epoch_t use_epoch) { assert(type == SSL3_RT_CHANGE_CIPHER_SPEC); /* ChangeCipherSpec cannot be fragmented. */ if (s->init_num > curr_mtu) { - OPENSSL_PUT_ERROR(SSL, SSL_R_MTU_TOO_SMALL); + OPENSSL_PUT_ERROR(SSL, dtls1_do_write, SSL_R_MTU_TOO_SMALL); return -1; } len = s->init_num; @@ -444,7 +450,8 @@ static hm_fragment *dtls1_get_buffered_message( frag->msg_header.msg_len != msg_hdr->msg_len) { /* The new fragment must be compatible with the previous fragments from * this message. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_FRAGMENT_MISMATCH); + OPENSSL_PUT_ERROR(SSL, dtls1_get_buffered_message, + SSL_R_FRAGMENT_MISMATCH); ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); return NULL; } @@ -466,7 +473,11 @@ static size_t dtls1_max_handshake_message_len(const SSL *s) { /* 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 *s) { - /* Read handshake message header. */ + /* Read handshake message header. + * + * TODO(davidben): ssl_read_bytes allows splitting the fragment header and + * body across two records. Change this interface to consume the fragment in + * one pass. */ uint8_t header[DTLS1_HM_HEADER_LENGTH]; int ret = dtls1_read_bytes(s, SSL3_RT_HANDSHAKE, header, DTLS1_HM_HEADER_LENGTH, 0); @@ -474,7 +485,7 @@ static int dtls1_process_fragment(SSL *s) { return ret; } if (ret != DTLS1_HM_HEADER_LENGTH) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); + OPENSSL_PUT_ERROR(SSL, dtls1_process_fragment, SSL_R_UNEXPECTED_MESSAGE); ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); return -1; } @@ -483,16 +494,14 @@ static int dtls1_process_fragment(SSL *s) { struct hm_header_st msg_hdr; dtls1_get_message_header(header, &msg_hdr); - /* TODO(davidben): dtls1_read_bytes is the wrong abstraction for DTLS. There - * should be no need to reach into |s->s3->rrec.length|. */ const size_t frag_off = msg_hdr.frag_off; const size_t frag_len = msg_hdr.frag_len; 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(s) || - frag_len > s->s3->rrec.length) { - OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE); + msg_len > dtls1_max_handshake_message_len(s)) { + OPENSSL_PUT_ERROR(SSL, dtls1_process_fragment, + SSL_R_EXCESSIVE_MESSAGE_SIZE); ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); return -1; } @@ -526,8 +535,8 @@ static int dtls1_process_fragment(SSL *s) { ret = dtls1_read_bytes(s, SSL3_RT_HANDSHAKE, frag->fragment + frag_off, frag_len, 0); if (ret != frag_len) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, dtls1_process_fragment, SSL_R_UNEXPECTED_MESSAGE); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); return -1; } dtls1_hm_fragment_mark(frag, frag_off, frag_off + frag_len); @@ -554,7 +563,7 @@ long dtls1_get_message(SSL *s, int st1, int stn, int msg_type, long max, s->s3->tmp.reuse_message = 0; if (msg_type >= 0 && s->s3->tmp.message_type != msg_type) { al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); + OPENSSL_PUT_ERROR(SSL, dtls1_get_message, SSL_R_UNEXPECTED_MESSAGE); goto f_err; } *ok = 1; @@ -580,19 +589,22 @@ long dtls1_get_message(SSL *s, int st1, int stn, int msg_type, long max, assert(frag->reassembly == NULL); if (frag->msg_header.msg_len > (size_t)max) { - OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE); + OPENSSL_PUT_ERROR(SSL, dtls1_get_message, SSL_R_EXCESSIVE_MESSAGE_SIZE); goto err; } - /* Reconstruct the assembled message. */ - size_t len; CBB cbb; - CBB_zero(&cbb); if (!BUF_MEM_grow(s->init_buf, (size_t)frag->msg_header.msg_len + DTLS1_HM_HEADER_LENGTH) || - !CBB_init_fixed(&cbb, (uint8_t *)s->init_buf->data, s->init_buf->max) || - !CBB_add_u8(&cbb, frag->msg_header.type) || + !CBB_init_fixed(&cbb, (uint8_t *)s->init_buf->data, s->init_buf->max)) { + OPENSSL_PUT_ERROR(SSL, dtls1_get_message, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* Reconstruct the assembled message. */ + size_t len; + if (!CBB_add_u8(&cbb, frag->msg_header.type) || !CBB_add_u24(&cbb, frag->msg_header.msg_len) || !CBB_add_u16(&cbb, frag->msg_header.seq) || !CBB_add_u24(&cbb, 0 /* frag_off */) || @@ -600,7 +612,7 @@ long dtls1_get_message(SSL *s, int st1, int stn, int msg_type, long max, !CBB_add_bytes(&cbb, frag->fragment, frag->msg_header.msg_len) || !CBB_finish(&cbb, NULL, &len)) { CBB_cleanup(&cbb); - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, dtls1_get_message, ERR_R_INTERNAL_ERROR); goto err; } assert(len == (size_t)frag->msg_header.msg_len + DTLS1_HM_HEADER_LENGTH); @@ -616,7 +628,7 @@ long dtls1_get_message(SSL *s, int st1, int stn, int msg_type, long max, if (msg_type >= 0 && s->s3->tmp.message_type != msg_type) { al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); + OPENSSL_PUT_ERROR(SSL, dtls1_get_message, SSL_R_UNEXPECTED_MESSAGE); goto f_err; } if (hash_message == ssl_hash_message && !ssl3_hash_current_message(s)) { diff --git a/src/ssl/d1_clnt.c b/src/ssl/d1_clnt.c index 73a3f8a..92fb8f6 100644 --- a/src/ssl/d1_clnt.c +++ b/src/ssl/d1_clnt.c @@ -112,8 +112,6 @@ * [including the GNU Public Licence.] */ -#include <openssl/ssl.h> - #include <assert.h> #include <stdio.h> #include <string.h> @@ -130,7 +128,6 @@ #include "internal.h" - static int dtls1_get_hello_verify(SSL *s); int dtls1_connect(SSL *s) { @@ -191,8 +188,9 @@ int dtls1_connect(SSL *s) { case SSL3_ST_CW_CLNT_HELLO_B: s->shutdown = 0; - if (!ssl3_init_handshake_buffer(s)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + /* every DTLS ClientHello resets Finished MAC */ + if (!ssl3_init_finished_mac(s)) { + OPENSSL_PUT_ERROR(SSL, dtls1_connect, ERR_R_INTERNAL_ERROR); ret = -1; goto end; } @@ -263,7 +261,7 @@ int dtls1_connect(SSL *s) { if (s->s3->tmp.certificate_status_expected) { s->state = SSL3_ST_CR_CERT_STATUS_A; } else { - s->state = SSL3_ST_VERIFY_SERVER_CERT; + s->state = SSL3_ST_CR_KEY_EXCH_A; } } else { skip = 1; @@ -272,16 +270,6 @@ int dtls1_connect(SSL *s) { s->init_num = 0; break; - case SSL3_ST_VERIFY_SERVER_CERT: - ret = ssl3_verify_server_cert(s); - if (ret <= 0) { - goto end; - } - - s->state = SSL3_ST_CR_KEY_EXCH_A; - s->init_num = 0; - break; - case SSL3_ST_CR_KEY_EXCH_A: case SSL3_ST_CR_KEY_EXCH_B: ret = ssl3_get_server_key_exchange(s); @@ -290,6 +278,13 @@ int dtls1_connect(SSL *s) { } s->state = SSL3_ST_CR_CERT_REQ_A; s->init_num = 0; + + /* at this point we check that we have the + * required stuff from the server */ + if (!ssl3_check_cert_and_algorithm(s)) { + ret = -1; + goto end; + } break; case SSL3_ST_CR_CERT_REQ_A: @@ -431,7 +426,7 @@ int dtls1_connect(SSL *s) { if (ret <= 0) { goto end; } - s->state = SSL3_ST_VERIFY_SERVER_CERT; + s->state = SSL3_ST_CR_KEY_EXCH_A; s->init_num = 0; break; @@ -488,7 +483,7 @@ int dtls1_connect(SSL *s) { goto end; default: - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE); + OPENSSL_PUT_ERROR(SSL, dtls1_connect, SSL_R_UNKNOWN_STATE); ret = -1; goto end; } @@ -543,7 +538,7 @@ static int dtls1_get_hello_verify(SSL *s) { !CBS_get_u8_length_prefixed(&hello_verify_request, &cookie) || CBS_len(&hello_verify_request) != 0) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, dtls1_get_hello_verify, SSL_R_DECODE_ERROR); goto f_err; } diff --git a/src/ssl/d1_lib.c b/src/ssl/d1_lib.c index cb95585..ef7a9c9 100644 --- a/src/ssl/d1_lib.c +++ b/src/ssl/d1_lib.c @@ -54,18 +54,12 @@ * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). */ -#include <openssl/ssl.h> +#include <openssl/base.h> #include <limits.h> #include <stdio.h> #include <string.h> -#include <openssl/err.h> -#include <openssl/mem.h> -#include <openssl/obj.h> - -#include "internal.h" - #if defined(OPENSSL_WINDOWS) #include <sys/timeb.h> #else @@ -73,6 +67,11 @@ #include <sys/time.h> #endif +#include <openssl/err.h> +#include <openssl/mem.h> +#include <openssl/obj.h> + +#include "internal.h" /* DTLS1_MTU_TIMEOUTS is the maximum number of timeouts to expire * before starting to decrease the MTU. */ @@ -153,9 +152,8 @@ void dtls1_free(SSL *s) { } int dtls1_supports_cipher(const SSL_CIPHER *cipher) { - /* DTLS does not support stream ciphers. The NULL cipher is rejected because - * it's not needed. */ - return cipher->algorithm_enc != SSL_RC4 && cipher->algorithm_enc != SSL_eNULL; + /* DTLS does not support stream ciphers. */ + return cipher->algorithm_enc != SSL_RC4; } void dtls1_start_timer(SSL *s) { @@ -264,7 +262,7 @@ int dtls1_check_timeout_num(SSL *s) { if (s->d1->num_timeouts > DTLS1_MAX_TIMEOUTS) { /* fail the connection, enough alerts have been sent */ - OPENSSL_PUT_ERROR(SSL, SSL_R_READ_TIMEOUT_EXPIRED); + OPENSSL_PUT_ERROR(SSL, dtls1_check_timeout_num, SSL_R_READ_TIMEOUT_EXPIRED); return -1; } @@ -330,9 +328,8 @@ int dtls1_set_handshake_header(SSL *s, int htype, unsigned long len) { s2n(msg_hdr->seq, p); l2n3(0, p); l2n3(msg_hdr->msg_len, p); - return ssl3_update_handshake_hash(s, serialised_header, - sizeof(serialised_header)) && - ssl3_update_handshake_hash(s, message + DTLS1_HM_HEADER_LENGTH, len); + return ssl3_finish_mac(s, serialised_header, sizeof(serialised_header)) && + ssl3_finish_mac(s, message + DTLS1_HM_HEADER_LENGTH, len); } int dtls1_handshake_write(SSL *s) { diff --git a/src/ssl/d1_meth.c b/src/ssl/d1_meth.c index d54a037..d90f75b 100644 --- a/src/ssl/d1_meth.c +++ b/src/ssl/d1_meth.c @@ -55,8 +55,6 @@ * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). */ -#include <openssl/ssl.h> - #include "internal.h" @@ -71,6 +69,8 @@ static const SSL_PROTOCOL_METHOD DTLS_protocol_method = { dtls1_read_close_notify, dtls1_write_app_data, dtls1_dispatch_alert, + ssl3_ctrl, + ssl3_ctx_ctrl, dtls1_supports_cipher, DTLS1_HM_HEADER_LENGTH, dtls1_set_handshake_header, diff --git a/src/ssl/d1_pkt.c b/src/ssl/d1_pkt.c index e2d505c..553499f 100644 --- a/src/ssl/d1_pkt.c +++ b/src/ssl/d1_pkt.c @@ -109,8 +109,6 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ -#include <openssl/ssl.h> - #include <assert.h> #include <stdio.h> #include <string.h> @@ -124,66 +122,270 @@ #include "internal.h" +/* mod 128 saturating subtract of two 64-bit values in big-endian order */ +static int satsub64be(const uint8_t *v1, const uint8_t *v2) { + int ret, sat, brw, i; + + if (sizeof(long) == 8) { + do { + const union { + long one; + char little; + } is_endian = {1}; + long l; + + if (is_endian.little) { + break; + } + /* not reached on little-endians */ + /* following test is redundant, because input is + * always aligned, but I take no chances... */ + if (((size_t)v1 | (size_t)v2) & 0x7) { + break; + } + + l = *((long *)v1); + l -= *((long *)v2); + if (l > 128) { + return 128; + } else if (l < -128) { + return -128; + } else { + return (int)l; + } + } while (0); + } + + ret = (int)v1[7] - (int)v2[7]; + sat = 0; + brw = ret >> 8; /* brw is either 0 or -1 */ + if (ret & 0x80) { + for (i = 6; i >= 0; i--) { + brw += (int)v1[i] - (int)v2[i]; + sat |= ~brw; + brw >>= 8; + } + } else { + for (i = 6; i >= 0; i--) { + brw += (int)v1[i] - (int)v2[i]; + sat |= brw; + brw >>= 8; + } + } + brw <<= 8; /* brw is either 0 or -256 */ + + if (sat & 0xff) { + return brw | 0x80; + } else { + return brw + (ret & 0xFF); + } +} + +static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap); +static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap); +static int dtls1_process_record(SSL *s); static int do_dtls1_write(SSL *s, int type, const uint8_t *buf, unsigned int len, enum dtls1_use_epoch_t use_epoch); -/* dtls1_get_record reads a new input record. On success, it places it in - * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if - * more data is needed. */ -static int dtls1_get_record(SSL *ssl) { -again: - /* 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 */); - if (ret <= 0) { - return ret; - } +static int dtls1_process_record(SSL *s) { + int al; + SSL3_RECORD *rr = &s->s3->rrec; + + /* check is not needed I believe */ + if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) { + al = SSL_AD_RECORD_OVERFLOW; + OPENSSL_PUT_ERROR(SSL, dtls1_process_record, + SSL_R_ENCRYPTED_LENGTH_TOO_LONG); + goto f_err; } - assert(ssl_read_buffer_len(ssl) > 0); - /* Ensure the packet is large enough to decrypt in-place. */ - if (ssl_read_buffer_len(ssl) < ssl_record_prefix_len(ssl)) { - ssl_read_buffer_clear(ssl); - goto again; + /* |rr->data| points to |rr->length| bytes of ciphertext in |s->packet|. */ + rr->data = &s->packet[DTLS1_RT_HEADER_LENGTH]; + + uint8_t seq[8]; + seq[0] = rr->epoch >> 8; + seq[1] = rr->epoch & 0xff; + memcpy(&seq[2], &rr->seq_num[2], 6); + + /* Decrypt the packet in-place. Note it is important that |SSL_AEAD_CTX_open| + * not write beyond |rr->length|. There may be another record in the packet. + * + * TODO(davidben): This assumes |s->version| is the same as the record-layer + * version which isn't always true, but it only differs with the NULL cipher + * which ignores the parameter. */ + size_t plaintext_len; + if (!SSL_AEAD_CTX_open(s->aead_read_ctx, rr->data, &plaintext_len, rr->length, + rr->type, s->version, seq, rr->data, rr->length)) { + /* Bad packets are silently dropped in DTLS. Clear the error queue of any + * errors decryption may have added. */ + ERR_clear_error(); + rr->length = 0; + s->packet_length = 0; + goto err; + } + + if (plaintext_len > SSL3_RT_MAX_PLAIN_LENGTH) { + al = SSL_AD_RECORD_OVERFLOW; + OPENSSL_PUT_ERROR(SSL, dtls1_process_record, SSL_R_DATA_LENGTH_TOO_LONG); + goto f_err; } + assert(plaintext_len < (1u << 16)); + rr->length = plaintext_len; - uint8_t *out = ssl_read_buffer(ssl) + ssl_record_prefix_len(ssl); - size_t max_out = ssl_read_buffer_len(ssl) - ssl_record_prefix_len(ssl); - uint8_t type, alert; - size_t len, consumed; - switch (dtls_open_record(ssl, &type, out, &len, &consumed, &alert, max_out, - ssl_read_buffer(ssl), ssl_read_buffer_len(ssl))) { - case ssl_open_record_success: - ssl_read_buffer_consume(ssl, consumed); + rr->off = 0; + /* So at this point the following is true + * ssl->s3->rrec.type is the type of record + * ssl->s3->rrec.length == number of bytes in record + * ssl->s3->rrec.off == offset to first valid byte + * ssl->s3->rrec.data == the first byte of the record body. */ + + /* we have pulled in a full packet so zero things */ + s->packet_length = 0; + return 1; + +f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); - if (len > 0xffff) { - OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); - return -1; +err: + return 0; +} + +/* Call this to get a new input record. + * It will return <= 0 if more data is needed, normally due to an error + * or non-blocking IO. + * When it finishes, one packet has been decoded and can be found in + * ssl->s3->rrec.type - is the type of record + * ssl->s3->rrec.data, - data + * ssl->s3->rrec.length, - number of bytes + * + * used only by dtls1_read_bytes */ +int dtls1_get_record(SSL *s) { + uint8_t ssl_major, ssl_minor; + int n; + SSL3_RECORD *rr; + uint8_t *p = NULL; + uint16_t version; + + rr = &(s->s3->rrec); + + /* get something from the wire */ +again: + /* check if we have the header */ + if ((s->rstate != SSL_ST_READ_BODY) || + (s->packet_length < DTLS1_RT_HEADER_LENGTH)) { + n = ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH, 0); + /* read timeout is handled by dtls1_read_bytes */ + if (n <= 0) { + return n; /* error or non-blocking */ + } + + /* this packet contained a partial record, dump it */ + if (s->packet_length != DTLS1_RT_HEADER_LENGTH) { + s->packet_length = 0; + goto again; + } + + s->rstate = SSL_ST_READ_BODY; + + p = s->packet; + + if (s->msg_callback) { + s->msg_callback(0, 0, SSL3_RT_HEADER, p, DTLS1_RT_HEADER_LENGTH, s, + s->msg_callback_arg); + } + + /* Pull apart the header into the DTLS1_RECORD */ + rr->type = *(p++); + ssl_major = *(p++); + ssl_minor = *(p++); + version = (((uint16_t)ssl_major) << 8) | ssl_minor; + + /* sequence number is 64 bits, with top 2 bytes = epoch */ + n2s(p, rr->epoch); + + memcpy(&(s->s3->read_sequence[2]), p, 6); + p += 6; + + n2s(p, rr->length); + + /* Lets check version */ + if (s->s3->have_version) { + if (version != s->version) { + /* The record's version doesn't match, so silently drop it. + * + * TODO(davidben): This doesn't work. The DTLS record layer is not + * packet-based, so the remainder of the packet isn't dropped and we + * get a framing error. It's also unclear what it means to silently + * drop a record in a packet containing two records. */ + rr->length = 0; + s->packet_length = 0; + goto again; } + } - SSL3_RECORD *rr = &ssl->s3->rrec; - rr->type = type; - rr->length = (uint16_t)len; - rr->off = 0; - rr->data = out; - return 1; + if ((version & 0xff00) != (s->version & 0xff00)) { + /* wrong version, silently discard record */ + rr->length = 0; + s->packet_length = 0; + goto again; + } - case ssl_open_record_discard: - ssl_read_buffer_consume(ssl, consumed); + if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) { + /* record too long, silently discard it */ + rr->length = 0; + s->packet_length = 0; goto again; + } - case ssl_open_record_error: - ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); - return -1; + /* now s->rstate == SSL_ST_READ_BODY */ + } + + /* s->rstate == SSL_ST_READ_BODY, get and decode the data */ + + if (rr->length > s->packet_length - DTLS1_RT_HEADER_LENGTH) { + /* now s->packet_length == DTLS1_RT_HEADER_LENGTH */ + n = ssl3_read_n(s, rr->length, 1); + /* This packet contained a partial record, dump it. */ + if (n != rr->length) { + rr->length = 0; + s->packet_length = 0; + goto again; + } - case ssl_open_record_partial: - /* Impossible in DTLS. */ - break; + /* now n == rr->length, + * and s->packet_length == DTLS1_RT_HEADER_LENGTH + rr->length */ } + s->rstate = SSL_ST_READ_HEADER; /* set state for later operations */ - assert(0); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return -1; + if (rr->epoch != s->d1->r_epoch) { + /* This record is from the wrong epoch. If it is the next epoch, it could be + * buffered. For simplicity, drop it and expect retransmit to handle it + * later; DTLS is supposed to handle packet loss. */ + rr->length = 0; + s->packet_length = 0; + goto again; + } + + /* Check whether this is a repeat, or aged record. */ + if (!dtls1_record_replay_check(s, &s->d1->bitmap)) { + rr->length = 0; + s->packet_length = 0; /* dump this record */ + goto again; /* get another record */ + } + + /* just read a 0 length packet */ + if (rr->length == 0) { + goto again; + } + + if (!dtls1_process_record(s)) { + rr->length = 0; + s->packet_length = 0; /* dump this record */ + goto again; /* get another record */ + } + dtls1_record_bitmap_update(s, &s->d1->bitmap); /* Mark receipt of record. */ + + return 1; } int dtls1_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek) { @@ -191,11 +393,7 @@ int dtls1_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek) { } void dtls1_read_close_notify(SSL *ssl) { - /* Bidirectional shutdown doesn't make sense for an unordered transport. DTLS - * 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; + dtls1_read_bytes(ssl, 0, NULL, 0, 0); } /* Return up to 'len' payload bytes received in 'type' records. @@ -203,6 +401,7 @@ void dtls1_read_close_notify(SSL *ssl) { * * - SSL3_RT_HANDSHAKE (when ssl3_get_message calls us) * - SSL3_RT_APPLICATION_DATA (when ssl3_read calls us) + * - 0 (during a shutdown, no data has to be returned) * * If we don't have stored data to work from, read a SSL/TLS record first * (possibly multiple records if we still don't have anything to return). @@ -230,9 +429,11 @@ int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek) { SSL3_RECORD *rr; void (*cb)(const SSL *ssl, int type2, int val) = NULL; - if ((type != SSL3_RT_APPLICATION_DATA && type != SSL3_RT_HANDSHAKE) || - (peek && type != SSL3_RT_APPLICATION_DATA)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + /* XXX: check what the second '&& type' is about */ + if ((type && (type != SSL3_RT_APPLICATION_DATA) && + (type != SSL3_RT_HANDSHAKE) && type) || + (peek && (type != SSL3_RT_APPLICATION_DATA))) { + OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, ERR_R_INTERNAL_ERROR); return -1; } @@ -243,7 +444,7 @@ int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek) { return i; } if (i == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE); + OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE); return -1; } } @@ -263,7 +464,7 @@ start: } /* get new packet if necessary */ - if (rr->length == 0) { + if (rr->length == 0 || s->rstate == SSL_ST_READ_BODY) { ret = dtls1_get_record(s); if (ret <= 0) { ret = dtls1_read_failed(s, ret); @@ -306,15 +507,10 @@ start: /* 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); + OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_APP_DATA_IN_HANDSHAKE); goto f_err; } - /* Discard empty records. */ - if (rr->length == 0) { - goto start; - } - if (len <= 0) { return len; } @@ -330,9 +526,8 @@ start: rr->length -= n; rr->off += n; if (rr->length == 0) { + s->rstate = SSL_ST_READ_HEADER; rr->off = 0; - /* The record has been consumed, so we may now clear the buffer. */ - ssl_read_buffer_discard(s); } } @@ -347,7 +542,7 @@ start: /* Alerts may not be fragmented. */ if (rr->length < 2) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT); + OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_BAD_ALERT); goto f_err; } @@ -381,7 +576,8 @@ start: s->rwstate = SSL_NOTHING; s->s3->fatal_alert = alert_descr; - OPENSSL_PUT_ERROR(SSL, SSL_AD_REASON_OFFSET + alert_descr); + OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, + SSL_AD_REASON_OFFSET + alert_descr); BIO_snprintf(tmp, sizeof tmp, "%d", alert_descr); ERR_add_error_data(2, "SSL alert number ", tmp); s->shutdown |= SSL_RECEIVED_SHUTDOWN; @@ -389,19 +585,26 @@ start: return 0; } else { al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_ALERT_TYPE); + OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_UNKNOWN_ALERT_TYPE); goto f_err; } goto start; } + if (s->shutdown & SSL_SENT_SHUTDOWN) { + /* but we have not received a shutdown */ + s->rwstate = SSL_NOTHING; + rr->length = 0; + return 0; + } + if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) { /* 'Change Cipher Spec' is just a single byte, so we know exactly what the * record payload has to look like */ if (rr->length != 1 || rr->off != 0 || rr->data[0] != SSL3_MT_CCS) { al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC); + OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_BAD_CHANGE_CIPHER_SPEC); goto f_err; } @@ -438,7 +641,7 @@ start: if (rr->type == SSL3_RT_HANDSHAKE && !s->in_handshake) { if (rr->length < DTLS1_HM_HEADER_LENGTH) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HANDSHAKE_RECORD); + OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_BAD_HANDSHAKE_RECORD); goto f_err; } struct hm_header_st msg_hdr; @@ -466,7 +669,7 @@ start: assert(rr->type != SSL3_RT_CHANGE_CIPHER_SPEC && rr->type != SSL3_RT_ALERT); al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD); + OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_UNEXPECTED_RECORD); f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); @@ -483,13 +686,13 @@ int dtls1_write_app_data(SSL *s, const void *buf_, int len) { return i; } if (i == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE); + OPENSSL_PUT_ERROR(SSL, dtls1_write_app_data, SSL_R_SSL_HANDSHAKE_FAILURE); return -1; } } if (len > SSL3_RT_MAX_PLAIN_LENGTH) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DTLS_MESSAGE_TOO_BIG); + OPENSSL_PUT_ERROR(SSL, dtls1_write_app_data, SSL_R_DTLS_MESSAGE_TOO_BIG); return -1; } @@ -510,11 +713,73 @@ int dtls1_write_bytes(SSL *s, int type, const void *buf, int len, return i; } +/* dtls1_seal_record seals a new record of type |type| and plaintext |in| and + * writes it to |out|. At most |max_out| bytes will be written. It returns one + * on success and zero on error. On success, it updates the write sequence + * number. */ +static int dtls1_seal_record(SSL *s, uint8_t *out, size_t *out_len, + size_t max_out, uint8_t type, const uint8_t *in, + size_t in_len, enum dtls1_use_epoch_t use_epoch) { + if (max_out < DTLS1_RT_HEADER_LENGTH) { + OPENSSL_PUT_ERROR(SSL, dtls1_seal_record, SSL_R_BUFFER_TOO_SMALL); + return 0; + } + + /* Determine the parameters for the current epoch. */ + uint16_t epoch = s->d1->w_epoch; + SSL_AEAD_CTX *aead = s->aead_write_ctx; + uint8_t *seq = s->s3->write_sequence; + if (use_epoch == dtls1_use_previous_epoch) { + /* DTLS renegotiation is unsupported, so only epochs 0 (NULL cipher) and 1 + * (negotiated cipher) exist. */ + assert(s->d1->w_epoch == 1); + epoch = s->d1->w_epoch - 1; + aead = NULL; + seq = s->d1->last_write_sequence; + } + + out[0] = type; + + uint16_t wire_version = s->s3->have_version ? s->version : DTLS1_VERSION; + out[1] = wire_version >> 8; + out[2] = wire_version & 0xff; + + out[3] = epoch >> 8; + out[4] = epoch & 0xff; + memcpy(&out[5], &seq[2], 6); + + size_t ciphertext_len; + if (!SSL_AEAD_CTX_seal(aead, out + DTLS1_RT_HEADER_LENGTH, &ciphertext_len, + max_out - DTLS1_RT_HEADER_LENGTH, type, wire_version, + &out[3] /* seq */, in, in_len) || + !ssl3_record_sequence_update(&seq[2], 6)) { + return 0; + } + + if (ciphertext_len >= 1 << 16) { + OPENSSL_PUT_ERROR(SSL, dtls1_seal_record, ERR_R_OVERFLOW); + return 0; + } + out[11] = ciphertext_len >> 8; + out[12] = ciphertext_len & 0xff; + + *out_len = DTLS1_RT_HEADER_LENGTH + ciphertext_len; + + if (s->msg_callback) { + s->msg_callback(1 /* write */, 0, SSL3_RT_HEADER, out, + DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg); + } + + return 1; +} + static int do_dtls1_write(SSL *s, int type, const uint8_t *buf, unsigned int len, enum dtls1_use_epoch_t use_epoch) { + SSL3_BUFFER *wb = &s->s3->wbuf; + /* ssl3_write_pending drops the write if |BIO_write| fails in DTLS, so there * is never pending data. */ - assert(!ssl_write_buffer_is_pending(s)); + assert(s->s3->wbuf.left == 0); /* If we have an alert to send, lets send it */ if (s->s3->alert_dispatch) { @@ -525,8 +790,7 @@ static int do_dtls1_write(SSL *s, int type, const uint8_t *buf, /* if it went, fall through and send more stuff */ } - if (len > SSL3_RT_MAX_PLAIN_LENGTH) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + if (wb->buf == NULL && !ssl3_setup_write_buffer(s)) { return -1; } @@ -534,15 +798,21 @@ static int do_dtls1_write(SSL *s, int type, const uint8_t *buf, return 0; } - size_t max_out = len + ssl_max_seal_overhead(s); - uint8_t *out; + /* Align the output so the ciphertext is aligned to |SSL3_ALIGN_PAYLOAD|. */ + uintptr_t align = (uintptr_t)wb->buf + DTLS1_RT_HEADER_LENGTH; + align = (0 - align) & (SSL3_ALIGN_PAYLOAD - 1); + uint8_t *out = wb->buf + align; + wb->offset = align; + size_t max_out = wb->len - wb->offset; + size_t ciphertext_len; - if (!ssl_write_buffer_init(s, &out, max_out) || - !dtls_seal_record(s, out, &ciphertext_len, max_out, type, buf, len, - use_epoch)) { + if (!dtls1_seal_record(s, out, &ciphertext_len, max_out, type, buf, len, + use_epoch)) { return -1; } - ssl_write_buffer_set_len(s, ciphertext_len); + + /* now let's set up wb */ + wb->left = ciphertext_len; /* memorize arguments so that ssl3_write_pending can detect bad write retries * later */ @@ -555,6 +825,49 @@ static int do_dtls1_write(SSL *s, int type, const uint8_t *buf, return ssl3_write_pending(s, type, buf, len); } +static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap) { + int cmp; + unsigned int shift; + const uint8_t *seq = s->s3->read_sequence; + + cmp = satsub64be(seq, bitmap->max_seq_num); + if (cmp > 0) { + memcpy(s->s3->rrec.seq_num, seq, 8); + return 1; /* this record in new */ + } + shift = -cmp; + if (shift >= sizeof(bitmap->map) * 8) { + return 0; /* stale, outside the window */ + } else if (bitmap->map & (((uint64_t)1) << shift)) { + return 0; /* record previously received */ + } + + memcpy(s->s3->rrec.seq_num, seq, 8); + return 1; +} + +static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap) { + int cmp; + unsigned int shift; + const uint8_t *seq = s->s3->read_sequence; + + cmp = satsub64be(seq, bitmap->max_seq_num); + if (cmp > 0) { + shift = cmp; + if (shift < sizeof(bitmap->map) * 8) { + bitmap->map <<= shift, bitmap->map |= 1UL; + } else { + bitmap->map = 1UL; + } + memcpy(bitmap->max_seq_num, seq, 8); + } else { + shift = -cmp; + if (shift < sizeof(bitmap->map) * 8) { + bitmap->map |= ((uint64_t)1) << shift; + } + } +} + int dtls1_dispatch_alert(SSL *s) { int i, j; void (*cb)(const SSL *ssl, int type, int val) = NULL; diff --git a/src/ssl/d1_srtp.c b/src/ssl/d1_srtp.c index 2fcc1ea..5928fc8 100644 --- a/src/ssl/d1_srtp.c +++ b/src/ssl/d1_srtp.c @@ -114,8 +114,6 @@ Copyright (C) 2011, RTFM, Inc. */ -#include <openssl/ssl.h> - #include <stdio.h> #include <string.h> @@ -124,14 +122,15 @@ #include <openssl/obj.h> #include "internal.h" +#include <openssl/srtp.h> -const SRTP_PROTECTION_PROFILE kSRTPProfiles[] = { +static const SRTP_PROTECTION_PROFILE srtp_known_profiles[] = { { - "SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80, + "SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80, }, { - "SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32, + "SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32, }, {0}, }; @@ -141,7 +140,7 @@ static int find_profile_by_name(const char *profile_name, size_t len) { const SRTP_PROTECTION_PROFILE *p; - p = kSRTPProfiles; + p = srtp_known_profiles; while (p->name) { if (len == strlen(p->name) && !strncmp(p->name, profile_name, len)) { *pptr = p; @@ -154,6 +153,22 @@ static int find_profile_by_name(const char *profile_name, return 0; } +static int find_profile_by_num(unsigned profile_num, + const SRTP_PROTECTION_PROFILE **pptr) { + const SRTP_PROTECTION_PROFILE *p; + + p = srtp_known_profiles; + while (p->name) { + if (p->id == profile_num) { + *pptr = p; + return 1; + } + p++; + } + + return 0; +} + static int ssl_ctx_make_profiles(const char *profiles_string, STACK_OF(SRTP_PROTECTION_PROFILE) **out) { STACK_OF(SRTP_PROTECTION_PROFILE) *profiles; @@ -163,7 +178,8 @@ static int ssl_ctx_make_profiles(const char *profiles_string, profiles = sk_SRTP_PROTECTION_PROFILE_new_null(); if (profiles == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES); + OPENSSL_PUT_ERROR(SSL, ssl_ctx_make_profiles, + SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES); return 0; } @@ -174,7 +190,8 @@ static int ssl_ctx_make_profiles(const char *profiles_string, if (find_profile_by_name(ptr, &p, col ? col - ptr : strlen(ptr))) { sk_SRTP_PROTECTION_PROFILE_push(profiles, p); } else { - OPENSSL_PUT_ERROR(SSL, SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE); + OPENSSL_PUT_ERROR(SSL, ssl_ctx_make_profiles, + SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE); return 0; } @@ -192,28 +209,28 @@ int SSL_CTX_set_srtp_profiles(SSL_CTX *ctx, const char *profiles) { return ssl_ctx_make_profiles(profiles, &ctx->srtp_profiles); } -int SSL_set_srtp_profiles(SSL *ssl, const char *profiles) { - return ssl_ctx_make_profiles(profiles, &ssl->srtp_profiles); +int SSL_set_srtp_profiles(SSL *s, const char *profiles) { + return ssl_ctx_make_profiles(profiles, &s->srtp_profiles); } -STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(SSL *ssl) { - if (ssl == NULL) { +STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(SSL *s) { + if (s == NULL) { return NULL; } - if (ssl->srtp_profiles != NULL) { - return ssl->srtp_profiles; + if (s->srtp_profiles != NULL) { + return s->srtp_profiles; } - if (ssl->ctx != NULL && ssl->ctx->srtp_profiles != NULL) { - return ssl->ctx->srtp_profiles; + if (s->ctx != NULL && s->ctx->srtp_profiles != NULL) { + return s->ctx->srtp_profiles; } return NULL; } -const SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *ssl) { - return ssl->srtp_profile; +const SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s) { + return s->srtp_profile; } int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx, const char *profiles) { @@ -221,7 +238,195 @@ int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx, const char *profiles) { return !SSL_CTX_set_srtp_profiles(ctx, profiles); } -int SSL_set_tlsext_use_srtp(SSL *ssl, const char *profiles) { +int SSL_set_tlsext_use_srtp(SSL *s, const char *profiles) { /* This API inverts its return value. */ - return !SSL_set_srtp_profiles(ssl, profiles); + return !SSL_set_srtp_profiles(s, profiles); +} + +/* Note: this function returns 0 length if there are no profiles specified */ +int ssl_add_clienthello_use_srtp_ext(SSL *s, uint8_t *p, int *len, int maxlen) { + int ct = 0; + int i; + STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = 0; + const SRTP_PROTECTION_PROFILE *prof; + + clnt = SSL_get_srtp_profiles(s); + ct = sk_SRTP_PROTECTION_PROFILE_num(clnt); /* -1 if clnt == 0 */ + + if (p) { + if (ct == 0) { + OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_use_srtp_ext, + SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST); + return 0; + } + + if (2 + ct * 2 + 1 > maxlen) { + OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_use_srtp_ext, + SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG); + return 0; + } + + /* Add the length */ + s2n(ct * 2, p); + for (i = 0; i < ct; i++) { + prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i); + s2n(prof->id, p); + } + + /* Add an empty use_mki value */ + *p++ = 0; + } + + *len = 2 + ct * 2 + 1; + + return 1; +} + +int ssl_parse_clienthello_use_srtp_ext(SSL *s, CBS *cbs, int *out_alert) { + CBS profile_ids, srtp_mki; + const SRTP_PROTECTION_PROFILE *cprof, *sprof; + STACK_OF(SRTP_PROTECTION_PROFILE) *client_profiles = 0, *server_profiles; + size_t i, j; + int ret = 0; + + if (!CBS_get_u16_length_prefixed(cbs, &profile_ids) || + CBS_len(&profile_ids) < 2 || + !CBS_get_u8_length_prefixed(cbs, &srtp_mki) || + CBS_len(cbs) != 0) { + OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_use_srtp_ext, + SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + *out_alert = SSL_AD_DECODE_ERROR; + goto done; + } + + client_profiles = sk_SRTP_PROTECTION_PROFILE_new_null(); + if (client_profiles == NULL) { + OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_use_srtp_ext, + ERR_R_MALLOC_FAILURE); + *out_alert = SSL_AD_INTERNAL_ERROR; + goto done; + } + + while (CBS_len(&profile_ids) > 0) { + uint16_t profile_id; + + if (!CBS_get_u16(&profile_ids, &profile_id)) { + *out_alert = SSL_AD_DECODE_ERROR; + goto done; + } + + if (find_profile_by_num(profile_id, &cprof)) { + sk_SRTP_PROTECTION_PROFILE_push(client_profiles, cprof); + } + } + + /* Discard the MKI value for now. */ + + server_profiles = SSL_get_srtp_profiles(s); + + /* Pick the server's most preferred profile. */ + for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(server_profiles); i++) { + sprof = sk_SRTP_PROTECTION_PROFILE_value(server_profiles, i); + + for (j = 0; j < sk_SRTP_PROTECTION_PROFILE_num(client_profiles); j++) { + cprof = sk_SRTP_PROTECTION_PROFILE_value(client_profiles, j); + + if (cprof->id == sprof->id) { + s->srtp_profile = sprof; + ret = 1; + goto done; + } + } + } + + ret = 1; + +done: + if (client_profiles) { + sk_SRTP_PROTECTION_PROFILE_free(client_profiles); + } + + return ret; +} + +int ssl_add_serverhello_use_srtp_ext(SSL *s, unsigned char *p, int *len, + int maxlen) { + if (p) { + if (maxlen < 5) { + OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_use_srtp_ext, + SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG); + return 0; + } + + if (s->srtp_profile == 0) { + OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_use_srtp_ext, + SSL_R_USE_SRTP_NOT_NEGOTIATED); + return 0; + } + + s2n(2, p); + s2n(s->srtp_profile->id, p); + *p++ = 0; + } + + *len = 5; + + return 1; +} + +int ssl_parse_serverhello_use_srtp_ext(SSL *s, CBS *cbs, int *out_alert) { + CBS profile_ids, srtp_mki; + uint16_t profile_id; + size_t i; + + STACK_OF(SRTP_PROTECTION_PROFILE) *client_profiles; + const SRTP_PROTECTION_PROFILE *prof; + + /* The extension consists of a u16-prefixed profile ID list containing a + * single uint16_t profile ID, then followed by a u8-prefixed srtp_mki field. + * + * See https://tools.ietf.org/html/rfc5764#section-4.1.1 */ + if (!CBS_get_u16_length_prefixed(cbs, &profile_ids) || + !CBS_get_u16(&profile_ids, &profile_id) || CBS_len(&profile_ids) != 0 || + !CBS_get_u8_length_prefixed(cbs, &srtp_mki) || CBS_len(cbs) != 0) { + OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_use_srtp_ext, + SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + + if (CBS_len(&srtp_mki) != 0) { + /* Must be no MKI, since we never offer one. */ + OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_use_srtp_ext, + SSL_R_BAD_SRTP_MKI_VALUE); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + client_profiles = SSL_get_srtp_profiles(s); + + /* Throw an error if the server gave us an unsolicited extension */ + if (client_profiles == NULL) { + OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_use_srtp_ext, + SSL_R_NO_SRTP_PROFILES); + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + + /* Check to see if the server gave us something we support + (and presumably offered). */ + for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(client_profiles); i++) { + prof = sk_SRTP_PROTECTION_PROFILE_value(client_profiles, i); + + if (prof->id == profile_id) { + s->srtp_profile = prof; + *out_alert = 0; + return 1; + } + } + + OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_use_srtp_ext, + SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; } diff --git a/src/ssl/d1_srvr.c b/src/ssl/d1_srvr.c index 89c26aa..e49a3f0 100644 --- a/src/ssl/d1_srvr.c +++ b/src/ssl/d1_srvr.c @@ -112,8 +112,6 @@ * [including the GNU Public Licence.] */ -#include <openssl/ssl.h> - #include <assert.h> #include <stdio.h> @@ -152,6 +150,11 @@ int dtls1_accept(SSL *s) { s->in_handshake++; + if (s->cert == NULL) { + OPENSSL_PUT_ERROR(SSL, dtls1_accept, SSL_R_NO_CERTIFICATE_SET); + return -1; + } + for (;;) { state = s->state; @@ -178,8 +181,8 @@ int dtls1_accept(SSL *s) { goto end; } - if (!ssl3_init_handshake_buffer(s)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + if (!ssl3_init_finished_mac(s)) { + OPENSSL_PUT_ERROR(SSL, dtls1_accept, ERR_R_INTERNAL_ERROR); ret = -1; goto end; } @@ -241,19 +244,8 @@ int dtls1_accept(SSL *s) { s->init_num = 0; break; - case SSL3_ST_SW_CERT_STATUS_A: - case SSL3_ST_SW_CERT_STATUS_B: - ret = ssl3_send_certificate_status(s); - if (ret <= 0) { - goto end; - } - s->state = SSL3_ST_SW_KEY_EXCH_A; - s->init_num = 0; - break; - case SSL3_ST_SW_KEY_EXCH_A: case SSL3_ST_SW_KEY_EXCH_B: - case SSL3_ST_SW_KEY_EXCH_C: alg_a = s->s3->tmp.new_cipher->algorithm_auth; /* Send a ServerKeyExchange message if: @@ -447,7 +439,7 @@ int dtls1_accept(SSL *s) { goto end; default: - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE); + OPENSSL_PUT_ERROR(SSL, dtls1_accept, SSL_R_UNKNOWN_STATE); ret = -1; goto end; } diff --git a/src/ssl/dtls_record.c b/src/ssl/dtls_record.c deleted file mode 100644 index 940494a..0000000 --- a/src/ssl/dtls_record.c +++ /dev/null @@ -1,308 +0,0 @@ -/* DTLS implementation written by Nagendra Modadugu - * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. */ -/* ==================================================================== - * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). - * - */ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] */ - -#include <openssl/ssl.h> - -#include <assert.h> -#include <string.h> - -#include <openssl/bytestring.h> -#include <openssl/err.h> - -#include "internal.h" - - -/* to_u64_be treats |in| as a 8-byte big-endian integer and returns the value as - * a |uint64_t|. */ -static uint64_t to_u64_be(const uint8_t in[8]) { - uint64_t ret = 0; - unsigned i; - for (i = 0; i < 8; i++) { - ret <<= 8; - ret |= in[i]; - } - return ret; -} - -/* dtls1_bitmap_should_discard returns one if |seq_num| has been seen in |bitmap| - * or is stale. Otherwise it returns zero. */ -static int dtls1_bitmap_should_discard(DTLS1_BITMAP *bitmap, - const uint8_t seq_num[8]) { - const unsigned kWindowSize = sizeof(bitmap->map) * 8; - - uint64_t seq_num_u = to_u64_be(seq_num); - if (seq_num_u > bitmap->max_seq_num) { - return 0; - } - uint64_t idx = bitmap->max_seq_num - seq_num_u; - return idx >= kWindowSize || (bitmap->map & (((uint64_t)1) << idx)); -} - -/* dtls1_bitmap_record updates |bitmap| to record receipt of sequence number - * |seq_num|. It slides the window forward if needed. It is an error to call - * this function on a stale sequence number. */ -static void dtls1_bitmap_record(DTLS1_BITMAP *bitmap, - const uint8_t seq_num[8]) { - const unsigned kWindowSize = sizeof(bitmap->map) * 8; - - uint64_t seq_num_u = to_u64_be(seq_num); - /* Shift the window if necessary. */ - if (seq_num_u > bitmap->max_seq_num) { - uint64_t shift = seq_num_u - bitmap->max_seq_num; - if (shift >= kWindowSize) { - bitmap->map = 0; - } else { - bitmap->map <<= shift; - } - bitmap->max_seq_num = seq_num_u; - } - - uint64_t idx = bitmap->max_seq_num - seq_num_u; - if (idx < kWindowSize) { - bitmap->map |= ((uint64_t)1) << idx; - } -} - -enum ssl_open_record_t dtls_open_record( - SSL *ssl, uint8_t *out_type, uint8_t *out, size_t *out_len, - size_t *out_consumed, uint8_t *out_alert, size_t max_out, const uint8_t *in, - size_t in_len) { - CBS cbs; - CBS_init(&cbs, in, in_len); - - /* Decode the record. */ - uint8_t type; - uint16_t version; - uint8_t sequence[8]; - CBS body; - if (!CBS_get_u8(&cbs, &type) || - !CBS_get_u16(&cbs, &version) || - !CBS_copy_bytes(&cbs, sequence, 8) || - !CBS_get_u16_length_prefixed(&cbs, &body) || - (ssl->s3->have_version && version != ssl->version) || - (version >> 8) != DTLS1_VERSION_MAJOR || - CBS_len(&body) > SSL3_RT_MAX_ENCRYPTED_LENGTH) { - /* The record header was incomplete or malformed. Drop the entire packet. */ - *out_consumed = in_len; - return ssl_open_record_discard; - } - - if (ssl->msg_callback != NULL) { - ssl->msg_callback(0 /* read */, 0, SSL3_RT_HEADER, in, - DTLS1_RT_HEADER_LENGTH, ssl, ssl->msg_callback_arg); - } - - uint16_t epoch = (((uint16_t)sequence[0]) << 8) | sequence[1]; - if (epoch != ssl->d1->r_epoch || - dtls1_bitmap_should_discard(&ssl->d1->bitmap, sequence)) { - /* Drop this record. It's from the wrong epoch or is a replay. Note that if - * |epoch| is the next epoch, the record could be buffered for later. For - * simplicity, drop it and expect retransmit to handle it later; DTLS must - * handle packet loss anyway. */ - *out_consumed = in_len - CBS_len(&cbs); - return ssl_open_record_discard; - } - - /* Decrypt the body. */ - size_t plaintext_len; - if (!SSL_AEAD_CTX_open(ssl->aead_read_ctx, out, &plaintext_len, max_out, - type, version, sequence, CBS_data(&body), - CBS_len(&body))) { - /* Bad packets are silently dropped in DTLS. See section 4.2.1 of RFC 6347. - * Clear the error queue of any errors decryption may have added. Drop the - * entire packet as it must not have come from the peer. - * - * TODO(davidben): This doesn't distinguish malloc failures from encryption - * failures. */ - ERR_clear_error(); - *out_consumed = in_len - CBS_len(&cbs); - return ssl_open_record_discard; - } - - /* Check the plaintext length. */ - if (plaintext_len > SSL3_RT_MAX_PLAIN_LENGTH) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG); - *out_alert = SSL_AD_RECORD_OVERFLOW; - return ssl_open_record_error; - } - - dtls1_bitmap_record(&ssl->d1->bitmap, sequence); - - /* TODO(davidben): Limit the number of empty records as in TLS? This is only - * useful if we also limit discarded packets. */ - - *out_type = type; - *out_len = plaintext_len; - *out_consumed = in_len - CBS_len(&cbs); - return ssl_open_record_success; -} - -int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, - uint8_t type, const uint8_t *in, size_t in_len, - enum dtls1_use_epoch_t use_epoch) { - /* Determine the parameters for the current epoch. */ - uint16_t epoch = ssl->d1->w_epoch; - SSL_AEAD_CTX *aead = ssl->aead_write_ctx; - uint8_t *seq = ssl->s3->write_sequence; - if (use_epoch == dtls1_use_previous_epoch) { - /* DTLS renegotiation is unsupported, so only epochs 0 (NULL cipher) and 1 - * (negotiated cipher) exist. */ - assert(ssl->d1->w_epoch == 1); - epoch = ssl->d1->w_epoch - 1; - aead = NULL; - seq = ssl->d1->last_write_sequence; - } - - if (max_out < DTLS1_RT_HEADER_LENGTH) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); - return 0; - } - /* Check the record header does not alias any part of the input. - * |SSL_AEAD_CTX_seal| will internally enforce other aliasing requirements. */ - if (in < out + DTLS1_RT_HEADER_LENGTH && out < in + in_len) { - OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT); - return 0; - } - - out[0] = type; - - uint16_t wire_version = ssl->s3->have_version ? ssl->version : DTLS1_VERSION; - out[1] = wire_version >> 8; - out[2] = wire_version & 0xff; - - out[3] = epoch >> 8; - out[4] = epoch & 0xff; - memcpy(&out[5], &seq[2], 6); - - size_t ciphertext_len; - if (!SSL_AEAD_CTX_seal(aead, out + DTLS1_RT_HEADER_LENGTH, &ciphertext_len, - max_out - DTLS1_RT_HEADER_LENGTH, type, wire_version, - &out[3] /* seq */, in, in_len) || - !ssl3_record_sequence_update(&seq[2], 6)) { - return 0; - } - - if (ciphertext_len >= 1 << 16) { - OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); - return 0; - } - out[11] = ciphertext_len >> 8; - out[12] = ciphertext_len & 0xff; - - *out_len = DTLS1_RT_HEADER_LENGTH + ciphertext_len; - - if (ssl->msg_callback) { - ssl->msg_callback(1 /* write */, 0, SSL3_RT_HEADER, out, - DTLS1_RT_HEADER_LENGTH, ssl, ssl->msg_callback_arg); - } - - return 1; -} diff --git a/src/ssl/internal.h b/src/ssl/internal.h index 6fb8dbe..4d70431 100644 --- a/src/ssl/internal.h +++ b/src/ssl/internal.h @@ -182,7 +182,6 @@ #define SSL_AES128GCM 0x00000010L #define SSL_AES256GCM 0x00000020L #define SSL_CHACHA20POLY1305 0x00000040L -#define SSL_eNULL 0x00000080L #define SSL_AES (SSL_AES128 | SSL_AES256 | SSL_AES128GCM | SSL_AES256GCM) @@ -203,15 +202,25 @@ #define SSL_TLSV1 SSL_SSLV3 #define SSL_TLSV1_2 0x00000004L -/* Bits for |algorithm_prf| (handshake digest). */ -#define SSL_HANDSHAKE_MAC_DEFAULT 0x1 -#define SSL_HANDSHAKE_MAC_SHA256 0x2 -#define SSL_HANDSHAKE_MAC_SHA384 0x4 +/* Bits for |algorithm2| (handshake digests and other extra flags). */ + +#define SSL_HANDSHAKE_MAC_MD5 0x10 +#define SSL_HANDSHAKE_MAC_SHA 0x20 +#define SSL_HANDSHAKE_MAC_SHA256 0x40 +#define SSL_HANDSHAKE_MAC_SHA384 0x80 +#define SSL_HANDSHAKE_MAC_DEFAULT \ + (SSL_HANDSHAKE_MAC_MD5 | SSL_HANDSHAKE_MAC_SHA) /* SSL_MAX_DIGEST is the number of digest types which exist. When adding a new * one, update the table in ssl_cipher.c. */ #define SSL_MAX_DIGEST 4 +/* SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD is a flag in + * SSL_CIPHER.algorithm2 which indicates that the variable part of the nonce is + * included as a prefix of the record. (AES-GCM, for example, does with with an + * 8-byte variable nonce.) */ +#define SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD (1<<22) + /* Bits for |algo_strength|, cipher strength information. */ #define SSL_MEDIUM 0x00000001L #define SSL_HIGH 0x00000002L @@ -227,11 +236,11 @@ int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead, size_t *out_fixed_iv_len, const SSL_CIPHER *cipher, uint16_t version); -/* ssl_get_handshake_digest returns the |EVP_MD| corresponding to - * |algorithm_prf|. It returns SHA-1 for |SSL_HANDSHAKE_DEFAULT|. The caller is - * responsible for maintaining the additional MD5 digest and switching to - * SHA-256 in TLS 1.2. */ -const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf); +/* ssl_get_handshake_digest looks up the |i|th handshake digest type and sets + * |*out_mask| to the |SSL_HANDSHAKE_MAC_*| mask and |*out_md| to the + * |EVP_MD|. It returns one on successs and zero if |i| >= |SSL_MAX_DIGEST|. */ +int ssl_get_handshake_digest(uint32_t *out_mask, const EVP_MD **out_md, + size_t i); /* ssl_create_cipher_list evaluates |rule_str| according to the ciphers in * |ssl_method|. It sets |*out_cipher_list| to a newly-allocated @@ -245,12 +254,18 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, STACK_OF(SSL_CIPHER) **out_cipher_list_by_id, const char *rule_str); +/* SSL_PKEY_* denote certificate types. */ +#define SSL_PKEY_RSA_ENC 0 +#define SSL_PKEY_RSA_SIGN 1 +#define SSL_PKEY_ECC 2 +#define SSL_PKEY_NUM 3 + /* ssl_cipher_get_value returns the cipher suite id of |cipher|. */ uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher); -/* ssl_cipher_get_key_type returns the |EVP_PKEY_*| value corresponding to the - * 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_get_cert_index returns the |SSL_PKEY_*| value corresponding to the + * certificate type of |cipher| or -1 if there is none. */ +int ssl_cipher_get_cert_index(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. @@ -260,16 +275,11 @@ int ssl_cipher_has_server_public_key(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. */ + * Unlike ssl_cipher_has_server_public_key, some ciphers take optional + * ServerKeyExchanges. PSK and RSA_PSK only use the ServerKeyExchange to + * communicate a psk_identity_hint, so it is optional. */ 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 - * length of an encrypted 1-byte record, for use in record-splitting. Otherwise - * it returns zero. */ -size_t ssl_cipher_get_record_split_len(const SSL_CIPHER *cipher); - /* Encryption layer. */ @@ -340,238 +350,6 @@ int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, size_t in_len); -/* DTLS replay bitmap. */ - -/* DTLS1_BITMAP maintains a sliding window of 64 sequence numbers to detect - * replayed packets. It should be initialized by zeroing every field. */ -typedef struct dtls1_bitmap_st { - /* map is a bit mask of the last 64 sequence numbers. Bit - * |1<<i| corresponds to |max_seq_num - i|. */ - uint64_t map; - /* max_seq_num is the largest sequence number seen so far as a 64-bit - * integer. */ - uint64_t max_seq_num; -} DTLS1_BITMAP; - - -/* Record layer. */ - -/* ssl_record_prefix_len returns the length of the prefix before the ciphertext - * of a record for |ssl|. - * - * TODO(davidben): Expose this as part of public API once the high-level - * buffer-free APIs are available. */ -size_t ssl_record_prefix_len(const SSL *ssl); - -enum ssl_open_record_t { - ssl_open_record_success, - ssl_open_record_discard, - ssl_open_record_partial, - ssl_open_record_error, -}; - -/* tls_open_record decrypts a record from |in|. - * - * On success, it returns |ssl_open_record_success|. It sets |*out_type| to the - * record type, |*out_len| to the plaintext length, and writes the record body - * to |out|. It sets |*out_consumed| to the number of bytes of |in| consumed. - * Note that |*out_len| may be zero. - * - * If a record was successfully processed but should be discarded, it returns - * |ssl_open_record_discard| and sets |*out_consumed| to the number of bytes - * consumed. - * - * If the input did not contain a complete record, it returns - * |ssl_open_record_partial|. It sets |*out_consumed| to the total number of - * bytes necessary. It is guaranteed that a successful call to |tls_open_record| - * will consume at least that many bytes. - * - * On failure, it returns |ssl_open_record_error| and sets |*out_alert| to an - * alert to emit. - * - * If |in| and |out| alias, |out| must be <= |in| + |ssl_record_prefix_len|. */ -enum ssl_open_record_t tls_open_record( - SSL *ssl, uint8_t *out_type, uint8_t *out, size_t *out_len, - size_t *out_consumed, uint8_t *out_alert, size_t max_out, const uint8_t *in, - size_t in_len); - -/* dtls_open_record implements |tls_open_record| for DTLS. It never returns - * |ssl_open_record_partial| but otherwise behaves analogously. */ -enum ssl_open_record_t dtls_open_record( - SSL *ssl, uint8_t *out_type, uint8_t *out, size_t *out_len, - size_t *out_consumed, uint8_t *out_alert, size_t max_out, const uint8_t *in, - size_t in_len); - -/* ssl_seal_prefix_len returns the length of the prefix before the ciphertext - * when sealing a record with |ssl|. Note that this value may differ from - * |ssl_record_prefix_len| when TLS 1.0 CBC record-splitting is enabled. Sealing - * a small record may also result in a smaller output than this value. - * - * TODO(davidben): Expose this as part of public API once the high-level - * buffer-free APIs are available. */ -size_t ssl_seal_prefix_len(const SSL *ssl); - -/* ssl_max_seal_overhead returns the maximum overhead of sealing a record with - * |ssl|. This includes |ssl_seal_prefix_len|. - * - * TODO(davidben): Expose this as part of public API once the high-level - * buffer-free APIs are available. */ -size_t ssl_max_seal_overhead(const SSL *ssl); - -/* tls_seal_record seals a new record of type |type| and body |in| and writes it - * to |out|. At most |max_out| bytes will be written. It returns one on success - * and zero on error. If enabled, |tls_seal_record| implements TLS 1.0 CBC 1/n-1 - * record splitting and may write two records concatenated. - * - * For a large record, the ciphertext will begin |ssl_seal_prefix_len| bytes - * into out. Aligning |out| appropriately may improve performance. It writes at - * most |in_len| + |ssl_max_seal_overhead| bytes to |out|. - * - * If |in| and |out| alias, |out| + |ssl_seal_prefix_len| must be <= |in|. */ -int tls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, - uint8_t type, const uint8_t *in, size_t in_len); - -enum dtls1_use_epoch_t { - dtls1_use_previous_epoch, - dtls1_use_current_epoch, -}; - -/* dtls_seal_record implements |tls_seal_record| for DTLS. |use_epoch| selects - * which epoch's cipher state to use. */ -int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, - uint8_t type, const uint8_t *in, size_t in_len, - enum dtls1_use_epoch_t use_epoch); - - -/* Private key operations. */ - -/* ssl_has_private_key returns one if |ssl| has a private key - * configured and zero otherwise. */ -int ssl_has_private_key(SSL *ssl); - -/* ssl_private_key_* call the corresponding function on the - * |SSL_PRIVATE_KEY_METHOD| for |ssl|, if configured. Otherwise, they implement - * the operation with |EVP_PKEY|. */ - -int ssl_private_key_type(SSL *ssl); - -size_t ssl_private_key_max_signature_len(SSL *ssl); - -enum ssl_private_key_result_t ssl_private_key_sign( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, const EVP_MD *md, - const uint8_t *in, size_t in_len); - -enum ssl_private_key_result_t ssl_private_key_sign_complete( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out); - - -/* Custom extensions */ - -/* ssl_custom_extension (a.k.a. SSL_CUSTOM_EXTENSION) is a structure that - * contains information about custom-extension callbacks. */ -struct ssl_custom_extension { - SSL_custom_ext_add_cb add_callback; - void *add_arg; - SSL_custom_ext_free_cb free_callback; - SSL_custom_ext_parse_cb parse_callback; - void *parse_arg; - uint16_t value; -}; - -void SSL_CUSTOM_EXTENSION_free(SSL_CUSTOM_EXTENSION *custom_extension); - -int custom_ext_add_clienthello(SSL *ssl, CBB *extensions); -int custom_ext_parse_serverhello(SSL *ssl, int *out_alert, uint16_t value, - const CBS *extension); -int custom_ext_parse_clienthello(SSL *ssl, int *out_alert, uint16_t value, - const CBS *extension); -int custom_ext_add_serverhello(SSL *ssl, CBB *extensions); - - -/* Handshake hash. - * - * The TLS handshake maintains a transcript of all handshake messages. At - * various points in the protocol, this is either a handshake buffer, a rolling - * hash (selected by cipher suite) or both. */ - -/* ssl3_init_handshake_buffer initializes the handshake buffer and resets the - * handshake hash. It returns one success and zero on failure. */ -int ssl3_init_handshake_buffer(SSL *ssl); - -/* ssl3_init_handshake_hash initializes the handshake hash based on the pending - * cipher and the contents of the handshake buffer. Subsequent calls to - * |ssl3_update_handshake_hash| will update the rolling hash. It returns one on - * success and zero on failure. It is an error to call this function after the - * handshake buffer is released. */ -int ssl3_init_handshake_hash(SSL *ssl); - -/* ssl3_free_handshake_buffer releases the handshake buffer. Subsequent calls - * to |ssl3_update_handshake_hash| will not update the handshake buffer. */ -void ssl3_free_handshake_buffer(SSL *ssl); - -/* ssl3_free_handshake_hash releases the handshake hash. */ -void ssl3_free_handshake_hash(SSL *s); - -/* ssl3_update_handshake_hash adds |in| to the handshake buffer and handshake - * hash, whichever is enabled. It returns one on success and zero on failure. */ -int ssl3_update_handshake_hash(SSL *ssl, const uint8_t *in, size_t in_len); - - -/* Transport buffers. */ - -/* ssl_read_buffer returns a pointer to contents of the read buffer. */ -uint8_t *ssl_read_buffer(SSL *ssl); - -/* ssl_read_buffer_len returns the length of the read buffer. */ -size_t ssl_read_buffer_len(const SSL *ssl); - -/* ssl_read_buffer_extend_to extends the read buffer to the desired length. For - * TLS, it reads to the end of the buffer until the buffer is |len| bytes - * long. For DTLS, it reads a new packet and ignores |len|. It returns one on - * success, zero on EOF, and a negative number on error. - * - * It is an error to call |ssl_read_buffer_extend_to| in DTLS when the buffer is - * non-empty. */ -int ssl_read_buffer_extend_to(SSL *ssl, size_t len); - -/* ssl_read_buffer_consume consumes |len| bytes from the read buffer. It - * advances the data pointer and decrements the length. The memory consumed will - * remain valid until the next call to |ssl_read_buffer_extend| or it is - * discarded with |ssl_read_buffer_discard|. */ -void ssl_read_buffer_consume(SSL *ssl, size_t len); - -/* ssl_read_buffer_discard discards the consumed bytes from the read buffer. If - * the buffer is now empty, it releases memory used by it. */ -void ssl_read_buffer_discard(SSL *ssl); - -/* ssl_read_buffer_clear releases all memory associated with the read buffer and - * zero-initializes it. */ -void ssl_read_buffer_clear(SSL *ssl); - -/* ssl_write_buffer_is_pending returns one if the write buffer has pending data - * and zero if is empty. */ -int ssl_write_buffer_is_pending(const SSL *ssl); - -/* ssl_write_buffer_init initializes the write buffer. On success, it sets - * |*out_ptr| to the start of the write buffer with space for up to |max_len| - * bytes. It returns one on success and zero on failure. Call - * |ssl_write_buffer_set_len| to complete initialization. */ -int ssl_write_buffer_init(SSL *ssl, uint8_t **out_ptr, size_t max_len); - -/* ssl_write_buffer_set_len is called after |ssl_write_buffer_init| to complete - * initialization after |len| bytes are written to the buffer. */ -void ssl_write_buffer_set_len(SSL *ssl, size_t len); - -/* ssl_write_buffer_flush flushes the write buffer to the transport. It returns - * one on success and <= 0 on error. For DTLS, whether or not the write - * succeeds, the write buffer will be cleared. */ -int ssl_write_buffer_flush(SSL *ssl); - -/* ssl_write_buffer_clear releases all memory associated with the write buffer - * and zero-initializes it. */ -void ssl_write_buffer_clear(SSL *ssl); - - /* Underdocumented functions. * * Functions below here haven't been touched up and may be underdocumented. */ @@ -705,6 +483,8 @@ void ssl_write_buffer_clear(SSL *ssl); * SSL_aRSA <- RSA_ENC | RSA_SIGN * SSL_aDSS <- DSA_SIGN */ +#define PENDING_SESSION -10000 + /* From RFC4492, used in encoding the curve type in ECParameters */ #define EXPLICIT_PRIME_CURVE_TYPE 1 #define EXPLICIT_CHAR2_CURVE_TYPE 2 @@ -715,21 +495,18 @@ enum ssl_hash_message_t { ssl_hash_message, }; -/* Structure containing decoded values of signature algorithms extension */ -typedef struct tls_sigalgs_st { - uint8_t rsign; - uint8_t rhash; -} TLS_SIGALGS; - -typedef struct cert_st { +typedef struct cert_pkey_st { X509 *x509; EVP_PKEY *privatekey; /* Chain for this certificate */ STACK_OF(X509) *chain; +} CERT_PKEY; - /* key_method, if non-NULL, is a set of callbacks to call for private key - * operations. */ - const SSL_PRIVATE_KEY_METHOD *key_method; +typedef struct cert_st { + /* Current active set */ + CERT_PKEY *key; /* ALWAYS points to an element of the pkeys array + * Probably it would make more sense to store + * an index, not a pointer. */ /* For clients the following masks are of *disabled* key and auth algorithms * based on the current session. @@ -754,18 +531,39 @@ typedef struct cert_st { * keys. If NULL, a curve is selected automatically. See * |SSL_CTX_set_tmp_ecdh_callback|. */ EC_KEY *(*ecdh_tmp_cb)(SSL *ssl, int is_export, int keysize); - - /* peer_sigalgs are the algorithm/hash pairs that the peer supports. These - * are taken from the contents of signature algorithms extension for a server - * or from the CertificateRequest for a client. */ - TLS_SIGALGS *peer_sigalgs; - /* peer_sigalgslen is the number of entries in |peer_sigalgs|. */ + CERT_PKEY pkeys[SSL_PKEY_NUM]; + + /* Server-only: client_certificate_types is list of certificate types to + * include in the CertificateRequest message. + */ + uint8_t *client_certificate_types; + size_t num_client_certificate_types; + + /* signature algorithms peer reports: e.g. supported signature + * algorithms extension for server or as part of a certificate + * request for client. */ + uint8_t *peer_sigalgs; + /* Size of above array */ size_t peer_sigalgslen; - - /* digest_nids, if non-NULL, is the set of digests supported by |privatekey| - * in decreasing order of preference. */ - int *digest_nids; - size_t num_digest_nids; + /* suppported signature algorithms. + * When set on a client this is sent in the client hello as the + * supported signature algorithms extension. For servers + * it represents the signature algorithms we are willing to use. */ + uint8_t *conf_sigalgs; + /* Size of above array */ + size_t conf_sigalgslen; + /* Client authentication signature algorithms, if not set then + * uses conf_sigalgs. On servers these will be the signature + * algorithms sent to the client in a cerificate request for TLS 1.2. + * On a client this represents the signature algortithms we are + * willing to use for client authentication. */ + uint8_t *client_sigalgs; + /* Size of above array */ + size_t client_sigalgslen; + /* Signature algorithms shared by client and server: cached + * because these are used most often. */ + TLS_SIGALGS *shared_sigalgs; + size_t shared_sigalgslen; /* Certificate setup callback: if set is called whenever a * certificate may be required (client or server). the callback @@ -775,8 +573,39 @@ typedef struct cert_st { * supported signature algorithms or curves. */ int (*cert_cb)(SSL *ssl, void *arg); void *cert_cb_arg; + + /* Optional X509_STORE for chain building or certificate validation + * If NULL the parent SSL_CTX store is used instead. */ + X509_STORE *chain_store; + X509_STORE *verify_store; } CERT; +typedef struct sess_cert_st { + /* cert_chain is the certificate chain sent by the peer. NOTE: for a client, + * this does includes the server's leaf certificate, but, for a server, this + * does NOT include the client's leaf. */ + STACK_OF(X509) *cert_chain; + + /* peer_cert, on a client, is the leaf certificate of the peer. */ + X509 *peer_cert; + + DH *peer_dh_tmp; + EC_KEY *peer_ecdh_tmp; +} SESS_CERT; + +/* Structure containing decoded values of signature algorithms extension */ +struct tls_sigalgs_st { + /* NID of hash algorithm */ + int hash_nid; + /* NID of signature algorithm */ + int sign_nid; + /* Combined hash and signature NID */ + int signandhash_nid; + /* Raw values used in extension */ + uint8_t rsign; + uint8_t rhash; +}; + /* SSL_METHOD is a compatibility structure to support the legacy version-locked * methods. */ struct ssl_method_st { @@ -803,6 +632,8 @@ struct ssl_protocol_method_st { void (*ssl_read_close_notify)(SSL *s); int (*ssl_write_app_data)(SSL *s, const void *buf_, int len); int (*ssl_dispatch_alert)(SSL *s); + long (*ssl_ctrl)(SSL *s, int cmd, long larg, void *parg); + long (*ssl_ctx_ctrl)(SSL_CTX *ctx, int cmd, long larg, void *parg); /* supports_cipher returns one if |cipher| is supported by this protocol and * zero otherwise. */ int (*supports_cipher)(const SSL_CIPHER *cipher); @@ -865,6 +696,15 @@ struct ssl3_enc_method { #define DTLS1_AL_HEADER_LENGTH 2 +typedef struct dtls1_bitmap_st { + /* map is a bit mask of the last 64 sequence numbers. Bit + * |1<<i| corresponds to |max_seq_num - i|. */ + uint64_t map; + /* max_seq_num is the largest sequence number seen so far. It + * is a 64-bit value in big-endian encoding. */ + uint8_t max_seq_num[8]; +} DTLS1_BITMAP; + /* TODO(davidben): This structure is used for both incoming messages and * outgoing messages. |is_ccs| and |epoch| are only used in the latter and * should be moved elsewhere. */ @@ -949,7 +789,6 @@ extern const SSL3_ENC_METHOD TLSv1_enc_data; extern const SSL3_ENC_METHOD TLSv1_1_enc_data; extern const SSL3_ENC_METHOD TLSv1_2_enc_data; extern const SSL3_ENC_METHOD SSLv3_enc_data; -extern const SRTP_PROTECTION_PROFILE kSRTPProfiles[]; void ssl_clear_cipher_ctx(SSL *s); int ssl_clear_bad_session(SSL *s); @@ -957,24 +796,11 @@ CERT *ssl_cert_new(void); CERT *ssl_cert_dup(CERT *cert); void ssl_cert_clear_certs(CERT *c); void ssl_cert_free(CERT *c); +SESS_CERT *ssl_sess_cert_new(void); +SESS_CERT *ssl_sess_cert_dup(const SESS_CERT *sess_cert); +void ssl_sess_cert_free(SESS_CERT *sess_cert); int ssl_get_new_session(SSL *s, int session); - -enum ssl_session_result_t { - ssl_session_success, - ssl_session_error, - ssl_session_retry, -}; - -/* ssl_get_prev_session looks up the previous session based on |ctx|. On - * success, it sets |*out_session| to the session or NULL if none was found. It - * sets |*out_send_ticket| to whether a ticket should be sent at the end of the - * handshake. If the session could not be looked up synchronously, it returns - * |ssl_session_retry| and should be called again. Otherwise, it returns - * |ssl_session_error|. */ -enum ssl_session_result_t ssl_get_prev_session( - SSL *ssl, SSL_SESSION **out_session, int *out_send_ticket, - const struct ssl_early_callback_ctx *ctx); - +int ssl_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx); STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs); int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, uint8_t *p); struct ssl_cipher_preference_list_st *ssl_cipher_preference_list_dup( @@ -985,16 +811,21 @@ struct ssl_cipher_preference_list_st *ssl_cipher_preference_list_from_ciphers( STACK_OF(SSL_CIPHER) *ciphers); struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *s); -int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain); -int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain); -int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509); -int ssl_cert_add1_chain_cert(CERT *cert, X509 *x509); -void ssl_cert_set_cert_cb(CERT *cert, - int (*cb)(SSL *ssl, void *arg), void *arg); - -int ssl_verify_cert_chain(SSL *ssl, STACK_OF(X509) *cert_chain); -int ssl_add_cert_chain(SSL *s, unsigned long *l); +int ssl_cert_set0_chain(CERT *c, STACK_OF(X509) *chain); +int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain); +int ssl_cert_add0_chain_cert(CERT *c, X509 *x); +int ssl_cert_add1_chain_cert(CERT *c, X509 *x); +int ssl_cert_select_current(CERT *c, X509 *x); +void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg), void *arg); + +int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk); +int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l); +int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags); +int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref); +CERT_PKEY *ssl_get_server_send_pkey(const SSL *s); +EVP_PKEY *ssl_get_sign_pkey(SSL *s, const SSL_CIPHER *c); void ssl_update_cache(SSL *s, int mode); +int ssl_cert_type(EVP_PKEY *pkey); /* ssl_get_compatible_server_ciphers determines the key exchange and * authentication cipher suite masks compatible with the server configuration @@ -1010,9 +841,10 @@ int ssl_verify_alarm_type(long type); * |len|. It returns one on success and zero on failure. */ int ssl_fill_hello_random(uint8_t *out, size_t len, int is_server); +int ssl3_init_finished_mac(SSL *s); int ssl3_send_server_certificate(SSL *s); int ssl3_send_new_session_ticket(SSL *s); -int ssl3_send_certificate_status(SSL *s); +int ssl3_send_cert_status(SSL *s); int ssl3_get_finished(SSL *s, int state_a, int state_b); int ssl3_send_change_cipher_spec(SSL *s, int state_a, int state_b); int ssl3_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret, @@ -1033,11 +865,11 @@ int ssl3_hash_current_message(SSL *s); /* ssl3_cert_verify_hash writes the CertificateVerify hash into the bytes * pointed to by |out| and writes the number of bytes to |*out_len|. |out| must * have room for EVP_MAX_MD_SIZE bytes. For TLS 1.2 and up, |*out_md| is used - * for the hash function, otherwise the hash function depends on |pkey_type| - * and is written to |*out_md|. It returns one on success and zero on + * for the hash function, otherwise the hash function depends on the type of + * |pkey| and is written to |*out_md|. It returns one on success and zero on * failure. */ int ssl3_cert_verify_hash(SSL *s, uint8_t *out, size_t *out_len, - const EVP_MD **out_md, int pkey_type); + const EVP_MD **out_md, EVP_PKEY *pkey); int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen); int ssl3_supports_cipher(const SSL_CIPHER *cipher); @@ -1050,15 +882,29 @@ int ssl3_write_app_data(SSL *ssl, const void *buf, int len); int ssl3_write_bytes(SSL *s, int type, const void *buf, int len); int ssl3_final_finish_mac(SSL *s, const char *sender, int slen, uint8_t *p); int ssl3_cert_verify_mac(SSL *s, int md_nid, uint8_t *p); -int ssl3_output_cert_chain(SSL *s); +int ssl3_finish_mac(SSL *s, const uint8_t *buf, int len); +void ssl3_free_digest_list(SSL *s); +int ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk); const SSL_CIPHER *ssl3_choose_cipher( SSL *ssl, STACK_OF(SSL_CIPHER) *clnt, struct ssl_cipher_preference_list_st *srvr); +int ssl3_setup_read_buffer(SSL *s); +int ssl3_setup_write_buffer(SSL *s); +int ssl3_release_read_buffer(SSL *s); +int ssl3_release_write_buffer(SSL *s); + +enum should_free_handshake_buffer_t { + free_handshake_buffer, + dont_free_handshake_buffer, +}; +int ssl3_digest_cached_records(SSL *s, enum should_free_handshake_buffer_t); int ssl3_new(SSL *s); void ssl3_free(SSL *s); int ssl3_accept(SSL *s); int ssl3_connect(SSL *s); +long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg); +long ssl3_ctx_ctrl(SSL_CTX *s, int cmd, long larg, void *parg); /* ssl3_record_sequence_update increments the sequence number in |seq|. It * returns one on success and zero on wraparound. */ @@ -1069,7 +915,13 @@ int ssl3_do_change_cipher_spec(SSL *ssl); int ssl3_set_handshake_header(SSL *s, int htype, unsigned long len); int ssl3_handshake_write(SSL *s); +enum dtls1_use_epoch_t { + dtls1_use_previous_epoch, + dtls1_use_current_epoch, +}; + int dtls1_do_write(SSL *s, int type, enum dtls1_use_epoch_t use_epoch); +int ssl3_read_n(SSL *s, int n, int extend); int dtls1_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek); void dtls1_read_close_notify(SSL *ssl); int dtls1_read_bytes(SSL *s, int type, uint8_t *buf, int len, int peek); @@ -1116,9 +968,11 @@ int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey); int ssl3_send_client_key_exchange(SSL *s); int ssl3_get_server_key_exchange(SSL *s); int ssl3_get_server_certificate(SSL *s); +int ssl3_check_cert_and_algorithm(SSL *s); int ssl3_send_next_proto(SSL *s); int ssl3_send_channel_id(SSL *s); -int ssl3_verify_server_cert(SSL *s); + +int dtls1_client_hello(SSL *s); /* some server-only functions */ int ssl3_get_initial_bytes(SSL *s); @@ -1141,6 +995,7 @@ void dtls1_free(SSL *s); long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, enum ssl_hash_message_t hash_message, int *ok); +int dtls1_get_record(SSL *s); int dtls1_dispatch_alert(SSL *s); int ssl_init_wbio_buffer(SSL *s, int push); @@ -1170,15 +1025,12 @@ int tls1_export_keying_material(SSL *s, uint8_t *out, size_t out_len, int tls1_alert_code(int code); int ssl3_alert_code(int code); +int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s); + char ssl_early_callback_init(struct ssl_early_callback_ctx *ctx); int tls1_ec_curve_id2nid(uint16_t curve_id); int tls1_ec_nid2curve_id(uint16_t *out_curve_id, int nid); -/* tls1_ec_curve_id2name returns a human-readable name for the - * curve specified by the TLS curve id in |curve_id|. If the - * curve is unknown, it returns NULL. */ -const char* tls1_ec_curve_id2name(uint16_t curve_id); - /* tls1_check_curve parses ECParameters out of |cbs|, modifying it. It * checks the curve is one of our preferences and writes the * NamedCurve value to |*out_curve_id|. It returns one on success and @@ -1208,39 +1060,28 @@ int tls1_check_ec_tmp_key(SSL *s); int tls1_shared_list(SSL *s, const uint8_t *l1, size_t l1len, const uint8_t *l2, size_t l2len, int nmatch); -uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *const buf, - uint8_t *const limit, size_t header_len); -uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *const buf, - uint8_t *const limit); +uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit, + size_t header_len); +uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit); int ssl_parse_clienthello_tlsext(SSL *s, CBS *cbs); int ssl_parse_serverhello_tlsext(SSL *s, CBS *cbs); +int ssl_prepare_clienthello_tlsext(SSL *s); +int ssl_prepare_serverhello_tlsext(SSL *s); #define tlsext_tick_md EVP_sha256 +int tls1_process_ticket(SSL *s, const struct ssl_early_callback_ctx *ctx, + SSL_SESSION **ret); -/* tls_process_ticket processes the session ticket extension. On success, it - * sets |*out_session| to the decrypted session or NULL if the ticket was - * rejected. It sets |*out_send_ticket| to whether a new ticket should be sent - * at the end of the handshake. It returns one on success and zero on fatal - * error. */ -int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, - int *out_send_ticket, const uint8_t *ticket, - size_t ticket_len, const uint8_t *session_id, - size_t session_id_len); - -/* tls12_get_sigandhash assembles the SignatureAndHashAlgorithm corresponding to - * |ssl|'s private key and |md|. The two-byte value is written to |p|. It - * returns one on success and zero on failure. */ -int tls12_get_sigandhash(SSL *ssl, uint8_t *p, const EVP_MD *md); -int tls12_get_sigid(int pkey_type); +int tls12_get_sigandhash(uint8_t *p, const EVP_PKEY *pk, const EVP_MD *md); +int tls12_get_sigid(const EVP_PKEY *pk); const EVP_MD *tls12_get_hash(uint8_t hash_alg); -/* tls1_channel_id_hash computes the hash to be signed by Channel ID and writes - * it to |out|, which must contain at least |EVP_MAX_MD_SIZE| bytes. It returns - * one on success and zero on failure. */ -int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len); - +int tls1_channel_id_hash(EVP_MD_CTX *ctx, SSL *s); int tls1_record_handshake_hashes_for_channel_id(SSL *s); +int tls1_set_sigalgs_list(CERT *c, const char *str, int client); +int tls1_set_sigalgs(CERT *c, const int *salg, size_t salglen, int client); + /* ssl_ctx_log_rsa_client_key_exchange logs |premaster| to |ctx|, if logging is * enabled. It returns one on success and zero on failure. The entry is * identified by the first 8 bytes of |encrypted_premaster|. */ @@ -1293,16 +1134,27 @@ int ssl3_is_version_enabled(SSL *s, uint16_t version); * the wire version except at API boundaries. */ uint16_t ssl3_version_from_wire(SSL *s, uint16_t wire_version); -uint32_t ssl_get_algorithm_prf(SSL *s); -int tls1_parse_peer_sigalgs(SSL *s, const CBS *sigalgs); +int ssl_add_serverhello_renegotiate_ext(SSL *s, uint8_t *p, int *len, + int maxlen); +int ssl_parse_serverhello_renegotiate_ext(SSL *s, CBS *cbs, int *out_alert); +int ssl_add_clienthello_renegotiate_ext(SSL *s, uint8_t *p, int *len, + int maxlen); +int ssl_parse_clienthello_renegotiate_ext(SSL *s, CBS *cbs, int *out_alert); +uint32_t ssl_get_algorithm2(SSL *s); +int tls1_process_sigalgs(SSL *s, const CBS *sigalgs); -/* tls1_choose_signing_digest returns a digest for use with |ssl|'s private key - * based on the peer's preferences the digests supported. */ -const EVP_MD *tls1_choose_signing_digest(SSL *ssl); +/* tls1_choose_signing_digest returns a digest for use with |pkey| based on the + * peer's preferences recorded for |s| and the digests supported by |pkey|. */ +const EVP_MD *tls1_choose_signing_digest(SSL *s, EVP_PKEY *pkey); size_t tls12_get_psigalgs(SSL *s, const uint8_t **psigs); int tls12_check_peer_sigalg(const EVP_MD **out_md, int *out_alert, SSL *s, CBS *cbs, EVP_PKEY *pkey); void ssl_set_client_disabled(SSL *s); +int ssl_add_clienthello_use_srtp_ext(SSL *s, uint8_t *p, int *len, int maxlen); +int ssl_parse_clienthello_use_srtp_ext(SSL *s, CBS *cbs, int *out_alert); +int ssl_add_serverhello_use_srtp_ext(SSL *s, uint8_t *p, int *len, int maxlen); +int ssl_parse_serverhello_use_srtp_ext(SSL *s, CBS *cbs, int *out_alert); + #endif /* OPENSSL_HEADER_SSL_INTERNAL_H */ diff --git a/src/ssl/s3_both.c b/src/ssl/s3_both.c index 31e36c7..06338b7 100644 --- a/src/ssl/s3_both.c +++ b/src/ssl/s3_both.c @@ -110,8 +110,6 @@ * ECC cipher suite support in OpenSSL originally developed by * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. */ -#include <openssl/ssl.h> - #include <assert.h> #include <limits.h> #include <stdio.h> @@ -244,7 +242,7 @@ int ssl3_get_finished(SSL *s, int a, int b) { * TODO(davidben): Is this check now redundant with SSL3_FLAGS_EXPECT_CCS? */ if (!s->s3->change_cipher_spec) { al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_GOT_A_FIN_BEFORE_A_CCS); + OPENSSL_PUT_ERROR(SSL, ssl3_get_finished, SSL_R_GOT_A_FIN_BEFORE_A_CCS); goto f_err; } s->s3->change_cipher_spec = 0; @@ -254,13 +252,13 @@ int ssl3_get_finished(SSL *s, int a, int b) { if (finished_len != message_len) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_DIGEST_LENGTH); + OPENSSL_PUT_ERROR(SSL, ssl3_get_finished, SSL_R_BAD_DIGEST_LENGTH); goto f_err; } if (CRYPTO_memcmp(p, s->s3->tmp.peer_finish_md, finished_len) != 0) { al = SSL_AD_DECRYPT_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED); + OPENSSL_PUT_ERROR(SSL, ssl3_get_finished, SSL_R_DIGEST_CHECK_FAILED); goto f_err; } @@ -303,11 +301,17 @@ int ssl3_send_change_cipher_spec(SSL *s, int a, int b) { return ssl3_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC); } -int ssl3_output_cert_chain(SSL *s) { +int ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk) { uint8_t *p; unsigned long l = 3 + SSL_HM_HEADER_LENGTH(s); - if (!ssl_add_cert_chain(s, &l)) { + if (cpk == NULL) { + /* TLSv1 sends a chain with nothing in it, instead of an alert. */ + if (!BUF_MEM_grow_clean(s->init_buf, l)) { + OPENSSL_PUT_ERROR(SSL, ssl3_output_cert_chain, ERR_R_BUF_LIB); + return 0; + } + } else if (!ssl_add_cert_chain(s, cpk, &l)) { return 0; } @@ -336,7 +340,7 @@ long ssl3_get_message(SSL *s, int header_state, int body_state, int msg_type, s->s3->tmp.reuse_message = 0; if (msg_type >= 0 && s->s3->tmp.message_type != msg_type) { al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_message, SSL_R_UNEXPECTED_MESSAGE); goto f_err; } *ok = 1; @@ -382,7 +386,7 @@ long ssl3_get_message(SSL *s, int header_state, int body_state, int msg_type, if (msg_type >= 0 && *p != msg_type) { al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_message, SSL_R_UNEXPECTED_MESSAGE); goto f_err; } s->s3->tmp.message_type = *(p++); @@ -390,12 +394,12 @@ long ssl3_get_message(SSL *s, int header_state, int body_state, int msg_type, n2l3(p, l); if (l > (unsigned long)max) { al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_message, SSL_R_EXCESSIVE_MESSAGE_SIZE); goto f_err; } if (l && !BUF_MEM_grow_clean(s->init_buf, l + 4)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_get_message, ERR_R_BUF_LIB); goto err; } s->s3->tmp.message_size = l; @@ -443,8 +447,8 @@ int ssl3_hash_current_message(SSL *s) { /* The handshake header (different size between DTLS and TLS) is included in * the hash. */ size_t header_len = s->init_msg - (uint8_t *)s->init_buf->data; - return ssl3_update_handshake_hash(s, (uint8_t *)s->init_buf->data, - s->init_num + header_len); + return ssl3_finish_mac(s, (uint8_t *)s->init_buf->data, + s->init_num + header_len); } /* ssl3_cert_verify_hash is documented as needing EVP_MAX_MD_SIZE because that @@ -453,25 +457,30 @@ OPENSSL_COMPILE_ASSERT(EVP_MAX_MD_SIZE > MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, combined_tls_hash_fits_in_max); int ssl3_cert_verify_hash(SSL *s, uint8_t *out, size_t *out_len, - const EVP_MD **out_md, int pkey_type) { + const EVP_MD **out_md, EVP_PKEY *pkey) { /* For TLS v1.2 send signature algorithm and signature using * agreed digest and cached handshake records. Otherwise, use * SHA1 or MD5 + SHA1 depending on key type. */ if (SSL_USE_SIGALGS(s)) { + const uint8_t *hdata; + size_t hdatalen; EVP_MD_CTX mctx; unsigned len; + if (!BIO_mem_contents(s->s3->handshake_buffer, &hdata, &hdatalen)) { + OPENSSL_PUT_ERROR(SSL, ssl3_cert_verify_hash, ERR_R_INTERNAL_ERROR); + return 0; + } EVP_MD_CTX_init(&mctx); if (!EVP_DigestInit_ex(&mctx, *out_md, NULL) || - !EVP_DigestUpdate(&mctx, s->s3->handshake_buffer->data, - s->s3->handshake_buffer->length) || + !EVP_DigestUpdate(&mctx, hdata, hdatalen) || !EVP_DigestFinal(&mctx, out, &len)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_EVP_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_cert_verify_hash, ERR_R_EVP_LIB); EVP_MD_CTX_cleanup(&mctx); return 0; } *out_len = len; - } else if (pkey_type == EVP_PKEY_RSA) { + } else if (pkey->type == EVP_PKEY_RSA) { if (s->enc_method->cert_verify_mac(s, NID_md5, out) == 0 || s->enc_method->cert_verify_mac(s, NID_sha1, out + MD5_DIGEST_LENGTH) == 0) { @@ -479,20 +488,31 @@ int ssl3_cert_verify_hash(SSL *s, uint8_t *out, size_t *out_len, } *out_len = MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH; *out_md = EVP_md5_sha1(); - } else if (pkey_type == EVP_PKEY_EC) { + } else if (pkey->type == EVP_PKEY_EC) { if (s->enc_method->cert_verify_mac(s, NID_sha1, out) == 0) { return 0; } *out_len = SHA_DIGEST_LENGTH; *out_md = EVP_sha1(); } else { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_cert_verify_hash, ERR_R_INTERNAL_ERROR); return 0; } return 1; } +int ssl_cert_type(EVP_PKEY *pkey) { + switch (pkey->type) { + case EVP_PKEY_RSA: + return SSL_PKEY_RSA_ENC; + case EVP_PKEY_EC: + return SSL_PKEY_ECC; + default: + return -1; + } +} + int ssl_verify_alarm_type(long type) { int al; @@ -561,6 +581,92 @@ int ssl_verify_alarm_type(long type) { return al; } +int ssl3_setup_read_buffer(SSL *s) { + uint8_t *p; + size_t len, align = 0, headerlen; + + if (SSL_IS_DTLS(s)) { + headerlen = DTLS1_RT_HEADER_LENGTH; + } else { + headerlen = SSL3_RT_HEADER_LENGTH; + } + +#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD != 0 + align = (-SSL3_RT_HEADER_LENGTH) & (SSL3_ALIGN_PAYLOAD - 1); +#endif + + if (s->s3->rbuf.buf == NULL) { + len = SSL3_RT_MAX_ENCRYPTED_LENGTH + headerlen + align; + if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) { + s->s3->init_extra = 1; + len += SSL3_RT_MAX_EXTRA; + } + p = OPENSSL_malloc(len); + if (p == NULL) { + goto err; + } + s->s3->rbuf.buf = p; + s->s3->rbuf.len = len; + } + + s->packet = &s->s3->rbuf.buf[0]; + return 1; + +err: + OPENSSL_PUT_ERROR(SSL, ssl3_setup_read_buffer, ERR_R_MALLOC_FAILURE); + return 0; +} + +int ssl3_setup_write_buffer(SSL *s) { + uint8_t *p; + size_t len, align = 0, headerlen; + + if (SSL_IS_DTLS(s)) { + headerlen = DTLS1_RT_HEADER_LENGTH + 1; + } else { + headerlen = SSL3_RT_HEADER_LENGTH; + } + +#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD != 0 + align = (-SSL3_RT_HEADER_LENGTH) & (SSL3_ALIGN_PAYLOAD - 1); +#endif + + if (s->s3->wbuf.buf == NULL) { + len = s->max_send_fragment + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD + + headerlen + align; + /* Account for 1/n-1 record splitting. */ + if (s->mode & SSL_MODE_CBC_RECORD_SPLITTING) { + len += headerlen + align + 1 + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD; + } + + p = OPENSSL_malloc(len); + if (p == NULL) { + goto err; + } + s->s3->wbuf.buf = p; + s->s3->wbuf.len = len; + } + + return 1; + +err: + OPENSSL_PUT_ERROR(SSL, ssl3_setup_write_buffer, ERR_R_MALLOC_FAILURE); + return 0; +} + +int ssl3_release_write_buffer(SSL *s) { + OPENSSL_free(s->s3->wbuf.buf); + s->s3->wbuf.buf = NULL; + return 1; +} + +int ssl3_release_read_buffer(SSL *s) { + OPENSSL_free(s->s3->rbuf.buf); + s->s3->rbuf.buf = NULL; + s->packet = NULL; + return 1; +} + int ssl_fill_hello_random(uint8_t *out, size_t len, int is_server) { if (is_server) { const uint32_t current_time = time(NULL); diff --git a/src/ssl/s3_clnt.c b/src/ssl/s3_clnt.c index 559db72..d334e1d 100644 --- a/src/ssl/s3_clnt.c +++ b/src/ssl/s3_clnt.c @@ -148,26 +148,21 @@ * OTHERWISE. */ -#include <openssl/ssl.h> - #include <assert.h> #include <stdio.h> #include <string.h> -#include <openssl/bn.h> #include <openssl/buf.h> #include <openssl/bytestring.h> -#include <openssl/dh.h> -#include <openssl/ec_key.h> -#include <openssl/ecdsa.h> +#include <openssl/rand.h> +#include <openssl/obj.h> #include <openssl/err.h> #include <openssl/evp.h> -#include <openssl/md5.h> #include <openssl/mem.h> -#include <openssl/obj.h> -#include <openssl/rand.h> +#include <openssl/md5.h> +#include <openssl/dh.h> +#include <openssl/bn.h> #include <openssl/x509.h> -#include <openssl/x509v3.h> #include "internal.h" #include "../crypto/dh/internal.h" @@ -222,8 +217,8 @@ int ssl3_connect(SSL *s) { /* don't push the buffering BIO quite yet */ - if (!ssl3_init_handshake_buffer(s)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + if (!ssl3_init_finished_mac(s)) { + OPENSSL_PUT_ERROR(SSL, ssl3_connect, ERR_R_INTERNAL_ERROR); ret = -1; goto end; } @@ -278,7 +273,7 @@ int ssl3_connect(SSL *s) { if (s->s3->tmp.certificate_status_expected) { s->state = SSL3_ST_CR_CERT_STATUS_A; } else { - s->state = SSL3_ST_VERIFY_SERVER_CERT; + s->state = SSL3_ST_CR_KEY_EXCH_A; } } else { skip = 1; @@ -287,16 +282,6 @@ int ssl3_connect(SSL *s) { s->init_num = 0; break; - case SSL3_ST_VERIFY_SERVER_CERT: - ret = ssl3_verify_server_cert(s); - if (ret <= 0) { - goto end; - } - - s->state = SSL3_ST_CR_KEY_EXCH_A; - s->init_num = 0; - break; - case SSL3_ST_CR_KEY_EXCH_A: case SSL3_ST_CR_KEY_EXCH_B: ret = ssl3_get_server_key_exchange(s); @@ -305,6 +290,13 @@ int ssl3_connect(SSL *s) { } s->state = SSL3_ST_CR_CERT_REQ_A; s->init_num = 0; + + /* at this point we check that we have the + * required stuff from the server */ + if (!ssl3_check_cert_and_algorithm(s)) { + ret = -1; + goto end; + } break; case SSL3_ST_CR_CERT_REQ_A: @@ -364,7 +356,6 @@ int ssl3_connect(SSL *s) { case SSL3_ST_CW_CERT_VRFY_A: case SSL3_ST_CW_CERT_VRFY_B: - case SSL3_ST_CW_CERT_VRFY_C: ret = ssl3_send_cert_verify(s); if (ret <= 0) { goto end; @@ -442,9 +433,11 @@ int ssl3_connect(SSL *s) { * record the handshake hashes at this point in the session so that * any resumption of this session with ChannelID can sign those * hashes. */ - ret = tls1_record_handshake_hashes_for_channel_id(s); - if (ret <= 0) { - goto end; + if (s->s3->tlsext_channel_id_new) { + ret = tls1_record_handshake_hashes_for_channel_id(s); + if (ret <= 0) { + goto end; + } } if ((SSL_get_mode(s) & SSL_MODE_ENABLE_FALSE_START) && ssl3_can_false_start(s) && @@ -480,7 +473,7 @@ int ssl3_connect(SSL *s) { if (ret <= 0) { goto end; } - s->state = SSL3_ST_VERIFY_SERVER_CERT; + s->state = SSL3_ST_CR_KEY_EXCH_A; s->init_num = 0; break; @@ -543,16 +536,11 @@ int ssl3_connect(SSL *s) { /* Remove write buffering now. */ ssl_free_wbio_buffer(s); - const int is_initial_handshake = !s->s3->initial_handshake_complete; - s->init_num = 0; s->s3->tmp.in_false_start = 0; s->s3->initial_handshake_complete = 1; - if (is_initial_handshake) { - /* Renegotiations do not participate in session resumption. */ - ssl_update_cache(s, SSL_SESS_CACHE_CLIENT); - } + ssl_update_cache(s, SSL_SESS_CACHE_CLIENT); ret = 1; /* s->server=0; */ @@ -564,7 +552,7 @@ int ssl3_connect(SSL *s) { goto end; default: - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE); + OPENSSL_PUT_ERROR(SSL, ssl3_connect, SSL_R_UNKNOWN_STATE); ret = -1; goto end; } @@ -600,7 +588,7 @@ int ssl3_send_client_hello(SSL *s) { uint16_t max_version = ssl3_get_max_client_version(s); /* Disabling all versions is silly: return an error. */ if (max_version == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SSL_VERSION); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello, SSL_R_WRONG_SSL_VERSION); goto err; } s->version = max_version; @@ -673,7 +661,7 @@ int ssl3_send_client_hello(SSL *s) { *(p++) = i; if (i != 0) { if (i > (int)sizeof(s->session->session_id)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello, ERR_R_INTERNAL_ERROR); goto err; } memcpy(p, s->session->session_id, i); @@ -683,7 +671,7 @@ int ssl3_send_client_hello(SSL *s) { /* cookie stuff for DTLS */ if (SSL_IS_DTLS(s)) { if (s->d1->cookie_len > sizeof(s->d1->cookie)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello, ERR_R_INTERNAL_ERROR); goto err; } *(p++) = s->d1->cookie_len; @@ -694,7 +682,8 @@ int ssl3_send_client_hello(SSL *s) { /* Ciphers supported */ i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &p[2]); if (i == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHERS_AVAILABLE); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello, + SSL_R_NO_CIPHERS_AVAILABLE); goto err; } s2n(i, p); @@ -705,10 +694,15 @@ int ssl3_send_client_hello(SSL *s) { *(p++) = 0; /* Add the NULL method */ /* TLS extensions*/ + if (ssl_prepare_clienthello_tlsext(s) <= 0) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello, SSL_R_CLIENTHELLO_TLSEXT); + goto err; + } + p = ssl_add_clienthello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH, p - buf); if (p == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello, ERR_R_INTERNAL_ERROR); goto err; } @@ -752,7 +746,8 @@ int ssl3_get_server_hello(SSL *s) { * parameters. Note: this error code comes after the original one. * * See https://crbug.com/446505. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, + SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO); } return n; } @@ -766,14 +761,14 @@ int ssl3_get_server_hello(SSL *s) { !CBS_get_u16(&server_hello, &cipher_suite) || !CBS_get_u8(&server_hello, &compression_method)) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_DECODE_ERROR); goto f_err; } assert(s->s3->have_version == s->s3->initial_handshake_complete); if (!s->s3->have_version) { if (!ssl3_is_version_enabled(s, server_version)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_UNSUPPORTED_PROTOCOL); s->version = server_version; /* Mark the version as fixed so the record-layer version is not clamped * to TLS 1.0. */ @@ -788,7 +783,7 @@ int ssl3_get_server_hello(SSL *s) { * fixed. Begin enforcing the record-layer version. */ s->s3->have_version = 1; } else if (server_version != s->version) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SSL_VERSION); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_WRONG_SSL_VERSION); al = SSL_AD_PROTOCOL_VERSION; goto f_err; } @@ -804,7 +799,7 @@ int ssl3_get_server_hello(SSL *s) { memcmp(s->session->sid_ctx, s->sid_ctx, s->sid_ctx_length)) { /* actually a client application bug */ al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT); goto f_err; } @@ -825,7 +820,8 @@ int ssl3_get_server_hello(SSL *s) { if (c == NULL) { /* unknown cipher */ al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_RETURNED); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, + SSL_R_UNKNOWN_CIPHER_RETURNED); goto f_err; } /* ct->mask_ssl was computed from client capabilities. Now @@ -841,7 +837,7 @@ int ssl3_get_server_hello(SSL *s) { (c->algorithm_mkey & ct->mask_k) || (c->algorithm_auth & ct->mask_a)) { al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_WRONG_CIPHER_RETURNED); goto f_err; } @@ -849,46 +845,45 @@ int ssl3_get_server_hello(SSL *s) { if (!sk_SSL_CIPHER_find(sk, NULL, c)) { /* we did not say we would use this cipher */ al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_WRONG_CIPHER_RETURNED); goto f_err; } if (s->hit) { if (s->session->cipher != c) { al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, + SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED); goto f_err; } if (s->session->ssl_version != s->version) { al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_VERSION_NOT_RETURNED); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, + SSL_R_OLD_SESSION_VERSION_NOT_RETURNED); goto f_err; } } s->s3->tmp.new_cipher = c; - /* Now that the cipher is known, initialize the handshake hash. */ - if (!ssl3_init_handshake_hash(s)) { - goto f_err; - } - /* 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_USE_SIGALGS(s) || s->hit) { - ssl3_free_handshake_buffer(s); + * different hash. Otherwise, release the handshake buffer. */ + if ((!SSL_USE_SIGALGS(s) || s->hit) && + !ssl3_digest_cached_records(s, free_handshake_buffer)) { + goto f_err; } /* Only the NULL compression algorithm is supported. */ if (compression_method != 0) { al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, + SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM); goto f_err; } /* TLS extensions */ if (!ssl_parse_serverhello_tlsext(s, &server_hello)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_PARSE_TLSEXT); goto err; } @@ -896,7 +891,7 @@ int ssl3_get_server_hello(SSL *s) { if (CBS_len(&server_hello) != 0) { /* wrong packet length */ al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_BAD_PACKET_LENGTH); goto f_err; } @@ -904,9 +899,11 @@ int ssl3_get_server_hello(SSL *s) { s->s3->tmp.extended_master_secret != s->session->extended_master_secret) { al = SSL_AD_HANDSHAKE_FAILURE; if (s->session->extended_master_secret) { - OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, + SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION); } else { - OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, + SSL_R_RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION); } goto f_err; } @@ -919,49 +916,12 @@ err: return -1; } -/* ssl3_check_certificate_for_cipher returns one if |leaf| is a suitable server - * certificate type for |cipher|. Otherwise, it returns zero and pushes an error - * on the error queue. */ -static int ssl3_check_certificate_for_cipher(X509 *leaf, - const SSL_CIPHER *cipher) { - int ret = 0; - EVP_PKEY *pkey = X509_get_pubkey(leaf); - if (pkey == NULL) { - goto err; - } - - /* Check the certificate's type matches the cipher. */ - int expected_type = ssl_cipher_get_key_type(cipher); - assert(expected_type != EVP_PKEY_NONE); - if (pkey->type != expected_type) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CERTIFICATE_TYPE); - goto err; - } - - /* TODO(davidben): This behavior is preserved from upstream. Should key usages - * be checked in other cases as well? */ - if (cipher->algorithm_auth & SSL_aECDSA) { - /* This call populates the ex_flags field correctly */ - X509_check_purpose(leaf, -1, 0); - if ((leaf->ex_flags & EXFLAG_KUSAGE) && - !(leaf->ex_kusage & X509v3_KU_DIGITAL_SIGNATURE)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ECC_CERT_NOT_FOR_SIGNING); - goto err; - } - } - - ret = 1; - -err: - EVP_PKEY_free(pkey); - return ret; -} - int ssl3_get_server_certificate(SSL *s) { - int al, ok, ret = -1; + int al, i, ok, ret = -1; unsigned long n; X509 *x = NULL; STACK_OF(X509) *sk = NULL; + SESS_CERT *sc; EVP_PKEY *pkey = NULL; CBS cbs, certificate_list; const uint8_t *data; @@ -978,15 +938,14 @@ int ssl3_get_server_certificate(SSL *s) { sk = sk_X509_new_null(); if (sk == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, ERR_R_MALLOC_FAILURE); goto err; } if (!CBS_get_u24_length_prefixed(&cbs, &certificate_list) || - CBS_len(&certificate_list) == 0 || CBS_len(&cbs) != 0) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, SSL_R_LENGTH_MISMATCH); goto f_err; } @@ -994,45 +953,90 @@ int ssl3_get_server_certificate(SSL *s) { CBS certificate; if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate)) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, + SSL_R_CERT_LENGTH_MISMATCH); goto f_err; } data = CBS_data(&certificate); x = d2i_X509(NULL, &data, CBS_len(&certificate)); if (x == NULL) { al = SSL_AD_BAD_CERTIFICATE; - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, ERR_R_ASN1_LIB); goto f_err; } if (data != CBS_data(&certificate) + CBS_len(&certificate)) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, + SSL_R_CERT_LENGTH_MISMATCH); goto f_err; } if (!sk_X509_push(sk, x)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, ERR_R_MALLOC_FAILURE); goto err; } x = NULL; } - X509 *leaf = sk_X509_value(sk, 0); - if (!ssl3_check_certificate_for_cipher(leaf, s->s3->tmp.new_cipher)) { - al = SSL_AD_ILLEGAL_PARAMETER; + i = ssl_verify_cert_chain(s, sk); + if (s->verify_mode != SSL_VERIFY_NONE && i <= 0) { + al = ssl_verify_alarm_type(s->verify_result); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, + SSL_R_CERTIFICATE_VERIFY_FAILED); goto f_err; } + ERR_clear_error(); /* but we keep s->verify_result */ + + sc = ssl_sess_cert_new(); + if (sc == NULL) { + goto err; + } - /* NOTE: Unlike the server half, the client's copy of |cert_chain| includes - * the leaf. */ - sk_X509_pop_free(s->session->cert_chain, X509_free); - s->session->cert_chain = sk; + ssl_sess_cert_free(s->session->sess_cert); + s->session->sess_cert = sc; + + sc->cert_chain = sk; + /* Inconsistency alert: cert_chain does include the peer's certificate, which + * we don't include in s3_srvr.c */ + x = sk_X509_value(sk, 0); sk = NULL; + /* VRS 19990621: possible memory leak; sk=null ==> !sk_pop_free() @end*/ + + pkey = X509_get_pubkey(x); + + if (pkey == NULL || EVP_PKEY_missing_parameters(pkey)) { + x = NULL; + al = SSL3_AL_FATAL; + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, + SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS); + goto f_err; + } + + i = ssl_cert_type(pkey); + if (i < 0) { + x = NULL; + al = SSL3_AL_FATAL; + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, + SSL_R_UNKNOWN_CERTIFICATE_TYPE); + goto f_err; + } + + int exp_idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher); + if (exp_idx >= 0 && i != exp_idx) { + x = NULL; + al = SSL_AD_ILLEGAL_PARAMETER; + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, + SSL_R_WRONG_CERTIFICATE_TYPE); + goto f_err; + } + X509_free(sc->peer_cert); + sc->peer_cert = X509_up_ref(x); X509_free(s->session->peer); - s->session->peer = X509_up_ref(leaf); + s->session->peer = X509_up_ref(x); s->session->verify_result = s->verify_result; + x = NULL; ret = 1; if (0) { @@ -1071,14 +1075,25 @@ int ssl3_get_server_key_exchange(SSL *s) { if (s->s3->tmp.message_type != SSL3_MT_SERVER_KEY_EXCHANGE) { if (ssl_cipher_requires_server_key_exchange(s->s3->tmp.new_cipher)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, + SSL_R_UNEXPECTED_MESSAGE); ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); return -1; } - /* In plain PSK ciphersuite, ServerKeyExchange may be omitted to send no - * identity hint. */ + /* In plain PSK ciphersuite, ServerKeyExchange can be + omitted if no identity hint is sent. Set session->sess_cert anyway to + avoid problems later.*/ if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aPSK) { + /* PSK ciphersuites that also send a Certificate would have already + * initialized |sess_cert|. */ + if (s->session->sess_cert == NULL) { + s->session->sess_cert = ssl_sess_cert_new(); + if (s->session->sess_cert == NULL) { + return -1; + } + } + /* TODO(davidben): This should be reset in one place with the rest of the * handshake state. */ OPENSSL_free(s->s3->tmp.peer_psk_identity_hint); @@ -1092,6 +1107,18 @@ int ssl3_get_server_key_exchange(SSL *s) { CBS_init(&server_key_exchange, s->init_msg, n); server_key_exchange_orig = server_key_exchange; + if (s->session->sess_cert != NULL) { + DH_free(s->session->sess_cert->peer_dh_tmp); + s->session->sess_cert->peer_dh_tmp = NULL; + EC_KEY_free(s->session->sess_cert->peer_ecdh_tmp); + s->session->sess_cert->peer_ecdh_tmp = NULL; + } else { + s->session->sess_cert = ssl_sess_cert_new(); + if (s->session->sess_cert == NULL) { + return -1; + } + } + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; alg_a = s->s3->tmp.new_cipher->algorithm_auth; EVP_MD_CTX_init(&md_ctx); @@ -1103,7 +1130,7 @@ int ssl3_get_server_key_exchange(SSL *s) { if (!CBS_get_u16_length_prefixed(&server_key_exchange, &psk_identity_hint)) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_DECODE_ERROR); goto f_err; } @@ -1117,14 +1144,16 @@ int ssl3_get_server_key_exchange(SSL *s) { if (CBS_len(&psk_identity_hint) > PSK_MAX_IDENTITY_LEN || CBS_contains_zero_byte(&psk_identity_hint)) { al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, + SSL_R_DATA_LENGTH_TOO_LONG); goto f_err; } /* Save the identity hint as a C string. */ if (!CBS_strdup(&psk_identity_hint, &s->s3->tmp.peer_psk_identity_hint)) { al = SSL_AD_INTERNAL_ERROR; - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, + ERR_R_MALLOC_FAILURE); goto f_err; } } @@ -1139,13 +1168,13 @@ int ssl3_get_server_key_exchange(SSL *s) { !CBS_get_u16_length_prefixed(&server_key_exchange, &dh_Ys) || CBS_len(&dh_Ys) == 0) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_DECODE_ERROR); goto f_err; } dh = DH_new(); if (dh == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, ERR_R_DH_LIB); goto err; } @@ -1153,17 +1182,22 @@ int ssl3_get_server_key_exchange(SSL *s) { (dh->g = BN_bin2bn(CBS_data(&dh_g), CBS_len(&dh_g), NULL)) == NULL || (dh->pub_key = BN_bin2bn(CBS_data(&dh_Ys), CBS_len(&dh_Ys), NULL)) == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BN_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, ERR_R_BN_LIB); goto err; } - s->session->key_exchange_info = DH_num_bits(dh); - if (s->session->key_exchange_info < 1024) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_DH_P_LENGTH); + if (DH_num_bits(dh) < 1024) { + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, + SSL_R_BAD_DH_P_LENGTH); goto err; } - DH_free(s->s3->tmp.peer_dh_tmp); - s->s3->tmp.peer_dh_tmp = dh; + + if (alg_a & SSL_aRSA) { + pkey = X509_get_pubkey(s->session->sess_cert->peer_cert); + } + /* else anonymous DH, so no certificate or pkey. */ + + s->session->sess_cert->peer_dh_tmp = dh; dh = NULL; } else if (alg_k & SSL_kECDHE) { uint16_t curve_id; @@ -1176,21 +1210,22 @@ int ssl3_get_server_key_exchange(SSL *s) { * invalid curve. */ if (!tls1_check_curve(s, &server_key_exchange, &curve_id)) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_WRONG_CURVE); goto f_err; } curve_nid = tls1_ec_curve_id2nid(curve_id); if (curve_nid == 0) { al = SSL_AD_INTERNAL_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, + SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS); goto f_err; } ecdh = EC_KEY_new_by_curve_name(curve_nid); - s->session->key_exchange_info = curve_id; if (ecdh == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_EC_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, + ERR_R_EC_LIB); goto err; } @@ -1199,25 +1234,35 @@ int ssl3_get_server_key_exchange(SSL *s) { /* Next, get the encoded ECPoint */ if (!CBS_get_u8_length_prefixed(&server_key_exchange, &point)) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_DECODE_ERROR); goto f_err; } if (((srvr_ecpoint = EC_POINT_new(group)) == NULL) || ((bn_ctx = BN_CTX_new()) == NULL)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, + ERR_R_MALLOC_FAILURE); goto err; } if (!EC_POINT_oct2point(group, srvr_ecpoint, CBS_data(&point), CBS_len(&point), bn_ctx)) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_BAD_ECPOINT); goto f_err; } + + /* The ECC/TLS specification does not mention the use of DSA to sign + * ECParameters in the server key exchange message. We do support RSA and + * ECDSA. */ + if (alg_a & (SSL_aRSA|SSL_aECDSA)) { + pkey = X509_get_pubkey(s->session->sess_cert->peer_cert); + } else { + /* Otherwise this is ECDHE_PSK, so no public key. */ + assert(alg_a == SSL_aPSK); + } EC_KEY_set_public_key(ecdh, srvr_ecpoint); - EC_KEY_free(s->s3->tmp.peer_ecdh_tmp); - s->s3->tmp.peer_ecdh_tmp = ecdh; + s->session->sess_cert->peer_ecdh_tmp = ecdh; ecdh = NULL; BN_CTX_free(bn_ctx); bn_ctx = NULL; @@ -1225,7 +1270,8 @@ int ssl3_get_server_key_exchange(SSL *s) { srvr_ecpoint = NULL; } else if (!(alg_k & SSL_kPSK)) { al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, + SSL_R_UNEXPECTED_MESSAGE); goto f_err; } @@ -1235,12 +1281,9 @@ int ssl3_get_server_key_exchange(SSL *s) { CBS_init(¶meter, CBS_data(&server_key_exchange_orig), 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(s->s3->tmp.new_cipher)) { - pkey = X509_get_pubkey(s->session->peer); - if (pkey == NULL) { - goto err; - } + /* if it was signed, check the signature */ + if (pkey != NULL) { + CBS signature; if (SSL_USE_SIGALGS(s)) { if (!tls12_check_peer_sigalg(&md, &al, s, &server_key_exchange, pkey)) { @@ -1253,11 +1296,10 @@ int ssl3_get_server_key_exchange(SSL *s) { } /* The last field in |server_key_exchange| is the signature. */ - CBS signature; if (!CBS_get_u16_length_prefixed(&server_key_exchange, &signature) || CBS_len(&server_key_exchange) != 0) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_DECODE_ERROR); goto f_err; } @@ -1272,16 +1314,24 @@ int ssl3_get_server_key_exchange(SSL *s) { CBS_len(&signature))) { /* bad signature */ al = SSL_AD_DECRYPT_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_BAD_SIGNATURE); goto f_err; } } else { - /* PSK ciphers are the only supported certificate-less ciphers. */ - assert(alg_a == SSL_aPSK); - + if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) { + /* Might be wrong key type, check it */ + if (ssl3_check_cert_and_algorithm(s)) { + /* Otherwise this shouldn't happen */ + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, + ERR_R_INTERNAL_ERROR); + } + goto err; + } + /* still data left over */ if (CBS_len(&server_key_exchange) > 0) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_EXTRA_DATA_IN_MESSAGE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, + SSL_R_EXTRA_DATA_IN_MESSAGE); goto f_err; } } @@ -1328,15 +1378,19 @@ int ssl3_get_certificate_request(SSL *s) { if (s->s3->tmp.message_type == SSL3_MT_SERVER_DONE) { s->s3->tmp.reuse_message = 1; - /* If we get here we don't need the handshake buffer as we won't be doing - * client auth. */ - ssl3_free_handshake_buffer(s); + /* If we get here we don't need any cached handshake records as we wont be + * doing client auth. */ + if (s->s3->handshake_buffer && + !ssl3_digest_cached_records(s, free_handshake_buffer)) { + goto err; + } return 1; } if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE_REQUEST) { ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_MESSAGE_TYPE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, + SSL_R_WRONG_MESSAGE_TYPE); goto err; } @@ -1344,14 +1398,14 @@ int ssl3_get_certificate_request(SSL *s) { ca_sk = sk_X509_NAME_new(ca_dn_cmp); if (ca_sk == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, ERR_R_MALLOC_FAILURE); goto err; } /* get the certificate types */ if (!CBS_get_u8_length_prefixed(&cbs, &certificate_types)) { ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, SSL_R_DECODE_ERROR); goto err; } @@ -1363,10 +1417,16 @@ int ssl3_get_certificate_request(SSL *s) { if (SSL_USE_SIGALGS(s)) { CBS supported_signature_algorithms; - if (!CBS_get_u16_length_prefixed(&cbs, &supported_signature_algorithms) || - !tls1_parse_peer_sigalgs(s, &supported_signature_algorithms)) { + if (!CBS_get_u16_length_prefixed(&cbs, &supported_signature_algorithms)) { ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, SSL_R_DECODE_ERROR); + goto err; + } + + if (!tls1_process_sigalgs(s, &supported_signature_algorithms)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, + SSL_R_SIGNATURE_ALGORITHMS_ERROR); goto err; } } @@ -1374,7 +1434,7 @@ int ssl3_get_certificate_request(SSL *s) { /* get the CA RDNs */ if (!CBS_get_u16_length_prefixed(&cbs, &certificate_authorities)) { ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - OPENSSL_PUT_ERROR(SSL, SSL_R_LENGTH_MISMATCH); + OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, SSL_R_LENGTH_MISMATCH); goto err; } @@ -1383,7 +1443,8 @@ int ssl3_get_certificate_request(SSL *s) { if (!CBS_get_u16_length_prefixed(&certificate_authorities, &distinguished_name)) { ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - OPENSSL_PUT_ERROR(SSL, SSL_R_CA_DN_TOO_LONG); + OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, + SSL_R_CA_DN_TOO_LONG); goto err; } @@ -1392,24 +1453,26 @@ int ssl3_get_certificate_request(SSL *s) { xn = d2i_X509_NAME(NULL, &data, CBS_len(&distinguished_name)); if (xn == NULL) { ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, ERR_R_ASN1_LIB); goto err; } if (!CBS_skip(&distinguished_name, data - CBS_data(&distinguished_name))) { ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, ERR_R_INTERNAL_ERROR); goto err; } if (CBS_len(&distinguished_name) != 0) { ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - OPENSSL_PUT_ERROR(SSL, SSL_R_CA_DN_LENGTH_MISMATCH); + OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, + SSL_R_CA_DN_LENGTH_MISMATCH); goto err; } if (!sk_X509_NAME_push(ca_sk, xn)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, + ERR_R_MALLOC_FAILURE); goto err; } } @@ -1453,9 +1516,18 @@ int ssl3_get_new_session_ticket(SSL *s) { OPENSSL_free(bytes); if (new_session == NULL) { /* This should never happen. */ - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_new_session_ticket, ERR_R_INTERNAL_ERROR); goto err; } + if (s->session->sess_cert != NULL) { + /* |sess_cert| is not serialized and must be duplicated explicitly. */ + assert(new_session->sess_cert == NULL); + new_session->sess_cert = ssl_sess_cert_dup(s->session->sess_cert); + if (new_session->sess_cert == NULL) { + SSL_SESSION_free(new_session); + goto err; + } + } SSL_SESSION_free(s->session); s->session = new_session; @@ -1468,13 +1540,13 @@ int ssl3_get_new_session_ticket(SSL *s) { !CBS_get_u16_length_prefixed(&new_session_ticket, &ticket) || CBS_len(&new_session_ticket) != 0) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_new_session_ticket, SSL_R_DECODE_ERROR); goto f_err; } if (!CBS_stow(&ticket, &s->session->tlsext_tick, &s->session->tlsext_ticklen)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_new_session_ticket, ERR_R_MALLOC_FAILURE); goto err; } @@ -1522,14 +1594,14 @@ int ssl3_get_cert_status(SSL *s) { CBS_len(&ocsp_response) == 0 || CBS_len(&certificate_status) != 0) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_status, SSL_R_DECODE_ERROR); goto f_err; } if (!CBS_stow(&ocsp_response, &s->session->ocsp_response, &s->session->ocsp_response_length)) { al = SSL_AD_INTERNAL_ERROR; - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_status, ERR_R_MALLOC_FAILURE); goto f_err; } return 1; @@ -1555,7 +1627,7 @@ int ssl3_get_server_done(SSL *s) { if (n > 0) { /* should contain no data */ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - OPENSSL_PUT_ERROR(SSL, SSL_R_LENGTH_MISMATCH); + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_done, SSL_R_LENGTH_MISMATCH); return -1; } @@ -1593,7 +1665,8 @@ int ssl3_send_client_key_exchange(SSL *s) { size_t identity_len; if (s->psk_client_callback == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_NO_CLIENT_CB); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + SSL_R_PSK_NO_CLIENT_CB); goto err; } @@ -1602,24 +1675,28 @@ int ssl3_send_client_key_exchange(SSL *s) { s->psk_client_callback(s, s->s3->tmp.peer_psk_identity_hint, identity, sizeof(identity), psk, sizeof(psk)); if (psk_len > PSK_MAX_PSK_LEN) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + ERR_R_INTERNAL_ERROR); goto err; } else if (psk_len == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + SSL_R_PSK_IDENTITY_NOT_FOUND); ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); goto err; } identity_len = OPENSSL_strnlen(identity, sizeof(identity)); if (identity_len > PSK_MAX_IDENTITY_LEN) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + ERR_R_INTERNAL_ERROR); goto err; } OPENSSL_free(s->session->psk_identity); s->session->psk_identity = BUF_strdup(identity); if (s->session->psk_identity == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + ERR_R_MALLOC_FAILURE); goto err; } @@ -1638,20 +1715,28 @@ int ssl3_send_client_key_exchange(SSL *s) { pms_len = SSL_MAX_MASTER_KEY_LENGTH; pms = OPENSSL_malloc(pms_len); if (pms == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + ERR_R_MALLOC_FAILURE); goto err; } - pkey = X509_get_pubkey(s->session->peer); + if (s->session->sess_cert == NULL) { + /* We should always have a server certificate with SSL_kRSA. */ + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + ERR_R_INTERNAL_ERROR); + goto err; + } + + pkey = X509_get_pubkey(s->session->sess_cert->peer_cert); if (pkey == NULL || pkey->type != EVP_PKEY_RSA || pkey->pkey.rsa == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + ERR_R_INTERNAL_ERROR); EVP_PKEY_free(pkey); goto err; } - s->session->key_exchange_info = EVP_PKEY_bits(pkey); rsa = pkey->pkey.rsa; EVP_PKEY_free(pkey); @@ -1671,7 +1756,8 @@ int ssl3_send_client_key_exchange(SSL *s) { } if (!RSA_encrypt(rsa, &enc_pms_len, p, RSA_size(rsa), pms, pms_len, RSA_PKCS1_PADDING)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_RSA_ENCRYPT); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + SSL_R_BAD_RSA_ENCRYPT); goto err; } n += enc_pms_len; @@ -1688,23 +1774,32 @@ int ssl3_send_client_key_exchange(SSL *s) { } } else if (alg_k & SSL_kDHE) { DH *dh_srvr, *dh_clnt; + SESS_CERT *scert = s->session->sess_cert; int dh_len; size_t pub_len; - if (s->s3->tmp.peer_dh_tmp == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + if (scert == NULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + SSL_R_UNEXPECTED_MESSAGE); + goto err; + } + + if (scert->peer_dh_tmp == NULL) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + ERR_R_INTERNAL_ERROR); goto err; } - dh_srvr = s->s3->tmp.peer_dh_tmp; + dh_srvr = scert->peer_dh_tmp; /* generate a new random key */ dh_clnt = DHparams_dup(dh_srvr); if (dh_clnt == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_DH_LIB); goto err; } if (!DH_generate_key(dh_clnt)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_DH_LIB); DH_free(dh_clnt); goto err; } @@ -1712,14 +1807,15 @@ int ssl3_send_client_key_exchange(SSL *s) { pms_len = DH_size(dh_clnt); pms = OPENSSL_malloc(pms_len); if (pms == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + ERR_R_MALLOC_FAILURE); DH_free(dh_clnt); goto err; } dh_len = DH_compute_key(pms, dh_srvr->pub_key, dh_clnt); if (dh_len <= 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_DH_LIB); DH_free(dh_clnt); goto err; } @@ -1737,53 +1833,64 @@ int ssl3_send_client_key_exchange(SSL *s) { EC_KEY *tkey; int field_size = 0, ecdh_len; - if (s->s3->tmp.peer_ecdh_tmp == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + if (s->session->sess_cert == NULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + SSL_R_UNEXPECTED_MESSAGE); goto err; } - tkey = s->s3->tmp.peer_ecdh_tmp; + if (s->session->sess_cert->peer_ecdh_tmp == NULL) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + ERR_R_INTERNAL_ERROR); + goto err; + } + + tkey = s->session->sess_cert->peer_ecdh_tmp; srvr_group = EC_KEY_get0_group(tkey); srvr_ecpoint = EC_KEY_get0_public_key(tkey); if (srvr_group == NULL || srvr_ecpoint == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + ERR_R_INTERNAL_ERROR); goto err; } clnt_ecdh = EC_KEY_new(); if (clnt_ecdh == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + ERR_R_MALLOC_FAILURE); goto err; } if (!EC_KEY_set_group(clnt_ecdh, srvr_group)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_EC_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_EC_LIB); goto err; } /* Generate a new ECDH key pair */ if (!EC_KEY_generate_key(clnt_ecdh)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ECDH_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB); goto err; } field_size = EC_GROUP_get_degree(srvr_group); if (field_size <= 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ECDH_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB); goto err; } pms_len = (field_size + 7) / 8; pms = OPENSSL_malloc(pms_len); if (pms == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + ERR_R_MALLOC_FAILURE); goto err; } ecdh_len = ECDH_compute_key(pms, pms_len, srvr_ecpoint, clnt_ecdh, NULL); if (ecdh_len <= 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ECDH_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB); goto err; } pms_len = ecdh_len; @@ -1797,7 +1904,8 @@ int ssl3_send_client_key_exchange(SSL *s) { (uint8_t *)OPENSSL_malloc(encoded_pt_len * sizeof(uint8_t)); bn_ctx = BN_CTX_new(); if (encodedPoint == NULL || bn_ctx == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + ERR_R_MALLOC_FAILURE); goto err; } @@ -1830,13 +1938,15 @@ int ssl3_send_client_key_exchange(SSL *s) { pms_len = psk_len; pms = OPENSSL_malloc(pms_len); if (pms == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + ERR_R_MALLOC_FAILURE); goto err; } memset(pms, 0, pms_len); } else { ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + ERR_R_INTERNAL_ERROR); goto err; } @@ -1847,15 +1957,19 @@ int ssl3_send_client_key_exchange(SSL *s) { uint8_t *new_pms; size_t new_pms_len; - CBB_zero(&cbb); - if (!CBB_init(&cbb, 2 + psk_len + 2 + pms_len) || - !CBB_add_u16_length_prefixed(&cbb, &child) || + if (!CBB_init(&cbb, 2 + psk_len + 2 + pms_len)) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + ERR_R_MALLOC_FAILURE); + goto err; + } + if (!CBB_add_u16_length_prefixed(&cbb, &child) || !CBB_add_bytes(&child, pms, pms_len) || !CBB_add_u16_length_prefixed(&cbb, &child) || !CBB_add_bytes(&child, psk, psk_len) || !CBB_finish(&cbb, &new_pms, &new_pms_len)) { CBB_cleanup(&cbb); - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, + ERR_R_INTERNAL_ERROR); goto err; } OPENSSL_cleanse(pms, pms_len); @@ -1897,87 +2011,87 @@ err: } int ssl3_send_cert_verify(SSL *s) { - if (s->state == SSL3_ST_CW_CERT_VRFY_A || - s->state == SSL3_ST_CW_CERT_VRFY_B) { - enum ssl_private_key_result_t sign_result; - uint8_t *p = ssl_handshake_start(s); - size_t signature_length = 0; - unsigned long n = 0; - assert(ssl_has_private_key(s)); - - if (s->state == SSL3_ST_CW_CERT_VRFY_A) { - uint8_t *buf = (uint8_t *)s->init_buf->data; - const EVP_MD *md = NULL; - uint8_t digest[EVP_MAX_MD_SIZE]; - size_t digest_length; - - /* Write out the digest type if need be. */ - if (SSL_USE_SIGALGS(s)) { - md = tls1_choose_signing_digest(s); - if (!tls12_get_sigandhash(s, p, md)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return -1; - } - p += 2; - n += 2; - } + uint8_t *buf, *p; + const EVP_MD *md = NULL; + uint8_t digest[EVP_MAX_MD_SIZE]; + size_t digest_length; + EVP_PKEY *pkey; + EVP_PKEY_CTX *pctx = NULL; + size_t signature_length = 0; + unsigned long n = 0; - /* Compute the digest. */ - const int pkey_type = ssl_private_key_type(s); - if (!ssl3_cert_verify_hash(s, digest, &digest_length, &md, pkey_type)) { - return -1; - } + buf = (uint8_t *)s->init_buf->data; - /* The handshake buffer is no longer necessary. */ - ssl3_free_handshake_buffer(s); + if (s->state == SSL3_ST_CW_CERT_VRFY_A) { + p = ssl_handshake_start(s); + pkey = s->cert->key->privatekey; - /* Sign the digest. */ - signature_length = ssl_private_key_max_signature_len(s); - if (p + 2 + signature_length > buf + SSL3_RT_MAX_PLAIN_LENGTH) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG); - return -1; + /* Write out the digest type if needbe. */ + if (SSL_USE_SIGALGS(s)) { + md = tls1_choose_signing_digest(s, pkey); + if (!tls12_get_sigandhash(p, pkey, md)) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, ERR_R_INTERNAL_ERROR); + goto err; } + p += 2; + n += 2; + } - s->rwstate = SSL_PRIVATE_KEY_OPERATION; - sign_result = ssl_private_key_sign(s, &p[2], &signature_length, - signature_length, md, digest, - digest_length); - } else { - if (SSL_USE_SIGALGS(s)) { - /* The digest has already been selected and written. */ - p += 2; - n += 2; - } - signature_length = ssl_private_key_max_signature_len(s); - s->rwstate = SSL_PRIVATE_KEY_OPERATION; - sign_result = ssl_private_key_sign_complete(s, &p[2], &signature_length, - signature_length); + /* Compute the digest. */ + if (!ssl3_cert_verify_hash(s, digest, &digest_length, &md, pkey)) { + goto err; } - if (sign_result == ssl_private_key_retry) { - s->state = SSL3_ST_CW_CERT_VRFY_B; - return -1; + /* The handshake buffer is no longer necessary. */ + if (s->s3->handshake_buffer && + !ssl3_digest_cached_records(s, free_handshake_buffer)) { + goto err; } - s->rwstate = SSL_NOTHING; - if (sign_result != ssl_private_key_success) { - return -1; + + /* Sign the digest. */ + pctx = EVP_PKEY_CTX_new(pkey, NULL); + if (pctx == NULL) { + goto err; + } + + /* Initialize the EVP_PKEY_CTX and determine the size of the signature. */ + if (!EVP_PKEY_sign_init(pctx) || !EVP_PKEY_CTX_set_signature_md(pctx, md) || + !EVP_PKEY_sign(pctx, NULL, &signature_length, digest, digest_length)) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, ERR_R_EVP_LIB); + goto err; + } + + if (p + 2 + signature_length > buf + SSL3_RT_MAX_PLAIN_LENGTH) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, SSL_R_DATA_LENGTH_TOO_LONG); + goto err; + } + + if (!EVP_PKEY_sign(pctx, &p[2], &signature_length, digest, digest_length)) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, ERR_R_EVP_LIB); + goto err; } s2n(signature_length, p); n += signature_length + 2; + if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n)) { - return -1; + goto err; } - s->state = SSL3_ST_CW_CERT_VRFY_C; + s->state = SSL3_ST_CW_CERT_VRFY_B; } + EVP_PKEY_CTX_free(pctx); return ssl_do_write(s); + +err: + EVP_PKEY_CTX_free(pctx); + return -1; } /* ssl3_has_client_certificate returns true if a client certificate is * configured. */ -static int ssl3_has_client_certificate(SSL *ssl) { - return ssl->cert && ssl->cert->x509 && ssl_has_private_key(ssl); +static int ssl3_has_client_certificate(SSL *s) { + return s->cert && s->cert->key->x509 && s->cert->key->privatekey; } int ssl3_send_client_certificate(SSL *s) { @@ -2025,7 +2139,8 @@ int ssl3_send_client_certificate(SSL *s) { } } else if (i == 1) { i = 0; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_certificate, + SSL_R_BAD_DATA_RETURNED_BY_CALLBACK); } X509_free(x509); @@ -2042,7 +2157,11 @@ int ssl3_send_client_certificate(SSL *s) { s->s3->tmp.cert_req = 2; /* There is no client certificate, so the handshake buffer may be * released. */ - ssl3_free_handshake_buffer(s); + if (s->s3->handshake_buffer && + !ssl3_digest_cached_records(s, free_handshake_buffer)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + return -1; + } } } @@ -2051,23 +2170,80 @@ int ssl3_send_client_certificate(SSL *s) { } if (s->state == SSL3_ST_CW_CERT_C) { - if (s->s3->tmp.cert_req == 2) { - /* Send an empty Certificate message. */ - uint8_t *p = ssl_handshake_start(s); - l2n3(0, p); - if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE, 3)) { - return -1; - } - } else if (!ssl3_output_cert_chain(s)) { + CERT_PKEY *cert_pkey = (s->s3->tmp.cert_req == 2) ? NULL : s->cert->key; + if (!ssl3_output_cert_chain(s, cert_pkey)) { return -1; } - s->state = SSL3_ST_CW_CERT_D; } /* SSL3_ST_CW_CERT_D */ return ssl_do_write(s); } +#define has_bits(i, m) (((i) & (m)) == (m)) + +int ssl3_check_cert_and_algorithm(SSL *s) { + long alg_k, alg_a; + SESS_CERT *sc; + DH *dh; + + /* we don't have a certificate */ + if (!ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) { + return 1; + } + + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + alg_a = s->s3->tmp.new_cipher->algorithm_auth; + + sc = s->session->sess_cert; + if (sc == NULL) { + OPENSSL_PUT_ERROR(SSL, ssl3_check_cert_and_algorithm, ERR_R_INTERNAL_ERROR); + goto err; + } + + dh = s->session->sess_cert->peer_dh_tmp; + + int cert_type = X509_certificate_type(sc->peer_cert, NULL); + if (cert_type & EVP_PK_EC) { + if (ssl_check_srvr_ecc_cert_and_alg(sc->peer_cert, s) == 0) { + /* check failed */ + OPENSSL_PUT_ERROR(SSL, ssl3_check_cert_and_algorithm, SSL_R_BAD_ECC_CERT); + goto f_err; + } else { + return 1; + } + } else if (alg_a & SSL_aECDSA) { + OPENSSL_PUT_ERROR(SSL, ssl3_check_cert_and_algorithm, + SSL_R_MISSING_ECDSA_SIGNING_CERT); + goto f_err; + } + + /* Check that we have a certificate if we require one */ + if ((alg_a & SSL_aRSA) && !has_bits(cert_type, EVP_PK_RSA | EVP_PKT_SIGN)) { + OPENSSL_PUT_ERROR(SSL, ssl3_check_cert_and_algorithm, + SSL_R_MISSING_RSA_SIGNING_CERT); + goto f_err; + } + + if ((alg_k & SSL_kRSA) && !has_bits(cert_type, EVP_PK_RSA | EVP_PKT_ENC)) { + OPENSSL_PUT_ERROR(SSL, ssl3_check_cert_and_algorithm, + SSL_R_MISSING_RSA_ENCRYPTING_CERT); + goto f_err; + } + + if ((alg_k & SSL_kDHE) && dh == NULL) { + OPENSSL_PUT_ERROR(SSL, ssl3_check_cert_and_algorithm, SSL_R_MISSING_DH_KEY); + goto f_err; + } + + return 1; + +f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); +err: + return 0; +} + int ssl3_send_next_proto(SSL *s) { unsigned int len, padding_len; uint8_t *d, *p; @@ -2097,6 +2273,7 @@ int ssl3_send_channel_id(SSL *s) { uint8_t *d; int ret = -1, public_key_len; EVP_MD_CTX md_ctx; + size_t sig_len; ECDSA_SIG *sig = NULL; uint8_t *public_key = NULL, *derp, *der_sig = NULL; @@ -2118,48 +2295,72 @@ int ssl3_send_channel_id(SSL *s) { } s->rwstate = SSL_NOTHING; - if (EVP_PKEY_id(s->tlsext_channel_id_private) != EVP_PKEY_EC) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return -1; - } - EC_KEY *ec_key = s->tlsext_channel_id_private->pkey.ec; - d = ssl_handshake_start(s); - s2n(TLSEXT_TYPE_channel_id, d); + if (s->s3->tlsext_channel_id_new) { + s2n(TLSEXT_TYPE_channel_id_new, d); + } else { + s2n(TLSEXT_TYPE_channel_id, d); + } s2n(TLSEXT_CHANNEL_ID_SIZE, d); EVP_MD_CTX_init(&md_ctx); - public_key_len = i2o_ECPublicKey(ec_key, NULL); + public_key_len = i2d_PublicKey(s->tlsext_channel_id_private, NULL); if (public_key_len <= 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_CANNOT_SERIALIZE_PUBLIC_KEY); + OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, + SSL_R_CANNOT_SERIALIZE_PUBLIC_KEY); goto err; } - /* i2o_ECPublicKey will produce an ANSI X9.62 public key which, for a + /* i2d_PublicKey will produce an ANSI X9.62 public key which, for a * P-256 key, is 0x04 (meaning uncompressed) followed by the x and y * field elements as 32-byte, big-endian numbers. */ if (public_key_len != 65) { - OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256); + OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, SSL_R_CHANNEL_ID_NOT_P256); goto err; } public_key = OPENSSL_malloc(public_key_len); if (!public_key) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, ERR_R_MALLOC_FAILURE); goto err; } derp = public_key; - i2o_ECPublicKey(ec_key, &derp); + i2d_PublicKey(s->tlsext_channel_id_private, &derp); - uint8_t digest[EVP_MAX_MD_SIZE]; - size_t digest_len; - if (!tls1_channel_id_hash(s, digest, &digest_len)) { + if (EVP_DigestSignInit(&md_ctx, NULL, EVP_sha256(), NULL, + s->tlsext_channel_id_private) != 1) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, + SSL_R_EVP_DIGESTSIGNINIT_FAILED); + goto err; + } + + if (!tls1_channel_id_hash(&md_ctx, s)) { + goto err; + } + + if (!EVP_DigestSignFinal(&md_ctx, NULL, &sig_len)) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, + SSL_R_EVP_DIGESTSIGNFINAL_FAILED); goto err; } - sig = ECDSA_do_sign(digest, digest_len, ec_key); + der_sig = OPENSSL_malloc(sig_len); + if (!der_sig) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EVP_DigestSignFinal(&md_ctx, der_sig, &sig_len)) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, + SSL_R_EVP_DIGESTSIGNFINAL_FAILED); + goto err; + } + + derp = der_sig; + sig = d2i_ECDSA_SIG(NULL, (const uint8_t **)&derp, sig_len); if (sig == NULL) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, SSL_R_D2I_ECDSA_SIG); goto err; } @@ -2168,7 +2369,7 @@ int ssl3_send_channel_id(SSL *s) { d += 64; if (!BN_bn2bin_padded(d, 32, sig->r) || !BN_bn2bin_padded(d + 32, 32, sig->s)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, ERR_R_INTERNAL_ERROR); goto err; } @@ -2196,17 +2397,3 @@ int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey) { } return i; } - -int ssl3_verify_server_cert(SSL *s) { - int ret = ssl_verify_cert_chain(s, s->session->cert_chain); - if (s->verify_mode != SSL_VERIFY_NONE && ret <= 0) { - int al = ssl_verify_alarm_type(s->verify_result); - ssl3_send_alert(s, SSL3_AL_FATAL, al); - OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED); - } else { - ret = 1; - ERR_clear_error(); /* but we keep s->verify_result */ - } - - return ret; -} diff --git a/src/ssl/s3_enc.c b/src/ssl/s3_enc.c index f1924c0..fbe68da 100644 --- a/src/ssl/s3_enc.c +++ b/src/ssl/s3_enc.c @@ -4,21 +4,21 @@ * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. - * + *g * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * + *g * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. - * + *g * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -33,10 +33,10 @@ * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from + * 4. If you include any Windows specific code (or a derivative thereof) fromg * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * + *g * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -48,7 +48,7 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * + *g * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence @@ -62,7 +62,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer.g * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in @@ -133,8 +133,6 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. */ -#include <openssl/ssl.h> - #include <assert.h> #include <stdio.h> #include <string.h> @@ -182,7 +180,7 @@ int ssl3_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret, k++; if (k > sizeof(buf)) { /* bug: 'buf' is too small for this ciphersuite */ - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_prf, ERR_R_INTERNAL_ERROR); return 0; } @@ -191,7 +189,7 @@ int ssl3_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret, } c++; if (!EVP_DigestInit_ex(&sha1, EVP_sha1(), NULL)) { - OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); + OPENSSL_PUT_ERROR(SSL, ssl3_prf, ERR_LIB_EVP); return 0; } EVP_DigestUpdate(&sha1, buf, k); @@ -206,7 +204,7 @@ int ssl3_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret, EVP_DigestFinal_ex(&sha1, smd, NULL); if (!EVP_DigestInit_ex(&md5, EVP_md5(), NULL)) { - OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); + OPENSSL_PUT_ERROR(SSL, ssl3_prf, ERR_LIB_EVP); return 0; } EVP_DigestUpdate(&md5, secret, secret_len); @@ -237,75 +235,96 @@ void ssl3_cleanup_key_block(SSL *s) { s->s3->tmp.key_block_length = 0; } -int ssl3_init_handshake_buffer(SSL *ssl) { - ssl3_free_handshake_buffer(ssl); - ssl3_free_handshake_hash(ssl); - ssl->s3->handshake_buffer = BUF_MEM_new(); - return ssl->s3->handshake_buffer != NULL; -} - -/* init_digest_with_data calls |EVP_DigestInit_ex| on |ctx| with |md| and then - * writes the data in |buf| to it. */ -static int init_digest_with_data(EVP_MD_CTX *ctx, const EVP_MD *md, - const BUF_MEM *buf) { - if (!EVP_DigestInit_ex(ctx, md, NULL)) { +int ssl3_init_finished_mac(SSL *s) { + BIO_free(s->s3->handshake_buffer); + ssl3_free_digest_list(s); + s->s3->handshake_buffer = BIO_new(BIO_s_mem()); + if (s->s3->handshake_buffer == NULL) { return 0; } - EVP_DigestUpdate(ctx, buf->data, buf->length); + BIO_set_close(s->s3->handshake_buffer, BIO_CLOSE); + return 1; } -int ssl3_init_handshake_hash(SSL *ssl) { - ssl3_free_handshake_hash(ssl); - - uint32_t algorithm_prf = ssl_get_algorithm_prf(ssl); - if (!init_digest_with_data(&ssl->s3->handshake_hash, - ssl_get_handshake_digest(algorithm_prf), - ssl->s3->handshake_buffer)) { - return 0; +void ssl3_free_digest_list(SSL *s) { + int i; + if (!s->s3->handshake_dgst) { + return; } + for (i = 0; i < SSL_MAX_DIGEST; i++) { + if (s->s3->handshake_dgst[i]) { + EVP_MD_CTX_destroy(s->s3->handshake_dgst[i]); + } + } + OPENSSL_free(s->s3->handshake_dgst); + s->s3->handshake_dgst = NULL; +} - if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT && - !init_digest_with_data(&ssl->s3->handshake_md5, EVP_md5(), - ssl->s3->handshake_buffer)) { - return 0; +int ssl3_finish_mac(SSL *s, const uint8_t *buf, int len) { + int i; + + if (s->s3->handshake_buffer) { + return BIO_write(s->s3->handshake_buffer, (void *)buf, len) >= 0; } + for (i = 0; i < SSL_MAX_DIGEST; i++) { + if (s->s3->handshake_dgst[i] != NULL) { + EVP_DigestUpdate(s->s3->handshake_dgst[i], buf, len); + } + } return 1; } -void ssl3_free_handshake_hash(SSL *ssl) { - EVP_MD_CTX_cleanup(&ssl->s3->handshake_hash); - EVP_MD_CTX_cleanup(&ssl->s3->handshake_md5); -} - -void ssl3_free_handshake_buffer(SSL *ssl) { - BUF_MEM_free(ssl->s3->handshake_buffer); - ssl->s3->handshake_buffer = NULL; -} +int ssl3_digest_cached_records( + SSL *s, enum should_free_handshake_buffer_t should_free_handshake_buffer) { + int i; + uint32_t mask; + const EVP_MD *md; + const uint8_t *hdata; + size_t hdatalen; + + /* Allocate handshake_dgst array */ + ssl3_free_digest_list(s); + s->s3->handshake_dgst = OPENSSL_malloc(SSL_MAX_DIGEST * sizeof(EVP_MD_CTX *)); + if (s->s3->handshake_dgst == NULL) { + OPENSSL_PUT_ERROR(SSL, ssl3_digest_cached_records, ERR_R_MALLOC_FAILURE); + return 0; + } -int ssl3_update_handshake_hash(SSL *ssl, const uint8_t *in, size_t in_len) { - /* Depending on the state of the handshake, either the handshake buffer may be - * active, the rolling hash, or both. */ + memset(s->s3->handshake_dgst, 0, SSL_MAX_DIGEST * sizeof(EVP_MD_CTX *)); + if (!BIO_mem_contents(s->s3->handshake_buffer, &hdata, &hdatalen)) { + OPENSSL_PUT_ERROR(SSL, ssl3_digest_cached_records, + SSL_R_BAD_HANDSHAKE_LENGTH); + return 0; + } - if (ssl->s3->handshake_buffer != NULL) { - size_t new_len = ssl->s3->handshake_buffer->length + in_len; - if (new_len < in_len) { - OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); - return 0; - } - if (!BUF_MEM_grow(ssl->s3->handshake_buffer, new_len)) { - return 0; + /* Loop through bits of algorithm2 field and create MD_CTX-es */ + for (i = 0; ssl_get_handshake_digest(&mask, &md, i); i++) { + if ((mask & ssl_get_algorithm2(s)) && md) { + s->s3->handshake_dgst[i] = EVP_MD_CTX_create(); + if (s->s3->handshake_dgst[i] == NULL) { + OPENSSL_PUT_ERROR(SSL, ssl3_digest_cached_records, ERR_LIB_EVP); + return 0; + } + if (!EVP_DigestInit_ex(s->s3->handshake_dgst[i], md, NULL)) { + EVP_MD_CTX_destroy(s->s3->handshake_dgst[i]); + s->s3->handshake_dgst[i] = NULL; + OPENSSL_PUT_ERROR(SSL, ssl3_digest_cached_records, ERR_LIB_EVP); + return 0; + } + EVP_DigestUpdate(s->s3->handshake_dgst[i], hdata, hdatalen); + } else { + s->s3->handshake_dgst[i] = NULL; } - memcpy(ssl->s3->handshake_buffer->data + new_len - in_len, in, in_len); } - if (EVP_MD_CTX_md(&ssl->s3->handshake_hash) != NULL) { - EVP_DigestUpdate(&ssl->s3->handshake_hash, in, in_len); - } - if (EVP_MD_CTX_md(&ssl->s3->handshake_md5) != NULL) { - EVP_DigestUpdate(&ssl->s3->handshake_md5, in, in_len); + if (should_free_handshake_buffer == free_handshake_buffer) { + /* Free handshake_buffer BIO */ + BIO_free(s->s3->handshake_buffer); + s->s3->handshake_buffer = NULL; } + return 1; } @@ -337,22 +356,31 @@ static int ssl3_handshake_mac(SSL *s, int md_nid, const char *sender, int len, int npad, n; unsigned int i; uint8_t md_buf[EVP_MAX_MD_SIZE]; - EVP_MD_CTX ctx; - const EVP_MD_CTX *ctx_template; - - if (md_nid == NID_md5) { - ctx_template = &s->s3->handshake_md5; - } else if (md_nid == EVP_MD_CTX_type(&s->s3->handshake_hash)) { - ctx_template = &s->s3->handshake_hash; - } else { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_REQUIRED_DIGEST); + EVP_MD_CTX ctx, *d = NULL; + + if (s->s3->handshake_buffer && + !ssl3_digest_cached_records(s, free_handshake_buffer)) { + return 0; + } + + /* Search for digest of specified type in the handshake_dgst array. */ + for (i = 0; i < SSL_MAX_DIGEST; i++) { + if (s->s3->handshake_dgst[i] && + EVP_MD_CTX_type(s->s3->handshake_dgst[i]) == md_nid) { + d = s->s3->handshake_dgst[i]; + break; + } + } + + if (!d) { + OPENSSL_PUT_ERROR(SSL, ssl3_handshake_mac, SSL_R_NO_REQUIRED_DIGEST); return 0; } EVP_MD_CTX_init(&ctx); - if (!EVP_MD_CTX_copy_ex(&ctx, ctx_template)) { + if (!EVP_MD_CTX_copy_ex(&ctx, d)) { EVP_MD_CTX_cleanup(&ctx); - OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); + OPENSSL_PUT_ERROR(SSL, ssl3_handshake_mac, ERR_LIB_EVP); return 0; } @@ -371,7 +399,7 @@ static int ssl3_handshake_mac(SSL *s, int md_nid, const char *sender, int len, if (!EVP_DigestInit_ex(&ctx, EVP_MD_CTX_md(&ctx), NULL)) { EVP_MD_CTX_cleanup(&ctx); - OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); + OPENSSL_PUT_ERROR(SSL, ssl3_handshake_mac, ERR_LIB_EVP); return 0; } EVP_DigestUpdate(&ctx, s->session->master_key, s->session->master_key_length); @@ -392,7 +420,7 @@ int ssl3_record_sequence_update(uint8_t *seq, size_t seq_len) { return 1; } } - OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); + OPENSSL_PUT_ERROR(SSL, ssl3_record_sequence_update, ERR_R_OVERFLOW); return 0; } diff --git a/src/ssl/s3_lib.c b/src/ssl/s3_lib.c index 617ea6e..1c28a73 100644 --- a/src/ssl/s3_lib.c +++ b/src/ssl/s3_lib.c @@ -146,15 +146,12 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. */ -#include <openssl/ssl.h> - #include <assert.h> #include <stdio.h> #include <string.h> #include <openssl/buf.h> #include <openssl/dh.h> -#include <openssl/digest.h> #include <openssl/err.h> #include <openssl/md5.h> #include <openssl/mem.h> @@ -189,8 +186,7 @@ int ssl3_set_handshake_header(SSL *s, int htype, unsigned long len) { s->init_off = 0; /* Add the message to the handshake hash. */ - return ssl3_update_handshake_hash(s, (uint8_t *)s->init_buf->data, - s->init_num); + return ssl3_finish_mac(s, (uint8_t *)s->init_buf->data, s->init_num); } int ssl3_handshake_write(SSL *s) { return ssl3_do_write(s, SSL3_RT_HANDSHAKE); } @@ -203,9 +199,7 @@ int ssl3_new(SSL *s) { goto err; } memset(s3, 0, sizeof *s3); - - EVP_MD_CTX_init(&s3->handshake_hash); - EVP_MD_CTX_init(&s3->handshake_md5); + memset(s3->rrec.seq_num, 0, sizeof(s3->rrec.seq_num)); s->s3 = s3; @@ -225,20 +219,20 @@ void ssl3_free(SSL *s) { return; } + BUF_MEM_free(s->s3->sniff_buffer); ssl3_cleanup_key_block(s); - ssl_read_buffer_clear(s); - ssl_write_buffer_clear(s); + ssl3_release_read_buffer(s); + ssl3_release_write_buffer(s); DH_free(s->s3->tmp.dh); EC_KEY_free(s->s3->tmp.ecdh); sk_X509_NAME_pop_free(s->s3->tmp.ca_names, X509_NAME_free); OPENSSL_free(s->s3->tmp.certificate_types); + OPENSSL_free(s->s3->tmp.peer_ecpointformatlist); OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist); OPENSSL_free(s->s3->tmp.peer_psk_identity_hint); - DH_free(s->s3->tmp.peer_dh_tmp); - EC_KEY_free(s->s3->tmp.peer_ecdh_tmp); - ssl3_free_handshake_buffer(s); - ssl3_free_handshake_hash(s); + BIO_free(s->s3->handshake_buffer); + ssl3_free_digest_list(s); OPENSSL_free(s->s3->alpn_selected); OPENSSL_cleanse(s->s3, sizeof *s->s3); @@ -246,6 +240,8 @@ void ssl3_free(SSL *s) { s->s3 = NULL; } +static int ssl3_set_req_cert_type(CERT *c, const uint8_t *p, size_t len); + int SSL_session_reused(const SSL *ssl) { return ssl->hit; } @@ -278,7 +274,7 @@ int SSL_CTX_set_tmp_dh(SSL_CTX *ctx, const DH *dh) { DH_free(ctx->cert->dh_tmp); ctx->cert->dh_tmp = DHparams_dup(dh); if (ctx->cert->dh_tmp == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB); + OPENSSL_PUT_ERROR(SSL, SSL_CTX_set_tmp_dh, ERR_R_DH_LIB); return 0; } return 1; @@ -288,7 +284,7 @@ int SSL_set_tmp_dh(SSL *ssl, const DH *dh) { DH_free(ssl->cert->dh_tmp); ssl->cert->dh_tmp = DHparams_dup(dh); if (ssl->cert->dh_tmp == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB); + OPENSSL_PUT_ERROR(SSL, SSL_set_tmp_dh, ERR_R_DH_LIB); return 0; } return 1; @@ -296,7 +292,7 @@ int SSL_set_tmp_dh(SSL *ssl, const DH *dh) { int SSL_CTX_set_tmp_ecdh(SSL_CTX *ctx, const EC_KEY *ec_key) { if (ec_key == NULL || EC_KEY_get0_group(ec_key) == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); + OPENSSL_PUT_ERROR(SSL, SSL_CTX_set_tmp_ecdh, ERR_R_PASSED_NULL_PARAMETER); return 0; } ctx->cert->ecdh_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); @@ -305,7 +301,7 @@ int SSL_CTX_set_tmp_ecdh(SSL_CTX *ctx, const EC_KEY *ec_key) { int SSL_set_tmp_ecdh(SSL *ssl, const EC_KEY *ec_key) { if (ec_key == NULL || EC_KEY_get0_group(ec_key) == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); + OPENSSL_PUT_ERROR(SSL, SSL_set_tmp_ecdh, ERR_R_PASSED_NULL_PARAMETER); return 0; } ssl->cert->ecdh_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); @@ -326,7 +322,8 @@ int SSL_CTX_set1_tls_channel_id(SSL_CTX *ctx, EVP_PKEY *private_key) { ctx->tlsext_channel_id_enabled = 1; if (EVP_PKEY_id(private_key) != EVP_PKEY_EC || EVP_PKEY_bits(private_key) != 256) { - OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256); + OPENSSL_PUT_ERROR(SSL, SSL_CTX_set1_tls_channel_id, + SSL_R_CHANNEL_ID_NOT_P256); return 0; } EVP_PKEY_free(ctx->tlsext_channel_id_private); @@ -338,7 +335,7 @@ int SSL_set1_tls_channel_id(SSL *ssl, EVP_PKEY *private_key) { ssl->tlsext_channel_id_enabled = 1; if (EVP_PKEY_id(private_key) != EVP_PKEY_EC || EVP_PKEY_bits(private_key) != 256) { - OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256); + OPENSSL_PUT_ERROR(SSL, SSL_set1_tls_channel_id, SSL_R_CHANNEL_ID_NOT_P256); return 0; } EVP_PKEY_free(ssl->tlsext_channel_id_private); @@ -362,36 +359,238 @@ int SSL_set_tlsext_host_name(SSL *ssl, const char *name) { return 1; } if (strlen(name) > TLSEXT_MAXLEN_host_name) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME); + OPENSSL_PUT_ERROR(SSL, SSL_set_tlsext_host_name, + SSL_R_SSL3_EXT_INVALID_SERVERNAME); return 0; } ssl->tlsext_hostname = BUF_strdup(name); if (ssl->tlsext_hostname == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_set_tlsext_host_name, ERR_R_MALLOC_FAILURE); return 0; } return 1; } -size_t SSL_get0_certificate_types(SSL *ssl, const uint8_t **out_types) { - if (ssl->server || !ssl->s3->tmp.cert_req) { - *out_types = NULL; - return 0; +long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) { + int ret = 0; + + switch (cmd) { + case SSL_CTRL_CHAIN: + if (larg) { + return ssl_cert_set1_chain(s->cert, (STACK_OF(X509) *)parg); + } else { + return ssl_cert_set0_chain(s->cert, (STACK_OF(X509) *)parg); + } + + case SSL_CTRL_CHAIN_CERT: + if (larg) { + return ssl_cert_add1_chain_cert(s->cert, (X509 *)parg); + } else { + return ssl_cert_add0_chain_cert(s->cert, (X509 *)parg); + } + + case SSL_CTRL_GET_CHAIN_CERTS: + *(STACK_OF(X509) **)parg = s->cert->key->chain; + ret = 1; + break; + + case SSL_CTRL_SELECT_CURRENT_CERT: + return ssl_cert_select_current(s->cert, (X509 *)parg); + + case SSL_CTRL_GET_CURVES: { + const uint16_t *clist = s->s3->tmp.peer_ellipticcurvelist; + size_t clistlen = s->s3->tmp.peer_ellipticcurvelist_length; + if (parg) { + size_t i; + int *cptr = parg; + int nid; + for (i = 0; i < clistlen; i++) { + nid = tls1_ec_curve_id2nid(clist[i]); + if (nid != NID_undef) { + cptr[i] = nid; + } else { + cptr[i] = TLSEXT_nid_unknown | clist[i]; + } + } + } + return (int)clistlen; + } + + case SSL_CTRL_SET_CURVES: + return tls1_set_curves(&s->tlsext_ellipticcurvelist, + &s->tlsext_ellipticcurvelist_length, parg, larg); + + case SSL_CTRL_SET_SIGALGS: + return tls1_set_sigalgs(s->cert, parg, larg, 0); + + case SSL_CTRL_SET_CLIENT_SIGALGS: + return tls1_set_sigalgs(s->cert, parg, larg, 1); + + case SSL_CTRL_GET_CLIENT_CERT_TYPES: { + const uint8_t **pctype = parg; + if (s->server || !s->s3->tmp.cert_req) { + return 0; + } + if (pctype) { + *pctype = s->s3->tmp.certificate_types; + } + return (int)s->s3->tmp.num_certificate_types; + } + + case SSL_CTRL_SET_CLIENT_CERT_TYPES: + if (!s->server) { + return 0; + } + return ssl3_set_req_cert_type(s->cert, parg, larg); + + case SSL_CTRL_BUILD_CERT_CHAIN: + return ssl_build_cert_chain(s->cert, s->ctx->cert_store, larg); + + case SSL_CTRL_SET_VERIFY_CERT_STORE: + return ssl_cert_set_cert_store(s->cert, parg, 0, larg); + + case SSL_CTRL_SET_CHAIN_CERT_STORE: + return ssl_cert_set_cert_store(s->cert, parg, 1, larg); + + case SSL_CTRL_GET_SERVER_TMP_KEY: + if (s->server || !s->session || !s->session->sess_cert) { + return 0; + } else { + SESS_CERT *sc; + EVP_PKEY *ptmp; + int rv = 0; + sc = s->session->sess_cert; + if (!sc->peer_dh_tmp && !sc->peer_ecdh_tmp) { + return 0; + } + ptmp = EVP_PKEY_new(); + if (!ptmp) { + return 0; + } + if (sc->peer_dh_tmp) { + rv = EVP_PKEY_set1_DH(ptmp, sc->peer_dh_tmp); + } else if (sc->peer_ecdh_tmp) { + rv = EVP_PKEY_set1_EC_KEY(ptmp, sc->peer_ecdh_tmp); + } + if (rv) { + *(EVP_PKEY **)parg = ptmp; + return 1; + } + EVP_PKEY_free(ptmp); + return 0; + } + + case SSL_CTRL_GET_EC_POINT_FORMATS: { + const uint8_t **pformat = parg; + if (!s->s3->tmp.peer_ecpointformatlist) { + return 0; + } + *pformat = s->s3->tmp.peer_ecpointformatlist; + return (int)s->s3->tmp.peer_ecpointformatlist_length; + } + + default: + break; } - *out_types = ssl->s3->tmp.certificate_types; - return ssl->s3->tmp.num_certificate_types; -} -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, - curves_len); + return ret; } -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, - curves_len); +long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) { + switch (cmd) { + case SSL_CTRL_SET_TLSEXT_TICKET_KEYS: + case SSL_CTRL_GET_TLSEXT_TICKET_KEYS: { + uint8_t *keys = parg; + if (!keys) { + return 48; + } + if (larg != 48) { + OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, SSL_R_INVALID_TICKET_KEYS_LENGTH); + return 0; + } + if (cmd == SSL_CTRL_SET_TLSEXT_TICKET_KEYS) { + memcpy(ctx->tlsext_tick_key_name, keys, 16); + memcpy(ctx->tlsext_tick_hmac_key, keys + 16, 16); + memcpy(ctx->tlsext_tick_aes_key, keys + 32, 16); + } else { + memcpy(keys, ctx->tlsext_tick_key_name, 16); + memcpy(keys + 16, ctx->tlsext_tick_hmac_key, 16); + memcpy(keys + 32, ctx->tlsext_tick_aes_key, 16); + } + return 1; + } + + case SSL_CTRL_SET_CURVES: + return tls1_set_curves(&ctx->tlsext_ellipticcurvelist, + &ctx->tlsext_ellipticcurvelist_length, parg, larg); + + case SSL_CTRL_SET_SIGALGS: + return tls1_set_sigalgs(ctx->cert, parg, larg, 0); + + case SSL_CTRL_SET_CLIENT_SIGALGS: + return tls1_set_sigalgs(ctx->cert, parg, larg, 1); + + case SSL_CTRL_SET_CLIENT_CERT_TYPES: + return ssl3_set_req_cert_type(ctx->cert, parg, larg); + + case SSL_CTRL_BUILD_CERT_CHAIN: + return ssl_build_cert_chain(ctx->cert, ctx->cert_store, larg); + + case SSL_CTRL_SET_VERIFY_CERT_STORE: + return ssl_cert_set_cert_store(ctx->cert, parg, 0, larg); + + case SSL_CTRL_SET_CHAIN_CERT_STORE: + return ssl_cert_set_cert_store(ctx->cert, parg, 1, larg); + + case SSL_CTRL_EXTRA_CHAIN_CERT: + if (ctx->extra_certs == NULL) { + ctx->extra_certs = sk_X509_new_null(); + if (ctx->extra_certs == NULL) { + return 0; + } + } + sk_X509_push(ctx->extra_certs, (X509 *)parg); + break; + + case SSL_CTRL_GET_EXTRA_CHAIN_CERTS: + if (ctx->extra_certs == NULL && larg == 0) { + *(STACK_OF(X509) **)parg = ctx->cert->key->chain; + } else { + *(STACK_OF(X509) **)parg = ctx->extra_certs; + } + break; + + case SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS: + sk_X509_pop_free(ctx->extra_certs, X509_free); + ctx->extra_certs = NULL; + break; + + case SSL_CTRL_CHAIN: + if (larg) { + return ssl_cert_set1_chain(ctx->cert, (STACK_OF(X509) *)parg); + } else { + return ssl_cert_set0_chain(ctx->cert, (STACK_OF(X509) *)parg); + } + + case SSL_CTRL_CHAIN_CERT: + if (larg) { + return ssl_cert_add1_chain_cert(ctx->cert, (X509 *)parg); + } else { + return ssl_cert_add0_chain_cert(ctx->cert, (X509 *)parg); + } + + case SSL_CTRL_GET_CHAIN_CERTS: + *(STACK_OF(X509) **)parg = ctx->cert->key->chain; + break; + + case SSL_CTRL_SELECT_CURRENT_CERT: + return ssl_cert_select_current(ctx->cert, (X509 *)parg); + + default: + return 0; + } + + return 1; } int SSL_CTX_set_tlsext_servername_callback( @@ -405,36 +604,6 @@ int SSL_CTX_set_tlsext_servername_arg(SSL_CTX *ctx, void *arg) { return 1; } -int SSL_CTX_get_tlsext_ticket_keys(SSL_CTX *ctx, void *out, size_t len) { - if (out == NULL) { - return 48; - } - if (len != 48) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH); - return 0; - } - uint8_t *out_bytes = out; - memcpy(out_bytes, ctx->tlsext_tick_key_name, 16); - memcpy(out_bytes + 16, ctx->tlsext_tick_hmac_key, 16); - memcpy(out_bytes + 32, ctx->tlsext_tick_aes_key, 16); - return 1; -} - -int SSL_CTX_set_tlsext_ticket_keys(SSL_CTX *ctx, const void *in, size_t len) { - if (in == NULL) { - return 48; - } - if (len != 48) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH); - return 0; - } - const uint8_t *in_bytes = in; - memcpy(ctx->tlsext_tick_key_name, in_bytes, 16); - memcpy(ctx->tlsext_tick_hmac_key, in_bytes + 16, 16); - memcpy(ctx->tlsext_tick_aes_key, in_bytes + 32, 16); - return 1; -} - int SSL_CTX_set_tlsext_ticket_key_cb( SSL_CTX *ctx, int (*callback)(SSL *ssl, uint8_t *key_name, uint8_t *iv, EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx, @@ -453,11 +622,6 @@ struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *s) { return s->ctx->cipher_list_tls11; } - if (s->version >= TLS1_VERSION && s->ctx != NULL && - s->ctx->cipher_list_tls10 != NULL) { - return s->ctx->cipher_list_tls10; - } - if (s->ctx != NULL && s->ctx->cipher_list != NULL) { return s->ctx->cipher_list; } @@ -544,6 +708,13 @@ int ssl3_get_req_cert_type(SSL *s, uint8_t *p) { int have_rsa_sign = 0; int have_ecdsa_sign = 0; + /* If we have custom certificate types set, use them */ + if (s->cert->client_certificate_types) { + memcpy(p, s->cert->client_certificate_types, + s->cert->num_client_certificate_types); + return s->cert->num_client_certificate_types; + } + /* get configured sigalgs */ siglen = tls12_get_psigalgs(s, &sig); for (i = 0; i < siglen; i += 2, sig += 2) { @@ -571,13 +742,36 @@ int ssl3_get_req_cert_type(SSL *s, uint8_t *p) { return ret; } +static int ssl3_set_req_cert_type(CERT *c, const uint8_t *p, size_t len) { + OPENSSL_free(c->client_certificate_types); + c->client_certificate_types = NULL; + c->num_client_certificate_types = 0; + + if (!p || !len) { + return 1; + } + + if (len > 0xff) { + return 0; + } + + c->client_certificate_types = BUF_memdup(p, len); + if (!c->client_certificate_types) { + return 0; + } + + c->num_client_certificate_types = len; + return 1; +} + /* If we are using default SHA1+MD5 algorithms switch to new SHA256 PRF and * handshake macs if required. */ -uint32_t ssl_get_algorithm_prf(SSL *s) { - uint32_t algorithm_prf = s->s3->tmp.new_cipher->algorithm_prf; +uint32_t ssl_get_algorithm2(SSL *s) { + static const uint32_t kMask = SSL_HANDSHAKE_MAC_DEFAULT; + uint32_t alg2 = s->s3->tmp.new_cipher->algorithm2; if (s->enc_method->enc_flags & SSL_ENC_FLAG_SHA256_PRF && - algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT) { + (alg2 & kMask) == kMask) { return SSL_HANDSHAKE_MAC_SHA256; } - return algorithm_prf; + return alg2; } diff --git a/src/ssl/s3_meth.c b/src/ssl/s3_meth.c index 01c1101..66bbb29 100644 --- a/src/ssl/s3_meth.c +++ b/src/ssl/s3_meth.c @@ -54,8 +54,6 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ -#include <openssl/ssl.h> - #include "internal.h" @@ -70,6 +68,8 @@ static const SSL_PROTOCOL_METHOD TLS_protocol_method = { ssl3_read_close_notify, ssl3_write_app_data, ssl3_dispatch_alert, + ssl3_ctrl, + ssl3_ctx_ctrl, ssl3_supports_cipher, SSL3_HM_HEADER_LENGTH, ssl3_set_handshake_header, diff --git a/src/ssl/s3_pkt.c b/src/ssl/s3_pkt.c index 3c2435d..4a9ae83 100644 --- a/src/ssl/s3_pkt.c +++ b/src/ssl/s3_pkt.c @@ -106,8 +106,6 @@ * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). */ -#include <openssl/ssl.h> - #include <assert.h> #include <limits.h> #include <stdio.h> @@ -122,65 +120,282 @@ #include "internal.h" -static int do_ssl3_write(SSL *s, int type, const uint8_t *buf, unsigned len); +static int do_ssl3_write(SSL *s, int type, const uint8_t *buf, unsigned int len, + char fragment); +static int ssl3_get_record(SSL *s); -/* kMaxWarningAlerts is the number of consecutive warning alerts that will be - * processed. */ -static const uint8_t kMaxWarningAlerts = 4; +int ssl3_read_n(SSL *s, int n, int extend) { + /* If |extend| is 0, obtain new n-byte packet; + * if |extend| is 1, increase packet by another n bytes. + * + * The packet will be in the sub-array of |s->s3->rbuf.buf| specified by + * |s->packet| and |s->packet_length|. (If DTLS and |extend| is 0, additional + * bytes will be read into |rbuf|, up to the size of the buffer.) + * + * TODO(davidben): |dtls1_get_record| and |ssl3_get_record| have very + * different needs. Separate the two record layers. In DTLS, |BIO_read| is + * called at most once, and only when |extend| is 0. In TLS, the buffer never + * contains more than one record. */ + int i, len, left; + uintptr_t align = 0; + uint8_t *pkt; + SSL3_BUFFER *rb; + + if (n <= 0) { + return n; + } -/* ssl3_get_record reads a new input record. On success, it places it in - * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if - * more data is needed. */ -static int ssl3_get_record(SSL *ssl) { - int ret; -again: - /* 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) { - return ret; - } - assert(ssl_read_buffer_len(ssl) >= ssl_record_prefix_len(ssl)); - - uint8_t *out = ssl_read_buffer(ssl) + ssl_record_prefix_len(ssl); - size_t max_out = ssl_read_buffer_len(ssl) - ssl_record_prefix_len(ssl); - uint8_t type, alert; - size_t len, consumed; - switch (tls_open_record(ssl, &type, out, &len, &consumed, &alert, max_out, - ssl_read_buffer(ssl), ssl_read_buffer_len(ssl))) { - case ssl_open_record_success: - ssl_read_buffer_consume(ssl, consumed); - - if (len > 0xffff) { - OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); - return -1; + rb = &s->s3->rbuf; + if (rb->buf == NULL && !ssl3_setup_read_buffer(s)) { + return -1; + } + + left = rb->left; + + align = (uintptr_t)rb->buf + SSL3_RT_HEADER_LENGTH; + align = (0 - align) & (SSL3_ALIGN_PAYLOAD - 1); + + if (!extend) { + /* start with empty packet ... */ + if (left == 0) { + rb->offset = align; + } else if (align != 0 && left >= SSL3_RT_HEADER_LENGTH) { + /* check if next packet length is large enough to justify payload + * alignment... */ + pkt = rb->buf + rb->offset; + if (pkt[0] == SSL3_RT_APPLICATION_DATA && (pkt[3] << 8 | pkt[4]) >= 128) { + /* Note that even if packet is corrupted and its length field is + * insane, we can only be led to wrong decision about whether memmove + * will occur or not. Header values has no effect on memmove arguments + * and therefore no buffer overrun can be triggered. */ + memmove(rb->buf + align, pkt, left); + rb->offset = align; } + } + s->packet = rb->buf + rb->offset; + s->packet_length = 0; + /* ... now we can act as if 'extend' was set */ + } + + /* In DTLS, if there is leftover data from the previous packet or |extend| is + * true, clamp to the previous read. DTLS records may not span packet + * boundaries. */ + if (SSL_IS_DTLS(s) && n > left && (left > 0 || extend)) { + n = left; + } - SSL3_RECORD *rr = &ssl->s3->rrec; - rr->type = type; - rr->length = (uint16_t)len; - rr->off = 0; - rr->data = out; - return 1; - - case ssl_open_record_partial: - ret = ssl_read_buffer_extend_to(ssl, consumed); - if (ret <= 0) { - return ret; + /* if there is enough in the buffer from a previous read, take some */ + if (left >= n) { + s->packet_length += n; + rb->left = left - n; + rb->offset += n; + return n; + } + + /* else we need to read more data */ + + len = s->packet_length; + pkt = rb->buf + align; + /* Move any available bytes to front of buffer: |len| bytes already pointed + * to by |packet|, |left| extra ones at the end. */ + if (s->packet != pkt) { + /* len > 0 */ + memmove(pkt, s->packet, len + left); + s->packet = pkt; + rb->offset = len + align; + } + + if (n > (int)(rb->len - rb->offset)) { + OPENSSL_PUT_ERROR(SSL, ssl3_read_n, ERR_R_INTERNAL_ERROR); + return -1; + } + + int max = n; + if (SSL_IS_DTLS(s) && !extend) { + max = rb->len - rb->offset; + } + + while (left < n) { + /* Now we have len+left bytes at the front of s->s3->rbuf.buf and need to + * read in more until we have len+n (up to len+max if possible). */ + ERR_clear_system_error(); + if (s->rbio != NULL) { + s->rwstate = SSL_READING; + i = BIO_read(s->rbio, pkt + len + left, max - left); + } else { + OPENSSL_PUT_ERROR(SSL, ssl3_read_n, SSL_R_READ_BIO_NOT_SET); + i = -1; + } + + if (i <= 0) { + rb->left = left; + if (len + left == 0) { + ssl3_release_read_buffer(s); } - goto again; + return i; + } + left += i; + /* reads should *never* span multiple packets for DTLS because the + * underlying transport protocol is message oriented as opposed to byte + * oriented as in the TLS case. */ + if (SSL_IS_DTLS(s) && n > left) { + n = left; /* makes the while condition false */ + } + } - case ssl_open_record_discard: - ssl_read_buffer_consume(ssl, consumed); - goto again; + /* done reading, now the book-keeping */ + rb->offset += n; + rb->left = left - n; + s->packet_length += n; + s->rwstate = SSL_NOTHING; - case ssl_open_record_error: - ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); - return -1; + return n; +} + +/* MAX_EMPTY_RECORDS defines the number of consecutive, empty records that will + * be processed per call to ssl3_get_record. Without this limit an attacker + * could send empty records at a faster rate than we can process and cause + * ssl3_get_record to loop forever. */ +#define MAX_EMPTY_RECORDS 32 + +/* Call this to get a new input record. It will return <= 0 if more data is + * needed, normally due to an error or non-blocking IO. When it finishes, one + * packet has been decoded and can be found in + * ssl->s3->rrec.type - is the type of record + * ssl->s3->rrec.data - data + * ssl->s3->rrec.length - number of bytes */ +/* used only by ssl3_read_bytes */ +static int ssl3_get_record(SSL *s) { + uint8_t ssl_major, ssl_minor; + int al, n, i, ret = -1; + SSL3_RECORD *rr = &s->s3->rrec; + uint8_t *p; + uint16_t version; + size_t extra; + unsigned empty_record_count = 0; + +again: + /* check if we have the header */ + if (s->rstate != SSL_ST_READ_BODY || + s->packet_length < SSL3_RT_HEADER_LENGTH) { + n = ssl3_read_n(s, SSL3_RT_HEADER_LENGTH, 0); + if (n <= 0) { + return n; /* error or non-blocking */ + } + s->rstate = SSL_ST_READ_BODY; + + /* Some bytes were read, so the read buffer must be existant and + * |s->s3->init_extra| is defined. */ + assert(s->s3->rbuf.buf != NULL); + extra = s->s3->init_extra ? SSL3_RT_MAX_EXTRA : 0; + + p = s->packet; + if (s->msg_callback) { + s->msg_callback(0, 0, SSL3_RT_HEADER, p, 5, s, s->msg_callback_arg); + } + + /* Pull apart the header into the SSL3_RECORD */ + rr->type = *(p++); + ssl_major = *(p++); + ssl_minor = *(p++); + version = (((uint16_t)ssl_major) << 8) | ssl_minor; + n2s(p, rr->length); + + if (s->s3->have_version && version != s->version) { + OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_WRONG_VERSION_NUMBER); + al = SSL_AD_PROTOCOL_VERSION; + goto f_err; + } + + if ((version >> 8) != SSL3_VERSION_MAJOR) { + OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_WRONG_VERSION_NUMBER); + goto err; + } + + if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH + extra) { + al = SSL_AD_RECORD_OVERFLOW; + OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_ENCRYPTED_LENGTH_TOO_LONG); + goto f_err; + } + + /* now s->rstate == SSL_ST_READ_BODY */ + } else { + /* |packet_length| is non-zero and |s->rstate| is |SSL_ST_READ_BODY|. The + * read buffer must be existant and |s->s3->init_extra| is defined. */ + assert(s->s3->rbuf.buf != NULL); + extra = s->s3->init_extra ? SSL3_RT_MAX_EXTRA : 0; } - assert(0); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return -1; + /* s->rstate == SSL_ST_READ_BODY, get and decode the data */ + + if (rr->length > s->packet_length - SSL3_RT_HEADER_LENGTH) { + /* now s->packet_length == SSL3_RT_HEADER_LENGTH */ + i = rr->length; + n = ssl3_read_n(s, i, 1); + if (n <= 0) { + /* Error or non-blocking IO. Now |n| == |rr->length|, and + * |s->packet_length| == |SSL3_RT_HEADER_LENGTH| + |rr->length|. */ + return n; + } + } + + s->rstate = SSL_ST_READ_HEADER; /* set state for later operations */ + + /* |rr->data| points to |rr->length| bytes of ciphertext in |s->packet|. */ + rr->data = &s->packet[SSL3_RT_HEADER_LENGTH]; + + /* Decrypt the packet in-place. + * + * TODO(davidben): This assumes |s->version| is the same as the record-layer + * version which isn't always true, but it only differs with the NULL cipher + * which ignores the parameter. */ + size_t plaintext_len; + if (!SSL_AEAD_CTX_open(s->aead_read_ctx, rr->data, &plaintext_len, rr->length, + rr->type, s->version, s->s3->read_sequence, rr->data, + rr->length)) { + al = SSL_AD_BAD_RECORD_MAC; + OPENSSL_PUT_ERROR(SSL, ssl3_get_record, + SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); + goto f_err; + } + if (!ssl3_record_sequence_update(s->s3->read_sequence, 8)) { + goto err; + } + if (plaintext_len > SSL3_RT_MAX_PLAIN_LENGTH + extra) { + al = SSL_AD_RECORD_OVERFLOW; + OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_DATA_LENGTH_TOO_LONG); + goto f_err; + } + assert(plaintext_len <= (1u << 16)); + rr->length = plaintext_len; + + rr->off = 0; + /* So at this point the following is true: + * ssl->s3->rrec.type is the type of record; + * ssl->s3->rrec.length is the number of bytes in the record; + * ssl->s3->rrec.off is the offset to first valid byte; + * ssl->s3->rrec.data the first byte of the record body. */ + + /* we have pulled in a full packet so zero things */ + s->packet_length = 0; + + /* just read a 0 length packet */ + if (rr->length == 0) { + empty_record_count++; + if (empty_record_count > MAX_EMPTY_RECORDS) { + al = SSL_AD_UNEXPECTED_MESSAGE; + OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_TOO_MANY_EMPTY_FRAGMENTS); + goto f_err; + } + goto again; + } + + return 1; + +f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); +err: + return ret; } int ssl3_write_app_data(SSL *ssl, const void *buf, int len) { @@ -205,7 +420,7 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) { return i; } if (i == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_write_bytes, SSL_R_SSL_HANDSHAKE_FAILURE); return -1; } } @@ -218,22 +433,33 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) { * beyond the end of the users buffer ... so we trap and report the error in * a way the user will notice. */ if (len < 0 || (size_t)len < tot) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_LENGTH); + OPENSSL_PUT_ERROR(SSL, ssl3_write_bytes, SSL_R_BAD_LENGTH); return -1; } + int record_split_done = 0; n = (len - tot); for (;;) { /* max contains the maximum number of bytes that we can put into a * record. */ unsigned max = s->max_send_fragment; + /* fragment is true if do_ssl3_write should send the first byte in its own + * record in order to randomise a CBC IV. */ + int fragment = 0; + if (!record_split_done && s->s3->need_record_splitting && + type == SSL3_RT_APPLICATION_DATA) { + /* Only the the first record per write call needs to be split. The + * remaining plaintext was determined before the IV was randomized. */ + fragment = 1; + record_split_done = 1; + } if (n > max) { nw = max; } else { nw = n; } - i = do_ssl3_write(s, type, &buf[tot], nw); + i = do_ssl3_write(s, type, &buf[tot], nw, fragment); if (i <= 0) { s->s3->wnum = tot; return i; @@ -249,10 +475,65 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) { } } -/* do_ssl3_write writes an SSL record of the given type. */ -static int do_ssl3_write(SSL *s, int type, const uint8_t *buf, unsigned len) { - /* If there is still data from the previous record, flush it. */ - if (ssl_write_buffer_is_pending(s)) { +/* ssl3_seal_record seals a new record of type |type| and plaintext |in| and + * writes it to |out|. At most |max_out| bytes will be written. It returns one + * on success and zero on error. On success, it updates the write sequence + * number. */ +static int ssl3_seal_record(SSL *s, uint8_t *out, size_t *out_len, + size_t max_out, uint8_t type, const uint8_t *in, + size_t in_len) { + if (max_out < SSL3_RT_HEADER_LENGTH) { + OPENSSL_PUT_ERROR(SSL, ssl3_seal_record, SSL_R_BUFFER_TOO_SMALL); + return 0; + } + + out[0] = type; + + /* Some servers hang if initial ClientHello is larger than 256 bytes and + * record version number > TLS 1.0. */ + uint16_t wire_version = s->version; + if (!s->s3->have_version && s->version > SSL3_VERSION) { + wire_version = TLS1_VERSION; + } + out[1] = wire_version >> 8; + out[2] = wire_version & 0xff; + + size_t ciphertext_len; + if (!SSL_AEAD_CTX_seal(s->aead_write_ctx, out + SSL3_RT_HEADER_LENGTH, + &ciphertext_len, max_out - SSL3_RT_HEADER_LENGTH, + type, wire_version, s->s3->write_sequence, in, + in_len) || + !ssl3_record_sequence_update(s->s3->write_sequence, 8)) { + return 0; + } + + if (ciphertext_len >= 1 << 16) { + OPENSSL_PUT_ERROR(SSL, ssl3_seal_record, ERR_R_OVERFLOW); + return 0; + } + out[3] = ciphertext_len >> 8; + out[4] = ciphertext_len & 0xff; + + *out_len = SSL3_RT_HEADER_LENGTH + ciphertext_len; + + if (s->msg_callback) { + s->msg_callback(1 /* write */, 0, SSL3_RT_HEADER, out, SSL3_RT_HEADER_LENGTH, + s, s->msg_callback_arg); + } + + return 1; +} + +/* do_ssl3_write writes an SSL record of the given type. If |fragment| is 1 + * then it splits the record into a one byte record and a record with the rest + * of the data in order to randomise a CBC IV. */ +static int do_ssl3_write(SSL *s, int type, const uint8_t *buf, unsigned int len, + char fragment) { + SSL3_BUFFER *wb = &s->s3->wbuf; + + /* first check if there is a SSL3_BUFFER still being written out. This will + * happen with non blocking IO */ + if (wb->left != 0) { return ssl3_write_pending(s, type, buf, len); } @@ -265,53 +546,113 @@ static int do_ssl3_write(SSL *s, int type, const uint8_t *buf, unsigned len) { /* if it went, fall through and send more stuff */ } - if (len > SSL3_RT_MAX_PLAIN_LENGTH) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + if (wb->buf == NULL && !ssl3_setup_write_buffer(s)) { return -1; } if (len == 0) { return 0; } + if (len == 1) { + /* No sense in fragmenting a one-byte record. */ + fragment = 0; + } - size_t max_out = len + ssl_max_seal_overhead(s); - if (max_out < len) { - OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); - return -1; + /* Align the output so the ciphertext is aligned to |SSL3_ALIGN_PAYLOAD|. */ + uintptr_t align; + if (fragment) { + /* Only CBC-mode ciphers require fragmenting. CBC-mode ciphertext is a + * multiple of the block size which we may assume is aligned. Thus we only + * need to account for a second copy of the record header. */ + align = (uintptr_t)wb->buf + 2 * SSL3_RT_HEADER_LENGTH; + } else { + align = (uintptr_t)wb->buf + SSL3_RT_HEADER_LENGTH; + } + align = (0 - align) & (SSL3_ALIGN_PAYLOAD - 1); + uint8_t *out = wb->buf + align; + wb->offset = align; + size_t max_out = wb->len - wb->offset; + + const uint8_t *orig_buf = buf; + unsigned int orig_len = len; + size_t fragment_len = 0; + if (fragment) { + /* Write the first byte in its own record as a countermeasure against + * known-IV weaknesses in CBC ciphersuites. (See + * http://www.openssl.org/~bodo/tls-cbc.txt.) */ + if (!ssl3_seal_record(s, out, &fragment_len, max_out, type, buf, 1)) { + return -1; + } + out += fragment_len; + max_out -= fragment_len; + buf++; + len--; } - uint8_t *out; + + assert((((uintptr_t)out + SSL3_RT_HEADER_LENGTH) & (SSL3_ALIGN_PAYLOAD - 1)) + == 0); size_t ciphertext_len; - if (!ssl_write_buffer_init(s, &out, max_out) || - !tls_seal_record(s, out, &ciphertext_len, max_out, type, buf, len)) { + if (!ssl3_seal_record(s, out, &ciphertext_len, max_out, type, buf, len)) { return -1; } - ssl_write_buffer_set_len(s, ciphertext_len); + ciphertext_len += fragment_len; + + /* now let's set up wb */ + wb->left = ciphertext_len; /* memorize arguments so that ssl3_write_pending can detect bad write retries * later */ - s->s3->wpend_tot = len; - s->s3->wpend_buf = buf; + s->s3->wpend_tot = orig_len; + s->s3->wpend_buf = orig_buf; s->s3->wpend_type = type; - s->s3->wpend_ret = len; + s->s3->wpend_ret = orig_len; /* we now just need to write the buffer */ - return ssl3_write_pending(s, type, buf, len); + return ssl3_write_pending(s, type, orig_buf, orig_len); } +/* if s->s3->wbuf.left != 0, we need to call this */ int ssl3_write_pending(SSL *s, int type, const uint8_t *buf, unsigned int len) { + int i; + SSL3_BUFFER *wb = &(s->s3->wbuf); + if (s->s3->wpend_tot > (int)len || (s->s3->wpend_buf != buf && !(s->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)) || s->s3->wpend_type != type) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_WRITE_RETRY); + OPENSSL_PUT_ERROR(SSL, ssl3_write_pending, SSL_R_BAD_WRITE_RETRY); return -1; } - int ret = ssl_write_buffer_flush(s); - if (ret <= 0) { - return ret; + for (;;) { + ERR_clear_system_error(); + if (s->wbio != NULL) { + s->rwstate = SSL_WRITING; + i = BIO_write(s->wbio, (char *)&(wb->buf[wb->offset]), + (unsigned int)wb->left); + } else { + OPENSSL_PUT_ERROR(SSL, ssl3_write_pending, SSL_R_BIO_NOT_SET); + i = -1; + } + if (i == wb->left) { + wb->left = 0; + wb->offset += i; + ssl3_release_write_buffer(s); + s->rwstate = SSL_NOTHING; + return s->s3->wpend_ret; + } else if (i <= 0) { + if (SSL_IS_DTLS(s)) { + /* For DTLS, just drop it. That's kind of the whole point in + * using a datagram service */ + wb->left = 0; + } + return i; + } + /* TODO(davidben): This codepath is used in DTLS, but the write + * payload may not split across packets. */ + wb->offset += i; + wb->left -= i; } - return s->s3->wpend_ret; } /* ssl3_expect_change_cipher_spec informs the record layer that a @@ -321,7 +662,8 @@ int ssl3_write_pending(SSL *s, int type, const uint8_t *buf, unsigned int len) { * function returns zero. Otherwise, the function returns one. */ int ssl3_expect_change_cipher_spec(SSL *s) { if (s->s3->handshake_fragment_len > 0 || s->s3->tmp.reuse_message) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNPROCESSED_HANDSHAKE_DATA); + OPENSSL_PUT_ERROR(SSL, ssl3_expect_change_cipher_spec, + SSL_R_UNPROCESSED_HANDSHAKE_DATA); return 0; } @@ -372,7 +714,7 @@ int ssl3_read_bytes(SSL *s, int type, uint8_t *buf, int len, int peek) { if ((type && type != SSL3_RT_APPLICATION_DATA && type != SSL3_RT_HANDSHAKE) || (peek && type != SSL3_RT_APPLICATION_DATA)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, ERR_R_INTERNAL_ERROR); return -1; } @@ -411,7 +753,7 @@ int ssl3_read_bytes(SSL *s, int type, uint8_t *buf, int len, int peek) { return i; } if (i == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE); return -1; } } @@ -426,7 +768,7 @@ start: rr = &s->s3->rrec; /* get new packet if necessary */ - if (rr->length == 0) { + if (rr->length == 0 || s->rstate == SSL_ST_READ_BODY) { ret = ssl3_get_record(s); if (ret <= 0) { return ret; @@ -440,7 +782,8 @@ start: if (s->s3->change_cipher_spec && rr->type != SSL3_RT_HANDSHAKE && rr->type != SSL3_RT_ALERT) { al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, + SSL_R_DATA_BETWEEN_CCS_AND_FINISHED); goto f_err; } @@ -448,7 +791,7 @@ start: * Handshake record. */ if (rr->type == SSL3_RT_HANDSHAKE && (s->s3->flags & SSL3_FLAGS_EXPECT_CCS)) { al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_HANDSHAKE_RECORD_BEFORE_CCS); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_HANDSHAKE_RECORD_BEFORE_CCS); goto f_err; } @@ -460,9 +803,7 @@ start: return 0; } - if (type != 0 && type == rr->type) { - s->s3->warning_alert_count = 0; - + if (type == rr->type) { /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */ /* make sure that we are not getting application data when we are doing a * handshake for the first time */ @@ -471,15 +812,10 @@ start: /* 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); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_APP_DATA_IN_HANDSHAKE); goto f_err; } - /* Discard empty records. */ - if (rr->length == 0) { - goto start; - } - if (len <= 0) { return len; } @@ -495,9 +831,11 @@ start: rr->length -= n; rr->off += n; if (rr->length == 0) { + s->rstate = SSL_ST_READ_HEADER; rr->off = 0; - /* The record has been consumed, so we may now clear the buffer. */ - ssl_read_buffer_discard(s); + if (s->s3->rbuf.left == 0) { + ssl3_release_read_buffer(s); + } } } @@ -511,7 +849,7 @@ start: * are fatal. Renegotiations as a server are never supported. */ if (!s->accept_peer_renegotiations || s->server) { al = SSL_AD_NO_RENEGOTIATION; - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_NO_RENEGOTIATION); goto f_err; } @@ -534,7 +872,7 @@ start: s->s3->handshake_fragment[2] != 0 || s->s3->handshake_fragment[3] != 0) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HELLO_REQUEST); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_BAD_HELLO_REQUEST); goto f_err; } s->s3->handshake_fragment_len = 0; @@ -548,7 +886,7 @@ start: /* This cannot happen. If a handshake is in progress, |type| must be * |SSL3_RT_HANDSHAKE|. */ assert(0); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, ERR_R_INTERNAL_ERROR); goto err; } @@ -556,9 +894,9 @@ start: * protocol, namely in HTTPS, just before reading the HTTP response. Require * the record-layer be idle and avoid complexities of sending a handshake * record while an application_data record is being written. */ - if (ssl_write_buffer_is_pending(s)) { + if (s->s3->wbuf.left != 0 || s->s3->rbuf.left != 0) { al = SSL_AD_NO_RENEGOTIATION; - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_NO_RENEGOTIATION); goto f_err; } @@ -569,7 +907,7 @@ start: return i; } if (i == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE); return -1; } @@ -583,7 +921,7 @@ start: /* Alerts may not be fragmented. */ if (rr->length < 2) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_BAD_ALERT); goto f_err; } @@ -622,14 +960,7 @@ start: * peer refused it where we carry on. */ else if (alert_descr == SSL_AD_NO_RENEGOTIATION) { al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION); - goto f_err; - } - - s->s3->warning_alert_count++; - if (s->s3->warning_alert_count > kMaxWarningAlerts) { - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_WARNING_ALERTS); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_NO_RENEGOTIATION); goto f_err; } } else if (alert_level == SSL3_AL_FATAL) { @@ -637,7 +968,8 @@ start: s->rwstate = SSL_NOTHING; s->s3->fatal_alert = alert_descr; - OPENSSL_PUT_ERROR(SSL, SSL_AD_REASON_OFFSET + alert_descr); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, + SSL_AD_REASON_OFFSET + alert_descr); BIO_snprintf(tmp, sizeof(tmp), "%d", alert_descr); ERR_add_error_data(2, "SSL alert number ", tmp); s->shutdown |= SSL_RECEIVED_SHUTDOWN; @@ -645,7 +977,7 @@ start: return 0; } else { al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_ALERT_TYPE); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_UNKNOWN_ALERT_TYPE); goto f_err; } @@ -653,9 +985,10 @@ start: } if (s->shutdown & SSL_SENT_SHUTDOWN) { - /* close_notify has been sent, so discard all records other than alerts. */ + /* but we have not received a shutdown */ + s->rwstate = SSL_NOTHING; rr->length = 0; - goto start; + return 0; } if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) { @@ -663,20 +996,20 @@ start: * record payload has to look like */ if (rr->length != 1 || rr->off != 0 || rr->data[0] != SSL3_MT_CCS) { al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_BAD_CHANGE_CIPHER_SPEC); goto f_err; } /* Check we have a cipher to change to */ if (s->s3->tmp.new_cipher == NULL) { al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_CCS_RECEIVED_EARLY); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_CCS_RECEIVED_EARLY); goto f_err; } if (!(s->s3->flags & SSL3_FLAGS_EXPECT_CCS)) { al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_CCS_RECEIVED_EARLY); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_CCS_RECEIVED_EARLY); goto f_err; } @@ -702,7 +1035,7 @@ start: rr->type != SSL3_RT_HANDSHAKE); al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_UNEXPECTED_RECORD); f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); @@ -722,7 +1055,8 @@ int ssl3_do_change_cipher_spec(SSL *s) { if (s->s3->tmp.key_block == NULL) { if (s->session == NULL || s->session->master_key_length == 0) { /* might happen if dtls1_read_bytes() calls this */ - OPENSSL_PUT_ERROR(SSL, SSL_R_CCS_RECEIVED_EARLY); + OPENSSL_PUT_ERROR(SSL, ssl3_do_change_cipher_spec, + SSL_R_CCS_RECEIVED_EARLY); return 0; } @@ -758,9 +1092,8 @@ int ssl3_send_alert(SSL *s, int level, int desc) { s->s3->alert_dispatch = 1; s->s3->send_alert[0] = level; s->s3->send_alert[1] = desc; - if (!ssl_write_buffer_is_pending(s)) { - /* Nothing is being written out, so the alert may be dispatched - * immediately. */ + if (s->s3->wbuf.left == 0) { + /* data is still being written out. */ return s->method->ssl_dispatch_alert(s); } @@ -774,7 +1107,7 @@ int ssl3_dispatch_alert(SSL *s) { void (*cb)(const SSL *ssl, int type, int val) = NULL; s->s3->alert_dispatch = 0; - i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], 2); + i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], 2, 0); if (i <= 0) { s->s3->alert_dispatch = 1; } else { diff --git a/src/ssl/s3_srvr.c b/src/ssl/s3_srvr.c index b428043..a72e17e 100644 --- a/src/ssl/s3_srvr.c +++ b/src/ssl/s3_srvr.c @@ -146,8 +146,6 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. */ -#include <openssl/ssl.h> - #include <assert.h> #include <stdio.h> #include <string.h> @@ -174,6 +172,10 @@ #include "../crypto/dh/internal.h" +/* INITIAL_SNIFF_BUFFER_SIZE is the number of bytes read in the initial sniff + * buffer. */ +#define INITIAL_SNIFF_BUFFER_SIZE 8 + int ssl3_accept(SSL *s) { BUF_MEM *buf = NULL; uint32_t alg_a; @@ -197,7 +199,7 @@ int ssl3_accept(SSL *s) { s->in_handshake++; if (s->cert == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET); + OPENSSL_PUT_ERROR(SSL, ssl3_accept, SSL_R_NO_CERTIFICATE_SET); return -1; } @@ -228,8 +230,8 @@ int ssl3_accept(SSL *s) { goto end; } - if (!ssl3_init_handshake_buffer(s)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + if (!ssl3_init_finished_mac(s)) { + OPENSSL_PUT_ERROR(SSL, ssl3_accept, ERR_R_INTERNAL_ERROR); ret = -1; goto end; } @@ -308,19 +310,8 @@ int ssl3_accept(SSL *s) { s->init_num = 0; break; - case SSL3_ST_SW_CERT_STATUS_A: - case SSL3_ST_SW_CERT_STATUS_B: - ret = ssl3_send_certificate_status(s); - if (ret <= 0) { - goto end; - } - s->state = SSL3_ST_SW_KEY_EXCH_A; - s->init_num = 0; - break; - case SSL3_ST_SW_KEY_EXCH_A: case SSL3_ST_SW_KEY_EXCH_B: - case SSL3_ST_SW_KEY_EXCH_C: alg_a = s->s3->tmp.new_cipher->algorithm_auth; /* Send a ServerKeyExchange message if: @@ -482,7 +473,7 @@ int ssl3_accept(SSL *s) { /* If this is a full handshake with ChannelID then record the hashshake * hashes in |s->session| in case we need them to verify a ChannelID * signature on a resumption of this session in the future. */ - if (!s->hit) { + if (!s->hit && s->s3->tlsext_channel_id_new) { ret = tls1_record_handshake_hashes_for_channel_id(s); if (ret <= 0) { goto end; @@ -559,8 +550,6 @@ int ssl3_accept(SSL *s) { if (s->ctx->retain_only_sha256_of_client_certs) { X509_free(s->session->peer); s->session->peer = NULL; - sk_X509_pop_free(s->session->cert_chain, X509_free); - s->session->cert_chain = NULL; } s->s3->initial_handshake_complete = 1; @@ -575,7 +564,7 @@ int ssl3_accept(SSL *s) { goto end; default: - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE); + OPENSSL_PUT_ERROR(SSL, ssl3_accept, SSL_R_UNKNOWN_STATE); ret = -1; goto end; } @@ -598,16 +587,42 @@ end: return ret; } +static int ssl3_read_sniff_buffer(SSL *s, size_t n) { + if (s->s3->sniff_buffer == NULL) { + s->s3->sniff_buffer = BUF_MEM_new(); + } + if (s->s3->sniff_buffer == NULL || !BUF_MEM_grow(s->s3->sniff_buffer, n)) { + return -1; + } + + while (s->s3->sniff_buffer_len < n) { + int ret; + + s->rwstate = SSL_READING; + ret = BIO_read(s->rbio, s->s3->sniff_buffer->data + s->s3->sniff_buffer_len, + n - s->s3->sniff_buffer_len); + if (ret <= 0) { + return ret; + } + s->rwstate = SSL_NOTHING; + s->s3->sniff_buffer_len += ret; + } + + return 1; +} + int ssl3_get_initial_bytes(SSL *s) { - /* Read the first 5 bytes, the size of the TLS record header. This is - * sufficient to detect a V2ClientHello and ensures that we never read beyond - * the first record. */ - int ret = ssl_read_buffer_extend_to(s, SSL3_RT_HEADER_LENGTH); + int ret; + const uint8_t *p; + + /* Read the first 8 bytes. To recognize a ClientHello or V2ClientHello only + * needs the first 6 bytes, but 8 is needed to recognize CONNECT below. */ + ret = ssl3_read_sniff_buffer(s, INITIAL_SNIFF_BUFFER_SIZE); if (ret <= 0) { return ret; } - assert(ssl_read_buffer_len(s) == SSL3_RT_HEADER_LENGTH); - const uint8_t *p = ssl_read_buffer(s); + assert(s->s3->sniff_buffer_len >= INITIAL_SNIFF_BUFFER_SIZE); + p = (const uint8_t *)s->s3->sniff_buffer->data; /* Some dedicated error codes for protocol mixups should the application wish * to interpret them differently. (These do not overlap with ClientHello or @@ -616,25 +631,46 @@ int ssl3_get_initial_bytes(SSL *s) { strncmp("POST ", (const char *)p, 5) == 0 || strncmp("HEAD ", (const char *)p, 5) == 0 || strncmp("PUT ", (const char *)p, 4) == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_HTTP_REQUEST); + OPENSSL_PUT_ERROR(SSL, ssl3_get_initial_bytes, SSL_R_HTTP_REQUEST); return -1; } - if (strncmp("CONNE", (const char *)p, 5) == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_HTTPS_PROXY_REQUEST); + if (strncmp("CONNECT ", (const char *)p, 8) == 0) { + OPENSSL_PUT_ERROR(SSL, ssl3_get_initial_bytes, SSL_R_HTTPS_PROXY_REQUEST); return -1; } - /* Determine if this is a V2ClientHello. */ + /* Determine if this is a ClientHello or V2ClientHello. */ if ((p[0] & 0x80) && p[2] == SSL2_MT_CLIENT_HELLO && p[3] >= SSL3_VERSION_MAJOR) { /* This is a V2ClientHello. */ s->state = SSL3_ST_SR_V2_CLIENT_HELLO; return 1; } + if (p[0] == SSL3_RT_HANDSHAKE && p[1] >= SSL3_VERSION_MAJOR && + p[5] == SSL3_MT_CLIENT_HELLO) { + /* This is a ClientHello. Initialize the record layer with the already + * consumed data and continue the handshake. */ + if (!ssl3_setup_read_buffer(s)) { + return -1; + } + assert(s->rstate == SSL_ST_READ_HEADER); + /* There cannot have already been data in the record layer. */ + assert(s->s3->rbuf.left == 0); + memcpy(s->s3->rbuf.buf, p, s->s3->sniff_buffer_len); + s->s3->rbuf.offset = 0; + s->s3->rbuf.left = s->s3->sniff_buffer_len; + s->packet_length = 0; - /* Fall through to the standard logic. */ - s->state = SSL3_ST_SR_CLNT_HELLO_A; - return 1; + BUF_MEM_free(s->s3->sniff_buffer); + s->s3->sniff_buffer = NULL; + s->s3->sniff_buffer_len = 0; + + s->state = SSL3_ST_SR_CLNT_HELLO_A; + return 1; + } + + OPENSSL_PUT_ERROR(SSL, ssl3_get_initial_bytes, SSL_R_UNKNOWN_PROTOCOL); + return -1; } int ssl3_get_v2_client_hello(SSL *s) { @@ -647,34 +683,36 @@ int ssl3_get_v2_client_hello(SSL *s) { CBB client_hello, hello_body, cipher_suites; uint8_t random[SSL3_RANDOM_SIZE]; - /* Determine the length of the V2ClientHello. */ - assert(ssl_read_buffer_len(s) >= SSL3_RT_HEADER_LENGTH); - p = ssl_read_buffer(s); + /* Read the remainder of the V2ClientHello. We have previously read 8 bytes + * in ssl3_get_initial_bytes. */ + assert(s->s3->sniff_buffer_len >= INITIAL_SNIFF_BUFFER_SIZE); + p = (const uint8_t *)s->s3->sniff_buffer->data; msg_length = ((p[0] & 0x7f) << 8) | p[1]; if (msg_length > (1024 * 4)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_TOO_LARGE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_v2_client_hello, SSL_R_RECORD_TOO_LARGE); return -1; } - if (msg_length < SSL3_RT_HEADER_LENGTH - 2) { - /* Reject lengths that are too short early. We have already read - * |SSL3_RT_HEADER_LENGTH| bytes, so we should not attempt to process an - * (invalid) V2ClientHello which would be shorter than that. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_LENGTH_MISMATCH); + if (msg_length < INITIAL_SNIFF_BUFFER_SIZE - 2) { + /* Reject lengths that are too short early. We have already read 8 bytes, + * so we should not attempt to process an (invalid) V2ClientHello which + * would be shorter than that. */ + OPENSSL_PUT_ERROR(SSL, ssl3_get_v2_client_hello, + SSL_R_RECORD_LENGTH_MISMATCH); return -1; } - /* Read the remainder of the V2ClientHello. */ - ret = ssl_read_buffer_extend_to(s, 2 + msg_length); + ret = ssl3_read_sniff_buffer(s, msg_length + 2); if (ret <= 0) { return ret; } - assert(ssl_read_buffer_len(s) == msg_length + 2); - CBS_init(&v2_client_hello, ssl_read_buffer(s) + 2, msg_length); + assert(s->s3->sniff_buffer_len == msg_length + 2); + CBS_init(&v2_client_hello, (const uint8_t *)s->s3->sniff_buffer->data + 2, + msg_length); - /* The V2ClientHello without the length is incorporated into the handshake + /* The V2ClientHello without the length is incorporated into the Finished * hash. */ - if (!ssl3_update_handshake_hash(s, CBS_data(&v2_client_hello), - CBS_len(&v2_client_hello))) { + if (!ssl3_finish_mac(s, CBS_data(&v2_client_hello), + CBS_len(&v2_client_hello))) { return -1; } if (s->msg_callback) { @@ -691,7 +729,7 @@ int ssl3_get_v2_client_hello(SSL *s) { !CBS_get_bytes(&v2_client_hello, &session_id, session_id_length) || !CBS_get_bytes(&v2_client_hello, &challenge, challenge_length) || CBS_len(&v2_client_hello) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_v2_client_hello, SSL_R_DECODE_ERROR); return -1; } @@ -709,10 +747,12 @@ int ssl3_get_v2_client_hello(SSL *s) { rand_len); /* Write out an equivalent SSLv3 ClientHello. */ - CBB_zero(&client_hello); if (!CBB_init_fixed(&client_hello, (uint8_t *)s->init_buf->data, - s->init_buf->max) || - !CBB_add_u8(&client_hello, SSL3_MT_CLIENT_HELLO) || + s->init_buf->max)) { + OPENSSL_PUT_ERROR(SSL, ssl3_get_v2_client_hello, ERR_R_MALLOC_FAILURE); + return -1; + } + if (!CBB_add_u8(&client_hello, SSL3_MT_CLIENT_HELLO) || !CBB_add_u24_length_prefixed(&client_hello, &hello_body) || !CBB_add_u16(&hello_body, version) || !CBB_add_bytes(&hello_body, random, SSL3_RANDOM_SIZE) || @@ -720,7 +760,7 @@ int ssl3_get_v2_client_hello(SSL *s) { !CBB_add_u8(&hello_body, 0) || !CBB_add_u16_length_prefixed(&hello_body, &cipher_suites)) { CBB_cleanup(&client_hello); - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_v2_client_hello, ERR_R_INTERNAL_ERROR); return -1; } @@ -729,7 +769,7 @@ int ssl3_get_v2_client_hello(SSL *s) { uint32_t cipher_spec; if (!CBS_get_u24(&cipher_specs, &cipher_spec)) { CBB_cleanup(&client_hello); - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_v2_client_hello, SSL_R_DECODE_ERROR); return -1; } @@ -739,7 +779,7 @@ int ssl3_get_v2_client_hello(SSL *s) { } if (!CBB_add_u16(&cipher_suites, cipher_spec)) { CBB_cleanup(&client_hello); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_v2_client_hello, ERR_R_INTERNAL_ERROR); return -1; } } @@ -748,7 +788,7 @@ int ssl3_get_v2_client_hello(SSL *s) { if (!CBB_add_u8(&hello_body, 1) || !CBB_add_u8(&hello_body, 0) || !CBB_finish(&client_hello, NULL, &len)) { CBB_cleanup(&client_hello); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_v2_client_hello, ERR_R_INTERNAL_ERROR); return -1; } @@ -758,9 +798,10 @@ int ssl3_get_v2_client_hello(SSL *s) { /* The handshake message header is 4 bytes. */ s->s3->tmp.message_size = len - 4; - /* Consume and discard the V2ClientHello. */ - ssl_read_buffer_consume(s, 2 + msg_length); - ssl_read_buffer_discard(s); + /* Drop the sniff buffer. */ + BUF_MEM_free(s->s3->sniff_buffer); + s->s3->sniff_buffer = NULL; + s->s3->sniff_buffer_len = 0; return 1; } @@ -774,7 +815,6 @@ int ssl3_get_client_hello(SSL *s) { CBS client_hello; uint16_t client_version; CBS client_random, session_id, cipher_suites, compression_methods; - SSL_SESSION *session = NULL; /* We do this so that we will respond with our native type. If we are TLSv1 * and we get SSLv3, we will respond with TLSv1, This down switching should @@ -807,7 +847,8 @@ int ssl3_get_client_hello(SSL *s) { early_ctx.client_hello_len = n; if (!ssl_early_callback_init(&early_ctx)) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, + SSL_R_CLIENTHELLO_PARSE_FAILED); goto f_err; } @@ -822,7 +863,8 @@ int ssl3_get_client_hello(SSL *s) { case -1: /* Connection rejected. */ al = SSL_AD_ACCESS_DENIED; - OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, + SSL_R_CONNECTION_REJECTED); goto f_err; default: @@ -833,7 +875,7 @@ int ssl3_get_client_hello(SSL *s) { break; default: - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_UNKNOWN_STATE); return -1; } @@ -843,7 +885,7 @@ int ssl3_get_client_hello(SSL *s) { !CBS_get_u8_length_prefixed(&client_hello, &session_id) || CBS_len(&session_id) > SSL_MAX_SSL_SESSION_ID_LENGTH) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_DECODE_ERROR); goto f_err; } @@ -860,7 +902,7 @@ int ssl3_get_client_hello(SSL *s) { if (!CBS_get_u8_length_prefixed(&client_hello, &cookie) || CBS_len(&cookie) > DTLS1_COOKIE_LENGTH) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_DECODE_ERROR); goto f_err; } } @@ -874,7 +916,7 @@ int ssl3_get_client_hello(SSL *s) { /* Select version to use */ uint16_t version = ssl3_get_mutual_version(s, client_version); if (version == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_UNSUPPORTED_PROTOCOL); s->version = s->client_version; al = SSL_AD_PROTOCOL_VERSION; goto f_err; @@ -887,23 +929,19 @@ int ssl3_get_client_hello(SSL *s) { s->s3->have_version = 1; } else if (SSL_IS_DTLS(s) ? (s->client_version > s->version) : (s->client_version < s->version)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_NUMBER); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_WRONG_VERSION_NUMBER); al = SSL_AD_PROTOCOL_VERSION; goto f_err; } s->hit = 0; - int send_new_ticket = 0; - switch (ssl_get_prev_session(s, &session, &send_new_ticket, &early_ctx)) { - case ssl_session_success: - break; - case ssl_session_error: - goto err; - case ssl_session_retry: - s->rwstate = SSL_PENDING_SESSION; - goto err; + int session_ret = ssl_get_prev_session(s, &early_ctx); + if (session_ret == PENDING_SESSION) { + s->rwstate = SSL_PENDING_SESSION; + goto err; + } else if (session_ret == -1) { + goto err; } - s->tlsext_ticket_expected = send_new_ticket; /* The EMS state is needed when making the resumption decision, but * extensions are not normally parsed until later. This detects the EMS @@ -918,40 +956,34 @@ int ssl3_get_client_hello(SSL *s) { &ems_data, &ems_len) && ems_len == 0; - if (session != NULL) { - if (session->extended_master_secret && + if (session_ret == 1) { + if (s->session->extended_master_secret && !have_extended_master_secret) { /* A ClientHello without EMS that attempts to resume a session with EMS * is fatal to the connection. */ al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, + SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION); goto f_err; } s->hit = /* Only resume if the session's version matches the negotiated version: * most clients do not accept a mismatch. */ - s->version == session->ssl_version && + s->version == s->session->ssl_version && /* If the client offers the EMS extension, but the previous session * didn't use it, then negotiate a new session. */ - have_extended_master_secret == session->extended_master_secret; + have_extended_master_secret == s->session->extended_master_secret; } - if (s->hit) { - /* Use the new session. */ - SSL_SESSION_free(s->session); - s->session = session; - session = NULL; - - s->verify_result = s->session->verify_result; - } else if (!ssl_get_new_session(s, 1)) { + if (!s->hit && !ssl_get_new_session(s, 1)) { goto err; } if (s->ctx->dos_protection_cb != NULL && s->ctx->dos_protection_cb(&early_ctx) == 0) { /* Connection rejected for DOS reasons. */ al = SSL_AD_ACCESS_DENIED; - OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_CONNECTION_REJECTED); goto f_err; } @@ -961,7 +993,7 @@ int ssl3_get_client_hello(SSL *s) { !CBS_get_u8_length_prefixed(&client_hello, &compression_methods) || CBS_len(&compression_methods) == 0) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_DECODE_ERROR); goto f_err; } @@ -988,7 +1020,8 @@ int ssl3_get_client_hello(SSL *s) { /* we need to have the cipher in the cipher list if we are asked to reuse * it */ al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_REQUIRED_CIPHER_MISSING); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, + SSL_R_REQUIRED_CIPHER_MISSING); goto f_err; } } @@ -997,14 +1030,15 @@ int ssl3_get_client_hello(SSL *s) { if (memchr(CBS_data(&compression_methods), 0, CBS_len(&compression_methods)) == NULL) { al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_COMPRESSION_SPECIFIED); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, + SSL_R_NO_COMPRESSION_SPECIFIED); goto f_err; } /* TLS extensions. */ if (s->version >= SSL3_VERSION && !ssl_parse_clienthello_tlsext(s, &client_hello)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_PARSE_TLSEXT); goto err; } @@ -1012,13 +1046,13 @@ int ssl3_get_client_hello(SSL *s) { if (CBS_len(&client_hello) != 0) { /* wrong packet length */ al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_BAD_PACKET_LENGTH); goto f_err; } if (have_extended_master_secret != s->s3->tmp.extended_master_secret) { al = SSL_AD_INTERNAL_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_EMS_STATE_INCONSISTENT); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_EMS_STATE_INCONSISTENT); goto f_err; } @@ -1026,7 +1060,7 @@ int ssl3_get_client_hello(SSL *s) { if (!s->hit) { if (ciphers == NULL) { al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHERS_PASSED); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_NO_CIPHERS_PASSED); goto f_err; } @@ -1035,7 +1069,7 @@ int ssl3_get_client_hello(SSL *s) { int rv = s->cert->cert_cb(s, s->cert->cert_cb_arg); if (rv == 0) { al = SSL_AD_INTERNAL_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_CERT_CB_ERROR); goto f_err; } if (rv < 0) { @@ -1048,7 +1082,7 @@ int ssl3_get_client_hello(SSL *s) { if (c == NULL) { al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_NO_SHARED_CIPHER); goto f_err; } s->s3->tmp.new_cipher = c; @@ -1070,15 +1104,11 @@ int ssl3_get_client_hello(SSL *s) { s->s3->tmp.cert_request = 0; } - /* Now that the cipher is known, initialize the handshake hash. */ - if (!ssl3_init_handshake_hash(s)) { - goto f_err; - } - /* In TLS 1.2, client authentication requires hashing the handshake transcript * under a different hash. Otherwise, release the handshake buffer. */ - if (!SSL_USE_SIGALGS(s) || !s->s3->tmp.cert_request) { - ssl3_free_handshake_buffer(s); + if ((!SSL_USE_SIGALGS(s) || !s->s3->tmp.cert_request) && + !ssl3_digest_cached_records(s, free_handshake_buffer)) { + goto f_err; } /* we now have the following setup; @@ -1102,7 +1132,6 @@ int ssl3_get_client_hello(SSL *s) { err: sk_SSL_CIPHER_free(ciphers); - SSL_SESSION_free(session); return ret; } @@ -1123,7 +1152,8 @@ int ssl3_send_server_hello(SSL *s) { /* If this is a resumption and the original handshake didn't support * ChannelID then we didn't record the original handshake hashes in the * session and so cannot resume with ChannelIDs. */ - if (s->hit && s->session->original_handshake_hash_len == 0) { + if (s->hit && s->s3->tlsext_channel_id_new && + s->session->original_handshake_hash_len == 0) { s->s3->tlsext_channel_id_valid = 0; } @@ -1137,7 +1167,7 @@ int ssl3_send_server_hello(SSL *s) { /* Random stuff */ if (!ssl_fill_hello_random(s->s3->server_random, SSL3_RANDOM_SIZE, 1 /* server */)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_hello, ERR_R_INTERNAL_ERROR); return -1; } memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE); @@ -1161,7 +1191,7 @@ int ssl3_send_server_hello(SSL *s) { sl = s->session->session_id_length; if (sl > (int)sizeof(s->session->session_id)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_hello, ERR_R_INTERNAL_ERROR); return -1; } *(p++) = sl; @@ -1173,10 +1203,13 @@ int ssl3_send_server_hello(SSL *s) { /* put the compression method */ *(p++) = 0; - + if (ssl_prepare_serverhello_tlsext(s) <= 0) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_hello, SSL_R_SERVERHELLO_TLSEXT); + return -1; + } p = ssl_add_serverhello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH); if (p == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_hello, ERR_R_INTERNAL_ERROR); return -1; } @@ -1192,32 +1225,6 @@ int ssl3_send_server_hello(SSL *s) { return ssl_do_write(s); } -int ssl3_send_certificate_status(SSL *ssl) { - if (ssl->state == SSL3_ST_SW_CERT_STATUS_A) { - CBB out, ocsp_response; - size_t length; - - CBB_zero(&out); - if (!CBB_init_fixed(&out, ssl_handshake_start(ssl), - ssl->init_buf->max - SSL_HM_HEADER_LENGTH(ssl)) || - !CBB_add_u8(&out, TLSEXT_STATUSTYPE_ocsp) || - !CBB_add_u24_length_prefixed(&out, &ocsp_response) || - !CBB_add_bytes(&ocsp_response, ssl->ctx->ocsp_response, - ssl->ctx->ocsp_response_length) || - !CBB_finish(&out, NULL, &length) || - !ssl_set_handshake_header(ssl, SSL3_MT_CERTIFICATE_STATUS, length)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - CBB_cleanup(&out); - return -1; - } - - ssl->state = SSL3_ST_SW_CERT_STATUS_B; - } - - /* SSL3_ST_SW_CERT_STATUS_B */ - return ssl_do_write(ssl); -} - int ssl3_send_server_done(SSL *s) { if (s->state == SSL3_ST_SW_SRVR_DONE_A) { if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_DONE, 0)) { @@ -1239,8 +1246,7 @@ int ssl3_send_server_key_exchange(SSL *s) { BN_CTX *bn_ctx = NULL; const char *psk_identity_hint = NULL; size_t psk_identity_hint_len = 0; - size_t sig_len; - size_t max_sig_len; + EVP_PKEY *pkey; uint8_t *p, *d; int al, i; uint32_t alg_k; @@ -1248,26 +1254,11 @@ int ssl3_send_server_key_exchange(SSL *s) { int n; CERT *cert; BIGNUM *r[4]; - int nr[4]; + int nr[4], kn; BUF_MEM *buf; EVP_MD_CTX md_ctx; - if (s->state == SSL3_ST_SW_KEY_EXCH_C) { - return ssl_do_write(s); - } - - if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) { - if (!ssl_has_private_key(s)) { - al = SSL_AD_INTERNAL_ERROR; - goto f_err; - } - max_sig_len = ssl_private_key_max_signature_len(s); - } else { - max_sig_len = 0; - } - EVP_MD_CTX_init(&md_ctx); - enum ssl_private_key_result_t sign_result; if (s->state == SSL3_ST_SW_KEY_EXCH_A) { alg_k = s->s3->tmp.new_cipher->algorithm_mkey; alg_a = s->s3->tmp.new_cipher->algorithm_auth; @@ -1295,23 +1286,25 @@ int ssl3_send_server_key_exchange(SSL *s) { } if (dhp == NULL) { al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_TMP_DH_KEY); + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, + SSL_R_MISSING_TMP_DH_KEY); goto f_err; } if (s->s3->tmp.dh != NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, + ERR_R_INTERNAL_ERROR); goto err; } dh = DHparams_dup(dhp); if (dh == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_DH_LIB); goto err; } s->s3->tmp.dh = dh; if (!DH_generate_key(dh)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_DH_LIB); goto err; } @@ -1335,12 +1328,14 @@ int ssl3_send_server_key_exchange(SSL *s) { } if (nid == NID_undef) { al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_TMP_ECDH_KEY); + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, + SSL_R_MISSING_TMP_ECDH_KEY); goto f_err; } if (s->s3->tmp.ecdh != NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, + ERR_R_INTERNAL_ERROR); goto err; } ecdh = EC_KEY_new_by_curve_name(nid); @@ -1350,14 +1345,15 @@ int ssl3_send_server_key_exchange(SSL *s) { s->s3->tmp.ecdh = ecdh; if (!EC_KEY_generate_key(ecdh)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ECDH_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_ECDH_LIB); goto err; } /* We only support ephemeral ECDH keys over named (not generic) curves. */ const EC_GROUP *group = EC_KEY_get0_group(ecdh); if (!tls1_ec_nid2curve_id(&curve_id, EC_GROUP_get_curve_name(group))) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE); + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, + SSL_R_UNSUPPORTED_ELLIPTIC_CURVE); goto err; } @@ -1370,7 +1366,8 @@ int ssl3_send_server_key_exchange(SSL *s) { encodedPoint = (uint8_t *)OPENSSL_malloc(encodedlen * sizeof(uint8_t)); bn_ctx = BN_CTX_new(); if (encodedPoint == NULL || bn_ctx == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, + ERR_R_MALLOC_FAILURE); goto err; } @@ -1379,7 +1376,7 @@ int ssl3_send_server_key_exchange(SSL *s) { encodedPoint, encodedlen, bn_ctx); if (encodedlen == 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ECDH_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_ECDH_LIB); goto err; } @@ -1399,7 +1396,8 @@ int ssl3_send_server_key_exchange(SSL *s) { r[3] = NULL; } else if (!(alg_k & SSL_kPSK)) { al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE); + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, + SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE); goto f_err; } @@ -1408,8 +1406,20 @@ int ssl3_send_server_key_exchange(SSL *s) { n += 2 + nr[i]; } - if (!BUF_MEM_grow_clean(buf, n + SSL_HM_HEADER_LENGTH(s) + max_sig_len)) { - OPENSSL_PUT_ERROR(SSL, ERR_LIB_BUF); + if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) { + pkey = ssl_get_sign_pkey(s, s->s3->tmp.new_cipher); + if (pkey == NULL) { + al = SSL_AD_DECODE_ERROR; + goto f_err; + } + kn = EVP_PKEY_size(pkey); + } else { + pkey = NULL; + kn = 0; + } + + if (!BUF_MEM_grow_clean(buf, n + SSL_HM_HEADER_LENGTH(s) + kn)) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_LIB_BUF); goto err; } d = p = ssl_handshake_start(s); @@ -1448,81 +1458,54 @@ int ssl3_send_server_key_exchange(SSL *s) { encodedPoint = NULL; } - if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) { - /* n is the length of the params, they start at d and p points to + /* not anonymous */ + if (pkey != NULL) { + /* n is the length of the params, they start at &(d[4]) and p points to * the space at the end. */ const EVP_MD *md; - uint8_t digest[EVP_MAX_MD_SIZE]; - unsigned int digest_length; - - const int pkey_type = ssl_private_key_type(s); + size_t sig_len = EVP_PKEY_size(pkey); /* Determine signature algorithm. */ if (SSL_USE_SIGALGS(s)) { - md = tls1_choose_signing_digest(s); - if (!tls12_get_sigandhash(s, p, md)) { + md = tls1_choose_signing_digest(s, pkey); + if (!tls12_get_sigandhash(p, pkey, md)) { /* Should never happen */ al = SSL_AD_INTERNAL_ERROR; - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, + ERR_R_INTERNAL_ERROR); goto f_err; } p += 2; - } else if (pkey_type == EVP_PKEY_RSA) { + } else if (pkey->type == EVP_PKEY_RSA) { md = EVP_md5_sha1(); } else { md = EVP_sha1(); } - if (!EVP_DigestInit_ex(&md_ctx, md, NULL) || - !EVP_DigestUpdate(&md_ctx, s->s3->client_random, SSL3_RANDOM_SIZE) || - !EVP_DigestUpdate(&md_ctx, s->s3->server_random, SSL3_RANDOM_SIZE) || - !EVP_DigestUpdate(&md_ctx, d, n) || - !EVP_DigestFinal_ex(&md_ctx, digest, &digest_length)) { - OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); + if (!EVP_DigestSignInit(&md_ctx, NULL, md, NULL, pkey) || + !EVP_DigestSignUpdate(&md_ctx, s->s3->client_random, + SSL3_RANDOM_SIZE) || + !EVP_DigestSignUpdate(&md_ctx, s->s3->server_random, + SSL3_RANDOM_SIZE) || + !EVP_DigestSignUpdate(&md_ctx, d, n) || + !EVP_DigestSignFinal(&md_ctx, &p[2], &sig_len)) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_LIB_EVP); goto err; } - sign_result = ssl_private_key_sign(s, &p[2], &sig_len, max_sig_len, - EVP_MD_CTX_md(&md_ctx), digest, - digest_length); - } else { - /* This key exchange doesn't involve a signature. */ - sign_result = ssl_private_key_success; - sig_len = 0; + s2n(sig_len, p); + n += sig_len + 2; + if (SSL_USE_SIGALGS(s)) { + n += 2; + } } - } else { - assert(s->state == SSL3_ST_SW_KEY_EXCH_B); - /* Restore |p|. */ - p = ssl_handshake_start(s) + s->init_num - SSL_HM_HEADER_LENGTH(s); - sign_result = ssl_private_key_sign_complete(s, &p[2], &sig_len, - max_sig_len); - } - switch (sign_result) { - case ssl_private_key_success: - s->rwstate = SSL_NOTHING; - break; - case ssl_private_key_failure: - s->rwstate = SSL_NOTHING; + if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE, n)) { goto err; - case ssl_private_key_retry: - s->rwstate = SSL_PRIVATE_KEY_OPERATION; - /* Stash away |p|. */ - s->init_num = p - ssl_handshake_start(s) + SSL_HM_HEADER_LENGTH(s); - s->state = SSL3_ST_SW_KEY_EXCH_B; - goto err; - } - - if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) { - s2n(sig_len, p); - p += sig_len; - } - if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE, - p - ssl_handshake_start(s))) { - goto err; + } } - s->state = SSL3_ST_SW_KEY_EXCH_C; + s->state = SSL3_ST_SW_KEY_EXCH_B; EVP_MD_CTX_cleanup(&md_ctx); return ssl_do_write(s); @@ -1575,7 +1558,7 @@ int ssl3_send_certificate_request(SSL *s) { name = sk_X509_NAME_value(sk, i); j = i2d_X509_NAME(name, NULL); if (!BUF_MEM_grow_clean(buf, SSL_HM_HEADER_LENGTH(s) + n + j + 2)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_send_certificate_request, ERR_R_BUF_LIB); goto err; } p = ssl_handshake_start(s) + n; @@ -1646,27 +1629,30 @@ int ssl3_get_client_key_exchange(SSL *s) { * then this is the only field in the message. */ if (!CBS_get_u16_length_prefixed(&client_key_exchange, &psk_identity) || ((alg_k & SSL_kPSK) && CBS_len(&client_key_exchange) != 0)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_DECODE_ERROR); al = SSL_AD_DECODE_ERROR; goto f_err; } if (s->psk_server_callback == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_NO_SERVER_CB); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + SSL_R_PSK_NO_SERVER_CB); al = SSL_AD_INTERNAL_ERROR; goto f_err; } if (CBS_len(&psk_identity) > PSK_MAX_IDENTITY_LEN || CBS_contains_zero_byte(&psk_identity)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + SSL_R_DATA_LENGTH_TOO_LONG); al = SSL_AD_ILLEGAL_PARAMETER; goto f_err; } if (!CBS_strdup(&psk_identity, &s->session->psk_identity)) { al = SSL_AD_INTERNAL_ERROR; - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + ERR_R_MALLOC_FAILURE); goto f_err; } @@ -1674,12 +1660,14 @@ int ssl3_get_client_key_exchange(SSL *s) { psk_len = s->psk_server_callback(s, s->session->psk_identity, psk, sizeof(psk)); if (psk_len > PSK_MAX_PSK_LEN) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + ERR_R_INTERNAL_ERROR); al = SSL_AD_INTERNAL_ERROR; goto f_err; } else if (psk_len == 0) { /* PSK related to the given identity not found */ - OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + SSL_R_PSK_IDENTITY_NOT_FOUND); al = SSL_AD_UNKNOWN_PSK_IDENTITY; goto f_err; } @@ -1693,10 +1681,11 @@ int ssl3_get_client_key_exchange(SSL *s) { uint8_t good; size_t rsa_size, decrypt_len, premaster_index, j; - pkey = s->cert->privatekey; + pkey = s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey; if (pkey == NULL || pkey->type != EVP_PKEY_RSA || pkey->pkey.rsa == NULL) { al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_RSA_CERTIFICATE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + SSL_R_MISSING_RSA_CERTIFICATE); goto f_err; } rsa = pkey->pkey.rsa; @@ -1709,7 +1698,8 @@ int ssl3_get_client_key_exchange(SSL *s) { CBS_len(&client_key_exchange) != 0) { if (!(s->options & SSL_OP_TLS_D5_BUG)) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG); goto f_err; } else { encrypted_premaster_secret = copy; @@ -1726,7 +1716,8 @@ int ssl3_get_client_key_exchange(SSL *s) { rsa_size = RSA_size(rsa); if (rsa_size < SSL_MAX_MASTER_KEY_LENGTH) { al = SSL_AD_DECRYPT_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + SSL_R_DECRYPTION_FAILED); goto f_err; } @@ -1742,7 +1733,8 @@ int ssl3_get_client_key_exchange(SSL *s) { /* Allocate a buffer large enough for an RSA decryption. */ decrypt_buf = OPENSSL_malloc(rsa_size); if (decrypt_buf == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + ERR_R_MALLOC_FAILURE); goto err; } @@ -1756,7 +1748,8 @@ int ssl3_get_client_key_exchange(SSL *s) { if (decrypt_len != rsa_size) { /* This should never happen, but do a check so we do not read * uninitialized memory. */ - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + ERR_R_INTERNAL_ERROR); goto err; } @@ -1779,7 +1772,8 @@ int ssl3_get_client_key_exchange(SSL *s) { BUF_memdup(decrypt_buf + (rsa_size - SSL_MAX_MASTER_KEY_LENGTH), SSL_MAX_MASTER_KEY_LENGTH); if (premaster_secret == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + ERR_R_MALLOC_FAILURE); goto err; } OPENSSL_free(decrypt_buf); @@ -1810,35 +1804,38 @@ int ssl3_get_client_key_exchange(SSL *s) { if (!CBS_get_u16_length_prefixed(&client_key_exchange, &dh_Yc) || CBS_len(&dh_Yc) == 0 || CBS_len(&client_key_exchange) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG); al = SSL_R_DECODE_ERROR; goto f_err; } if (s->s3->tmp.dh == NULL) { al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_TMP_DH_KEY); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + SSL_R_MISSING_TMP_DH_KEY); goto f_err; } dh_srvr = s->s3->tmp.dh; pub = BN_bin2bn(CBS_data(&dh_Yc), CBS_len(&dh_Yc), NULL); if (pub == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BN_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_BN_LIB); goto err; } /* Allocate a buffer for the premaster secret. */ premaster_secret = OPENSSL_malloc(DH_size(dh_srvr)); if (premaster_secret == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + ERR_R_MALLOC_FAILURE); BN_clear_free(pub); goto err; } dh_len = DH_compute_key(premaster_secret, pub, dh_srvr); if (dh_len <= 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_DH_LIB); BN_clear_free(pub); goto err; } @@ -1859,7 +1856,8 @@ int ssl3_get_client_key_exchange(SSL *s) { /* initialize structures for server's ECDH key pair */ srvr_ecdh = EC_KEY_new(); if (srvr_ecdh == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + ERR_R_MALLOC_FAILURE); goto err; } @@ -1872,14 +1870,15 @@ int ssl3_get_client_key_exchange(SSL *s) { if (!EC_KEY_set_group(srvr_ecdh, group) || !EC_KEY_set_private_key(srvr_ecdh, priv_key)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_EC_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_EC_LIB); goto err; } /* Let's get client's public key */ clnt_ecpoint = EC_POINT_new(group); if (clnt_ecpoint == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + ERR_R_MALLOC_FAILURE); goto err; } @@ -1888,33 +1887,35 @@ int ssl3_get_client_key_exchange(SSL *s) { if (!CBS_get_u8_length_prefixed(&client_key_exchange, &ecdh_Yc) || CBS_len(&client_key_exchange) != 0) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_DECODE_ERROR); goto f_err; } bn_ctx = BN_CTX_new(); if (bn_ctx == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + ERR_R_MALLOC_FAILURE); goto err; } if (!EC_POINT_oct2point(group, clnt_ecpoint, CBS_data(&ecdh_Yc), CBS_len(&ecdh_Yc), bn_ctx)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_EC_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_EC_LIB); goto err; } /* Allocate a buffer for both the secret and the PSK. */ field_size = EC_GROUP_get_degree(group); if (field_size <= 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ECDH_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_ECDH_LIB); goto err; } ecdh_len = (field_size + 7) / 8; premaster_secret = OPENSSL_malloc(ecdh_len); if (premaster_secret == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + ERR_R_MALLOC_FAILURE); goto err; } @@ -1922,7 +1923,7 @@ int ssl3_get_client_key_exchange(SSL *s) { ecdh_len = ECDH_compute_key(premaster_secret, ecdh_len, clnt_ecpoint, srvr_ecdh, NULL); if (ecdh_len <= 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ECDH_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_ECDH_LIB); goto err; } @@ -1944,13 +1945,15 @@ int ssl3_get_client_key_exchange(SSL *s) { premaster_secret_len = psk_len; premaster_secret = OPENSSL_malloc(premaster_secret_len); if (premaster_secret == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + ERR_R_MALLOC_FAILURE); goto err; } memset(premaster_secret, 0, premaster_secret_len); } else { al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_TYPE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + SSL_R_UNKNOWN_CIPHER_TYPE); goto f_err; } @@ -1961,14 +1964,18 @@ int ssl3_get_client_key_exchange(SSL *s) { uint8_t *new_data; size_t new_len; - CBB_zero(&new_premaster); - if (!CBB_init(&new_premaster, 2 + psk_len + 2 + premaster_secret_len) || - !CBB_add_u16_length_prefixed(&new_premaster, &child) || + if (!CBB_init(&new_premaster, 2 + psk_len + 2 + premaster_secret_len)) { + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + ERR_R_MALLOC_FAILURE); + goto err; + } + if (!CBB_add_u16_length_prefixed(&new_premaster, &child) || !CBB_add_bytes(&child, premaster_secret, premaster_secret_len) || !CBB_add_u16_length_prefixed(&new_premaster, &child) || !CBB_add_bytes(&child, psk, psk_len) || !CBB_finish(&new_premaster, &new_data, &new_len)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, + ERR_R_INTERNAL_ERROR); CBB_cleanup(&new_premaster); goto err; } @@ -2024,7 +2031,10 @@ int ssl3_get_cert_verify(SSL *s) { * CertificateVerify is required if and only if there's a client certificate. * */ if (peer == NULL) { - ssl3_free_handshake_buffer(s); + if (s->s3->handshake_buffer && + !ssl3_digest_cached_records(s, free_handshake_buffer)) { + return -1; + } return 1; } @@ -2045,7 +2055,8 @@ int ssl3_get_cert_verify(SSL *s) { if (!(X509_certificate_type(peer, pkey) & EVP_PKT_SIGN) || (pkey->type != EVP_PKEY_RSA && pkey->type != EVP_PKEY_EC)) { al = SSL_AD_UNSUPPORTED_CERTIFICATE; - OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, + SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE); goto f_err; } @@ -2058,13 +2069,16 @@ int ssl3_get_cert_verify(SSL *s) { } /* Compute the digest. */ - if (!ssl3_cert_verify_hash(s, digest, &digest_length, &md, pkey->type)) { + if (!ssl3_cert_verify_hash(s, digest, &digest_length, &md, pkey)) { goto err; } /* The handshake buffer is no longer necessary, and we may hash the current * message.*/ - ssl3_free_handshake_buffer(s); + if (s->s3->handshake_buffer && + !ssl3_digest_cached_records(s, free_handshake_buffer)) { + goto err; + } if (!ssl3_hash_current_message(s)) { goto err; } @@ -2073,7 +2087,7 @@ int ssl3_get_cert_verify(SSL *s) { if (!CBS_get_u16_length_prefixed(&certificate_verify, &signature) || CBS_len(&certificate_verify) != 0) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_DECODE_ERROR); goto f_err; } @@ -2086,7 +2100,7 @@ int ssl3_get_cert_verify(SSL *s) { !EVP_PKEY_verify(pctx, CBS_data(&signature), CBS_len(&signature), digest, digest_length)) { al = SSL_AD_DECRYPT_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_SIGNATURE); goto f_err; } @@ -2123,14 +2137,15 @@ int ssl3_get_client_certificate(SSL *s) { if (s->s3->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE) { if ((s->verify_mode & SSL_VERIFY_PEER) && (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, + SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); al = SSL_AD_HANDSHAKE_FAILURE; goto f_err; } /* If tls asked for a client cert, the client must return a 0 list */ if (s->version > SSL3_VERSION && s->s3->tmp.cert_request) { - OPENSSL_PUT_ERROR(SSL, + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST); al = SSL_AD_UNEXPECTED_MESSAGE; goto f_err; @@ -2142,7 +2157,8 @@ int ssl3_get_client_certificate(SSL *s) { if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE) { al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_MESSAGE_TYPE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, + SSL_R_WRONG_MESSAGE_TYPE); goto f_err; } @@ -2150,14 +2166,14 @@ int ssl3_get_client_certificate(SSL *s) { sk = sk_X509_new_null(); if (sk == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, ERR_R_MALLOC_FAILURE); goto err; } if (!CBS_get_u24_length_prefixed(&certificate_msg, &certificate_list) || CBS_len(&certificate_msg) != 0) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, SSL_R_DECODE_ERROR); goto f_err; } @@ -2167,7 +2183,7 @@ int ssl3_get_client_certificate(SSL *s) { if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate)) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, SSL_R_DECODE_ERROR); goto f_err; } @@ -2185,42 +2201,50 @@ int ssl3_get_client_certificate(SSL *s) { x = d2i_X509(NULL, &data, CBS_len(&certificate)); if (x == NULL) { al = SSL_AD_BAD_CERTIFICATE; - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, ERR_R_ASN1_LIB); goto f_err; } if (data != CBS_data(&certificate) + CBS_len(&certificate)) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, + SSL_R_CERT_LENGTH_MISMATCH); goto f_err; } if (!sk_X509_push(sk, x)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, ERR_R_MALLOC_FAILURE); goto err; } x = NULL; } if (sk_X509_num(sk) <= 0) { - /* No client certificate so the handshake buffer may be discarded. */ - ssl3_free_handshake_buffer(s); - /* TLS does not mind 0 certs returned */ if (s->version == SSL3_VERSION) { al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATES_RETURNED); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, + SSL_R_NO_CERTIFICATES_RETURNED); goto f_err; - } else if ((s->verify_mode & SSL_VERIFY_PEER) && + } + /* Fail for TLS only if we required a certificate */ + else if ((s->verify_mode & SSL_VERIFY_PEER) && (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) { - /* Fail for TLS only if we required a certificate */ - OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, + SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); al = SSL_AD_HANDSHAKE_FAILURE; goto f_err; } + /* No client certificate so digest cached records */ + if (s->s3->handshake_buffer && + !ssl3_digest_cached_records(s, free_handshake_buffer)) { + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } } else { i = ssl_verify_cert_chain(s, sk); if (i <= 0) { al = ssl_verify_alarm_type(s->verify_result); - OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED); + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, + SSL_R_CERTIFICATE_VERIFY_FAILED); goto f_err; } } @@ -2229,8 +2253,17 @@ int ssl3_get_client_certificate(SSL *s) { s->session->peer = sk_X509_shift(sk); s->session->verify_result = s->verify_result; - sk_X509_pop_free(s->session->cert_chain, X509_free); - s->session->cert_chain = sk; + /* With the current implementation, sess_cert will always be NULL when we + * arrive here. */ + if (s->session->sess_cert == NULL) { + s->session->sess_cert = ssl_sess_cert_new(); + if (s->session->sess_cert == NULL) { + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, ERR_R_MALLOC_FAILURE); + goto err; + } + } + sk_X509_pop_free(s->session->sess_cert->cert_chain, X509_free); + s->session->sess_cert->cert_chain = sk; /* Inconsistency alert: cert_chain does *not* include the peer's own * certificate, while we do include it in s3_clnt.c */ @@ -2250,8 +2283,17 @@ err: } int ssl3_send_server_certificate(SSL *s) { + CERT_PKEY *cpk; + if (s->state == SSL3_ST_SW_CERT_A) { - if (!ssl3_output_cert_chain(s)) { + cpk = ssl_get_server_send_pkey(s); + if (cpk == NULL) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_certificate, + ERR_R_INTERNAL_ERROR); + return 0; + } + + if (!ssl3_output_cert_chain(s, cpk)) { return 0; } s->state = SSL3_ST_SW_CERT_B; @@ -2402,7 +2444,8 @@ int ssl3_get_next_proto(SSL *s) { /* Clients cannot send a NextProtocol message if we didn't see the extension * in their ClientHello */ if (!s->s3->next_proto_neg_seen) { - OPENSSL_PUT_ERROR(SSL, SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION); + OPENSSL_PUT_ERROR(SSL, ssl3_get_next_proto, + SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION); return -1; } @@ -2422,7 +2465,8 @@ int ssl3_get_next_proto(SSL *s) { * TODO(davidben): Is this check now redundant with * SSL3_FLAGS_EXPECT_CCS? */ if (!s->s3->change_cipher_spec) { - OPENSSL_PUT_ERROR(SSL, SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS); + OPENSSL_PUT_ERROR(SSL, ssl3_get_next_proto, + SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS); return -1; } @@ -2448,10 +2492,11 @@ int ssl3_get_next_proto(SSL *s) { int ssl3_get_channel_id(SSL *s) { int ret = -1, ok; long n; - uint8_t channel_id_hash[EVP_MAX_MD_SIZE]; - size_t channel_id_hash_len; + EVP_MD_CTX md_ctx; + uint8_t channel_id_hash[SHA256_DIGEST_LENGTH]; + unsigned int channel_id_hash_len; const uint8_t *p; - uint16_t extension_type; + uint16_t extension_type, expected_extension_type; EC_GROUP *p256 = NULL; EC_KEY *key = NULL; EC_POINT *point = NULL; @@ -2470,9 +2515,15 @@ int ssl3_get_channel_id(SSL *s) { /* Before incorporating the EncryptedExtensions message to the handshake * hash, compute the hash that should have been signed. */ - if (!tls1_channel_id_hash(s, channel_id_hash, &channel_id_hash_len)) { + channel_id_hash_len = sizeof(channel_id_hash); + EVP_MD_CTX_init(&md_ctx); + if (!EVP_DigestInit_ex(&md_ctx, EVP_sha256(), NULL) || + !tls1_channel_id_hash(&md_ctx, s) || + !EVP_DigestFinal(&md_ctx, channel_id_hash, &channel_id_hash_len)) { + EVP_MD_CTX_cleanup(&md_ctx); return -1; } + EVP_MD_CTX_cleanup(&md_ctx); assert(channel_id_hash_len == SHA256_DIGEST_LENGTH); if (!ssl3_hash_current_message(s)) { @@ -2485,7 +2536,8 @@ int ssl3_get_channel_id(SSL *s) { * * TODO(davidben): Is this check now redundant with SSL3_FLAGS_EXPECT_CCS? */ if (!s->s3->change_cipher_spec) { - OPENSSL_PUT_ERROR(SSL, SSL_R_GOT_CHANNEL_ID_BEFORE_A_CCS); + OPENSSL_PUT_ERROR(SSL, ssl3_get_channel_id, + SSL_R_GOT_CHANNEL_ID_BEFORE_A_CCS); return -1; } @@ -2502,19 +2554,23 @@ int ssl3_get_channel_id(SSL *s) { * uint8 y[32]; * uint8 r[32]; * uint8 s[32]; */ + expected_extension_type = TLSEXT_TYPE_channel_id; + if (s->s3->tlsext_channel_id_new) { + expected_extension_type = TLSEXT_TYPE_channel_id_new; + } if (!CBS_get_u16(&encrypted_extensions, &extension_type) || !CBS_get_u16_length_prefixed(&encrypted_extensions, &extension) || CBS_len(&encrypted_extensions) != 0 || - extension_type != TLSEXT_TYPE_channel_id || + extension_type != expected_extension_type || CBS_len(&extension) != TLSEXT_CHANNEL_ID_SIZE) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_MESSAGE); + OPENSSL_PUT_ERROR(SSL, ssl3_get_channel_id, SSL_R_INVALID_MESSAGE); return -1; } p256 = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); if (!p256) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_P256_SUPPORT); + OPENSSL_PUT_ERROR(SSL, ssl3_get_channel_id, SSL_R_NO_P256_SUPPORT); return -1; } @@ -2548,7 +2604,8 @@ int ssl3_get_channel_id(SSL *s) { /* We stored the handshake hash in |tlsext_channel_id| the first time that we * were called. */ if (!ECDSA_do_verify(channel_id_hash, channel_id_hash_len, &sig, key)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_SIGNATURE_INVALID); + OPENSSL_PUT_ERROR(SSL, ssl3_get_channel_id, + SSL_R_CHANNEL_ID_SIGNATURE_INVALID); s->s3->tlsext_channel_id_valid = 0; goto err; } diff --git a/src/ssl/ssl_aead_ctx.c b/src/ssl/ssl_aead_ctx.c index f9001c7..c2fba1d 100644 --- a/src/ssl/ssl_aead_ctx.c +++ b/src/ssl/ssl_aead_ctx.c @@ -12,8 +12,6 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <openssl/ssl.h> - #include <assert.h> #include <string.h> @@ -36,7 +34,7 @@ SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction, const EVP_AEAD *aead; size_t discard; if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard, cipher, version)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_new, ERR_R_INTERNAL_ERROR); return 0; } @@ -45,7 +43,7 @@ SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction, /* This is a "stateful" AEAD (for compatibility with pre-AEAD cipher * suites). */ if (mac_key_len + enc_key_len + fixed_iv_len > sizeof(merged_key)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_new, ERR_R_INTERNAL_ERROR); return 0; } memcpy(merged_key, mac_key, mac_key_len); @@ -58,7 +56,7 @@ SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction, SSL_AEAD_CTX *aead_ctx = (SSL_AEAD_CTX *)OPENSSL_malloc(sizeof(SSL_AEAD_CTX)); if (aead_ctx == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_new, ERR_R_MALLOC_FAILURE); return NULL; } memset(aead_ctx, 0, sizeof(SSL_AEAD_CTX)); @@ -78,17 +76,16 @@ SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction, if (fixed_iv_len > sizeof(aead_ctx->fixed_nonce) || fixed_iv_len > aead_ctx->variable_nonce_len) { SSL_AEAD_CTX_free(aead_ctx); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_new, ERR_R_INTERNAL_ERROR); return 0; } aead_ctx->variable_nonce_len -= fixed_iv_len; memcpy(aead_ctx->fixed_nonce, fixed_iv, fixed_iv_len); aead_ctx->fixed_nonce_len = fixed_iv_len; - /* AES-GCM uses an explicit nonce. */ - if (cipher->algorithm_enc & (SSL_AES128GCM | SSL_AES256GCM)) { - aead_ctx->variable_nonce_included_in_record = 1; - } + aead_ctx->variable_nonce_included_in_record = + (cipher->algorithm2 & + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD) != 0; } else { aead_ctx->variable_nonce_included_in_record = 1; aead_ctx->random_variable_nonce = 1; @@ -149,7 +146,7 @@ int SSL_AEAD_CTX_open(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len, if (aead == NULL) { /* Handle the initial NULL cipher. */ if (in_len > max_out) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_open, SSL_R_BUFFER_TOO_SMALL); return 0; } memmove(out, in, in_len); @@ -164,7 +161,7 @@ int SSL_AEAD_CTX_open(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len, size_t overhead = SSL_AEAD_CTX_max_overhead(aead); if (in_len < overhead) { /* Publicly invalid. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH); + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_open, SSL_R_BAD_PACKET_LENGTH); return 0; } plaintext_len = in_len - overhead; @@ -181,7 +178,7 @@ int SSL_AEAD_CTX_open(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len, if (aead->variable_nonce_included_in_record) { if (in_len < aead->variable_nonce_len) { /* Publicly invalid. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH); + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_open, SSL_R_BAD_PACKET_LENGTH); return 0; } memcpy(nonce + nonce_len, in, aead->variable_nonce_len); @@ -204,7 +201,7 @@ int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len, if (aead == NULL) { /* Handle the initial NULL cipher. */ if (in_len > max_out) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_seal, SSL_R_BUFFER_TOO_SMALL); return 0; } memmove(out, in, in_len); @@ -238,11 +235,11 @@ int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len, size_t extra_len = 0; if (aead->variable_nonce_included_in_record) { if (max_out < aead->variable_nonce_len) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_seal, SSL_R_BUFFER_TOO_SMALL); return 0; } if (out < in + in_len && in < out + aead->variable_nonce_len) { - OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT); + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_seal, SSL_R_OUTPUT_ALIASES_INPUT); return 0; } memcpy(out, nonce + aead->fixed_nonce_len, aead->variable_nonce_len); diff --git a/src/ssl/ssl_algs.c b/src/ssl/ssl_algs.c new file mode 100644 index 0000000..fda39a5 --- /dev/null +++ b/src/ssl/ssl_algs.c @@ -0,0 +1,66 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include "internal.h" + +#include <openssl/crypto.h> + +int SSL_library_init(void) { + CRYPTO_library_init(); + return 1; +} + +void SSL_load_error_strings(void) {} diff --git a/src/ssl/ssl_asn1.c b/src/ssl/ssl_asn1.c index 0d4760d..76052df 100644 --- a/src/ssl/ssl_asn1.c +++ b/src/ssl/ssl_asn1.c @@ -80,8 +80,6 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. */ -#include <openssl/ssl.h> - #include <limits.h> #include <string.h> @@ -116,10 +114,8 @@ * signedCertTimestampList [15] OCTET STRING OPTIONAL, * -- contents of SCT extension * ocspResponse [16] OCTET STRING OPTIONAL, - * -- stapled OCSP response from the server + * -- stapled OCSP response from the server * extendedMasterSecret [17] BOOLEAN OPTIONAL, - * keyExchangeInfo [18] INTEGER OPTIONAL, - * certChain [19] SEQUENCE OF Certificate OPTIONAL, * } * * Note: historically this serialization has included other optional @@ -158,28 +154,8 @@ static const int kOCSPResponseTag = CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 16; static const int kExtendedMasterSecretTag = CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 17; -static const int kKeyExchangeInfoTag = - CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 18; -static const int kCertChainTag = - CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 19; - -static int add_X509(CBB *cbb, X509 *x509) { - int len = i2d_X509(x509, NULL); - if (len < 0) { - return 0; - } - uint8_t *buf; - if (!CBB_add_space(cbb, &buf, len)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return 0; - } - if (buf != NULL && i2d_X509(x509, &buf) < 0) { - return 0; - } - return 1; -} -static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, +static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data, size_t *out_len, int for_ticket) { CBB cbb, session, child, child2; @@ -187,9 +163,11 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, return 0; } - CBB_zero(&cbb); - if (!CBB_init(&cbb, 0) || - !CBB_add_asn1(&cbb, &session, CBS_ASN1_SEQUENCE) || + if (!CBB_init(&cbb, 0)) { + return 0; + } + + if (!CBB_add_asn1(&cbb, &session, CBS_ASN1_SEQUENCE) || !CBB_add_asn1_uint64(&session, SSL_SESSION_ASN1_VERSION) || !CBB_add_asn1_uint64(&session, in->ssl_version) || !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) || @@ -200,14 +178,14 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, for_ticket ? 0 : in->session_id_length) || !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) || !CBB_add_bytes(&child, in->master_key, in->master_key_length)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } if (in->time != 0) { if (!CBB_add_asn1(&session, &child, kTimeTag) || !CBB_add_asn1_uint64(&child, in->time)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -215,7 +193,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, if (in->timeout != 0) { if (!CBB_add_asn1(&session, &child, kTimeoutTag) || !CBB_add_asn1_uint64(&child, in->timeout)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -223,11 +201,17 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, /* The peer certificate is only serialized if the SHA-256 isn't * serialized instead. */ if (in->peer && !in->peer_sha256_valid) { - if (!CBB_add_asn1(&session, &child, kPeerTag)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + uint8_t *buf; + int len = i2d_X509(in->peer, NULL); + if (len < 0) { + goto err; + } + if (!CBB_add_asn1(&session, &child, kPeerTag) || + !CBB_add_space(&child, &buf, len)) { + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } - if (!add_X509(&child, in->peer)) { + if (buf != NULL && i2d_X509(in->peer, &buf) < 0) { goto err; } } @@ -237,14 +221,14 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, if (!CBB_add_asn1(&session, &child, kSessionIDContextTag) || !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || !CBB_add_bytes(&child2, in->sid_ctx, in->sid_ctx_length)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } if (in->verify_result != X509_V_OK) { if (!CBB_add_asn1(&session, &child, kVerifyResultTag) || !CBB_add_asn1_uint64(&child, in->verify_result)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -254,7 +238,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || !CBB_add_bytes(&child2, (const uint8_t *)in->tlsext_hostname, strlen(in->tlsext_hostname))) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -264,7 +248,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || !CBB_add_bytes(&child2, (const uint8_t *)in->psk_identity, strlen(in->psk_identity))) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -272,7 +256,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, if (in->tlsext_tick_lifetime_hint > 0) { if (!CBB_add_asn1(&session, &child, kTicketLifetimeHintTag) || !CBB_add_asn1_uint64(&child, in->tlsext_tick_lifetime_hint)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -281,7 +265,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, if (!CBB_add_asn1(&session, &child, kTicketTag) || !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || !CBB_add_bytes(&child2, in->tlsext_tick, in->tlsext_ticklen)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -290,7 +274,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, if (!CBB_add_asn1(&session, &child, kPeerSHA256Tag) || !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || !CBB_add_bytes(&child2, in->peer_sha256, sizeof(in->peer_sha256))) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -300,7 +284,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || !CBB_add_bytes(&child2, in->original_handshake_hash, in->original_handshake_hash_len)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -310,7 +294,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || !CBB_add_bytes(&child2, in->tlsext_signed_cert_timestamp_list, in->tlsext_signed_cert_timestamp_list_length)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -319,7 +303,7 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, if (!CBB_add_asn1(&session, &child, kOCSPResponseTag) || !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || !CBB_add_bytes(&child2, in->ocsp_response, in->ocsp_response_length)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -328,35 +312,13 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, if (!CBB_add_asn1(&session, &child, kExtendedMasterSecretTag) || !CBB_add_asn1(&child, &child2, CBS_ASN1_BOOLEAN) || !CBB_add_u8(&child2, 0xff)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } - if (in->key_exchange_info > 0 && - (!CBB_add_asn1(&session, &child, kKeyExchangeInfoTag) || - !CBB_add_asn1_uint64(&child, in->key_exchange_info))) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - - /* The certificate chain is only serialized if the leaf's SHA-256 isn't - * serialized instead. */ - if (in->cert_chain != NULL && !in->peer_sha256_valid) { - if (!CBB_add_asn1(&session, &child, kCertChainTag)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - size_t i; - for (i = 0; i < sk_X509_num(in->cert_chain); i++) { - if (!add_X509(&child, sk_X509_value(in->cert_chain, i))) { - goto err; - } - } - } - if (!CBB_finish(&cbb, out_data, out_len)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } return 1; @@ -366,12 +328,11 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, return 0; } -int SSL_SESSION_to_bytes(const SSL_SESSION *in, uint8_t **out_data, - size_t *out_len) { +int SSL_SESSION_to_bytes(SSL_SESSION *in, uint8_t **out_data, size_t *out_len) { return SSL_SESSION_to_bytes_full(in, out_data, out_len, 0); } -int SSL_SESSION_to_bytes_for_ticket(const SSL_SESSION *in, uint8_t **out_data, +int SSL_SESSION_to_bytes_for_ticket(SSL_SESSION *in, uint8_t **out_data, size_t *out_len) { return SSL_SESSION_to_bytes_full(in, out_data, out_len, 1); } @@ -386,7 +347,7 @@ int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp) { if (len > INT_MAX) { OPENSSL_free(out); - OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_OVERFLOW); return -1; } @@ -409,16 +370,17 @@ static int SSL_SESSION_parse_string(CBS *cbs, char **out, unsigned tag) { CBS value; int present; if (!CBS_get_optional_asn1_octet_string(cbs, &value, &present, tag)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse_string, SSL_R_INVALID_SSL_SESSION); return 0; } if (present) { if (CBS_contains_zero_byte(&value)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse_string, + SSL_R_INVALID_SSL_SESSION); return 0; } if (!CBS_strdup(&value, out)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse_string, ERR_R_MALLOC_FAILURE); return 0; } } else { @@ -435,168 +397,170 @@ static int SSL_SESSION_parse_string(CBS *cbs, char **out, unsigned tag) { * |*out_ptr| to NULL. It returns one on success, whether or not the * element was found, and zero on decode error. */ static int SSL_SESSION_parse_octet_string(CBS *cbs, uint8_t **out_ptr, - size_t *out_len, unsigned tag) { + size_t *out_len, unsigned tag) { CBS value; if (!CBS_get_optional_asn1_octet_string(cbs, &value, NULL, tag)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse_octet_string, + SSL_R_INVALID_SSL_SESSION); return 0; } if (!CBS_stow(&value, out_ptr, out_len)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse_octet_string, + ERR_R_MALLOC_FAILURE); return 0; } return 1; } -/* SSL_SESSION_parse_bounded_octet_string parses an optional ASN.1 OCTET STRING - * explicitly tagged with |tag| of size at most |max_out|. */ -static int SSL_SESSION_parse_bounded_octet_string( - CBS *cbs, uint8_t *out, unsigned *out_len, unsigned max_out, unsigned tag) { - CBS value; - if (!CBS_get_optional_asn1_octet_string(cbs, &value, NULL, tag) || - CBS_len(&value) > max_out) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - return 0; - } - memcpy(out, CBS_data(&value), CBS_len(&value)); - *out_len = (unsigned)CBS_len(&value); - return 1; -} +static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { + SSL_SESSION *ret = NULL; + CBS session, cipher, session_id, master_key; + CBS peer, sid_ctx, peer_sha256, original_handshake_hash; + int has_peer, has_peer_sha256, extended_master_secret; + uint64_t version, ssl_version; + uint64_t session_time, timeout, verify_result, ticket_lifetime_hint; -static int SSL_SESSION_parse_long(CBS *cbs, long *out, unsigned tag, - long default_value) { - uint64_t value; - if (!CBS_get_optional_asn1_uint64(cbs, &value, tag, - (uint64_t)default_value) || - value > LONG_MAX) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - return 0; + ret = SSL_SESSION_new(); + if (ret == NULL) { + goto err; } - *out = (long)value; - return 1; -} -static int SSL_SESSION_parse_u32(CBS *cbs, uint32_t *out, unsigned tag, - uint32_t default_value) { - uint64_t value; - if (!CBS_get_optional_asn1_uint64(cbs, &value, tag, - (uint64_t)default_value) || - value > 0xffffffff) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - return 0; + if (!CBS_get_asn1(cbs, &session, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1_uint64(&session, &version) || + !CBS_get_asn1_uint64(&session, &ssl_version) || + !CBS_get_asn1(&session, &cipher, CBS_ASN1_OCTETSTRING) || + !CBS_get_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING) || + !CBS_get_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING) || + !CBS_get_optional_asn1_uint64(&session, &session_time, kTimeTag, + time(NULL)) || + !CBS_get_optional_asn1_uint64(&session, &timeout, kTimeoutTag, 3) || + !CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag) || + !CBS_get_optional_asn1_octet_string(&session, &sid_ctx, NULL, + kSessionIDContextTag) || + !CBS_get_optional_asn1_uint64(&session, &verify_result, kVerifyResultTag, + X509_V_OK)) { + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION); + goto err; } - *out = (uint32_t)value; - return 1; -} - -static X509 *parse_x509(CBS *cbs) { - const uint8_t *ptr = CBS_data(cbs); - X509 *ret = d2i_X509(NULL, &ptr, CBS_len(cbs)); - if (ret == NULL) { - return NULL; + if (!SSL_SESSION_parse_string(&session, &ret->tlsext_hostname, + kHostNameTag) || + !SSL_SESSION_parse_string(&session, &ret->psk_identity, + kPSKIdentityTag)) { + goto err; } - CBS_skip(cbs, ptr - CBS_data(cbs)); - return ret; -} - -static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { - SSL_SESSION *ret = SSL_SESSION_new(); - if (ret == NULL) { + if (!CBS_get_optional_asn1_uint64(&session, &ticket_lifetime_hint, + kTicketLifetimeHintTag, 0)) { + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION); + goto err; + } + if (!SSL_SESSION_parse_octet_string(&session, &ret->tlsext_tick, + &ret->tlsext_ticklen, kTicketTag)) { goto err; } + if (!CBS_get_optional_asn1_octet_string(&session, &peer_sha256, + &has_peer_sha256, kPeerSHA256Tag) || + !CBS_get_optional_asn1_octet_string(&session, &original_handshake_hash, + NULL, kOriginalHandshakeHashTag)) { + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION); + goto err; + } + if (!SSL_SESSION_parse_octet_string( + &session, &ret->tlsext_signed_cert_timestamp_list, + &ret->tlsext_signed_cert_timestamp_list_length, + kSignedCertTimestampListTag) || + !SSL_SESSION_parse_octet_string( + &session, &ret->ocsp_response, &ret->ocsp_response_length, + kOCSPResponseTag)) { + goto err; + } + if (!CBS_get_optional_asn1_bool(&session, &extended_master_secret, + kExtendedMasterSecretTag, + 0 /* default to false */) || + CBS_len(&session) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION); + goto err; + } + ret->extended_master_secret = extended_master_secret; - CBS session; - uint64_t version, ssl_version; - if (!CBS_get_asn1(cbs, &session, CBS_ASN1_SEQUENCE) || - !CBS_get_asn1_uint64(&session, &version) || - version != SSL_SESSION_ASN1_VERSION || - !CBS_get_asn1_uint64(&session, &ssl_version)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + if (version != SSL_SESSION_ASN1_VERSION) { + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION); goto err; } + /* Only support SSLv3/TLS and DTLS. */ if ((ssl_version >> 8) != SSL3_VERSION_MAJOR && (ssl_version >> 8) != (DTLS1_VERSION >> 8)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_SSL_VERSION); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_UNKNOWN_SSL_VERSION); goto err; } ret->ssl_version = ssl_version; - CBS cipher; uint16_t cipher_value; - if (!CBS_get_asn1(&session, &cipher, CBS_ASN1_OCTETSTRING) || - !CBS_get_u16(&cipher, &cipher_value) || - CBS_len(&cipher) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + if (!CBS_get_u16(&cipher, &cipher_value) || CBS_len(&cipher) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_CIPHER_CODE_WRONG_LENGTH); goto err; } ret->cipher = SSL_get_cipher_by_value(cipher_value); if (ret->cipher == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_CIPHER); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_UNSUPPORTED_CIPHER); goto err; } - CBS session_id, master_key; - if (!CBS_get_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING) || - CBS_len(&session_id) > SSL3_MAX_SSL_SESSION_ID_LENGTH || - !CBS_get_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING) || - CBS_len(&master_key) > SSL_MAX_MASTER_KEY_LENGTH) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + if (CBS_len(&session_id) > SSL3_MAX_SSL_SESSION_ID_LENGTH) { + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION); goto err; } memcpy(ret->session_id, CBS_data(&session_id), CBS_len(&session_id)); ret->session_id_length = CBS_len(&session_id); - memcpy(ret->master_key, CBS_data(&master_key), CBS_len(&master_key)); - ret->master_key_length = CBS_len(&master_key); - if (!SSL_SESSION_parse_long(&session, &ret->time, kTimeTag, time(NULL)) || - !SSL_SESSION_parse_long(&session, &ret->timeout, kTimeoutTag, 3)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + if (CBS_len(&master_key) > SSL_MAX_MASTER_KEY_LENGTH) { + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION); goto err; } + memcpy(ret->master_key, CBS_data(&master_key), CBS_len(&master_key)); + ret->master_key_length = CBS_len(&master_key); - CBS peer; - int has_peer; - if (!CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + if (session_time > LONG_MAX || + timeout > LONG_MAX) { + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION); goto err; } + ret->time = session_time; + ret->timeout = timeout; + X509_free(ret->peer); ret->peer = NULL; if (has_peer) { - ret->peer = parse_x509(&peer); + const uint8_t *ptr; + ptr = CBS_data(&peer); + ret->peer = d2i_X509(NULL, &ptr, CBS_len(&peer)); if (ret->peer == NULL) { goto err; } - if (CBS_len(&peer) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + if (ptr != CBS_data(&peer) + CBS_len(&peer)) { + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION); goto err; } } - if (!SSL_SESSION_parse_bounded_octet_string( - &session, ret->sid_ctx, &ret->sid_ctx_length, sizeof(ret->sid_ctx), - kSessionIDContextTag) || - !SSL_SESSION_parse_long(&session, &ret->verify_result, kVerifyResultTag, - X509_V_OK) || - !SSL_SESSION_parse_string(&session, &ret->tlsext_hostname, - kHostNameTag) || - !SSL_SESSION_parse_string(&session, &ret->psk_identity, - kPSKIdentityTag) || - !SSL_SESSION_parse_u32(&session, &ret->tlsext_tick_lifetime_hint, - kTicketLifetimeHintTag, 0) || - !SSL_SESSION_parse_octet_string(&session, &ret->tlsext_tick, - &ret->tlsext_ticklen, kTicketTag)) { + if (CBS_len(&sid_ctx) > sizeof(ret->sid_ctx)) { + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION); + goto err; + } + memcpy(ret->sid_ctx, CBS_data(&sid_ctx), CBS_len(&sid_ctx)); + ret->sid_ctx_length = CBS_len(&sid_ctx); + + if (verify_result > LONG_MAX || + ticket_lifetime_hint > 0xffffffff) { + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION); goto err; } + ret->verify_result = verify_result; + ret->tlsext_tick_lifetime_hint = ticket_lifetime_hint; - if (CBS_peek_asn1_tag(&session, kPeerSHA256Tag)) { - CBS child, peer_sha256; - if (!CBS_get_asn1(&session, &child, kPeerSHA256Tag) || - !CBS_get_asn1(&child, &peer_sha256, CBS_ASN1_OCTETSTRING) || - CBS_len(&peer_sha256) != sizeof(ret->peer_sha256) || - CBS_len(&child) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + if (has_peer_sha256) { + if (CBS_len(&peer_sha256) != sizeof(ret->peer_sha256)) { + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION); goto err; } memcpy(ret->peer_sha256, CBS_data(&peer_sha256), sizeof(ret->peer_sha256)); @@ -605,67 +569,14 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { ret->peer_sha256_valid = 0; } - if (!SSL_SESSION_parse_bounded_octet_string( - &session, ret->original_handshake_hash, - &ret->original_handshake_hash_len, - sizeof(ret->original_handshake_hash), kOriginalHandshakeHashTag) || - !SSL_SESSION_parse_octet_string( - &session, &ret->tlsext_signed_cert_timestamp_list, - &ret->tlsext_signed_cert_timestamp_list_length, - kSignedCertTimestampListTag) || - !SSL_SESSION_parse_octet_string( - &session, &ret->ocsp_response, &ret->ocsp_response_length, - kOCSPResponseTag)) { - goto err; - } - - int extended_master_secret; - if (!CBS_get_optional_asn1_bool(&session, &extended_master_secret, - kExtendedMasterSecretTag, - 0 /* default to false */)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; - } - ret->extended_master_secret = !!extended_master_secret; - - if (!SSL_SESSION_parse_u32(&session, &ret->key_exchange_info, - kKeyExchangeInfoTag, 0)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; - } - - CBS cert_chain; - int has_cert_chain; - if (!CBS_get_optional_asn1(&session, &cert_chain, &has_cert_chain, - kCertChainTag)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; - } - sk_X509_pop_free(ret->cert_chain, X509_free); - ret->cert_chain = NULL; - if (has_cert_chain) { - ret->cert_chain = sk_X509_new_null(); - if (ret->cert_chain == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - while (CBS_len(&cert_chain) > 0) { - X509 *x509 = parse_x509(&cert_chain); - if (x509 == NULL) { - goto err; - } - if (!sk_X509_push(ret->cert_chain, x509)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - X509_free(x509); - goto err; - } - } - } - - if (CBS_len(&session) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + if (CBS_len(&original_handshake_hash) > + sizeof(ret->original_handshake_hash)) { + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION); goto err; } + memcpy(ret->original_handshake_hash, CBS_data(&original_handshake_hash), + CBS_len(&original_handshake_hash)); + ret->original_handshake_hash_len = CBS_len(&original_handshake_hash); return ret; @@ -682,7 +593,7 @@ SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len) { return NULL; } if (CBS_len(&cbs) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_from_bytes, SSL_R_INVALID_SSL_SESSION); SSL_SESSION_free(ret); return NULL; } @@ -691,7 +602,7 @@ SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len) { SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) { if (length < 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, ERR_R_INTERNAL_ERROR); return NULL; } diff --git a/src/ssl/ssl_buffer.c b/src/ssl/ssl_buffer.c deleted file mode 100644 index 63dcd80..0000000 --- a/src/ssl/ssl_buffer.c +++ /dev/null @@ -1,318 +0,0 @@ -/* Copyright (c) 2015, 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. */ - -#include <openssl/ssl.h> - -#include <assert.h> -#include <limits.h> -#include <stdlib.h> -#include <string.h> - -#include <openssl/bio.h> -#include <openssl/err.h> -#include <openssl/mem.h> -#include <openssl/type_check.h> - -#include "internal.h" - - -OPENSSL_COMPILE_ASSERT(0xffff <= INT_MAX, uint16_fits_in_int); - -OPENSSL_COMPILE_ASSERT((SSL3_ALIGN_PAYLOAD & (SSL3_ALIGN_PAYLOAD - 1)) == 0, - align_to_a_power_of_two); - -/* setup_buffer initializes |buf| with capacity |cap|, aligned such that data - * written after |header_len| is aligned to a |SSL3_ALIGN_PAYLOAD|-byte - * boundary. It returns one on success and zero on error. */ -static int setup_buffer(SSL3_BUFFER *buf, size_t header_len, size_t cap) { - if (buf->buf != NULL || cap > 0xffff) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return 0; - } - - /* Add up to |SSL3_ALIGN_PAYLOAD| - 1 bytes of slack for alignment. */ - buf->buf = OPENSSL_malloc(cap + SSL3_ALIGN_PAYLOAD - 1); - if (buf->buf == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return 0; - } - - /* Arrange the buffer such that the record body is aligned. */ - buf->offset = (0 - header_len - (uintptr_t)buf->buf) & - (SSL3_ALIGN_PAYLOAD - 1); - buf->len = 0; - buf->cap = cap; - return 1; -} - -static void consume_buffer(SSL3_BUFFER *buf, size_t len) { - if (len > buf->len) { - abort(); - } - buf->offset += (uint16_t)len; - buf->len -= (uint16_t)len; - buf->cap -= (uint16_t)len; -} - -static void clear_buffer(SSL3_BUFFER *buf) { - OPENSSL_free(buf->buf); - memset(buf, 0, sizeof(SSL3_BUFFER)); -} - -OPENSSL_COMPILE_ASSERT(DTLS1_RT_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH + - SSL3_RT_MAX_EXTRA <= 0xffff, - maximum_read_buffer_too_large); - -/* setup_read_buffer initializes the read buffer if not already initialized. It - * returns one on success and zero on failure. */ -static int setup_read_buffer(SSL *ssl) { - SSL3_BUFFER *buf = &ssl->s3->read_buffer; - - if (buf->buf != NULL) { - return 1; - } - - size_t header_len = ssl_record_prefix_len(ssl); - size_t cap = SSL3_RT_MAX_ENCRYPTED_LENGTH; - if (SSL_IS_DTLS(ssl)) { - cap += DTLS1_RT_HEADER_LENGTH; - } else { - cap += SSL3_RT_HEADER_LENGTH; - } - if (ssl->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) { - cap += SSL3_RT_MAX_EXTRA; - } - - return setup_buffer(buf, header_len, cap); -} - -uint8_t *ssl_read_buffer(SSL *ssl) { - return ssl->s3->read_buffer.buf + ssl->s3->read_buffer.offset; -} - -size_t ssl_read_buffer_len(const SSL *ssl) { - return ssl->s3->read_buffer.len; -} - -static int dtls_read_buffer_next_packet(SSL *ssl) { - SSL3_BUFFER *buf = &ssl->s3->read_buffer; - - if (buf->len > 0) { - /* It is an error to call |dtls_read_buffer_extend| when the read buffer is - * not empty. */ - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return -1; - } - - /* Read a single packet from |ssl->rbio|. |buf->cap| must fit in an int. */ - ssl->rwstate = SSL_READING; - int ret = BIO_read(ssl->rbio, buf->buf + buf->offset, (int)buf->cap); - if (ret <= 0) { - return ret; - } - ssl->rwstate = SSL_NOTHING; - /* |BIO_read| was bound by |buf->cap|, so this cannot overflow. */ - buf->len = (uint16_t)ret; - return 1; -} - -static int tls_read_buffer_extend_to(SSL *ssl, size_t len) { - SSL3_BUFFER *buf = &ssl->s3->read_buffer; - - if (len > buf->cap) { - /* This may occur if |SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER| was toggled after - * |setup_read_buffer| was called. Stay within bounds, but do not attempt to - * recover. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); - return -1; - } - - /* Read until the target length is reached. */ - while (buf->len < len) { - /* The amount of data to read is bounded by |buf->cap|, which must fit in an - * int. */ - ssl->rwstate = SSL_READING; - int ret = BIO_read(ssl->rbio, buf->buf + buf->offset + buf->len, - (int)(len - buf->len)); - if (ret <= 0) { - return ret; - } - ssl->rwstate = SSL_NOTHING; - /* |BIO_read| was bound by |buf->cap - buf->len|, so this cannot - * overflow. */ - buf->len += (uint16_t)ret; - } - - return 1; -} - -int ssl_read_buffer_extend_to(SSL *ssl, size_t len) { - /* |ssl_read_buffer_extend_to| implicitly discards any consumed data. */ - ssl_read_buffer_discard(ssl); - - if (!setup_read_buffer(ssl)) { - return -1; - } - - if (ssl->rbio == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BIO_NOT_SET); - return -1; - } - - ERR_clear_system_error(); - - int ret; - if (SSL_IS_DTLS(ssl)) { - /* |len| is ignored for a datagram transport. */ - ret = dtls_read_buffer_next_packet(ssl); - } else { - ret = tls_read_buffer_extend_to(ssl, len); - } - - if (ret <= 0) { - /* If the buffer was empty originally and remained empty after attempting to - * extend it, release the buffer until the next attempt. */ - ssl_read_buffer_discard(ssl); - } - return ret; -} - -void ssl_read_buffer_consume(SSL *ssl, size_t len) { - SSL3_BUFFER *buf = &ssl->s3->read_buffer; - - consume_buffer(buf, len); - if (!SSL_IS_DTLS(ssl)) { - /* The TLS stack never reads beyond the current record, so there will never - * be unconsumed data. If read-ahead is ever reimplemented, - * |ssl_read_buffer_discard| will require a |memcpy| to shift the excess - * back to the front of the buffer, to ensure there is enough space for the - * next record. */ - assert(buf->len == 0); - } -} - -void ssl_read_buffer_discard(SSL *ssl) { - if (ssl->s3->read_buffer.len == 0) { - ssl_read_buffer_clear(ssl); - } -} - -void ssl_read_buffer_clear(SSL *ssl) { - clear_buffer(&ssl->s3->read_buffer); -} - - -int ssl_write_buffer_is_pending(const SSL *ssl) { - return ssl->s3->write_buffer.len > 0; -} - -OPENSSL_COMPILE_ASSERT(SSL3_RT_HEADER_LENGTH * 2 + - SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD * 2 + - SSL3_RT_MAX_PLAIN_LENGTH <= 0xffff, - maximum_tls_write_buffer_too_large); - -OPENSSL_COMPILE_ASSERT(DTLS1_RT_HEADER_LENGTH + - SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD + - SSL3_RT_MAX_PLAIN_LENGTH <= 0xffff, - maximum_dtls_write_buffer_too_large); - -int ssl_write_buffer_init(SSL *ssl, uint8_t **out_ptr, size_t max_len) { - SSL3_BUFFER *buf = &ssl->s3->write_buffer; - - if (buf->buf != NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return 0; - } - - size_t header_len = ssl_seal_prefix_len(ssl); - - /* TODO(davidben): This matches the original behavior in keeping the malloc - * size consistent. Does this matter? |cap| could just be |max_len|. */ - size_t cap = SSL3_RT_MAX_PLAIN_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD; - if (SSL_IS_DTLS(ssl)) { - cap += DTLS1_RT_HEADER_LENGTH; - } else { - cap += SSL3_RT_HEADER_LENGTH; - if (ssl->mode & SSL_MODE_CBC_RECORD_SPLITTING) { - cap += SSL3_RT_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD; - } - } - - if (max_len > cap) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); - return 0; - } - - if (!setup_buffer(buf, header_len, cap)) { - return 0; - } - *out_ptr = buf->buf + buf->offset; - return 1; -} - -void ssl_write_buffer_set_len(SSL *ssl, size_t len) { - SSL3_BUFFER *buf = &ssl->s3->write_buffer; - - if (len > buf->cap) { - abort(); - } - buf->len = len; -} - -static int tls_write_buffer_flush(SSL *ssl) { - SSL3_BUFFER *buf = &ssl->s3->write_buffer; - - while (buf->len > 0) { - ssl->rwstate = SSL_WRITING; - int ret = BIO_write(ssl->wbio, buf->buf + buf->offset, buf->len); - if (ret <= 0) { - return ret; - } - ssl->rwstate = SSL_NOTHING; - consume_buffer(buf, (size_t)ret); - } - ssl_write_buffer_clear(ssl); - return 1; -} - -static int dtls_write_buffer_flush(SSL *ssl) { - SSL3_BUFFER *buf = &ssl->s3->write_buffer; - if (buf->len == 0) { - return 1; - } - - int ret = BIO_write(ssl->wbio, buf->buf + buf->offset, buf->len); - /* Drop the write buffer whether or not the write succeeded synchronously. - * TODO(davidben): How does this interact with the retry flag? */ - ssl_write_buffer_clear(ssl); - return (ret <= 0) ? ret : 1; -} - -int ssl_write_buffer_flush(SSL *ssl) { - if (ssl->wbio == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BIO_NOT_SET); - return -1; - } - ERR_clear_system_error(); - - if (SSL_IS_DTLS(ssl)) { - return dtls_write_buffer_flush(ssl); - } else { - return tls_write_buffer_flush(ssl); - } -} - -void ssl_write_buffer_clear(SSL *ssl) { - clear_buffer(&ssl->s3->write_buffer); -} diff --git a/src/ssl/ssl_cert.c b/src/ssl/ssl_cert.c index 4094b27..85aa079 100644 --- a/src/ssl/ssl_cert.c +++ b/src/ssl/ssl_cert.c @@ -112,64 +112,84 @@ * ECC cipher suite support in OpenSSL originally developed by * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. */ -#include <openssl/ssl.h> - +#include <errno.h> +#include <stdio.h> #include <string.h> +#include <openssl/bio.h> #include <openssl/bn.h> #include <openssl/buf.h> #include <openssl/ec_key.h> #include <openssl/dh.h> #include <openssl/err.h> #include <openssl/mem.h> +#include <openssl/obj.h> +#include <openssl/pem.h> #include <openssl/x509.h> #include <openssl/x509v3.h> #include "../crypto/dh/internal.h" +#include "../crypto/directory.h" #include "../crypto/internal.h" #include "internal.h" +static CRYPTO_once_t g_x509_store_ex_data_index_once; +static int g_x509_store_ex_data_index; + +static void ssl_x509_store_ex_data_index_init(void) { + g_x509_store_ex_data_index = X509_STORE_CTX_get_ex_new_index( + 0, "SSL for verify callback", NULL, NULL, NULL); +} + int SSL_get_ex_data_X509_STORE_CTX_idx(void) { - /* The ex_data index to go from |X509_STORE_CTX| to |SSL| always uses the - * reserved app_data slot. Before ex_data was introduced, app_data was used. - * Avoid breaking any software which assumes |X509_STORE_CTX_get_app_data| - * works. */ - return 0; + CRYPTO_once(&g_x509_store_ex_data_index_once, + ssl_x509_store_ex_data_index_init); + return g_x509_store_ex_data_index; } CERT *ssl_cert_new(void) { - CERT *ret = (CERT *)OPENSSL_malloc(sizeof(CERT)); + CERT *ret; + + ret = (CERT *)OPENSSL_malloc(sizeof(CERT)); if (ret == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl_cert_new, ERR_R_MALLOC_FAILURE); return NULL; } memset(ret, 0, sizeof(CERT)); + ret->key = &ret->pkeys[SSL_PKEY_RSA_ENC]; return ret; } CERT *ssl_cert_dup(CERT *cert) { - CERT *ret = (CERT *)OPENSSL_malloc(sizeof(CERT)); + CERT *ret; + int i; + + ret = (CERT *)OPENSSL_malloc(sizeof(CERT)); if (ret == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_MALLOC_FAILURE); return NULL; } memset(ret, 0, sizeof(CERT)); + ret->key = &ret->pkeys[cert->key - &cert->pkeys[0]]; + /* or ret->key = ret->pkeys + (cert->key - cert->pkeys), if you find that + * more readable */ + ret->mask_k = cert->mask_k; ret->mask_a = cert->mask_a; if (cert->dh_tmp != NULL) { ret->dh_tmp = DHparams_dup(cert->dh_tmp); if (ret->dh_tmp == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB); + OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_DH_LIB); goto err; } if (cert->dh_tmp->priv_key) { BIGNUM *b = BN_dup(cert->dh_tmp->priv_key); if (!b) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BN_LIB); + OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_BN_LIB); goto err; } ret->dh_tmp->priv_key = b; @@ -177,7 +197,7 @@ CERT *ssl_cert_dup(CERT *cert) { if (cert->dh_tmp->pub_key) { BIGNUM *b = BN_dup(cert->dh_tmp->pub_key); if (!b) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BN_LIB); + OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_BN_LIB); goto err; } ret->dh_tmp->pub_key = b; @@ -188,25 +208,67 @@ CERT *ssl_cert_dup(CERT *cert) { ret->ecdh_nid = cert->ecdh_nid; ret->ecdh_tmp_cb = cert->ecdh_tmp_cb; - if (cert->x509 != NULL) { - ret->x509 = X509_up_ref(cert->x509); + for (i = 0; i < SSL_PKEY_NUM; i++) { + CERT_PKEY *cpk = cert->pkeys + i; + CERT_PKEY *rpk = ret->pkeys + i; + if (cpk->x509 != NULL) { + rpk->x509 = X509_up_ref(cpk->x509); + } + + if (cpk->privatekey != NULL) { + rpk->privatekey = EVP_PKEY_up_ref(cpk->privatekey); + } + + if (cpk->chain) { + rpk->chain = X509_chain_up_ref(cpk->chain); + if (!rpk->chain) { + OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_MALLOC_FAILURE); + goto err; + } + } } - if (cert->privatekey != NULL) { - ret->privatekey = EVP_PKEY_up_ref(cert->privatekey); + /* Copy over signature algorithm configuration. */ + if (cert->conf_sigalgs) { + ret->conf_sigalgs = BUF_memdup(cert->conf_sigalgs, cert->conf_sigalgslen); + if (!ret->conf_sigalgs) { + goto err; + } + ret->conf_sigalgslen = cert->conf_sigalgslen; } - if (cert->chain) { - ret->chain = X509_chain_up_ref(cert->chain); - if (!ret->chain) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + if (cert->client_sigalgs) { + ret->client_sigalgs = BUF_memdup(cert->client_sigalgs, + cert->client_sigalgslen); + if (!ret->client_sigalgs) { goto err; } + ret->client_sigalgslen = cert->client_sigalgslen; + } + + /* Copy any custom client certificate types */ + if (cert->client_certificate_types) { + ret->client_certificate_types = BUF_memdup( + cert->client_certificate_types, cert->num_client_certificate_types); + if (!ret->client_certificate_types) { + goto err; + } + ret->num_client_certificate_types = cert->num_client_certificate_types; } ret->cert_cb = cert->cert_cb; ret->cert_cb_arg = cert->cert_cb_arg; + if (cert->verify_store) { + CRYPTO_refcount_inc(&cert->verify_store->references); + ret->verify_store = cert->verify_store; + } + + if (cert->chain_store) { + CRYPTO_refcount_inc(&cert->chain_store->references); + ret->chain_store = cert->chain_store; + } + return ret; err: @@ -215,18 +277,27 @@ err: } /* Free up and clear all certificates and chains */ -void ssl_cert_clear_certs(CERT *cert) { - if (cert == NULL) { +void ssl_cert_clear_certs(CERT *c) { + int i; + if (c == NULL) { return; } - X509_free(cert->x509); - cert->x509 = NULL; - EVP_PKEY_free(cert->privatekey); - cert->privatekey = NULL; - sk_X509_pop_free(cert->chain, X509_free); - cert->chain = NULL; - cert->key_method = NULL; + for (i = 0; i < SSL_PKEY_NUM; i++) { + CERT_PKEY *cpk = c->pkeys + i; + if (cpk->x509) { + X509_free(cpk->x509); + cpk->x509 = NULL; + } + if (cpk->privatekey) { + EVP_PKEY_free(cpk->privatekey); + cpk->privatekey = NULL; + } + if (cpk->chain) { + sk_X509_pop_free(cpk->chain, X509_free); + cpk->chain = NULL; + } + } } void ssl_cert_free(CERT *c) { @@ -238,29 +309,38 @@ void ssl_cert_free(CERT *c) { ssl_cert_clear_certs(c); OPENSSL_free(c->peer_sigalgs); - OPENSSL_free(c->digest_nids); + OPENSSL_free(c->conf_sigalgs); + OPENSSL_free(c->client_sigalgs); + OPENSSL_free(c->shared_sigalgs); + OPENSSL_free(c->client_certificate_types); + X509_STORE_free(c->verify_store); + X509_STORE_free(c->chain_store); OPENSSL_free(c); } -int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain) { - sk_X509_pop_free(cert->chain, X509_free); - cert->chain = chain; +int ssl_cert_set0_chain(CERT *c, STACK_OF(X509) *chain) { + CERT_PKEY *cpk = c->key; + if (!cpk) { + return 0; + } + sk_X509_pop_free(cpk->chain, X509_free); + cpk->chain = chain; return 1; } -int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain) { +int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain) { STACK_OF(X509) *dchain; - if (chain == NULL) { - return ssl_cert_set0_chain(cert, NULL); + if (!chain) { + return ssl_cert_set0_chain(c, NULL); } dchain = X509_chain_up_ref(chain); - if (dchain == NULL) { + if (!dchain) { return 0; } - if (!ssl_cert_set0_chain(cert, dchain)) { + if (!ssl_cert_set0_chain(c, dchain)) { sk_X509_pop_free(dchain, X509_free); return 0; } @@ -268,71 +348,158 @@ int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain) { return 1; } -int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509) { - if (cert->chain == NULL) { - cert->chain = sk_X509_new_null(); +int ssl_cert_add0_chain_cert(CERT *c, X509 *x) { + CERT_PKEY *cpk = c->key; + if (!cpk) { + return 0; } - if (cert->chain == NULL || !sk_X509_push(cert->chain, x509)) { + + if (!cpk->chain) { + cpk->chain = sk_X509_new_null(); + } + if (!cpk->chain || !sk_X509_push(cpk->chain, x)) { return 0; } return 1; } -int ssl_cert_add1_chain_cert(CERT *cert, X509 *x509) { - if (!ssl_cert_add0_chain_cert(cert, x509)) { +int ssl_cert_add1_chain_cert(CERT *c, X509 *x) { + if (!ssl_cert_add0_chain_cert(c, x)) { return 0; } - X509_up_ref(x509); + X509_up_ref(x); return 1; } +int ssl_cert_select_current(CERT *c, X509 *x) { + int i; + if (x == NULL) { + return 0; + } + + for (i = 0; i < SSL_PKEY_NUM; i++) { + if (c->pkeys[i].x509 == x) { + c->key = &c->pkeys[i]; + return 1; + } + } + + for (i = 0; i < SSL_PKEY_NUM; i++) { + if (c->pkeys[i].x509 && !X509_cmp(c->pkeys[i].x509, x)) { + c->key = &c->pkeys[i]; + return 1; + } + } + + return 0; +} + void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg), void *arg) { c->cert_cb = cb; c->cert_cb_arg = arg; } -int ssl_verify_cert_chain(SSL *ssl, STACK_OF(X509) *cert_chain) { - if (cert_chain == NULL || sk_X509_num(cert_chain) == 0) { - return 0; +SESS_CERT *ssl_sess_cert_new(void) { + SESS_CERT *ret; + + ret = OPENSSL_malloc(sizeof *ret); + if (ret == NULL) { + OPENSSL_PUT_ERROR(SSL, ssl_sess_cert_new, ERR_R_MALLOC_FAILURE); + return NULL; } - X509 *leaf = sk_X509_value(cert_chain, 0); - int ret = 0; + memset(ret, 0, sizeof *ret); + + return ret; +} + +SESS_CERT *ssl_sess_cert_dup(const SESS_CERT *sess_cert) { + SESS_CERT *ret = ssl_sess_cert_new(); + if (ret == NULL) { + return NULL; + } + + if (sess_cert->cert_chain != NULL) { + ret->cert_chain = X509_chain_up_ref(sess_cert->cert_chain); + if (ret->cert_chain == NULL) { + ssl_sess_cert_free(ret); + return NULL; + } + } + if (sess_cert->peer_cert != NULL) { + ret->peer_cert = X509_up_ref(sess_cert->peer_cert); + } + if (sess_cert->peer_dh_tmp != NULL) { + ret->peer_dh_tmp = sess_cert->peer_dh_tmp; + DH_up_ref(ret->peer_dh_tmp); + } + if (sess_cert->peer_ecdh_tmp != NULL) { + ret->peer_ecdh_tmp = sess_cert->peer_ecdh_tmp; + EC_KEY_up_ref(ret->peer_ecdh_tmp); + } + return ret; +} + +void ssl_sess_cert_free(SESS_CERT *sess_cert) { + if (sess_cert == NULL) { + return; + } + + sk_X509_pop_free(sess_cert->cert_chain, X509_free); + X509_free(sess_cert->peer_cert); + DH_free(sess_cert->peer_dh_tmp); + EC_KEY_free(sess_cert->peer_ecdh_tmp); + + OPENSSL_free(sess_cert); +} + +int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk) { + X509 *x; + int i; + X509_STORE *verify_store; X509_STORE_CTX ctx; - if (!X509_STORE_CTX_init(&ctx, ssl->ctx->cert_store, leaf, cert_chain)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB); + + if (s->cert->verify_store) { + verify_store = s->cert->verify_store; + } else { + verify_store = s->ctx->cert_store; + } + + if (sk == NULL || sk_X509_num(sk) == 0) { return 0; } - if (!X509_STORE_CTX_set_ex_data(&ctx, SSL_get_ex_data_X509_STORE_CTX_idx(), - ssl)) { - goto err; + + x = sk_X509_value(sk, 0); + if (!X509_STORE_CTX_init(&ctx, verify_store, x, sk)) { + OPENSSL_PUT_ERROR(SSL, ssl_verify_cert_chain, ERR_R_X509_LIB); + return 0; } + X509_STORE_CTX_set_ex_data(&ctx, SSL_get_ex_data_X509_STORE_CTX_idx(), s); /* We need to inherit the verify parameters. These can be determined by the * context: if its a server it will verify SSL client certificates or vice * versa. */ - X509_STORE_CTX_set_default(&ctx, ssl->server ? "ssl_client" : "ssl_server"); + X509_STORE_CTX_set_default(&ctx, s->server ? "ssl_client" : "ssl_server"); /* Anything non-default in "param" should overwrite anything in the ctx. */ - X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), ssl->param); + X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), s->param); - if (ssl->verify_callback) { - X509_STORE_CTX_set_verify_cb(&ctx, ssl->verify_callback); + if (s->verify_callback) { + X509_STORE_CTX_set_verify_cb(&ctx, s->verify_callback); } - if (ssl->ctx->app_verify_callback != NULL) { - ret = ssl->ctx->app_verify_callback(&ctx, ssl->ctx->app_verify_arg); + if (s->ctx->app_verify_callback != NULL) { + i = s->ctx->app_verify_callback(&ctx, s->ctx->app_verify_arg); } else { - ret = X509_verify_cert(&ctx); + i = X509_verify_cert(&ctx); } - ssl->verify_result = ctx.error; - -err: + s->verify_result = ctx.error; X509_STORE_CTX_cleanup(&ctx); - return ret; + + return i; } static void set_client_CA_list(STACK_OF(X509_NAME) **ca_list, @@ -341,17 +508,15 @@ static void set_client_CA_list(STACK_OF(X509_NAME) **ca_list, *ca_list = name_list; } -STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *list) { - STACK_OF(X509_NAME) *ret = sk_X509_NAME_new_null(); - if (ret == NULL) { - return NULL; - } - +STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk) { size_t i; - for (i = 0; i < sk_X509_NAME_num(list); i++) { - X509_NAME *name = X509_NAME_dup(sk_X509_NAME_value(list, i)); + STACK_OF(X509_NAME) *ret; + X509_NAME *name; + + ret = sk_X509_NAME_new_null(); + for (i = 0; i < sk_X509_NAME_num(sk); i++) { + name = X509_NAME_dup(sk_X509_NAME_value(sk, i)); if (name == NULL || !sk_X509_NAME_push(ret, name)) { - X509_NAME_free(name); sk_X509_NAME_pop_free(ret, X509_NAME_free); return NULL; } @@ -360,38 +525,38 @@ STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *list) { return ret; } -void SSL_set_client_CA_list(SSL *ssl, STACK_OF(X509_NAME) *name_list) { - set_client_CA_list(&ssl->client_CA, name_list); +void SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) *name_list) { + set_client_CA_list(&(s->client_CA), name_list); } void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list) { - set_client_CA_list(&ctx->client_CA, name_list); + set_client_CA_list(&(ctx->client_CA), name_list); } STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx) { return ctx->client_CA; } -STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl) { - /* For historical reasons, this function is used both to query configuration - * state on a server as well as handshake state on a client. However, whether - * |ssl| is a client or server is not known until explicitly configured with - * |SSL_set_connect_state|. If |handshake_func| is NULL, |ssl| is in an - * indeterminate mode and |ssl->server| is unset. */ - if (ssl->handshake_func != NULL && !ssl->server) { - return ssl->s3->tmp.ca_names; - } - - if (ssl->client_CA != NULL) { - return ssl->client_CA; +STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s) { + if (s->server) { + if (s->client_CA != NULL) { + return s->client_CA; + } else { + return s->ctx->client_CA; + } + } else { + if ((s->version >> 8) == SSL3_VERSION_MAJOR && s->s3 != NULL) { + return s->s3->tmp.ca_names; + } else { + return NULL; + } } - return ssl->ctx->client_CA; } -static int add_client_CA(STACK_OF(X509_NAME) **sk, X509 *x509) { +static int add_client_CA(STACK_OF(X509_NAME) **sk, X509 *x) { X509_NAME *name; - if (x509 == NULL) { + if (x == NULL) { return 0; } if (*sk == NULL) { @@ -401,7 +566,7 @@ static int add_client_CA(STACK_OF(X509_NAME) **sk, X509 *x509) { } } - name = X509_NAME_dup(X509_get_subject_name(x509)); + name = X509_NAME_dup(X509_get_subject_name(x)); if (name == NULL) { return 0; } @@ -414,12 +579,195 @@ static int add_client_CA(STACK_OF(X509_NAME) **sk, X509 *x509) { return 1; } -int SSL_add_client_CA(SSL *ssl, X509 *x509) { - return add_client_CA(&ssl->client_CA, x509); +int SSL_add_client_CA(SSL *ssl, X509 *x) { + return add_client_CA(&(ssl->client_CA), x); +} + +int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) { + return add_client_CA(&(ctx->client_CA), x); } -int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x509) { - return add_client_CA(&ctx->client_CA, x509); +static int xname_cmp(const X509_NAME **a, const X509_NAME **b) { + return X509_NAME_cmp(*a, *b); +} + +/* Load CA certs from a file into a STACK. Note that it is somewhat misnamed; + * it doesn't really have anything to do with clients (except that a common use + * for a stack of CAs is to send it to the client). Actually, it doesn't have + * much to do with CAs, either, since it will load any old cert. + * + * \param file the file containing one or more certs. + * \return a ::STACK containing the certs. */ +STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) { + BIO *in; + X509 *x = NULL; + X509_NAME *xn = NULL; + STACK_OF(X509_NAME) *ret = NULL, *sk; + + sk = sk_X509_NAME_new(xname_cmp); + in = BIO_new(BIO_s_file()); + + if (sk == NULL || in == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_load_client_CA_file, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!BIO_read_filename(in, file)) { + goto err; + } + + for (;;) { + if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL) { + break; + } + if (ret == NULL) { + ret = sk_X509_NAME_new_null(); + if (ret == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_load_client_CA_file, ERR_R_MALLOC_FAILURE); + goto err; + } + } + xn = X509_get_subject_name(x); + if (xn == NULL) { + goto err; + } + + /* check for duplicates */ + xn = X509_NAME_dup(xn); + if (xn == NULL) { + goto err; + } + if (sk_X509_NAME_find(sk, NULL, xn)) { + X509_NAME_free(xn); + } else { + sk_X509_NAME_push(sk, xn); + sk_X509_NAME_push(ret, xn); + } + } + + if (0) { + err: + sk_X509_NAME_pop_free(ret, X509_NAME_free); + ret = NULL; + } + + sk_X509_NAME_free(sk); + BIO_free(in); + X509_free(x); + if (ret != NULL) { + ERR_clear_error(); + } + return ret; +} + +/* Add a file of certs to a stack. + * + * \param stack the stack to add to. + * \param file the file to add from. All certs in this file that are not + * already in the stack will be added. + * \return 1 for success, 0 for failure. Note that in the case of failure some + * certs may have been added to \c stack. */ +int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, + const char *file) { + BIO *in; + X509 *x = NULL; + X509_NAME *xn = NULL; + int ret = 1; + int (*oldcmp)(const X509_NAME **a, const X509_NAME **b); + + oldcmp = sk_X509_NAME_set_cmp_func(stack, xname_cmp); + in = BIO_new(BIO_s_file()); + + if (in == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_add_file_cert_subjects_to_stack, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!BIO_read_filename(in, file)) { + goto err; + } + + for (;;) { + if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL) { + break; + } + xn = X509_get_subject_name(x); + if (xn == NULL) { + goto err; + } + xn = X509_NAME_dup(xn); + if (xn == NULL) { + goto err; + } + if (sk_X509_NAME_find(stack, NULL, xn)) { + X509_NAME_free(xn); + } else { + sk_X509_NAME_push(stack, xn); + } + } + + ERR_clear_error(); + + if (0) { + err: + ret = 0; + } + + BIO_free(in); + X509_free(x); + + (void) sk_X509_NAME_set_cmp_func(stack, oldcmp); + + return ret; +} + +/* Add a directory of certs to a stack. + * + * \param stack the stack to append to. + * \param dir the directory to append from. All files in this directory will be + * examined as potential certs. Any that are acceptable to + * SSL_add_dir_cert_subjects_to_stack() that are not already in the stack will + * be included. + * \return 1 for success, 0 for failure. Note that in the case of failure some + * certs may have been added to \c stack. */ +int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, + const char *dir) { + OPENSSL_DIR_CTX *d = NULL; + const char *filename; + int ret = 0; + + /* Note that a side effect is that the CAs will be sorted by name */ + while ((filename = OPENSSL_DIR_read(&d, dir))) { + char buf[1024]; + int r; + + if (strlen(dir) + strlen(filename) + 2 > sizeof(buf)) { + OPENSSL_PUT_ERROR(SSL, SSL_add_dir_cert_subjects_to_stack, + SSL_R_PATH_TOO_LONG); + goto err; + } + + r = BIO_snprintf(buf, sizeof buf, "%s/%s", dir, filename); + if (r <= 0 || r >= (int)sizeof(buf) || + !SSL_add_file_cert_subjects_to_stack(stack, buf)) { + goto err; + } + } + + if (errno) { + OPENSSL_PUT_ERROR(SSL, SSL_add_dir_cert_subjects_to_stack, ERR_R_SYS_LIB); + ERR_add_error_data(3, "OPENSSL_DIR_read(&ctx, '", dir, "')"); + goto err; + } + + ret = 1; + +err: + if (d) { + OPENSSL_DIR_end(&d); + } + return ret; } /* Add a certificate to a BUF_MEM structure */ @@ -429,7 +777,7 @@ static int ssl_add_cert_to_buf(BUF_MEM *buf, unsigned long *l, X509 *x) { n = i2d_X509(x, NULL); if (!BUF_MEM_grow_clean(buf, (int)(n + (*l) + 3))) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); + OPENSSL_PUT_ERROR(SSL, ssl_add_cert_to_buf, ERR_R_BUF_LIB); return 0; } p = (uint8_t *)&(buf->data[*l]); @@ -441,21 +789,34 @@ static int ssl_add_cert_to_buf(BUF_MEM *buf, unsigned long *l, X509 *x) { } /* Add certificate chain to internal SSL BUF_MEM structure. */ -int ssl_add_cert_chain(SSL *ssl, unsigned long *l) { - CERT *cert = ssl->cert; - BUF_MEM *buf = ssl->init_buf; +int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l) { + BUF_MEM *buf = s->init_buf; int no_chain = 0; size_t i; - X509 *x = cert->x509; - STACK_OF(X509) *chain = cert->chain; + X509 *x = cpk->x509; + STACK_OF(X509) *extra_certs; + X509_STORE *chain_store; if (x == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET); + OPENSSL_PUT_ERROR(SSL, ssl_add_cert_chain, SSL_R_NO_CERTIFICATE_SET); return 0; } - if ((ssl->mode & SSL_MODE_NO_AUTO_CHAIN) || chain != NULL) { + if (s->cert->chain_store) { + chain_store = s->cert->chain_store; + } else { + chain_store = s->ctx->cert_store; + } + + /* If we have a certificate specific chain use it, else use parent ctx. */ + if (cpk && cpk->chain) { + extra_certs = cpk->chain; + } else { + extra_certs = s->ctx->extra_certs; + } + + if ((s->mode & SSL_MODE_NO_AUTO_CHAIN) || extra_certs) { no_chain = 1; } @@ -464,8 +825,8 @@ int ssl_add_cert_chain(SSL *ssl, unsigned long *l) { return 0; } - for (i = 0; i < sk_X509_num(chain); i++) { - x = sk_X509_value(chain, i); + for (i = 0; i < sk_X509_num(extra_certs); i++) { + x = sk_X509_value(extra_certs, i); if (!ssl_add_cert_to_buf(buf, l, x)) { return 0; } @@ -473,8 +834,8 @@ int ssl_add_cert_chain(SSL *ssl, unsigned long *l) { } else { X509_STORE_CTX xs_ctx; - if (!X509_STORE_CTX_init(&xs_ctx, ssl->ctx->cert_store, x, NULL)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB); + if (!X509_STORE_CTX_init(&xs_ctx, chain_store, x, NULL)) { + OPENSSL_PUT_ERROR(SSL, ssl_add_cert_chain, ERR_R_X509_LIB); return 0; } X509_verify_cert(&xs_ctx); @@ -494,65 +855,132 @@ int ssl_add_cert_chain(SSL *ssl, unsigned long *l) { return 1; } -int SSL_CTX_set0_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) { - return ssl_cert_set0_chain(ctx->cert, chain); -} +/* Build a certificate chain for current certificate */ +int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags) { + CERT_PKEY *cpk = c->key; + X509_STORE_CTX xs_ctx; + STACK_OF(X509) *chain = NULL, *untrusted = NULL; + X509 *x; + int i, rv = 0; + uint32_t error; -int SSL_CTX_set1_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) { - return ssl_cert_set1_chain(ctx->cert, chain); -} + if (!cpk->x509) { + OPENSSL_PUT_ERROR(SSL, ssl_build_cert_chain, SSL_R_NO_CERTIFICATE_SET); + goto err; + } -int SSL_set0_chain(SSL *ssl, STACK_OF(X509) *chain) { - return ssl_cert_set0_chain(ssl->cert, chain); -} + /* Rearranging and check the chain: add everything to a store */ + if (flags & SSL_BUILD_CHAIN_FLAG_CHECK) { + size_t j; + chain_store = X509_STORE_new(); + if (!chain_store) { + goto err; + } -int SSL_set1_chain(SSL *ssl, STACK_OF(X509) *chain) { - return ssl_cert_set1_chain(ssl->cert, chain); -} + for (j = 0; j < sk_X509_num(cpk->chain); j++) { + x = sk_X509_value(cpk->chain, j); + if (!X509_STORE_add_cert(chain_store, x)) { + error = ERR_peek_last_error(); + if (ERR_GET_LIB(error) != ERR_LIB_X509 || + ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE) { + goto err; + } + ERR_clear_error(); + } + } -int SSL_CTX_add0_chain_cert(SSL_CTX *ctx, X509 *x509) { - return ssl_cert_add0_chain_cert(ctx->cert, x509); -} + /* Add EE cert too: it might be self signed */ + if (!X509_STORE_add_cert(chain_store, cpk->x509)) { + error = ERR_peek_last_error(); + if (ERR_GET_LIB(error) != ERR_LIB_X509 || + ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE) { + goto err; + } + ERR_clear_error(); + } + } else { + if (c->chain_store) { + chain_store = c->chain_store; + } -int SSL_CTX_add1_chain_cert(SSL_CTX *ctx, X509 *x509) { - return ssl_cert_add1_chain_cert(ctx->cert, x509); -} + if (flags & SSL_BUILD_CHAIN_FLAG_UNTRUSTED) { + untrusted = cpk->chain; + } + } -int SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *x509) { - return SSL_CTX_add0_chain_cert(ctx, x509); -} + if (!X509_STORE_CTX_init(&xs_ctx, chain_store, cpk->x509, untrusted)) { + OPENSSL_PUT_ERROR(SSL, ssl_build_cert_chain, ERR_R_X509_LIB); + goto err; + } -int SSL_add0_chain_cert(SSL *ssl, X509 *x509) { - return ssl_cert_add0_chain_cert(ssl->cert, x509); -} + i = X509_verify_cert(&xs_ctx); + if (i <= 0 && flags & SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR) { + if (flags & SSL_BUILD_CHAIN_FLAG_CLEAR_ERROR) { + ERR_clear_error(); + } + i = 1; + rv = 2; + } -int SSL_add1_chain_cert(SSL *ssl, X509 *x509) { - return ssl_cert_add1_chain_cert(ssl->cert, x509); -} + if (i > 0) { + chain = X509_STORE_CTX_get1_chain(&xs_ctx); + } + if (i <= 0) { + OPENSSL_PUT_ERROR(SSL, ssl_build_cert_chain, + SSL_R_CERTIFICATE_VERIFY_FAILED); + i = X509_STORE_CTX_get_error(&xs_ctx); + ERR_add_error_data(2, "Verify error:", X509_verify_cert_error_string(i)); -int SSL_CTX_clear_chain_certs(SSL_CTX *ctx) { - return SSL_CTX_set0_chain(ctx, NULL); -} + X509_STORE_CTX_cleanup(&xs_ctx); + goto err; + } -int SSL_CTX_clear_extra_chain_certs(SSL_CTX *ctx) { - return SSL_CTX_clear_chain_certs(ctx); -} + X509_STORE_CTX_cleanup(&xs_ctx); + if (cpk->chain) { + sk_X509_pop_free(cpk->chain, X509_free); + } -int SSL_clear_chain_certs(SSL *ssl) { - return SSL_set0_chain(ssl, NULL); -} + /* Remove EE certificate from chain */ + x = sk_X509_shift(chain); + X509_free(x); + if (flags & SSL_BUILD_CHAIN_FLAG_NO_ROOT) { + if (sk_X509_num(chain) > 0) { + /* See if last cert is self signed */ + x = sk_X509_value(chain, sk_X509_num(chain) - 1); + X509_check_purpose(x, -1, 0); + if (x->ex_flags & EXFLAG_SS) { + x = sk_X509_pop(chain); + X509_free(x); + } + } + } -int SSL_CTX_get0_chain_certs(const SSL_CTX *ctx, STACK_OF(X509) **out_chain) { - *out_chain = ctx->cert->chain; - return 1; -} + cpk->chain = chain; + if (rv == 0) { + rv = 1; + } + +err: + if (flags & SSL_BUILD_CHAIN_FLAG_CHECK) { + X509_STORE_free(chain_store); + } -int SSL_CTX_get_extra_chain_certs(const SSL_CTX *ctx, - STACK_OF(X509) **out_chain) { - return SSL_CTX_get0_chain_certs(ctx, out_chain); + return rv; } -int SSL_get0_chain_certs(const SSL *ssl, STACK_OF(X509) **out_chain) { - *out_chain = ssl->cert->chain; +int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref) { + X509_STORE **pstore; + if (chain) { + pstore = &c->chain_store; + } else { + pstore = &c->verify_store; + } + + X509_STORE_free(*pstore); + *pstore = store; + + if (ref && store) { + CRYPTO_refcount_inc(&store->references); + } return 1; } diff --git a/src/ssl/ssl_cipher.c b/src/ssl/ssl_cipher.c index b23d775..8d03c9e 100644 --- a/src/ssl/ssl_cipher.c +++ b/src/ssl/ssl_cipher.c @@ -138,8 +138,6 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. */ -#include <openssl/ssl.h> - #include <assert.h> #include <stdio.h> #include <string.h> @@ -157,12 +155,6 @@ /* kCiphers is an array of all supported ciphers, sorted by id. */ const SSL_CIPHER kCiphers[] = { /* The RSA ciphers */ - /* Cipher 02 */ - { - SSL3_TXT_RSA_NULL_SHA, SSL3_CK_RSA_NULL_SHA, SSL_kRSA, SSL_aRSA, - SSL_eNULL, SSL_SHA1, SSL_SSLV3, SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT, 0, 0, - }, - /* Cipher 04 */ { SSL3_TXT_RSA_RC4_128_MD5, SSL3_CK_RSA_RC4_128_MD5, SSL_kRSA, SSL_aRSA, @@ -278,7 +270,8 @@ const SSL_CIPHER kCiphers[] = { TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256, TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, SSL_kRSA, SSL_aRSA, SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA256, + SSL_HANDSHAKE_MAC_SHA256 | + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 128, 128, }, @@ -287,7 +280,8 @@ const SSL_CIPHER kCiphers[] = { TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384, TLS1_CK_RSA_WITH_AES_256_GCM_SHA384, SSL_kRSA, SSL_aRSA, SSL_AES256GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA384, + SSL_HANDSHAKE_MAC_SHA384 | + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 256, 256, }, @@ -296,7 +290,8 @@ const SSL_CIPHER kCiphers[] = { TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256, SSL_kDHE, SSL_aRSA, SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA256, + SSL_HANDSHAKE_MAC_SHA256 | + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 128, 128, }, @@ -305,7 +300,8 @@ const SSL_CIPHER kCiphers[] = { TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384, SSL_kDHE, SSL_aRSA, SSL_AES256GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA384, + SSL_HANDSHAKE_MAC_SHA384 | + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 256, 256, }, @@ -399,7 +395,8 @@ const SSL_CIPHER kCiphers[] = { TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, SSL_kECDHE, SSL_aECDSA, SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA256, + SSL_HANDSHAKE_MAC_SHA256 | + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 128, 128, }, @@ -408,7 +405,8 @@ const SSL_CIPHER kCiphers[] = { TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, SSL_kECDHE, SSL_aECDSA, SSL_AES256GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA384, + SSL_HANDSHAKE_MAC_SHA384 | + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 256, 256, }, @@ -417,7 +415,8 @@ const SSL_CIPHER kCiphers[] = { TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, SSL_kECDHE, SSL_aRSA, SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA256, + SSL_HANDSHAKE_MAC_SHA256 | + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 128, 128, }, @@ -426,7 +425,8 @@ const SSL_CIPHER kCiphers[] = { TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, SSL_kECDHE, SSL_aRSA, SSL_AES256GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA384, + SSL_HANDSHAKE_MAC_SHA384 | + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 256, 256, }, @@ -448,15 +448,15 @@ const SSL_CIPHER kCiphers[] = { SSL_HANDSHAKE_MAC_DEFAULT, 256, 256, }, -#if !defined(BORINGSSL_ANDROID_SYSTEM) /* ChaCha20-Poly1305 cipher suites. */ +#if !defined(ANDROID) { TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305, TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, SSL_kECDHE, SSL_aRSA, SSL_CHACHA20POLY1305, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH, SSL_HANDSHAKE_MAC_SHA256, - 256, 256, + 256, 0, }, { @@ -464,13 +464,33 @@ const SSL_CIPHER kCiphers[] = { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, SSL_kECDHE, SSL_aECDSA, SSL_CHACHA20POLY1305, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH, SSL_HANDSHAKE_MAC_SHA256, - 256, 256, + 256, 0, + }, + + { + TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305, + TLS1_CK_DHE_RSA_CHACHA20_POLY1305, SSL_kDHE, SSL_aRSA, + SSL_CHACHA20POLY1305, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH, + SSL_HANDSHAKE_MAC_SHA256, + 256, 0, }, #endif }; static const size_t kCiphersLen = sizeof(kCiphers) / sizeof(kCiphers[0]); +struct handshake_digest { + uint32_t mask; + const EVP_MD *(*md_func)(void); +}; + +static const struct handshake_digest ssl_handshake_digests[SSL_MAX_DIGEST] = { + {SSL_HANDSHAKE_MAC_MD5, EVP_md5}, + {SSL_HANDSHAKE_MAC_SHA, EVP_sha1}, + {SSL_HANDSHAKE_MAC_SHA256, EVP_sha256}, + {SSL_HANDSHAKE_MAC_SHA384, EVP_sha384}, +}; + #define CIPHER_ADD 1 #define CIPHER_KILL 2 #define CIPHER_DEL 3 @@ -501,8 +521,7 @@ typedef struct cipher_alias_st { } CIPHER_ALIAS; static const CIPHER_ALIAS kCipherAliases[] = { - /* "ALL" doesn't include eNULL (must be specifically enabled) */ - {SSL_TXT_ALL, ~0u, ~0u, ~SSL_eNULL, ~0u, ~0u, ~0u}, + {SSL_TXT_ALL, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u}, /* The "COMPLEMENTOFDEFAULT" rule is omitted. It matches nothing. */ @@ -523,7 +542,7 @@ static const CIPHER_ALIAS kCipherAliases[] = { {SSL_TXT_kPSK, SSL_kPSK, ~0u, ~0u, ~0u, ~0u, ~0u}, /* server authentication aliases */ - {SSL_TXT_aRSA, ~0u, SSL_aRSA, ~SSL_eNULL, ~0u, ~0u, ~0u}, + {SSL_TXT_aRSA, ~0u, SSL_aRSA, ~0u, ~0u, ~0u, ~0u}, {SSL_TXT_aECDSA, ~0u, SSL_aECDSA, ~0u, ~0u, ~0u, ~0u}, {SSL_TXT_ECDSA, ~0u, SSL_aECDSA, ~0u, ~0u, ~0u, ~0u}, {SSL_TXT_aPSK, ~0u, SSL_aPSK, ~0u, ~0u, ~0u, ~0u}, @@ -533,7 +552,7 @@ static const CIPHER_ALIAS kCipherAliases[] = { {SSL_TXT_EDH, SSL_kDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, {SSL_TXT_ECDHE, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, {SSL_TXT_EECDH, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, - {SSL_TXT_RSA, SSL_kRSA, SSL_aRSA, ~SSL_eNULL, ~0u, ~0u, ~0u}, + {SSL_TXT_RSA, SSL_kRSA, SSL_aRSA, ~0u, ~0u, ~0u, ~0u}, {SSL_TXT_PSK, SSL_kPSK, SSL_aPSK, ~0u, ~0u, ~0u, ~0u}, /* symmetric encryption aliases */ @@ -547,21 +566,21 @@ static const CIPHER_ALIAS kCipherAliases[] = { /* MAC aliases */ {SSL_TXT_MD5, ~0u, ~0u, ~0u, SSL_MD5, ~0u, ~0u}, - {SSL_TXT_SHA1, ~0u, ~0u, ~SSL_eNULL, SSL_SHA1, ~0u, ~0u}, - {SSL_TXT_SHA, ~0u, ~0u, ~SSL_eNULL, SSL_SHA1, ~0u, ~0u}, + {SSL_TXT_SHA1, ~0u, ~0u, ~0u, SSL_SHA1, ~0u, ~0u}, + {SSL_TXT_SHA, ~0u, ~0u, ~0u, SSL_SHA1, ~0u, ~0u}, {SSL_TXT_SHA256, ~0u, ~0u, ~0u, SSL_SHA256, ~0u, ~0u}, {SSL_TXT_SHA384, ~0u, ~0u, ~0u, SSL_SHA384, ~0u, ~0u}, /* protocol version aliases */ - {SSL_TXT_SSLV3, ~0u, ~0u, ~SSL_eNULL, ~0u, SSL_SSLV3, ~0u}, - {SSL_TXT_TLSV1, ~0u, ~0u, ~SSL_eNULL, ~0u, SSL_TLSV1, ~0u}, - {SSL_TXT_TLSV1_2, ~0u, ~0u, ~SSL_eNULL, ~0u, SSL_TLSV1_2, ~0u}, + {SSL_TXT_SSLV3, ~0u, ~0u, ~0u, ~0u, SSL_SSLV3, ~0u}, + {SSL_TXT_TLSV1, ~0u, ~0u, ~0u, ~0u, SSL_TLSV1, ~0u}, + {SSL_TXT_TLSV1_2, ~0u, ~0u, ~0u, ~0u, SSL_TLSV1_2, ~0u}, /* strength classes */ {SSL_TXT_MEDIUM, ~0u, ~0u, ~0u, ~0u, ~0u, SSL_MEDIUM}, {SSL_TXT_HIGH, ~0u, ~0u, ~0u, ~0u, ~0u, SSL_HIGH}, /* FIPS 140-2 approved ciphersuite */ - {SSL_TXT_FIPS, ~0u, ~0u, ~SSL_eNULL, ~0u, ~0u, SSL_FIPS}, + {SSL_TXT_FIPS, ~0u, ~0u, ~0u, ~0u, ~0u, SSL_FIPS}, }; static const size_t kCipherAliasesLen = @@ -611,7 +630,7 @@ int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead, *out_fixed_iv_len = 4; return 1; -#if !defined(BORINGSSL_ANDROID_SYSTEM) +#if !defined(ANDROID) case SSL_CHACHA20POLY1305: *out_aead = EVP_aead_chacha20_poly1305(); *out_fixed_iv_len = 0; @@ -706,36 +725,19 @@ int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead, return 0; } - case SSL_eNULL: - switch (cipher->algorithm_mac) { - case SSL_SHA1: - if (version == SSL3_VERSION) { - *out_aead = EVP_aead_null_sha1_ssl3(); - } else { - *out_aead = EVP_aead_null_sha1_tls(); - } - *out_mac_secret_len = SHA_DIGEST_LENGTH; - return 1; - default: - return 0; - } - default: return 0; } } -const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf) { - switch (algorithm_prf) { - case SSL_HANDSHAKE_MAC_DEFAULT: - return EVP_sha1(); - case SSL_HANDSHAKE_MAC_SHA256: - return EVP_sha256(); - case SSL_HANDSHAKE_MAC_SHA384: - return EVP_sha384(); - default: - return NULL; +int ssl_get_handshake_digest(uint32_t *out_mask, const EVP_MD **out_md, + size_t idx) { + if (idx >= SSL_MAX_DIGEST) { + return 0; } + *out_mask = ssl_handshake_digests[idx].mask; + *out_md = ssl_handshake_digests[idx].md_func(); + return 1; } #define ITEM_SEP(a) \ @@ -977,7 +979,7 @@ static int ssl_cipher_strength_sort(CIPHER_ORDER **head_p, number_uses = OPENSSL_malloc((max_strength_bits + 1) * sizeof(int)); if (!number_uses) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl_cipher_strength_sort, ERR_R_MALLOC_FAILURE); return 0; } memset(number_uses, 0, (max_strength_bits + 1) * sizeof(int)); @@ -1039,7 +1041,8 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, continue; } else if (!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') && !(ch >= '0' && ch <= '9')) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_OPERATOR_IN_GROUP); + OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, + SSL_R_UNEXPECTED_OPERATOR_IN_GROUP); retval = in_group = 0; break; } else { @@ -1059,7 +1062,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, l++; } else if (ch == '[') { if (in_group) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NESTED_GROUP); + OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_NESTED_GROUP); retval = in_group = 0; break; } @@ -1074,7 +1077,8 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, /* If preference groups are enabled, the only legal operator is +. * Otherwise the in_group bits will get mixed up. */ if (has_group && rule != CIPHER_ADD) { - OPENSSL_PUT_ERROR(SSL, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS); + OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, + SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS); retval = in_group = 0; break; } @@ -1106,7 +1110,8 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, if (buf_len == 0) { /* We hit something we cannot deal with, it is no command or separator * nor alphanumeric, so we call this an error. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND); + OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, + SSL_R_INVALID_COMMAND); retval = in_group = 0; l++; break; @@ -1160,7 +1165,8 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, if (buf_len == 8 && !strncmp(buf, "STRENGTH", 8)) { ok = ssl_cipher_strength_sort(head_p, tail_p); } else { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND); + OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, + SSL_R_INVALID_COMMAND); } if (ok == 0) { @@ -1180,7 +1186,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, } if (in_group) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND); + OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_INVALID_COMMAND); retval = 0; } @@ -1210,7 +1216,7 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, * allocation. */ co_list = (CIPHER_ORDER *)OPENSSL_malloc(sizeof(CIPHER_ORDER) * kCiphersLen); if (co_list == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl_create_cipher_list, ERR_R_MALLOC_FAILURE); return NULL; } @@ -1385,27 +1391,13 @@ int SSL_CIPHER_has_MD5_HMAC(const SSL_CIPHER *cipher) { } int SSL_CIPHER_is_AESGCM(const SSL_CIPHER *cipher) { - return (cipher->algorithm_enc & (SSL_AES128GCM | SSL_AES256GCM)) != 0; + return (cipher->algorithm_mac & (SSL_AES128GCM | SSL_AES256GCM)) != 0; } int SSL_CIPHER_is_CHACHA20POLY1305(const SSL_CIPHER *cipher) { return (cipher->algorithm_enc & SSL_CHACHA20POLY1305) != 0; } -int SSL_CIPHER_is_NULL(const SSL_CIPHER *cipher) { - return (cipher->algorithm_enc & SSL_eNULL) != 0; -} - -int SSL_CIPHER_is_RC4(const SSL_CIPHER *cipher) { - return (cipher->algorithm_enc & SSL_RC4) != 0; -} - -int SSL_CIPHER_is_block_cipher(const SSL_CIPHER *cipher) { - /* Neither stream cipher nor AEAD. */ - return (cipher->algorithm_enc & (SSL_RC4 | SSL_eNULL)) == 0 && - cipher->algorithm_mac != SSL_AEAD; -} - /* return the actual cipher being used */ const char *SSL_CIPHER_get_name(const SSL_CIPHER *cipher) { if (cipher != NULL) { @@ -1480,24 +1472,27 @@ static const char *ssl_cipher_get_enc_name(const SSL_CIPHER *cipher) { } static const char *ssl_cipher_get_prf_name(const SSL_CIPHER *cipher) { - switch (cipher->algorithm_prf) { - case SSL_HANDSHAKE_MAC_DEFAULT: - /* Before TLS 1.2, the PRF component is the hash used in the HMAC, which is - * only ever MD5 or SHA-1. */ - switch (cipher->algorithm_mac) { - case SSL_MD5: - return "MD5"; - case SSL_SHA1: - return "SHA"; - } - break; - case SSL_HANDSHAKE_MAC_SHA256: - return "SHA256"; - case SSL_HANDSHAKE_MAC_SHA384: - return "SHA384"; + if ((cipher->algorithm2 & SSL_HANDSHAKE_MAC_DEFAULT) == + SSL_HANDSHAKE_MAC_DEFAULT) { + /* Before TLS 1.2, the PRF component is the hash used in the HMAC, which is + * only ever MD5 or SHA-1. */ + switch (cipher->algorithm_mac) { + case SSL_MD5: + return "MD5"; + case SSL_SHA1: + return "SHA"; + default: + assert(0); + return "UNKNOWN"; + } + } else if (cipher->algorithm2 & SSL_HANDSHAKE_MAC_SHA256) { + return "SHA256"; + } else if (cipher->algorithm2 & SSL_HANDSHAKE_MAC_SHA384) { + return "SHA384"; + } else { + assert(0); + return "UNKNOWN"; } - assert(0); - return "UNKNOWN"; } char *SSL_CIPHER_get_rfc_name(const SSL_CIPHER *cipher) { @@ -1630,10 +1625,6 @@ const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, enc = "ChaCha20-Poly1305"; break; - case SSL_eNULL: - enc="None"; - break; - default: enc = "unknown"; break; @@ -1683,28 +1674,29 @@ const char *SSL_CIPHER_get_version(const SSL_CIPHER *cipher) { return "TLSv1/SSLv3"; } -COMP_METHOD *SSL_COMP_get_compression_methods(void) { return NULL; } +void *SSL_COMP_get_compression_methods(void) { return NULL; } -int SSL_COMP_add_compression_method(int id, COMP_METHOD *cm) { return 1; } +int SSL_COMP_add_compression_method(int id, void *cm) { return 1; } -const char *SSL_COMP_get_name(const COMP_METHOD *comp) { return NULL; } +const char *SSL_COMP_get_name(const void *comp) { return NULL; } -int ssl_cipher_get_key_type(const SSL_CIPHER *cipher) { +int ssl_cipher_get_cert_index(const SSL_CIPHER *cipher) { uint32_t alg_a = cipher->algorithm_auth; if (alg_a & SSL_aECDSA) { - return EVP_PKEY_EC; + return SSL_PKEY_ECC; } else if (alg_a & SSL_aRSA) { - return EVP_PKEY_RSA; + return SSL_PKEY_RSA_ENC; } - return EVP_PKEY_NONE; + return -1; } 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) { + /* PSK-authenticated ciphers do not use a public key, except for + * RSA_PSK. */ + if ((cipher->algorithm_auth & SSL_aPSK) && + !(cipher->algorithm_mkey & SSL_kRSA)) { return 0; } @@ -1721,34 +1713,3 @@ int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher) { /* It is optional in all others. */ return 0; } - -size_t ssl_cipher_get_record_split_len(const SSL_CIPHER *cipher) { - size_t block_size; - switch (cipher->algorithm_enc) { - case SSL_3DES: - block_size = 8; - break; - case SSL_AES128: - case SSL_AES256: - block_size = 16; - break; - default: - return 0; - } - - size_t mac_len; - switch (cipher->algorithm_mac) { - case SSL_MD5: - mac_len = MD5_DIGEST_LENGTH; - break; - case SSL_SHA1: - mac_len = SHA_DIGEST_LENGTH; - break; - default: - return 0; - } - - size_t ret = 1 + mac_len; - ret += block_size - (ret % block_size); - return ret; -} diff --git a/src/ssl/ssl_file.c b/src/ssl/ssl_file.c deleted file mode 100644 index 88ad5b7..0000000 --- a/src/ssl/ssl_file.c +++ /dev/null @@ -1,623 +0,0 @@ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ -/* ==================================================================== - * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). - * - */ - -#include <openssl/ssl.h> - -#include <errno.h> -#include <string.h> - -#include <openssl/bio.h> -#include <openssl/err.h> -#include <openssl/mem.h> -#include <openssl/pem.h> -#include <openssl/stack.h> -#include <openssl/x509.h> - -#include "../crypto/directory.h" -#include "internal.h" - - -static int xname_cmp(const X509_NAME **a, const X509_NAME **b) { - return X509_NAME_cmp(*a, *b); -} - -/* TODO(davidben): Is there any reason this doesn't call - * |SSL_add_file_cert_subjects_to_stack|? */ -STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) { - BIO *in; - X509 *x = NULL; - X509_NAME *xn = NULL; - STACK_OF(X509_NAME) *ret = NULL, *sk; - - sk = sk_X509_NAME_new(xname_cmp); - in = BIO_new(BIO_s_file()); - - if (sk == NULL || in == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - - if (!BIO_read_filename(in, file)) { - goto err; - } - - for (;;) { - if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL) { - break; - } - if (ret == NULL) { - ret = sk_X509_NAME_new_null(); - if (ret == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - } - xn = X509_get_subject_name(x); - if (xn == NULL) { - goto err; - } - - /* check for duplicates */ - xn = X509_NAME_dup(xn); - if (xn == NULL) { - goto err; - } - if (sk_X509_NAME_find(sk, NULL, xn)) { - X509_NAME_free(xn); - } else { - sk_X509_NAME_push(sk, xn); - sk_X509_NAME_push(ret, xn); - } - } - - if (0) { - err: - sk_X509_NAME_pop_free(ret, X509_NAME_free); - ret = NULL; - } - - sk_X509_NAME_free(sk); - BIO_free(in); - X509_free(x); - if (ret != NULL) { - ERR_clear_error(); - } - return ret; -} - -int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, - const char *file) { - BIO *in; - X509 *x = NULL; - X509_NAME *xn = NULL; - int ret = 1; - int (*oldcmp)(const X509_NAME **a, const X509_NAME **b); - - oldcmp = sk_X509_NAME_set_cmp_func(stack, xname_cmp); - in = BIO_new(BIO_s_file()); - - if (in == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - - if (!BIO_read_filename(in, file)) { - goto err; - } - - for (;;) { - if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL) { - break; - } - xn = X509_get_subject_name(x); - if (xn == NULL) { - goto err; - } - xn = X509_NAME_dup(xn); - if (xn == NULL) { - goto err; - } - if (sk_X509_NAME_find(stack, NULL, xn)) { - X509_NAME_free(xn); - } else { - sk_X509_NAME_push(stack, xn); - } - } - - ERR_clear_error(); - - if (0) { - err: - ret = 0; - } - - BIO_free(in); - X509_free(x); - - (void) sk_X509_NAME_set_cmp_func(stack, oldcmp); - - return ret; -} - -/* Add a directory of certs to a stack. - * - * \param stack the stack to append to. - * \param dir the directory to append from. All files in this directory will be - * examined as potential certs. Any that are acceptable to - * SSL_add_dir_cert_subjects_to_stack() that are not already in the stack will - * be included. - * \return 1 for success, 0 for failure. Note that in the case of failure some - * certs may have been added to \c stack. */ -int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, - const char *dir) { - OPENSSL_DIR_CTX *d = NULL; - const char *filename; - int ret = 0; - - /* Note that a side effect is that the CAs will be sorted by name */ - while ((filename = OPENSSL_DIR_read(&d, dir))) { - char buf[1024]; - int r; - - if (strlen(dir) + strlen(filename) + 2 > sizeof(buf)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_PATH_TOO_LONG); - goto err; - } - - r = BIO_snprintf(buf, sizeof buf, "%s/%s", dir, filename); - if (r <= 0 || r >= (int)sizeof(buf) || - !SSL_add_file_cert_subjects_to_stack(stack, buf)) { - goto err; - } - } - - if (errno) { - OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB); - ERR_add_error_data(3, "OPENSSL_DIR_read(&ctx, '", dir, "')"); - goto err; - } - - ret = 1; - -err: - if (d) { - OPENSSL_DIR_end(&d); - } - return ret; -} - -int SSL_use_certificate_file(SSL *ssl, const char *file, int type) { - int reason_code; - BIO *in; - int ret = 0; - X509 *x = NULL; - - in = BIO_new(BIO_s_file()); - if (in == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); - goto end; - } - - if (BIO_read_filename(in, file) <= 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB); - goto end; - } - - if (type == SSL_FILETYPE_ASN1) { - reason_code = ERR_R_ASN1_LIB; - x = d2i_X509_bio(in, NULL); - } else if (type == SSL_FILETYPE_PEM) { - reason_code = ERR_R_PEM_LIB; - x = PEM_read_bio_X509(in, NULL, ssl->ctx->default_passwd_callback, - ssl->ctx->default_passwd_callback_userdata); - } else { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE); - goto end; - } - - if (x == NULL) { - OPENSSL_PUT_ERROR(SSL, reason_code); - goto end; - } - - ret = SSL_use_certificate(ssl, x); - -end: - X509_free(x); - BIO_free(in); - - return ret; -} - -int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type) { - int reason_code, ret = 0; - BIO *in; - RSA *rsa = NULL; - - in = BIO_new(BIO_s_file()); - if (in == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); - goto end; - } - - if (BIO_read_filename(in, file) <= 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB); - goto end; - } - - if (type == SSL_FILETYPE_ASN1) { - reason_code = ERR_R_ASN1_LIB; - rsa = d2i_RSAPrivateKey_bio(in, NULL); - } else if (type == SSL_FILETYPE_PEM) { - reason_code = ERR_R_PEM_LIB; - rsa = - PEM_read_bio_RSAPrivateKey(in, NULL, ssl->ctx->default_passwd_callback, - ssl->ctx->default_passwd_callback_userdata); - } else { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE); - goto end; - } - - if (rsa == NULL) { - OPENSSL_PUT_ERROR(SSL, reason_code); - goto end; - } - ret = SSL_use_RSAPrivateKey(ssl, rsa); - RSA_free(rsa); - -end: - BIO_free(in); - return ret; -} - -int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type) { - int reason_code, ret = 0; - BIO *in; - EVP_PKEY *pkey = NULL; - - in = BIO_new(BIO_s_file()); - if (in == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); - goto end; - } - - if (BIO_read_filename(in, file) <= 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB); - goto end; - } - - if (type == SSL_FILETYPE_PEM) { - reason_code = ERR_R_PEM_LIB; - pkey = PEM_read_bio_PrivateKey(in, NULL, ssl->ctx->default_passwd_callback, - ssl->ctx->default_passwd_callback_userdata); - } else if (type == SSL_FILETYPE_ASN1) { - reason_code = ERR_R_ASN1_LIB; - pkey = d2i_PrivateKey_bio(in, NULL); - } else { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE); - goto end; - } - - if (pkey == NULL) { - OPENSSL_PUT_ERROR(SSL, reason_code); - goto end; - } - ret = SSL_use_PrivateKey(ssl, pkey); - EVP_PKEY_free(pkey); - -end: - BIO_free(in); - return ret; -} - -int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) { - int reason_code; - BIO *in; - int ret = 0; - X509 *x = NULL; - - in = BIO_new(BIO_s_file()); - if (in == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); - goto end; - } - - if (BIO_read_filename(in, file) <= 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB); - goto end; - } - - if (type == SSL_FILETYPE_ASN1) { - reason_code = ERR_R_ASN1_LIB; - x = d2i_X509_bio(in, NULL); - } else if (type == SSL_FILETYPE_PEM) { - reason_code = ERR_R_PEM_LIB; - x = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback, - ctx->default_passwd_callback_userdata); - } else { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE); - goto end; - } - - if (x == NULL) { - OPENSSL_PUT_ERROR(SSL, reason_code); - goto end; - } - - ret = SSL_CTX_use_certificate(ctx, x); - -end: - X509_free(x); - BIO_free(in); - return ret; -} - -int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type) { - int reason_code, ret = 0; - BIO *in; - RSA *rsa = NULL; - - in = BIO_new(BIO_s_file()); - if (in == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); - goto end; - } - - if (BIO_read_filename(in, file) <= 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB); - goto end; - } - - if (type == SSL_FILETYPE_ASN1) { - reason_code = ERR_R_ASN1_LIB; - rsa = d2i_RSAPrivateKey_bio(in, NULL); - } else if (type == SSL_FILETYPE_PEM) { - reason_code = ERR_R_PEM_LIB; - rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ctx->default_passwd_callback, - ctx->default_passwd_callback_userdata); - } else { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE); - goto end; - } - - if (rsa == NULL) { - OPENSSL_PUT_ERROR(SSL, reason_code); - goto end; - } - ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa); - RSA_free(rsa); - -end: - BIO_free(in); - return ret; -} - -int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) { - int reason_code, ret = 0; - BIO *in; - EVP_PKEY *pkey = NULL; - - in = BIO_new(BIO_s_file()); - if (in == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); - goto end; - } - - if (BIO_read_filename(in, file) <= 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB); - goto end; - } - - if (type == SSL_FILETYPE_PEM) { - reason_code = ERR_R_PEM_LIB; - pkey = PEM_read_bio_PrivateKey(in, NULL, ctx->default_passwd_callback, - ctx->default_passwd_callback_userdata); - } else if (type == SSL_FILETYPE_ASN1) { - reason_code = ERR_R_ASN1_LIB; - pkey = d2i_PrivateKey_bio(in, NULL); - } else { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE); - goto end; - } - - if (pkey == NULL) { - OPENSSL_PUT_ERROR(SSL, reason_code); - goto end; - } - ret = SSL_CTX_use_PrivateKey(ctx, pkey); - EVP_PKEY_free(pkey); - -end: - BIO_free(in); - return ret; -} - -/* Read a file that contains our certificate in "PEM" format, possibly followed - * by a sequence of CA certificates that should be sent to the peer in the - * Certificate message. */ -int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) { - BIO *in; - int ret = 0; - X509 *x = NULL; - - ERR_clear_error(); /* clear error stack for SSL_CTX_use_certificate() */ - - in = BIO_new(BIO_s_file()); - if (in == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); - goto end; - } - - if (BIO_read_filename(in, file) <= 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB); - goto end; - } - - x = PEM_read_bio_X509_AUX(in, NULL, ctx->default_passwd_callback, - ctx->default_passwd_callback_userdata); - if (x == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PEM_LIB); - goto end; - } - - ret = SSL_CTX_use_certificate(ctx, x); - - if (ERR_peek_error() != 0) { - ret = 0; /* Key/certificate mismatch doesn't imply ret==0 ... */ - } - - if (ret) { - /* If we could set up our certificate, now proceed to the CA - * certificates. */ - X509 *ca; - int r; - uint32_t err; - - SSL_CTX_clear_chain_certs(ctx); - - while ((ca = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback, - ctx->default_passwd_callback_userdata)) != - NULL) { - r = SSL_CTX_add0_chain_cert(ctx, ca); - if (!r) { - X509_free(ca); - ret = 0; - goto end; - } - /* Note that we must not free r if it was successfully added to the chain - * (while we must free the main certificate, since its reference count is - * increased by SSL_CTX_use_certificate). */ - } - - /* When the while loop ends, it's usually just EOF. */ - err = ERR_peek_last_error(); - if (ERR_GET_LIB(err) == ERR_LIB_PEM && - ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { - ERR_clear_error(); - } else { - ret = 0; /* some real error */ - } - } - -end: - X509_free(x); - BIO_free(in); - return ret; -} - -void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb) { - ctx->default_passwd_callback = cb; -} - -void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *data) { - ctx->default_passwd_callback_userdata = data; -} - -IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION) diff --git a/src/ssl/ssl_lib.c b/src/ssl/ssl_lib.c index 74bd633..9e1e308 100644 --- a/src/ssl/ssl_lib.c +++ b/src/ssl/ssl_lib.c @@ -138,14 +138,11 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. */ -#include <openssl/ssl.h> - #include <assert.h> #include <stdio.h> #include <string.h> #include <openssl/bytestring.h> -#include <openssl/crypto.h> #include <openssl/dh.h> #include <openssl/err.h> #include <openssl/lhash.h> @@ -158,10 +155,6 @@ #include "../crypto/internal.h" -/* |SSL_R_UNKNOWN_PROTOCOL| is no longer emitted, but continue to define it - * to avoid downstream churn. */ -OPENSSL_DECLARE_ERROR_REASON(SSL, UNKNOWN_PROTOCOL) - /* Some error codes are special. Ensure the make_errors.go script never * regresses this. */ OPENSSL_COMPILE_ASSERT(SSL_R_TLSV1_ALERT_NO_RENEGOTIATION == @@ -171,192 +164,91 @@ OPENSSL_COMPILE_ASSERT(SSL_R_TLSV1_ALERT_NO_RENEGOTIATION == /* kMaxHandshakeSize is the maximum size, in bytes, of a handshake message. */ static const size_t kMaxHandshakeSize = (1u << 24) - 1; -static CRYPTO_EX_DATA_CLASS g_ex_data_class_ssl = - CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA; -static CRYPTO_EX_DATA_CLASS g_ex_data_class_ssl_ctx = - CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA; - -int SSL_library_init(void) { - CRYPTO_library_init(); - return 1; -} - -static uint32_t ssl_session_hash(const SSL_SESSION *a) { - uint32_t hash = - ((uint32_t)a->session_id[0]) || - ((uint32_t)a->session_id[1] << 8) || - ((uint32_t)a->session_id[2] << 16) || - ((uint32_t)a->session_id[3] << 24); - - return hash; -} - -/* NB: If this function (or indeed the hash function which uses a sort of - * coarser function than this one) is changed, ensure - * SSL_CTX_has_matching_session_id() is checked accordingly. It relies on being - * able to construct an SSL_SESSION that will collide with any existing session - * with a matching session ID. */ -static int ssl_session_cmp(const SSL_SESSION *a, const SSL_SESSION *b) { - if (a->ssl_version != b->ssl_version) { - return 1; - } - - if (a->session_id_length != b->session_id_length) { - return 1; - } - - return memcmp(a->session_id, b->session_id, a->session_id_length); -} - -SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) { - SSL_CTX *ret = NULL; +static CRYPTO_EX_DATA_CLASS g_ex_data_class_ssl = CRYPTO_EX_DATA_CLASS_INIT; +static CRYPTO_EX_DATA_CLASS g_ex_data_class_ssl_ctx = CRYPTO_EX_DATA_CLASS_INIT; - if (method == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NULL_SSL_METHOD_PASSED); - return NULL; - } - - if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS); - goto err; +int SSL_clear(SSL *ssl) { + if (ssl->method == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_clear, SSL_R_NO_METHOD_SPECIFIED); + return 0; } - ret = (SSL_CTX *)OPENSSL_malloc(sizeof(SSL_CTX)); - if (ret == NULL) { - goto err; + if (ssl_clear_bad_session(ssl)) { + SSL_SESSION_free(ssl->session); + ssl->session = NULL; } - memset(ret, 0, sizeof(SSL_CTX)); - - ret->method = method->method; - - CRYPTO_MUTEX_init(&ret->lock); - - ret->session_cache_mode = SSL_SESS_CACHE_SERVER; - ret->session_cache_size = SSL_SESSION_CACHE_MAX_SIZE_DEFAULT; - - /* We take the system default */ - ret->session_timeout = SSL_DEFAULT_SESSION_TIMEOUT; - - ret->references = 1; + ssl->hit = 0; + ssl->shutdown = 0; - ret->max_cert_list = SSL_MAX_CERT_LIST_DEFAULT; - ret->verify_mode = SSL_VERIFY_NONE; - ret->cert = ssl_cert_new(); - if (ret->cert == NULL) { - goto err; + /* 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 + * half and reset |ssl->state| accordingly. */ + if (ssl->handshake_func != NULL) { + if (ssl->server) { + SSL_set_accept_state(ssl); + } else { + SSL_set_connect_state(ssl); + } + } else { + assert(ssl->state == 0); } - ret->sessions = lh_SSL_SESSION_new(ssl_session_hash, ssl_session_cmp); - if (ret->sessions == NULL) { - goto err; - } - ret->cert_store = X509_STORE_new(); - if (ret->cert_store == NULL) { - goto err; - } + /* TODO(davidben): Some state on |ssl| is reset both in |SSL_new| and + * |SSL_clear| because it is per-connection state rather than configuration + * state. Per-connection state should be on |ssl->s3| and |ssl->d1| so it is + * naturally reset at the right points between |SSL_new|, |SSL_clear|, and + * |ssl3_new|. */ - ssl_create_cipher_list(ret->method, &ret->cipher_list, - &ret->cipher_list_by_id, SSL_DEFAULT_CIPHER_LIST); - if (ret->cipher_list == NULL || - sk_SSL_CIPHER_num(ret->cipher_list->ciphers) <= 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_LIBRARY_HAS_NO_CIPHERS); - goto err2; - } + ssl->rwstate = SSL_NOTHING; + ssl->rstate = SSL_ST_READ_HEADER; - ret->param = X509_VERIFY_PARAM_new(); - if (!ret->param) { - goto err; - } + BUF_MEM_free(ssl->init_buf); + ssl->init_buf = NULL; - ret->client_CA = sk_X509_NAME_new_null(); - if (ret->client_CA == NULL) { - goto err; - } + ssl->packet = NULL; + ssl->packet_length = 0; - CRYPTO_new_ex_data(&g_ex_data_class_ssl_ctx, ret, &ret->ex_data); + ssl_clear_cipher_ctx(ssl); - ret->max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH; + OPENSSL_free(ssl->next_proto_negotiated); + ssl->next_proto_negotiated = NULL; + ssl->next_proto_negotiated_len = 0; - /* Setup RFC4507 ticket keys */ - if (!RAND_bytes(ret->tlsext_tick_key_name, 16) || - !RAND_bytes(ret->tlsext_tick_hmac_key, 16) || - !RAND_bytes(ret->tlsext_tick_aes_key, 16)) { - ret->options |= SSL_OP_NO_TICKET; + /* The ssl->d1->mtu is simultaneously configuration (preserved across + * clear) and connection-specific state (gets reset). + * + * TODO(davidben): Avoid this. */ + unsigned mtu = 0; + if (ssl->d1 != NULL) { + mtu = ssl->d1->mtu; } - /* Default is to connect to non-RI servers. When RI is more widely deployed - * might change this. */ - ret->options |= SSL_OP_LEGACY_SERVER_CONNECT; - - /* Lock the SSL_CTX to the specified version, for compatibility with legacy - * uses of SSL_METHOD. */ - if (method->version != 0) { - SSL_CTX_set_max_version(ret, method->version); - SSL_CTX_set_min_version(ret, method->version); + ssl->method->ssl_free(ssl); + if (!ssl->method->ssl_new(ssl)) { + return 0; } + ssl->enc_method = ssl3_get_enc_method(ssl->version); + assert(ssl->enc_method != NULL); - return ret; - -err: - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); -err2: - SSL_CTX_free(ret); - return NULL; -} - -void SSL_CTX_free(SSL_CTX *ctx) { - if (ctx == NULL || - !CRYPTO_refcount_dec_and_test_zero(&ctx->references)) { - return; + if (SSL_IS_DTLS(ssl) && (SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) { + ssl->d1->mtu = mtu; } - X509_VERIFY_PARAM_free(ctx->param); - - /* Free internal session cache. However: the remove_cb() may reference the - * ex_data of SSL_CTX, thus the ex_data store can only be removed after the - * sessions were flushed. As the ex_data handling routines might also touch - * the session cache, the most secure solution seems to be: empty (flush) the - * cache, then free ex_data, then finally free the cache. (See ticket - * [openssl.org #212].) */ - SSL_CTX_flush_sessions(ctx, 0); - - CRYPTO_free_ex_data(&g_ex_data_class_ssl_ctx, ctx, &ctx->ex_data); - - CRYPTO_MUTEX_cleanup(&ctx->lock); - lh_SSL_SESSION_free(ctx->sessions); - X509_STORE_free(ctx->cert_store); - ssl_cipher_preference_list_free(ctx->cipher_list); - sk_SSL_CIPHER_free(ctx->cipher_list_by_id); - ssl_cipher_preference_list_free(ctx->cipher_list_tls10); - ssl_cipher_preference_list_free(ctx->cipher_list_tls11); - ssl_cert_free(ctx->cert); - sk_SSL_CUSTOM_EXTENSION_pop_free(ctx->client_custom_extensions, - SSL_CUSTOM_EXTENSION_free); - sk_SSL_CUSTOM_EXTENSION_pop_free(ctx->server_custom_extensions, - SSL_CUSTOM_EXTENSION_free); - sk_X509_NAME_pop_free(ctx->client_CA, X509_NAME_free); - sk_SRTP_PROTECTION_PROFILE_free(ctx->srtp_profiles); - OPENSSL_free(ctx->psk_identity_hint); - OPENSSL_free(ctx->tlsext_ellipticcurvelist); - OPENSSL_free(ctx->alpn_client_proto_list); - OPENSSL_free(ctx->ocsp_response); - OPENSSL_free(ctx->signed_cert_timestamp_list); - EVP_PKEY_free(ctx->tlsext_channel_id_private); - BIO_free(ctx->keylog_bio); + ssl->client_version = ssl->version; - OPENSSL_free(ctx); + return 1; } SSL *SSL_new(SSL_CTX *ctx) { SSL *s; if (ctx == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NULL_SSL_CTX); + OPENSSL_PUT_ERROR(SSL, SSL_new, SSL_R_NULL_SSL_CTX); return NULL; } if (ctx->method == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION); + OPENSSL_PUT_ERROR(SSL, SSL_new, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION); return NULL; } @@ -397,8 +289,17 @@ SSL *SSL_new(SSL_CTX *ctx) { CRYPTO_refcount_inc(&ctx->references); s->ctx = ctx; + s->tlsext_ticket_expected = 0; CRYPTO_refcount_inc(&ctx->references); s->initial_ctx = ctx; + if (ctx->tlsext_ecpointformatlist) { + s->tlsext_ecpointformatlist = BUF_memdup( + ctx->tlsext_ecpointformatlist, ctx->tlsext_ecpointformatlist_length); + if (!s->tlsext_ecpointformatlist) { + goto err; + } + s->tlsext_ecpointformatlist_length = ctx->tlsext_ecpointformatlist_length; + } if (ctx->tlsext_ellipticcurvelist) { s->tlsext_ellipticcurvelist = @@ -409,6 +310,7 @@ SSL *SSL_new(SSL_CTX *ctx) { } s->tlsext_ellipticcurvelist_length = ctx->tlsext_ellipticcurvelist_length; } + s->next_proto_negotiated = NULL; if (s->ctx->alpn_client_proto_list) { s->alpn_client_proto_list = BUF_memdup(s->ctx->alpn_client_proto_list, @@ -429,6 +331,7 @@ SSL *SSL_new(SSL_CTX *ctx) { assert(s->enc_method != NULL); s->rwstate = SSL_NOTHING; + s->rstate = SSL_ST_READ_HEADER; CRYPTO_new_ex_data(&g_ex_data_class_ssl, s, &s->ex_data); @@ -455,474 +358,16 @@ SSL *SSL_new(SSL_CTX *ctx) { err: SSL_free(s); - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_new, ERR_R_MALLOC_FAILURE); return NULL; } -void SSL_free(SSL *ssl) { - if (ssl == NULL) { - return; - } - - X509_VERIFY_PARAM_free(ssl->param); - - 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; - } - - int free_wbio = ssl->wbio != ssl->rbio; - BIO_free_all(ssl->rbio); - if (free_wbio) { - BIO_free_all(ssl->wbio); - } - - BUF_MEM_free(ssl->init_buf); - - /* add extra stuff */ - ssl_cipher_preference_list_free(ssl->cipher_list); - sk_SSL_CIPHER_free(ssl->cipher_list_by_id); - - ssl_clear_bad_session(ssl); - SSL_SESSION_free(ssl->session); - - ssl_clear_cipher_ctx(ssl); - - ssl_cert_free(ssl->cert); - - OPENSSL_free(ssl->tlsext_hostname); - SSL_CTX_free(ssl->initial_ctx); - OPENSSL_free(ssl->tlsext_ellipticcurvelist); - OPENSSL_free(ssl->alpn_client_proto_list); - EVP_PKEY_free(ssl->tlsext_channel_id_private); - OPENSSL_free(ssl->psk_identity_hint); - sk_X509_NAME_pop_free(ssl->client_CA, X509_NAME_free); - OPENSSL_free(ssl->next_proto_negotiated); - sk_SRTP_PROTECTION_PROFILE_free(ssl->srtp_profiles); - - if (ssl->method != NULL) { - ssl->method->ssl_free(ssl); - } - SSL_CTX_free(ssl->ctx); - - OPENSSL_free(ssl); -} - -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; - /* clear the current cipher */ - ssl_clear_cipher_ctx(ssl); -} - -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; - /* clear the current cipher */ - ssl_clear_cipher_ctx(ssl); -} - -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; - } - } - - if (ssl->rbio != rbio) { - BIO_free_all(ssl->rbio); - } - if (ssl->wbio != wbio && ssl->rbio != ssl->wbio) { - BIO_free_all(ssl->wbio); - } - ssl->rbio = rbio; - ssl->wbio = wbio; -} - -BIO *SSL_get_rbio(const SSL *ssl) { return ssl->rbio; } - -BIO *SSL_get_wbio(const SSL *ssl) { return ssl->wbio; } - -int SSL_do_handshake(SSL *ssl) { - if (ssl->handshake_func == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_TYPE_NOT_SET); - return -1; - } - - if (!SSL_in_init(ssl)) { - return 1; - } - - return ssl->handshake_func(ssl); -} - -int SSL_connect(SSL *ssl) { - if (ssl->handshake_func == 0) { - /* Not properly initialized yet */ - SSL_set_connect_state(ssl); - } - - if (ssl->handshake_func != ssl->method->ssl_connect) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return -1; - } - - return ssl->handshake_func(ssl); -} - -int SSL_accept(SSL *ssl) { - if (ssl->handshake_func == 0) { - /* Not properly initialized yet */ - SSL_set_accept_state(ssl); - } - - if (ssl->handshake_func != ssl->method->ssl_accept) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return -1; - } - - return ssl->handshake_func(ssl); -} - -int SSL_read(SSL *ssl, void *buf, int num) { - if (ssl->handshake_func == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED); - return -1; - } - - if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) { - ssl->rwstate = SSL_NOTHING; - return 0; - } - - ERR_clear_system_error(); - return ssl->method->ssl_read_app_data(ssl, buf, num, 0); -} - -int SSL_peek(SSL *ssl, void *buf, int num) { - if (ssl->handshake_func == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED); - return -1; - } - - if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) { - return 0; - } - - ERR_clear_system_error(); - return ssl->method->ssl_read_app_data(ssl, buf, num, 1); -} - -int SSL_write(SSL *ssl, const void *buf, int num) { - if (ssl->handshake_func == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED); - return -1; - } - - if (ssl->shutdown & SSL_SENT_SHUTDOWN) { - ssl->rwstate = SSL_NOTHING; - OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN); - return -1; - } - - ERR_clear_system_error(); - return ssl->method->ssl_write_app_data(ssl, buf, num); -} - -int SSL_shutdown(SSL *ssl) { - /* 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 == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED); - return -1; - } - - if (SSL_in_init(ssl)) { - return 1; - } - - /* Do nothing if configured not to send a close_notify. */ - if (ssl->quiet_shutdown) { - ssl->shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN; - return 1; - } - - if (!(ssl->shutdown & SSL_SENT_SHUTDOWN)) { - ssl->shutdown |= SSL_SENT_SHUTDOWN; - ssl3_send_alert(ssl, SSL3_AL_WARNING, SSL_AD_CLOSE_NOTIFY); - - /* 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 */ - } - } 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; - } - } else if (!(ssl->shutdown & SSL_RECEIVED_SHUTDOWN)) { - /* If we are waiting for a close from our peer, we are closed */ - ssl->method->ssl_read_close_notify(ssl); - if (!(ssl->shutdown & SSL_RECEIVED_SHUTDOWN)) { - return -1; /* return WANT_READ */ - } - } - - if (ssl->shutdown == (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN) && - !ssl->s3->alert_dispatch) { - return 1; - } else { - return 0; - } -} - -int SSL_get_error(const SSL *ssl, int ret_code) { - int reason; - uint32_t err; - BIO *bio; - - if (ret_code > 0) { - return SSL_ERROR_NONE; - } - - /* Make things return SSL_ERROR_SYSCALL when doing SSL_do_handshake etc, - * where we do encode the error */ - err = ERR_peek_error(); - if (err != 0) { - if (ERR_GET_LIB(err) == ERR_LIB_SYS) { - return SSL_ERROR_SYSCALL; - } - return SSL_ERROR_SSL; - } - - if (ret_code == 0) { - if ((ssl->shutdown & SSL_RECEIVED_SHUTDOWN) && - (ssl->s3->warn_alert == SSL_AD_CLOSE_NOTIFY)) { - /* The socket was cleanly shut down with a close_notify. */ - return SSL_ERROR_ZERO_RETURN; - } - /* An EOF was observed which violates the protocol, and the underlying - * transport does not participate in the error queue. Bubble up to the - * caller. */ - return SSL_ERROR_SYSCALL; - } - - if (SSL_want_session(ssl)) { - return SSL_ERROR_PENDING_SESSION; - } - - if (SSL_want_certificate(ssl)) { - return SSL_ERROR_PENDING_CERTIFICATE; - } - - if (SSL_want_read(ssl)) { - bio = SSL_get_rbio(ssl); - if (BIO_should_read(bio)) { - return SSL_ERROR_WANT_READ; - } - - if (BIO_should_write(bio)) { - /* This one doesn't make too much sense ... We never try to write to the - * rbio, and an application program where rbio and wbio are separate - * couldn't even know what it should wait for. However if we ever set - * s->rwstate incorrectly (so that we have SSL_want_read(s) instead of - * SSL_want_write(s)) and rbio and wbio *are* the same, this test works - * around that bug; so it might be safer to keep it. */ - return SSL_ERROR_WANT_WRITE; - } - - if (BIO_should_io_special(bio)) { - reason = BIO_get_retry_reason(bio); - if (reason == BIO_RR_CONNECT) { - return SSL_ERROR_WANT_CONNECT; - } - - if (reason == BIO_RR_ACCEPT) { - return SSL_ERROR_WANT_ACCEPT; - } - - return SSL_ERROR_SYSCALL; /* unknown */ - } - } - - if (SSL_want_write(ssl)) { - bio = SSL_get_wbio(ssl); - if (BIO_should_write(bio)) { - return SSL_ERROR_WANT_WRITE; - } - - if (BIO_should_read(bio)) { - /* See above (SSL_want_read(ssl) with BIO_should_write(bio)) */ - return SSL_ERROR_WANT_READ; - } - - if (BIO_should_io_special(bio)) { - reason = BIO_get_retry_reason(bio); - if (reason == BIO_RR_CONNECT) { - return SSL_ERROR_WANT_CONNECT; - } - - if (reason == BIO_RR_ACCEPT) { - return SSL_ERROR_WANT_ACCEPT; - } - - return SSL_ERROR_SYSCALL; - } - } - - if (SSL_want_x509_lookup(ssl)) { - return SSL_ERROR_WANT_X509_LOOKUP; - } - - if (SSL_want_channel_id_lookup(ssl)) { - return SSL_ERROR_WANT_CHANNEL_ID_LOOKUP; - } - - if (SSL_want_private_key_operation(ssl)) { - return SSL_ERROR_WANT_PRIVATE_KEY_OPERATION; - } - - return SSL_ERROR_SYSCALL; -} - -void SSL_CTX_set_min_version(SSL_CTX *ctx, uint16_t version) { - ctx->min_version = version; -} - -void SSL_CTX_set_max_version(SSL_CTX *ctx, uint16_t version) { - ctx->max_version = version; -} - -void SSL_set_min_version(SSL *ssl, uint16_t version) { - ssl->min_version = version; -} - -void SSL_set_max_version(SSL *ssl, uint16_t version) { - ssl->max_version = version; -} - -uint32_t SSL_CTX_set_options(SSL_CTX *ctx, uint32_t options) { - ctx->options |= options; - return ctx->options; -} - -uint32_t SSL_CTX_clear_options(SSL_CTX *ctx, uint32_t options) { - ctx->options &= ~options; - return ctx->options; -} - -uint32_t SSL_CTX_get_options(const SSL_CTX *ctx) { return ctx->options; } - -uint32_t SSL_set_options(SSL *ssl, uint32_t options) { - ssl->options |= options; - return ssl->options; -} - -uint32_t SSL_clear_options(SSL *ssl, uint32_t options) { - ssl->options &= ~options; - return ssl->options; -} - -uint32_t SSL_get_options(const SSL *ssl) { return ssl->options; } - -uint32_t SSL_CTX_set_mode(SSL_CTX *ctx, uint32_t mode) { - ctx->mode |= mode; - return ctx->mode; -} - -uint32_t SSL_CTX_clear_mode(SSL_CTX *ctx, uint32_t mode) { - ctx->mode &= ~mode; - return ctx->mode; -} - -uint32_t SSL_CTX_get_mode(const SSL_CTX *ctx) { return ctx->mode; } - -uint32_t SSL_set_mode(SSL *ssl, uint32_t mode) { - ssl->mode |= mode; - return ssl->mode; -} - -uint32_t SSL_clear_mode(SSL *ssl, uint32_t mode) { - ssl->mode &= ~mode; - return ssl->mode; -} - -uint32_t SSL_get_mode(const SSL *ssl) { return ssl->mode; } - -X509 *SSL_get_peer_certificate(const SSL *ssl) { - if (ssl == NULL || ssl->session == NULL || ssl->session->peer == NULL) { - return NULL; - } - return X509_up_ref(ssl->session->peer); -} - -STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *ssl) { - if (ssl == NULL || ssl->session == NULL) { - return NULL; - } - return ssl->session->cert_chain; -} - -int SSL_get_tls_unique(const SSL *ssl, uint8_t *out, size_t *out_len, - size_t max_out) { - /* The tls-unique value is the first Finished message in the handshake, which - * is the client's in a full handshake and the server's for a resumption. See - * https://tools.ietf.org/html/rfc5929#section-3.1. */ - const uint8_t *finished = ssl->s3->previous_client_finished; - size_t finished_len = ssl->s3->previous_client_finished_len; - if (ssl->hit) { - /* tls-unique is broken for resumed sessions unless EMS is used. */ - if (!ssl->session->extended_master_secret) { - goto err; - } - finished = ssl->s3->previous_server_finished; - finished_len = ssl->s3->previous_server_finished_len; - } - - if (!ssl->s3->initial_handshake_complete || - ssl->version < TLS1_VERSION) { - goto err; - } - - *out_len = finished_len; - if (finished_len > max_out) { - *out_len = max_out; - } - - memcpy(out, finished, *out_len); - return 1; - -err: - *out_len = 0; - memset(out, 0, max_out); - return 0; -} - int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const uint8_t *sid_ctx, - unsigned sid_ctx_len) { - if (sid_ctx_len > sizeof(ctx->sid_ctx)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); + unsigned int sid_ctx_len) { + if (sid_ctx_len > sizeof ctx->sid_ctx) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_set_session_id_context, + SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); return 0; } ctx->sid_ctx_length = sid_ctx_len; @@ -932,9 +377,10 @@ int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const uint8_t *sid_ctx, } int SSL_set_session_id_context(SSL *ssl, const uint8_t *sid_ctx, - unsigned sid_ctx_len) { + unsigned int sid_ctx_len) { if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); + OPENSSL_PUT_ERROR(SSL, SSL_set_session_id_context, + SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); return 0; } ssl->sid_ctx_length = sid_ctx_len; @@ -954,7 +400,7 @@ int SSL_set_generate_session_id(SSL *ssl, GEN_SESSION_CB cb) { } int SSL_has_matching_session_id(const SSL *ssl, const uint8_t *id, - unsigned id_len) { + unsigned int id_len) { /* A quick examination of SSL_SESSION_hash and SSL_SESSION_cmp shows how we * can "construct" a session to give us the desired check - ie. to find if * there's a session in the hash table that would conflict with any new @@ -976,28 +422,28 @@ int SSL_has_matching_session_id(const SSL *ssl, const uint8_t *id, return p != NULL; } -int SSL_CTX_set_purpose(SSL_CTX *ctx, int purpose) { - return X509_VERIFY_PARAM_set_purpose(ctx->param, purpose); +int SSL_CTX_set_purpose(SSL_CTX *s, int purpose) { + return X509_VERIFY_PARAM_set_purpose(s->param, purpose); } -int SSL_set_purpose(SSL *ssl, int purpose) { - return X509_VERIFY_PARAM_set_purpose(ssl->param, purpose); +int SSL_set_purpose(SSL *s, int purpose) { + return X509_VERIFY_PARAM_set_purpose(s->param, purpose); } -int SSL_CTX_set_trust(SSL_CTX *ctx, int trust) { - return X509_VERIFY_PARAM_set_trust(ctx->param, trust); +int SSL_CTX_set_trust(SSL_CTX *s, int trust) { + return X509_VERIFY_PARAM_set_trust(s->param, trust); } -int SSL_set_trust(SSL *ssl, int trust) { - return X509_VERIFY_PARAM_set_trust(ssl->param, trust); +int SSL_set_trust(SSL *s, int trust) { + return X509_VERIFY_PARAM_set_trust(s->param, trust); } -int SSL_CTX_set1_param(SSL_CTX *ctx, const X509_VERIFY_PARAM *param) { - return X509_VERIFY_PARAM_set1(ctx->param, param); +int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm) { + return X509_VERIFY_PARAM_set1(ctx->param, vpm); } -int SSL_set1_param(SSL *ssl, const X509_VERIFY_PARAM *param) { - return X509_VERIFY_PARAM_set1(ssl->param, param); +int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm) { + return X509_VERIFY_PARAM_set1(ssl->param, vpm); } void ssl_cipher_preference_list_free( @@ -1069,7 +515,86 @@ X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx) { return ctx->param; } X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl) { return ssl->param; } -void SSL_certs_clear(SSL *ssl) { ssl_cert_clear_certs(ssl->cert); } +void SSL_certs_clear(SSL *s) { ssl_cert_clear_certs(s->cert); } + +void SSL_free(SSL *ssl) { + if (ssl == NULL) { + return; + } + + X509_VERIFY_PARAM_free(ssl->param); + + 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; + } + + int free_wbio = ssl->wbio != ssl->rbio; + BIO_free_all(ssl->rbio); + if (free_wbio) { + BIO_free_all(ssl->wbio); + } + + BUF_MEM_free(ssl->init_buf); + + /* add extra stuff */ + ssl_cipher_preference_list_free(ssl->cipher_list); + sk_SSL_CIPHER_free(ssl->cipher_list_by_id); + + ssl_clear_bad_session(ssl); + SSL_SESSION_free(ssl->session); + + ssl_clear_cipher_ctx(ssl); + + ssl_cert_free(ssl->cert); + + OPENSSL_free(ssl->tlsext_hostname); + SSL_CTX_free(ssl->initial_ctx); + OPENSSL_free(ssl->tlsext_ecpointformatlist); + OPENSSL_free(ssl->tlsext_ellipticcurvelist); + OPENSSL_free(ssl->alpn_client_proto_list); + EVP_PKEY_free(ssl->tlsext_channel_id_private); + OPENSSL_free(ssl->psk_identity_hint); + sk_X509_NAME_pop_free(ssl->client_CA, X509_NAME_free); + OPENSSL_free(ssl->next_proto_negotiated); + sk_SRTP_PROTECTION_PROFILE_free(ssl->srtp_profiles); + + if (ssl->method != NULL) { + ssl->method->ssl_free(ssl); + } + SSL_CTX_free(ssl->ctx); + + OPENSSL_free(ssl); +} + +void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio) { + /* If the output buffering BIO is still in place, remove it. */ + if (s->bbio != NULL) { + if (s->wbio == s->bbio) { + s->wbio = s->wbio->next_bio; + s->bbio->next_bio = NULL; + } + } + + if (s->rbio != rbio) { + BIO_free_all(s->rbio); + } + if (s->wbio != wbio && s->rbio != s->wbio) { + BIO_free_all(s->wbio); + } + s->rbio = rbio; + s->wbio = wbio; +} + +BIO *SSL_get_rbio(const SSL *s) { return s->rbio; } + +BIO *SSL_get_wbio(const SSL *s) { return s->wbio; } int SSL_get_fd(const SSL *s) { return SSL_get_rfd(s); } @@ -1105,7 +630,7 @@ int SSL_set_fd(SSL *s, int fd) { bio = BIO_new(BIO_s_fd()); if (bio == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); + OPENSSL_PUT_ERROR(SSL, SSL_set_fd, ERR_R_BUF_LIB); goto err; } BIO_set_fd(bio, fd, BIO_NOCLOSE); @@ -1125,7 +650,7 @@ int SSL_set_wfd(SSL *s, int fd) { bio = BIO_new(BIO_s_fd()); if (bio == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); + OPENSSL_PUT_ERROR(SSL, SSL_set_wfd, ERR_R_BUF_LIB); goto err; } BIO_set_fd(bio, fd, BIO_NOCLOSE); @@ -1149,7 +674,7 @@ int SSL_set_rfd(SSL *s, int fd) { bio = BIO_new(BIO_s_fd()); if (bio == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); + OPENSSL_PUT_ERROR(SSL, SSL_set_rfd, ERR_R_BUF_LIB); goto err; } BIO_set_fd(bio, fd, BIO_NOCLOSE); @@ -1193,18 +718,14 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count) { return ret; } -int SSL_get_verify_mode(const SSL *ssl) { return ssl->verify_mode; } - -int SSL_get_verify_depth(const SSL *ssl) { - return X509_VERIFY_PARAM_get_depth(ssl->param); -} +int SSL_get_verify_mode(const SSL *s) { return s->verify_mode; } -int SSL_get_extms_support(const SSL *ssl) { - return ssl->s3->tmp.extended_master_secret == 1; +int SSL_get_verify_depth(const SSL *s) { + return X509_VERIFY_PARAM_get_depth(s->param); } -int (*SSL_get_verify_callback(const SSL *ssl))(int, X509_STORE_CTX *) { - return ssl->verify_callback; +int (*SSL_get_verify_callback(const SSL *s))(int, X509_STORE_CTX *) { + return s->verify_callback; } int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) { return ctx->verify_mode; } @@ -1213,21 +734,20 @@ int SSL_CTX_get_verify_depth(const SSL_CTX *ctx) { return X509_VERIFY_PARAM_get_depth(ctx->param); } -int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))( - int ok, X509_STORE_CTX *store_ctx) { +int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))(int, X509_STORE_CTX *) { return ctx->default_verify_callback; } -void SSL_set_verify(SSL *ssl, int mode, - int (*callback)(int ok, X509_STORE_CTX *store_ctx)) { - ssl->verify_mode = mode; +void SSL_set_verify(SSL *s, int mode, + int (*callback)(int ok, X509_STORE_CTX *ctx)) { + s->verify_mode = mode; if (callback != NULL) { - ssl->verify_callback = callback; + s->verify_callback = callback; } } -void SSL_set_verify_depth(SSL *ssl, int depth) { - X509_VERIFY_PARAM_set_depth(ssl->param, depth); +void SSL_set_verify_depth(SSL *s, int depth) { + X509_VERIFY_PARAM_set_depth(s->param, depth); } int SSL_CTX_get_read_ahead(const SSL_CTX *ctx) { return 0; } @@ -1239,47 +759,226 @@ void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes) { } void SSL_set_read_ahead(SSL *s, int yes) { } int SSL_pending(const SSL *s) { + if (s->rstate == SSL_ST_READ_BODY) { + return 0; + } + return (s->s3->rrec.type == SSL3_RT_APPLICATION_DATA) ? s->s3->rrec.length : 0; } +X509 *SSL_get_peer_certificate(const SSL *s) { + X509 *r; + + if (s == NULL || s->session == NULL) { + r = NULL; + } else { + r = s->session->peer; + } + + if (r == NULL) { + return NULL; + } + + return X509_up_ref(r); +} + +STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s) { + STACK_OF(X509) *r; + + if (s == NULL || s->session == NULL || s->session->sess_cert == NULL) { + r = NULL; + } else { + r = s->session->sess_cert->cert_chain; + } + + /* If we are a client, cert_chain includes the peer's own certificate; if we + * are a server, it does not. */ + return r; +} + /* Fix this so it checks all the valid key/cert options */ int SSL_CTX_check_private_key(const SSL_CTX *ctx) { - if (ctx->cert->x509 == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED); + if (ctx == NULL || ctx->cert == NULL || ctx->cert->key->x509 == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_check_private_key, + SSL_R_NO_CERTIFICATE_ASSIGNED); return 0; } - if (ctx->cert->privatekey == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED); + if (ctx->cert->key->privatekey == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_check_private_key, + SSL_R_NO_PRIVATE_KEY_ASSIGNED); return 0; } - return X509_check_private_key(ctx->cert->x509, ctx->cert->privatekey); + return X509_check_private_key(ctx->cert->key->x509, + ctx->cert->key->privatekey); } /* Fix this function so that it takes an optional type parameter */ int SSL_check_private_key(const SSL *ssl) { - if (ssl->cert->x509 == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED); + if (ssl == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_check_private_key, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (ssl->cert == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_check_private_key, + SSL_R_NO_CERTIFICATE_ASSIGNED); + return 0; + } + + if (ssl->cert->key->x509 == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_check_private_key, + SSL_R_NO_CERTIFICATE_ASSIGNED); return 0; } - if (ssl->cert->privatekey == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED); + if (ssl->cert->key->privatekey == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_check_private_key, + SSL_R_NO_PRIVATE_KEY_ASSIGNED); return 0; } - return X509_check_private_key(ssl->cert->x509, ssl->cert->privatekey); + return X509_check_private_key(ssl->cert->key->x509, + ssl->cert->key->privatekey); +} + +int SSL_accept(SSL *s) { + if (s->handshake_func == 0) { + /* Not properly initialized yet */ + SSL_set_accept_state(s); + } + + if (s->handshake_func != s->method->ssl_accept) { + OPENSSL_PUT_ERROR(SSL, SSL_accept, ERR_R_INTERNAL_ERROR); + return -1; + } + + return s->handshake_func(s); +} + +int SSL_connect(SSL *s) { + if (s->handshake_func == 0) { + /* Not properly initialized yet */ + SSL_set_connect_state(s); + } + + if (s->handshake_func != s->method->ssl_connect) { + OPENSSL_PUT_ERROR(SSL, SSL_connect, ERR_R_INTERNAL_ERROR); + return -1; + } + + return s->handshake_func(s); } -long SSL_get_default_timeout(const SSL *ssl) { +long SSL_get_default_timeout(const SSL *s) { return SSL_DEFAULT_SESSION_TIMEOUT; } +int SSL_read(SSL *s, void *buf, int num) { + if (s->handshake_func == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_read, SSL_R_UNINITIALIZED); + return -1; + } + + if (s->shutdown & SSL_RECEIVED_SHUTDOWN) { + s->rwstate = SSL_NOTHING; + return 0; + } + + ERR_clear_system_error(); + return s->method->ssl_read_app_data(s, buf, num, 0); +} + +int SSL_peek(SSL *s, void *buf, int num) { + if (s->handshake_func == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_peek, SSL_R_UNINITIALIZED); + return -1; + } + + if (s->shutdown & SSL_RECEIVED_SHUTDOWN) { + return 0; + } + + ERR_clear_system_error(); + return s->method->ssl_read_app_data(s, buf, num, 1); +} + +int SSL_write(SSL *s, const void *buf, int num) { + if (s->handshake_func == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_write, SSL_R_UNINITIALIZED); + return -1; + } + + if (s->shutdown & SSL_SENT_SHUTDOWN) { + s->rwstate = SSL_NOTHING; + OPENSSL_PUT_ERROR(SSL, SSL_write, SSL_R_PROTOCOL_IS_SHUTDOWN); + return -1; + } + + ERR_clear_system_error(); + return s->method->ssl_write_app_data(s, buf, num); +} + +int SSL_shutdown(SSL *s) { + /* 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 (s->handshake_func == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_shutdown, SSL_R_UNINITIALIZED); + return -1; + } + + if (SSL_in_init(s)) { + return 1; + } + + /* Do nothing if configured not to send a close_notify. */ + if (s->quiet_shutdown) { + s->shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN; + return 1; + } + + if (!(s->shutdown & SSL_SENT_SHUTDOWN)) { + s->shutdown |= SSL_SENT_SHUTDOWN; + ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_CLOSE_NOTIFY); + + /* our shutdown alert has been sent now, and if it still needs to be + * written, s->s3->alert_dispatch will be true */ + if (s->s3->alert_dispatch) { + return -1; /* return WANT_WRITE */ + } + } else if (s->s3->alert_dispatch) { + /* resend it if not sent */ + int ret = s->method->ssl_dispatch_alert(s); + 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; + } + } else if (!(s->shutdown & SSL_RECEIVED_SHUTDOWN)) { + /* If we are waiting for a close from our peer, we are closed */ + s->method->ssl_read_close_notify(s); + if (!(s->shutdown & SSL_RECEIVED_SHUTDOWN)) { + return -1; /* return WANT_READ */ + } + } + + if (s->shutdown == (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN) && + !s->s3->alert_dispatch) { + return 1; + } else { + return 0; + } +} + int SSL_renegotiate(SSL *ssl) { /* Caller-initiated renegotiation is not supported. */ - OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + OPENSSL_PUT_ERROR(SSL, SSL_renegotiate, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } @@ -1287,6 +986,54 @@ int SSL_renegotiate_pending(SSL *ssl) { return SSL_in_init(ssl) && ssl->s3->initial_handshake_complete; } +uint32_t SSL_CTX_set_options(SSL_CTX *ctx, uint32_t options) { + ctx->options |= options; + return ctx->options; +} + +uint32_t SSL_set_options(SSL *ssl, uint32_t options) { + ssl->options |= options; + return ssl->options; +} + +uint32_t SSL_CTX_clear_options(SSL_CTX *ctx, uint32_t options) { + ctx->options &= ~options; + return ctx->options; +} + +uint32_t SSL_clear_options(SSL *ssl, uint32_t options) { + ssl->options &= ~options; + return ssl->options; +} + +uint32_t SSL_CTX_get_options(const SSL_CTX *ctx) { return ctx->options; } + +uint32_t SSL_get_options(const SSL *ssl) { return ssl->options; } + +uint32_t SSL_CTX_set_mode(SSL_CTX *ctx, uint32_t mode) { + ctx->mode |= mode; + return ctx->mode; +} + +uint32_t SSL_set_mode(SSL *ssl, uint32_t mode) { + ssl->mode |= mode; + return ssl->mode; +} + +uint32_t SSL_CTX_clear_mode(SSL_CTX *ctx, uint32_t mode) { + ctx->mode &= ~mode; + return ctx->mode; +} + +uint32_t SSL_clear_mode(SSL *ssl, uint32_t mode) { + ssl->mode &= ~mode; + return ssl->mode; +} + +uint32_t SSL_CTX_get_mode(const SSL_CTX *ctx) { return ctx->mode; } + +uint32_t SSL_get_mode(const SSL *ssl) { return ssl->mode; } + size_t SSL_CTX_get_max_cert_list(const SSL_CTX *ctx) { return ctx->max_cert_list; } @@ -1341,6 +1088,10 @@ int SSL_get_secure_renegotiation_support(const SSL *ssl) { return ssl->s3->send_connection_binding; } +long SSL_ctrl(SSL *s, int cmd, long larg, void *parg) { + return s->method->ssl_ctrl(s, cmd, larg, parg); +} + LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx) { return ctx->sessions; } size_t SSL_CTX_sess_number(const SSL_CTX *ctx) { @@ -1367,6 +1118,10 @@ int SSL_CTX_get_session_cache_mode(const SSL_CTX *ctx) { return ctx->session_cache_mode; } +long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) { + return ctx->method->ssl_ctx_ctrl(ctx, cmd, larg, parg); +} + /* return a STACK of the ciphers available for the SSL and in order of * preference */ STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s) { @@ -1383,11 +1138,6 @@ STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s) { return s->ctx->cipher_list_tls11->ciphers; } - if (s->version >= TLS1_VERSION && s->ctx != NULL && - s->ctx->cipher_list_tls10 != NULL) { - return s->ctx->cipher_list_tls10->ciphers; - } - if (s->ctx != NULL && s->ctx->cipher_list != NULL) { return s->ctx->cipher_list->ciphers; } @@ -1449,21 +1199,7 @@ int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) { if (sk == NULL) { return 0; } else if (sk_SSL_CIPHER_num(sk) == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH); - return 0; - } - - return 1; -} - -int SSL_CTX_set_cipher_list_tls10(SSL_CTX *ctx, const char *str) { - STACK_OF(SSL_CIPHER) *sk; - - sk = ssl_create_cipher_list(ctx->method, &ctx->cipher_list_tls10, NULL, str); - if (sk == NULL) { - return 0; - } else if (sk_SSL_CIPHER_num(sk) == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH); + OPENSSL_PUT_ERROR(SSL, SSL_CTX_set_cipher_list, SSL_R_NO_CIPHER_MATCH); return 0; } @@ -1477,7 +1213,8 @@ int SSL_CTX_set_cipher_list_tls11(SSL_CTX *ctx, const char *str) { if (sk == NULL) { return 0; } else if (sk_SSL_CIPHER_num(sk) == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH); + OPENSSL_PUT_ERROR(SSL, SSL_CTX_set_cipher_list_tls11, + SSL_R_NO_CIPHER_MATCH); return 0; } @@ -1495,7 +1232,7 @@ int SSL_set_cipher_list(SSL *s, const char *str) { if (sk == NULL) { return 0; } else if (sk_SSL_CIPHER_num(sk) == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH); + OPENSSL_PUT_ERROR(SSL, SSL_set_cipher_list, SSL_R_NO_CIPHER_MATCH); return 0; } @@ -1531,13 +1268,9 @@ int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, uint8_t *p) { return 0; } - /* For SSLv3, the SCSV is added. Otherwise the renegotiation extension is - * added. */ - if (s->client_version == SSL3_VERSION && - !s->s3->initial_handshake_complete) { + /* Add SCSVs. */ + if (!s->s3->initial_handshake_complete) { s2n(SSL3_CK_SCSV & 0xffff, p); - /* The renegotiation extension is required to be at index zero. */ - s->s3->tmp.extensions.sent |= (1u << 0); } if (s->mode & SSL_MODE_SEND_FALLBACK_SCSV) { @@ -1557,13 +1290,14 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) { } if (CBS_len(&cipher_suites) % 2 != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST); + OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, + SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST); return NULL; } sk = sk_SSL_CIPHER_new_null(); if (sk == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, ERR_R_MALLOC_FAILURE); goto err; } @@ -1571,7 +1305,7 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) { uint16_t cipher_suite; if (!CBS_get_u16(&cipher_suites, &cipher_suite)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, ERR_R_INTERNAL_ERROR); goto err; } @@ -1579,7 +1313,8 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) { if (s->s3 && cipher_suite == (SSL3_CK_SCSV & 0xffff)) { /* SCSV is fatal if renegotiating. */ if (s->s3->initial_handshake_complete) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING); + OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, + SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING); ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); goto err; } @@ -1592,7 +1327,8 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) { uint16_t max_version = ssl3_get_max_server_version(s); if (SSL_IS_DTLS(s) ? (uint16_t)s->version > max_version : (uint16_t)s->version < max_version) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INAPPROPRIATE_FALLBACK); + OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, + SSL_R_INAPPROPRIATE_FALLBACK); ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_INAPPROPRIATE_FALLBACK); goto err; } @@ -1601,7 +1337,7 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) { c = SSL_get_cipher_by_value(cipher_suite); if (c != NULL && !sk_SSL_CIPHER_push(sk, c)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, ERR_R_MALLOC_FAILURE); goto err; } } @@ -1679,37 +1415,39 @@ void SSL_get0_ocsp_response(const SSL *ssl, const uint8_t **out, *out_len = session->ocsp_response_length; } -int SSL_CTX_set_signed_cert_timestamp_list(SSL_CTX *ctx, const uint8_t *list, - size_t list_len) { - OPENSSL_free(ctx->signed_cert_timestamp_list); - ctx->signed_cert_timestamp_list_length = 0; - - ctx->signed_cert_timestamp_list = BUF_memdup(list, list_len); - if (ctx->signed_cert_timestamp_list == NULL) { - return 0; - } - ctx->signed_cert_timestamp_list_length = list_len; - - return 1; -} - -int SSL_CTX_set_ocsp_response(SSL_CTX *ctx, const uint8_t *response, - size_t response_len) { - OPENSSL_free(ctx->ocsp_response); - ctx->ocsp_response_length = 0; - - ctx->ocsp_response = BUF_memdup(response, response_len); - if (ctx->ocsp_response == NULL) { - return 0; - } - ctx->ocsp_response_length = response_len; - - return 1; -} - -int SSL_select_next_proto(uint8_t **out, uint8_t *out_len, - const uint8_t *server, unsigned server_len, - const uint8_t *client, unsigned client_len) { +/* SSL_select_next_proto implements the standard protocol selection. It is + * expected that this function is called from the callback set by + * SSL_CTX_set_next_proto_select_cb. + * + * The protocol data is assumed to be a vector of 8-bit, length prefixed byte + * strings. The length byte itself is not included in the length. A byte + * string of length 0 is invalid. No byte string may be truncated. + * + * The current, but experimental algorithm for selecting the protocol is: + * + * 1) If the server doesn't support NPN then this is indicated to the + * callback. In this case, the client application has to abort the connection + * or have a default application level protocol. + * + * 2) If the server supports NPN, but advertises an empty list then the + * client selects the first protcol in its list, but indicates via the + * API that this fallback case was enacted. + * + * 3) Otherwise, the client finds the first protocol in the server's list + * that it supports and selects this protocol. This is because it's + * assumed that the server has better information about which protocol + * a client should use. + * + * 4) If the client doesn't support any of the server's advertised + * protocols, then this is treated the same as case 2. + * + * It returns either + * OPENSSL_NPN_NEGOTIATED if a common protocol was found, or + * OPENSSL_NPN_NO_OVERLAP if the fallback case was reached. + */ +int SSL_select_next_proto(uint8_t **out, uint8_t *outlen, const uint8_t *server, + unsigned int server_len, const uint8_t *client, + unsigned int client_len) { unsigned int i, j; const uint8_t *result; int status = OPENSSL_NPN_UNSUPPORTED; @@ -1737,31 +1475,57 @@ int SSL_select_next_proto(uint8_t **out, uint8_t *out_len, found: *out = (uint8_t *)result + 1; - *out_len = result[0]; + *outlen = result[0]; return status; } -void SSL_get0_next_proto_negotiated(const SSL *ssl, const uint8_t **out_data, - unsigned *out_len) { - *out_data = ssl->next_proto_negotiated; - if (*out_data == NULL) { - *out_len = 0; +/* SSL_get0_next_proto_negotiated sets *data and *len to point to the client's + * requested protocol for this connection and returns 0. If the client didn't + * request any protocol, then *data is set to NULL. + * + * Note that the client can request any protocol it chooses. The value returned + * from this function need not be a member of the list of supported protocols + * provided by the callback. */ +void SSL_get0_next_proto_negotiated(const SSL *s, const uint8_t **data, + unsigned *len) { + *data = s->next_proto_negotiated; + if (!*data) { + *len = 0; } else { - *out_len = ssl->next_proto_negotiated_len; + *len = s->next_proto_negotiated_len; } } +/* SSL_CTX_set_next_protos_advertised_cb sets a callback that is called when a + * TLS server needs a list of supported protocols for Next Protocol + * Negotiation. The returned list must be in wire format. The list is returned + * by setting |out| to point to it and |outlen| to its length. This memory will + * not be modified, but one should assume that the SSL* keeps a reference to + * it. + * + * The callback should return SSL_TLSEXT_ERR_OK if it wishes to advertise. + * Otherwise, no such extension will be included in the ServerHello. */ void SSL_CTX_set_next_protos_advertised_cb( SSL_CTX *ctx, - int (*cb)(SSL *ssl, const uint8_t **out, unsigned *out_len, void *arg), + int (*cb)(SSL *ssl, const uint8_t **out, unsigned int *outlen, void *arg), void *arg) { ctx->next_protos_advertised_cb = cb; ctx->next_protos_advertised_cb_arg = arg; } +/* SSL_CTX_set_next_proto_select_cb sets a callback that is called when a + * client needs to select a protocol from the server's provided list. |out| + * must be set to point to the selected protocol (which may be within |in|). + * The length of the protocol name must be written into |outlen|. The server's + * advertised protocols are provided in |in| and |inlen|. The callback can + * assume that |in| is syntactically valid. + * + * The client must select a protocol. It is fatal to the connection if this + * callback returns a value other than SSL_TLSEXT_ERR_OK. + */ void SSL_CTX_set_next_proto_select_cb( - SSL_CTX *ctx, int (*cb)(SSL *ssl, uint8_t **out, uint8_t *out_len, - const uint8_t *in, unsigned in_len, void *arg), + SSL_CTX *ctx, int (*cb)(SSL *s, uint8_t **out, uint8_t *outlen, + const uint8_t *in, unsigned int inlen, void *arg), void *arg) { ctx->next_proto_select_cb = cb; ctx->next_proto_select_cb_arg = arg; @@ -1790,25 +1554,32 @@ int SSL_set_alpn_protos(SSL *ssl, const uint8_t *protos, unsigned protos_len) { return 0; } +/* SSL_CTX_set_alpn_select_cb sets a callback function on |ctx| that is called + * during ClientHello processing in order to select an ALPN protocol from the + * client's list of offered protocols. */ void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, const uint8_t **out, - uint8_t *out_len, const uint8_t *in, - unsigned in_len, void *arg), + uint8_t *outlen, const uint8_t *in, + unsigned int inlen, void *arg), void *arg) { ctx->alpn_select_cb = cb; ctx->alpn_select_cb_arg = arg; } -void SSL_get0_alpn_selected(const SSL *ssl, const uint8_t **out_data, - unsigned *out_len) { - *out_data = NULL; +/* SSL_get0_alpn_selected gets the selected ALPN protocol (if any) from |ssl|. + * On return it sets |*data| to point to |*len| bytes of protocol name (not + * including the leading length-prefix byte). If the server didn't respond with + * a negotiated protocol then |*len| will be zero. */ +void SSL_get0_alpn_selected(const SSL *ssl, const uint8_t **data, + unsigned *len) { + *data = NULL; if (ssl->s3) { - *out_data = ssl->s3->alpn_selected; + *data = ssl->s3->alpn_selected; } - if (*out_data == NULL) { - *out_len = 0; + if (*data == NULL) { + *len = 0; } else { - *out_len = ssl->s3->alpn_selected_len; + *len = ssl->s3->alpn_selected_len; } } @@ -1824,9 +1595,210 @@ int SSL_export_keying_material(SSL *s, uint8_t *out, size_t out_len, s, out, out_len, label, label_len, context, context_len, use_context); } +static uint32_t ssl_session_hash(const SSL_SESSION *a) { + uint32_t hash = + ((uint32_t)a->session_id[0]) || + ((uint32_t)a->session_id[1] << 8) || + ((uint32_t)a->session_id[2] << 16) || + ((uint32_t)a->session_id[3] << 24); + + return hash; +} + +/* NB: If this function (or indeed the hash function which uses a sort of + * coarser function than this one) is changed, ensure + * SSL_CTX_has_matching_session_id() is checked accordingly. It relies on being + * able to construct an SSL_SESSION that will collide with any existing session + * with a matching session ID. */ +static int ssl_session_cmp(const SSL_SESSION *a, const SSL_SESSION *b) { + if (a->ssl_version != b->ssl_version) { + return 1; + } + + if (a->session_id_length != b->session_id_length) { + return 1; + } + + return memcmp(a->session_id, b->session_id, a->session_id_length); +} + +SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) { + SSL_CTX *ret = NULL; + + if (method == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_new, SSL_R_NULL_SSL_METHOD_PASSED); + return NULL; + } + + if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_new, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS); + goto err; + } + + ret = (SSL_CTX *)OPENSSL_malloc(sizeof(SSL_CTX)); + if (ret == NULL) { + goto err; + } + + memset(ret, 0, sizeof(SSL_CTX)); + + ret->method = method->method; + + CRYPTO_MUTEX_init(&ret->lock); + + ret->cert_store = NULL; + ret->session_cache_mode = SSL_SESS_CACHE_SERVER; + ret->session_cache_size = SSL_SESSION_CACHE_MAX_SIZE_DEFAULT; + ret->session_cache_head = NULL; + ret->session_cache_tail = NULL; + + /* We take the system default */ + ret->session_timeout = SSL_DEFAULT_SESSION_TIMEOUT; + + ret->new_session_cb = 0; + ret->remove_session_cb = 0; + ret->get_session_cb = 0; + ret->generate_session_id = 0; + + ret->references = 1; + ret->quiet_shutdown = 0; + + ret->info_callback = NULL; + + ret->app_verify_callback = 0; + ret->app_verify_arg = NULL; + + ret->max_cert_list = SSL_MAX_CERT_LIST_DEFAULT; + ret->msg_callback = 0; + ret->msg_callback_arg = NULL; + ret->verify_mode = SSL_VERIFY_NONE; + ret->sid_ctx_length = 0; + ret->default_verify_callback = NULL; + ret->cert = ssl_cert_new(); + if (ret->cert == NULL) { + goto err; + } + + ret->default_passwd_callback = 0; + ret->default_passwd_callback_userdata = NULL; + ret->client_cert_cb = 0; + + ret->sessions = lh_SSL_SESSION_new(ssl_session_hash, ssl_session_cmp); + if (ret->sessions == NULL) { + goto err; + } + ret->cert_store = X509_STORE_new(); + if (ret->cert_store == NULL) { + goto err; + } + + ssl_create_cipher_list(ret->method, &ret->cipher_list, + &ret->cipher_list_by_id, SSL_DEFAULT_CIPHER_LIST); + if (ret->cipher_list == NULL || + sk_SSL_CIPHER_num(ret->cipher_list->ciphers) <= 0) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_new, SSL_R_LIBRARY_HAS_NO_CIPHERS); + goto err2; + } + + ret->param = X509_VERIFY_PARAM_new(); + if (!ret->param) { + goto err; + } + + ret->client_CA = sk_X509_NAME_new_null(); + if (ret->client_CA == NULL) { + goto err; + } + + CRYPTO_new_ex_data(&g_ex_data_class_ssl_ctx, ret, &ret->ex_data); + + ret->extra_certs = NULL; + + ret->max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH; + + ret->tlsext_servername_callback = 0; + ret->tlsext_servername_arg = NULL; + /* Setup RFC4507 ticket keys */ + if (!RAND_bytes(ret->tlsext_tick_key_name, 16) || + !RAND_bytes(ret->tlsext_tick_hmac_key, 16) || + !RAND_bytes(ret->tlsext_tick_aes_key, 16)) { + ret->options |= SSL_OP_NO_TICKET; + } + + ret->next_protos_advertised_cb = 0; + ret->next_proto_select_cb = 0; + ret->psk_identity_hint = NULL; + ret->psk_client_callback = NULL; + ret->psk_server_callback = NULL; + + /* Default is to connect to non-RI servers. When RI is more widely deployed + * might change this. */ + ret->options |= SSL_OP_LEGACY_SERVER_CONNECT; + + /* Lock the SSL_CTX to the specified version, for compatibility with legacy + * uses of SSL_METHOD. */ + if (method->version != 0) { + SSL_CTX_set_max_version(ret, method->version); + SSL_CTX_set_min_version(ret, method->version); + } + + return ret; + +err: + OPENSSL_PUT_ERROR(SSL, SSL_CTX_new, ERR_R_MALLOC_FAILURE); +err2: + SSL_CTX_free(ret); + return NULL; +} + +void SSL_CTX_free(SSL_CTX *ctx) { + if (ctx == NULL || + !CRYPTO_refcount_dec_and_test_zero(&ctx->references)) { + return; + } + + X509_VERIFY_PARAM_free(ctx->param); + + /* Free internal session cache. However: the remove_cb() may reference the + * ex_data of SSL_CTX, thus the ex_data store can only be removed after the + * sessions were flushed. As the ex_data handling routines might also touch + * the session cache, the most secure solution seems to be: empty (flush) the + * cache, then free ex_data, then finally free the cache. (See ticket + * [openssl.org #212].) */ + SSL_CTX_flush_sessions(ctx, 0); + + CRYPTO_free_ex_data(&g_ex_data_class_ssl_ctx, ctx, &ctx->ex_data); + + CRYPTO_MUTEX_cleanup(&ctx->lock); + lh_SSL_SESSION_free(ctx->sessions); + X509_STORE_free(ctx->cert_store); + ssl_cipher_preference_list_free(ctx->cipher_list); + sk_SSL_CIPHER_free(ctx->cipher_list_by_id); + ssl_cipher_preference_list_free(ctx->cipher_list_tls11); + ssl_cert_free(ctx->cert); + sk_X509_NAME_pop_free(ctx->client_CA, X509_NAME_free); + sk_X509_pop_free(ctx->extra_certs, X509_free); + sk_SRTP_PROTECTION_PROFILE_free(ctx->srtp_profiles); + OPENSSL_free(ctx->psk_identity_hint); + OPENSSL_free(ctx->tlsext_ecpointformatlist); + OPENSSL_free(ctx->tlsext_ellipticcurvelist); + OPENSSL_free(ctx->alpn_client_proto_list); + EVP_PKEY_free(ctx->tlsext_channel_id_private); + BIO_free(ctx->keylog_bio); + + OPENSSL_free(ctx); +} + +void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb) { + ctx->default_passwd_callback = cb; +} + +void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u) { + ctx->default_passwd_callback_userdata = u; +} + void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, - int (*cb)(X509_STORE_CTX *store_ctx, - void *arg), + int (*cb)(X509_STORE_CTX *, void *), void *arg) { ctx->app_verify_callback = cb; ctx->app_verify_arg = arg; @@ -1842,48 +1814,57 @@ void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) { X509_VERIFY_PARAM_set_depth(ctx->param, depth); } -void SSL_CTX_set_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, void *arg), +void SSL_CTX_set_cert_cb(SSL_CTX *c, int (*cb)(SSL *ssl, void *arg), void *arg) { - ssl_cert_set_cert_cb(ctx->cert, cb, arg); + ssl_cert_set_cert_cb(c->cert, cb, arg); } -void SSL_set_cert_cb(SSL *ssl, int (*cb)(SSL *ssl, void *arg), void *arg) { - ssl_cert_set_cert_cb(ssl->cert, cb, arg); +void SSL_set_cert_cb(SSL *s, int (*cb)(SSL *ssl, void *arg), void *arg) { + ssl_cert_set_cert_cb(s->cert, cb, arg); +} + +static int ssl_has_key(SSL *s, size_t idx) { + CERT_PKEY *cpk = &s->cert->pkeys[idx]; + return cpk->x509 && cpk->privatekey; } void ssl_get_compatible_server_ciphers(SSL *s, uint32_t *out_mask_k, uint32_t *out_mask_a) { CERT *c = s->cert; - int have_rsa_cert = 0, dh_tmp; + int rsa_enc, rsa_sign, dh_tmp; uint32_t mask_k, mask_a; - int have_ecc_cert = 0, ecdsa_ok; + int have_ecc_cert, ecdsa_ok; X509 *x; - dh_tmp = (c->dh_tmp != NULL || c->dh_tmp_cb != NULL); - - if (s->cert->x509 != NULL && ssl_has_private_key(s)) { - if (ssl_private_key_type(s) == EVP_PKEY_RSA) { - have_rsa_cert = 1; - } else if (ssl_private_key_type(s) == EVP_PKEY_EC) { - have_ecc_cert = 1; - } + if (c == NULL) { + /* TODO(davidben): Is this codepath possible? */ + *out_mask_k = 0; + *out_mask_a = 0; + return; } + dh_tmp = (c->dh_tmp != NULL || c->dh_tmp_cb != NULL); + + rsa_enc = ssl_has_key(s, SSL_PKEY_RSA_ENC); + rsa_sign = ssl_has_key(s, SSL_PKEY_RSA_SIGN); + have_ecc_cert = ssl_has_key(s, SSL_PKEY_ECC); mask_k = 0; mask_a = 0; + if (rsa_enc) { + mask_k |= SSL_kRSA; + } if (dh_tmp) { mask_k |= SSL_kDHE; } - if (have_rsa_cert) { - mask_k |= SSL_kRSA; + if (rsa_enc || rsa_sign) { mask_a |= SSL_aRSA; } /* An ECC certificate may be usable for ECDSA cipher suites depending on the * key usage extension and on the client's curve preferences. */ if (have_ecc_cert) { - x = c->x509; + x = c->pkeys[SSL_PKEY_ECC].x509; /* This call populates extension flags (ex_flags). */ X509_check_purpose(x, -1, 0); ecdsa_ok = (x->ex_flags & EXFLAG_KUSAGE) @@ -1913,6 +1894,81 @@ void ssl_get_compatible_server_ciphers(SSL *s, uint32_t *out_mask_k, *out_mask_a = mask_a; } +/* This handy macro borrowed from crypto/x509v3/v3_purp.c */ +#define ku_reject(x, usage) \ + (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage))) + +int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s) { + const SSL_CIPHER *cs = s->s3->tmp.new_cipher; + uint32_t alg_a = cs->algorithm_auth; + int signature_nid = 0, md_nid = 0, pk_nid = 0; + + /* This call populates the ex_flags field correctly */ + X509_check_purpose(x, -1, 0); + if (x->sig_alg && x->sig_alg->algorithm) { + signature_nid = OBJ_obj2nid(x->sig_alg->algorithm); + OBJ_find_sigid_algs(signature_nid, &md_nid, &pk_nid); + } + if (alg_a & SSL_aECDSA) { + /* key usage, if present, must allow signing */ + if (ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE)) { + OPENSSL_PUT_ERROR(SSL, ssl_check_srvr_ecc_cert_and_alg, + SSL_R_ECC_CERT_NOT_FOR_SIGNING); + return 0; + } + } + + return 1; /* all checks are ok */ +} + +static int ssl_get_server_cert_index(const SSL *s) { + int idx; + idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher); + if (idx == SSL_PKEY_RSA_ENC && !s->cert->pkeys[SSL_PKEY_RSA_ENC].x509) { + idx = SSL_PKEY_RSA_SIGN; + } + if (idx == -1) { + OPENSSL_PUT_ERROR(SSL, ssl_get_server_cert_index, ERR_R_INTERNAL_ERROR); + } + return idx; +} + +CERT_PKEY *ssl_get_server_send_pkey(const SSL *s) { + int i = ssl_get_server_cert_index(s); + + /* This may or may not be an error. */ + if (i < 0) { + return NULL; + } + + /* May be NULL. */ + return &s->cert->pkeys[i]; +} + +EVP_PKEY *ssl_get_sign_pkey(SSL *s, const SSL_CIPHER *cipher) { + uint32_t alg_a = cipher->algorithm_auth; + CERT *c = s->cert; + int idx = -1; + + if (alg_a & SSL_aRSA) { + if (c->pkeys[SSL_PKEY_RSA_SIGN].privatekey != NULL) { + idx = SSL_PKEY_RSA_SIGN; + } else if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey != NULL) { + idx = SSL_PKEY_RSA_ENC; + } + } else if ((alg_a & SSL_aECDSA) && + (c->pkeys[SSL_PKEY_ECC].privatekey != NULL)) { + idx = SSL_PKEY_ECC; + } + + if (idx == -1) { + OPENSSL_PUT_ERROR(SSL, ssl_get_sign_pkey, ERR_R_INTERNAL_ERROR); + return NULL; + } + + return c->pkeys[idx].privatekey; +} + void ssl_update_cache(SSL *s, int mode) { /* Never cache sessions with empty session IDs. */ if (s->session->session_id_length == 0) { @@ -1958,6 +2014,143 @@ void ssl_update_cache(SSL *s, int mode) { } } +int SSL_get_error(const SSL *s, int ret_code) { + int reason; + uint32_t err; + BIO *bio; + + if (ret_code > 0) { + return SSL_ERROR_NONE; + } + + /* Make things return SSL_ERROR_SYSCALL when doing SSL_do_handshake etc, + * where we do encode the error */ + err = ERR_peek_error(); + if (err != 0) { + if (ERR_GET_LIB(err) == ERR_LIB_SYS) { + return SSL_ERROR_SYSCALL; + } + return SSL_ERROR_SSL; + } + + if (ret_code == 0) { + if ((s->shutdown & SSL_RECEIVED_SHUTDOWN) && + (s->s3->warn_alert == SSL_AD_CLOSE_NOTIFY)) { + /* The socket was cleanly shut down with a close_notify. */ + return SSL_ERROR_ZERO_RETURN; + } + /* An EOF was observed which violates the protocol, and the underlying + * transport does not participate in the error queue. Bubble up to the + * caller. */ + return SSL_ERROR_SYSCALL; + } + + if (SSL_want_session(s)) { + return SSL_ERROR_PENDING_SESSION; + } + + if (SSL_want_certificate(s)) { + return SSL_ERROR_PENDING_CERTIFICATE; + } + + if (SSL_want_read(s)) { + bio = SSL_get_rbio(s); + if (BIO_should_read(bio)) { + return SSL_ERROR_WANT_READ; + } + + if (BIO_should_write(bio)) { + /* This one doesn't make too much sense ... We never try to write to the + * rbio, and an application program where rbio and wbio are separate + * couldn't even know what it should wait for. However if we ever set + * s->rwstate incorrectly (so that we have SSL_want_read(s) instead of + * SSL_want_write(s)) and rbio and wbio *are* the same, this test works + * around that bug; so it might be safer to keep it. */ + return SSL_ERROR_WANT_WRITE; + } + + if (BIO_should_io_special(bio)) { + reason = BIO_get_retry_reason(bio); + if (reason == BIO_RR_CONNECT) { + return SSL_ERROR_WANT_CONNECT; + } + + if (reason == BIO_RR_ACCEPT) { + return SSL_ERROR_WANT_ACCEPT; + } + + return SSL_ERROR_SYSCALL; /* unknown */ + } + } + + if (SSL_want_write(s)) { + bio = SSL_get_wbio(s); + if (BIO_should_write(bio)) { + return SSL_ERROR_WANT_WRITE; + } + + if (BIO_should_read(bio)) { + /* See above (SSL_want_read(s) with BIO_should_write(bio)) */ + return SSL_ERROR_WANT_READ; + } + + if (BIO_should_io_special(bio)) { + reason = BIO_get_retry_reason(bio); + if (reason == BIO_RR_CONNECT) { + return SSL_ERROR_WANT_CONNECT; + } + + if (reason == BIO_RR_ACCEPT) { + return SSL_ERROR_WANT_ACCEPT; + } + + return SSL_ERROR_SYSCALL; + } + } + + if (SSL_want_x509_lookup(s)) { + return SSL_ERROR_WANT_X509_LOOKUP; + } + + if (SSL_want_channel_id_lookup(s)) { + return SSL_ERROR_WANT_CHANNEL_ID_LOOKUP; + } + + return SSL_ERROR_SYSCALL; +} + +int SSL_do_handshake(SSL *s) { + int ret = 1; + + if (s->handshake_func == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_do_handshake, SSL_R_CONNECTION_TYPE_NOT_SET); + return -1; + } + + if (SSL_in_init(s)) { + ret = s->handshake_func(s); + } + return ret; +} + +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; + /* clear the current cipher */ + ssl_clear_cipher_ctx(ssl); +} + +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; + /* clear the current cipher */ + ssl_clear_cipher_ctx(ssl); +} + static const char *ssl_get_version(int version) { switch (version) { case TLS1_2_VERSION: @@ -1983,16 +2176,12 @@ static const char *ssl_get_version(int version) { } } -const char *SSL_get_version(const SSL *ssl) { - return ssl_get_version(ssl->version); -} - -const char *SSL_SESSION_get_version(const SSL_SESSION *session) { - return ssl_get_version(session->ssl_version); +const char *SSL_get_version(const SSL *s) { + return ssl_get_version(s->version); } -const char* SSL_get_curve_name(uint16_t curve_id) { - return tls1_ec_curve_id2name(curve_id); +const char *SSL_SESSION_get_version(const SSL_SESSION *sess) { + return ssl_get_version(sess->ssl_version); } void ssl_clear_cipher_ctx(SSL *s) { @@ -2004,7 +2193,7 @@ void ssl_clear_cipher_ctx(SSL *s) { X509 *SSL_get_certificate(const SSL *s) { if (s->cert != NULL) { - return s->cert->x509; + return s->cert->key->x509; } return NULL; @@ -2012,7 +2201,7 @@ X509 *SSL_get_certificate(const SSL *s) { EVP_PKEY *SSL_get_privatekey(const SSL *s) { if (s->cert != NULL) { - return s->cert->privatekey; + return s->cert->key->privatekey; } return NULL; @@ -2020,7 +2209,7 @@ EVP_PKEY *SSL_get_privatekey(const SSL *s) { X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) { if (ctx->cert != NULL) { - return ctx->cert->x509; + return ctx->cert->key->x509; } return NULL; @@ -2028,22 +2217,22 @@ X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) { EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx) { if (ctx->cert != NULL) { - return ctx->cert->privatekey; + return ctx->cert->key->privatekey; } return NULL; } -const SSL_CIPHER *SSL_get_current_cipher(const SSL *ssl) { - if (ssl->aead_write_ctx == NULL) { +const SSL_CIPHER *SSL_get_current_cipher(const SSL *s) { + if (s->aead_write_ctx == NULL) { return NULL; } - return ssl->aead_write_ctx->cipher; + return s->aead_write_ctx->cipher; } -const COMP_METHOD *SSL_get_current_compression(SSL *s) { return NULL; } +const void *SSL_get_current_compression(SSL *s) { return NULL; } -const COMP_METHOD *SSL_get_current_expansion(SSL *s) { return NULL; } +const void *SSL_get_current_expansion(SSL *s) { return NULL; } int ssl_init_wbio_buffer(SSL *s, int push) { BIO *bbio; @@ -2063,7 +2252,7 @@ int ssl_init_wbio_buffer(SSL *s, int push) { BIO_reset(bbio); if (!BIO_set_read_buffer_size(bbio, 1)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); + OPENSSL_PUT_ERROR(SSL, ssl_init_wbio_buffer, ERR_R_BUF_LIB); return 0; } @@ -2141,9 +2330,9 @@ int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx) { return X509_STORE_set_default_paths(ctx->cert_store); } -int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *ca_file, - const char *ca_dir) { - return X509_STORE_load_locations(ctx->cert_store, ca_file, ca_dir); +int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, + const char *CApath) { + return X509_STORE_load_locations(ctx->cert_store, CAfile, CApath); } void SSL_set_info_callback(SSL *ssl, @@ -2160,9 +2349,7 @@ int SSL_state(const SSL *ssl) { return ssl->state; } void SSL_set_state(SSL *ssl, int state) { } -void SSL_set_verify_result(SSL *ssl, long result) { - ssl->verify_result = result; -} +void SSL_set_verify_result(SSL *ssl, long arg) { ssl->verify_result = arg; } long SSL_get_verify_result(const SSL *ssl) { return ssl->verify_result; } @@ -2176,12 +2363,12 @@ int SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, return index; } -int SSL_set_ex_data(SSL *ssl, int idx, void *arg) { - return CRYPTO_set_ex_data(&ssl->ex_data, idx, arg); +int SSL_set_ex_data(SSL *s, int idx, void *arg) { + return CRYPTO_set_ex_data(&s->ex_data, idx, arg); } -void *SSL_get_ex_data(const SSL *ssl, int idx) { - return CRYPTO_get_ex_data(&ssl->ex_data, idx); +void *SSL_get_ex_data(const SSL *s, int idx) { + return CRYPTO_get_ex_data(&s->ex_data, idx); } int SSL_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, @@ -2195,12 +2382,12 @@ int SSL_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, return index; } -int SSL_CTX_set_ex_data(SSL_CTX *ctx, int idx, void *arg) { - return CRYPTO_set_ex_data(&ctx->ex_data, idx, arg); +int SSL_CTX_set_ex_data(SSL_CTX *s, int idx, void *arg) { + return CRYPTO_set_ex_data(&s->ex_data, idx, arg); } -void *SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx) { - return CRYPTO_get_ex_data(&ctx->ex_data, idx); +void *SSL_CTX_get_ex_data(const SSL_CTX *s, int idx) { + return CRYPTO_get_ex_data(&s->ex_data, idx); } X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) { @@ -2248,7 +2435,8 @@ void SSL_set_tmp_ecdh_callback(SSL *ssl, int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint) { if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG); + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_psk_identity_hint, + SSL_R_DATA_LENGTH_TOO_LONG); return 0; } @@ -2266,23 +2454,24 @@ int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint) { return 1; } -int SSL_use_psk_identity_hint(SSL *ssl, const char *identity_hint) { - if (ssl == NULL) { +int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint) { + if (s == NULL) { return 0; } if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG); + OPENSSL_PUT_ERROR(SSL, SSL_use_psk_identity_hint, + SSL_R_DATA_LENGTH_TOO_LONG); return 0; } /* Clear currently configured hint, if any. */ - OPENSSL_free(ssl->psk_identity_hint); - ssl->psk_identity_hint = NULL; + OPENSSL_free(s->psk_identity_hint); + s->psk_identity_hint = NULL; if (identity_hint != NULL) { - ssl->psk_identity_hint = BUF_strdup(identity_hint); - if (ssl->psk_identity_hint == NULL) { + s->psk_identity_hint = BUF_strdup(identity_hint); + if (s->psk_identity_hint == NULL) { return 0; } } @@ -2290,47 +2479,63 @@ int SSL_use_psk_identity_hint(SSL *ssl, const char *identity_hint) { return 1; } -const char *SSL_get_psk_identity_hint(const SSL *ssl) { - if (ssl == NULL) { +const char *SSL_get_psk_identity_hint(const SSL *s) { + if (s == NULL) { return NULL; } - return ssl->psk_identity_hint; + return s->psk_identity_hint; } -const char *SSL_get_psk_identity(const SSL *ssl) { - if (ssl == NULL || ssl->session == NULL) { +const char *SSL_get_psk_identity(const SSL *s) { + if (s == NULL || s->session == NULL) { return NULL; } - return ssl->session->psk_identity; + return s->session->psk_identity; } void SSL_set_psk_client_callback( - SSL *ssl, unsigned (*cb)(SSL *ssl, const char *hint, char *identity, - unsigned max_identity_len, uint8_t *psk, - unsigned max_psk_len)) { - ssl->psk_client_callback = cb; + SSL *s, unsigned int (*cb)(SSL *ssl, const char *hint, char *identity, + unsigned int max_identity_len, uint8_t *psk, + unsigned int max_psk_len)) { + s->psk_client_callback = cb; } void SSL_CTX_set_psk_client_callback( - SSL_CTX *ctx, unsigned (*cb)(SSL *ssl, const char *hint, char *identity, - unsigned max_identity_len, uint8_t *psk, - unsigned max_psk_len)) { + SSL_CTX *ctx, unsigned int (*cb)(SSL *ssl, const char *hint, char *identity, + unsigned int max_identity_len, + uint8_t *psk, unsigned int max_psk_len)) { ctx->psk_client_callback = cb; } void SSL_set_psk_server_callback( - SSL *ssl, unsigned (*cb)(SSL *ssl, const char *identity, uint8_t *psk, - unsigned max_psk_len)) { - ssl->psk_server_callback = cb; + SSL *s, unsigned int (*cb)(SSL *ssl, const char *identity, uint8_t *psk, + unsigned int max_psk_len)) { + s->psk_server_callback = cb; } void SSL_CTX_set_psk_server_callback( - SSL_CTX *ctx, unsigned (*cb)(SSL *ssl, const char *identity, - uint8_t *psk, unsigned max_psk_len)) { + SSL_CTX *ctx, unsigned int (*cb)(SSL *ssl, const char *identity, + uint8_t *psk, unsigned int max_psk_len)) { ctx->psk_server_callback = cb; } +void SSL_CTX_set_min_version(SSL_CTX *ctx, uint16_t version) { + ctx->min_version = version; +} + +void SSL_CTX_set_max_version(SSL_CTX *ctx, uint16_t version) { + ctx->max_version = version; +} + +void SSL_set_min_version(SSL *ssl, uint16_t version) { + ssl->min_version = version; +} + +void SSL_set_max_version(SSL *ssl, uint16_t version) { + ssl->max_version = version; +} + void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, @@ -2391,13 +2596,16 @@ int ssl_ctx_log_rsa_client_key_exchange(SSL_CTX *ctx, } if (encrypted_premaster_len < 8) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl_ctx_log_rsa_client_key_exchange, + ERR_R_INTERNAL_ERROR); + return 0; + } + + if (!CBB_init(&cbb, 4 + 16 + 1 + premaster_len * 2 + 1)) { return 0; } - CBB_zero(&cbb); - if (!CBB_init(&cbb, 4 + 16 + 1 + premaster_len * 2 + 1) || - !CBB_add_bytes(&cbb, (const uint8_t *)"RSA ", 4) || + if (!CBB_add_bytes(&cbb, (const uint8_t *)"RSA ", 4) || /* Only the first 8 bytes of the encrypted premaster secret are * logged. */ !cbb_add_hex(&cbb, encrypted_premaster, 8) || @@ -2431,13 +2639,15 @@ int ssl_ctx_log_master_secret(SSL_CTX *ctx, const uint8_t *client_random, } if (client_random_len != 32) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl_ctx_log_master_secret, ERR_R_INTERNAL_ERROR); return 0; } - CBB_zero(&cbb); - if (!CBB_init(&cbb, 14 + 64 + 1 + master_len * 2 + 1) || - !CBB_add_bytes(&cbb, (const uint8_t *)"CLIENT_RANDOM ", 14) || + if (!CBB_init(&cbb, 14 + 64 + 1 + master_len * 2 + 1)) { + return 0; + } + + if (!CBB_add_bytes(&cbb, (const uint8_t *)"CLIENT_RANDOM ", 14) || !cbb_add_hex(&cbb, client_random, 32) || !CBB_add_bytes(&cbb, (const uint8_t *)" ", 1) || !cbb_add_hex(&cbb, master, master_len) || @@ -2696,15 +2906,19 @@ uint16_t ssl3_version_from_wire(SSL *s, uint16_t wire_version) { return version; } -int SSL_cache_hit(SSL *ssl) { return SSL_session_reused(ssl); } +int SSL_cache_hit(SSL *s) { return s->hit; } -int SSL_is_server(SSL *ssl) { return ssl->server; } +int SSL_is_server(SSL *s) { return s->server; } void SSL_CTX_set_dos_protection_cb( SSL_CTX *ctx, int (*cb)(const struct ssl_early_callback_ctx *)) { ctx->dos_protection_cb = cb; } +void SSL_enable_fastradio_padding(SSL *s, char on_off) { + s->fastradio_padding = on_off; +} + void SSL_set_reject_peer_renegotiations(SSL *s, int reject) { s->accept_peer_renegotiations = !reject; } @@ -2719,73 +2933,43 @@ int SSL_get_rc4_state(const SSL *ssl, const RC4_KEY **read_key, EVP_AEAD_CTX_get_rc4_state(&ssl->aead_write_ctx->ctx, write_key); } -int SSL_clear(SSL *ssl) { - if (ssl->method == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_METHOD_SPECIFIED); - return 0; - } - - if (ssl_clear_bad_session(ssl)) { - SSL_SESSION_free(ssl->session); - ssl->session = NULL; - } - - 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 - * half and reset |ssl->state| accordingly. */ - if (ssl->handshake_func != NULL) { - if (ssl->server) { - SSL_set_accept_state(ssl); - } else { - SSL_set_connect_state(ssl); +int SSL_get_tls_unique(const SSL *ssl, uint8_t *out, size_t *out_len, + size_t max_out) { + /* The tls-unique value is the first Finished message in the handshake, which + * is the client's in a full handshake and the server's for a resumption. See + * https://tools.ietf.org/html/rfc5929#section-3.1. */ + const uint8_t *finished = ssl->s3->previous_client_finished; + size_t finished_len = ssl->s3->previous_client_finished_len; + if (ssl->hit) { + /* tls-unique is broken for resumed sessions unless EMS is used. */ + if (!ssl->session->extended_master_secret) { + goto err; } - } else { - assert(ssl->state == 0); + finished = ssl->s3->previous_server_finished; + finished_len = ssl->s3->previous_server_finished_len; } - /* TODO(davidben): Some state on |ssl| is reset both in |SSL_new| and - * |SSL_clear| because it is per-connection state rather than configuration - * state. Per-connection state should be on |ssl->s3| and |ssl->d1| so it is - * naturally reset at the right points between |SSL_new|, |SSL_clear|, and - * |ssl3_new|. */ - - ssl->rwstate = SSL_NOTHING; - - BUF_MEM_free(ssl->init_buf); - ssl->init_buf = NULL; - - ssl_clear_cipher_ctx(ssl); - - OPENSSL_free(ssl->next_proto_negotiated); - ssl->next_proto_negotiated = NULL; - ssl->next_proto_negotiated_len = 0; - - /* The ssl->d1->mtu is simultaneously configuration (preserved across - * clear) and connection-specific state (gets reset). - * - * TODO(davidben): Avoid this. */ - unsigned mtu = 0; - if (ssl->d1 != NULL) { - mtu = ssl->d1->mtu; + if (!ssl->s3->initial_handshake_complete || + ssl->version < TLS1_VERSION) { + goto err; } - ssl->method->ssl_free(ssl); - if (!ssl->method->ssl_new(ssl)) { - return 0; + *out_len = finished_len; + if (finished_len > max_out) { + *out_len = max_out; } - ssl->enc_method = ssl3_get_enc_method(ssl->version); - assert(ssl->enc_method != NULL); - if (SSL_IS_DTLS(ssl) && (SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) { - ssl->d1->mtu = mtu; - } + memcpy(out, finished, *out_len); + return 1; - ssl->client_version = ssl->version; +err: + *out_len = 0; + memset(out, 0, max_out); + return 0; +} - return 1; +int SSL_initial_handshake_complete(const SSL *ssl) { + return ssl->s3->initial_handshake_complete; } int SSL_CTX_sess_connect(const SSL_CTX *ctx) { return 0; } @@ -2799,5 +2983,3 @@ int SSL_CTX_sess_cb_hits(const SSL_CTX *ctx) { return 0; } int SSL_CTX_sess_misses(const SSL_CTX *ctx) { return 0; } int SSL_CTX_sess_timeouts(const SSL_CTX *ctx) { return 0; } int SSL_CTX_sess_cache_full(const SSL_CTX *ctx) { return 0; } -void ERR_load_SSL_strings(void) {} -void SSL_load_error_strings(void) {} diff --git a/src/ssl/ssl_rsa.c b/src/ssl/ssl_rsa.c index ccd3858..87f4c1c 100644 --- a/src/ssl/ssl_rsa.c +++ b/src/ssl/ssl_rsa.c @@ -54,38 +54,79 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ -#include <openssl/ssl.h> +#include <stdio.h> +#include <openssl/bio.h> #include <openssl/err.h> #include <openssl/evp.h> #include <openssl/mem.h> +#include <openssl/obj.h> +#include <openssl/pem.h> #include <openssl/x509.h> #include "internal.h" - static int ssl_set_cert(CERT *c, X509 *x509); static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey); -static int is_key_type_supported(int key_type) { - return key_type == EVP_PKEY_RSA || key_type == EVP_PKEY_EC; -} - int SSL_use_certificate(SSL *ssl, X509 *x) { if (x == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); + OPENSSL_PUT_ERROR(SSL, SSL_use_certificate, ERR_R_PASSED_NULL_PARAMETER); return 0; } return ssl_set_cert(ssl->cert, x); } +int SSL_use_certificate_file(SSL *ssl, const char *file, int type) { + int reason_code; + BIO *in; + int ret = 0; + X509 *x = NULL; + + in = BIO_new(BIO_s_file()); + if (in == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_use_certificate_file, ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in, file) <= 0) { + OPENSSL_PUT_ERROR(SSL, SSL_use_certificate_file, ERR_R_SYS_LIB); + goto end; + } + + if (type == SSL_FILETYPE_ASN1) { + reason_code = ERR_R_ASN1_LIB; + x = d2i_X509_bio(in, NULL); + } else if (type == SSL_FILETYPE_PEM) { + reason_code = ERR_R_PEM_LIB; + x = PEM_read_bio_X509(in, NULL, ssl->ctx->default_passwd_callback, + ssl->ctx->default_passwd_callback_userdata); + } else { + OPENSSL_PUT_ERROR(SSL, SSL_use_certificate_file, SSL_R_BAD_SSL_FILETYPE); + goto end; + } + + if (x == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_use_certificate_file, reason_code); + goto end; + } + + ret = SSL_use_certificate(ssl, x); + +end: + X509_free(x); + BIO_free(in); + + return ret; +} + int SSL_use_certificate_ASN1(SSL *ssl, const uint8_t *d, int len) { X509 *x; int ret; x = d2i_X509(NULL, &d, (long)len); if (x == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); + OPENSSL_PUT_ERROR(SSL, SSL_use_certificate_ASN1, ERR_R_ASN1_LIB); return 0; } @@ -99,13 +140,13 @@ int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) { int ret; if (rsa == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); + OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey, ERR_R_PASSED_NULL_PARAMETER); return 0; } pkey = EVP_PKEY_new(); if (pkey == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_EVP_LIB); + OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey, ERR_R_EVP_LIB); return 0; } @@ -119,36 +160,86 @@ int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) { } static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) { - if (!is_key_type_supported(pkey->type)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); + int i; + + i = ssl_cert_type(pkey); + if (i < 0) { + OPENSSL_PUT_ERROR(SSL, ssl_set_pkey, SSL_R_UNKNOWN_CERTIFICATE_TYPE); return 0; } - if (c->x509 != NULL) { + if (c->pkeys[i].x509 != NULL) { /* Sanity-check that the private key and the certificate match, unless the * key is opaque (in case of, say, a smartcard). */ if (!EVP_PKEY_is_opaque(pkey) && - !X509_check_private_key(c->x509, pkey)) { - X509_free(c->x509); - c->x509 = NULL; + !X509_check_private_key(c->pkeys[i].x509, pkey)) { + X509_free(c->pkeys[i].x509); + c->pkeys[i].x509 = NULL; return 0; } } - EVP_PKEY_free(c->privatekey); - c->privatekey = EVP_PKEY_up_ref(pkey); + EVP_PKEY_free(c->pkeys[i].privatekey); + c->pkeys[i].privatekey = EVP_PKEY_up_ref(pkey); + c->key = &(c->pkeys[i]); return 1; } -int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, const uint8_t *der, size_t der_len) { - RSA *rsa = RSA_private_key_from_bytes(der, der_len); +int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type) { + int reason_code, ret = 0; + BIO *in; + RSA *rsa = NULL; + + in = BIO_new(BIO_s_file()); + if (in == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey_file, ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in, file) <= 0) { + OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey_file, ERR_R_SYS_LIB); + goto end; + } + + if (type == SSL_FILETYPE_ASN1) { + reason_code = ERR_R_ASN1_LIB; + rsa = d2i_RSAPrivateKey_bio(in, NULL); + } else if (type == SSL_FILETYPE_PEM) { + reason_code = ERR_R_PEM_LIB; + rsa = + PEM_read_bio_RSAPrivateKey(in, NULL, ssl->ctx->default_passwd_callback, + ssl->ctx->default_passwd_callback_userdata); + } else { + OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey_file, SSL_R_BAD_SSL_FILETYPE); + goto end; + } + + if (rsa == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey_file, reason_code); + goto end; + } + ret = SSL_use_RSAPrivateKey(ssl, rsa); + RSA_free(rsa); + +end: + BIO_free(in); + return ret; +} + +int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, uint8_t *d, long len) { + int ret; + const uint8_t *p; + RSA *rsa; + + p = d; + rsa = d2i_RSAPrivateKey(NULL, &p, (long)len); if (rsa == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); + OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey_ASN1, ERR_R_ASN1_LIB); return 0; } - int ret = SSL_use_RSAPrivateKey(ssl, rsa); + ret = SSL_use_RSAPrivateKey(ssl, rsa); RSA_free(rsa); return ret; } @@ -157,7 +248,7 @@ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) { int ret; if (pkey == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); + OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey, ERR_R_PASSED_NULL_PARAMETER); return 0; } @@ -165,6 +256,46 @@ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) { return ret; } +int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type) { + int reason_code, ret = 0; + BIO *in; + EVP_PKEY *pkey = NULL; + + in = BIO_new(BIO_s_file()); + if (in == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey_file, ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in, file) <= 0) { + OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey_file, ERR_R_SYS_LIB); + goto end; + } + + if (type == SSL_FILETYPE_PEM) { + reason_code = ERR_R_PEM_LIB; + pkey = PEM_read_bio_PrivateKey(in, NULL, ssl->ctx->default_passwd_callback, + ssl->ctx->default_passwd_callback_userdata); + } else if (type == SSL_FILETYPE_ASN1) { + reason_code = ERR_R_ASN1_LIB; + pkey = d2i_PrivateKey_bio(in, NULL); + } else { + OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey_file, SSL_R_BAD_SSL_FILETYPE); + goto end; + } + + if (pkey == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey_file, reason_code); + goto end; + } + ret = SSL_use_PrivateKey(ssl, pkey); + EVP_PKEY_free(pkey); + +end: + BIO_free(in); + return ret; +} + int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const uint8_t *d, long len) { int ret; const uint8_t *p; @@ -173,7 +304,7 @@ int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const uint8_t *d, long len) { p = d; pkey = d2i_PrivateKey(type, NULL, &p, (long)len); if (pkey == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); + OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey_ASN1, ERR_R_ASN1_LIB); return 0; } @@ -184,7 +315,8 @@ int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const uint8_t *d, long len) { int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) { if (x == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate, + ERR_R_PASSED_NULL_PARAMETER); return 0; } @@ -192,28 +324,32 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) { } static int ssl_set_cert(CERT *c, X509 *x) { - EVP_PKEY *pkey = X509_get_pubkey(x); + EVP_PKEY *pkey; + int i; + + pkey = X509_get_pubkey(x); if (pkey == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_X509_LIB); + OPENSSL_PUT_ERROR(SSL, ssl_set_cert, SSL_R_X509_LIB); return 0; } - if (!is_key_type_supported(pkey->type)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); + i = ssl_cert_type(pkey); + if (i < 0) { + OPENSSL_PUT_ERROR(SSL, ssl_set_cert, SSL_R_UNKNOWN_CERTIFICATE_TYPE); EVP_PKEY_free(pkey); return 0; } - if (c->privatekey != NULL) { + if (c->pkeys[i].privatekey != NULL) { /* Sanity-check that the private key and the certificate match, unless the * key is opaque (in case of, say, a smartcard). */ - if (!EVP_PKEY_is_opaque(c->privatekey) && - !X509_check_private_key(x, c->privatekey)) { + if (!EVP_PKEY_is_opaque(c->pkeys[i].privatekey) && + !X509_check_private_key(x, c->pkeys[i].privatekey)) { /* don't fail for a cert/key mismatch, just free current private key * (when switching to a different cert & key, first this function should * be used, then ssl_set_pkey */ - EVP_PKEY_free(c->privatekey); - c->privatekey = NULL; + EVP_PKEY_free(c->pkeys[i].privatekey); + c->pkeys[i].privatekey = NULL; /* clear error queue */ ERR_clear_error(); } @@ -221,19 +357,63 @@ static int ssl_set_cert(CERT *c, X509 *x) { EVP_PKEY_free(pkey); - X509_free(c->x509); - c->x509 = X509_up_ref(x); + X509_free(c->pkeys[i].x509); + c->pkeys[i].x509 = X509_up_ref(x); + c->key = &(c->pkeys[i]); return 1; } +int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) { + int reason_code; + BIO *in; + int ret = 0; + X509 *x = NULL; + + in = BIO_new(BIO_s_file()); + if (in == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_file, ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in, file) <= 0) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_file, ERR_R_SYS_LIB); + goto end; + } + + if (type == SSL_FILETYPE_ASN1) { + reason_code = ERR_R_ASN1_LIB; + x = d2i_X509_bio(in, NULL); + } else if (type == SSL_FILETYPE_PEM) { + reason_code = ERR_R_PEM_LIB; + x = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata); + } else { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_file, + SSL_R_BAD_SSL_FILETYPE); + goto end; + } + + if (x == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_file, reason_code); + goto end; + } + + ret = SSL_CTX_use_certificate(ctx, x); + +end: + X509_free(x); + BIO_free(in); + return ret; +} + int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const uint8_t *d) { X509 *x; int ret; x = d2i_X509(NULL, &d, (long)len); if (x == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_ASN1, ERR_R_ASN1_LIB); return 0; } @@ -247,13 +427,14 @@ int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa) { EVP_PKEY *pkey; if (rsa == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey, + ERR_R_PASSED_NULL_PARAMETER); return 0; } pkey = EVP_PKEY_new(); if (pkey == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_EVP_LIB); + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey, ERR_R_EVP_LIB); return 0; } @@ -265,28 +446,113 @@ int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa) { return ret; } -int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const uint8_t *der, - size_t der_len) { - RSA *rsa = RSA_private_key_from_bytes(der, der_len); +int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type) { + int reason_code, ret = 0; + BIO *in; + RSA *rsa = NULL; + + in = BIO_new(BIO_s_file()); + if (in == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey_file, ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in, file) <= 0) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey_file, ERR_R_SYS_LIB); + goto end; + } + + if (type == SSL_FILETYPE_ASN1) { + reason_code = ERR_R_ASN1_LIB; + rsa = d2i_RSAPrivateKey_bio(in, NULL); + } else if (type == SSL_FILETYPE_PEM) { + reason_code = ERR_R_PEM_LIB; + rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata); + } else { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey_file, + SSL_R_BAD_SSL_FILETYPE); + goto end; + } + + if (rsa == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey_file, reason_code); + goto end; + } + ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa); + RSA_free(rsa); + +end: + BIO_free(in); + return ret; +} + +int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const uint8_t *d, long len) { + int ret; + const uint8_t *p; + RSA *rsa; + + p = d; + rsa = d2i_RSAPrivateKey(NULL, &p, (long)len); if (rsa == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey_ASN1, ERR_R_ASN1_LIB); return 0; } - int ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa); + ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa); RSA_free(rsa); return ret; } int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) { if (pkey == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey, ERR_R_PASSED_NULL_PARAMETER); return 0; } return ssl_set_pkey(ctx->cert, pkey); } +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) { + int reason_code, ret = 0; + BIO *in; + EVP_PKEY *pkey = NULL; + + in = BIO_new(BIO_s_file()); + if (in == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey_file, ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in, file) <= 0) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey_file, ERR_R_SYS_LIB); + goto end; + } + + if (type == SSL_FILETYPE_PEM) { + reason_code = ERR_R_PEM_LIB; + pkey = PEM_read_bio_PrivateKey(in, NULL, ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata); + } else if (type == SSL_FILETYPE_ASN1) { + reason_code = ERR_R_ASN1_LIB; + pkey = d2i_PrivateKey_bio(in, NULL); + } else { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey_file, SSL_R_BAD_SSL_FILETYPE); + goto end; + } + + if (pkey == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey_file, reason_code); + goto end; + } + ret = SSL_CTX_use_PrivateKey(ctx, pkey); + EVP_PKEY_free(pkey); + +end: + BIO_free(in); + return ret; +} + int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, const uint8_t *d, long len) { int ret; @@ -296,7 +562,7 @@ int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, const uint8_t *d, p = d; pkey = d2i_PrivateKey(type, NULL, &p, (long)len); if (pkey == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey_ASN1, ERR_R_ASN1_LIB); return 0; } @@ -305,74 +571,76 @@ int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, const uint8_t *d, return ret; } -void SSL_set_private_key_method(SSL *ssl, - const SSL_PRIVATE_KEY_METHOD *key_method) { - ssl->cert->key_method = key_method; -} - -int SSL_set_private_key_digest_prefs(SSL *ssl, const int *digest_nids, - size_t num_digests) { - OPENSSL_free(ssl->cert->digest_nids); - - ssl->cert->num_digest_nids = 0; - ssl->cert->digest_nids = BUF_memdup(digest_nids, num_digests*sizeof(int)); - if (ssl->cert->digest_nids == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return 0; - } - ssl->cert->num_digest_nids = num_digests; - return 1; -} +/* Read a file that contains our certificate in "PEM" format, possibly followed + * by a sequence of CA certificates that should be sent to the peer in the + * Certificate message. */ +int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) { + BIO *in; + int ret = 0; + X509 *x = NULL; -int ssl_has_private_key(SSL *ssl) { - return ssl->cert->privatekey != NULL || ssl->cert->key_method != NULL; -} + ERR_clear_error(); /* clear error stack for SSL_CTX_use_certificate() */ -int ssl_private_key_type(SSL *ssl) { - if (ssl->cert->key_method != NULL) { - return ssl->cert->key_method->type(ssl); + in = BIO_new(BIO_s_file()); + if (in == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_chain_file, ERR_R_BUF_LIB); + goto end; } - return EVP_PKEY_id(ssl->cert->privatekey); -} -size_t ssl_private_key_max_signature_len(SSL *ssl) { - if (ssl->cert->key_method != NULL) { - return ssl->cert->key_method->max_signature_len(ssl); + if (BIO_read_filename(in, file) <= 0) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_chain_file, ERR_R_SYS_LIB); + goto end; } - return EVP_PKEY_size(ssl->cert->privatekey); -} -enum ssl_private_key_result_t ssl_private_key_sign( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, const EVP_MD *md, - const uint8_t *in, size_t in_len) { - if (ssl->cert->key_method != NULL) { - return ssl->cert->key_method->sign(ssl, out, out_len, max_out, md, in, - in_len); + x = PEM_read_bio_X509_AUX(in, NULL, ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata); + if (x == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_chain_file, ERR_R_PEM_LIB); + goto end; } - enum ssl_private_key_result_t ret = ssl_private_key_failure; - EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(ssl->cert->privatekey, NULL); - if (ctx == NULL) { - goto end; + ret = SSL_CTX_use_certificate(ctx, x); + + if (ERR_peek_error() != 0) { + ret = 0; /* Key/certificate mismatch doesn't imply ret==0 ... */ } - size_t len = max_out; - if (!EVP_PKEY_sign_init(ctx) || - !EVP_PKEY_CTX_set_signature_md(ctx, md) || - !EVP_PKEY_sign(ctx, out, &len, in, in_len)) { - goto end; + if (ret) { + /* If we could set up our certificate, now proceed to the CA + * certificates. */ + X509 *ca; + int r; + uint32_t err; + + SSL_CTX_clear_chain_certs(ctx); + + while ((ca = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata)) != + NULL) { + r = SSL_CTX_add0_chain_cert(ctx, ca); + if (!r) { + X509_free(ca); + ret = 0; + goto end; + } + /* Note that we must not free r if it was successfully added to the chain + * (while we must free the main certificate, since its reference count is + * increased by SSL_CTX_use_certificate). */ + } + + /* When the while loop ends, it's usually just EOF. */ + err = ERR_peek_last_error(); + if (ERR_GET_LIB(err) == ERR_LIB_PEM && + ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { + ERR_clear_error(); + } else { + ret = 0; /* some real error */ + } } - *out_len = len; - ret = ssl_private_key_success; end: - EVP_PKEY_CTX_free(ctx); + X509_free(x); + BIO_free(in); return ret; } - -enum ssl_private_key_result_t ssl_private_key_sign_complete( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out) { - /* Only custom keys may be asynchronous. */ - return ssl->cert->key_method->sign_complete(ssl, out, out_len, max_out); -} diff --git a/src/ssl/ssl_session.c b/src/ssl/ssl_sess.c index 345aca2..9ab4585 100644 --- a/src/ssl/ssl_session.c +++ b/src/ssl/ssl_sess.c @@ -133,9 +133,6 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. */ -#include <openssl/ssl.h> - -#include <assert.h> #include <stdio.h> #include <string.h> @@ -153,111 +150,11 @@ * that it needs to asynchronously fetch session information. */ static const char g_pending_session_magic = 0; -static CRYPTO_EX_DATA_CLASS g_ex_data_class = - CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA; - -static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *session); -static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *session); -static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock); - -SSL_SESSION *SSL_SESSION_new(void) { - SSL_SESSION *session = (SSL_SESSION *)OPENSSL_malloc(sizeof(SSL_SESSION)); - if (session == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return 0; - } - memset(session, 0, sizeof(SSL_SESSION)); - - session->verify_result = 1; /* avoid 0 (= X509_V_OK) just in case */ - session->references = 1; - session->timeout = SSL_DEFAULT_SESSION_TIMEOUT; - session->time = (unsigned long)time(NULL); - CRYPTO_new_ex_data(&g_ex_data_class, session, &session->ex_data); - return session; -} - -SSL_SESSION *SSL_SESSION_up_ref(SSL_SESSION *session) { - if (session != NULL) { - CRYPTO_refcount_inc(&session->references); - } - return session; -} - -void SSL_SESSION_free(SSL_SESSION *session) { - if (session == NULL || - !CRYPTO_refcount_dec_and_test_zero(&session->references)) { - return; - } - - CRYPTO_free_ex_data(&g_ex_data_class, session, &session->ex_data); - - OPENSSL_cleanse(session->master_key, sizeof(session->master_key)); - OPENSSL_cleanse(session->session_id, sizeof(session->session_id)); - X509_free(session->peer); - sk_X509_pop_free(session->cert_chain, X509_free); - OPENSSL_free(session->tlsext_hostname); - OPENSSL_free(session->tlsext_tick); - OPENSSL_free(session->tlsext_signed_cert_timestamp_list); - OPENSSL_free(session->ocsp_response); - OPENSSL_free(session->psk_identity); - OPENSSL_cleanse(session, sizeof(*session)); - OPENSSL_free(session); -} - -const uint8_t *SSL_SESSION_get_id(const SSL_SESSION *session, - unsigned *out_len) { - if (out_len != NULL) { - *out_len = session->session_id_length; - } - return session->session_id; -} - -long SSL_SESSION_get_timeout(const SSL_SESSION *session) { - return session->timeout; -} - -long SSL_SESSION_get_time(const SSL_SESSION *session) { - return session->time; -} - -uint32_t SSL_SESSION_get_key_exchange_info(const SSL_SESSION *session) { - return session->key_exchange_info; -} - -X509 *SSL_SESSION_get0_peer(const SSL_SESSION *session) { - return session->peer; -} - -long SSL_SESSION_set_time(SSL_SESSION *session, long time) { - if (session == NULL) { - return 0; - } - - session->time = time; - return time; -} - -long SSL_SESSION_set_timeout(SSL_SESSION *session, long timeout) { - if (session == NULL) { - return 0; - } +static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT; - session->timeout = timeout; - return 1; -} - -int SSL_SESSION_set1_id_context(SSL_SESSION *session, const uint8_t *sid_ctx, - unsigned sid_ctx_len) { - if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); - return 0; - } - - session->sid_ctx_length = sid_ctx_len; - memcpy(session->sid_ctx, sid_ctx, sid_ctx_len); - - return 1; -} +static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s); +static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s); +static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck); SSL_SESSION *SSL_magic_pending_session_ptr(void) { return (SSL_SESSION *)&g_pending_session_magic; @@ -285,12 +182,37 @@ int SSL_SESSION_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, return index; } -int SSL_SESSION_set_ex_data(SSL_SESSION *session, int idx, void *arg) { - return CRYPTO_set_ex_data(&session->ex_data, idx, arg); +int SSL_SESSION_set_ex_data(SSL_SESSION *s, int idx, void *arg) { + return CRYPTO_set_ex_data(&s->ex_data, idx, arg); +} + +void *SSL_SESSION_get_ex_data(const SSL_SESSION *s, int idx) { + return CRYPTO_get_ex_data(&s->ex_data, idx); } -void *SSL_SESSION_get_ex_data(const SSL_SESSION *session, int idx) { - return CRYPTO_get_ex_data(&session->ex_data, idx); +SSL_SESSION *SSL_SESSION_new(void) { + SSL_SESSION *ss; + + ss = (SSL_SESSION *)OPENSSL_malloc(sizeof(SSL_SESSION)); + if (ss == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_new, ERR_R_MALLOC_FAILURE); + return 0; + } + memset(ss, 0, sizeof(SSL_SESSION)); + + ss->verify_result = 1; /* avoid 0 (= X509_V_OK) just in case */ + ss->references = 1; + ss->timeout = SSL_DEFAULT_SESSION_TIMEOUT; + ss->time = (unsigned long)time(NULL); + CRYPTO_new_ex_data(&g_ex_data_class, ss, &ss->ex_data); + return ss; +} + +const uint8_t *SSL_SESSION_get_id(const SSL_SESSION *s, unsigned int *len) { + if (len) { + *len = s->session_id_length; + } + return s->session_id; } /* Even with SSLv2, we have 16 bytes (128 bits) of session ID space. @@ -303,9 +225,9 @@ void *SSL_SESSION_get_ex_data(const SSL_SESSION *session, int idx) { * server. How you might store that many sessions is perhaps a more interesting * question ... */ static int def_generate_session_id(const SSL *ssl, uint8_t *id, - unsigned *id_len) { + unsigned int *id_len) { static const unsigned kMaxAttempts = 10; - unsigned retry = 0; + unsigned int retry = 0; do { if (!RAND_bytes(id, *id_len)) { return 0; @@ -335,7 +257,8 @@ int ssl_get_new_session(SSL *s, int session) { GEN_SESSION_CB cb = def_generate_session_id; if (s->mode & SSL_MODE_NO_SESSION_CREATION) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SESSION_MAY_NOT_BE_CREATED); + OPENSSL_PUT_ERROR(SSL, ssl_get_new_session, + SSL_R_SESSION_MAY_NOT_BE_CREATED); return 0; } @@ -359,7 +282,8 @@ int ssl_get_new_session(SSL *s, int session) { ss->ssl_version = s->version; ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH; } else { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_SSL_VERSION); + OPENSSL_PUT_ERROR(SSL, ssl_get_new_session, + SSL_R_UNSUPPORTED_SSL_VERSION); SSL_SESSION_free(ss); return 0; } @@ -381,7 +305,8 @@ int ssl_get_new_session(SSL *s, int session) { tmp = ss->session_id_length; if (!cb(s, ss->session_id, &tmp)) { /* The callback failed */ - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CALLBACK_FAILED); + OPENSSL_PUT_ERROR(SSL, ssl_get_new_session, + SSL_R_SSL_SESSION_ID_CALLBACK_FAILED); SSL_SESSION_free(ss); return 0; } @@ -390,7 +315,8 @@ int ssl_get_new_session(SSL *s, int session) { * higher than it was. */ if (!tmp || tmp > ss->session_id_length) { /* The callback set an illegal length */ - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH); + OPENSSL_PUT_ERROR(SSL, ssl_get_new_session, + SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH); SSL_SESSION_free(ss); return 0; } @@ -398,7 +324,8 @@ int ssl_get_new_session(SSL *s, int session) { ss->session_id_length = tmp; /* Finally, check for a conflict */ if (SSL_has_matching_session_id(s, ss->session_id, ss->session_id_length)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONFLICT); + OPENSSL_PUT_ERROR(SSL, ssl_get_new_session, + SSL_R_SSL_SESSION_ID_CONFLICT); SSL_SESSION_free(ss); return 0; } @@ -407,7 +334,7 @@ int ssl_get_new_session(SSL *s, int session) { if (s->tlsext_hostname) { ss->tlsext_hostname = BUF_strdup(s->tlsext_hostname); if (ss->tlsext_hostname == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl_get_new_session, ERR_R_INTERNAL_ERROR); SSL_SESSION_free(ss); return 0; } @@ -417,7 +344,7 @@ int ssl_get_new_session(SSL *s, int session) { } if (s->sid_ctx_length > sizeof(ss->sid_ctx)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl_get_new_session, ERR_R_INTERNAL_ERROR); SSL_SESSION_free(ss); return 0; } @@ -431,110 +358,121 @@ int ssl_get_new_session(SSL *s, int session) { return 1; } -/* ssl_lookup_session looks up |session_id| in the session cache and sets - * |*out_session| to an |SSL_SESSION| object if found. The caller takes - * ownership of the result. */ -static enum ssl_session_result_t ssl_lookup_session( - SSL *ssl, SSL_SESSION **out_session, const uint8_t *session_id, - size_t session_id_len) { - *out_session = NULL; +/* ssl_get_prev attempts to find an SSL_SESSION to be used to resume this + * connection. It is only called by servers. + * + * ctx: contains the early callback context, which is the result of a + * shallow parse of the ClientHello. + * + * Returns: + * -1: error + * 0: a session may have been found. + * + * Side effects: + * - If a session is found then s->session is pointed at it (after freeing an + * existing session if need be) and s->verify_result is set from the session. + * - Both for new and resumed sessions, s->tlsext_ticket_expected is set to 1 + * if the server should issue a new session ticket (to 0 otherwise). */ +int ssl_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx) { + /* This is used only by servers. */ + SSL_SESSION *ret = NULL; + int fatal = 0; + int try_session_cache = 1; + int r; + + if (ctx->session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) { + goto err; + } - if (session_id_len == 0 || session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) { - return ssl_session_success; + if (ctx->session_id_len == 0) { + try_session_cache = 0; } - SSL_SESSION *session; - /* Try the internal cache, if it exists. */ - if (!(ssl->initial_ctx->session_cache_mode & + r = tls1_process_ticket(s, ctx, &ret); /* sets s->tlsext_ticket_expected */ + switch (r) { + case -1: /* Error during processing */ + fatal = 1; + goto err; + + case 0: /* No ticket found */ + case 1: /* Zero length ticket found */ + break; /* Ok to carry on processing session id. */ + + case 2: /* Ticket found but not decrypted. */ + case 3: /* Ticket decrypted, *ret has been set. */ + try_session_cache = 0; + break; + + default: + abort(); + } + + if (try_session_cache && ret == NULL && + !(s->initial_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) { SSL_SESSION data; - data.ssl_version = ssl->version; - data.session_id_length = session_id_len; - memcpy(data.session_id, session_id, session_id_len); - - CRYPTO_MUTEX_lock_read(&ssl->initial_ctx->lock); - session = lh_SSL_SESSION_retrieve(ssl->initial_ctx->sessions, &data); - if (session != NULL) { - SSL_SESSION_up_ref(session); + data.ssl_version = s->version; + data.session_id_length = ctx->session_id_len; + if (ctx->session_id_len == 0) { + return 0; } - CRYPTO_MUTEX_unlock(&ssl->initial_ctx->lock); + memcpy(data.session_id, ctx->session_id, ctx->session_id_len); - if (session != NULL) { - *out_session = session; - return ssl_session_success; + CRYPTO_MUTEX_lock_read(&s->initial_ctx->lock); + ret = lh_SSL_SESSION_retrieve(s->initial_ctx->sessions, &data); + CRYPTO_MUTEX_unlock(&s->initial_ctx->lock); + + if (ret != NULL) { + SSL_SESSION_up_ref(ret); } } - /* Fall back to the external cache, if it exists. */ - if (ssl->initial_ctx->get_session_cb == NULL) { - return ssl_session_success; - } - int copy = 1; - session = ssl->initial_ctx->get_session_cb(ssl, (uint8_t *)session_id, - session_id_len, ©); - if (session == NULL) { - return ssl_session_success; - } - if (session == SSL_magic_pending_session_ptr()) { - return ssl_session_retry; - } + if (try_session_cache && ret == NULL && + s->initial_ctx->get_session_cb != NULL) { + int copy = 1; - /* Increment reference count now if the session callback asks us to do so - * (note that if the session structures returned by the callback are shared - * between threads, it must handle the reference count itself [i.e. copy == - * 0], or things won't be thread-safe). */ - if (copy) { - SSL_SESSION_up_ref(session); - } - - /* Add the externally cached session to the internal cache if necessary. */ - if (!(ssl->initial_ctx->session_cache_mode & - SSL_SESS_CACHE_NO_INTERNAL_STORE)) { - SSL_CTX_add_session(ssl->initial_ctx, session); - } + ret = s->initial_ctx->get_session_cb(s, (uint8_t *)ctx->session_id, + ctx->session_id_len, ©); + if (ret != NULL) { + if (ret == SSL_magic_pending_session_ptr()) { + /* This is a magic value which indicates that the callback needs to + * unwind the stack and figure out the session asynchronously. */ + return PENDING_SESSION; + } - *out_session = session; - return ssl_session_success; -} + /* Increment reference count now if the session callback asks us to do so + * (note that if the session structures returned by the callback are + * shared between threads, it must handle the reference count itself + * [i.e. copy == 0], or things won't be thread-safe). */ + if (copy) { + SSL_SESSION_up_ref(ret); + } -enum ssl_session_result_t ssl_get_prev_session( - SSL *ssl, SSL_SESSION **out_session, int *out_send_ticket, - const struct ssl_early_callback_ctx *ctx) { - /* This is used only by servers. */ - assert(ssl->server); - SSL_SESSION *session = NULL; - int send_ticket = 0; - - /* If tickets are disabled, always behave as if no tickets are present. */ - const uint8_t *ticket = NULL; - size_t ticket_len = 0; - const int tickets_supported = - !(SSL_get_options(ssl) & SSL_OP_NO_TICKET) && - (ssl->version > SSL3_VERSION || ctx->extensions != NULL) && - SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_session_ticket, - &ticket, &ticket_len); - if (tickets_supported) { - if (!tls_process_ticket(ssl, &session, &send_ticket, ticket, ticket_len, - ctx->session_id, ctx->session_id_len)) { - return ssl_session_error; - } - } else { - /* The client does not support session tickets, so the session ID should be - * used instead. */ - enum ssl_session_result_t lookup_ret = ssl_lookup_session( - ssl, &session, ctx->session_id, ctx->session_id_len); - if (lookup_ret != ssl_session_success) { - return lookup_ret; + /* Add the externally cached session to the internal cache as well if and + * only if we are supposed to. */ + if (!(s->initial_ctx->session_cache_mode & + SSL_SESS_CACHE_NO_INTERNAL_STORE)) { + /* The following should not return 1, otherwise, things are very + * strange */ + SSL_CTX_add_session(s->initial_ctx, ret); + } } } - if (session == NULL || - session->sid_ctx_length != ssl->sid_ctx_length || - memcmp(session->sid_ctx, ssl->sid_ctx, ssl->sid_ctx_length) != 0) { - goto no_session; + if (ret == NULL) { + goto err; } - if ((ssl->verify_mode & SSL_VERIFY_PEER) && ssl->sid_ctx_length == 0) { + /* Now ret is non-NULL and we own one of its reference counts. */ + + if (ret->sid_ctx_length != s->sid_ctx_length || + memcmp(ret->sid_ctx, s->sid_ctx, ret->sid_ctx_length)) { + /* We have the session requested by the client, but we don't want to use it + * in this context. */ + goto err; /* treat like cache miss */ + } + + if ((s->verify_mode & SSL_VERIFY_PEER) && s->sid_ctx_length == 0) { /* We can't be sure if this session is being used out of context, which is * especially important for SSL_VERIFY_PEER. The application should have * used SSL[_CTX]_set_session_id_context. @@ -543,76 +481,83 @@ enum ssl_session_result_t ssl_get_prev_session( * like a cache miss (otherwise it would be easy for applications to * effectively disable the session cache by accident without anyone * noticing). */ - OPENSSL_PUT_ERROR(SSL, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED); - goto fatal_error; + OPENSSL_PUT_ERROR(SSL, ssl_get_prev_session, + SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED); + fatal = 1; + goto err; } - if (session->timeout < (long)(time(NULL) - session->time)) { - if (!tickets_supported) { - /* The session was from the cache, so remove it. */ - SSL_CTX_remove_session(ssl->initial_ctx, session); + if (ret->timeout < (long)(time(NULL) - ret->time)) { + /* timeout */ + if (try_session_cache) { + /* session was from the cache, so remove it */ + SSL_CTX_remove_session(s->initial_ctx, ret); } - goto no_session; + goto err; } - *out_session = session; - *out_send_ticket = send_ticket; - return ssl_session_success; - -fatal_error: - SSL_SESSION_free(session); - return ssl_session_error; + SSL_SESSION_free(s->session); + s->session = ret; + s->verify_result = s->session->verify_result; + return 1; -no_session: - *out_session = NULL; - *out_send_ticket = tickets_supported; - SSL_SESSION_free(session); - return ssl_session_success; +err: + if (ret != NULL) { + SSL_SESSION_free(ret); + if (!try_session_cache) { + /* The session was from a ticket, so we should + * issue a ticket for the new session */ + s->tlsext_ticket_expected = 1; + } + } + if (fatal) { + return -1; + } + return 0; } -int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *session) { +int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) { int ret = 0; - SSL_SESSION *old_session; + SSL_SESSION *s; - /* Add just 1 reference count for the |SSL_CTX|'s session cache even though it + /* add just 1 reference count for the SSL_CTX's session cache even though it * has two ways of access: each session is in a doubly linked list and an - * lhash. */ - SSL_SESSION_up_ref(session); - /* If |session| is in already in cache, we take back the increment later. */ + * lhash */ + SSL_SESSION_up_ref(c); + /* if session c is in already in cache, we take back the increment later */ CRYPTO_MUTEX_lock_write(&ctx->lock); - if (!lh_SSL_SESSION_insert(ctx->sessions, &old_session, session)) { + if (!lh_SSL_SESSION_insert(ctx->sessions, &s, c)) { CRYPTO_MUTEX_unlock(&ctx->lock); - SSL_SESSION_free(session); return 0; } - /* |old_session| != NULL iff we already had a session with the given session - * ID. In this case, |old_session| == |session| should hold (then we did not - * really modify |ctx->sessions|), or we're in trouble. */ - if (old_session != NULL && old_session != session) { + /* s != NULL iff we already had a session with the given PID. In this case, s + * == c should hold (then we did not really modify ctx->sessions), or we're + * in trouble. */ + if (s != NULL && s != c) { /* We *are* in trouble ... */ - SSL_SESSION_list_remove(ctx, old_session); - SSL_SESSION_free(old_session); + SSL_SESSION_list_remove(ctx, s); + SSL_SESSION_free(s); /* ... so pretend the other session did not exist in cache (we cannot - * handle two |SSL_SESSION| structures with identical session ID in the same + * handle two SSL_SESSION structures with identical session ID in the same * cache, which could happen e.g. when two threads concurrently obtain the - * same session from an external cache). */ - old_session = NULL; + * same session from an external cache) */ + s = NULL; } - /* Put at the head of the queue unless it is already in the cache. */ - if (old_session == NULL) { - SSL_SESSION_list_add(ctx, session); + /* Put at the head of the queue unless it is already in the cache */ + if (s == NULL) { + SSL_SESSION_list_add(ctx, c); } - if (old_session != NULL) { - /* Existing cache entry -- decrement previously incremented reference count - * because it already takes into account the cache. */ - SSL_SESSION_free(old_session); /* |old_session| == |session| */ + if (s != NULL) { + /* existing cache entry -- decrement previously incremented reference count + * because it already takes into account the cache */ + SSL_SESSION_free(s); /* s == c */ ret = 0; } else { - /* New cache entry -- remove old ones if cache has become too large. */ + /* new cache entry -- remove old ones if cache has become too large */ ret = 1; if (SSL_CTX_sess_get_cache_size(ctx) > 0) { @@ -628,23 +573,23 @@ int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *session) { return ret; } -int SSL_CTX_remove_session(SSL_CTX *ctx, SSL_SESSION *session) { - return remove_session_lock(ctx, session, 1); +int SSL_CTX_remove_session(SSL_CTX *ctx, SSL_SESSION *c) { + return remove_session_lock(ctx, c, 1); } -static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock) { +static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lock) { + SSL_SESSION *r; int ret = 0; - if (session != NULL && session->session_id_length != 0) { + if (c != NULL && c->session_id_length != 0) { if (lock) { CRYPTO_MUTEX_lock_write(&ctx->lock); } - SSL_SESSION *found_session = lh_SSL_SESSION_retrieve(ctx->sessions, - session); - if (found_session == session) { + r = lh_SSL_SESSION_retrieve(ctx->sessions, c); + if (r == c) { ret = 1; - found_session = lh_SSL_SESSION_delete(ctx->sessions, session); - SSL_SESSION_list_remove(ctx, session); + r = lh_SSL_SESSION_delete(ctx->sessions, c); + SSL_SESSION_list_remove(ctx, c); } if (lock) { @@ -652,48 +597,127 @@ static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock) { } if (ret) { - found_session->not_resumable = 1; + r->not_resumable = 1; if (ctx->remove_session_cb != NULL) { - ctx->remove_session_cb(ctx, found_session); + ctx->remove_session_cb(ctx, r); } - SSL_SESSION_free(found_session); + SSL_SESSION_free(r); } } return ret; } -int SSL_set_session(SSL *ssl, SSL_SESSION *session) { - if (ssl->session == session) { +SSL_SESSION *SSL_SESSION_up_ref(SSL_SESSION *session) { + if (session) { + CRYPTO_refcount_inc(&session->references); + } + return session; +} + +void SSL_SESSION_free(SSL_SESSION *session) { + if (session == NULL || + !CRYPTO_refcount_dec_and_test_zero(&session->references)) { + return; + } + + CRYPTO_free_ex_data(&g_ex_data_class, session, &session->ex_data); + + OPENSSL_cleanse(session->master_key, sizeof(session->master_key)); + OPENSSL_cleanse(session->session_id, sizeof(session->session_id)); + ssl_sess_cert_free(session->sess_cert); + X509_free(session->peer); + OPENSSL_free(session->tlsext_hostname); + OPENSSL_free(session->tlsext_tick); + OPENSSL_free(session->tlsext_signed_cert_timestamp_list); + OPENSSL_free(session->ocsp_response); + OPENSSL_free(session->psk_identity); + OPENSSL_cleanse(session, sizeof(*session)); + OPENSSL_free(session); +} + +int SSL_set_session(SSL *s, SSL_SESSION *session) { + if (s->session == session) { return 1; } - SSL_SESSION_free(ssl->session); - ssl->session = session; + SSL_SESSION_free(s->session); + s->session = session; if (session != NULL) { SSL_SESSION_up_ref(session); - ssl->verify_result = session->verify_result; + s->verify_result = session->verify_result; } return 1; } -long SSL_CTX_set_timeout(SSL_CTX *ctx, long timeout) { - if (ctx == NULL) { +long SSL_SESSION_set_timeout(SSL_SESSION *s, long t) { + if (s == NULL) { return 0; } - long old_timeout = ctx->session_timeout; - ctx->session_timeout = timeout; - return old_timeout; + s->timeout = t; + return 1; } -long SSL_CTX_get_timeout(const SSL_CTX *ctx) { - if (ctx == NULL) { +long SSL_SESSION_get_timeout(const SSL_SESSION *s) { + if (s == NULL) { return 0; } - return ctx->session_timeout; + return s->timeout; +} + +long SSL_SESSION_get_time(const SSL_SESSION *s) { + if (s == NULL) { + return 0; + } + + return s->time; +} + +long SSL_SESSION_set_time(SSL_SESSION *s, long t) { + if (s == NULL) { + return 0; + } + + s->time = t; + return t; +} + +X509 *SSL_SESSION_get0_peer(SSL_SESSION *s) { return s->peer; } + +int SSL_SESSION_set1_id_context(SSL_SESSION *s, const uint8_t *sid_ctx, + unsigned int sid_ctx_len) { + if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) { + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_set1_id_context, + SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); + return 0; + } + + s->sid_ctx_length = sid_ctx_len; + memcpy(s->sid_ctx, sid_ctx, sid_ctx_len); + + return 1; +} + +long SSL_CTX_set_timeout(SSL_CTX *s, long t) { + long l; + if (s == NULL) { + return 0; + } + + l = s->session_timeout; + s->session_timeout = t; + return l; +} + +long SSL_CTX_get_timeout(const SSL_CTX *s) { + if (s == NULL) { + return 0; + } + + return s->session_timeout; } typedef struct timeout_param_st { @@ -702,25 +726,25 @@ typedef struct timeout_param_st { LHASH_OF(SSL_SESSION) *cache; } TIMEOUT_PARAM; -static void timeout_doall_arg(SSL_SESSION *session, void *void_param) { +static void timeout_doall_arg(SSL_SESSION *sess, void *void_param) { TIMEOUT_PARAM *param = void_param; if (param->time == 0 || - param->time > (session->time + session->timeout)) { + param->time > (sess->time + sess->timeout)) { /* timeout */ /* The reason we don't call SSL_CTX_remove_session() is to * save on locking overhead */ - (void) lh_SSL_SESSION_delete(param->cache, session); - SSL_SESSION_list_remove(param->ctx, session); - session->not_resumable = 1; + (void) lh_SSL_SESSION_delete(param->cache, sess); + SSL_SESSION_list_remove(param->ctx, sess); + sess->not_resumable = 1; if (param->ctx->remove_session_cb != NULL) { - param->ctx->remove_session_cb(param->ctx, session); + param->ctx->remove_session_cb(param->ctx, sess); } - SSL_SESSION_free(session); + SSL_SESSION_free(sess); } } -void SSL_CTX_flush_sessions(SSL_CTX *ctx, long time) { +void SSL_CTX_flush_sessions(SSL_CTX *ctx, long t) { TIMEOUT_PARAM tp; tp.ctx = ctx; @@ -728,7 +752,7 @@ void SSL_CTX_flush_sessions(SSL_CTX *ctx, long time) { if (tp.cache == NULL) { return; } - tp.time = time; + tp.time = t; CRYPTO_MUTEX_lock_write(&ctx->lock); lh_SSL_SESSION_doall_arg(tp.cache, timeout_doall_arg, &tp); CRYPTO_MUTEX_unlock(&ctx->lock); @@ -745,80 +769,80 @@ int ssl_clear_bad_session(SSL *s) { } /* locked by SSL_CTX in the calling function */ -static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *session) { - if (session->next == NULL || session->prev == NULL) { +static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s) { + if (s->next == NULL || s->prev == NULL) { return; } - if (session->next == (SSL_SESSION *)&ctx->session_cache_tail) { + if (s->next == (SSL_SESSION *)&ctx->session_cache_tail) { /* last element in list */ - if (session->prev == (SSL_SESSION *)&ctx->session_cache_head) { + if (s->prev == (SSL_SESSION *)&ctx->session_cache_head) { /* only one element in list */ ctx->session_cache_head = NULL; ctx->session_cache_tail = NULL; } else { - ctx->session_cache_tail = session->prev; - session->prev->next = (SSL_SESSION *)&(ctx->session_cache_tail); + ctx->session_cache_tail = s->prev; + s->prev->next = (SSL_SESSION *)&(ctx->session_cache_tail); } } else { - if (session->prev == (SSL_SESSION *)&ctx->session_cache_head) { + if (s->prev == (SSL_SESSION *)&ctx->session_cache_head) { /* first element in list */ - ctx->session_cache_head = session->next; - session->next->prev = (SSL_SESSION *)&(ctx->session_cache_head); + ctx->session_cache_head = s->next; + s->next->prev = (SSL_SESSION *)&(ctx->session_cache_head); } else { /* middle of list */ - session->next->prev = session->prev; - session->prev->next = session->next; + s->next->prev = s->prev; + s->prev->next = s->next; } } - session->prev = session->next = NULL; + s->prev = s->next = NULL; } -static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *session) { - if (session->next != NULL && session->prev != NULL) { - SSL_SESSION_list_remove(ctx, session); +static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s) { + if (s->next != NULL && s->prev != NULL) { + SSL_SESSION_list_remove(ctx, s); } if (ctx->session_cache_head == NULL) { - ctx->session_cache_head = session; - ctx->session_cache_tail = session; - session->prev = (SSL_SESSION *)&(ctx->session_cache_head); - session->next = (SSL_SESSION *)&(ctx->session_cache_tail); + ctx->session_cache_head = s; + ctx->session_cache_tail = s; + s->prev = (SSL_SESSION *)&(ctx->session_cache_head); + s->next = (SSL_SESSION *)&(ctx->session_cache_tail); } else { - session->next = ctx->session_cache_head; - session->next->prev = session; - session->prev = (SSL_SESSION *)&(ctx->session_cache_head); - ctx->session_cache_head = session; + s->next = ctx->session_cache_head; + s->next->prev = s; + s->prev = (SSL_SESSION *)&(ctx->session_cache_head); + ctx->session_cache_head = s; } } void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx, - int (*cb)(SSL *ssl, SSL_SESSION *session)) { + int (*cb)(struct ssl_st *ssl, SSL_SESSION *sess)) { ctx->new_session_cb = cb; } -int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx))(SSL *ssl, SSL_SESSION *session) { +int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx))(SSL *ssl, SSL_SESSION *sess) { return ctx->new_session_cb; } -void SSL_CTX_sess_set_remove_cb( - SSL_CTX *ctx, void (*cb)(SSL_CTX *ctx, SSL_SESSION *session)) { +void SSL_CTX_sess_set_remove_cb(SSL_CTX *ctx, + void (*cb)(SSL_CTX *ctx, SSL_SESSION *sess)) { ctx->remove_session_cb = cb; } void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx))(SSL_CTX *ctx, - SSL_SESSION *session) { + SSL_SESSION *sess) { return ctx->remove_session_cb; } void SSL_CTX_sess_set_get_cb(SSL_CTX *ctx, - SSL_SESSION *(*cb)(SSL *ssl, - uint8_t *id, int id_len, - int *out_copy)) { + SSL_SESSION *(*cb)(struct ssl_st *ssl, + uint8_t *data, int len, + int *copy)) { ctx->get_session_cb = cb; } -SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx))( - SSL *ssl, uint8_t *id, int id_len, int *out_copy) { +SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx))(SSL *ssl, uint8_t *data, + int len, int *copy) { return ctx->get_session_cb; } @@ -850,3 +874,5 @@ void SSL_CTX_set_channel_id_cb(SSL_CTX *ctx, void (*SSL_CTX_get_channel_id_cb(SSL_CTX *ctx))(SSL *ssl, EVP_PKEY **pkey) { return ctx->channel_id_cb; } + +IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION) diff --git a/src/ssl/ssl_stat.c b/src/ssl/ssl_stat.c index 5ad1e47..fa5541b 100644 --- a/src/ssl/ssl_stat.c +++ b/src/ssl/ssl_stat.c @@ -82,11 +82,9 @@ * OTHERWISE. */ -#include <openssl/ssl.h> - +#include <stdio.h> #include "internal.h" - const char *SSL_state_string_long(const SSL *s) { const char *str; @@ -336,6 +334,37 @@ const char *SSL_state_string_long(const SSL *s) { str = "SSLv3 read certificate verify B"; break; + /* SSLv2/v3 compatibility states */ + /* client */ + case SSL23_ST_CW_CLNT_HELLO_A: + str = "SSLv2/v3 write client hello A"; + break; + + case SSL23_ST_CW_CLNT_HELLO_B: + str = "SSLv2/v3 write client hello B"; + break; + + case SSL23_ST_CR_SRVR_HELLO_A: + str = "SSLv2/v3 read server hello A"; + break; + + case SSL23_ST_CR_SRVR_HELLO_B: + str = "SSLv2/v3 read server hello B"; + break; + + /* server */ + case SSL23_ST_SR_CLNT_HELLO: + str = "SSLv2/v3 read client hello"; + break; + + case SSL23_ST_SR_V2_CLNT_HELLO: + str = "SSLv2/v3 read v2 client hello"; + break; + + case SSL23_ST_SR_SWITCH_VERSION: + str = "SSLv2/v3 switch version"; + break; + /* DTLS */ case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A: str = "DTLS1 read hello verify request A"; @@ -353,6 +382,30 @@ const char *SSL_state_string_long(const SSL *s) { return str; } +const char *SSL_rstate_string_long(const SSL *s) { + const char *str; + + switch (s->rstate) { + case SSL_ST_READ_HEADER: + str = "read header"; + break; + + case SSL_ST_READ_BODY: + str = "read body"; + break; + + case SSL_ST_READ_DONE: + str = "read done"; + break; + + default: + str = "unknown"; + break; + } + + return str; +} + const char *SSL_state_string(const SSL *s) { const char *str; @@ -582,6 +635,37 @@ const char *SSL_state_string(const SSL *s) { str = "3RCV_B"; break; + /* SSLv2/v3 compatibility states */ + /* client */ + case SSL23_ST_CW_CLNT_HELLO_A: + str = "23WCHA"; + break; + + case SSL23_ST_CW_CLNT_HELLO_B: + str = "23WCHB"; + break; + + case SSL23_ST_CR_SRVR_HELLO_A: + str = "23RSHA"; + break; + + case SSL23_ST_CR_SRVR_HELLO_B: + str = "23RSHA"; + break; + + /* server */ + case SSL23_ST_SR_CLNT_HELLO: + str = "23RCH_"; + break; + + case SSL23_ST_SR_V2_CLNT_HELLO: + str = "23R2CH"; + break; + + case SSL23_ST_SR_SWITCH_VERSION: + str = "23RSW_"; + break; + /* DTLS */ case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A: str = "DRCHVA"; @@ -884,3 +968,27 @@ const char *SSL_alert_desc_string_long(int value) { return str; } + +const char *SSL_rstate_string(const SSL *s) { + const char *str; + + switch (s->rstate) { + case SSL_ST_READ_HEADER: + str = "RH"; + break; + + case SSL_ST_READ_BODY: + str = "RB"; + break; + + case SSL_ST_READ_DONE: + str = "RD"; + break; + + default: + str = "unknown"; + break; + } + + return str; +} diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc index 810d3fa..9f2ddb9 100644 --- a/src/ssl/ssl_test.cc +++ b/src/ssl/ssl_test.cc @@ -24,8 +24,6 @@ #include <openssl/ssl.h> #include "test/scoped_types.h" -#include "../crypto/test/test_util.h" - struct ExpectedCipher { unsigned long id; @@ -214,21 +212,6 @@ static const char *kBadRules[] = { NULL, }; -static const char *kMustNotIncludeNull[] = { - "ALL", - "DEFAULT", - "ALL:!eNULL", - "ALL:!NULL", - "FIPS", - "SHA", - "SHA1", - "RSA", - "SSLv3", - "TLSv1", - "TLSv1.2", - NULL -}; - 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++) { @@ -282,24 +265,6 @@ static bool TestCipherRule(CipherTest *t) { return true; } -static bool TestRuleDoesNotIncludeNull(const char *rule) { - ScopedSSL_CTX ctx(SSL_CTX_new(SSLv23_server_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_NULL(sk_SSL_CIPHER_value(ctx->cipher_list->ciphers, i))) { - fprintf(stderr, "Error: cipher rule '%s' includes NULL\n",rule); - return false; - } - } - return true; -} - static bool TestCipherRules() { for (size_t i = 0; kCipherTests[i].rule != NULL; i++) { if (!TestCipherRule(&kCipherTests[i])) { @@ -319,12 +284,6 @@ static bool TestCipherRules() { ERR_clear_error(); } - for (size_t i = 0; kMustNotIncludeNull[i] != NULL; i++) { - if (!TestRuleDoesNotIncludeNull(kMustNotIncludeNull[i])) { - return false; - } - } - return true; } @@ -376,104 +335,6 @@ static const char kCustomSession[] = "q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG" "BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBLADBAEF"; -// kBoringSSLSession is a serialized SSL_SESSION generated from bssl client. -static const char kBoringSSLSession[] = - "MIIRwQIBAQICAwMEAsAvBCDdoGxGK26mR+8lM0uq6+k9xYuxPnwAjpcF9n0Yli9R" - "kQQwbyshfWhdi5XQ1++7n2L1qqrcVlmHBPpr6yknT/u4pUrpQB5FZ7vqvNn8MdHf" - "9rWgoQYCBFXgs7uiBAICHCCjggR6MIIEdjCCA16gAwIBAgIIf+yfD7Y6UicwDQYJ" - "KoZIhvcNAQELBQAwSTELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMx" - "JTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3JpdHkgRzIwHhcNMTUwODEy" - "MTQ1MzE1WhcNMTUxMTEwMDAwMDAwWjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwK" - "Q2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzETMBEGA1UECgwKR29v" - "Z2xlIEluYzEXMBUGA1UEAwwOd3d3Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEB" - "AQUAA4IBDwAwggEKAoIBAQC0MeG5YGQ0t+IeJeoneP/PrhEaieibeKYkbKVLNZpo" - "PLuBinvhkXZo3DC133NpCBpy6ZktBwamqyixAyuk/NU6OjgXqwwxfQ7di1AInLIU" - "792c7hFyNXSUCG7At8Ifi3YwBX9Ba6u/1d6rWTGZJrdCq3QU11RkKYyTq2KT5mce" - "Tv9iGKqSkSTlp8puy/9SZ/3DbU3U+BuqCFqeSlz7zjwFmk35acdCilpJlVDDN5C/" - "RCh8/UKc8PaL+cxlt531qoTENvYrflBno14YEZlCBZsPiFeUSILpKEj3Ccwhy0eL" - "EucWQ72YZU8mUzXBoXGn0zA0crFl5ci/2sTBBGZsylNBAgMBAAGjggFBMIIBPTAd" - "BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdv" - "b2dsZS5jb20waAYIKwYBBQUHAQEEXDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtp" - "Lmdvb2dsZS5jb20vR0lBRzIuY3J0MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50" - "czEuZ29vZ2xlLmNvbS9vY3NwMB0GA1UdDgQWBBS/bzHxcE73Q4j3slC4BLbMtLjG" - "GjAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEv" - "MBcGA1UdIAQQMA4wDAYKKwYBBAHWeQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRw" - "Oi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQAb" - "qdWPZEHk0X7iKPCTHL6S3w6q1eR67goxZGFSM1lk1hjwyu7XcLJuvALVV9uY3ovE" - "kQZSHwT+pyOPWQhsSjO+1GyjvCvK/CAwiUmBX+bQRGaqHsRcio7xSbdVcajQ3bXd" - "X+s0WdbOpn6MStKAiBVloPlSxEI8pxY6x/BBCnTIk/+DMB17uZlOjG3vbAnkDkP+" - "n0OTucD9sHV7EVj9XUxi51nOfNBCN/s7lpUjDS/NJ4k3iwOtbCPswiot8vLO779a" - "f07vR03r349Iz/KTzk95rlFtX0IU+KYNxFNsanIXZ+C9FYGRXkwhHcvFb4qMUB1y" - "TTlM80jBMOwyjZXmjRAhpAIEAKUDAgEUqQUCAwGJwKqBpwSBpOgebbmn9NRUtMWH" - "+eJpqA5JLMFSMCChOsvKey3toBaCNGU7HfAEiiXNuuAdCBoK262BjQc2YYfqFzqH" - "zuppopXCvhohx7j/tnCNZIMgLYt/O9SXK2RYI5z8FhCCHvB4CbD5G0LGl5EFP27s" - "Jb6S3aTTYPkQe8yZSlxevg6NDwmTogLO9F7UUkaYmVcMQhzssEE2ZRYNwSOU6KjE" - "0Yj+8fAiBtbQriIEIN2L8ZlpaVrdN5KFNdvcmOxJu81P8q53X55xQyGTnGWwsgMC" - "ARezggvvMIIEdjCCA16gAwIBAgIIf+yfD7Y6UicwDQYJKoZIhvcNAQELBQAwSTEL" - "MAkGA1UEBhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2ds" - "ZSBJbnRlcm5ldCBBdXRob3JpdHkgRzIwHhcNMTUwODEyMTQ1MzE1WhcNMTUxMTEw" - "MDAwMDAwWjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG" - "A1UEBwwNTW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UE" - "AwwOd3d3Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB" - "AQC0MeG5YGQ0t+IeJeoneP/PrhEaieibeKYkbKVLNZpoPLuBinvhkXZo3DC133Np" - "CBpy6ZktBwamqyixAyuk/NU6OjgXqwwxfQ7di1AInLIU792c7hFyNXSUCG7At8If" - "i3YwBX9Ba6u/1d6rWTGZJrdCq3QU11RkKYyTq2KT5mceTv9iGKqSkSTlp8puy/9S" - "Z/3DbU3U+BuqCFqeSlz7zjwFmk35acdCilpJlVDDN5C/RCh8/UKc8PaL+cxlt531" - "qoTENvYrflBno14YEZlCBZsPiFeUSILpKEj3Ccwhy0eLEucWQ72YZU8mUzXBoXGn" - "0zA0crFl5ci/2sTBBGZsylNBAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEF" - "BQcDAQYIKwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYB" - "BQUHAQEEXDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB" - "RzIuY3J0MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9v" - "Y3NwMB0GA1UdDgQWBBS/bzHxcE73Q4j3slC4BLbMtLjGGjAMBgNVHRMBAf8EAjAA" - "MB8GA1UdIwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYK" - "KwYBBAHWeQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5j" - "b20vR0lBRzIuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQAbqdWPZEHk0X7iKPCTHL6S" - "3w6q1eR67goxZGFSM1lk1hjwyu7XcLJuvALVV9uY3ovEkQZSHwT+pyOPWQhsSjO+" - "1GyjvCvK/CAwiUmBX+bQRGaqHsRcio7xSbdVcajQ3bXdX+s0WdbOpn6MStKAiBVl" - "oPlSxEI8pxY6x/BBCnTIk/+DMB17uZlOjG3vbAnkDkP+n0OTucD9sHV7EVj9XUxi" - "51nOfNBCN/s7lpUjDS/NJ4k3iwOtbCPswiot8vLO779af07vR03r349Iz/KTzk95" - "rlFtX0IU+KYNxFNsanIXZ+C9FYGRXkwhHcvFb4qMUB1yTTlM80jBMOwyjZXmjRAh" - "MIID8DCCAtigAwIBAgIDAjqDMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT" - "MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i" - "YWwgQ0EwHhcNMTMwNDA1MTUxNTU2WhcNMTYxMjMxMjM1OTU5WjBJMQswCQYDVQQG" - "EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy" - "bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB" - "AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP" - "VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv" - "h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE" - "ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ" - "EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC" - "DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB5zCB5DAfBgNVHSMEGDAWgBTAephojYn7" - "qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wDgYD" - "VR0PAQH/BAQDAgEGMC4GCCsGAQUFBwEBBCIwIDAeBggrBgEFBQcwAYYSaHR0cDov" - "L2cuc3ltY2QuY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwNQYDVR0fBC4wLDAqoCig" - "JoYkaHR0cDovL2cuc3ltY2IuY29tL2NybHMvZ3RnbG9iYWwuY3JsMBcGA1UdIAQQ" - "MA4wDAYKKwYBBAHWeQIFATANBgkqhkiG9w0BAQsFAAOCAQEAqvqpIM1qZ4PtXtR+" - "3h3Ef+AlBgDFJPupyC1tft6dgmUsgWM0Zj7pUsIItMsv91+ZOmqcUHqFBYx90SpI" - "hNMJbHzCzTWf84LuUt5oX+QAihcglvcpjZpNy6jehsgNb1aHA30DP9z6eX0hGfnI" - "Oi9RdozHQZJxjyXON/hKTAAj78Q1EK7gI4BzfE00LshukNYQHpmEcxpw8u1VDu4X" - "Bupn7jLrLN1nBz/2i8Jw3lsA5rsb0zYaImxssDVCbJAJPZPpZAkiDoUGn8JzIdPm" - "X4DkjYUiOnMDsWCOrmji9D6X52ASCWg23jrW4kOVWzeBkoEfu43XrVJkFleW2V40" - "fsg12DCCA30wggLmoAMCAQICAxK75jANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG" - "EwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUg" - "Q2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTAyMDUyMTA0MDAwMFoXDTE4MDgyMTA0" - "MDAwMFowQjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xGzAZ" - "BgNVBAMTEkdlb1RydXN0IEdsb2JhbCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP" - "ADCCAQoCggEBANrMGGMw/fQXIxpWflvfPGw45HG3eJHUvKHYTPioQ7YD6U0hBwiI" - "2lgvZjkpvQV4i5046AW3an5xpObEYKaw74DkiSgPniXW7YPzraaRx5jJQhg1FJ2t" - "mEaSLk/K8YdDwRaVVy1Q74ktgHpXrfLuX2vSAI25FPgUFTXZwEaje3LIkb/JVSvN" - "0Jc+nCZkzN/Ogxlxyk7m1NV7qRnNVd7I7NJeOFPlXE+MLf5QIzb8ZubLjqQ5GQC3" - "lQI5kQsO/jgu0R0FmvZNPm8PBx2vLB6PYDni+jZTEznUXiYr2z2oFL0y6xgDKFIE" - "ceWrMz3hOLsHNoRinHnqFjD0X8Ar6HFr5PkCAwEAAaOB8DCB7TAfBgNVHSMEGDAW" - "gBRI5mj5K9KylddH2CMgEE8zmJCf1DAdBgNVHQ4EFgQUwHqYaI2J+6sFZAwRfap9" - "ZbjKzE4wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMw" - "MTAvoC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9zZWN1cmVjYS5j" - "cmwwTgYDVR0gBEcwRTBDBgRVHSAAMDswOQYIKwYBBQUHAgEWLWh0dHBzOi8vd3d3" - "Lmdlb3RydXN0LmNvbS9yZXNvdXJjZXMvcmVwb3NpdG9yeTANBgkqhkiG9w0BAQUF" - "AAOBgQB24RJuTksWEoYwBrKBCM/wCMfHcX5m7sLt1Dsf//DwyE7WQziwuTB9GNBV" - "g6JqyzYRnOhIZqNtf7gT1Ef+i1pcc/yu2RsyGTirlzQUqpbS66McFAhJtrvlke+D" - "NusdVm/K2rxzY5Dkf3s+Iss9B+1fOHSc4wNQTqGvmO5h8oQ/Eg=="; - // kBadSessionExtraField is a custom serialized SSL_SESSION generated by replacing // the final (optional) element of |kCustomSession| with tag number 30. static const char kBadSessionExtraField[] = @@ -557,8 +418,6 @@ static bool TestSSL_SESSIONEncoding(const char *input_b64) { if (encoded_len != input.size() || memcmp(bssl::vector_data(&input), encoded.get(), input.size()) != 0) { fprintf(stderr, "SSL_SESSION_to_bytes did not round-trip\n"); - hexdump(stderr, "Before: ", input.data(), input.size()); - hexdump(stderr, "After: ", encoded_raw, encoded_len); return false; } @@ -690,141 +549,12 @@ static bool TestCipherGetRFCName(void) { return true; } -// CreateSessionWithTicket returns a sample |SSL_SESSION| with the ticket -// replaced for one of length |ticket_len| or nullptr on failure. -static ScopedSSL_SESSION CreateSessionWithTicket(size_t ticket_len) { - std::vector<uint8_t> der; - if (!DecodeBase64(&der, kOpenSSLSession)) { - return nullptr; - } - ScopedSSL_SESSION session(SSL_SESSION_from_bytes(bssl::vector_data(&der), - der.size())); - if (!session) { - return nullptr; - } - - // Swap out the ticket for a garbage one. - OPENSSL_free(session->tlsext_tick); - session->tlsext_tick = reinterpret_cast<uint8_t*>(OPENSSL_malloc(ticket_len)); - if (session->tlsext_tick == nullptr) { - return nullptr; - } - memset(session->tlsext_tick, 'a', ticket_len); - session->tlsext_ticklen = ticket_len; - return session; -} - -// GetClientHelloLen creates a client SSL connection with a ticket of length -// |ticket_len| and records the ClientHello. It returns the length of the -// ClientHello, not including the record header, on success and zero on error. -static size_t GetClientHelloLen(size_t ticket_len) { - ScopedSSL_CTX ctx(SSL_CTX_new(TLS_method())); - ScopedSSL_SESSION session = CreateSessionWithTicket(ticket_len); - if (!ctx || !session) { - return 0; - } - ScopedSSL ssl(SSL_new(ctx.get())); - ScopedBIO bio(BIO_new(BIO_s_mem())); - if (!ssl || !bio || !SSL_set_session(ssl.get(), session.get())) { - return 0; - } - // Do not configure a reading BIO, but record what's written to a memory BIO. - SSL_set_bio(ssl.get(), nullptr /* rbio */, BIO_up_ref(bio.get())); - int ret = SSL_connect(ssl.get()); - if (ret > 0) { - // SSL_connect should fail without a BIO to write to. - return 0; - } - ERR_clear_error(); - - const uint8_t *unused; - size_t client_hello_len; - if (!BIO_mem_contents(bio.get(), &unused, &client_hello_len) || - client_hello_len <= SSL3_RT_HEADER_LENGTH) { - return 0; - } - return client_hello_len - SSL3_RT_HEADER_LENGTH; -} - -struct PaddingTest { - size_t input_len, padded_len; -}; - -static const PaddingTest kPaddingTests[] = { - // ClientHellos of length below 0x100 do not require padding. - {0xfe, 0xfe}, - {0xff, 0xff}, - // ClientHellos of length 0x100 through 0x1fb are padded up to 0x200. - {0x100, 0x200}, - {0x123, 0x200}, - {0x1fb, 0x200}, - // ClientHellos of length 0x1fc through 0x1ff get padded beyond 0x200. The - // padding extension takes a minimum of four bytes plus one required content - // byte. (To work around yet more server bugs, we avoid empty final - // extensions.) - {0x1fc, 0x201}, - {0x1fd, 0x202}, - {0x1fe, 0x203}, - {0x1ff, 0x204}, - // Finally, larger ClientHellos need no padding. - {0x200, 0x200}, - {0x201, 0x201}, -}; - -static bool TestPaddingExtension() { - // Sample a baseline length. - size_t base_len = GetClientHelloLen(1); - if (base_len == 0) { - return false; - } - - for (const PaddingTest &test : kPaddingTests) { - if (base_len > test.input_len) { - fprintf(stderr, "Baseline ClientHello too long.\n"); - return false; - } - - size_t padded_len = GetClientHelloLen(1 + test.input_len - base_len); - if (padded_len != test.padded_len) { - fprintf(stderr, "%u-byte ClientHello padded to %u bytes, not %u.\n", - static_cast<unsigned>(test.input_len), - static_cast<unsigned>(padded_len), - static_cast<unsigned>(test.padded_len)); - return false; - } - } - return true; -} - -// Test that |SSL_get_client_CA_list| echoes back the configured parameter even -// before configuring as a server. -static bool TestClientCAList() { - ScopedSSL_CTX ctx(SSL_CTX_new(TLS_method())); - if (!ctx) { - return false; - } - ScopedSSL ssl(SSL_new(ctx.get())); - if (!ssl) { - return false; - } - - STACK_OF(X509_NAME) *stack = sk_X509_NAME_new_null(); - if (stack == nullptr) { - return false; - } - // |SSL_set_client_CA_list| takes ownership. - SSL_set_client_CA_list(ssl.get(), stack); - - return SSL_get_client_CA_list(ssl.get()) == stack; -} - -int main() { +int main(void) { SSL_library_init(); if (!TestCipherRules() || !TestSSL_SESSIONEncoding(kOpenSSLSession) || !TestSSL_SESSIONEncoding(kCustomSession) || - !TestSSL_SESSIONEncoding(kBoringSSLSession) || !TestBadSSL_SESSIONEncoding(kBadSessionExtraField) || !TestBadSSL_SESSIONEncoding(kBadSessionVersion) || !TestBadSSL_SESSIONEncoding(kBadSessionTrailingData) || @@ -836,9 +566,7 @@ int main() { !TestDefaultVersion(0, &DTLS_method) || !TestDefaultVersion(DTLS1_VERSION, &DTLSv1_method) || !TestDefaultVersion(DTLS1_2_VERSION, &DTLSv1_2_method) || - !TestCipherGetRFCName() || - !TestPaddingExtension() || - !TestClientCAList()) { + !TestCipherGetRFCName()) { ERR_print_errors_fp(stderr); return 1; } diff --git a/src/ssl/ssl_txt.c b/src/ssl/ssl_txt.c index 3ba0887..2275f16 100644 --- a/src/ssl/ssl_txt.c +++ b/src/ssl/ssl_txt.c @@ -80,14 +80,12 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. */ -#include <openssl/ssl.h> - #include <inttypes.h> #include <stdio.h> -#include <openssl/bio.h> +#include <openssl/buf.h> #include <openssl/err.h> -#include <openssl/x509.h> +#include <openssl/mem.h> #include "internal.h" @@ -98,7 +96,7 @@ int SSL_SESSION_print_fp(FILE *fp, const SSL_SESSION *x) { b = BIO_new(BIO_s_file()); if (b == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_print_fp, ERR_R_BUF_LIB); return 0; } diff --git a/src/ssl/t1_enc.c b/src/ssl/t1_enc.c index 076f8bd..6bd80c3 100644 --- a/src/ssl/t1_enc.c +++ b/src/ssl/t1_enc.c @@ -133,8 +133,6 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. */ -#include <openssl/ssl.h> - #include <assert.h> #include <stdio.h> #include <string.h> @@ -151,7 +149,7 @@ /* tls1_P_hash computes the TLS P_<hash> function as described in RFC 5246, - * section 5. It XORs |out_len| bytes to |out|, using |md| as the hash and + * section 5. It writes |out_len| bytes to |out|, using |md| as the hash and * |secret| as the secret. |seed1| through |seed3| are concatenated to form the * seed parameter. It returns one on success and zero on failure. */ static int tls1_P_hash(uint8_t *out, size_t out_len, const EVP_MD *md, @@ -190,32 +188,26 @@ static int tls1_P_hash(uint8_t *out, size_t out_len, const EVP_MD *md, goto err; } - unsigned len; - uint8_t hmac[EVP_MAX_MD_SIZE]; - if (!HMAC_Final(&ctx, hmac, &len)) { - goto err; - } - assert(len == chunk); - - /* XOR the result into |out|. */ - if (len > out_len) { - len = out_len; - } - unsigned i; - for (i = 0; i < len; i++) { - out[i] ^= hmac[i]; - } - out += len; - out_len -= len; - - if (out_len == 0) { + if (out_len > chunk) { + unsigned len; + if (!HMAC_Final(&ctx, out, &len)) { + goto err; + } + assert(len == chunk); + out += len; + out_len -= len; + /* Calculate the next A1 value. */ + if (!HMAC_Final(&ctx_tmp, A1, &A1_len)) { + goto err; + } + } else { + /* Last chunk. */ + if (!HMAC_Final(&ctx, A1, &A1_len)) { + goto err; + } + memcpy(out, A1, out_len); break; } - - /* Calculate the next A1 value. */ - if (!HMAC_Final(&ctx_tmp, A1, &A1_len)) { - goto err; - } } ret = 1; @@ -232,36 +224,62 @@ int tls1_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, const uint8_t *seed1, size_t seed1_len, const uint8_t *seed2, size_t seed2_len) { + size_t idx, len, count, i; + const uint8_t *S1; + uint32_t m; + const EVP_MD *md; + int ret = 0; + uint8_t *tmp; if (out_len == 0) { return 1; } - memset(out, 0, out_len); + /* Allocate a temporary buffer. */ + tmp = OPENSSL_malloc(out_len); + if (tmp == NULL) { + OPENSSL_PUT_ERROR(SSL, tls1_prf, ERR_R_MALLOC_FAILURE); + return 0; + } - uint32_t algorithm_prf = ssl_get_algorithm_prf(s); - if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT) { - /* If using the MD5/SHA1 PRF, |secret| is partitioned between SHA-1 and - * MD5, MD5 first. */ - size_t secret_half = secret_len - (secret_len / 2); - if (!tls1_P_hash(out, out_len, EVP_md5(), secret, secret_half, - (const uint8_t *)label, label_len, seed1, seed1_len, seed2, - seed2_len)) { - return 0; + /* Count number of digests and partition |secret| evenly. */ + count = 0; + for (idx = 0; ssl_get_handshake_digest(&m, &md, idx); idx++) { + if (m & ssl_get_algorithm2(s)) { + count++; } - - /* Note that, if |secret_len| is odd, the two halves share a byte. */ - secret = secret + (secret_len - secret_half); - secret_len = secret_half; } - - if (!tls1_P_hash(out, out_len, ssl_get_handshake_digest(algorithm_prf), - secret, secret_len, (const uint8_t *)label, label_len, - seed1, seed1_len, seed2, seed2_len)) { - return 0; + /* TODO(davidben): The only case where count isn't 1 is the old MD5/SHA-1 + * combination. The logic around multiple handshake digests can probably be + * simplified. */ + assert(count == 1 || count == 2); + len = secret_len / count; + if (count == 1) { + secret_len = 0; + } + S1 = secret; + memset(out, 0, out_len); + for (idx = 0; ssl_get_handshake_digest(&m, &md, idx); idx++) { + if (m & ssl_get_algorithm2(s)) { + /* If |count| is 2 and |secret_len| is odd, |secret| is partitioned into + * two halves with an overlapping byte. */ + if (!tls1_P_hash(tmp, out_len, md, S1, len + (secret_len & 1), + (const uint8_t *)label, label_len, seed1, seed1_len, + seed2, seed2_len)) { + goto err; + } + S1 += len; + for (i = 0; i < out_len; i++) { + out[i] ^= tmp[i]; + } + } } + ret = 1; - return 1; +err: + OPENSSL_cleanse(tmp, out_len); + OPENSSL_free(tmp); + return ret; } static int tls1_generate_key_block(SSL *s, uint8_t *out, size_t out_len) { @@ -299,7 +317,7 @@ int tls1_change_cipher_state(SSL *s, int which) { iv_len = s->s3->tmp.new_fixed_iv_len; if (aead == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state, ERR_R_INTERNAL_ERROR); return 0; } @@ -309,7 +327,7 @@ int tls1_change_cipher_state(SSL *s, int which) { * suites) the key length reported by |EVP_AEAD_key_length| will * include the MAC and IV key bytes. */ if (key_len < mac_secret_len + iv_len) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state, ERR_R_INTERNAL_ERROR); return 0; } key_len -= mac_secret_len + iv_len; @@ -340,7 +358,7 @@ int tls1_change_cipher_state(SSL *s, int which) { } if (key_data - s->s3->tmp.key_block != s->s3->tmp.key_block_length) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state, ERR_R_INTERNAL_ERROR); return 0; } @@ -351,26 +369,14 @@ int tls1_change_cipher_state(SSL *s, int which) { s->s3->tmp.new_cipher, key, key_len, mac_secret, mac_secret_len, iv, iv_len); return s->aead_read_ctx != NULL; + } else { + SSL_AEAD_CTX_free(s->aead_write_ctx); + s->aead_write_ctx = SSL_AEAD_CTX_new( + evp_aead_seal, ssl3_version_from_wire(s, s->version), + s->s3->tmp.new_cipher, key, key_len, mac_secret, mac_secret_len, iv, + iv_len); + return s->aead_write_ctx != NULL; } - - SSL_AEAD_CTX_free(s->aead_write_ctx); - s->aead_write_ctx = SSL_AEAD_CTX_new( - evp_aead_seal, ssl3_version_from_wire(s, s->version), - s->s3->tmp.new_cipher, key, key_len, mac_secret, mac_secret_len, iv, - iv_len); - if (s->aead_write_ctx == NULL) { - return 0; - } - - s->s3->need_record_splitting = 0; - if (!SSL_USE_EXPLICIT_IV(s) && - (s->mode & SSL_MODE_CBC_RECORD_SPLITTING) != 0 && - SSL_CIPHER_is_block_cipher(s->s3->tmp.new_cipher)) { - /* Enable 1/n-1 record-splitting to randomize the IV. See - * https://www.openssl.org/~bodo/tls-cbc.txt and the BEAST attack. */ - s->s3->need_record_splitting = 1; - } - return 1; } int tls1_setup_key_block(SSL *s) { @@ -400,14 +406,14 @@ int tls1_setup_key_block(SSL *s) { * key length reported by |EVP_AEAD_key_length| will include the MAC key * bytes and initial implicit IV. */ if (key_len < mac_secret_len + fixed_iv_len) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block, ERR_R_INTERNAL_ERROR); return 0; } key_len -= mac_secret_len + fixed_iv_len; } else { /* The nonce is split into a fixed portion and a variable portion. */ if (variable_iv_len < fixed_iv_len) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block, ERR_R_INTERNAL_ERROR); return 0; } variable_iv_len -= fixed_iv_len; @@ -429,7 +435,7 @@ int tls1_setup_key_block(SSL *s) { p = (uint8_t *)OPENSSL_malloc(key_block_len); if (p == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block, ERR_R_MALLOC_FAILURE); goto err; } @@ -440,61 +446,60 @@ int tls1_setup_key_block(SSL *s) { goto err; } + if (!SSL_USE_EXPLICIT_IV(s) && + (s->mode & SSL_MODE_CBC_RECORD_SPLITTING) != 0) { + /* enable vulnerability countermeasure for CBC ciphers with known-IV + * problem (http://www.openssl.org/~bodo/tls-cbc.txt). */ + s->s3->need_record_splitting = 1; + + if (s->session->cipher != NULL && + s->session->cipher->algorithm_enc == SSL_RC4) { + s->s3->need_record_splitting = 0; + } + } + ret = 1; err: return ret; cipher_unavailable_err: - OPENSSL_PUT_ERROR(SSL, SSL_R_CIPHER_OR_HASH_UNAVAILABLE); + OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block, + SSL_R_CIPHER_OR_HASH_UNAVAILABLE); return 0; } int tls1_cert_verify_mac(SSL *s, int md_nid, uint8_t *out) { - const EVP_MD_CTX *ctx_template; - if (md_nid == NID_md5) { - ctx_template = &s->s3->handshake_md5; - } else if (md_nid == EVP_MD_CTX_type(&s->s3->handshake_hash)) { - ctx_template = &s->s3->handshake_hash; - } else { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_REQUIRED_DIGEST); + unsigned int ret; + EVP_MD_CTX ctx, *d = NULL; + int i; + + if (s->s3->handshake_buffer && + !ssl3_digest_cached_records(s, free_handshake_buffer)) { + return 0; + } + + for (i = 0; i < SSL_MAX_DIGEST; i++) { + if (s->s3->handshake_dgst[i] && + EVP_MD_CTX_type(s->s3->handshake_dgst[i]) == md_nid) { + d = s->s3->handshake_dgst[i]; + break; + } + } + + if (!d) { + OPENSSL_PUT_ERROR(SSL, tls1_cert_verify_mac, SSL_R_NO_REQUIRED_DIGEST); return 0; } - EVP_MD_CTX ctx; EVP_MD_CTX_init(&ctx); - if (!EVP_MD_CTX_copy_ex(&ctx, ctx_template)) { + if (!EVP_MD_CTX_copy_ex(&ctx, d)) { EVP_MD_CTX_cleanup(&ctx); return 0; } - unsigned ret; EVP_DigestFinal_ex(&ctx, out, &ret); EVP_MD_CTX_cleanup(&ctx); - return ret; -} - -static int append_digest(const EVP_MD_CTX *ctx, uint8_t *out, size_t *out_len, - size_t max_out) { - int ret = 0; - EVP_MD_CTX ctx_copy; - EVP_MD_CTX_init(&ctx_copy); - - if (EVP_MD_CTX_size(ctx) > max_out) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); - goto err; - } - unsigned len; - if (!EVP_MD_CTX_copy_ex(&ctx_copy, ctx) || - !EVP_DigestFinal_ex(&ctx_copy, out, &len)) { - goto err; - } - assert(len == EVP_MD_CTX_size(ctx)); - - *out_len = len; - ret = 1; -err: - EVP_MD_CTX_cleanup(&ctx_copy); return ret; } @@ -504,19 +509,44 @@ err: * underlying digests so can be called multiple times and prior to the final * update etc. */ int tls1_handshake_digest(SSL *s, uint8_t *out, size_t out_len) { - size_t md5_len = 0; - if (EVP_MD_CTX_md(&s->s3->handshake_md5) != NULL && - !append_digest(&s->s3->handshake_md5, out, &md5_len, out_len)) { - return -1; + const EVP_MD *md; + EVP_MD_CTX ctx; + int err = 0, len = 0; + size_t i; + uint32_t mask; + + EVP_MD_CTX_init(&ctx); + + for (i = 0; ssl_get_handshake_digest(&mask, &md, i); i++) { + size_t hash_size; + unsigned int digest_len; + EVP_MD_CTX *hdgst = s->s3->handshake_dgst[i]; + + if ((mask & ssl_get_algorithm2(s)) == 0) { + continue; + } + + hash_size = EVP_MD_size(md); + if (!hdgst || + hash_size > out_len || + !EVP_MD_CTX_copy_ex(&ctx, hdgst) || + !EVP_DigestFinal_ex(&ctx, out, &digest_len) || + digest_len != hash_size /* internal error */) { + err = 1; + break; + } + + out += digest_len; + out_len -= digest_len; + len += digest_len; } - size_t len; - if (!append_digest(&s->s3->handshake_hash, out + md5_len, &len, - out_len - md5_len)) { + EVP_MD_CTX_cleanup(&ctx); + + if (err != 0) { return -1; } - - return (int)(md5_len + len); + return len; } int tls1_final_finish_mac(SSL *s, const char *str, int slen, uint8_t *out) { @@ -525,8 +555,14 @@ int tls1_final_finish_mac(SSL *s, const char *str, int slen, uint8_t *out) { int digests_len; /* At this point, the handshake should have released the handshake buffer on - * its own. */ + * its own. + * TODO(davidben): Apart from initialization, the handshake buffer should be + * orthogonal to the handshake digest. https://crbug.com/492371 */ assert(s->s3->handshake_buffer == NULL); + if (s->s3->handshake_buffer && + !ssl3_digest_cached_records(s, free_handshake_buffer)) { + return 0; + } digests_len = tls1_handshake_digest(s, buf, sizeof(buf)); if (digests_len < 0) { @@ -551,7 +587,21 @@ int tls1_generate_master_secret(SSL *s, uint8_t *out, const uint8_t *premaster, size_t premaster_len) { if (s->s3->tmp.extended_master_secret) { uint8_t digests[2 * EVP_MAX_MD_SIZE]; - int digests_len = tls1_handshake_digest(s, digests, sizeof(digests)); + int digests_len; + + /* The master secret is based on the handshake hash just after sending the + * ClientKeyExchange. However, we might have a client certificate to send, + * in which case we might need different hashes for the verification and + * thus still need the handshake buffer around. Keeping both a handshake + * buffer *and* running hashes isn't yet supported so, when it comes to + * calculating the Finished hash, we'll have to hash the handshake buffer + * again. */ + if (s->s3->handshake_buffer && + !ssl3_digest_cached_records(s, dont_free_handshake_buffer)) { + return 0; + } + + digests_len = tls1_handshake_digest(s, digests, sizeof(digests)); if (digests_len == -1) { return 0; } @@ -580,21 +630,22 @@ int tls1_export_keying_material(SSL *s, uint8_t *out, size_t out_len, const uint8_t *context, size_t context_len, int use_context) { if (!s->s3->have_version || s->version == SSL3_VERSION) { - OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + OPENSSL_PUT_ERROR(SSL, tls1_export_keying_material, + ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } size_t seed_len = 2 * SSL3_RANDOM_SIZE; if (use_context) { if (context_len >= 1u << 16) { - OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); + OPENSSL_PUT_ERROR(SSL, tls1_export_keying_material, ERR_R_OVERFLOW); return 0; } seed_len += 2 + context_len; } uint8_t *seed = OPENSSL_malloc(seed_len); if (seed == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, tls1_export_keying_material, ERR_R_MALLOC_FAILURE); return 0; } diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c index f30e8eb..213a647 100644 --- a/src/ssl/t1_lib.c +++ b/src/ssl/t1_lib.c @@ -106,16 +106,12 @@ * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). */ -#include <openssl/ssl.h> - #include <assert.h> -#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <openssl/bytestring.h> -#include <openssl/digest.h> #include <openssl/err.h> #include <openssl/evp.h> #include <openssl/hmac.h> @@ -126,6 +122,9 @@ #include "internal.h" +static int tls_decrypt_ticket(SSL *s, const uint8_t *tick, int ticklen, + const uint8_t *sess_id, int sesslen, + SSL_SESSION **psess); static int ssl_check_clienthello_tlsext(SSL *s); static int ssl_check_serverhello_tlsext(SSL *s); @@ -214,7 +213,8 @@ static int tls1_check_duplicate_extensions(const CBS *cbs) { extension_types = (uint16_t *)OPENSSL_malloc(sizeof(uint16_t) * num_extensions); if (extension_types == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, tls1_check_duplicate_extensions, + ERR_R_MALLOC_FAILURE); goto done; } @@ -338,21 +338,24 @@ char SSL_early_callback_ctx_extension_get( struct tls_curve { uint16_t curve_id; int nid; - const char curve_name[8]; }; /* ECC curves from RFC4492. */ static const struct tls_curve tls_curves[] = { - {21, NID_secp224r1, "P-224"}, - {23, NID_X9_62_prime256v1, "P-256"}, - {24, NID_secp384r1, "P-384"}, - {25, NID_secp521r1, "P-521"}, + {21, NID_secp224r1}, + {23, NID_X9_62_prime256v1}, + {24, NID_secp384r1}, + {25, NID_secp521r1}, +}; + +static const uint8_t ecformats_default[] = { + TLSEXT_ECPOINTFORMAT_uncompressed, }; static const uint16_t eccurves_default[] = { 23, /* X9_62_prime256v1 */ 24, /* secp384r1 */ -#if defined(BORINGSSL_ANDROID_SYSTEM) +#if defined(ANDROID) 25, /* secp521r1 */ #endif }; @@ -378,16 +381,6 @@ int tls1_ec_nid2curve_id(uint16_t *out_curve_id, int nid) { return 0; } -const char* tls1_ec_curve_id2name(uint16_t curve_id) { - size_t i; - for (i = 0; i < sizeof(tls_curves) / sizeof(tls_curves[0]); i++) { - if (curve_id == tls_curves[i].curve_id) { - return tls_curves[i].curve_name; - } - } - return NULL; -} - /* 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. */ @@ -542,6 +535,28 @@ static int tls1_curve_params_from_ec_key(uint16_t *out_curve_id, return 1; } +/* tls1_check_point_format returns one if |comp_id| is consistent with the + * peer's point format preferences. */ +static int tls1_check_point_format(SSL *s, uint8_t comp_id) { + uint8_t *p = s->s3->tmp.peer_ecpointformatlist; + size_t plen = s->s3->tmp.peer_ecpointformatlist_length; + size_t i; + + /* If point formats extension present check it, otherwise everything is + * supported (see RFC4492). */ + if (p == NULL) { + return 1; + } + + for (i = 0; i < plen; i++) { + if (comp_id == p[i]) { + return 1; + } + } + + return 0; +} + /* 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 * preferences are checked; the peer (the server) does not send preferences. */ @@ -578,6 +593,18 @@ static int tls1_check_curve_id(SSL *s, uint16_t curve_id) { return 1; } +static void tls1_get_formatlist(SSL *s, const uint8_t **pformats, + size_t *pformatslen) { + /* If we have a custom point format list use it otherwise use default */ + if (s->tlsext_ecpointformatlist) { + *pformats = s->tlsext_ecpointformatlist; + *pformatslen = s->tlsext_ecpointformatlist_length; + } else { + *pformats = ecformats_default; + *pformatslen = sizeof(ecformats_default); + } +} + int tls1_check_ec_cert(SSL *s, X509 *x) { int ret = 0; EVP_PKEY *pkey = X509_get_pubkey(x); @@ -588,7 +615,7 @@ int tls1_check_ec_cert(SSL *s, X509 *x) { pkey->type != EVP_PKEY_EC || !tls1_curve_params_from_ec_key(&curve_id, &comp_id, pkey->pkey.ec) || !tls1_check_curve_id(s, curve_id) || - comp_id != TLSEXT_ECPOINTFORMAT_uncompressed) { + !tls1_check_point_format(s, comp_id)) { goto done; } @@ -636,8 +663,17 @@ static const uint8_t tls12_sigalgs[] = { }; size_t tls12_get_psigalgs(SSL *s, const uint8_t **psigs) { - *psigs = tls12_sigalgs; - return sizeof(tls12_sigalgs); + /* If server use client authentication sigalgs if not NULL */ + if (s->server && s->cert->client_sigalgs) { + *psigs = s->cert->client_sigalgs; + return s->cert->client_sigalgslen; + } else if (s->cert->conf_sigalgs) { + *psigs = s->cert->conf_sigalgs; + return s->cert->conf_sigalgslen; + } else { + *psigs = tls12_sigalgs; + return sizeof(tls12_sigalgs); + } } /* tls12_check_peer_sigalg parses a SignatureAndHashAlgorithm out of |cbs|. It @@ -648,26 +684,26 @@ int tls12_check_peer_sigalg(const EVP_MD **out_md, int *out_alert, SSL *s, CBS *cbs, EVP_PKEY *pkey) { const uint8_t *sent_sigs; size_t sent_sigslen, i; - int sigalg = tls12_get_sigid(pkey->type); + int sigalg = tls12_get_sigid(pkey); uint8_t hash, signature; /* Should never happen */ if (sigalg == -1) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, ERR_R_INTERNAL_ERROR); *out_alert = SSL_AD_INTERNAL_ERROR; return 0; } if (!CBS_get_u8(cbs, &hash) || !CBS_get_u8(cbs, &signature)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_DECODE_ERROR); *out_alert = SSL_AD_DECODE_ERROR; return 0; } /* Check key type is consistent with signature */ if (sigalg != signature) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); + OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_WRONG_SIGNATURE_TYPE); *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } @@ -682,8 +718,8 @@ int tls12_check_peer_sigalg(const EVP_MD **out_md, int *out_alert, SSL *s, } if (s->server && (!tls1_check_curve_id(s, curve_id) || - comp_id != TLSEXT_ECPOINTFORMAT_uncompressed)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); + !tls1_check_point_format(s, comp_id))) { + OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_WRONG_CURVE); *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } @@ -699,14 +735,14 @@ int tls12_check_peer_sigalg(const EVP_MD **out_md, int *out_alert, SSL *s, /* Allow fallback to SHA-1. */ if (i == sent_sigslen && hash != TLSEXT_hash_sha1) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); + OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_WRONG_SIGNATURE_TYPE); *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } *out_md = tls12_get_hash(hash); if (*out_md == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_DIGEST); + OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_UNKNOWN_DIGEST); *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } @@ -763,1785 +799,1128 @@ void ssl_set_client_disabled(SSL *s) { } } -/* tls_extension represents a TLS extension that is handled internally. The - * |init| function is called for each handshake, before any other functions of - * the extension. Then the add and parse callbacks are called as needed. - * - * The parse callbacks receive a |CBS| that contains the contents of the - * extension (i.e. not including the type and length bytes). If an extension is - * not received then the parse callbacks will be called with a NULL CBS so that - * they can do any processing needed to handle the absence of an extension. - * - * The add callbacks receive a |CBB| to which the extension can be appended but - * the function is responsible for appending the type and length bytes too. - * - * All callbacks return one for success and zero for error. If a parse function - * returns zero then a fatal alert with value |*out_alert| will be sent. If - * |*out_alert| isn't set, then a |decode_error| alert will be sent. */ -struct tls_extension { - uint16_t value; - void (*init)(SSL *ssl); - - int (*add_clienthello)(SSL *ssl, CBB *out); - int (*parse_serverhello)(SSL *ssl, uint8_t *out_alert, CBS *contents); - - int (*parse_clienthello)(SSL *ssl, uint8_t *out_alert, CBS *contents); - int (*add_serverhello)(SSL *ssl, CBB *out); -}; - - -/* Server name indication (SNI). - * - * https://tools.ietf.org/html/rfc6066#section-3. */ - -static void ext_sni_init(SSL *ssl) { - ssl->s3->tmp.should_ack_sni = 0; -} - -static int ext_sni_add_clienthello(SSL *ssl, CBB *out) { - if (ssl->tlsext_hostname == NULL) { - return 1; +/* header_len is the length of the ClientHello header written so far, used to + * compute padding. It does not include the record header. Pass 0 if no padding + * is to be done. */ +uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit, + size_t header_len) { + int extdatalen = 0; + uint8_t *ret = buf; + uint8_t *orig = buf; + /* See if we support any ECC ciphersuites */ + int using_ecc = 0; + + if (s->version >= TLS1_VERSION || SSL_IS_DTLS(s)) { + size_t i; + uint32_t alg_k, alg_a; + STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s); + + for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) { + const SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i); + + alg_k = c->algorithm_mkey; + alg_a = c->algorithm_auth; + if ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)) { + using_ecc = 1; + break; + } + } } - CBB contents, server_name_list, name; - if (!CBB_add_u16(out, TLSEXT_TYPE_server_name) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &server_name_list) || - !CBB_add_u8(&server_name_list, TLSEXT_NAMETYPE_host_name) || - !CBB_add_u16_length_prefixed(&server_name_list, &name) || - !CBB_add_bytes(&name, (const uint8_t *)ssl->tlsext_hostname, - strlen(ssl->tlsext_hostname)) || - !CBB_flush(out)) { - return 0; + /* don't add extensions for SSLv3 unless doing secure renegotiation */ + if (s->client_version == SSL3_VERSION && !s->s3->send_connection_binding) { + return orig; } - return 1; -} + ret += 2; -static int ext_sni_parse_serverhello(SSL *ssl, uint8_t *out_alert, CBS *contents) { - if (contents == NULL) { - return 1; + if (ret >= limit) { + return NULL; /* should never occur. */ } - if (CBS_len(contents) != 0) { - return 0; - } + if (s->tlsext_hostname != NULL) { + /* Add TLS extension servername to the Client Hello message */ + unsigned long size_str; + long lenmax; - assert(ssl->tlsext_hostname != NULL); + /* check for enough space. + 4 for the servername type and entension length + 2 for servernamelist length + 1 for the hostname type + 2 for hostname length + + hostname length */ - if (!ssl->hit) { - assert(ssl->session->tlsext_hostname == NULL); - ssl->session->tlsext_hostname = BUF_strdup(ssl->tlsext_hostname); - if (!ssl->session->tlsext_hostname) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; + lenmax = limit - ret - 9; + size_str = strlen(s->tlsext_hostname); + if (lenmax < 0 || size_str > (unsigned long)lenmax) { + return NULL; } - } - return 1; -} + /* extension type and length */ + s2n(TLSEXT_TYPE_server_name, ret); + s2n(size_str + 5, ret); -static int ext_sni_parse_clienthello(SSL *ssl, uint8_t *out_alert, CBS *contents) { - if (contents == NULL) { - return 1; - } + /* length of servername list */ + s2n(size_str + 3, ret); - /* The servername extension is treated as follows: - * - * - Only the hostname type is supported with a maximum length of 255. - * - The servername is rejected if too long or if it contains zeros, in - * which case an fatal alert is generated. - * - The servername field is maintained together with the session cache. - * - When a session is resumed, the servername callback is invoked in order - * to allow the application to position itself to the right context. - * - The servername is acknowledged if it is new for a session or when - * it is identical to a previously used for the same session. - * Applications can control the behaviour. They can at any time - * set a 'desirable' servername for a new SSL object. This can be the - * case for example with HTTPS when a Host: header field is received and - * a renegotiation is requested. In this case, a possible servername - * presented in the new client hello is only acknowledged if it matches - * the value of the Host: field. - * - Applications must use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION - * if they provide for changing an explicit servername context for the - * session, - * i.e. when the session has been established with a servername extension. - */ - - CBS server_name_list; - char have_seen_host_name = 0; - - if (!CBS_get_u16_length_prefixed(contents, &server_name_list) || - CBS_len(&server_name_list) == 0 || - CBS_len(contents) != 0) { - return 0; + /* hostname type, length and hostname */ + *(ret++) = (uint8_t)TLSEXT_NAMETYPE_host_name; + s2n(size_str, ret); + memcpy(ret, s->tlsext_hostname, size_str); + ret += size_str; } - /* Decode each ServerName in the extension. */ - while (CBS_len(&server_name_list) > 0) { - uint8_t name_type; - CBS host_name; + /* Add RI if renegotiating */ + if (s->s3->initial_handshake_complete) { + int el; - if (!CBS_get_u8(&server_name_list, &name_type) || - !CBS_get_u16_length_prefixed(&server_name_list, &host_name)) { - return 0; - } - - /* Only host_name is supported. */ - if (name_type != TLSEXT_NAMETYPE_host_name) { - continue; - } - - if (have_seen_host_name) { - /* The ServerNameList MUST NOT contain more than one name of the same - * name_type. */ - return 0; + if (!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0)) { + OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; } - have_seen_host_name = 1; - - if (CBS_len(&host_name) == 0 || - CBS_len(&host_name) > TLSEXT_MAXLEN_host_name || - CBS_contains_zero_byte(&host_name)) { - *out_alert = SSL_AD_UNRECOGNIZED_NAME; - return 0; + if ((limit - ret - 4 - el) < 0) { + return NULL; } - if (!ssl->hit) { - assert(ssl->session->tlsext_hostname == NULL); - if (ssl->session->tlsext_hostname) { - /* This should be impossible. */ - return 0; - } - - /* Copy the hostname as a string. */ - if (!CBS_strdup(&host_name, &ssl->session->tlsext_hostname)) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; - } + s2n(TLSEXT_TYPE_renegotiate, ret); + s2n(el, ret); - ssl->s3->tmp.should_ack_sni = 1; + if (!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el)) { + OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; } - } - - return 1; -} - -static int ext_sni_add_serverhello(SSL *ssl, CBB *out) { - if (ssl->hit || - !ssl->s3->tmp.should_ack_sni || - ssl->session->tlsext_hostname == NULL) { - return 1; - } - - if (!CBB_add_u16(out, TLSEXT_TYPE_server_name) || - !CBB_add_u16(out, 0 /* length */)) { - return 0; - } - - return 1; -} - -/* Renegotiation indication. - * - * https://tools.ietf.org/html/rfc5746 */ - -static int ext_ri_add_clienthello(SSL *ssl, CBB *out) { - CBB contents, prev_finished; - if (!CBB_add_u16(out, TLSEXT_TYPE_renegotiate) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u8_length_prefixed(&contents, &prev_finished) || - !CBB_add_bytes(&prev_finished, ssl->s3->previous_client_finished, - ssl->s3->previous_client_finished_len) || - !CBB_flush(out)) { - return 0; + ret += el; } - return 1; -} - -static int ext_ri_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - /* No renegotiation extension received. - * - * Strictly speaking if we want to avoid an attack we should *always* see - * RI even on initial ServerHello because the client doesn't see any - * renegotiation during an attack. However this would mean we could not - * connect to any server which doesn't support RI. - * - * A lack of the extension is allowed if SSL_OP_LEGACY_SERVER_CONNECT is - * defined. */ - if (ssl->options & SSL_OP_LEGACY_SERVER_CONNECT) { - return 1; + /* Add extended master secret. */ + if (s->version != SSL3_VERSION) { + if (limit - ret - 4 < 0) { + return NULL; + } + s2n(TLSEXT_TYPE_extended_master_secret, ret); + s2n(0, ret); + } + + if (!(SSL_get_options(s) & SSL_OP_NO_TICKET)) { + int ticklen = 0; + /* Renegotiation does not participate in session resumption. However, still + * advertise the extension to avoid potentially breaking servers which carry + * over the state from the previous handshake, such as OpenSSL servers + * without upstream's 3c3f0259238594d77264a78944d409f2127642c4. */ + if (!s->s3->initial_handshake_complete && s->session != NULL && + s->session->tlsext_tick != NULL) { + ticklen = s->session->tlsext_ticklen; } - *out_alert = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); - return 0; + /* Check for enough room 2 for extension type, 2 for len rest for + * ticket. */ + if ((long)(limit - ret - 4 - ticklen) < 0) { + return NULL; + } + s2n(TLSEXT_TYPE_session_ticket, ret); + s2n(ticklen, ret); + if (ticklen) { + memcpy(ret, s->session->tlsext_tick, ticklen); + ret += ticklen; + } } - const size_t expected_len = ssl->s3->previous_client_finished_len + - ssl->s3->previous_server_finished_len; - - /* Check for logic errors */ - assert(!expected_len || ssl->s3->previous_client_finished_len); - assert(!expected_len || ssl->s3->previous_server_finished_len); - - /* Parse out the extension contents. */ - CBS renegotiated_connection; - if (!CBS_get_u8_length_prefixed(contents, &renegotiated_connection) || - CBS_len(contents) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_ENCODING_ERR); - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - return 0; - } + if (ssl3_version_from_wire(s, s->client_version) >= TLS1_2_VERSION) { + size_t salglen; + const uint8_t *salg; + salglen = tls12_get_psigalgs(s, &salg); + if ((size_t)(limit - ret) < salglen + 6) { + return NULL; + } + s2n(TLSEXT_TYPE_signature_algorithms, ret); + s2n(salglen + 2, ret); + s2n(salglen, ret); + memcpy(ret, salg, salglen); + ret += salglen; + } + + if (s->ocsp_stapling_enabled) { + /* The status_request extension is excessively extensible at every layer. + * On the client, only support requesting OCSP responses with an empty + * responder_id_list and no extensions. */ + if (limit - ret - 4 - 1 - 2 - 2 < 0) { + return NULL; + } - /* Check that the extension matches. */ - if (CBS_len(&renegotiated_connection) != expected_len) { - OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH); - *out_alert = SSL_AD_HANDSHAKE_FAILURE; - return 0; + s2n(TLSEXT_TYPE_status_request, ret); + s2n(1 + 2 + 2, ret); + /* status_type */ + *(ret++) = TLSEXT_STATUSTYPE_ocsp; + /* responder_id_list - empty */ + s2n(0, ret); + /* request_extensions - empty */ + s2n(0, ret); + } + + if (s->ctx->next_proto_select_cb && !s->s3->initial_handshake_complete && + !SSL_IS_DTLS(s)) { + /* The client advertises an emtpy extension to indicate its support for + * Next Protocol Negotiation */ + if (limit - ret - 4 < 0) { + return NULL; + } + s2n(TLSEXT_TYPE_next_proto_neg, ret); + s2n(0, ret); } - const uint8_t *d = CBS_data(&renegotiated_connection); - if (CRYPTO_memcmp(d, ssl->s3->previous_client_finished, - ssl->s3->previous_client_finished_len)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH); - *out_alert = SSL_AD_HANDSHAKE_FAILURE; - return 0; + if (s->signed_cert_timestamps_enabled) { + /* The client advertises an empty extension to indicate its support for + * certificate timestamps. */ + if (limit - ret - 4 < 0) { + return NULL; + } + s2n(TLSEXT_TYPE_certificate_timestamp, ret); + s2n(0, ret); } - d += ssl->s3->previous_client_finished_len; - if (CRYPTO_memcmp(d, ssl->s3->previous_server_finished, - ssl->s3->previous_server_finished_len)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH); - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - return 0; + if (s->alpn_client_proto_list && !s->s3->initial_handshake_complete) { + if ((size_t)(limit - ret) < 6 + s->alpn_client_proto_list_len) { + return NULL; + } + s2n(TLSEXT_TYPE_application_layer_protocol_negotiation, ret); + s2n(2 + s->alpn_client_proto_list_len, ret); + s2n(s->alpn_client_proto_list_len, ret); + memcpy(ret, s->alpn_client_proto_list, s->alpn_client_proto_list_len); + ret += s->alpn_client_proto_list_len; } - ssl->s3->send_connection_binding = 1; - return 1; -} - -static int ext_ri_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - /* Renegotiation isn't supported as a server so this function should never be - * called after the initial handshake. */ - assert(!ssl->s3->initial_handshake_complete); - - CBS fake_contents; - static const uint8_t kFakeExtension[] = {0}; - - if (contents == NULL) { - if (ssl->s3->send_connection_binding) { - /* The renegotiation SCSV was received so pretend that we received a - * renegotiation extension. */ - CBS_init(&fake_contents, kFakeExtension, sizeof(kFakeExtension)); - contents = &fake_contents; - /* We require that the renegotiation extension is at index zero of - * kExtensions. */ - ssl->s3->tmp.extensions.received |= (1u << 0); + if (s->tlsext_channel_id_enabled && !SSL_IS_DTLS(s)) { + /* The client advertises an emtpy extension to indicate its support for + * Channel ID. */ + if (limit - ret - 4 < 0) { + return NULL; + } + if (s->ctx->tlsext_channel_id_enabled_new) { + s2n(TLSEXT_TYPE_channel_id_new, ret); } else { - return 1; + s2n(TLSEXT_TYPE_channel_id, ret); } + s2n(0, ret); } - CBS renegotiated_connection; - - if (!CBS_get_u8_length_prefixed(contents, &renegotiated_connection) || - CBS_len(contents) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_ENCODING_ERR); - return 0; - } - - /* Check that the extension matches */ - if (!CBS_mem_equal(&renegotiated_connection, ssl->s3->previous_client_finished, - ssl->s3->previous_client_finished_len)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH); - *out_alert = SSL_AD_HANDSHAKE_FAILURE; - return 0; - } - - ssl->s3->send_connection_binding = 1; - - return 1; -} + if (SSL_get_srtp_profiles(s)) { + int el; -static int ext_ri_add_serverhello(SSL *ssl, CBB *out) { - CBB contents, prev_finished; - if (!CBB_add_u16(out, TLSEXT_TYPE_renegotiate) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u8_length_prefixed(&contents, &prev_finished) || - !CBB_add_bytes(&prev_finished, ssl->s3->previous_client_finished, - ssl->s3->previous_client_finished_len) || - !CBB_add_bytes(&prev_finished, ssl->s3->previous_server_finished, - ssl->s3->previous_server_finished_len) || - !CBB_flush(out)) { - return 0; - } - - return 1; -} - - -/* Extended Master Secret. - * - * https://tools.ietf.org/html/draft-ietf-tls-session-hash-05 */ - -static void ext_ems_init(SSL *ssl) { - ssl->s3->tmp.extended_master_secret = 0; -} - -static int ext_ems_add_clienthello(SSL *ssl, CBB *out) { - if (ssl->version == SSL3_VERSION) { - return 1; - } - - if (!CBB_add_u16(out, TLSEXT_TYPE_extended_master_secret) || - !CBB_add_u16(out, 0 /* length */)) { - return 0; - } + ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0); - return 1; -} - -static int ext_ems_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } - - if (ssl->version == SSL3_VERSION || CBS_len(contents) != 0) { - return 0; - } - - ssl->s3->tmp.extended_master_secret = 1; - return 1; -} - -static int ext_ems_parse_clienthello(SSL *ssl, uint8_t *out_alert, CBS *contents) { - if (ssl->version == SSL3_VERSION || contents == NULL) { - return 1; - } - - if (CBS_len(contents) != 0) { - return 0; - } - - ssl->s3->tmp.extended_master_secret = 1; - return 1; -} - -static int ext_ems_add_serverhello(SSL *ssl, CBB *out) { - if (!ssl->s3->tmp.extended_master_secret) { - return 1; - } - - if (!CBB_add_u16(out, TLSEXT_TYPE_extended_master_secret) || - !CBB_add_u16(out, 0 /* length */)) { - return 0; - } - - return 1; -} - - -/* Session tickets. - * - * https://tools.ietf.org/html/rfc5077 */ - -static int ext_ticket_add_clienthello(SSL *ssl, CBB *out) { - if (SSL_get_options(ssl) & SSL_OP_NO_TICKET) { - return 1; - } - - const uint8_t *ticket_data = NULL; - int ticket_len = 0; - - /* Renegotiation does not participate in session resumption. However, still - * advertise the extension to avoid potentially breaking servers which carry - * over the state from the previous handshake, such as OpenSSL servers - * without upstream's 3c3f0259238594d77264a78944d409f2127642c4. */ - if (!ssl->s3->initial_handshake_complete && - ssl->session != NULL && - ssl->session->tlsext_tick != NULL) { - ticket_data = ssl->session->tlsext_tick; - ticket_len = ssl->session->tlsext_ticklen; - } - - CBB ticket; - if (!CBB_add_u16(out, TLSEXT_TYPE_session_ticket) || - !CBB_add_u16_length_prefixed(out, &ticket) || - !CBB_add_bytes(&ticket, ticket_data, ticket_len) || - !CBB_flush(out)) { - return 0; - } - - return 1; -} - -static int ext_ticket_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - ssl->tlsext_ticket_expected = 0; - - if (contents == NULL) { - return 1; - } - - /* If |SSL_OP_NO_TICKET| is set then no extension will have been sent and - * this function should never be called, even if the server tries to send the - * extension. */ - assert((SSL_get_options(ssl) & SSL_OP_NO_TICKET) == 0); - - if (CBS_len(contents) != 0) { - return 0; - } - - ssl->tlsext_ticket_expected = 1; - return 1; -} - -static int ext_ticket_parse_clienthello(SSL *ssl, uint8_t *out_alert, CBS *contents) { - /* This function isn't used because the ticket extension from the client is - * handled in ssl_sess.c. */ - return 1; -} - -static int ext_ticket_add_serverhello(SSL *ssl, CBB *out) { - if (!ssl->tlsext_ticket_expected) { - return 1; - } + if ((limit - ret - 4 - el) < 0) { + return NULL; + } - /* If |SSL_OP_NO_TICKET| is set, |tlsext_ticket_expected| should never be - * true. */ - assert((SSL_get_options(ssl) & SSL_OP_NO_TICKET) == 0); + s2n(TLSEXT_TYPE_use_srtp, ret); + s2n(el, ret); - if (!CBB_add_u16(out, TLSEXT_TYPE_session_ticket) || - !CBB_add_u16(out, 0 /* length */)) { - return 0; + if (!ssl_add_clienthello_use_srtp_ext(s, ret, &el, el)) { + OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; + } + ret += el; } - return 1; -} - - -/* Signature Algorithms. - * - * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ - -static int ext_sigalgs_add_clienthello(SSL *ssl, CBB *out) { - if (ssl3_version_from_wire(ssl, ssl->client_version) < TLS1_2_VERSION) { - return 1; - } + if (using_ecc) { + /* Add TLS extension ECPointFormats to the ClientHello message */ + long lenmax; + const uint8_t *formats; + const uint16_t *curves; + size_t formats_len, curves_len, i; - const uint8_t *sigalgs_data; - const size_t sigalgs_len = tls12_get_psigalgs(ssl, &sigalgs_data); + tls1_get_formatlist(s, &formats, &formats_len); - CBB contents, sigalgs; - if (!CBB_add_u16(out, TLSEXT_TYPE_signature_algorithms) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &sigalgs) || - !CBB_add_bytes(&sigalgs, sigalgs_data, sigalgs_len) || - !CBB_flush(out)) { - return 0; - } + lenmax = limit - ret - 5; + if (lenmax < 0) { + return NULL; + } + if (formats_len > (size_t)lenmax) { + return NULL; + } + if (formats_len > 255) { + OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; + } - return 1; -} + s2n(TLSEXT_TYPE_ec_point_formats, ret); + s2n(formats_len + 1, ret); + *(ret++) = (uint8_t)formats_len; + memcpy(ret, formats, formats_len); + ret += formats_len; -static int ext_sigalgs_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents != NULL) { - /* Servers MUST NOT send this extension. */ - *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; - OPENSSL_PUT_ERROR(SSL, SSL_R_SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER); - return 0; - } + /* Add TLS extension EllipticCurves to the ClientHello message */ + tls1_get_curvelist(s, 0, &curves, &curves_len); - return 1; -} + lenmax = limit - ret - 6; + if (lenmax < 0) { + return NULL; + } + if (curves_len * 2 > (size_t)lenmax) { + return NULL; + } + if (curves_len * 2 > 65532) { + OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; + } -static int ext_sigalgs_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - OPENSSL_free(ssl->cert->peer_sigalgs); - ssl->cert->peer_sigalgs = NULL; - ssl->cert->peer_sigalgslen = 0; + s2n(TLSEXT_TYPE_elliptic_curves, ret); + s2n((curves_len * 2) + 2, ret); - if (contents == NULL) { - return 1; - } - - CBS supported_signature_algorithms; - if (!CBS_get_u16_length_prefixed(contents, &supported_signature_algorithms) || - CBS_len(contents) != 0 || - CBS_len(&supported_signature_algorithms) == 0 || - !tls1_parse_peer_sigalgs(ssl, &supported_signature_algorithms)) { - return 0; + s2n(curves_len * 2, ret); + for (i = 0; i < curves_len; i++) { + s2n(curves[i], ret); + } } - return 1; -} - -static int ext_sigalgs_add_serverhello(SSL *ssl, CBB *out) { - /* Servers MUST NOT send this extension. */ - return 1; -} - - -/* OCSP Stapling. - * - * https://tools.ietf.org/html/rfc6066#section-8 */ + if (header_len > 0) { + size_t clienthello_minsize = 0; + header_len += ret - orig; + if (header_len > 0xff && header_len < 0x200) { + /* Add padding to workaround bugs in F5 terminators. See + * https://tools.ietf.org/html/draft-agl-tls-padding-03 + * + * NB: because this code works out the length of all existing extensions + * it MUST always appear last. */ + clienthello_minsize = 0x200; + } + if (s->fastradio_padding) { + /* Pad the ClientHello record to 1024 bytes to fast forward the radio + * into DCH (high data rate) state in 3G networks. Note that when + * fastradio_padding is enabled, even if the header_len is less than 255 + * bytes, the padding will be applied regardless. This is slightly + * different from the TLS padding extension suggested in + * https://tools.ietf.org/html/draft-agl-tls-padding-03 */ + clienthello_minsize = 0x400; + } + if (header_len < clienthello_minsize) { + size_t padding_len = clienthello_minsize - header_len; + /* Extensions take at least four bytes to encode. Always include least + * one byte of data if including the extension. WebSphere Application + * Server 7.0 is intolerant to the last extension being zero-length. */ + if (padding_len >= 4 + 1) { + padding_len -= 4; + } else { + padding_len = 1; + } -static void ext_ocsp_init(SSL *ssl) { - ssl->s3->tmp.certificate_status_expected = 0; -} + if (limit - ret - 4 - (long)padding_len < 0) { + return NULL; + } -static int ext_ocsp_add_clienthello(SSL *ssl, CBB *out) { - if (!ssl->ocsp_stapling_enabled) { - return 1; + s2n(TLSEXT_TYPE_padding, ret); + s2n(padding_len, ret); + memset(ret, 0, padding_len); + ret += padding_len; + } } - CBB contents; - if (!CBB_add_u16(out, TLSEXT_TYPE_status_request) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u8(&contents, TLSEXT_STATUSTYPE_ocsp) || - !CBB_add_u16(&contents, 0 /* empty responder ID list */) || - !CBB_add_u16(&contents, 0 /* empty request extensions */) || - !CBB_flush(out)) { - return 0; + extdatalen = ret - orig - 2; + if (extdatalen == 0) { + return orig; } - return 1; + s2n(extdatalen, orig); + return ret; } -static int ext_ocsp_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } - - if (CBS_len(contents) != 0) { - return 0; - } - - ssl->s3->tmp.certificate_status_expected = 1; - return 1; -} +uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit) { + int extdatalen = 0; + uint8_t *orig = buf; + uint8_t *ret = buf; + int next_proto_neg_seen; + uint32_t alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + uint32_t alg_a = s->s3->tmp.new_cipher->algorithm_auth; + int using_ecc = (alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA); + using_ecc = using_ecc && (s->s3->tmp.peer_ecpointformatlist != NULL); -static int ext_ocsp_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; + /* don't add extensions for SSLv3, unless doing secure renegotiation */ + if (s->version == SSL3_VERSION && !s->s3->send_connection_binding) { + return orig; } - uint8_t status_type; - if (!CBS_get_u8(contents, &status_type)) { - return 0; + ret += 2; + if (ret >= limit) { + return NULL; /* should never happen. */ } - /* We cannot decide whether OCSP stapling will occur yet because the correct - * SSL_CTX might not have been selected. */ - ssl->s3->tmp.ocsp_stapling_requested = status_type == TLSEXT_STATUSTYPE_ocsp; - - return 1; -} + if (!s->hit && s->should_ack_sni && s->session->tlsext_hostname != NULL) { + if ((long)(limit - ret - 4) < 0) { + return NULL; + } -static int ext_ocsp_add_serverhello(SSL *ssl, CBB *out) { - /* The extension shouldn't be sent when resuming sessions. */ - if (ssl->hit || - !ssl->s3->tmp.ocsp_stapling_requested || - ssl->ctx->ocsp_response_length == 0) { - return 1; + s2n(TLSEXT_TYPE_server_name, ret); + s2n(0, ret); } - ssl->s3->tmp.certificate_status_expected = 1; - - return CBB_add_u16(out, TLSEXT_TYPE_status_request) && - CBB_add_u16(out, 0 /* length */); -} - - -/* Next protocol negotiation. - * - * https://htmlpreview.github.io/?https://github.com/agl/technotes/blob/master/nextprotoneg.html */ - -static void ext_npn_init(SSL *ssl) { - ssl->s3->next_proto_neg_seen = 0; -} - -static int ext_npn_add_clienthello(SSL *ssl, CBB *out) { - if (ssl->s3->initial_handshake_complete || - ssl->ctx->next_proto_select_cb == NULL || - SSL_IS_DTLS(ssl)) { - return 1; - } + if (s->s3->send_connection_binding) { + int el; - if (!CBB_add_u16(out, TLSEXT_TYPE_next_proto_neg) || - !CBB_add_u16(out, 0 /* length */)) { - return 0; - } + if (!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0)) { + OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; + } - return 1; -} + if ((limit - ret - 4 - el) < 0) { + return NULL; + } -static int ext_npn_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } + s2n(TLSEXT_TYPE_renegotiate, ret); + s2n(el, ret); - /* If any of these are false then we should never have sent the NPN - * extension in the ClientHello and thus this function should never have been - * called. */ - assert(!ssl->s3->initial_handshake_complete); - assert(!SSL_IS_DTLS(ssl)); - assert(ssl->ctx->next_proto_select_cb != NULL); + if (!ssl_add_serverhello_renegotiate_ext(s, ret, &el, el)) { + OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; + } - if (ssl->s3->alpn_selected != NULL) { - /* NPN and ALPN may not be negotiated in the same connection. */ - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_BOTH_NPN_AND_ALPN); - return 0; + ret += el; } - const uint8_t *const orig_contents = CBS_data(contents); - const size_t orig_len = CBS_len(contents); - - while (CBS_len(contents) != 0) { - CBS proto; - if (!CBS_get_u8_length_prefixed(contents, &proto) || - CBS_len(&proto) == 0) { - return 0; + if (s->s3->tmp.extended_master_secret) { + if ((long)(limit - ret - 4) < 0) { + return NULL; } - } - - uint8_t *selected; - uint8_t selected_len; - if (ssl->ctx->next_proto_select_cb( - ssl, &selected, &selected_len, orig_contents, orig_len, - ssl->ctx->next_proto_select_cb_arg) != SSL_TLSEXT_ERR_OK) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; - } - OPENSSL_free(ssl->next_proto_negotiated); - ssl->next_proto_negotiated = BUF_memdup(selected, selected_len); - if (ssl->next_proto_negotiated == NULL) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; + s2n(TLSEXT_TYPE_extended_master_secret, ret); + s2n(0, ret); } - ssl->next_proto_negotiated_len = selected_len; - ssl->s3->next_proto_neg_seen = 1; - - return 1; -} - -static int ext_npn_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents != NULL && CBS_len(contents) != 0) { - return 0; - } + if (using_ecc) { + const uint8_t *plist; + size_t plistlen; + /* Add TLS extension ECPointFormats to the ServerHello message */ + long lenmax; - if (contents == NULL || - ssl->s3->initial_handshake_complete || - /* If the ALPN extension is seen before NPN, ignore it. (If ALPN is seen - * afterwards, parsing the ALPN extension will clear - * |next_proto_neg_seen|. */ - ssl->s3->alpn_selected != NULL || - ssl->ctx->next_protos_advertised_cb == NULL || - SSL_IS_DTLS(ssl)) { - return 1; - } + tls1_get_formatlist(s, &plist, &plistlen); - ssl->s3->next_proto_neg_seen = 1; - return 1; -} + lenmax = limit - ret - 5; + if (lenmax < 0) { + return NULL; + } + if (plistlen > (size_t)lenmax) { + return NULL; + } + if (plistlen > 255) { + OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; + } -static int ext_npn_add_serverhello(SSL *ssl, CBB *out) { - /* |next_proto_neg_seen| might have been cleared when an ALPN extension was - * parsed. */ - if (!ssl->s3->next_proto_neg_seen) { - return 1; + s2n(TLSEXT_TYPE_ec_point_formats, ret); + s2n(plistlen + 1, ret); + *(ret++) = (uint8_t)plistlen; + memcpy(ret, plist, plistlen); + ret += plistlen; } + /* Currently the server should not respond with a SupportedCurves extension */ - const uint8_t *npa; - unsigned npa_len; - - if (ssl->ctx->next_protos_advertised_cb( - ssl, &npa, &npa_len, ssl->ctx->next_protos_advertised_cb_arg) != - SSL_TLSEXT_ERR_OK) { - ssl->s3->next_proto_neg_seen = 0; - return 1; + if (s->tlsext_ticket_expected && !(SSL_get_options(s) & SSL_OP_NO_TICKET)) { + if ((long)(limit - ret - 4) < 0) { + return NULL; + } + s2n(TLSEXT_TYPE_session_ticket, ret); + s2n(0, ret); } - CBB contents; - if (!CBB_add_u16(out, TLSEXT_TYPE_next_proto_neg) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_bytes(&contents, npa, npa_len) || - !CBB_flush(out)) { - return 0; + if (s->s3->tmp.certificate_status_expected) { + if ((long)(limit - ret - 4) < 0) { + return NULL; + } + s2n(TLSEXT_TYPE_status_request, ret); + s2n(0, ret); } - return 1; -} + if (s->srtp_profile) { + int el; + ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0); -/* Signed certificate timestamps. - * - * https://tools.ietf.org/html/rfc6962#section-3.3.1 */ + if ((limit - ret - 4 - el) < 0) { + return NULL; + } -static int ext_sct_add_clienthello(SSL *ssl, CBB *out) { - if (!ssl->signed_cert_timestamps_enabled) { - return 1; - } + s2n(TLSEXT_TYPE_use_srtp, ret); + s2n(el, ret); - if (!CBB_add_u16(out, TLSEXT_TYPE_certificate_timestamp) || - !CBB_add_u16(out, 0 /* length */)) { - return 0; + if (!ssl_add_serverhello_use_srtp_ext(s, ret, &el, el)) { + OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; + } + ret += el; } - return 1; -} + next_proto_neg_seen = s->s3->next_proto_neg_seen; + s->s3->next_proto_neg_seen = 0; + if (next_proto_neg_seen && s->ctx->next_protos_advertised_cb) { + const uint8_t *npa; + unsigned int npalen; + int r; -static int ext_sct_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; + r = s->ctx->next_protos_advertised_cb( + s, &npa, &npalen, s->ctx->next_protos_advertised_cb_arg); + if (r == SSL_TLSEXT_ERR_OK) { + if ((long)(limit - ret - 4 - npalen) < 0) { + return NULL; + } + s2n(TLSEXT_TYPE_next_proto_neg, ret); + s2n(npalen, ret); + memcpy(ret, npa, npalen); + ret += npalen; + s->s3->next_proto_neg_seen = 1; + } } - /* If this is false then we should never have sent the SCT extension in the - * ClientHello and thus this function should never have been called. */ - assert(ssl->signed_cert_timestamps_enabled); - - if (CBS_len(contents) == 0) { - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } + if (s->s3->alpn_selected) { + const uint8_t *selected = s->s3->alpn_selected; + size_t len = s->s3->alpn_selected_len; - /* Session resumption uses the original session information. */ - if (!ssl->hit && - !CBS_stow(contents, &ssl->session->tlsext_signed_cert_timestamp_list, - &ssl->session->tlsext_signed_cert_timestamp_list_length)) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; + if ((long)(limit - ret - 4 - 2 - 1 - len) < 0) { + return NULL; + } + s2n(TLSEXT_TYPE_application_layer_protocol_negotiation, ret); + s2n(3 + len, ret); + s2n(1 + len, ret); + *ret++ = len; + memcpy(ret, selected, len); + ret += len; + } + + /* If the client advertised support for Channel ID, and we have it + * enabled, then we want to echo it back. */ + if (s->s3->tlsext_channel_id_valid) { + if (limit - ret - 4 < 0) { + return NULL; + } + if (s->s3->tlsext_channel_id_new) { + s2n(TLSEXT_TYPE_channel_id_new, ret); + } else { + s2n(TLSEXT_TYPE_channel_id, ret); + } + s2n(0, ret); } - return 1; -} - -static int ext_sct_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - return contents == NULL || CBS_len(contents) == 0; -} - -static int ext_sct_add_serverhello(SSL *ssl, CBB *out) { - /* The extension shouldn't be sent when resuming sessions. */ - if (ssl->hit || - ssl->ctx->signed_cert_timestamp_list_length == 0) { - return 1; + extdatalen = ret - orig - 2; + if (extdatalen == 0) { + return orig; } - CBB contents; - return CBB_add_u16(out, TLSEXT_TYPE_certificate_timestamp) && - CBB_add_u16_length_prefixed(out, &contents) && - CBB_add_bytes(&contents, ssl->ctx->signed_cert_timestamp_list, - ssl->ctx->signed_cert_timestamp_list_length) && - CBB_flush(out); + s2n(extdatalen, orig); + return ret; } - -/* Application-level Protocol Negotiation. +/* tls1_alpn_handle_client_hello is called to process the ALPN extension in a + * ClientHello. + * cbs: the contents of the extension, not including the type and length. + * out_alert: a pointer to the alert value to send in the event of a zero + * return. * - * https://tools.ietf.org/html/rfc7301 */ - -static void ext_alpn_init(SSL *ssl) { - OPENSSL_free(ssl->s3->alpn_selected); - ssl->s3->alpn_selected = NULL; -} - -static int ext_alpn_add_clienthello(SSL *ssl, CBB *out) { - if (ssl->alpn_client_proto_list == NULL || - ssl->s3->initial_handshake_complete) { - return 1; - } - - CBB contents, proto_list; - if (!CBB_add_u16(out, TLSEXT_TYPE_application_layer_protocol_negotiation) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &proto_list) || - !CBB_add_bytes(&proto_list, ssl->alpn_client_proto_list, - ssl->alpn_client_proto_list_len) || - !CBB_flush(out)) { - return 0; - } - - return 1; -} - -static int ext_alpn_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } - - assert(!ssl->s3->initial_handshake_complete); - assert(ssl->alpn_client_proto_list != NULL); - - if (ssl->s3->next_proto_neg_seen) { - /* NPN and ALPN may not be negotiated in the same connection. */ - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_BOTH_NPN_AND_ALPN); - return 0; - } - - /* The extension data consists of a ProtocolNameList which must have - * exactly one ProtocolName. Each of these is length-prefixed. */ - CBS protocol_name_list, protocol_name; - if (!CBS_get_u16_length_prefixed(contents, &protocol_name_list) || - CBS_len(contents) != 0 || - !CBS_get_u8_length_prefixed(&protocol_name_list, &protocol_name) || - /* Empty protocol names are forbidden. */ - CBS_len(&protocol_name) == 0 || - CBS_len(&protocol_name_list) != 0) { - return 0; - } - - if (!CBS_stow(&protocol_name, &ssl->s3->alpn_selected, - &ssl->s3->alpn_selected_len)) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; - } - - return 1; -} - -static int ext_alpn_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } + * returns: 1 on success. */ +static int tls1_alpn_handle_client_hello(SSL *s, CBS *cbs, int *out_alert) { + CBS protocol_name_list, protocol_name_list_copy; + const uint8_t *selected; + uint8_t selected_len; + int r; - if (ssl->ctx->alpn_select_cb == NULL || - ssl->s3->initial_handshake_complete) { + if (s->ctx->alpn_select_cb == NULL) { return 1; } - /* ALPN takes precedence over NPN. */ - ssl->s3->next_proto_neg_seen = 0; - - CBS protocol_name_list; - if (!CBS_get_u16_length_prefixed(contents, &protocol_name_list) || - CBS_len(contents) != 0 || - CBS_len(&protocol_name_list) < 2) { - return 0; + if (!CBS_get_u16_length_prefixed(cbs, &protocol_name_list) || + CBS_len(cbs) != 0 || CBS_len(&protocol_name_list) < 2) { + goto parse_error; } /* Validate the protocol list. */ - CBS protocol_name_list_copy = protocol_name_list; + protocol_name_list_copy = protocol_name_list; while (CBS_len(&protocol_name_list_copy) > 0) { CBS protocol_name; - if (!CBS_get_u8_length_prefixed(&protocol_name_list_copy, &protocol_name) || - /* Empty protocol names are forbidden. */ - CBS_len(&protocol_name) == 0) { - return 0; + if (!CBS_get_u8_length_prefixed(&protocol_name_list_copy, &protocol_name)) { + goto parse_error; } } - const uint8_t *selected; - uint8_t selected_len; - if (ssl->ctx->alpn_select_cb( - ssl, &selected, &selected_len, CBS_data(&protocol_name_list), - CBS_len(&protocol_name_list), - ssl->ctx->alpn_select_cb_arg) == SSL_TLSEXT_ERR_OK) { - OPENSSL_free(ssl->s3->alpn_selected); - ssl->s3->alpn_selected = BUF_memdup(selected, selected_len); - if (ssl->s3->alpn_selected == NULL) { + r = s->ctx->alpn_select_cb( + s, &selected, &selected_len, CBS_data(&protocol_name_list), + CBS_len(&protocol_name_list), s->ctx->alpn_select_cb_arg); + if (r == SSL_TLSEXT_ERR_OK) { + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = BUF_memdup(selected, selected_len); + if (!s->s3->alpn_selected) { *out_alert = SSL_AD_INTERNAL_ERROR; return 0; } - ssl->s3->alpn_selected_len = selected_len; - } - - return 1; -} - -static int ext_alpn_add_serverhello(SSL *ssl, CBB *out) { - if (ssl->s3->alpn_selected == NULL) { - return 1; - } - - CBB contents, proto_list, proto; - if (!CBB_add_u16(out, TLSEXT_TYPE_application_layer_protocol_negotiation) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &proto_list) || - !CBB_add_u8_length_prefixed(&proto_list, &proto) || - !CBB_add_bytes(&proto, ssl->s3->alpn_selected, ssl->s3->alpn_selected_len) || - !CBB_flush(out)) { - return 0; + s->s3->alpn_selected_len = selected_len; } return 1; -} - - -/* Channel ID. - * - * https://tools.ietf.org/html/draft-balfanz-tls-channelid-01 */ - -static void ext_channel_id_init(SSL *ssl) { - ssl->s3->tlsext_channel_id_valid = 0; -} - -static int ext_channel_id_add_clienthello(SSL *ssl, CBB *out) { - if (!ssl->tlsext_channel_id_enabled || - SSL_IS_DTLS(ssl)) { - return 1; - } - - if (!CBB_add_u16(out, TLSEXT_TYPE_channel_id) || - !CBB_add_u16(out, 0 /* length */)) { - return 0; - } - return 1; +parse_error: + *out_alert = SSL_AD_DECODE_ERROR; + return 0; } -static int ext_channel_id_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } +static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) { + int renegotiate_seen = 0; + CBS extensions; - assert(!SSL_IS_DTLS(ssl)); - assert(ssl->tlsext_channel_id_enabled); + s->should_ack_sni = 0; + s->srtp_profile = NULL; + s->s3->next_proto_neg_seen = 0; + s->s3->tmp.certificate_status_expected = 0; + s->s3->tmp.extended_master_secret = 0; - if (CBS_len(contents) != 0) { - return 0; - } + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = NULL; - ssl->s3->tlsext_channel_id_valid = 1; - return 1; -} + /* Clear any signature algorithms extension received */ + OPENSSL_free(s->cert->peer_sigalgs); + s->cert->peer_sigalgs = NULL; + s->cert->peer_sigalgslen = 0; -static int ext_channel_id_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL || - !ssl->tlsext_channel_id_enabled || - SSL_IS_DTLS(ssl)) { - return 1; - } + /* Clear any shared signature algorithms */ + OPENSSL_free(s->cert->shared_sigalgs); + s->cert->shared_sigalgs = NULL; + s->cert->shared_sigalgslen = 0; - if (CBS_len(contents) != 0) { - return 0; - } + /* Clear ECC extensions */ + OPENSSL_free(s->s3->tmp.peer_ecpointformatlist); + s->s3->tmp.peer_ecpointformatlist = NULL; + s->s3->tmp.peer_ecpointformatlist_length = 0; - ssl->s3->tlsext_channel_id_valid = 1; - return 1; -} + OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist); + s->s3->tmp.peer_ellipticcurvelist = NULL; + s->s3->tmp.peer_ellipticcurvelist_length = 0; -static int ext_channel_id_add_serverhello(SSL *ssl, CBB *out) { - if (!ssl->s3->tlsext_channel_id_valid) { - return 1; + /* There may be no extensions. */ + if (CBS_len(cbs) == 0) { + goto ri_check; } - if (!CBB_add_u16(out, TLSEXT_TYPE_channel_id) || - !CBB_add_u16(out, 0 /* length */)) { + /* Decode the extensions block and check it is valid. */ + if (!CBS_get_u16_length_prefixed(cbs, &extensions) || + !tls1_check_duplicate_extensions(&extensions)) { + *out_alert = SSL_AD_DECODE_ERROR; return 0; } - return 1; -} - - -/* Secure Real-time Transport Protocol (SRTP) extension. - * - * https://tools.ietf.org/html/rfc5764 */ - - -static void ext_srtp_init(SSL *ssl) { - ssl->srtp_profile = NULL; -} - -static int ext_srtp_add_clienthello(SSL *ssl, CBB *out) { - STACK_OF(SRTP_PROTECTION_PROFILE) *profiles = SSL_get_srtp_profiles(ssl); - if (profiles == NULL) { - return 1; - } - const size_t num_profiles = sk_SRTP_PROTECTION_PROFILE_num(profiles); - if (num_profiles == 0) { - return 1; - } - - CBB contents, profile_ids; - if (!CBB_add_u16(out, TLSEXT_TYPE_srtp) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &profile_ids)) { - return 0; - } + while (CBS_len(&extensions) != 0) { + uint16_t type; + CBS extension; - size_t i; - for (i = 0; i < num_profiles; i++) { - if (!CBB_add_u16(&profile_ids, - sk_SRTP_PROTECTION_PROFILE_value(profiles, i)->id)) { + /* Decode the next extension. */ + if (!CBS_get_u16(&extensions, &type) || + !CBS_get_u16_length_prefixed(&extensions, &extension)) { + *out_alert = SSL_AD_DECODE_ERROR; return 0; } - } - - if (!CBB_add_u8(&contents, 0 /* empty use_mki value */) || - !CBB_flush(out)) { - return 0; - } - return 1; -} + /* The servername extension is treated as follows: + + - Only the hostname type is supported with a maximum length of 255. + - The servername is rejected if too long or if it contains zeros, in + which case an fatal alert is generated. + - The servername field is maintained together with the session cache. + - When a session is resumed, the servername call back invoked in order + to allow the application to position itself to the right context. + - The servername is acknowledged if it is new for a session or when + it is identical to a previously used for the same session. + Applications can control the behaviour. They can at any time + set a 'desirable' servername for a new SSL object. This can be the + case for example with HTTPS when a Host: header field is received and + a renegotiation is requested. In this case, a possible servername + presented in the new client hello is only acknowledged if it matches + the value of the Host: field. + - Applications must use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION + if they provide for changing an explicit servername context for the + session, + i.e. when the session has been established with a servername extension. + - On session reconnect, the servername extension may be absent. */ + + if (type == TLSEXT_TYPE_server_name) { + CBS server_name_list; + char have_seen_host_name = 0; + + if (!CBS_get_u16_length_prefixed(&extension, &server_name_list) || + CBS_len(&server_name_list) < 1 || CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } -static int ext_srtp_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } + /* Decode each ServerName in the extension. */ + while (CBS_len(&server_name_list) > 0) { + uint8_t name_type; + CBS host_name; - /* The extension consists of a u16-prefixed profile ID list containing a - * single uint16_t profile ID, then followed by a u8-prefixed srtp_mki field. - * - * See https://tools.ietf.org/html/rfc5764#section-4.1.1 */ - CBS profile_ids, srtp_mki; - uint16_t profile_id; - if (!CBS_get_u16_length_prefixed(contents, &profile_ids) || - !CBS_get_u16(&profile_ids, &profile_id) || - CBS_len(&profile_ids) != 0 || - !CBS_get_u8_length_prefixed(contents, &srtp_mki) || - CBS_len(contents) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - return 0; - } + /* Decode the NameType. */ + if (!CBS_get_u8(&server_name_list, &name_type)) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - if (CBS_len(&srtp_mki) != 0) { - /* Must be no MKI, since we never offer one. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_MKI_VALUE); - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - return 0; - } + /* Only host_name is supported. */ + if (name_type != TLSEXT_NAMETYPE_host_name) { + continue; + } - STACK_OF(SRTP_PROTECTION_PROFILE) *profiles = SSL_get_srtp_profiles(ssl); + if (have_seen_host_name) { + /* The ServerNameList MUST NOT contain more than one name of the same + * name_type. */ + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - /* Check to see if the server gave us something we support (and presumably - * offered). */ - size_t i; - for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(profiles); i++) { - const SRTP_PROTECTION_PROFILE *profile = - sk_SRTP_PROTECTION_PROFILE_value(profiles, i); + have_seen_host_name = 1; - if (profile->id == profile_id) { - ssl->srtp_profile = profile; - return 1; - } - } + if (!CBS_get_u16_length_prefixed(&server_name_list, &host_name) || + CBS_len(&host_name) < 1) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - return 0; -} + if (CBS_len(&host_name) > TLSEXT_MAXLEN_host_name || + CBS_contains_zero_byte(&host_name)) { + *out_alert = SSL_AD_UNRECOGNIZED_NAME; + return 0; + } -static int ext_srtp_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } + if (!s->hit) { + assert(s->session->tlsext_hostname == NULL); + if (s->session->tlsext_hostname) { + /* This should be impossible. */ + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + + /* Copy the hostname as a string. */ + if (!CBS_strdup(&host_name, &s->session->tlsext_hostname)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + + s->should_ack_sni = 1; + } + } + } else if (type == TLSEXT_TYPE_ec_point_formats) { + CBS ec_point_format_list; - CBS profile_ids, srtp_mki; - if (!CBS_get_u16_length_prefixed(contents, &profile_ids) || - CBS_len(&profile_ids) < 2 || - !CBS_get_u8_length_prefixed(contents, &srtp_mki) || - CBS_len(contents) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - return 0; - } - /* Discard the MKI value for now. */ + if (!CBS_get_u8_length_prefixed(&extension, &ec_point_format_list) || + CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - const STACK_OF(SRTP_PROTECTION_PROFILE) *server_profiles = - SSL_get_srtp_profiles(ssl); + if (!CBS_stow(&ec_point_format_list, &s->s3->tmp.peer_ecpointformatlist, + &s->s3->tmp.peer_ecpointformatlist_length)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + } else if (type == TLSEXT_TYPE_elliptic_curves) { + CBS elliptic_curve_list; + size_t i, num_curves; + + if (!CBS_get_u16_length_prefixed(&extension, &elliptic_curve_list) || + CBS_len(&elliptic_curve_list) == 0 || + (CBS_len(&elliptic_curve_list) & 1) != 0 || + CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - /* Pick the server's most preferred profile. */ - size_t i; - for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(server_profiles); i++) { - const SRTP_PROTECTION_PROFILE *server_profile = - sk_SRTP_PROTECTION_PROFILE_value(server_profiles, i); + OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist); + s->s3->tmp.peer_ellipticcurvelist_length = 0; - CBS profile_ids_tmp; - CBS_init(&profile_ids_tmp, CBS_data(&profile_ids), CBS_len(&profile_ids)); + s->s3->tmp.peer_ellipticcurvelist = + (uint16_t *)OPENSSL_malloc(CBS_len(&elliptic_curve_list)); - while (CBS_len(&profile_ids_tmp) > 0) { - uint16_t profile_id; - if (!CBS_get_u16(&profile_ids_tmp, &profile_id)) { + if (s->s3->tmp.peer_ellipticcurvelist == NULL) { + *out_alert = SSL_AD_INTERNAL_ERROR; return 0; } - if (server_profile->id == profile_id) { - ssl->srtp_profile = server_profile; - return 1; + num_curves = CBS_len(&elliptic_curve_list) / 2; + for (i = 0; i < num_curves; i++) { + if (!CBS_get_u16(&elliptic_curve_list, + &s->s3->tmp.peer_ellipticcurvelist[i])) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } } - } - } - - return 1; -} - -static int ext_srtp_add_serverhello(SSL *ssl, CBB *out) { - if (ssl->srtp_profile == NULL) { - return 1; - } - CBB contents, profile_ids; - if (!CBB_add_u16(out, TLSEXT_TYPE_srtp) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &profile_ids) || - !CBB_add_u16(&profile_ids, ssl->srtp_profile->id) || - !CBB_add_u8(&contents, 0 /* empty MKI */) || - !CBB_flush(out)) { - return 0; - } + if (CBS_len(&elliptic_curve_list) != 0) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } - return 1; -} + s->s3->tmp.peer_ellipticcurvelist_length = num_curves; + } else if (type == TLSEXT_TYPE_renegotiate) { + if (!ssl_parse_clienthello_renegotiate_ext(s, &extension, out_alert)) { + return 0; + } + renegotiate_seen = 1; + } else if (type == TLSEXT_TYPE_signature_algorithms) { + CBS supported_signature_algorithms; + if (!CBS_get_u16_length_prefixed(&extension, + &supported_signature_algorithms) || + CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } -/* EC point formats. - * - * https://tools.ietf.org/html/rfc4492#section-5.1.2 */ + /* Ensure the signature algorithms are non-empty. It contains a list of + * SignatureAndHashAlgorithms which are two bytes each. */ + if (CBS_len(&supported_signature_algorithms) == 0 || + (CBS_len(&supported_signature_algorithms) % 2) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } -static int ssl_any_ec_cipher_suites_enabled(const SSL *ssl) { - if (ssl->version < TLS1_VERSION && !SSL_IS_DTLS(ssl)) { - return 0; - } + if (!tls1_process_sigalgs(s, &supported_signature_algorithms)) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + /* If sigalgs received and no shared algorithms fatal error. */ + if (s->cert->peer_sigalgs && !s->cert->shared_sigalgs) { + OPENSSL_PUT_ERROR(SSL, ssl_scan_clienthello_tlsext, + SSL_R_NO_SHARED_SIGATURE_ALGORITHMS); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + } else if (type == TLSEXT_TYPE_next_proto_neg && + !s->s3->initial_handshake_complete && + s->s3->alpn_selected == NULL && !SSL_IS_DTLS(s)) { + /* The extension must be empty. */ + if (CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + s->s3->next_proto_neg_seen = 1; + } else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation && + s->ctx->alpn_select_cb && !s->s3->initial_handshake_complete) { + if (!tls1_alpn_handle_client_hello(s, &extension, out_alert)) { + return 0; + } + /* ALPN takes precedence over NPN. */ + s->s3->next_proto_neg_seen = 0; + } else if (type == TLSEXT_TYPE_channel_id && s->tlsext_channel_id_enabled && + !SSL_IS_DTLS(s)) { + /* The extension must be empty. */ + if (CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - const STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(ssl); + s->s3->tlsext_channel_id_valid = 1; + } else if (type == TLSEXT_TYPE_channel_id_new && + s->tlsext_channel_id_enabled && !SSL_IS_DTLS(s)) { + /* The extension must be empty. */ + if (CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - size_t i; - for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) { - const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(cipher_stack, i); + s->s3->tlsext_channel_id_valid = 1; + s->s3->tlsext_channel_id_new = 1; + } else if (type == TLSEXT_TYPE_use_srtp) { + if (!ssl_parse_clienthello_use_srtp_ext(s, &extension, out_alert)) { + return 0; + } + } else if (type == TLSEXT_TYPE_extended_master_secret && + s->version != SSL3_VERSION) { + if (CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - const uint32_t alg_k = cipher->algorithm_mkey; - const uint32_t alg_a = cipher->algorithm_auth; - if ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)) { - return 1; + s->s3->tmp.extended_master_secret = 1; } } - return 0; -} +ri_check: + /* Need RI if renegotiating */ -static int ext_ec_point_add_extension(SSL *ssl, CBB *out) { - CBB contents, formats; - if (!CBB_add_u16(out, TLSEXT_TYPE_ec_point_formats) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u8_length_prefixed(&contents, &formats) || - !CBB_add_u8(&formats, TLSEXT_ECPOINTFORMAT_uncompressed) || - !CBB_flush(out)) { + if (!renegotiate_seen && s->s3->initial_handshake_complete && + !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) { + *out_alert = SSL_AD_HANDSHAKE_FAILURE; + OPENSSL_PUT_ERROR(SSL, ssl_scan_clienthello_tlsext, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); return 0; } return 1; } -static int ext_ec_point_add_clienthello(SSL *ssl, CBB *out) { - if (!ssl_any_ec_cipher_suites_enabled(ssl)) { - return 1; - } - - return ext_ec_point_add_extension(ssl, out); -} - -static int ext_ec_point_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } - - CBS ec_point_format_list; - if (!CBS_get_u8_length_prefixed(contents, &ec_point_format_list) || - CBS_len(contents) != 0) { +int ssl_parse_clienthello_tlsext(SSL *s, CBS *cbs) { + int alert = -1; + if (ssl_scan_clienthello_tlsext(s, cbs, &alert) <= 0) { + ssl3_send_alert(s, SSL3_AL_FATAL, alert); return 0; } - /* Per RFC 4492, section 5.1.2, implementations MUST support the uncompressed - * point format. */ - if (memchr(CBS_data(&ec_point_format_list), TLSEXT_ECPOINTFORMAT_uncompressed, - CBS_len(&ec_point_format_list)) == NULL) { - *out_alert = SSL_AD_ILLEGAL_PARAMETER; + if (ssl_check_clienthello_tlsext(s) <= 0) { + OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_tlsext, + SSL_R_CLIENTHELLO_TLSEXT); return 0; } return 1; } -static int ext_ec_point_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - return ext_ec_point_parse_serverhello(ssl, out_alert, contents); -} - -static int ext_ec_point_add_serverhello(SSL *ssl, CBB *out) { - const uint32_t alg_k = ssl->s3->tmp.new_cipher->algorithm_mkey; - const uint32_t alg_a = ssl->s3->tmp.new_cipher->algorithm_auth; - const int using_ecc = (alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA); - - if (!using_ecc) { - return 1; - } - - return ext_ec_point_add_extension(ssl, out); -} - - -/* EC supported curves. - * - * https://tools.ietf.org/html/rfc4492#section-5.1.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 int ext_ec_curves_add_clienthello(SSL *ssl, CBB *out) { - if (!ssl_any_ec_cipher_suites_enabled(ssl)) { - return 1; - } +/* ssl_next_proto_validate validates a Next Protocol Negotiation block. No + * elements of zero length are allowed and the set of elements must exactly + * fill the length of the block. */ +static char ssl_next_proto_validate(const CBS *cbs) { + CBS copy = *cbs; - CBB contents, curves_bytes; - if (!CBB_add_u16(out, TLSEXT_TYPE_elliptic_curves) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &curves_bytes)) { - return 0; - } - - const uint16_t *curves; - size_t curves_len; - tls1_get_curvelist(ssl, 0, &curves, &curves_len); - - size_t i; - for (i = 0; i < curves_len; i++) { - if (!CBB_add_u16(&curves_bytes, curves[i])) { + while (CBS_len(©) != 0) { + CBS proto; + if (!CBS_get_u8_length_prefixed(©, &proto) || CBS_len(&proto) == 0) { return 0; } } - return CBB_flush(out); -} - -static int ext_ec_curves_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) { - 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_len(contents) != 0) { - return 0; - } - - ssl->s3->tmp.peer_ellipticcurvelist = - (uint16_t *)OPENSSL_malloc(CBS_len(&elliptic_curve_list)); - - if (ssl->s3->tmp.peer_ellipticcurvelist == NULL) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; - } - - const size_t num_curves = CBS_len(&elliptic_curve_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])) { - goto err; - } - } - - assert(CBS_len(&elliptic_curve_list) == 0); - ssl->s3->tmp.peer_ellipticcurvelist_length = num_curves; - - return 1; - -err: - OPENSSL_free(ssl->s3->tmp.peer_ellipticcurvelist); - ssl->s3->tmp.peer_ellipticcurvelist = NULL; - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; -} - -static int ext_ec_curves_add_serverhello(SSL *ssl, CBB *out) { - /* Servers don't echo this extension. */ return 1; } +static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) { + int tlsext_servername = 0; + int renegotiate_seen = 0; + CBS extensions; -/* kExtensions contains all the supported extensions. */ -static const struct tls_extension kExtensions[] = { - { - /* The renegotiation extension must always be at index zero because the - * |received| and |sent| bitsets need to be tweaked when the "extension" is - * sent as an SCSV. */ - TLSEXT_TYPE_renegotiate, - NULL, - ext_ri_add_clienthello, - ext_ri_parse_serverhello, - ext_ri_parse_clienthello, - ext_ri_add_serverhello, - }, - { - TLSEXT_TYPE_server_name, - ext_sni_init, - ext_sni_add_clienthello, - ext_sni_parse_serverhello, - ext_sni_parse_clienthello, - ext_sni_add_serverhello, - }, - { - TLSEXT_TYPE_extended_master_secret, - ext_ems_init, - ext_ems_add_clienthello, - ext_ems_parse_serverhello, - ext_ems_parse_clienthello, - ext_ems_add_serverhello, - }, - { - TLSEXT_TYPE_session_ticket, - NULL, - ext_ticket_add_clienthello, - ext_ticket_parse_serverhello, - ext_ticket_parse_clienthello, - ext_ticket_add_serverhello, - }, - { - TLSEXT_TYPE_signature_algorithms, - NULL, - ext_sigalgs_add_clienthello, - ext_sigalgs_parse_serverhello, - ext_sigalgs_parse_clienthello, - ext_sigalgs_add_serverhello, - }, - { - TLSEXT_TYPE_status_request, - ext_ocsp_init, - ext_ocsp_add_clienthello, - ext_ocsp_parse_serverhello, - ext_ocsp_parse_clienthello, - ext_ocsp_add_serverhello, - }, - { - TLSEXT_TYPE_next_proto_neg, - ext_npn_init, - ext_npn_add_clienthello, - ext_npn_parse_serverhello, - ext_npn_parse_clienthello, - ext_npn_add_serverhello, - }, - { - TLSEXT_TYPE_certificate_timestamp, - NULL, - ext_sct_add_clienthello, - ext_sct_parse_serverhello, - ext_sct_parse_clienthello, - ext_sct_add_serverhello, - }, - { - TLSEXT_TYPE_application_layer_protocol_negotiation, - ext_alpn_init, - ext_alpn_add_clienthello, - ext_alpn_parse_serverhello, - ext_alpn_parse_clienthello, - ext_alpn_add_serverhello, - }, - { - TLSEXT_TYPE_channel_id, - ext_channel_id_init, - ext_channel_id_add_clienthello, - ext_channel_id_parse_serverhello, - ext_channel_id_parse_clienthello, - ext_channel_id_add_serverhello, - }, - { - TLSEXT_TYPE_srtp, - ext_srtp_init, - ext_srtp_add_clienthello, - ext_srtp_parse_serverhello, - ext_srtp_parse_clienthello, - ext_srtp_add_serverhello, - }, - { - TLSEXT_TYPE_ec_point_formats, - NULL, - ext_ec_point_add_clienthello, - ext_ec_point_parse_serverhello, - ext_ec_point_parse_clienthello, - ext_ec_point_add_serverhello, - }, - { - 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, - }, -}; - -#define kNumExtensions (sizeof(kExtensions) / sizeof(struct tls_extension)) - -OPENSSL_COMPILE_ASSERT(kNumExtensions <= - sizeof(((SSL *)NULL)->s3->tmp.extensions.sent) * 8, - too_many_extensions_for_sent_bitset); -OPENSSL_COMPILE_ASSERT(kNumExtensions <= - sizeof(((SSL *)NULL)->s3->tmp.extensions.received) * - 8, - too_many_extensions_for_received_bitset); - -static const struct tls_extension *tls_extension_find(uint32_t *out_index, - uint16_t value) { - unsigned i; - for (i = 0; i < kNumExtensions; i++) { - if (kExtensions[i].value == value) { - *out_index = i; - return &kExtensions[i]; - } - } - - return NULL; -} + /* TODO(davidben): Move all of these to some per-handshake state that gets + * systematically reset on a new handshake; perhaps allocate it fresh each + * time so it's not even kept around post-handshake. */ + s->s3->next_proto_neg_seen = 0; + s->tlsext_ticket_expected = 0; + s->s3->tmp.certificate_status_expected = 0; + s->s3->tmp.extended_master_secret = 0; + s->srtp_profile = NULL; -int SSL_extension_supported(unsigned extension_value) { - uint32_t index; - return extension_value == TLSEXT_TYPE_padding || - tls_extension_find(&index, extension_value) != NULL; -} + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = NULL; -/* header_len is the length of the ClientHello header written so far, used to - * compute padding. It does not include the record header. Pass 0 if no padding - * is to be done. */ -uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *const buf, - uint8_t *const limit, size_t header_len) { - /* don't add extensions for SSLv3 unless doing secure renegotiation */ - if (s->client_version == SSL3_VERSION && !s->s3->send_connection_binding) { - return buf; - } + /* Clear ECC extensions */ + OPENSSL_free(s->s3->tmp.peer_ecpointformatlist); + s->s3->tmp.peer_ecpointformatlist = NULL; + s->s3->tmp.peer_ecpointformatlist_length = 0; - CBB cbb, extensions; - CBB_zero(&cbb); - if (!CBB_init_fixed(&cbb, buf, limit - buf) || - !CBB_add_u16_length_prefixed(&cbb, &extensions)) { - goto err; + /* There may be no extensions. */ + if (CBS_len(cbs) == 0) { + goto ri_check; } - s->s3->tmp.extensions.sent = 0; - s->s3->tmp.custom_extensions.sent = 0; - - size_t i; - for (i = 0; i < kNumExtensions; i++) { - if (kExtensions[i].init != NULL) { - kExtensions[i].init(s); - } + /* Decode the extensions block and check it is valid. */ + if (!CBS_get_u16_length_prefixed(cbs, &extensions) || + !tls1_check_duplicate_extensions(&extensions)) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; } - for (i = 0; i < kNumExtensions; i++) { - const size_t len_before = CBB_len(&extensions); - if (!kExtensions[i].add_clienthello(s, &extensions)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value); - goto err; - } + while (CBS_len(&extensions) != 0) { + uint16_t type; + CBS extension; - if (CBB_len(&extensions) != len_before) { - s->s3->tmp.extensions.sent |= (1u << i); + /* Decode the next extension. */ + if (!CBS_get_u16(&extensions, &type) || + !CBS_get_u16_length_prefixed(&extensions, &extension)) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; } - } - if (!custom_ext_add_clienthello(s, &extensions)) { - goto err; - } - - if (header_len > 0) { - header_len += CBB_len(&extensions); - if (header_len > 0xff && header_len < 0x200) { - /* Add padding to workaround bugs in F5 terminators. See - * https://tools.ietf.org/html/draft-agl-tls-padding-03 - * - * NB: because this code works out the length of all existing extensions - * it MUST always appear last. */ - size_t padding_len = 0x200 - header_len; - /* Extensions take at least four bytes to encode. Always include least - * one byte of data if including the extension. WebSphere Application - * Server 7.0 is intolerant to the last extension being zero-length. */ - if (padding_len >= 4 + 1) { - padding_len -= 4; - } else { - padding_len = 1; + if (type == TLSEXT_TYPE_server_name) { + /* The extension must be empty. */ + if (CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; } - uint8_t *padding_bytes; - if (!CBB_add_u16(&extensions, TLSEXT_TYPE_padding) || - !CBB_add_u16(&extensions, padding_len) || - !CBB_add_space(&extensions, &padding_bytes, padding_len)) { - goto err; + /* We must have sent it in ClientHello. */ + if (s->tlsext_hostname == NULL) { + *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; + return 0; } - memset(padding_bytes, 0, padding_len); - } - } - - if (!CBB_flush(&cbb)) { - goto err; - } - - uint8_t *ret = buf; - const size_t cbb_len = CBB_len(&cbb); - /* If only two bytes have been written then the extensions are actually empty - * and those two bytes are the zero length. In that case, we don't bother - * sending the extensions length. */ - if (cbb_len > 2) { - ret += cbb_len; - } - - CBB_cleanup(&cbb); - return ret; - -err: - CBB_cleanup(&cbb); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return NULL; -} - -uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *const buf, - uint8_t *const limit) { - /* don't add extensions for SSLv3, unless doing secure renegotiation */ - if (s->version == SSL3_VERSION && !s->s3->send_connection_binding) { - return buf; - } - - CBB cbb, extensions; - CBB_zero(&cbb); - if (!CBB_init_fixed(&cbb, buf, limit - buf) || - !CBB_add_u16_length_prefixed(&cbb, &extensions)) { - goto err; - } - - unsigned i; - for (i = 0; i < kNumExtensions; i++) { - if (!(s->s3->tmp.extensions.received & (1u << i))) { - /* Don't send extensions that were not received. */ - continue; - } - - if (!kExtensions[i].add_serverhello(s, &extensions)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value); - goto err; - } - } - - if (!custom_ext_add_serverhello(s, &extensions)) { - goto err; - } - - if (!CBB_flush(&cbb)) { - goto err; - } - - uint8_t *ret = buf; - const size_t cbb_len = CBB_len(&cbb); - /* If only two bytes have been written then the extensions are actually empty - * and those two bytes are the zero length. In that case, we don't bother - * sending the extensions length. */ - if (cbb_len > 2) { - ret += cbb_len; - } - - CBB_cleanup(&cbb); - return ret; - -err: - CBB_cleanup(&cbb); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return NULL; -} - -static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) { - size_t i; - for (i = 0; i < kNumExtensions; i++) { - if (kExtensions[i].init != NULL) { - kExtensions[i].init(s); - } - } - - s->s3->tmp.extensions.received = 0; - s->s3->tmp.custom_extensions.received = 0; - /* The renegotiation extension must always be at index zero because the - * |received| and |sent| bitsets need to be tweaked when the "extension" is - * sent as an SCSV. */ - assert(kExtensions[0].value == TLSEXT_TYPE_renegotiate); + tlsext_servername = 1; + } else if (type == TLSEXT_TYPE_ec_point_formats) { + CBS ec_point_format_list; - /* There may be no extensions. */ - if (CBS_len(cbs) != 0) { - /* Decode the extensions block and check it is valid. */ - CBS extensions; - if (!CBS_get_u16_length_prefixed(cbs, &extensions) || - !tls1_check_duplicate_extensions(&extensions)) { - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } - - while (CBS_len(&extensions) != 0) { - uint16_t type; - CBS extension; - - /* Decode the next extension. */ - if (!CBS_get_u16(&extensions, &type) || - !CBS_get_u16_length_prefixed(&extensions, &extension)) { + if (!CBS_get_u8_length_prefixed(&extension, &ec_point_format_list) || + CBS_len(&extension) != 0) { *out_alert = SSL_AD_DECODE_ERROR; return 0; } - unsigned ext_index; - const struct tls_extension *const ext = - tls_extension_find(&ext_index, type); - - if (ext == NULL) { - if (!custom_ext_parse_clienthello(s, out_alert, type, &extension)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); - return 0; - } - continue; + if (!CBS_stow(&ec_point_format_list, &s->s3->tmp.peer_ecpointformatlist, + &s->s3->tmp.peer_ecpointformatlist_length)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + } else if (type == TLSEXT_TYPE_session_ticket) { + if ((SSL_get_options(s) & SSL_OP_NO_TICKET) || CBS_len(&extension) > 0) { + *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; + return 0; } - s->s3->tmp.extensions.received |= (1u << ext_index); - uint8_t alert = SSL_AD_DECODE_ERROR; - if (!ext->parse_clienthello(s, &alert, &extension)) { - *out_alert = alert; - OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)type); + s->tlsext_ticket_expected = 1; + } else if (type == TLSEXT_TYPE_status_request) { + /* The extension MUST be empty and may only sent if we've requested a + * status request message. */ + if (CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; return 0; } - } - } - for (i = 0; i < kNumExtensions; i++) { - if (!(s->s3->tmp.extensions.received & (1u << i))) { - /* Extension wasn't observed so call the callback with a NULL - * parameter. */ - uint8_t alert = SSL_AD_DECODE_ERROR; - if (!kExtensions[i].parse_clienthello(s, &alert, NULL)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value); - *out_alert = alert; + if (!s->ocsp_stapling_enabled) { + *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; return 0; } - } - } - return 1; -} + /* Set a flag to expect a CertificateStatus message */ + s->s3->tmp.certificate_status_expected = 1; + } else if (type == TLSEXT_TYPE_next_proto_neg && + !s->s3->initial_handshake_complete && !SSL_IS_DTLS(s)) { + uint8_t *selected; + uint8_t selected_len; -int ssl_parse_clienthello_tlsext(SSL *s, CBS *cbs) { - int alert = -1; - if (ssl_scan_clienthello_tlsext(s, cbs, &alert) <= 0) { - ssl3_send_alert(s, SSL3_AL_FATAL, alert); - return 0; - } + /* We must have requested it. */ + if (s->ctx->next_proto_select_cb == NULL) { + *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; + return 0; + } - if (ssl_check_clienthello_tlsext(s) <= 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_TLSEXT); - return 0; - } + /* The data must be valid. */ + if (!ssl_next_proto_validate(&extension)) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - return 1; -} + if (s->ctx->next_proto_select_cb( + s, &selected, &selected_len, CBS_data(&extension), + CBS_len(&extension), + s->ctx->next_proto_select_cb_arg) != SSL_TLSEXT_ERR_OK) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } -static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) { - uint32_t received = 0; - assert(kNumExtensions <= sizeof(received) * 8); - - if (CBS_len(cbs) != 0) { - /* Decode the extensions block and check it is valid. */ - CBS extensions; - if (!CBS_get_u16_length_prefixed(cbs, &extensions) || - !tls1_check_duplicate_extensions(&extensions)) { - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } + s->next_proto_negotiated = BUF_memdup(selected, selected_len); + if (s->next_proto_negotiated == NULL) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + s->next_proto_negotiated_len = selected_len; + s->s3->next_proto_neg_seen = 1; + } else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation && + !s->s3->initial_handshake_complete) { + CBS protocol_name_list, protocol_name; - while (CBS_len(&extensions) != 0) { - uint16_t type; - CBS extension; + /* We must have requested it. */ + if (s->alpn_client_proto_list == NULL) { + *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; + return 0; + } - /* Decode the next extension. */ - if (!CBS_get_u16(&extensions, &type) || - !CBS_get_u16_length_prefixed(&extensions, &extension)) { + /* The extension data consists of a ProtocolNameList which must have + * exactly one ProtocolName. Each of these is length-prefixed. */ + if (!CBS_get_u16_length_prefixed(&extension, &protocol_name_list) || + CBS_len(&extension) != 0 || + !CBS_get_u8_length_prefixed(&protocol_name_list, &protocol_name) || + CBS_len(&protocol_name_list) != 0) { *out_alert = SSL_AD_DECODE_ERROR; return 0; } - unsigned ext_index; - const struct tls_extension *const ext = - tls_extension_find(&ext_index, type); + if (!CBS_stow(&protocol_name, &s->s3->alpn_selected, + &s->s3->alpn_selected_len)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + } else if (type == TLSEXT_TYPE_channel_id && !SSL_IS_DTLS(s)) { + if (CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - if (ext == NULL) { - if (!custom_ext_parse_serverhello(s, out_alert, type, &extension)) { - return 0; - } - continue; + s->s3->tlsext_channel_id_valid = 1; + } else if (type == TLSEXT_TYPE_channel_id_new && !SSL_IS_DTLS(s)) { + if (CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; } - if (!(s->s3->tmp.extensions.sent & (1u << ext_index))) { - /* If the extension was never sent then it is illegal. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); - ERR_add_error_dataf("extension :%u", (unsigned)type); + s->s3->tlsext_channel_id_valid = 1; + s->s3->tlsext_channel_id_new = 1; + } else if (type == TLSEXT_TYPE_certificate_timestamp) { + if (CBS_len(&extension) == 0) { *out_alert = SSL_AD_DECODE_ERROR; return 0; } - received |= (1u << ext_index); + /* Session resumption uses the original session information. */ + if (!s->hit && + !CBS_stow(&extension, &s->session->tlsext_signed_cert_timestamp_list, + &s->session->tlsext_signed_cert_timestamp_list_length)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + } else if (type == TLSEXT_TYPE_renegotiate) { + if (!ssl_parse_serverhello_renegotiate_ext(s, &extension, out_alert)) { + return 0; + } - uint8_t alert = SSL_AD_DECODE_ERROR; - if (!ext->parse_serverhello(s, &alert, &extension)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)type); - *out_alert = alert; + renegotiate_seen = 1; + } else if (type == TLSEXT_TYPE_use_srtp) { + if (!ssl_parse_serverhello_use_srtp_ext(s, &extension, out_alert)) { return 0; } + } else if (type == TLSEXT_TYPE_extended_master_secret) { + if (/* It is invalid for the server to select EMS and + SSLv3. */ + s->version == SSL3_VERSION || CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + + s->s3->tmp.extended_master_secret = 1; } } - size_t i; - for (i = 0; i < kNumExtensions; i++) { - if (!(received & (1u << i))) { - /* Extension wasn't observed so call the callback with a NULL - * parameter. */ - uint8_t alert = SSL_AD_DECODE_ERROR; - if (!kExtensions[i].parse_serverhello(s, &alert, NULL)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value); - *out_alert = alert; + if (!s->hit && tlsext_servername == 1 && s->tlsext_hostname) { + if (s->session->tlsext_hostname == NULL) { + s->session->tlsext_hostname = BUF_strdup(s->tlsext_hostname); + if (!s->session->tlsext_hostname) { + *out_alert = SSL_AD_UNRECOGNIZED_NAME; return 0; } + } else { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; } } +ri_check: + /* Determine if we need to see RI. Strictly speaking if we want to avoid an + * attack we should *always* see RI even on initial server hello because the + * client doesn't see any renegotiation during an attack. However this would + * mean we could not connect to any server which doesn't support RI so for + * the immediate future tolerate RI absence on initial connect only. */ + if (!renegotiate_seen && !(s->options & SSL_OP_LEGACY_SERVER_CONNECT) && + !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) { + *out_alert = SSL_AD_HANDSHAKE_FAILURE; + OPENSSL_PUT_ERROR(SSL, ssl_scan_serverhello_tlsext, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + return 0; + } + return 1; } +int ssl_prepare_clienthello_tlsext(SSL *s) { return 1; } + +int ssl_prepare_serverhello_tlsext(SSL *s) { return 1; } + static int ssl_check_clienthello_tlsext(SSL *s) { int ret = SSL_TLSEXT_ERR_NOACK; int al = SSL_AD_UNRECOGNIZED_NAME; @@ -2568,7 +1947,7 @@ static int ssl_check_clienthello_tlsext(SSL *s) { return 1; case SSL_TLSEXT_ERR_NOACK: - s->s3->tmp.should_ack_sni = 0; + s->should_ack_sni = 0; return 1; default: @@ -2577,9 +1956,22 @@ static int ssl_check_clienthello_tlsext(SSL *s) { } static int ssl_check_serverhello_tlsext(SSL *s) { - int ret = SSL_TLSEXT_ERR_OK; + int ret = SSL_TLSEXT_ERR_NOACK; int al = SSL_AD_UNRECOGNIZED_NAME; + /* If we are client and using an elliptic curve cryptography cipher suite, + * then if server returns an EC point formats lists extension it must contain + * uncompressed. */ + uint32_t alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + uint32_t alg_a = s->s3->tmp.new_cipher->algorithm_auth; + if (((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)) && + !tls1_check_point_format(s, TLSEXT_ECPOINTFORMAT_uncompressed)) { + OPENSSL_PUT_ERROR(SSL, ssl_check_serverhello_tlsext, + SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST); + return -1; + } + ret = SSL_TLSEXT_ERR_OK; + if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) { ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg); @@ -2615,131 +2007,203 @@ int ssl_parse_serverhello_tlsext(SSL *s, CBS *cbs) { } if (ssl_check_serverhello_tlsext(s) <= 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SERVERHELLO_TLSEXT); + OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_tlsext, + SSL_R_SERVERHELLO_TLSEXT); return 0; } return 1; } -int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, - int *out_send_ticket, const uint8_t *ticket, - size_t ticket_len, const uint8_t *session_id, - size_t session_id_len) { - int ret = 1; /* Most errors are non-fatal. */ - SSL_CTX *ssl_ctx = ssl->initial_ctx; - uint8_t *plaintext = NULL; - - HMAC_CTX hmac_ctx; - HMAC_CTX_init(&hmac_ctx); - EVP_CIPHER_CTX cipher_ctx; - EVP_CIPHER_CTX_init(&cipher_ctx); - - *out_send_ticket = 0; - *out_session = NULL; +/* Since the server cache lookup is done early on in the processing of the + * ClientHello, and other operations depend on the result, we need to handle + * any TLS session ticket extension at the same time. + * + * ctx: contains the early callback context, which is the result of a + * shallow parse of the ClientHello. + * ret: (output) on return, if a ticket was decrypted, then this is set to + * point to the resulting session. + * + * Returns: + * -1: fatal error, either from parsing or decrypting the ticket. + * 0: no ticket was found (or was ignored, based on settings). + * 1: a zero length extension was found, indicating that the client supports + * session tickets but doesn't currently have one to offer. + * 2: a ticket was offered but couldn't be decrypted because of a non-fatal + * error. + * 3: a ticket was successfully decrypted and *ret was set. + * + * Side effects: + * Sets s->tlsext_ticket_expected to 1 if the server will have to issue + * a new session ticket to the client because the client indicated support + * but the client either doesn't have a session ticket or we couldn't use + * the one it gave us, or if s->ctx->tlsext_ticket_key_cb asked to renew + * the client's ticket. Otherwise, s->tlsext_ticket_expected is set to 0. + */ +int tls1_process_ticket(SSL *s, const struct ssl_early_callback_ctx *ctx, + SSL_SESSION **ret) { + *ret = NULL; + s->tlsext_ticket_expected = 0; + const uint8_t *data; + size_t len; + int r; - if (session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) { - goto done; + /* If tickets disabled behave as if no ticket present to permit stateful + * resumption. */ + if ((SSL_get_options(s) & SSL_OP_NO_TICKET) || + (s->version <= SSL3_VERSION && !ctx->extensions) || + !SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_session_ticket, + &data, &len)) { + return 0; } - if (ticket_len == 0) { + if (len == 0) { /* The client will accept a ticket but doesn't currently have one. */ - *out_send_ticket = 1; - goto done; + s->tlsext_ticket_expected = 1; + return 1; + } + + r = tls_decrypt_ticket(s, data, len, ctx->session_id, ctx->session_id_len, + ret); + switch (r) { + case 2: /* ticket couldn't be decrypted */ + s->tlsext_ticket_expected = 1; + return 2; + + case 3: /* ticket was decrypted */ + return r; + + case 4: /* ticket decrypted but need to renew */ + s->tlsext_ticket_expected = 1; + return 3; + + default: /* fatal error */ + return -1; } +} + +/* tls_decrypt_ticket attempts to decrypt a session ticket. + * + * etick: points to the body of the session ticket extension. + * eticklen: the length of the session tickets extenion. + * sess_id: points at the session ID. + * sesslen: the length of the session ID. + * psess: (output) on return, if a ticket was decrypted, then this is set to + * point to the resulting session. + * + * Returns: + * -1: fatal error, either from parsing or decrypting the ticket. + * 2: the ticket couldn't be decrypted. + * 3: a ticket was successfully decrypted and *psess was set. + * 4: same as 3, but the ticket needs to be renewed. */ +static int tls_decrypt_ticket(SSL *s, const uint8_t *etick, int eticklen, + const uint8_t *sess_id, int sesslen, + SSL_SESSION **psess) { + SSL_SESSION *sess; + uint8_t *sdec; + const uint8_t *p; + int slen, mlen, renew_ticket = 0; + uint8_t tick_hmac[EVP_MAX_MD_SIZE]; + HMAC_CTX hctx; + EVP_CIPHER_CTX ctx; + SSL_CTX *tctx = s->initial_ctx; /* Ensure there is room for the key name and the largest IV * |tlsext_ticket_key_cb| may try to consume. The real limit may be lower, but * the maximum IV length should be well under the minimum size for the * session material and HMAC. */ - if (ticket_len < SSL_TICKET_KEY_NAME_LEN + EVP_MAX_IV_LENGTH) { - goto done; - } - const uint8_t *iv = ticket + SSL_TICKET_KEY_NAME_LEN; - - if (ssl_ctx->tlsext_ticket_key_cb != NULL) { - int cb_ret = ssl_ctx->tlsext_ticket_key_cb(ssl, (uint8_t*)ticket /* name */, - (uint8_t*)iv, &cipher_ctx, &hmac_ctx, - 0 /* decrypt */); - if (cb_ret < 0) { - ret = 0; - goto done; + if (eticklen < 16 + EVP_MAX_IV_LENGTH) { + return 2; + } + + /* Initialize session ticket encryption and HMAC contexts */ + HMAC_CTX_init(&hctx); + EVP_CIPHER_CTX_init(&ctx); + if (tctx->tlsext_ticket_key_cb) { + uint8_t *nctick = (uint8_t *)etick; + int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16, &ctx, &hctx, + 0 /* decrypt */); + if (rv < 0) { + return -1; } - if (cb_ret == 0) { - goto done; + if (rv == 0) { + return 2; } - if (cb_ret == 2) { - *out_send_ticket = 1; + if (rv == 2) { + renew_ticket = 1; } } else { - /* Check the key name matches. */ - if (memcmp(ticket, ssl_ctx->tlsext_tick_key_name, - SSL_TICKET_KEY_NAME_LEN) != 0) { - goto done; + /* Check key name matches */ + if (memcmp(etick, tctx->tlsext_tick_key_name, 16)) { + return 2; } - if (!HMAC_Init_ex(&hmac_ctx, ssl_ctx->tlsext_tick_hmac_key, - sizeof(ssl_ctx->tlsext_tick_hmac_key), tlsext_tick_md(), + if (!HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, tlsext_tick_md(), NULL) || - !EVP_DecryptInit_ex(&cipher_ctx, EVP_aes_128_cbc(), NULL, - ssl_ctx->tlsext_tick_aes_key, iv)) { - ret = 0; - goto done; + !EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, + tctx->tlsext_tick_aes_key, etick + 16)) { + HMAC_CTX_cleanup(&hctx); + EVP_CIPHER_CTX_cleanup(&ctx); + return -1; } } - size_t iv_len = EVP_CIPHER_CTX_iv_length(&cipher_ctx); - /* Check the MAC at the end of the ticket. */ - uint8_t mac[EVP_MAX_MD_SIZE]; - size_t mac_len = HMAC_size(&hmac_ctx); - if (ticket_len < SSL_TICKET_KEY_NAME_LEN + iv_len + 1 + mac_len) { + /* First, check the MAC. The MAC is at the end of the ticket. */ + mlen = HMAC_size(&hctx); + if ((size_t) eticklen < 16 + EVP_CIPHER_CTX_iv_length(&ctx) + 1 + mlen) { /* The ticket must be large enough for key name, IV, data, and MAC. */ - goto done; - } - HMAC_Update(&hmac_ctx, ticket, ticket_len - mac_len); - HMAC_Final(&hmac_ctx, mac, NULL); - if (CRYPTO_memcmp(mac, ticket + (ticket_len - mac_len), mac_len) != 0) { - goto done; - } - - /* Decrypt the session data. */ - const uint8_t *ciphertext = ticket + SSL_TICKET_KEY_NAME_LEN + iv_len; - size_t ciphertext_len = ticket_len - SSL_TICKET_KEY_NAME_LEN - iv_len - - mac_len; - plaintext = OPENSSL_malloc(ciphertext_len); - if (plaintext == NULL) { - ret = 0; - goto done; - } - if (ciphertext_len >= INT_MAX) { - goto done; - } - int len1, len2; - if (!EVP_DecryptUpdate(&cipher_ctx, plaintext, &len1, ciphertext, - (int)ciphertext_len) || - !EVP_DecryptFinal_ex(&cipher_ctx, plaintext + len1, &len2)) { - ERR_clear_error(); /* Don't leave an error on the queue. */ - goto done; + HMAC_CTX_cleanup(&hctx); + EVP_CIPHER_CTX_cleanup(&ctx); + return 2; + } + eticklen -= mlen; + /* Check HMAC of encrypted ticket */ + HMAC_Update(&hctx, etick, eticklen); + HMAC_Final(&hctx, tick_hmac, NULL); + HMAC_CTX_cleanup(&hctx); + if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen)) { + EVP_CIPHER_CTX_cleanup(&ctx); + return 2; + } + + /* Attempt to decrypt session data */ + /* Move p after IV to start of encrypted ticket, update length */ + p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx); + eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx); + sdec = OPENSSL_malloc(eticklen); + if (!sdec) { + EVP_CIPHER_CTX_cleanup(&ctx); + return -1; } - - /* Decode the session. */ - SSL_SESSION *session = SSL_SESSION_from_bytes(plaintext, len1 + len2); - if (session == NULL) { - ERR_clear_error(); /* Don't leave an error on the queue. */ - goto done; + EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen); + if (EVP_DecryptFinal_ex(&ctx, sdec + slen, &mlen) <= 0) { + EVP_CIPHER_CTX_cleanup(&ctx); + OPENSSL_free(sdec); + return 2; + } + slen += mlen; + EVP_CIPHER_CTX_cleanup(&ctx); + p = sdec; + + sess = SSL_SESSION_from_bytes(sdec, slen); + OPENSSL_free(sdec); + if (sess) { + /* The session ID, if non-empty, is used by some clients to detect that the + * ticket has been accepted. So we copy it to the session structure. If it + * is empty set length to zero as required by standard. */ + if (sesslen) { + memcpy(sess->session_id, sess_id, sesslen); + } + sess->session_id_length = sesslen; + *psess = sess; + if (renew_ticket) { + return 4; + } + return 3; } - /* Copy the client's session ID into the new session, to denote the ticket has - * been accepted. */ - memcpy(session->session_id, session_id, session_id_len); - session->session_id_length = session_id_len; - - *out_session = session; - -done: - OPENSSL_free(plaintext); - HMAC_CTX_cleanup(&hmac_ctx); - EVP_CIPHER_CTX_cleanup(&cipher_ctx); - return ret; + ERR_clear_error(); + /* For session parse failure, indicate that we need to send a new ticket. */ + return 2; } /* Tables to translate from NIDs to TLS v1.2 ids */ @@ -2769,12 +2233,18 @@ static int tls12_find_id(int nid, const tls12_lookup *table, size_t tlen) { return -1; } -int tls12_get_sigid(int pkey_type) { - return tls12_find_id(pkey_type, tls12_sig, - sizeof(tls12_sig) / sizeof(tls12_lookup)); +static int tls12_find_nid(int id, const tls12_lookup *table, size_t tlen) { + size_t i; + for (i = 0; i < tlen; i++) { + if (table[i].id == id) { + return table[i].nid; + } + } + + return NID_undef; } -int tls12_get_sigandhash(SSL *ssl, uint8_t *p, const EVP_MD *md) { +int tls12_get_sigandhash(uint8_t *p, const EVP_PKEY *pk, const EVP_MD *md) { int sig_id, md_id; if (!md) { @@ -2787,7 +2257,7 @@ int tls12_get_sigandhash(SSL *ssl, uint8_t *p, const EVP_MD *md) { return 0; } - sig_id = tls12_get_sigid(ssl_private_key_type(ssl)); + sig_id = tls12_get_sigid(pk); if (sig_id == -1) { return 0; } @@ -2797,6 +2267,11 @@ int tls12_get_sigandhash(SSL *ssl, uint8_t *p, const EVP_MD *md) { return 1; } +int tls12_get_sigid(const EVP_PKEY *pk) { + return tls12_find_id(pk->type, tls12_sig, + sizeof(tls12_sig) / sizeof(tls12_lookup)); +} + const EVP_MD *tls12_get_hash(uint8_t hash_alg) { switch (hash_alg) { case TLSEXT_hash_md5: @@ -2837,129 +2312,256 @@ static int tls12_get_pkey_type(uint8_t sig_alg) { } } -OPENSSL_COMPILE_ASSERT(sizeof(TLS_SIGALGS) == 2, - sizeof_tls_sigalgs_is_not_two); +/* Convert TLS 1.2 signature algorithm extension values into NIDs */ +static void tls1_lookup_sigalg(int *phash_nid, int *psign_nid, + int *psignhash_nid, const uint8_t *data) { + int sign_nid = 0, hash_nid = 0; + if (!phash_nid && !psign_nid && !psignhash_nid) { + return; + } -int tls1_parse_peer_sigalgs(SSL *ssl, const CBS *in_sigalgs) { - /* Extension ignored for inappropriate versions */ - if (!SSL_USE_SIGALGS(ssl)) { - return 1; + if (phash_nid || psignhash_nid) { + hash_nid = tls12_find_nid(data[0], tls12_md, + sizeof(tls12_md) / sizeof(tls12_lookup)); + if (phash_nid) { + *phash_nid = hash_nid; + } } - CERT *const cert = ssl->cert; - OPENSSL_free(cert->peer_sigalgs); - cert->peer_sigalgs = NULL; - cert->peer_sigalgslen = 0; + if (psign_nid || psignhash_nid) { + sign_nid = tls12_find_nid(data[1], tls12_sig, + sizeof(tls12_sig) / sizeof(tls12_lookup)); + if (psign_nid) { + *psign_nid = sign_nid; + } + } - size_t num_sigalgs = CBS_len(in_sigalgs); + if (psignhash_nid) { + if (sign_nid && hash_nid) { + OBJ_find_sigid_by_algs(psignhash_nid, hash_nid, sign_nid); + } else { + *psignhash_nid = NID_undef; + } + } +} - if (num_sigalgs % 2 != 0) { - return 0; +/* Given preference and allowed sigalgs set shared sigalgs */ +static int tls12_do_shared_sigalgs(TLS_SIGALGS *shsig, const uint8_t *pref, + size_t preflen, const uint8_t *allow, + size_t allowlen) { + const uint8_t *ptmp, *atmp; + size_t i, j, nmatch = 0; + + for (i = 0, ptmp = pref; i < preflen; i += 2, ptmp += 2) { + /* Skip disabled hashes or signature algorithms */ + if (tls12_get_hash(ptmp[0]) == NULL || + tls12_get_pkey_type(ptmp[1]) == -1) { + continue; + } + + for (j = 0, atmp = allow; j < allowlen; j += 2, atmp += 2) { + if (ptmp[0] == atmp[0] && ptmp[1] == atmp[1]) { + nmatch++; + if (shsig) { + shsig->rhash = ptmp[0]; + shsig->rsign = ptmp[1]; + tls1_lookup_sigalg(&shsig->hash_nid, &shsig->sign_nid, + &shsig->signandhash_nid, ptmp); + shsig++; + } + + break; + } + } + } + + return nmatch; +} + +/* Set shared signature algorithms for SSL structures */ +static int tls1_set_shared_sigalgs(SSL *s) { + const uint8_t *pref, *allow, *conf; + size_t preflen, allowlen, conflen; + size_t nmatch; + TLS_SIGALGS *salgs = NULL; + CERT *c = s->cert; + + OPENSSL_free(c->shared_sigalgs); + c->shared_sigalgs = NULL; + c->shared_sigalgslen = 0; + + /* If client use client signature algorithms if not NULL */ + if (!s->server && c->client_sigalgs) { + conf = c->client_sigalgs; + conflen = c->client_sigalgslen; + } else if (c->conf_sigalgs) { + conf = c->conf_sigalgs; + conflen = c->conf_sigalgslen; + } else { + conflen = tls12_get_psigalgs(s, &conf); } - num_sigalgs /= 2; - /* supported_signature_algorithms in the certificate request is - * allowed to be empty. */ - if (num_sigalgs == 0) { + if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { + pref = conf; + preflen = conflen; + allow = c->peer_sigalgs; + allowlen = c->peer_sigalgslen; + } else { + allow = conf; + allowlen = conflen; + pref = c->peer_sigalgs; + preflen = c->peer_sigalgslen; + } + + nmatch = tls12_do_shared_sigalgs(NULL, pref, preflen, allow, allowlen); + if (!nmatch) { return 1; } - /* This multiplication doesn't overflow because sizeof(TLS_SIGALGS) is two - * (statically asserted above) and we just divided |num_sigalgs| by two. */ - cert->peer_sigalgs = OPENSSL_malloc(num_sigalgs * sizeof(TLS_SIGALGS)); - if (cert->peer_sigalgs == NULL) { + salgs = OPENSSL_malloc(nmatch * sizeof(TLS_SIGALGS)); + if (!salgs) { return 0; } - cert->peer_sigalgslen = num_sigalgs; - CBS sigalgs; - CBS_init(&sigalgs, CBS_data(in_sigalgs), CBS_len(in_sigalgs)); + nmatch = tls12_do_shared_sigalgs(salgs, pref, preflen, allow, allowlen); + c->shared_sigalgs = salgs; + c->shared_sigalgslen = nmatch; + return 1; +} - size_t i; - for (i = 0; i < num_sigalgs; i++) { - TLS_SIGALGS *const sigalg = &cert->peer_sigalgs[i]; - if (!CBS_get_u8(&sigalgs, &sigalg->rhash) || - !CBS_get_u8(&sigalgs, &sigalg->rsign)) { - return 0; - } +/* Set preferred digest for each key type */ +int tls1_process_sigalgs(SSL *s, const CBS *sigalgs) { + CERT *c = s->cert; + + /* Extension ignored for inappropriate versions */ + if (!SSL_USE_SIGALGS(s)) { + return 1; + } + + if (CBS_len(sigalgs) % 2 != 0 || + !CBS_stow(sigalgs, &c->peer_sigalgs, &c->peer_sigalgslen) || + !tls1_set_shared_sigalgs(s)) { + return 0; } return 1; } -const EVP_MD *tls1_choose_signing_digest(SSL *ssl) { - CERT *cert = ssl->cert; - int type = ssl_private_key_type(ssl); - size_t i, j; - - static const int kDefaultDigestList[] = {NID_sha256, NID_sha384, NID_sha512, - NID_sha224, NID_sha1}; - - const int *digest_nids = kDefaultDigestList; - size_t num_digest_nids = - sizeof(kDefaultDigestList) / sizeof(kDefaultDigestList[0]); - if (cert->digest_nids != NULL) { - digest_nids = cert->digest_nids; - num_digest_nids = cert->num_digest_nids; - } - - for (i = 0; i < num_digest_nids; i++) { - const int digest_nid = digest_nids[i]; - for (j = 0; j < cert->peer_sigalgslen; j++) { - const EVP_MD *md = tls12_get_hash(cert->peer_sigalgs[j].rhash); - if (md == NULL || - digest_nid != EVP_MD_type(md) || - tls12_get_pkey_type(cert->peer_sigalgs[j].rsign) != type) { - continue; - } +const EVP_MD *tls1_choose_signing_digest(SSL *s, EVP_PKEY *pkey) { + CERT *c = s->cert; + int type = EVP_PKEY_id(pkey); + size_t i; - return md; + /* Select the first shared digest supported by our key. */ + for (i = 0; i < c->shared_sigalgslen; i++) { + const EVP_MD *md = tls12_get_hash(c->shared_sigalgs[i].rhash); + if (md == NULL || + tls12_get_pkey_type(c->shared_sigalgs[i].rsign) != type || + !EVP_PKEY_supports_digest(pkey, md)) { + continue; } + return md; } /* If no suitable digest may be found, default to SHA-1. */ return EVP_sha1(); } -int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len) { - int ret = 0; - EVP_MD_CTX ctx; +int SSL_get_sigalgs(SSL *s, int idx, int *psign, int *phash, int *psignhash, + uint8_t *rsig, uint8_t *rhash) { + const uint8_t *psig = s->cert->peer_sigalgs; - EVP_MD_CTX_init(&ctx); - if (!EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL)) { - goto err; + if (psig == NULL) { + return 0; } + if (idx >= 0) { + idx <<= 1; + if (idx >= (int)s->cert->peer_sigalgslen) { + return 0; + } + psig += idx; + if (rhash) { + *rhash = psig[0]; + } + if (rsig) { + *rsig = psig[1]; + } + tls1_lookup_sigalg(phash, psign, psignhash, psig); + } + + return s->cert->peer_sigalgslen / 2; +} + +int SSL_get_shared_sigalgs(SSL *s, int idx, int *psign, int *phash, + int *psignhash, uint8_t *rsig, uint8_t *rhash) { + TLS_SIGALGS *shsigalgs = s->cert->shared_sigalgs; + + if (!shsigalgs || idx >= (int)s->cert->shared_sigalgslen) { + return 0; + } + + shsigalgs += idx; + if (phash) { + *phash = shsigalgs->hash_nid; + } + if (psign) { + *psign = shsigalgs->sign_nid; + } + if (psignhash) { + *psignhash = shsigalgs->signandhash_nid; + } + if (rsig) { + *rsig = shsigalgs->rsign; + } + if (rhash) { + *rhash = shsigalgs->rhash; + } + + return s->cert->shared_sigalgslen; +} + +/* tls1_channel_id_hash calculates the signed data for a Channel ID on the + * given SSL connection and writes it to |md|. */ +int tls1_channel_id_hash(EVP_MD_CTX *md, SSL *s) { + EVP_MD_CTX ctx; + uint8_t temp_digest[EVP_MAX_MD_SIZE]; + unsigned temp_digest_len; + int i; static const char kClientIDMagic[] = "TLS Channel ID signature"; - EVP_DigestUpdate(&ctx, kClientIDMagic, sizeof(kClientIDMagic)); - if (ssl->hit) { + if (s->s3->handshake_buffer && + !ssl3_digest_cached_records(s, free_handshake_buffer)) { + return 0; + } + + EVP_DigestUpdate(md, kClientIDMagic, sizeof(kClientIDMagic)); + + if (s->hit && s->s3->tlsext_channel_id_new) { static const char kResumptionMagic[] = "Resumption"; - EVP_DigestUpdate(&ctx, kResumptionMagic, sizeof(kResumptionMagic)); - if (ssl->session->original_handshake_hash_len == 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - goto err; + EVP_DigestUpdate(md, kResumptionMagic, sizeof(kResumptionMagic)); + if (s->session->original_handshake_hash_len == 0) { + return 0; } - EVP_DigestUpdate(&ctx, ssl->session->original_handshake_hash, - ssl->session->original_handshake_hash_len); + EVP_DigestUpdate(md, s->session->original_handshake_hash, + s->session->original_handshake_hash_len); } - uint8_t handshake_hash[EVP_MAX_MD_SIZE]; - int handshake_hash_len = tls1_handshake_digest(ssl, handshake_hash, - sizeof(handshake_hash)); - if (handshake_hash_len < 0) { - goto err; + EVP_MD_CTX_init(&ctx); + for (i = 0; i < SSL_MAX_DIGEST; i++) { + if (s->s3->handshake_dgst[i] == NULL) { + continue; + } + if (!EVP_MD_CTX_copy_ex(&ctx, s->s3->handshake_dgst[i])) { + EVP_MD_CTX_cleanup(&ctx); + return 0; + } + EVP_DigestFinal_ex(&ctx, temp_digest, &temp_digest_len); + EVP_DigestUpdate(md, temp_digest, temp_digest_len); } - EVP_DigestUpdate(&ctx, handshake_hash, (size_t)handshake_hash_len); - unsigned len_u; - EVP_DigestFinal_ex(&ctx, out, &len_u); - *out_len = len_u; - - ret = 1; - -err: EVP_MD_CTX_cleanup(&ctx); - return ret; + + return 1; } /* tls1_record_handshake_hashes_for_channel_id records the current handshake @@ -2973,6 +2575,12 @@ int tls1_record_handshake_hashes_for_channel_id(SSL *s) { return -1; } + /* It only makes sense to call this function if Channel IDs have been + * negotiated. */ + if (!s->s3->tlsext_channel_id_new) { + return -1; + } + digest_len = tls1_handshake_digest(s, s->session->original_handshake_hash, sizeof(s->session->original_handshake_hash)); @@ -2984,3 +2592,48 @@ int tls1_record_handshake_hashes_for_channel_id(SSL *s) { return 1; } + +int tls1_set_sigalgs(CERT *c, const int *psig_nids, size_t salglen, + int client) { + uint8_t *sigalgs, *sptr; + int rhash, rsign; + size_t i; + + if (salglen & 1) { + return 0; + } + + sigalgs = OPENSSL_malloc(salglen); + if (sigalgs == NULL) { + return 0; + } + + for (i = 0, sptr = sigalgs; i < salglen; i += 2) { + rhash = tls12_find_id(*psig_nids++, tls12_md, + sizeof(tls12_md) / sizeof(tls12_lookup)); + rsign = tls12_find_id(*psig_nids++, tls12_sig, + sizeof(tls12_sig) / sizeof(tls12_lookup)); + + if (rhash == -1 || rsign == -1) { + goto err; + } + *sptr++ = rhash; + *sptr++ = rsign; + } + + if (client) { + OPENSSL_free(c->client_sigalgs); + c->client_sigalgs = sigalgs; + c->client_sigalgslen = salglen; + } else { + OPENSSL_free(c->conf_sigalgs); + c->conf_sigalgs = sigalgs; + c->conf_sigalgslen = salglen; + } + + return 1; + +err: + OPENSSL_free(sigalgs); + return 0; +} diff --git a/src/ssl/t1_reneg.c b/src/ssl/t1_reneg.c new file mode 100644 index 0000000..d0009c1 --- /dev/null +++ b/src/ssl/t1_reneg.c @@ -0,0 +1,246 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2009 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include <assert.h> +#include <stdio.h> +#include <string.h> + +#include <openssl/bytestring.h> +#include <openssl/err.h> + +#include "internal.h" + + +/* Add the client's renegotiation binding */ +int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, int *len, + int maxlen) { + if (p) { + if (s->s3->previous_client_finished_len + 1 > maxlen) { + OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_renegotiate_ext, + SSL_R_RENEGOTIATE_EXT_TOO_LONG); + return 0; + } + + /* Length byte */ + *p = s->s3->previous_client_finished_len; + p++; + + memcpy(p, s->s3->previous_client_finished, + s->s3->previous_client_finished_len); + } + + *len = s->s3->previous_client_finished_len + 1; + + return 1; +} + +/* Parse the client's renegotiation binding and abort if it's not right */ +int ssl_parse_clienthello_renegotiate_ext(SSL *s, CBS *cbs, int *out_alert) { + CBS renegotiated_connection; + + if (!CBS_get_u8_length_prefixed(cbs, &renegotiated_connection) || + CBS_len(cbs) != 0) { + OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_renegotiate_ext, + SSL_R_RENEGOTIATION_ENCODING_ERR); + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + + /* Check that the extension matches */ + if (!CBS_mem_equal(&renegotiated_connection, s->s3->previous_client_finished, + s->s3->previous_client_finished_len)) { + OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_renegotiate_ext, + SSL_R_RENEGOTIATION_MISMATCH); + *out_alert = SSL_AD_HANDSHAKE_FAILURE; + return 0; + } + + s->s3->send_connection_binding = 1; + + return 1; +} + +/* Add the server's renegotiation binding */ +int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len, + int maxlen) { + if (p) { + if (s->s3->previous_client_finished_len + + s->s3->previous_server_finished_len + 1 > maxlen) { + OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_renegotiate_ext, + SSL_R_RENEGOTIATE_EXT_TOO_LONG); + return 0; + } + + /* Length byte */ + *p = s->s3->previous_client_finished_len + + s->s3->previous_server_finished_len; + p++; + + memcpy(p, s->s3->previous_client_finished, + s->s3->previous_client_finished_len); + p += s->s3->previous_client_finished_len; + + memcpy(p, s->s3->previous_server_finished, + s->s3->previous_server_finished_len); + } + + *len = s->s3->previous_client_finished_len + + s->s3->previous_server_finished_len + 1; + + return 1; +} + +/* Parse the server's renegotiation binding and abort if it's not right */ +int ssl_parse_serverhello_renegotiate_ext(SSL *s, CBS *cbs, int *out_alert) { + int expected_len = + s->s3->previous_client_finished_len + s->s3->previous_server_finished_len; + CBS renegotiated_connection; + const uint8_t *d; + + /* Check for logic errors */ + assert(!expected_len || s->s3->previous_client_finished_len); + assert(!expected_len || s->s3->previous_server_finished_len); + + /* Parse out the extension contents. */ + if (!CBS_get_u8_length_prefixed(cbs, &renegotiated_connection) || + CBS_len(cbs) != 0) { + OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_renegotiate_ext, + SSL_R_RENEGOTIATION_ENCODING_ERR); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + /* Check that the extension matches. */ + if (CBS_len(&renegotiated_connection) != expected_len) { + OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_renegotiate_ext, + SSL_R_RENEGOTIATION_MISMATCH); + *out_alert = SSL_AD_HANDSHAKE_FAILURE; + return 0; + } + + d = CBS_data(&renegotiated_connection); + if (memcmp(d, s->s3->previous_client_finished, + s->s3->previous_client_finished_len)) { + OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_renegotiate_ext, + SSL_R_RENEGOTIATION_MISMATCH); + *out_alert = SSL_AD_HANDSHAKE_FAILURE; + return 0; + } + d += s->s3->previous_client_finished_len; + + if (memcmp(d, s->s3->previous_server_finished, + s->s3->previous_server_finished_len)) { + OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_renegotiate_ext, + SSL_R_RENEGOTIATION_MISMATCH); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + s->s3->send_connection_binding = 1; + + return 1; +} diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc index edae67b..3b95d7e 100644 --- a/src/ssl/test/bssl_shim.cc +++ b/src/ssl/test/bssl_shim.cc @@ -38,14 +38,10 @@ #include <openssl/bio.h> #include <openssl/buf.h> #include <openssl/bytestring.h> -#include <openssl/cipher.h> #include <openssl/err.h> -#include <openssl/hmac.h> -#include <openssl/rand.h> #include <openssl/ssl.h> #include <memory> -#include <string> #include <vector> #include "../../crypto/test/scoped_types.h" @@ -94,17 +90,10 @@ struct TestState { ScopedSSL_SESSION pending_session; bool early_callback_called = false; bool handshake_done = false; - // private_key is the underlying private key used when testing custom keys. - ScopedEVP_PKEY private_key; - std::vector<uint8_t> signature; - // signature_retries is the number of times an asynchronous sign operation has - // been retried. - unsigned signature_retries = 0; - bool got_new_session = false; }; static void TestStateExFree(void *parent, void *ptr, CRYPTO_EX_DATA *ad, - int index, long argl, void *argp) { + int index, long argl, void *argp) { delete ((TestState *)ptr); } @@ -140,137 +129,18 @@ static ScopedEVP_PKEY LoadPrivateKey(const std::string &file) { return pkey; } -static int AsyncPrivateKeyType(SSL *ssl) { - return EVP_PKEY_id(GetTestState(ssl)->private_key.get()); -} - -static size_t AsyncPrivateKeyMaxSignatureLen(SSL *ssl) { - return EVP_PKEY_size(GetTestState(ssl)->private_key.get()); -} - -static ssl_private_key_result_t AsyncPrivateKeySign( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, - const EVP_MD *md, const uint8_t *in, size_t in_len) { - TestState *test_state = GetTestState(ssl); - if (!test_state->signature.empty()) { - fprintf(stderr, "AsyncPrivateKeySign called with operation pending.\n"); - abort(); - } - - ScopedEVP_PKEY_CTX ctx(EVP_PKEY_CTX_new(test_state->private_key.get(), - nullptr)); - if (!ctx) { - return ssl_private_key_failure; - } - - // Write the signature into |test_state|. - size_t len = 0; - if (!EVP_PKEY_sign_init(ctx.get()) || - !EVP_PKEY_CTX_set_signature_md(ctx.get(), md) || - !EVP_PKEY_sign(ctx.get(), nullptr, &len, in, in_len)) { - return ssl_private_key_failure; - } - test_state->signature.resize(len); - if (!EVP_PKEY_sign(ctx.get(), bssl::vector_data(&test_state->signature), &len, - in, in_len)) { - return ssl_private_key_failure; - } - test_state->signature.resize(len); - - // The signature will be released asynchronously in |AsyncPrivateKeySignComplete|. - return ssl_private_key_retry; -} - -static ssl_private_key_result_t AsyncPrivateKeySignComplete( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out) { - TestState *test_state = GetTestState(ssl); - if (test_state->signature.empty()) { - fprintf(stderr, - "AsyncPrivateKeySignComplete called without operation pending.\n"); - abort(); - } - - if (test_state->signature_retries < 2) { - // Only return the signature on the second attempt, to test both incomplete - // |sign| and |sign_complete|. - return ssl_private_key_retry; - } - - if (max_out < test_state->signature.size()) { - fprintf(stderr, "Output buffer too small.\n"); - return ssl_private_key_failure; - } - memcpy(out, bssl::vector_data(&test_state->signature), - test_state->signature.size()); - *out_len = test_state->signature.size(); - - test_state->signature.clear(); - test_state->signature_retries = 0; - return ssl_private_key_success; -} - -static const SSL_PRIVATE_KEY_METHOD g_async_private_key_method = { - AsyncPrivateKeyType, - AsyncPrivateKeyMaxSignatureLen, - AsyncPrivateKeySign, - AsyncPrivateKeySignComplete, -}; - -template<typename T> -struct Free { - void operator()(T *buf) { - free(buf); - } -}; - static bool InstallCertificate(SSL *ssl) { const TestConfig *config = GetConfigPtr(ssl); - TestState *test_state = GetTestState(ssl); - - if (!config->digest_prefs.empty()) { - std::unique_ptr<char, Free<char>> digest_prefs( - strdup(config->digest_prefs.c_str())); - std::vector<int> digest_list; - - for (;;) { - char *token = - strtok(digest_list.empty() ? digest_prefs.get() : nullptr, ","); - if (token == nullptr) { - break; - } - - digest_list.push_back(EVP_MD_type(EVP_get_digestbyname(token))); - } - - if (!SSL_set_private_key_digest_prefs(ssl, digest_list.data(), - digest_list.size())) { - return false; - } - } - - if (!config->key_file.empty()) { - if (config->use_async_private_key) { - test_state->private_key = LoadPrivateKey(config->key_file.c_str()); - if (!test_state->private_key) { - return false; - } - SSL_set_private_key_method(ssl, &g_async_private_key_method); - } else if (!SSL_use_PrivateKey_file(ssl, config->key_file.c_str(), - SSL_FILETYPE_PEM)) { - return false; - } + if (!config->key_file.empty() && + !SSL_use_PrivateKey_file(ssl, config->key_file.c_str(), + SSL_FILETYPE_PEM)) { + return false; } if (!config->cert_file.empty() && !SSL_use_certificate_file(ssl, config->cert_file.c_str(), SSL_FILETYPE_PEM)) { return false; } - if (!config->ocsp_response.empty() && - !SSL_CTX_set_ocsp_response(ssl->ctx, - (const uint8_t *)config->ocsp_response.data(), - config->ocsp_response.size())) { - return false; - } return true; } @@ -326,29 +196,10 @@ static int SelectCertificateCallback(const struct ssl_early_callback_ctx *ctx) { return 1; } -static int VerifySucceed(X509_STORE_CTX *store_ctx, void *arg) { - SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(store_ctx, - SSL_get_ex_data_X509_STORE_CTX_idx()); - const TestConfig *config = GetConfigPtr(ssl); - - if (!config->expected_ocsp_response.empty()) { - const uint8_t *data; - size_t len; - SSL_get0_ocsp_response(ssl, &data, &len); - if (len == 0) { - fprintf(stderr, "OCSP response not available in verify callback\n"); - return 0; - } - } - +static int SkipVerify(int preverify_ok, X509_STORE_CTX *store_ctx) { return 1; } -static int VerifyFail(X509_STORE_CTX *store_ctx, void *arg) { - store_ctx->error = X509_V_ERR_APPLICATION_VERIFICATION; - return 0; -} - static int NextProtosAdvertisedCallback(SSL *ssl, const uint8_t **out, unsigned int *out_len, void *arg) { const TestConfig *config = GetConfigPtr(ssl); @@ -490,94 +341,6 @@ static void InfoCallback(const SSL *ssl, int type, int val) { } } -static int NewSessionCallback(SSL *ssl, SSL_SESSION *session) { - GetTestState(ssl)->got_new_session = true; - // BoringSSL passes a reference to |session|. - SSL_SESSION_free(session); - return 1; -} - -static int TicketKeyCallback(SSL *ssl, uint8_t *key_name, uint8_t *iv, - EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx, - int encrypt) { - // This is just test code, so use the all-zeros key. - static const uint8_t kZeros[16] = {0}; - - if (encrypt) { - memcpy(key_name, kZeros, sizeof(kZeros)); - RAND_bytes(iv, 16); - } else if (memcmp(key_name, kZeros, 16) != 0) { - return 0; - } - - if (!HMAC_Init_ex(hmac_ctx, kZeros, sizeof(kZeros), EVP_sha256(), NULL) || - !EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, kZeros, iv, encrypt)) { - return -1; - } - - if (!encrypt) { - return GetConfigPtr(ssl)->renew_ticket ? 2 : 1; - } - return 1; -} - -// kCustomExtensionValue is the extension value that the custom extension -// callbacks will add. -static const uint16_t kCustomExtensionValue = 1234; -static void *const kCustomExtensionAddArg = - reinterpret_cast<void *>(kCustomExtensionValue); -static void *const kCustomExtensionParseArg = - reinterpret_cast<void *>(kCustomExtensionValue + 1); -static const char kCustomExtensionContents[] = "custom extension"; - -static int CustomExtensionAddCallback(SSL *ssl, unsigned extension_value, - const uint8_t **out, size_t *out_len, - int *out_alert_value, void *add_arg) { - if (extension_value != kCustomExtensionValue || - add_arg != kCustomExtensionAddArg) { - abort(); - } - - if (GetConfigPtr(ssl)->custom_extension_skip) { - return 0; - } - if (GetConfigPtr(ssl)->custom_extension_fail_add) { - return -1; - } - - *out = reinterpret_cast<const uint8_t*>(kCustomExtensionContents); - *out_len = sizeof(kCustomExtensionContents) - 1; - - return 1; -} - -static void CustomExtensionFreeCallback(SSL *ssl, unsigned extension_value, - const uint8_t *out, void *add_arg) { - if (extension_value != kCustomExtensionValue || - add_arg != kCustomExtensionAddArg || - out != reinterpret_cast<const uint8_t *>(kCustomExtensionContents)) { - abort(); - } -} - -static int CustomExtensionParseCallback(SSL *ssl, unsigned extension_value, - const uint8_t *contents, - size_t contents_len, - int *out_alert_value, void *parse_arg) { - if (extension_value != kCustomExtensionValue || - parse_arg != kCustomExtensionParseArg) { - abort(); - } - - if (contents_len != sizeof(kCustomExtensionContents) - 1 || - memcmp(contents, kCustomExtensionContents, contents_len) != 0) { - *out_alert_value = SSL_AD_DECODE_ERROR; - return 0; - } - - return 1; -} - // Connect returns a new socket connected to localhost on |port| or -1 on // error. static int Connect(uint16_t port) { @@ -643,23 +406,7 @@ static ScopedSSL_CTX SetupCtx(const TestConfig *config) { return nullptr; } - std::string cipher_list = "ALL"; - if (!config->cipher.empty()) { - cipher_list = config->cipher; - SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_CIPHER_SERVER_PREFERENCE); - } - if (!SSL_CTX_set_cipher_list(ssl_ctx.get(), cipher_list.c_str())) { - return nullptr; - } - - if (!config->cipher_tls10.empty() && - !SSL_CTX_set_cipher_list_tls10(ssl_ctx.get(), - config->cipher_tls10.c_str())) { - return nullptr; - } - if (!config->cipher_tls11.empty() && - !SSL_CTX_set_cipher_list_tls11(ssl_ctx.get(), - config->cipher_tls11.c_str())) { + if (!SSL_CTX_set_cipher_list(ssl_ctx.get(), "ALL")) { return nullptr; } @@ -691,46 +438,12 @@ static ScopedSSL_CTX SetupCtx(const TestConfig *config) { SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), AlpnSelectCallback, NULL); } - SSL_CTX_enable_tls_channel_id(ssl_ctx.get()); + ssl_ctx->tlsext_channel_id_enabled_new = 1; SSL_CTX_set_channel_id_cb(ssl_ctx.get(), ChannelIdCallback); ssl_ctx->current_time_cb = CurrentTimeCallback; SSL_CTX_set_info_callback(ssl_ctx.get(), InfoCallback); - SSL_CTX_sess_set_new_cb(ssl_ctx.get(), NewSessionCallback); - - if (config->use_ticket_callback) { - SSL_CTX_set_tlsext_ticket_key_cb(ssl_ctx.get(), TicketKeyCallback); - } - - if (config->enable_client_custom_extension && - !SSL_CTX_add_client_custom_ext( - ssl_ctx.get(), kCustomExtensionValue, CustomExtensionAddCallback, - CustomExtensionFreeCallback, kCustomExtensionAddArg, - CustomExtensionParseCallback, kCustomExtensionParseArg)) { - return nullptr; - } - - if (config->enable_server_custom_extension && - !SSL_CTX_add_server_custom_ext( - ssl_ctx.get(), kCustomExtensionValue, CustomExtensionAddCallback, - CustomExtensionFreeCallback, kCustomExtensionAddArg, - CustomExtensionParseCallback, kCustomExtensionParseArg)) { - return nullptr; - } - - if (config->verify_fail) { - SSL_CTX_set_cert_verify_callback(ssl_ctx.get(), VerifyFail, NULL); - } else { - SSL_CTX_set_cert_verify_callback(ssl_ctx.get(), VerifySucceed, NULL); - } - - if (!config->signed_cert_timestamps.empty() && - !SSL_CTX_set_signed_cert_timestamp_list( - ssl_ctx.get(), (const uint8_t *)config->signed_cert_timestamps.data(), - config->signed_cert_timestamps.size())) { - return nullptr; - } return ssl_ctx; } @@ -787,9 +500,6 @@ static bool RetryAsync(SSL *ssl, int ret) { case SSL_ERROR_PENDING_CERTIFICATE: // The handshake will resume without a second call to the early callback. return InstallCertificate(ssl); - case SSL_ERROR_WANT_PRIVATE_KEY_OPERATION: - test_state->signature_retries++; - return true; default: return false; } @@ -821,177 +531,6 @@ static int WriteAll(SSL *ssl, const uint8_t *in, size_t in_len) { return ret; } -// 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); - int ret; - do { - ret = SSL_shutdown(ssl); - } while (config->async && RetryAsync(ssl, ret)); - return ret; -} - -// CheckHandshakeProperties checks, immediately after |ssl| completes its -// 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); - - if (SSL_get_current_cipher(ssl) == nullptr) { - fprintf(stderr, "null cipher after handshake\n"); - return false; - } - - if (is_resume && - (!!SSL_session_reused(ssl) == config->expect_session_miss)) { - fprintf(stderr, "session was%s reused\n", - SSL_session_reused(ssl) ? "" : " not"); - return false; - } - - bool expect_handshake_done = is_resume || !config->false_start; - if (expect_handshake_done != GetTestState(ssl)->handshake_done) { - fprintf(stderr, "handshake was%s completed\n", - GetTestState(ssl)->handshake_done ? "" : " not"); - return false; - } - - if (expect_handshake_done && !config->is_server) { - bool expect_new_session = - !config->expect_no_session && - (!SSL_session_reused(ssl) || config->expect_ticket_renewal); - if (expect_new_session != GetTestState(ssl)->got_new_session) { - fprintf(stderr, - "new session was%s established, but we expected the opposite\n", - GetTestState(ssl)->got_new_session ? "" : " not"); - return false; - } - } - - if (config->is_server && !GetTestState(ssl)->early_callback_called) { - fprintf(stderr, "early callback not called\n"); - return false; - } - - if (!config->expected_server_name.empty()) { - const char *server_name = - SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); - if (server_name != config->expected_server_name) { - fprintf(stderr, "servername mismatch (got %s; want %s)\n", - server_name, config->expected_server_name.c_str()); - return false; - } - } - - if (!config->expected_certificate_types.empty()) { - const uint8_t *certificate_types; - size_t certificate_types_len = - SSL_get0_certificate_types(ssl, &certificate_types); - if (certificate_types_len != config->expected_certificate_types.size() || - memcmp(certificate_types, - config->expected_certificate_types.data(), - certificate_types_len) != 0) { - fprintf(stderr, "certificate types mismatch\n"); - return false; - } - } - - if (!config->expected_next_proto.empty()) { - const uint8_t *next_proto; - unsigned next_proto_len; - SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len); - if (next_proto_len != config->expected_next_proto.size() || - memcmp(next_proto, config->expected_next_proto.data(), - next_proto_len) != 0) { - fprintf(stderr, "negotiated next proto mismatch\n"); - return false; - } - } - - if (!config->expected_alpn.empty()) { - const uint8_t *alpn_proto; - unsigned alpn_proto_len; - SSL_get0_alpn_selected(ssl, &alpn_proto, &alpn_proto_len); - if (alpn_proto_len != config->expected_alpn.size() || - memcmp(alpn_proto, config->expected_alpn.data(), - alpn_proto_len) != 0) { - fprintf(stderr, "negotiated alpn proto mismatch\n"); - return false; - } - } - - if (!config->expected_channel_id.empty()) { - uint8_t channel_id[64]; - if (!SSL_get_tls_channel_id(ssl, channel_id, sizeof(channel_id))) { - fprintf(stderr, "no channel id negotiated\n"); - return false; - } - if (config->expected_channel_id.size() != 64 || - memcmp(config->expected_channel_id.data(), - channel_id, 64) != 0) { - fprintf(stderr, "channel id mismatch\n"); - return false; - } - } - - if (config->expect_extended_master_secret) { - if (!ssl->session->extended_master_secret) { - fprintf(stderr, "No EMS for session when expected"); - return false; - } - } - - if (!config->expected_ocsp_response.empty()) { - const uint8_t *data; - size_t len; - SSL_get0_ocsp_response(ssl, &data, &len); - if (config->expected_ocsp_response.size() != len || - memcmp(config->expected_ocsp_response.data(), data, len) != 0) { - fprintf(stderr, "OCSP response mismatch\n"); - return false; - } - } - - if (!config->expected_signed_cert_timestamps.empty()) { - const uint8_t *data; - size_t len; - SSL_get0_signed_cert_timestamp_list(ssl, &data, &len); - if (config->expected_signed_cert_timestamps.size() != len || - memcmp(config->expected_signed_cert_timestamps.data(), - data, len) != 0) { - fprintf(stderr, "SCT list mismatch\n"); - return false; - } - } - - if (config->expect_verify_result) { - int expected_verify_result = config->verify_fail ? - X509_V_ERR_APPLICATION_VERIFICATION : - X509_V_OK; - - if (SSL_get_verify_result(ssl) != expected_verify_result) { - fprintf(stderr, "Wrong certificate verification result\n"); - return false; - } - } - - if (!config->is_server) { - /* Clients should expect a peer certificate chain iff this was not a PSK - * cipher suite. */ - if (config->psk.empty()) { - if (SSL_get_peer_cert_chain(ssl) == nullptr) { - fprintf(stderr, "Missing peer certificate chain!\n"); - return false; - } - } else if (SSL_get_peer_cert_chain(ssl) != nullptr) { - fprintf(stderr, "Unexpected peer certificate chain!\n"); - return false; - } - } - return true; -} - // DoExchange runs a test SSL exchange against the peer. On success, it returns // true and sets |*out_session| to the negotiated SSL session. If the test is a // resumption attempt, |is_resume| is true and |session| is the session from the @@ -1023,10 +562,7 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx, } if (config->require_any_client_certificate) { SSL_set_verify(ssl.get(), SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, - NULL); - } - if (config->verify_peer) { - SSL_set_verify(ssl.get(), SSL_VERIFY_PEER, NULL); + SkipVerify); } if (config->false_start) { SSL_set_mode(ssl.get(), SSL_MODE_ENABLE_FALSE_START); @@ -1052,8 +588,8 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx, if (config->tls_d5_bug) { SSL_set_options(ssl.get(), SSL_OP_TLS_D5_BUG); } - if (config->microsoft_big_sslv3_buffer) { - SSL_set_options(ssl.get(), SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER); + if (config->allow_unsafe_legacy_renegotiation) { + SSL_set_options(ssl.get(), SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); } if (config->no_legacy_server_connect) { SSL_clear_options(ssl.get(), SSL_OP_LEGACY_SERVER_CONNECT); @@ -1101,6 +637,7 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx, !SSL_enable_signed_cert_timestamps(ssl.get())) { return false; } + SSL_enable_fastradio_padding(ssl.get(), config->fastradio_padding); if (config->min_version != 0) { SSL_set_min_version(ssl.get(), (uint16_t)config->min_version); } @@ -1114,13 +651,14 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx, if (config->install_ddos_callback) { SSL_CTX_set_dos_protection_cb(ssl_ctx, DDoSCallback); } + if (!config->cipher.empty() && + !SSL_set_cipher_list(ssl.get(), config->cipher.c_str())) { + return false; + } if (!config->reject_peer_renegotiations) { /* Renegotiations are disabled by default. */ SSL_set_reject_peer_renegotiations(ssl.get(), 0); } - if (!config->check_close_notify) { - SSL_set_quiet_shutdown(ssl.get(), 1); - } int sock = Connect(config->port); if (sock == -1) { @@ -1181,14 +719,139 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx, ret = SSL_connect(ssl.get()); } } while (config->async && RetryAsync(ssl.get(), ret)); - if (ret != 1 || - !CheckHandshakeProperties(ssl.get(), is_resume)) { + if (ret != 1) { + return false; + } + + if (SSL_get_current_cipher(ssl.get()) == nullptr) { + fprintf(stderr, "null cipher after handshake\n"); + return false; + } + + if (is_resume && + (!!SSL_session_reused(ssl.get()) == config->expect_session_miss)) { + fprintf(stderr, "session was%s reused\n", + SSL_session_reused(ssl.get()) ? "" : " not"); + return false; + } + + bool expect_handshake_done = is_resume || !config->false_start; + if (expect_handshake_done != GetTestState(ssl.get())->handshake_done) { + fprintf(stderr, "handshake was%s completed\n", + GetTestState(ssl.get())->handshake_done ? "" : " not"); + return false; + } + + if (config->is_server && !GetTestState(ssl.get())->early_callback_called) { + fprintf(stderr, "early callback not called\n"); return false; } - // Reset the state to assert later that the callback isn't called in - // renegotations. - GetTestState(ssl.get())->got_new_session = false; + if (!config->expected_server_name.empty()) { + const char *server_name = + SSL_get_servername(ssl.get(), TLSEXT_NAMETYPE_host_name); + if (server_name != config->expected_server_name) { + fprintf(stderr, "servername mismatch (got %s; want %s)\n", + server_name, config->expected_server_name.c_str()); + return false; + } + } + + if (!config->expected_certificate_types.empty()) { + uint8_t *certificate_types; + int num_certificate_types = + SSL_get0_certificate_types(ssl.get(), &certificate_types); + if (num_certificate_types != + (int)config->expected_certificate_types.size() || + memcmp(certificate_types, + config->expected_certificate_types.data(), + num_certificate_types) != 0) { + fprintf(stderr, "certificate types mismatch\n"); + return false; + } + } + + if (!config->expected_next_proto.empty()) { + const uint8_t *next_proto; + unsigned next_proto_len; + SSL_get0_next_proto_negotiated(ssl.get(), &next_proto, &next_proto_len); + if (next_proto_len != config->expected_next_proto.size() || + memcmp(next_proto, config->expected_next_proto.data(), + next_proto_len) != 0) { + fprintf(stderr, "negotiated next proto mismatch\n"); + return false; + } + } + + if (!config->expected_alpn.empty()) { + const uint8_t *alpn_proto; + unsigned alpn_proto_len; + SSL_get0_alpn_selected(ssl.get(), &alpn_proto, &alpn_proto_len); + if (alpn_proto_len != config->expected_alpn.size() || + memcmp(alpn_proto, config->expected_alpn.data(), + alpn_proto_len) != 0) { + fprintf(stderr, "negotiated alpn proto mismatch\n"); + return false; + } + } + + if (!config->expected_channel_id.empty()) { + uint8_t channel_id[64]; + if (!SSL_get_tls_channel_id(ssl.get(), channel_id, sizeof(channel_id))) { + fprintf(stderr, "no channel id negotiated\n"); + return false; + } + if (config->expected_channel_id.size() != 64 || + memcmp(config->expected_channel_id.data(), + channel_id, 64) != 0) { + fprintf(stderr, "channel id mismatch\n"); + return false; + } + } + + if (config->expect_extended_master_secret) { + if (!ssl->session->extended_master_secret) { + fprintf(stderr, "No EMS for session when expected"); + return false; + } + } + + if (!config->expected_ocsp_response.empty()) { + const uint8_t *data; + size_t len; + SSL_get0_ocsp_response(ssl.get(), &data, &len); + if (config->expected_ocsp_response.size() != len || + memcmp(config->expected_ocsp_response.data(), data, len) != 0) { + fprintf(stderr, "OCSP response mismatch\n"); + return false; + } + } + + if (!config->expected_signed_cert_timestamps.empty()) { + const uint8_t *data; + size_t len; + SSL_get0_signed_cert_timestamp_list(ssl.get(), &data, &len); + if (config->expected_signed_cert_timestamps.size() != len || + memcmp(config->expected_signed_cert_timestamps.data(), + data, len) != 0) { + fprintf(stderr, "SCT list mismatch\n"); + return false; + } + } + + if (!config->is_server) { + /* Clients should expect a peer certificate chain iff this was not a PSK + * cipher suite. */ + if (config->psk.empty()) { + if (SSL_get_peer_cert_chain(ssl.get()) == nullptr) { + fprintf(stderr, "Missing peer certificate chain!\n"); + return false; + } + } else if (SSL_get_peer_cert_chain(ssl.get()) != nullptr) { + fprintf(stderr, "Unexpected peer certificate chain!\n"); + return false; + } + } } if (config->export_keying_material > 0) { @@ -1234,19 +897,18 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx, } // This mode writes a number of different record sizes in an attempt to // trip up the CBC record splitting code. - static const size_t kBufLen = 32769; - std::unique_ptr<uint8_t[]> buf(new uint8_t[kBufLen]); - memset(buf.get(), 0x42, kBufLen); + uint8_t buf[32769]; + memset(buf, 0x42, sizeof(buf)); static const size_t kRecordSizes[] = { 0, 1, 255, 256, 257, 16383, 16384, 16385, 32767, 32768, 32769}; for (size_t i = 0; i < sizeof(kRecordSizes) / sizeof(kRecordSizes[0]); i++) { const size_t len = kRecordSizes[i]; - if (len > kBufLen) { + if (len > sizeof(buf)) { fprintf(stderr, "Bad kRecordSizes value.\n"); return false; } - if (WriteAll(ssl.get(), buf.get(), len) < 0) { + if (WriteAll(ssl.get(), buf, len) < 0) { return false; } } @@ -1257,82 +919,53 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx, return false; } } - if (!config->shim_shuts_down) { - for (;;) { - static const size_t kBufLen = 16384; - std::unique_ptr<uint8_t[]> buf(new uint8_t[kBufLen]); - - // Read only 512 bytes at a time in TLS to ensure records may be - // returned in multiple reads. - int n = DoRead(ssl.get(), buf.get(), config->is_dtls ? kBufLen : 512); - int err = SSL_get_error(ssl.get(), n); - if (err == SSL_ERROR_ZERO_RETURN || - (n == 0 && err == SSL_ERROR_SYSCALL)) { - if (n != 0) { - fprintf(stderr, "Invalid SSL_get_error output\n"); - return false; - } - // Stop on either clean or unclean shutdown. - break; - } else if (err != SSL_ERROR_NONE) { - if (n > 0) { - fprintf(stderr, "Invalid SSL_get_error output\n"); - return false; - } + for (;;) { + uint8_t buf[512]; + int n = DoRead(ssl.get(), buf, sizeof(buf)); + int err = SSL_get_error(ssl.get(), n); + if (err == SSL_ERROR_ZERO_RETURN || + (n == 0 && err == SSL_ERROR_SYSCALL)) { + if (n != 0) { + fprintf(stderr, "Invalid SSL_get_error output\n"); return false; } - // Successfully read data. - if (n <= 0) { + // Accept shutdowns with or without close_notify. + // TODO(davidben): Write tests which distinguish these two cases. + break; + } else if (err != SSL_ERROR_NONE) { + if (n > 0) { fprintf(stderr, "Invalid SSL_get_error output\n"); return false; } + return false; + } + // Successfully read data. + if (n <= 0) { + fprintf(stderr, "Invalid SSL_get_error output\n"); + return false; + } - // After a successful read, with or without False Start, the handshake - // must be complete. - if (!GetTestState(ssl.get())->handshake_done) { - fprintf(stderr, "handshake was not completed after SSL_read\n"); - return false; - } + // After a successful read, with or without False Start, the handshake + // must be complete. + if (!GetTestState(ssl.get())->handshake_done) { + fprintf(stderr, "handshake was not completed after SSL_read\n"); + return false; + } - for (int i = 0; i < n; i++) { - buf[i] ^= 0xff; - } - if (WriteAll(ssl.get(), buf.get(), n) < 0) { - return false; - } + for (int i = 0; i < n; i++) { + buf[i] ^= 0xff; + } + if (WriteAll(ssl.get(), buf, n) < 0) { + return false; } } } - if (!config->is_server && !config->false_start && - !config->implicit_handshake && - GetTestState(ssl.get())->got_new_session) { - fprintf(stderr, "new session was established after the handshake\n"); - return false; - } - if (out_session) { out_session->reset(SSL_get1_session(ssl.get())); } - ret = DoShutdown(ssl.get()); - - if (config->shim_shuts_down && config->check_close_notify) { - // We initiate shutdown, so |SSL_shutdown| will return in two stages. First - // it returns zero when our close_notify is sent, then one when the peer's - // is received. - if (ret != 0) { - fprintf(stderr, "Unexpected SSL_shutdown result: %d != 0\n", ret); - return false; - } - ret = DoShutdown(ssl.get()); - } - - if (ret != 1) { - fprintf(stderr, "Unexpected SSL_shutdown result: %d != 1\n", ret); - return false; - } - + SSL_shutdown(ssl.get()); return true; } diff --git a/src/ssl/test/runner/cipher_suites.go b/src/ssl/test/runner/cipher_suites.go index ffc056d..70c7262 100644 --- a/src/ssl/test/runner/cipher_suites.go +++ b/src/ssl/test/runner/cipher_suites.go @@ -102,6 +102,7 @@ var cipherSuites = []*cipherSuite{ {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_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 0, dheRSAKA, suiteTLS12, nil, nil, aeadCHACHA20POLY1305}, {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}, @@ -119,18 +120,12 @@ var cipherSuites = []*cipherSuite{ {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil}, {TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, dheRSAKA, 0, cipher3DES, macSHA1, nil}, {TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil}, + {TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdhePSKKA, suiteECDHE | suiteTLS12 | suitePSK, nil, nil, aeadAESGCM}, {TLS_PSK_WITH_RC4_128_SHA, 16, 20, 0, pskKA, suiteNoDTLS | suitePSK, cipherRC4, macSHA1, nil}, {TLS_PSK_WITH_AES_128_CBC_SHA, 16, 20, 16, pskKA, suitePSK, cipherAES, macSHA1, nil}, {TLS_PSK_WITH_AES_256_CBC_SHA, 32, 20, 16, pskKA, suitePSK, cipherAES, macSHA1, nil}, {TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdhePSKKA, suiteECDHE | suitePSK, cipherAES, macSHA1, nil}, {TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdhePSKKA, suiteECDHE | suitePSK, cipherAES, macSHA1, nil}, - {TLS_RSA_WITH_NULL_SHA, 0, 20, 0, rsaKA, suiteNoDTLS, cipherNull, macSHA1, nil}, -} - -type nullCipher struct{} - -func cipherNull(key, iv []byte, isRead bool) interface{} { - return nullCipher{} } func cipherRC4(key, iv []byte, isRead bool) interface{} { @@ -375,7 +370,6 @@ func mutualCipherSuite(have []uint16, want uint16) *cipherSuite { // A list of the possible cipher suite ids. Taken from // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml const ( - TLS_RSA_WITH_NULL_SHA uint16 = 0x0002 TLS_RSA_WITH_RC4_128_MD5 uint16 = 0x0004 TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005 TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a @@ -412,12 +406,13 @@ const ( TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030 TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA uint16 = 0xc035 TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA uint16 = 0xc036 - renegotiationSCSV uint16 = 0x00ff fallbackSCSV uint16 = 0x5600 ) // Additional cipher suite IDs, not IANA-assigned. const ( + TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0xcafe TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcc13 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcc14 + TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcc15 ) diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go index 77be9f6..edebba1 100644 --- a/src/ssl/test/runner/common.go +++ b/src/ssl/test/runner/common.go @@ -82,7 +82,6 @@ const ( extensionSignedCertificateTimestamp uint16 = 18 extensionExtendedMasterSecret uint16 = 23 extensionSessionTicket uint16 = 35 - extensionCustom uint16 = 1234 // not IANA assigned extensionNextProtoNeg uint16 = 13172 // not IANA assigned extensionRenegotiationInfo uint16 = 0xff01 extensionChannelID uint16 = 30032 // not IANA assigned @@ -189,9 +188,7 @@ type ConnectionState struct { VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates ChannelID *ecdsa.PublicKey // the channel ID for this connection SRTPProtectionProfile uint16 // the negotiated DTLS-SRTP protection profile - TLSUnique []byte // the tls-unique channel binding - SCTList []byte // signed certificate timestamp list - ClientCertSignatureHash uint8 // TLS id of the hash used by the client to sign the handshake + TLSUnique []byte } // ClientAuthType declares the policy the server will follow for @@ -217,8 +214,6 @@ type ClientSessionState struct { handshakeHash []byte // Handshake hash for Channel ID purposes. serverCertificates []*x509.Certificate // Certificate chain presented by the server extendedMasterSecret bool // Whether an extended master secret was used to generate the session - sctList []byte - ocspResponse []byte } // ClientSessionCache is a cache of ClientSessionState objects that can be used @@ -404,10 +399,6 @@ type ProtocolBugs struct { // ServerKeyExchange message should be invalid. InvalidSKXSignature bool - // InvalidCertVerifySignature specifies that the signature in a - // CertificateVerify message should be invalid. - InvalidCertVerifySignature bool - // InvalidSKXCurve causes the curve ID in the ServerKeyExchange message // to be wrong. InvalidSKXCurve bool @@ -485,10 +476,6 @@ type ProtocolBugs struct { // TLS_FALLBACK_SCSV in the ClientHello. SendFallbackSCSV bool - // SendRenegotiationSCSV causes the client to include the renegotiation - // SCSV in the ClientHello. - SendRenegotiationSCSV bool - // MaxHandshakeRecordLength, if non-zero, is the maximum size of a // handshake record. Handshake messages will be split into multiple // records at the specified size, except that the client_version will @@ -548,14 +535,11 @@ type ProtocolBugs struct { // must specify in the server_name extension. ExpectServerName string - // SwapNPNAndALPN switches the relative order between NPN and ALPN in - // both ClientHello and ServerHello. + // SwapNPNAndALPN switches the relative order between NPN and + // ALPN on the server. This is to test that server preference + // of ALPN works regardless of their relative order. SwapNPNAndALPN bool - // ALPNProtocol, if not nil, sets the ALPN protocol that a server will - // return. - ALPNProtocol *string - // AllowSessionVersionMismatch causes the server to resume sessions // regardless of the version associated with the session. AllowSessionVersionMismatch bool @@ -588,15 +572,11 @@ type ProtocolBugs struct { // didn't support the renegotiation info extension. NoRenegotiationInfo bool - // RequireRenegotiationInfo, if true, causes the client to return an - // error if the server doesn't reply with the renegotiation extension. - RequireRenegotiationInfo bool - - // SequenceNumberMapping, if non-nil, is the mapping function to apply - // to the sequence number of outgoing packets. For both TLS and DTLS, - // the two most-significant bytes in the resulting sequence number are - // ignored so that the DTLS epoch cannot be changed. - SequenceNumberMapping func(uint64) uint64 + // SequenceNumberIncrement, if non-zero, causes outgoing sequence + // numbers in DTLS to increment by that value rather by 1. This is to + // stress the replay bitmap window by simulating extreme packet loss and + // retransmit at the record layer. + SequenceNumberIncrement uint64 // RSAEphemeralKey, if true, causes the server to send a // ServerKeyExchange message containing an ephemeral key (as in @@ -629,6 +609,10 @@ type ProtocolBugs struct { // across a renego. RequireSameRenegoClientVersion bool + // RequireFastradioPadding, if true, requires that ClientHello messages + // be at least 1000 bytes long. + RequireFastradioPadding bool + // ExpectInitialRecordVersion, if non-zero, is the expected // version of the records before the version is determined. ExpectInitialRecordVersion uint16 @@ -642,11 +626,7 @@ type ProtocolBugs struct { // the server believes it has actually negotiated. SendCipherSuite uint16 - // AppDataBeforeHandshake, if not nil, causes application data to be - // sent immediately before the first handshake message. - AppDataBeforeHandshake []byte - - // AppDataAfterChangeCipherSpec, if not nil, causes application data to + // AppDataAfterChangeCipherSpec, if not null, causes application data to // be sent immediately after ChangeCipherSpec. AppDataAfterChangeCipherSpec []byte @@ -688,10 +668,17 @@ type ProtocolBugs struct { // handshake fragments in DTLS to have the wrong message length. FragmentMessageLengthMismatch bool - // SplitFragments, if non-zero, causes the handshake fragments in DTLS - // to be split across two records. The value of |SplitFragments| is the - // number of bytes in the first fragment. - SplitFragments int + // SplitFragmentHeader, if true, causes the handshake fragments in DTLS + // to be split across two records. + SplitFragmentHeader bool + + // SplitFragmentBody, if true, causes the handshake bodies in DTLS to be + // split across two records. + // + // TODO(davidben): There's one final split to test: when the header and + // body are split across two records. But those are (incorrectly) + // accepted right now. + SplitFragmentBody bool // SendEmptyFragments, if true, causes handshakes to include empty // fragments in DTLS. @@ -718,6 +705,10 @@ type ProtocolBugs struct { // preferences to be ignored. IgnorePeerCurvePreferences bool + // SendWarningAlerts, if non-zero, causes every record to be prefaced by + // a warning alert. + SendWarningAlerts alert + // BadFinished, if true, causes the Finished hash to be broken. BadFinished bool @@ -736,43 +727,6 @@ type ProtocolBugs struct { // EnableAllCiphersInDTLS, if true, causes RC4 to be enabled in DTLS. EnableAllCiphersInDTLS bool - - // EmptyCertificateList, if true, causes the server to send an empty - // certificate list in the Certificate message. - EmptyCertificateList bool - - // ExpectNewTicket, if true, causes the client to abort if it does not - // receive a new ticket. - ExpectNewTicket bool - - // RequireClientHelloSize, if not zero, is the required length in bytes - // of the ClientHello /record/. This is checked by the server. - RequireClientHelloSize int - - // CustomExtension, if not empty, contains the contents of an extension - // that will be added to client/server hellos. - CustomExtension string - - // ExpectedCustomExtension, if not nil, contains the expected contents - // of a custom extension. - ExpectedCustomExtension *string - - // NoCloseNotify, if true, causes the close_notify alert to be skipped - // on connection shutdown. - NoCloseNotify bool - - // 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. - ExpectCloseNotify bool - - // SendLargeRecords, if true, allows outgoing records to be sent - // arbitrarily large. - SendLargeRecords bool - - // NegotiateALPNAndNPN, if true, causes the server to negotiate both - // ALPN and NPN in the same connetion. - NegotiateALPNAndNPN bool } func (c *Config) serverInit() { diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go index 39bdfda..adbc1c3 100644 --- a/src/ssl/test/runner/conn.go +++ b/src/ssl/test/runner/conn.go @@ -12,7 +12,6 @@ import ( "crypto/ecdsa" "crypto/subtle" "crypto/x509" - "encoding/binary" "errors" "fmt" "io" @@ -40,7 +39,6 @@ type Conn struct { extendedMasterSecret bool // whether this session used an extended master secret cipherSuite *cipherSuite ocspResponse []byte // stapled OCSP response - sctList []byte // signed certificate timestamp list peerCertificates []*x509.Certificate // verifiedChains contains the certificate chains that we built, as // opposed to the ones presented by the server. @@ -50,11 +48,6 @@ type Conn struct { // firstFinished contains the first Finished hash sent during the // handshake. This is the "tls-unique" channel binding value. firstFinished [12]byte - // clientCertSignatureHash contains the TLS hash id for the hash that - // was used by the client to sign the handshake with a client - // certificate. This is only set by a server and is zero if no client - // certificates were used. - clientCertSignatureHash uint8 clientRandom, serverRandom [32]byte masterSecret [48]byte @@ -94,8 +87,6 @@ func (c *Conn) init() { c.out.isDTLS = c.isDTLS c.in.config = c.config c.out.config = c.config - - c.out.updateOutSeq() } // Access to net.Conn methods. @@ -143,7 +134,6 @@ type halfConn struct { cipher interface{} // cipher algorithm mac macFunction seq [8]byte // 64-bit sequence number - outSeq [8]byte // Mapped sequence number bfree *block // list of free blocks nextCipher interface{} // next encryption state @@ -199,6 +189,10 @@ func (hc *halfConn) incSeq(isOutgoing bool) { if hc.isDTLS { // Increment up to the epoch in DTLS. limit = 2 + + if isOutgoing && hc.config.Bugs.SequenceNumberIncrement != 0 { + increment = hc.config.Bugs.SequenceNumberIncrement + } } for i := 7; i >= limit; i-- { increment += uint64(hc.seq[i]) @@ -212,8 +206,6 @@ func (hc *halfConn) incSeq(isOutgoing bool) { if increment != 0 { panic("TLS: sequence number wraparound") } - - hc.updateOutSeq() } // incNextSeq increments the starting sequence number for the next epoch. @@ -249,22 +241,6 @@ func (hc *halfConn) incEpoch() { hc.seq[i] = 0 } } - - hc.updateOutSeq() -} - -func (hc *halfConn) updateOutSeq() { - if hc.config.Bugs.SequenceNumberMapping != nil { - seqU64 := binary.BigEndian.Uint64(hc.seq[:]) - seqU64 = hc.config.Bugs.SequenceNumberMapping(seqU64) - binary.BigEndian.PutUint64(hc.outSeq[:], seqU64) - - // The DTLS epoch cannot be changed. - copy(hc.outSeq[:2], hc.seq[:2]) - return - } - - copy(hc.outSeq[:], hc.seq[:]) } func (hc *halfConn) recordHeaderLen() int { @@ -421,8 +397,6 @@ func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert) // // However, our behavior matches OpenSSL, so we leak // only as much as they do. - case nullCipher: - break default: panic("unknown cipher type") } @@ -486,7 +460,7 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) { // mac if hc.mac != nil { - mac := hc.mac.MAC(hc.outDigestBuf, hc.outSeq[0:], b.data[:3], b.data[recordHeaderLen-2:recordHeaderLen], b.data[recordHeaderLen+explicitIVLen:]) + mac := hc.mac.MAC(hc.outDigestBuf, hc.seq[0:], b.data[:3], b.data[recordHeaderLen-2:recordHeaderLen], b.data[recordHeaderLen+explicitIVLen:]) n := len(b.data) b.resize(n + len(mac)) @@ -504,7 +478,7 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) { case *tlsAead: payloadLen := len(b.data) - recordHeaderLen - explicitIVLen b.resize(len(b.data) + c.Overhead()) - nonce := hc.outSeq[:] + nonce := hc.seq[:] if c.explicitNonce { nonce = b.data[recordHeaderLen : recordHeaderLen+explicitIVLen] } @@ -512,7 +486,7 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) { payload = payload[:payloadLen] var additionalData [13]byte - copy(additionalData[:], hc.outSeq[:]) + copy(additionalData[:], hc.seq[:]) copy(additionalData[8:], b.data[:3]) additionalData[11] = byte(payloadLen >> 8) additionalData[12] = byte(payloadLen) @@ -528,8 +502,6 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) { b.resize(recordHeaderLen + explicitIVLen + len(prefix) + len(finalBlock)) c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen:], prefix) c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen+len(prefix):], finalBlock) - case nullCipher: - break default: panic("unknown cipher type") } @@ -658,10 +630,10 @@ func (c *Conn) doReadRecord(want recordType) (recordType, *block, error) { if err := b.readFromUntil(c.conn, recordHeaderLen); err != nil { // RFC suggests that EOF without an alertCloseNotify is // an error, but popular web sites seem to do this, - // so we can't make it an error, outside of tests. - if err == io.EOF && c.config.Bugs.ExpectCloseNotify { - err = io.ErrUnexpectedEOF - } + // so we can't make it an error. + // if err == io.EOF { + // err = io.ErrUnexpectedEOF + // } if e, ok := err.(net.Error); !ok || !e.Temporary() { c.in.setErrorLocked(err) } @@ -750,10 +722,6 @@ func (c *Conn) readRecord(want recordType) error { c.sendAlert(alertInternalError) return c.in.setErrorLocked(errors.New("tls: application data record requested before handshake complete")) } - case recordTypeAlert: - // Looking for a close_notify. Note: unlike a real - // implementation, this is not tolerant of additional records. - // See the documentation for ExpectCloseNotify. } Again: @@ -816,7 +784,7 @@ Again: // A client might need to process a HelloRequest from // the server, thus receiving a handshake message when // application data is expected is ok. - if !c.isClient || want != recordTypeApplicationData { + if !c.isClient { return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation)) } } @@ -831,8 +799,13 @@ Again: // sendAlert sends a TLS alert message. // c.out.Mutex <= L. -func (c *Conn) sendAlertLocked(level byte, err alert) error { - c.tmp[0] = level +func (c *Conn) sendAlertLocked(err alert) error { + switch err { + case alertNoRenegotiation, alertCloseNotify: + c.tmp[0] = alertLevelWarning + default: + c.tmp[0] = alertLevelError + } c.tmp[1] = byte(err) if c.config.Bugs.FragmentAlert { c.writeRecord(recordTypeAlert, c.tmp[0:1]) @@ -840,8 +813,8 @@ func (c *Conn) sendAlertLocked(level byte, err alert) error { } else { c.writeRecord(recordTypeAlert, c.tmp[0:2]) } - // Error alerts are fatal to the connection. - if level == alertLevelError { + // closeNotify is a special case in that it isn't an error: + if err != alertCloseNotify { return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err}) } return nil @@ -850,17 +823,9 @@ func (c *Conn) sendAlertLocked(level byte, err alert) error { // sendAlert sends a TLS alert message. // L < c.out.Mutex. func (c *Conn) sendAlert(err alert) error { - level := byte(alertLevelError) - if err == alertNoRenegotiation || err == alertCloseNotify { - level = alertLevelWarning - } - return c.SendAlert(level, err) -} - -func (c *Conn) SendAlert(level byte, err alert) error { c.out.Lock() defer c.out.Unlock() - return c.sendAlertLocked(level, err) + return c.sendAlertLocked(err) } // writeV2Record writes a record for a V2ClientHello. @@ -876,6 +841,13 @@ func (c *Conn) writeV2Record(data []byte) (n int, err error) { // to the connection and updates the record layer state. // c.out.Mutex <= L. func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) { + if typ != recordTypeAlert && c.config.Bugs.SendWarningAlerts != 0 { + alert := make([]byte, 2) + alert[0] = alertLevelWarning + alert[1] = byte(c.config.Bugs.SendWarningAlerts) + c.writeRecord(recordTypeAlert, alert) + } + if c.isDTLS { return c.dtlsWriteRecord(typ, data) } @@ -884,9 +856,9 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) { b := c.out.newBlock() first := true isClientHello := typ == recordTypeHandshake && len(data) > 0 && data[0] == typeClientHello - for len(data) > 0 || first { + for len(data) > 0 { m := len(data) - if m > maxPlaintext && !c.config.Bugs.SendLargeRecords { + if m > maxPlaintext { m = maxPlaintext } if typ == recordTypeHandshake && c.config.Bugs.MaxHandshakeRecordLength > 0 && m > c.config.Bugs.MaxHandshakeRecordLength { @@ -1066,9 +1038,6 @@ func (c *Conn) readHandshake() (interface{}, error) { // sequence number expectations but otherwise ignores them. func (c *Conn) skipPacket(packet []byte) error { for len(packet) > 0 { - if len(packet) < 13 { - return errors.New("tls: bad packet") - } // Dropped packets are completely ignored save to update // expected sequence numbers for this and the next epoch. (We // don't assert on the contents of the packets both for @@ -1088,9 +1057,6 @@ func (c *Conn) skipPacket(packet []byte) error { } c.in.incNextSeq() } - if len(packet) < 13+int(length) { - return errors.New("tls: bad packet") - } packet = packet[13+length:] } return nil @@ -1147,7 +1113,7 @@ func (c *Conn) Write(b []byte) (int, error) { } if c.config.Bugs.SendSpuriousAlert != 0 { - c.sendAlertLocked(alertLevelError, c.config.Bugs.SendSpuriousAlert) + c.sendAlertLocked(c.config.Bugs.SendSpuriousAlert) } // SSL 3.0 and TLS 1.0 are susceptible to a chosen-plaintext @@ -1274,22 +1240,10 @@ func (c *Conn) Close() error { c.handshakeMutex.Lock() defer c.handshakeMutex.Unlock() - if c.handshakeComplete && !c.config.Bugs.NoCloseNotify { + if c.handshakeComplete { alertErr = c.sendAlert(alertCloseNotify) } - // Consume a close_notify from the peer if one hasn't been received - // already. This avoids the peer from failing |SSL_shutdown| due to a - // write failing. - if c.handshakeComplete && alertErr == nil && c.config.Bugs.ExpectCloseNotify { - for c.in.error() == nil { - c.readRecord(recordTypeAlert) - } - if c.in.error() != io.EOF { - alertErr = c.in.error() - } - } - if err := c.conn.Close(); err != nil { return err } @@ -1319,9 +1273,6 @@ func (c *Conn) Handshake() error { }) c.conn.Write([]byte{alertLevelError, byte(alertInternalError)}) } - if data := c.config.Bugs.AppDataBeforeHandshake; data != nil { - c.writeRecord(recordTypeApplicationData, data) - } if c.isClient { c.handshakeErr = c.clientHandshake() } else { @@ -1353,8 +1304,6 @@ func (c *Conn) ConnectionState() ConnectionState { state.ChannelID = c.channelID state.SRTPProtectionProfile = c.srtpProtectionProfile state.TLSUnique = c.firstFinished[:] - state.SCTList = c.sctList - state.ClientCertSignatureHash = c.clientCertSignatureHash } return state diff --git a/src/ssl/test/runner/dtls.go b/src/ssl/test/runner/dtls.go index 5c59dea..50f7786 100644 --- a/src/ssl/test/runner/dtls.go +++ b/src/ssl/test/runner/dtls.go @@ -216,10 +216,13 @@ func (c *Conn) dtlsFlushHandshake() error { // Pack handshake fragments into records. var records [][]byte for _, fragment := range fragments { - if n := c.config.Bugs.SplitFragments; n > 0 { - if len(fragment) > n { - records = append(records, fragment[:n]) - records = append(records, fragment[n:]) + if c.config.Bugs.SplitFragmentHeader { + records = append(records, fragment[:2]) + records = append(records, fragment[2:]) + } else if c.config.Bugs.SplitFragmentBody { + if len(fragment) > 12 { + records = append(records, fragment[:13]) + records = append(records, fragment[13:]) } else { records = append(records, fragment) } @@ -298,13 +301,13 @@ func (c *Conn) dtlsSealRecord(typ recordType, data []byte) (b *block, err error) b.data[1] = byte(vers >> 8) b.data[2] = byte(vers) // DTLS records include an explicit sequence number. - copy(b.data[3:11], c.out.outSeq[0:]) + copy(b.data[3:11], c.out.seq[0:]) b.data[11] = byte(len(data) >> 8) b.data[12] = byte(len(data)) if explicitIVLen > 0 { explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen] if explicitIVIsSeq { - copy(explicitIV, c.out.outSeq[:]) + copy(explicitIV, c.out.seq[:]) } else { if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil { return diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go index a3ce686..a950313 100644 --- a/src/ssl/test/runner/handshake_client.go +++ b/src/ssl/test/runner/handshake_client.go @@ -45,7 +45,7 @@ func (c *Conn) clientHandshake() error { nextProtosLength := 0 for _, proto := range c.config.NextProtos { - if l := len(proto); l > 255 { + if l := len(proto); l == 0 || l > 255 { return errors.New("tls: invalid NextProtos value") } else { nextProtosLength += 1 + l @@ -61,7 +61,6 @@ func (c *Conn) clientHandshake() error { compressionMethods: []uint8{compressionNone}, random: make([]byte, 32), ocspStapling: true, - sctListSupported: true, serverName: c.config.ServerName, supportedCurves: c.config.curvePreferences(), supportedPoints: []uint8{pointFormatUncompressed}, @@ -74,7 +73,6 @@ func (c *Conn) clientHandshake() error { extendedMasterSecret: c.config.maxVersion() >= VersionTLS10, srtpProtectionProfiles: c.config.SRTPProtectionProfiles, srtpMasterKeyIdentifier: c.config.Bugs.SRTPMasterKeyIdentifer, - customExtension: c.config.Bugs.CustomExtension, } if c.config.Bugs.SendClientVersion != 0 { @@ -125,10 +123,6 @@ NextCipherSuite: } } - if c.config.Bugs.SendRenegotiationSCSV { - hello.cipherSuites = append(hello.cipherSuites, renegotiationSCSV) - } - if c.config.Bugs.SendFallbackSCSV { hello.cipherSuites = append(hello.cipherSuites, fallbackSCSV) } @@ -278,10 +272,6 @@ NextCipherSuite: return fmt.Errorf("tls: server selected an unsupported cipher suite") } - if c.config.Bugs.RequireRenegotiationInfo && serverHello.secureRenegotiation == nil { - return errors.New("tls: renegotiation extension missing") - } - if len(c.clientVerify) > 0 && !c.config.Bugs.NoRenegotiationInfo { var expectedRenegInfo []byte expectedRenegInfo = append(expectedRenegInfo, c.clientVerify...) @@ -292,12 +282,6 @@ NextCipherSuite: } } - if expected := c.config.Bugs.ExpectedCustomExtension; expected != nil { - if serverHello.customExtension != *expected { - return fmt.Errorf("tls: bad custom extension contents %q", serverHello.customExtension) - } - } - hs := &clientHandshakeState{ c: c, serverHello: serverHello, @@ -372,7 +356,6 @@ NextCipherSuite: copy(c.clientRandom[:], hs.hello.random) copy(c.serverRandom[:], hs.serverHello.random) copy(c.masterSecret[:], hs.masterSecret) - return nil } @@ -624,9 +607,6 @@ func (hs *clientHandshakeState) doFullHandshake() error { c.sendAlert(alertInternalError) return err } - if c.config.Bugs.InvalidCertVerifySignature { - digest[0] ^= 0x80 - } switch key := c.config.Certificates[0].PrivateKey.(type) { case *ecdsa.PrivateKey: @@ -750,28 +730,13 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) { return false, errors.New("tls: server resumed session on renegotiation") } - if hs.serverHello.sctList != nil { - return false, errors.New("tls: server sent SCT extension on session resumption") - } - - if hs.serverHello.ocspStapling { - return false, errors.New("tls: server sent OCSP extension on session resumption") - } - // Restore masterSecret and peerCerts from previous state hs.masterSecret = hs.session.masterSecret c.peerCertificates = hs.session.serverCertificates c.extendedMasterSecret = hs.session.extendedMasterSecret - c.sctList = hs.session.sctList - c.ocspResponse = hs.session.ocspResponse hs.finishedHash.discardHandshakeBuffer() return true, nil } - - if hs.serverHello.sctList != nil { - c.sctList = hs.serverHello.sctList - } - return false, nil } @@ -818,14 +783,9 @@ func (hs *clientHandshakeState) readSessionTicket() error { masterSecret: hs.masterSecret, handshakeHash: hs.finishedHash.server.Sum(nil), serverCertificates: c.peerCertificates, - sctList: c.sctList, - ocspResponse: c.ocspResponse, } if !hs.serverHello.ticketSupported { - if c.config.Bugs.ExpectNewTicket { - return errors.New("tls: expected new ticket") - } if hs.session == nil && len(hs.serverHello.sessionId) > 0 { session.sessionId = hs.serverHello.sessionId hs.session = session diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go index da85e7a..ce214fd 100644 --- a/src/ssl/test/runner/handshake_messages.go +++ b/src/ssl/test/runner/handshake_messages.go @@ -32,7 +32,6 @@ type clientHelloMsg struct { srtpProtectionProfiles []uint16 srtpMasterKeyIdentifier string sctListSupported bool - customExtension string } func (m *clientHelloMsg) equal(i interface{}) bool { @@ -66,8 +65,7 @@ func (m *clientHelloMsg) equal(i interface{}) bool { m.extendedMasterSecret == m1.extendedMasterSecret && eqUint16s(m.srtpProtectionProfiles, m1.srtpProtectionProfiles) && m.srtpMasterKeyIdentifier == m1.srtpMasterKeyIdentifier && - m.sctListSupported == m1.sctListSupported && - m.customExtension == m1.customExtension + m.sctListSupported == m1.sctListSupported } func (m *clientHelloMsg) marshal() []byte { @@ -121,7 +119,7 @@ func (m *clientHelloMsg) marshal() []byte { if len(m.alpnProtocols) > 0 { extensionsLength += 2 for _, s := range m.alpnProtocols { - if l := len(s); l > 255 { + if l := len(s); l == 0 || l > 255 { panic("invalid ALPN protocol") } extensionsLength++ @@ -140,10 +138,6 @@ func (m *clientHelloMsg) marshal() []byte { if m.sctListSupported { numExtensions++ } - if l := len(m.customExtension); l > 0 { - extensionsLength += l - numExtensions++ - } if numExtensions > 0 { extensionsLength += 4 * numExtensions length += 2 + extensionsLength @@ -382,14 +376,6 @@ func (m *clientHelloMsg) marshal() []byte { z[1] = byte(extensionSignedCertificateTimestamp & 0xff) z = z[4:] } - if l := len(m.customExtension); l > 0 { - z[0] = byte(extensionCustom >> 8) - z[1] = byte(extensionCustom & 0xff) - z[2] = byte(l >> 8) - z[3] = byte(l & 0xff) - copy(z[4:], []byte(m.customExtension)) - z = z[4+l:] - } m.raw = x @@ -457,7 +443,6 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { m.signatureAndHashes = nil m.alpnProtocols = nil m.extendedMasterSecret = false - m.customExtension = "" if len(data) == 0 { // ClientHello is optionally followed by extension data @@ -619,8 +604,6 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { return false } m.sctListSupported = true - case extensionCustom: - m.customExtension = string(data[:length]) } data = data[length:] } @@ -642,15 +625,40 @@ type serverHelloMsg struct { ticketSupported bool secureRenegotiation []byte alpnProtocol string - alpnProtocolEmpty bool duplicateExtension bool channelIDRequested bool extendedMasterSecret bool srtpProtectionProfile uint16 srtpMasterKeyIdentifier string sctList []byte - customExtension string - npnLast bool +} + +func (m *serverHelloMsg) equal(i interface{}) bool { + m1, ok := i.(*serverHelloMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + m.isDTLS == m1.isDTLS && + m.vers == m1.vers && + bytes.Equal(m.random, m1.random) && + bytes.Equal(m.sessionId, m1.sessionId) && + m.cipherSuite == m1.cipherSuite && + m.compressionMethod == m1.compressionMethod && + m.nextProtoNeg == m1.nextProtoNeg && + eqStrings(m.nextProtos, m1.nextProtos) && + m.ocspStapling == m1.ocspStapling && + m.ticketSupported == m1.ticketSupported && + bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) && + (m.secureRenegotiation == nil) == (m1.secureRenegotiation == nil) && + m.alpnProtocol == m1.alpnProtocol && + m.duplicateExtension == m1.duplicateExtension && + m.channelIDRequested == m1.channelIDRequested && + m.extendedMasterSecret == m1.extendedMasterSecret && + m.srtpProtectionProfile == m1.srtpProtectionProfile && + m.srtpMasterKeyIdentifier == m1.srtpMasterKeyIdentifier && + bytes.Equal(m.sctList, m1.sctList) } func (m *serverHelloMsg) marshal() []byte { @@ -687,7 +695,7 @@ func (m *serverHelloMsg) marshal() []byte { if m.channelIDRequested { numExtensions++ } - if alpnLen := len(m.alpnProtocol); alpnLen > 0 || m.alpnProtocolEmpty { + if alpnLen := len(m.alpnProtocol); alpnLen > 0 { if alpnLen >= 256 { panic("invalid ALPN protocol") } @@ -705,10 +713,6 @@ func (m *serverHelloMsg) marshal() []byte { extensionsLength += len(m.sctList) numExtensions++ } - if l := len(m.customExtension); l > 0 { - extensionsLength += l - numExtensions++ - } if numExtensions > 0 { extensionsLength += 4 * numExtensions @@ -743,7 +747,7 @@ func (m *serverHelloMsg) marshal() []byte { z[1] = 0xff z = z[4:] } - if m.nextProtoNeg && !m.npnLast { + if m.nextProtoNeg { z[0] = byte(extensionNextProtoNeg >> 8) z[1] = byte(extensionNextProtoNeg & 0xff) z[2] = byte(nextProtoLen >> 8) @@ -780,7 +784,7 @@ func (m *serverHelloMsg) marshal() []byte { copy(z, m.secureRenegotiation) z = z[len(m.secureRenegotiation):] } - if alpnLen := len(m.alpnProtocol); alpnLen > 0 || m.alpnProtocolEmpty { + if alpnLen := len(m.alpnProtocol); alpnLen > 0 { z[0] = byte(extensionALPN >> 8) z[1] = byte(extensionALPN & 0xff) l := 2 + 1 + alpnLen @@ -834,31 +838,6 @@ func (m *serverHelloMsg) marshal() []byte { copy(z[4:], m.sctList) z = z[4+l:] } - if l := len(m.customExtension); l > 0 { - z[0] = byte(extensionCustom >> 8) - z[1] = byte(extensionCustom & 0xff) - z[2] = byte(l >> 8) - z[3] = byte(l & 0xff) - copy(z[4:], []byte(m.customExtension)) - z = z[4+l:] - } - if m.nextProtoNeg && m.npnLast { - z[0] = byte(extensionNextProtoNeg >> 8) - z[1] = byte(extensionNextProtoNeg & 0xff) - z[2] = byte(nextProtoLen >> 8) - z[3] = byte(nextProtoLen) - z = z[4:] - - for _, v := range m.nextProtos { - l := len(v) - if l > 255 { - l = 255 - } - z[0] = byte(l) - copy(z[1:], []byte(v[0:l])) - z = z[1+l:] - } - } m.raw = x @@ -890,9 +869,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { m.ocspStapling = false m.ticketSupported = false m.alpnProtocol = "" - m.alpnProtocolEmpty = false m.extendedMasterSecret = false - m.customExtension = "" if len(data) == 0 { // ServerHello is optionally followed by extension data @@ -963,7 +940,6 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { } d = d[1:] m.alpnProtocol = string(d) - m.alpnProtocolEmpty = len(d) == 0 case extensionChannelID: if length > 0 { return false @@ -989,9 +965,14 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { } m.srtpMasterKeyIdentifier = string(d[1:]) case extensionSignedCertificateTimestamp: - m.sctList = data[:length] - case extensionCustom: - m.customExtension = string(data[:length]) + if length < 2 { + return false + } + l := int(data[0])<<8 | int(data[1]) + if l != len(data)-2 { + return false + } + m.sctList = data[2:length] } data = data[length:] } @@ -1004,6 +985,16 @@ type certificateMsg struct { certificates [][]byte } +func (m *certificateMsg) equal(i interface{}) bool { + m1, ok := i.(*certificateMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + eqByteSlices(m.certificates, m1.certificates) +} + func (m *certificateMsg) marshal() (x []byte) { if m.raw != nil { return m.raw @@ -1081,6 +1072,16 @@ type serverKeyExchangeMsg struct { key []byte } +func (m *serverKeyExchangeMsg) equal(i interface{}) bool { + m1, ok := i.(*serverKeyExchangeMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + bytes.Equal(m.key, m1.key) +} + func (m *serverKeyExchangeMsg) marshal() []byte { if m.raw != nil { return m.raw @@ -1112,6 +1113,17 @@ type certificateStatusMsg struct { response []byte } +func (m *certificateStatusMsg) equal(i interface{}) bool { + m1, ok := i.(*certificateStatusMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + m.statusType == m1.statusType && + bytes.Equal(m.response, m1.response) +} + func (m *certificateStatusMsg) marshal() []byte { if m.raw != nil { return m.raw @@ -1163,6 +1175,11 @@ func (m *certificateStatusMsg) unmarshal(data []byte) bool { type serverHelloDoneMsg struct{} +func (m *serverHelloDoneMsg) equal(i interface{}) bool { + _, ok := i.(*serverHelloDoneMsg) + return ok +} + func (m *serverHelloDoneMsg) marshal() []byte { x := make([]byte, 4) x[0] = typeServerHelloDone @@ -1178,6 +1195,16 @@ type clientKeyExchangeMsg struct { ciphertext []byte } +func (m *clientKeyExchangeMsg) equal(i interface{}) bool { + m1, ok := i.(*clientKeyExchangeMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + bytes.Equal(m.ciphertext, m1.ciphertext) +} + func (m *clientKeyExchangeMsg) marshal() []byte { if m.raw != nil { return m.raw @@ -1212,6 +1239,16 @@ type finishedMsg struct { verifyData []byte } +func (m *finishedMsg) equal(i interface{}) bool { + m1, ok := i.(*finishedMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + bytes.Equal(m.verifyData, m1.verifyData) +} + func (m *finishedMsg) marshal() (x []byte) { if m.raw != nil { return m.raw @@ -1239,6 +1276,16 @@ type nextProtoMsg struct { proto string } +func (m *nextProtoMsg) equal(i interface{}) bool { + m1, ok := i.(*nextProtoMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + m.proto == m1.proto +} + func (m *nextProtoMsg) marshal() []byte { if m.raw != nil { return m.raw @@ -1306,6 +1353,18 @@ type certificateRequestMsg struct { certificateAuthorities [][]byte } +func (m *certificateRequestMsg) equal(i interface{}) bool { + m1, ok := i.(*certificateRequestMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + bytes.Equal(m.certificateTypes, m1.certificateTypes) && + eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities) && + eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) +} + func (m *certificateRequestMsg) marshal() (x []byte) { if m.raw != nil { return m.raw @@ -1448,6 +1507,19 @@ type certificateVerifyMsg struct { signature []byte } +func (m *certificateVerifyMsg) equal(i interface{}) bool { + m1, ok := i.(*certificateVerifyMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + m.hasSignatureAndHash == m1.hasSignatureAndHash && + m.signatureAndHash.hash == m1.signatureAndHash.hash && + m.signatureAndHash.signature == m1.signatureAndHash.signature && + bytes.Equal(m.signature, m1.signature) +} + func (m *certificateVerifyMsg) marshal() (x []byte) { if m.raw != nil { return m.raw @@ -1517,6 +1589,16 @@ type newSessionTicketMsg struct { ticket []byte } +func (m *newSessionTicketMsg) equal(i interface{}) bool { + m1, ok := i.(*newSessionTicketMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + bytes.Equal(m.ticket, m1.ticket) +} + func (m *newSessionTicketMsg) marshal() (x []byte) { if m.raw != nil { return m.raw @@ -1569,6 +1651,19 @@ type v2ClientHelloMsg struct { challenge []byte } +func (m *v2ClientHelloMsg) equal(i interface{}) bool { + m1, ok := i.(*v2ClientHelloMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + m.vers == m1.vers && + eqUint16s(m.cipherSuites, m1.cipherSuites) && + bytes.Equal(m.sessionId, m1.sessionId) && + bytes.Equal(m.challenge, m1.challenge) +} + func (m *v2ClientHelloMsg) marshal() []byte { if m.raw != nil { return m.raw @@ -1608,6 +1703,17 @@ type helloVerifyRequestMsg struct { cookie []byte } +func (m *helloVerifyRequestMsg) equal(i interface{}) bool { + m1, ok := i.(*helloVerifyRequestMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + m.vers == m1.vers && + bytes.Equal(m.cookie, m1.cookie) +} + func (m *helloVerifyRequestMsg) marshal() []byte { if m.raw != nil { return m.raw @@ -1649,6 +1755,16 @@ type encryptedExtensionsMsg struct { channelID []byte } +func (m *encryptedExtensionsMsg) equal(i interface{}) bool { + m1, ok := i.(*encryptedExtensionsMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + bytes.Equal(m.channelID, m1.channelID) +} + func (m *encryptedExtensionsMsg) marshal() []byte { if m.raw != nil { return m.raw diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go index 068dff9..85cc0d2 100644 --- a/src/ssl/test/runner/handshake_server.go +++ b/src/ssl/test/runner/handshake_server.go @@ -139,8 +139,8 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) { c.sendAlert(alertUnexpectedMessage) return false, unexpectedMessageError(hs.clientHello, msg) } - if size := config.Bugs.RequireClientHelloSize; size != 0 && len(hs.clientHello.raw) != size { - return false, fmt.Errorf("tls: ClientHello record size is %d, but expected %d", len(hs.clientHello.raw), size) + if config.Bugs.RequireFastradioPadding && len(hs.clientHello.raw) < 1000 { + return false, errors.New("tls: ClientHello record size should be larger than 1000 bytes when padding enabled.") } if c.isDTLS && !config.Bugs.SkipHelloVerifyRequest { @@ -210,11 +210,8 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) { } c.haveVers = true - hs.hello = &serverHelloMsg{ - isDTLS: c.isDTLS, - customExtension: config.Bugs.CustomExtension, - npnLast: config.Bugs.SwapNPNAndALPN, - } + hs.hello = new(serverHelloMsg) + hs.hello.isDTLS = c.isDTLS supportedCurve := false preferredCurves := config.curvePreferences() @@ -288,18 +285,12 @@ Curves: } if len(hs.clientHello.alpnProtocols) > 0 { - if proto := c.config.Bugs.ALPNProtocol; proto != nil { - hs.hello.alpnProtocol = *proto - hs.hello.alpnProtocolEmpty = len(*proto) == 0 - c.clientProtocol = *proto - c.usedALPN = true - } else if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback { + if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback { hs.hello.alpnProtocol = selectedProto c.clientProtocol = selectedProto c.usedALPN = true } - } - if len(hs.clientHello.alpnProtocols) == 0 || c.config.Bugs.NegotiateALPNAndNPN { + } else { // Although sending an empty NPN extension is reasonable, Firefox has // had a bug around this. Best to send nothing at all if // config.NextProtos is empty. See @@ -344,12 +335,6 @@ Curves: hs.hello.srtpProtectionProfile = c.config.Bugs.SendSRTPProtectionProfile } - if expected := c.config.Bugs.ExpectedCustomExtension; expected != nil { - if hs.clientHello.customExtension != *expected { - return false, fmt.Errorf("tls: bad custom extension contents %q", hs.clientHello.customExtension) - } - } - _, hs.ecdsaOk = hs.cert.PrivateKey.(*ecdsa.PrivateKey) // For test purposes, check that the peer never offers a session when @@ -531,9 +516,7 @@ func (hs *serverHandshakeState) doFullHandshake() error { if !isPSK { certMsg := new(certificateMsg) - if !config.Bugs.EmptyCertificateList { - certMsg.certificates = hs.cert.Certificate - } + certMsg.certificates = hs.cert.Certificate if !config.Bugs.UnauthenticatedECDH { certMsgBytes := certMsg.marshal() if config.Bugs.WrongCertificateMessageType { @@ -685,7 +668,6 @@ func (hs *serverHandshakeState) doFullHandshake() error { if !isSupportedSignatureAndHash(signatureAndHash, config.signatureAndHashesForServer()) { return errors.New("tls: unsupported hash function for client certificate") } - c.clientCertSignatureHash = signatureAndHash.hash } else { // Before TLS 1.2 the signature algorithm was implicit // from the key type, and only one hash per signature diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go index 269a955..94c1d32 100644 --- a/src/ssl/test/runner/runner.go +++ b/src/ssl/test/runner/runner.go @@ -32,10 +32,6 @@ var ( mallocTestDebug = flag.Bool("malloc-test-debug", false, "If true, ask bssl_shim to abort rather than fail a malloc. This can be used with a specific value for --malloc-test to identity the malloc failing that is causing problems.") jsonOutput = flag.String("json-output", "", "The file to output JSON results to.") pipe = flag.Bool("pipe", false, "If true, print status output suitable for piping into another program.") - testToRun = flag.String("test", "", "The name of a test to run, or empty to run all tests") - numWorkers = flag.Int("num-workers", runtime.NumCPU(), "The number of workers to run in parallel.") - shimPath = flag.String("shim-path", "../../../build/ssl/test/bssl_shim", "The location of the shim binary.") - resourceDir = flag.String("resource-dir", ".", "The directory in which to find certificate and key files.") ) const ( @@ -58,21 +54,21 @@ var testSCTList = []byte{5, 6, 7, 8} func initCertificates() { var err error - rsaCertificate, err = LoadX509KeyPair(path.Join(*resourceDir, rsaCertificateFile), path.Join(*resourceDir, rsaKeyFile)) + rsaCertificate, err = LoadX509KeyPair(rsaCertificateFile, rsaKeyFile) if err != nil { panic(err) } rsaCertificate.OCSPStaple = testOCSPResponse rsaCertificate.SignedCertificateTimestampList = testSCTList - ecdsaCertificate, err = LoadX509KeyPair(path.Join(*resourceDir, ecdsaCertificateFile), path.Join(*resourceDir, ecdsaKeyFile)) + ecdsaCertificate, err = LoadX509KeyPair(ecdsaCertificateFile, ecdsaKeyFile) if err != nil { panic(err) } ecdsaCertificate.OCSPStaple = testOCSPResponse ecdsaCertificate.SignedCertificateTimestampList = testSCTList - channelIDPEMBlock, err := ioutil.ReadFile(path.Join(*resourceDir, channelIDKeyFile)) + channelIDPEMBlock, err := ioutil.ReadFile(channelIDKeyFile) if err != nil { panic(err) } @@ -155,21 +151,9 @@ type testCase struct { // expectedSRTPProtectionProfile is the DTLS-SRTP profile that // should be negotiated. If zero, none should be negotiated. expectedSRTPProtectionProfile uint16 - // expectedOCSPResponse, if not nil, is the expected OCSP response to be received. - expectedOCSPResponse []uint8 - // expectedSCTList, if not nil, is the expected SCT list to be received. - expectedSCTList []uint8 - // expectedClientCertSignatureHash, if not zero, is the TLS id of the - // hash function that the client should have used when signing the - // handshake with a client certificate. - expectedClientCertSignatureHash uint8 // messageLen is the length, in bytes, of the test message that will be // sent. messageLen int - // messageCount is the number of test messages that will be sent. - messageCount int - // digestPrefs is the list of digest preferences from the client. - digestPrefs string // certFile is the path to the certificate to use for the server. certFile string // keyFile is the path to the private key to use for the server. @@ -190,19 +174,12 @@ type testCase struct { // newSessionsOnResume, if true, will cause resumeConfig to // use a different session resumption context. newSessionsOnResume bool - // noSessionCache, if true, will cause the server to run without a - // session cache. - noSessionCache bool // sendPrefix sends a prefix on the socket before actually performing a // handshake. sendPrefix string // shimWritesFirst controls whether the shim sends an initial "hello" // message before doing a roundtrip with the runner. shimWritesFirst bool - // shimShutsDown, if true, runs a test where the shim shuts down the - // connection immediately after the handshake rather than echoing - // messages from the runner. - shimShutsDown bool // renegotiate indicates the the connection should be renegotiated // during the exchange. renegotiate bool @@ -227,20 +204,941 @@ type testCase struct { // testTLSUnique, if true, causes the shim to send the tls-unique value // which will be compared against the expected value. testTLSUnique bool - // sendEmptyRecords is the number of consecutive empty records to send - // before and after the test message. - sendEmptyRecords int - // sendWarningAlerts is the number of consecutive warning alerts to send - // before and after the test message. - sendWarningAlerts int - // expectMessageDropped, if true, means the test message is expected to - // be dropped by the client rather than echoed back. - expectMessageDropped bool } -var testCases []testCase +var testCases = []testCase{ + { + name: "BadRSASignature", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + Bugs: ProtocolBugs{ + InvalidSKXSignature: true, + }, + }, + shouldFail: true, + expectedError: ":BAD_SIGNATURE:", + }, + { + name: "BadECDSASignature", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, + Bugs: ProtocolBugs{ + InvalidSKXSignature: true, + }, + Certificates: []Certificate{getECDSACertificate()}, + }, + shouldFail: true, + expectedError: ":BAD_SIGNATURE:", + }, + { + name: "BadECDSACurve", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, + Bugs: ProtocolBugs{ + InvalidSKXCurve: true, + }, + Certificates: []Certificate{getECDSACertificate()}, + }, + shouldFail: true, + expectedError: ":WRONG_CURVE:", + }, + { + testType: serverTest, + name: "BadRSAVersion", + config: Config{ + CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + Bugs: ProtocolBugs{ + RsaClientKeyExchangeVersion: VersionTLS11, + }, + }, + shouldFail: true, + expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:", + }, + { + name: "NoFallbackSCSV", + config: Config{ + Bugs: ProtocolBugs{ + FailIfNotFallbackSCSV: true, + }, + }, + shouldFail: true, + expectedLocalError: "no fallback SCSV found", + }, + { + name: "SendFallbackSCSV", + config: Config{ + Bugs: ProtocolBugs{ + FailIfNotFallbackSCSV: true, + }, + }, + flags: []string{"-fallback-scsv"}, + }, + { + name: "ClientCertificateTypes", + config: Config{ + ClientAuth: RequestClientCert, + ClientCertificateTypes: []byte{ + CertTypeDSSSign, + CertTypeRSASign, + CertTypeECDSASign, + }, + }, + flags: []string{ + "-expect-certificate-types", + base64.StdEncoding.EncodeToString([]byte{ + CertTypeDSSSign, + CertTypeRSASign, + CertTypeECDSASign, + }), + }, + }, + { + name: "NoClientCertificate", + config: Config{ + ClientAuth: RequireAnyClientCert, + }, + shouldFail: true, + expectedLocalError: "client didn't provide a certificate", + }, + { + name: "UnauthenticatedECDH", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + Bugs: ProtocolBugs{ + UnauthenticatedECDH: true, + }, + }, + shouldFail: true, + expectedError: ":UNEXPECTED_MESSAGE:", + }, + { + name: "SkipCertificateStatus", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + Bugs: ProtocolBugs{ + SkipCertificateStatus: true, + }, + }, + flags: []string{ + "-enable-ocsp-stapling", + }, + }, + { + name: "SkipServerKeyExchange", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + Bugs: ProtocolBugs{ + SkipServerKeyExchange: true, + }, + }, + shouldFail: true, + expectedError: ":UNEXPECTED_MESSAGE:", + }, + { + name: "SkipChangeCipherSpec-Client", + config: Config{ + Bugs: ProtocolBugs{ + SkipChangeCipherSpec: true, + }, + }, + shouldFail: true, + expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:", + }, + { + testType: serverTest, + name: "SkipChangeCipherSpec-Server", + config: Config{ + Bugs: ProtocolBugs{ + SkipChangeCipherSpec: true, + }, + }, + shouldFail: true, + expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:", + }, + { + testType: serverTest, + name: "SkipChangeCipherSpec-Server-NPN", + config: Config{ + NextProtos: []string{"bar"}, + Bugs: ProtocolBugs{ + SkipChangeCipherSpec: true, + }, + }, + flags: []string{ + "-advertise-npn", "\x03foo\x03bar\x03baz", + }, + shouldFail: true, + expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:", + }, + { + name: "FragmentAcrossChangeCipherSpec-Client", + config: Config{ + Bugs: ProtocolBugs{ + FragmentAcrossChangeCipherSpec: true, + }, + }, + shouldFail: true, + expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:", + }, + { + testType: serverTest, + name: "FragmentAcrossChangeCipherSpec-Server", + config: Config{ + Bugs: ProtocolBugs{ + FragmentAcrossChangeCipherSpec: true, + }, + }, + shouldFail: true, + expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:", + }, + { + testType: serverTest, + name: "FragmentAcrossChangeCipherSpec-Server-NPN", + config: Config{ + NextProtos: []string{"bar"}, + Bugs: ProtocolBugs{ + FragmentAcrossChangeCipherSpec: true, + }, + }, + flags: []string{ + "-advertise-npn", "\x03foo\x03bar\x03baz", + }, + shouldFail: true, + expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:", + }, + { + testType: serverTest, + name: "Alert", + config: Config{ + Bugs: ProtocolBugs{ + SendSpuriousAlert: alertRecordOverflow, + }, + }, + shouldFail: true, + expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:", + }, + { + protocol: dtls, + testType: serverTest, + name: "Alert-DTLS", + config: Config{ + Bugs: ProtocolBugs{ + SendSpuriousAlert: alertRecordOverflow, + }, + }, + shouldFail: true, + expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:", + }, + { + testType: serverTest, + name: "FragmentAlert", + config: Config{ + Bugs: ProtocolBugs{ + FragmentAlert: true, + SendSpuriousAlert: alertRecordOverflow, + }, + }, + shouldFail: true, + expectedError: ":BAD_ALERT:", + }, + { + protocol: dtls, + testType: serverTest, + name: "FragmentAlert-DTLS", + config: Config{ + Bugs: ProtocolBugs{ + FragmentAlert: true, + SendSpuriousAlert: alertRecordOverflow, + }, + }, + shouldFail: true, + expectedError: ":BAD_ALERT:", + }, + { + testType: serverTest, + name: "EarlyChangeCipherSpec-server-1", + config: Config{ + Bugs: ProtocolBugs{ + EarlyChangeCipherSpec: 1, + }, + }, + shouldFail: true, + expectedError: ":CCS_RECEIVED_EARLY:", + }, + { + testType: serverTest, + name: "EarlyChangeCipherSpec-server-2", + config: Config{ + Bugs: ProtocolBugs{ + EarlyChangeCipherSpec: 2, + }, + }, + shouldFail: true, + expectedError: ":CCS_RECEIVED_EARLY:", + }, + { + name: "SkipNewSessionTicket", + config: Config{ + Bugs: ProtocolBugs{ + SkipNewSessionTicket: true, + }, + }, + shouldFail: true, + expectedError: ":CCS_RECEIVED_EARLY:", + }, + { + testType: serverTest, + name: "FallbackSCSV", + config: Config{ + MaxVersion: VersionTLS11, + Bugs: ProtocolBugs{ + SendFallbackSCSV: true, + }, + }, + shouldFail: true, + expectedError: ":INAPPROPRIATE_FALLBACK:", + }, + { + testType: serverTest, + name: "FallbackSCSV-VersionMatch", + config: Config{ + Bugs: ProtocolBugs{ + SendFallbackSCSV: true, + }, + }, + }, + { + testType: serverTest, + name: "FragmentedClientVersion", + config: Config{ + Bugs: ProtocolBugs{ + MaxHandshakeRecordLength: 1, + FragmentClientVersion: true, + }, + }, + expectedVersion: VersionTLS12, + }, + { + testType: serverTest, + name: "MinorVersionTolerance", + config: Config{ + Bugs: ProtocolBugs{ + SendClientVersion: 0x03ff, + }, + }, + expectedVersion: VersionTLS12, + }, + { + testType: serverTest, + name: "MajorVersionTolerance", + config: Config{ + Bugs: ProtocolBugs{ + SendClientVersion: 0x0400, + }, + }, + expectedVersion: VersionTLS12, + }, + { + testType: serverTest, + name: "VersionTooLow", + config: Config{ + Bugs: ProtocolBugs{ + SendClientVersion: 0x0200, + }, + }, + shouldFail: true, + expectedError: ":UNSUPPORTED_PROTOCOL:", + }, + { + testType: serverTest, + name: "HttpGET", + sendPrefix: "GET / HTTP/1.0\n", + shouldFail: true, + expectedError: ":HTTP_REQUEST:", + }, + { + testType: serverTest, + name: "HttpPOST", + sendPrefix: "POST / HTTP/1.0\n", + shouldFail: true, + expectedError: ":HTTP_REQUEST:", + }, + { + testType: serverTest, + name: "HttpHEAD", + sendPrefix: "HEAD / HTTP/1.0\n", + shouldFail: true, + expectedError: ":HTTP_REQUEST:", + }, + { + testType: serverTest, + name: "HttpPUT", + sendPrefix: "PUT / HTTP/1.0\n", + shouldFail: true, + expectedError: ":HTTP_REQUEST:", + }, + { + testType: serverTest, + name: "HttpCONNECT", + sendPrefix: "CONNECT www.google.com:443 HTTP/1.0\n", + shouldFail: true, + expectedError: ":HTTPS_PROXY_REQUEST:", + }, + { + testType: serverTest, + name: "Garbage", + sendPrefix: "blah", + shouldFail: true, + expectedError: ":UNKNOWN_PROTOCOL:", + }, + { + name: "SkipCipherVersionCheck", + config: Config{ + CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, + MaxVersion: VersionTLS11, + Bugs: ProtocolBugs{ + SkipCipherVersionCheck: true, + }, + }, + shouldFail: true, + expectedError: ":WRONG_CIPHER_RETURNED:", + }, + { + name: "RSAEphemeralKey", + config: Config{ + CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, + Bugs: ProtocolBugs{ + RSAEphemeralKey: true, + }, + }, + shouldFail: true, + expectedError: ":UNEXPECTED_MESSAGE:", + }, + { + name: "DisableEverything", + flags: []string{"-no-tls12", "-no-tls11", "-no-tls1", "-no-ssl3"}, + shouldFail: true, + expectedError: ":WRONG_SSL_VERSION:", + }, + { + protocol: dtls, + name: "DisableEverything-DTLS", + flags: []string{"-no-tls12", "-no-tls1"}, + shouldFail: true, + expectedError: ":WRONG_SSL_VERSION:", + }, + { + name: "NoSharedCipher", + config: Config{ + CipherSuites: []uint16{}, + }, + shouldFail: true, + expectedError: ":HANDSHAKE_FAILURE_ON_CLIENT_HELLO:", + }, + { + protocol: dtls, + testType: serverTest, + name: "MTU", + config: Config{ + Bugs: ProtocolBugs{ + MaxPacketLength: 256, + }, + }, + flags: []string{"-mtu", "256"}, + }, + { + protocol: dtls, + testType: serverTest, + name: "MTUExceeded", + config: Config{ + Bugs: ProtocolBugs{ + MaxPacketLength: 255, + }, + }, + flags: []string{"-mtu", "256"}, + shouldFail: true, + expectedLocalError: "dtls: exceeded maximum packet length", + }, + { + name: "CertMismatchRSA", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, + Certificates: []Certificate{getECDSACertificate()}, + Bugs: ProtocolBugs{ + SendCipherSuite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + }, + }, + shouldFail: true, + expectedError: ":WRONG_CERTIFICATE_TYPE:", + }, + { + name: "CertMismatchECDSA", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + Certificates: []Certificate{getRSACertificate()}, + Bugs: ProtocolBugs{ + SendCipherSuite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + }, + }, + shouldFail: true, + expectedError: ":WRONG_CERTIFICATE_TYPE:", + }, + { + name: "TLSFatalBadPackets", + damageFirstWrite: true, + shouldFail: true, + expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:", + }, + { + protocol: dtls, + name: "DTLSIgnoreBadPackets", + damageFirstWrite: true, + }, + { + protocol: dtls, + name: "DTLSIgnoreBadPackets-Async", + damageFirstWrite: true, + flags: []string{"-async"}, + }, + { + name: "AppDataAfterChangeCipherSpec", + config: Config{ + Bugs: ProtocolBugs{ + AppDataAfterChangeCipherSpec: []byte("TEST MESSAGE"), + }, + }, + shouldFail: true, + expectedError: ":DATA_BETWEEN_CCS_AND_FINISHED:", + }, + { + protocol: dtls, + name: "AppDataAfterChangeCipherSpec-DTLS", + config: Config{ + Bugs: ProtocolBugs{ + AppDataAfterChangeCipherSpec: []byte("TEST MESSAGE"), + }, + }, + // BoringSSL's DTLS implementation will drop the out-of-order + // application data. + }, + { + name: "AlertAfterChangeCipherSpec", + config: Config{ + Bugs: ProtocolBugs{ + AlertAfterChangeCipherSpec: alertRecordOverflow, + }, + }, + shouldFail: true, + expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:", + }, + { + protocol: dtls, + name: "AlertAfterChangeCipherSpec-DTLS", + config: Config{ + Bugs: ProtocolBugs{ + AlertAfterChangeCipherSpec: alertRecordOverflow, + }, + }, + shouldFail: true, + expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:", + }, + { + protocol: dtls, + name: "ReorderHandshakeFragments-Small-DTLS", + config: Config{ + Bugs: ProtocolBugs{ + ReorderHandshakeFragments: true, + // Small enough that every handshake message is + // fragmented. + MaxHandshakeRecordLength: 2, + }, + }, + }, + { + protocol: dtls, + name: "ReorderHandshakeFragments-Large-DTLS", + config: Config{ + Bugs: ProtocolBugs{ + ReorderHandshakeFragments: true, + // Large enough that no handshake message is + // fragmented. + MaxHandshakeRecordLength: 2048, + }, + }, + }, + { + protocol: dtls, + name: "MixCompleteMessageWithFragments-DTLS", + config: Config{ + Bugs: ProtocolBugs{ + ReorderHandshakeFragments: true, + MixCompleteMessageWithFragments: true, + MaxHandshakeRecordLength: 2, + }, + }, + }, + { + name: "SendInvalidRecordType", + config: Config{ + Bugs: ProtocolBugs{ + SendInvalidRecordType: true, + }, + }, + shouldFail: true, + expectedError: ":UNEXPECTED_RECORD:", + }, + { + protocol: dtls, + name: "SendInvalidRecordType-DTLS", + config: Config{ + Bugs: ProtocolBugs{ + SendInvalidRecordType: true, + }, + }, + shouldFail: true, + expectedError: ":UNEXPECTED_RECORD:", + }, + { + name: "FalseStart-SkipServerSecondLeg", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + NextProtos: []string{"foo"}, + Bugs: ProtocolBugs{ + SkipNewSessionTicket: true, + SkipChangeCipherSpec: true, + SkipFinished: true, + ExpectFalseStart: true, + }, + }, + flags: []string{ + "-false-start", + "-handshake-never-done", + "-advertise-alpn", "\x03foo", + }, + shimWritesFirst: true, + shouldFail: true, + expectedError: ":UNEXPECTED_RECORD:", + }, + { + name: "FalseStart-SkipServerSecondLeg-Implicit", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + NextProtos: []string{"foo"}, + Bugs: ProtocolBugs{ + SkipNewSessionTicket: true, + SkipChangeCipherSpec: true, + SkipFinished: true, + }, + }, + flags: []string{ + "-implicit-handshake", + "-false-start", + "-handshake-never-done", + "-advertise-alpn", "\x03foo", + }, + shouldFail: true, + expectedError: ":UNEXPECTED_RECORD:", + }, + { + testType: serverTest, + name: "FailEarlyCallback", + flags: []string{"-fail-early-callback"}, + shouldFail: true, + expectedError: ":CONNECTION_REJECTED:", + expectedLocalError: "remote error: access denied", + }, + { + name: "WrongMessageType", + config: Config{ + Bugs: ProtocolBugs{ + WrongCertificateMessageType: true, + }, + }, + shouldFail: true, + expectedError: ":UNEXPECTED_MESSAGE:", + expectedLocalError: "remote error: unexpected message", + }, + { + protocol: dtls, + name: "WrongMessageType-DTLS", + config: Config{ + Bugs: ProtocolBugs{ + WrongCertificateMessageType: true, + }, + }, + shouldFail: true, + expectedError: ":UNEXPECTED_MESSAGE:", + expectedLocalError: "remote error: unexpected message", + }, + { + protocol: dtls, + name: "FragmentMessageTypeMismatch-DTLS", + config: Config{ + Bugs: ProtocolBugs{ + MaxHandshakeRecordLength: 2, + FragmentMessageTypeMismatch: true, + }, + }, + shouldFail: true, + expectedError: ":FRAGMENT_MISMATCH:", + }, + { + protocol: dtls, + name: "FragmentMessageLengthMismatch-DTLS", + config: Config{ + Bugs: ProtocolBugs{ + MaxHandshakeRecordLength: 2, + FragmentMessageLengthMismatch: true, + }, + }, + shouldFail: true, + expectedError: ":FRAGMENT_MISMATCH:", + }, + { + protocol: dtls, + name: "SplitFragmentHeader-DTLS", + config: Config{ + Bugs: ProtocolBugs{ + SplitFragmentHeader: true, + }, + }, + shouldFail: true, + expectedError: ":UNEXPECTED_MESSAGE:", + }, + { + protocol: dtls, + name: "SplitFragmentBody-DTLS", + config: Config{ + Bugs: ProtocolBugs{ + SplitFragmentBody: true, + }, + }, + shouldFail: true, + expectedError: ":UNEXPECTED_MESSAGE:", + }, + { + protocol: dtls, + name: "SendEmptyFragments-DTLS", + config: Config{ + Bugs: ProtocolBugs{ + SendEmptyFragments: true, + }, + }, + }, + { + name: "UnsupportedCipherSuite", + config: Config{ + CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + Bugs: ProtocolBugs{ + IgnorePeerCipherPreferences: true, + }, + }, + flags: []string{"-cipher", "DEFAULT:!RC4"}, + shouldFail: true, + expectedError: ":WRONG_CIPHER_RETURNED:", + }, + { + name: "UnsupportedCurve", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + // BoringSSL implements P-224 but doesn't enable it by + // default. + CurvePreferences: []CurveID{CurveP224}, + Bugs: ProtocolBugs{ + IgnorePeerCurvePreferences: true, + }, + }, + shouldFail: true, + expectedError: ":WRONG_CURVE:", + }, + { + name: "SendWarningAlerts", + config: Config{ + Bugs: ProtocolBugs{ + SendWarningAlerts: alertAccessDenied, + }, + }, + }, + { + protocol: dtls, + name: "SendWarningAlerts-DTLS", + config: Config{ + Bugs: ProtocolBugs{ + SendWarningAlerts: alertAccessDenied, + }, + }, + }, + { + name: "BadFinished", + config: Config{ + Bugs: ProtocolBugs{ + BadFinished: true, + }, + }, + shouldFail: true, + expectedError: ":DIGEST_CHECK_FAILED:", + }, + { + name: "FalseStart-BadFinished", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + NextProtos: []string{"foo"}, + Bugs: ProtocolBugs{ + BadFinished: true, + ExpectFalseStart: true, + }, + }, + flags: []string{ + "-false-start", + "-handshake-never-done", + "-advertise-alpn", "\x03foo", + }, + shimWritesFirst: true, + shouldFail: true, + expectedError: ":DIGEST_CHECK_FAILED:", + }, + { + name: "NoFalseStart-NoALPN", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + Bugs: ProtocolBugs{ + ExpectFalseStart: true, + AlertBeforeFalseStartTest: alertAccessDenied, + }, + }, + flags: []string{ + "-false-start", + }, + shimWritesFirst: true, + shouldFail: true, + expectedError: ":TLSV1_ALERT_ACCESS_DENIED:", + expectedLocalError: "tls: peer did not false start: EOF", + }, + { + name: "NoFalseStart-NoAEAD", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, + NextProtos: []string{"foo"}, + Bugs: ProtocolBugs{ + ExpectFalseStart: true, + AlertBeforeFalseStartTest: alertAccessDenied, + }, + }, + flags: []string{ + "-false-start", + "-advertise-alpn", "\x03foo", + }, + shimWritesFirst: true, + shouldFail: true, + expectedError: ":TLSV1_ALERT_ACCESS_DENIED:", + expectedLocalError: "tls: peer did not false start: EOF", + }, + { + name: "NoFalseStart-RSA", + config: Config{ + CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, + NextProtos: []string{"foo"}, + Bugs: ProtocolBugs{ + ExpectFalseStart: true, + AlertBeforeFalseStartTest: alertAccessDenied, + }, + }, + flags: []string{ + "-false-start", + "-advertise-alpn", "\x03foo", + }, + shimWritesFirst: true, + shouldFail: true, + expectedError: ":TLSV1_ALERT_ACCESS_DENIED:", + expectedLocalError: "tls: peer did not false start: EOF", + }, + { + name: "NoFalseStart-DHE_RSA", + config: Config{ + CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256}, + NextProtos: []string{"foo"}, + Bugs: ProtocolBugs{ + ExpectFalseStart: true, + AlertBeforeFalseStartTest: alertAccessDenied, + }, + }, + flags: []string{ + "-false-start", + "-advertise-alpn", "\x03foo", + }, + shimWritesFirst: true, + shouldFail: true, + expectedError: ":TLSV1_ALERT_ACCESS_DENIED:", + expectedLocalError: "tls: peer did not false start: EOF", + }, + { + testType: serverTest, + name: "NoSupportedCurves", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + Bugs: ProtocolBugs{ + NoSupportedCurves: true, + }, + }, + }, + { + testType: serverTest, + name: "NoCommonCurves", + config: Config{ + CipherSuites: []uint16{ + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + }, + CurvePreferences: []CurveID{CurveP224}, + }, + expectedCipher: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + }, + { + protocol: dtls, + name: "SendSplitAlert-Sync", + config: Config{ + Bugs: ProtocolBugs{ + SendSplitAlert: true, + }, + }, + }, + { + protocol: dtls, + name: "SendSplitAlert-Async", + config: Config{ + Bugs: ProtocolBugs{ + SendSplitAlert: true, + }, + }, + flags: []string{"-async"}, + }, + { + protocol: dtls, + name: "PackDTLSHandshake", + config: Config{ + Bugs: ProtocolBugs{ + MaxHandshakeRecordLength: 2, + PackHandshakeFragments: 20, + PackHandshakeRecords: 200, + }, + }, + }, + { + testType: serverTest, + protocol: dtls, + name: "NoRC4-DTLS", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}, + Bugs: ProtocolBugs{ + EnableAllCiphersInDTLS: true, + }, + }, + shouldFail: true, + expectedError: ":NO_SHARED_CIPHER:", + }, +} -func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool) error { +func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error { var connDebug *recordingConn var connDamage *damageAdaptor if *flagDebug { @@ -285,7 +1183,6 @@ func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool) er tlsConn = Client(conn, config) } } - defer tlsConn.Close() if err := tlsConn.Handshake(); err != nil { return err @@ -338,18 +1235,6 @@ func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool) er return fmt.Errorf("SRTP profile mismatch: got %d, wanted %d", p, test.expectedSRTPProtectionProfile) } - if test.expectedOCSPResponse != nil && !bytes.Equal(test.expectedOCSPResponse, tlsConn.OCSPResponse()) { - return fmt.Errorf("OCSP Response mismatch") - } - - if test.expectedSCTList != nil && !bytes.Equal(test.expectedSCTList, connState.SCTList) { - return fmt.Errorf("SCT list mismatch") - } - - if expected := test.expectedClientCertSignatureHash; expected != 0 && expected != connState.ClientCertSignatureHash { - return fmt.Errorf("expected client to sign handshake with hash %d, but got %d", expected, connState.ClientCertSignatureHash) - } - if test.exportKeyingMaterial > 0 { actual := make([]byte, test.exportKeyingMaterial) if _, err := io.ReadFull(tlsConn, actual); err != nil { @@ -386,14 +1271,6 @@ func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool) er } } - for i := 0; i < test.sendEmptyRecords; i++ { - tlsConn.Write(nil) - } - - for i := 0; i < test.sendWarningAlerts; i++ { - tlsConn.SendAlert(alertLevelWarning, alertUnexpectedMessage) - } - if test.renegotiate { if test.renegotiateCiphers != nil { config.CipherSuites = test.renegotiateCiphers @@ -411,7 +1288,6 @@ func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool) er connDamage.setDamage(false) } - messageLen := test.messageLen if messageLen < 0 { if test.protocol == dtls { return fmt.Errorf("messageLen < 0 not supported for DTLS tests") @@ -420,57 +1296,37 @@ func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool) er _, err := io.Copy(ioutil.Discard, tlsConn) return err } + if messageLen == 0 { messageLen = 32 } - - messageCount := test.messageCount - if messageCount == 0 { - messageCount = 1 + testMessage := make([]byte, messageLen) + for i := range testMessage { + testMessage[i] = 0x42 } + tlsConn.Write(testMessage) - for j := 0; j < messageCount; j++ { - testMessage := make([]byte, messageLen) - for i := range testMessage { - testMessage[i] = 0x42 ^ byte(j) - } - tlsConn.Write(testMessage) - - for i := 0; i < test.sendEmptyRecords; i++ { - tlsConn.Write(nil) + buf := make([]byte, len(testMessage)) + if test.protocol == dtls { + bufTmp := make([]byte, len(buf)+1) + n, err := tlsConn.Read(bufTmp) + if err != nil { + return err } - - for i := 0; i < test.sendWarningAlerts; i++ { - tlsConn.SendAlert(alertLevelWarning, alertUnexpectedMessage) + if n != len(buf) { + return fmt.Errorf("bad reply; length mismatch (%d vs %d)", n, len(buf)) } - - if test.shimShutsDown || test.expectMessageDropped { - // The shim will not respond. - continue - } - - buf := make([]byte, len(testMessage)) - if test.protocol == dtls { - bufTmp := make([]byte, len(buf)+1) - n, err := tlsConn.Read(bufTmp) - if err != nil { - return err - } - if n != len(buf) { - return fmt.Errorf("bad reply; length mismatch (%d vs %d)", n, len(buf)) - } - copy(buf, bufTmp) - } else { - _, err := io.ReadFull(tlsConn, buf) - if err != nil { - return err - } + copy(buf, bufTmp) + } else { + _, err := io.ReadFull(tlsConn, buf) + if err != nil { + return err } + } - for i, v := range buf { - if v != testMessage[i]^0xff { - return fmt.Errorf("bad reply contents at byte %d", i) - } + for i, v := range buf { + if v != testMessage[i]^0xff { + return fmt.Errorf("bad reply contents at byte %d", i) } } @@ -526,7 +1382,7 @@ func acceptOrWait(listener net.Listener, waitChan chan error) (net.Conn, error) } } -func runTest(test *testCase, shimPath string, mallocNumToFail int64) error { +func runTest(test *testCase, buildDir string, mallocNumToFail int64) error { if !test.shouldFail && (len(test.expectedError) > 0 || len(test.expectedLocalError) > 0) { panic("Error expected without shouldFail in " + test.name) } @@ -535,10 +1391,6 @@ func runTest(test *testCase, shimPath string, mallocNumToFail int64) error { panic("expectResumeRejected without resumeSession in " + test.name) } - if test.testType != clientTest && test.expectedClientCertSignatureHash != 0 { - panic("expectedClientCertSignatureHash non-zero with serverTest in " + test.name) - } - listener, err := net.ListenTCP("tcp4", &net.TCPAddr{IP: net.IP{127, 0, 0, 1}}) if err != nil { panic(err) @@ -549,30 +1401,26 @@ func runTest(test *testCase, shimPath string, mallocNumToFail int64) error { } }() + shim_path := path.Join(buildDir, "ssl/test/bssl_shim") flags := []string{"-port", strconv.Itoa(listener.Addr().(*net.TCPAddr).Port)} if test.testType == serverTest { flags = append(flags, "-server") flags = append(flags, "-key-file") if test.keyFile == "" { - flags = append(flags, path.Join(*resourceDir, rsaKeyFile)) + flags = append(flags, rsaKeyFile) } else { - flags = append(flags, path.Join(*resourceDir, test.keyFile)) + flags = append(flags, test.keyFile) } flags = append(flags, "-cert-file") if test.certFile == "" { - flags = append(flags, path.Join(*resourceDir, rsaCertificateFile)) + flags = append(flags, rsaCertificateFile) } else { - flags = append(flags, path.Join(*resourceDir, test.certFile)) + flags = append(flags, test.certFile) } } - if test.digestPrefs != "" { - flags = append(flags, "-digest-prefs") - flags = append(flags, test.digestPrefs) - } - if test.protocol == dtls { flags = append(flags, "-dtls") } @@ -585,10 +1433,6 @@ func runTest(test *testCase, shimPath string, mallocNumToFail int64) error { flags = append(flags, "-shim-writes-first") } - if test.shimShutsDown { - flags = append(flags, "-shim-shuts-down") - } - if test.exportKeyingMaterial > 0 { flags = append(flags, "-export-keying-material", strconv.Itoa(test.exportKeyingMaterial)) flags = append(flags, "-export-label", test.exportLabel) @@ -609,11 +1453,11 @@ func runTest(test *testCase, shimPath string, mallocNumToFail int64) error { var shim *exec.Cmd if *useValgrind { - shim = valgrindOf(false, shimPath, flags...) + shim = valgrindOf(false, shim_path, flags...) } else if *useGDB { - shim = gdbOf(shimPath, flags...) + shim = gdbOf(shim_path, flags...) } else { - shim = exec.Command(shimPath, flags...) + shim = exec.Command(shim_path, flags...) } shim.Stdin = os.Stdin var stdoutBuf, stderrBuf bytes.Buffer @@ -623,7 +1467,7 @@ func runTest(test *testCase, shimPath string, mallocNumToFail int64) error { shim.Env = os.Environ() shim.Env = append(shim.Env, "MALLOC_NUMBER_TO_FAIL="+strconv.FormatInt(mallocNumToFail, 10)) if *mallocTestDebug { - shim.Env = append(shim.Env, "MALLOC_BREAK_ON_FAIL=1") + shim.Env = append(shim.Env, "MALLOC_ABORT_ON_FAIL=1") } shim.Env = append(shim.Env, "_MALLOC_CHECK=1") } @@ -635,10 +1479,8 @@ func runTest(test *testCase, shimPath string, mallocNumToFail int64) error { go func() { waitChan <- shim.Wait() }() config := test.config - if !test.noSessionCache { - config.ClientSessionCache = NewLRUClientSessionCache(1) - config.ServerSessionCache = NewLRUServerSessionCache(1) - } + config.ClientSessionCache = NewLRUClientSessionCache(1) + config.ServerSessionCache = NewLRUServerSessionCache(1) if test.testType == clientTest { if len(config.Certificates) == 0 { config.Certificates = []Certificate{getRSACertificate()} @@ -653,7 +1495,7 @@ func runTest(test *testCase, shimPath string, mallocNumToFail int64) error { conn, err := acceptOrWait(listener, waitChan) if err == nil { - err = doExchange(test, &config, conn, false /* not a resumption */) + err = doExchange(test, &config, conn, test.messageLen, false /* not a resumption */) conn.Close() } @@ -667,12 +1509,7 @@ func runTest(test *testCase, shimPath string, mallocNumToFail int64) error { if len(resumeConfig.Certificates) == 0 { resumeConfig.Certificates = []Certificate{getRSACertificate()} } - if test.newSessionsOnResume { - if !test.noSessionCache { - resumeConfig.ClientSessionCache = NewLRUClientSessionCache(1) - resumeConfig.ServerSessionCache = NewLRUServerSessionCache(1) - } - } else { + if !test.newSessionsOnResume { resumeConfig.SessionTicketKey = config.SessionTicketKey resumeConfig.ClientSessionCache = config.ClientSessionCache resumeConfig.ServerSessionCache = config.ServerSessionCache @@ -683,7 +1520,7 @@ func runTest(test *testCase, shimPath string, mallocNumToFail int64) error { var connResume net.Conn connResume, err = acceptOrWait(listener, waitChan) if err == nil { - err = doExchange(test, &resumeConfig, connResume, true /* resumption */) + err = doExchange(test, &resumeConfig, connResume, test.messageLen, true /* resumption */) connResume.Close() } } @@ -769,6 +1606,7 @@ var testCipherSuites = []struct { {"DHE-RSA-AES256-GCM", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384}, {"DHE-RSA-AES256-SHA", TLS_DHE_RSA_WITH_AES_256_CBC_SHA}, {"DHE-RSA-AES256-SHA256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256}, + {"DHE-RSA-CHACHA20-POLY1305", TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, {"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, {"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA}, {"ECDHE-ECDSA-AES128-SHA256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256}, @@ -792,7 +1630,6 @@ var testCipherSuites = []struct { {"PSK-RC4-SHA", TLS_PSK_WITH_RC4_128_SHA}, {"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5}, {"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA}, - {"NULL-SHA", TLS_RSA_WITH_NULL_SHA}, } func hasComponent(suiteName, component string) bool { @@ -807,7 +1644,7 @@ func isTLS12Only(suiteName string) bool { } func isDTLSCipher(suiteName string) bool { - return !hasComponent(suiteName, "RC4") && !hasComponent(suiteName, "NULL") + return !hasComponent(suiteName, "RC4") } func bigFromHex(hex string) *big.Int { @@ -818,1152 +1655,6 @@ func bigFromHex(hex string) *big.Int { return ret } -func addBasicTests() { - basicTests := []testCase{ - { - name: "BadRSASignature", - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - Bugs: ProtocolBugs{ - InvalidSKXSignature: true, - }, - }, - shouldFail: true, - expectedError: ":BAD_SIGNATURE:", - }, - { - name: "BadECDSASignature", - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, - Bugs: ProtocolBugs{ - InvalidSKXSignature: true, - }, - Certificates: []Certificate{getECDSACertificate()}, - }, - shouldFail: true, - expectedError: ":BAD_SIGNATURE:", - }, - { - testType: serverTest, - name: "BadRSASignature-ClientAuth", - config: Config{ - Bugs: ProtocolBugs{ - InvalidCertVerifySignature: true, - }, - Certificates: []Certificate{getRSACertificate()}, - }, - shouldFail: true, - expectedError: ":BAD_SIGNATURE:", - flags: []string{"-require-any-client-certificate"}, - }, - { - testType: serverTest, - name: "BadECDSASignature-ClientAuth", - config: Config{ - Bugs: ProtocolBugs{ - InvalidCertVerifySignature: true, - }, - Certificates: []Certificate{getECDSACertificate()}, - }, - shouldFail: true, - expectedError: ":BAD_SIGNATURE:", - flags: []string{"-require-any-client-certificate"}, - }, - { - name: "BadECDSACurve", - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, - Bugs: ProtocolBugs{ - InvalidSKXCurve: true, - }, - Certificates: []Certificate{getECDSACertificate()}, - }, - shouldFail: true, - expectedError: ":WRONG_CURVE:", - }, - { - testType: serverTest, - name: "BadRSAVersion", - config: Config{ - CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, - Bugs: ProtocolBugs{ - RsaClientKeyExchangeVersion: VersionTLS11, - }, - }, - shouldFail: true, - expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:", - }, - { - name: "NoFallbackSCSV", - config: Config{ - Bugs: ProtocolBugs{ - FailIfNotFallbackSCSV: true, - }, - }, - shouldFail: true, - expectedLocalError: "no fallback SCSV found", - }, - { - name: "SendFallbackSCSV", - config: Config{ - Bugs: ProtocolBugs{ - FailIfNotFallbackSCSV: true, - }, - }, - flags: []string{"-fallback-scsv"}, - }, - { - name: "ClientCertificateTypes", - config: Config{ - ClientAuth: RequestClientCert, - ClientCertificateTypes: []byte{ - CertTypeDSSSign, - CertTypeRSASign, - CertTypeECDSASign, - }, - }, - flags: []string{ - "-expect-certificate-types", - base64.StdEncoding.EncodeToString([]byte{ - CertTypeDSSSign, - CertTypeRSASign, - CertTypeECDSASign, - }), - }, - }, - { - name: "NoClientCertificate", - config: Config{ - ClientAuth: RequireAnyClientCert, - }, - shouldFail: true, - expectedLocalError: "client didn't provide a certificate", - }, - { - name: "UnauthenticatedECDH", - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - Bugs: ProtocolBugs{ - UnauthenticatedECDH: true, - }, - }, - shouldFail: true, - expectedError: ":UNEXPECTED_MESSAGE:", - }, - { - name: "SkipCertificateStatus", - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - Bugs: ProtocolBugs{ - SkipCertificateStatus: true, - }, - }, - flags: []string{ - "-enable-ocsp-stapling", - }, - }, - { - name: "SkipServerKeyExchange", - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - Bugs: ProtocolBugs{ - SkipServerKeyExchange: true, - }, - }, - shouldFail: true, - expectedError: ":UNEXPECTED_MESSAGE:", - }, - { - name: "SkipChangeCipherSpec-Client", - config: Config{ - Bugs: ProtocolBugs{ - SkipChangeCipherSpec: true, - }, - }, - shouldFail: true, - expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:", - }, - { - testType: serverTest, - name: "SkipChangeCipherSpec-Server", - config: Config{ - Bugs: ProtocolBugs{ - SkipChangeCipherSpec: true, - }, - }, - shouldFail: true, - expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:", - }, - { - testType: serverTest, - name: "SkipChangeCipherSpec-Server-NPN", - config: Config{ - NextProtos: []string{"bar"}, - Bugs: ProtocolBugs{ - SkipChangeCipherSpec: true, - }, - }, - flags: []string{ - "-advertise-npn", "\x03foo\x03bar\x03baz", - }, - shouldFail: true, - expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:", - }, - { - name: "FragmentAcrossChangeCipherSpec-Client", - config: Config{ - Bugs: ProtocolBugs{ - FragmentAcrossChangeCipherSpec: true, - }, - }, - shouldFail: true, - expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:", - }, - { - testType: serverTest, - name: "FragmentAcrossChangeCipherSpec-Server", - config: Config{ - Bugs: ProtocolBugs{ - FragmentAcrossChangeCipherSpec: true, - }, - }, - shouldFail: true, - expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:", - }, - { - testType: serverTest, - name: "FragmentAcrossChangeCipherSpec-Server-NPN", - config: Config{ - NextProtos: []string{"bar"}, - Bugs: ProtocolBugs{ - FragmentAcrossChangeCipherSpec: true, - }, - }, - flags: []string{ - "-advertise-npn", "\x03foo\x03bar\x03baz", - }, - shouldFail: true, - expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:", - }, - { - testType: serverTest, - name: "Alert", - config: Config{ - Bugs: ProtocolBugs{ - SendSpuriousAlert: alertRecordOverflow, - }, - }, - shouldFail: true, - expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:", - }, - { - protocol: dtls, - testType: serverTest, - name: "Alert-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - SendSpuriousAlert: alertRecordOverflow, - }, - }, - shouldFail: true, - expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:", - }, - { - testType: serverTest, - name: "FragmentAlert", - config: Config{ - Bugs: ProtocolBugs{ - FragmentAlert: true, - SendSpuriousAlert: alertRecordOverflow, - }, - }, - shouldFail: true, - expectedError: ":BAD_ALERT:", - }, - { - protocol: dtls, - testType: serverTest, - name: "FragmentAlert-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - FragmentAlert: true, - SendSpuriousAlert: alertRecordOverflow, - }, - }, - shouldFail: true, - expectedError: ":BAD_ALERT:", - }, - { - testType: serverTest, - name: "EarlyChangeCipherSpec-server-1", - config: Config{ - Bugs: ProtocolBugs{ - EarlyChangeCipherSpec: 1, - }, - }, - shouldFail: true, - expectedError: ":CCS_RECEIVED_EARLY:", - }, - { - testType: serverTest, - name: "EarlyChangeCipherSpec-server-2", - config: Config{ - Bugs: ProtocolBugs{ - EarlyChangeCipherSpec: 2, - }, - }, - shouldFail: true, - expectedError: ":CCS_RECEIVED_EARLY:", - }, - { - name: "SkipNewSessionTicket", - config: Config{ - Bugs: ProtocolBugs{ - SkipNewSessionTicket: true, - }, - }, - shouldFail: true, - expectedError: ":CCS_RECEIVED_EARLY:", - }, - { - testType: serverTest, - name: "FallbackSCSV", - config: Config{ - MaxVersion: VersionTLS11, - Bugs: ProtocolBugs{ - SendFallbackSCSV: true, - }, - }, - shouldFail: true, - expectedError: ":INAPPROPRIATE_FALLBACK:", - }, - { - testType: serverTest, - name: "FallbackSCSV-VersionMatch", - config: Config{ - Bugs: ProtocolBugs{ - SendFallbackSCSV: true, - }, - }, - }, - { - testType: serverTest, - name: "FragmentedClientVersion", - config: Config{ - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: 1, - FragmentClientVersion: true, - }, - }, - expectedVersion: VersionTLS12, - }, - { - testType: serverTest, - name: "MinorVersionTolerance", - config: Config{ - Bugs: ProtocolBugs{ - SendClientVersion: 0x03ff, - }, - }, - expectedVersion: VersionTLS12, - }, - { - testType: serverTest, - name: "MajorVersionTolerance", - config: Config{ - Bugs: ProtocolBugs{ - SendClientVersion: 0x0400, - }, - }, - expectedVersion: VersionTLS12, - }, - { - testType: serverTest, - name: "VersionTooLow", - config: Config{ - Bugs: ProtocolBugs{ - SendClientVersion: 0x0200, - }, - }, - shouldFail: true, - expectedError: ":UNSUPPORTED_PROTOCOL:", - }, - { - testType: serverTest, - name: "HttpGET", - sendPrefix: "GET / HTTP/1.0\n", - shouldFail: true, - expectedError: ":HTTP_REQUEST:", - }, - { - testType: serverTest, - name: "HttpPOST", - sendPrefix: "POST / HTTP/1.0\n", - shouldFail: true, - expectedError: ":HTTP_REQUEST:", - }, - { - testType: serverTest, - name: "HttpHEAD", - sendPrefix: "HEAD / HTTP/1.0\n", - shouldFail: true, - expectedError: ":HTTP_REQUEST:", - }, - { - testType: serverTest, - name: "HttpPUT", - sendPrefix: "PUT / HTTP/1.0\n", - shouldFail: true, - expectedError: ":HTTP_REQUEST:", - }, - { - testType: serverTest, - name: "HttpCONNECT", - sendPrefix: "CONNECT www.google.com:443 HTTP/1.0\n", - shouldFail: true, - expectedError: ":HTTPS_PROXY_REQUEST:", - }, - { - testType: serverTest, - name: "Garbage", - sendPrefix: "blah", - shouldFail: true, - expectedError: ":WRONG_VERSION_NUMBER:", - }, - { - name: "SkipCipherVersionCheck", - config: Config{ - CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, - MaxVersion: VersionTLS11, - Bugs: ProtocolBugs{ - SkipCipherVersionCheck: true, - }, - }, - shouldFail: true, - expectedError: ":WRONG_CIPHER_RETURNED:", - }, - { - name: "RSAEphemeralKey", - config: Config{ - CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, - Bugs: ProtocolBugs{ - RSAEphemeralKey: true, - }, - }, - shouldFail: true, - expectedError: ":UNEXPECTED_MESSAGE:", - }, - { - name: "DisableEverything", - flags: []string{"-no-tls12", "-no-tls11", "-no-tls1", "-no-ssl3"}, - shouldFail: true, - expectedError: ":WRONG_SSL_VERSION:", - }, - { - protocol: dtls, - name: "DisableEverything-DTLS", - flags: []string{"-no-tls12", "-no-tls1"}, - shouldFail: true, - expectedError: ":WRONG_SSL_VERSION:", - }, - { - name: "NoSharedCipher", - config: Config{ - CipherSuites: []uint16{}, - }, - shouldFail: true, - expectedError: ":HANDSHAKE_FAILURE_ON_CLIENT_HELLO:", - }, - { - protocol: dtls, - testType: serverTest, - name: "MTU", - config: Config{ - Bugs: ProtocolBugs{ - MaxPacketLength: 256, - }, - }, - flags: []string{"-mtu", "256"}, - }, - { - protocol: dtls, - testType: serverTest, - name: "MTUExceeded", - config: Config{ - Bugs: ProtocolBugs{ - MaxPacketLength: 255, - }, - }, - flags: []string{"-mtu", "256"}, - shouldFail: true, - expectedLocalError: "dtls: exceeded maximum packet length", - }, - { - name: "CertMismatchRSA", - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, - Certificates: []Certificate{getECDSACertificate()}, - Bugs: ProtocolBugs{ - SendCipherSuite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - }, - }, - shouldFail: true, - expectedError: ":WRONG_CERTIFICATE_TYPE:", - }, - { - name: "CertMismatchECDSA", - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - Certificates: []Certificate{getRSACertificate()}, - Bugs: ProtocolBugs{ - SendCipherSuite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - }, - }, - shouldFail: true, - expectedError: ":WRONG_CERTIFICATE_TYPE:", - }, - { - name: "EmptyCertificateList", - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - Bugs: ProtocolBugs{ - EmptyCertificateList: true, - }, - }, - shouldFail: true, - expectedError: ":DECODE_ERROR:", - }, - { - name: "TLSFatalBadPackets", - damageFirstWrite: true, - shouldFail: true, - expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:", - }, - { - protocol: dtls, - name: "DTLSIgnoreBadPackets", - damageFirstWrite: true, - }, - { - protocol: dtls, - name: "DTLSIgnoreBadPackets-Async", - damageFirstWrite: true, - flags: []string{"-async"}, - }, - { - name: "AppDataBeforeHandshake", - config: Config{ - Bugs: ProtocolBugs{ - AppDataBeforeHandshake: []byte("TEST MESSAGE"), - }, - }, - shouldFail: true, - expectedError: ":UNEXPECTED_RECORD:", - }, - { - name: "AppDataBeforeHandshake-Empty", - config: Config{ - Bugs: ProtocolBugs{ - AppDataBeforeHandshake: []byte{}, - }, - }, - shouldFail: true, - expectedError: ":UNEXPECTED_RECORD:", - }, - { - protocol: dtls, - name: "AppDataBeforeHandshake-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - AppDataBeforeHandshake: []byte("TEST MESSAGE"), - }, - }, - shouldFail: true, - expectedError: ":UNEXPECTED_RECORD:", - }, - { - protocol: dtls, - name: "AppDataBeforeHandshake-DTLS-Empty", - config: Config{ - Bugs: ProtocolBugs{ - AppDataBeforeHandshake: []byte{}, - }, - }, - shouldFail: true, - expectedError: ":UNEXPECTED_RECORD:", - }, - { - name: "AppDataAfterChangeCipherSpec", - config: Config{ - Bugs: ProtocolBugs{ - AppDataAfterChangeCipherSpec: []byte("TEST MESSAGE"), - }, - }, - shouldFail: true, - expectedError: ":DATA_BETWEEN_CCS_AND_FINISHED:", - }, - { - name: "AppDataAfterChangeCipherSpec-Empty", - config: Config{ - Bugs: ProtocolBugs{ - AppDataAfterChangeCipherSpec: []byte{}, - }, - }, - shouldFail: true, - expectedError: ":DATA_BETWEEN_CCS_AND_FINISHED:", - }, - { - protocol: dtls, - name: "AppDataAfterChangeCipherSpec-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - AppDataAfterChangeCipherSpec: []byte("TEST MESSAGE"), - }, - }, - // BoringSSL's DTLS implementation will drop the out-of-order - // application data. - }, - { - protocol: dtls, - name: "AppDataAfterChangeCipherSpec-DTLS-Empty", - config: Config{ - Bugs: ProtocolBugs{ - AppDataAfterChangeCipherSpec: []byte{}, - }, - }, - // BoringSSL's DTLS implementation will drop the out-of-order - // application data. - }, - { - name: "AlertAfterChangeCipherSpec", - config: Config{ - Bugs: ProtocolBugs{ - AlertAfterChangeCipherSpec: alertRecordOverflow, - }, - }, - shouldFail: true, - expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:", - }, - { - protocol: dtls, - name: "AlertAfterChangeCipherSpec-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - AlertAfterChangeCipherSpec: alertRecordOverflow, - }, - }, - shouldFail: true, - expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:", - }, - { - protocol: dtls, - name: "ReorderHandshakeFragments-Small-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - ReorderHandshakeFragments: true, - // Small enough that every handshake message is - // fragmented. - MaxHandshakeRecordLength: 2, - }, - }, - }, - { - protocol: dtls, - name: "ReorderHandshakeFragments-Large-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - ReorderHandshakeFragments: true, - // Large enough that no handshake message is - // fragmented. - MaxHandshakeRecordLength: 2048, - }, - }, - }, - { - protocol: dtls, - name: "MixCompleteMessageWithFragments-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - ReorderHandshakeFragments: true, - MixCompleteMessageWithFragments: true, - MaxHandshakeRecordLength: 2, - }, - }, - }, - { - name: "SendInvalidRecordType", - config: Config{ - Bugs: ProtocolBugs{ - SendInvalidRecordType: true, - }, - }, - shouldFail: true, - expectedError: ":UNEXPECTED_RECORD:", - }, - { - protocol: dtls, - name: "SendInvalidRecordType-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - SendInvalidRecordType: true, - }, - }, - shouldFail: true, - expectedError: ":UNEXPECTED_RECORD:", - }, - { - name: "FalseStart-SkipServerSecondLeg", - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - NextProtos: []string{"foo"}, - Bugs: ProtocolBugs{ - SkipNewSessionTicket: true, - SkipChangeCipherSpec: true, - SkipFinished: true, - ExpectFalseStart: true, - }, - }, - flags: []string{ - "-false-start", - "-handshake-never-done", - "-advertise-alpn", "\x03foo", - }, - shimWritesFirst: true, - shouldFail: true, - expectedError: ":UNEXPECTED_RECORD:", - }, - { - name: "FalseStart-SkipServerSecondLeg-Implicit", - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - NextProtos: []string{"foo"}, - Bugs: ProtocolBugs{ - SkipNewSessionTicket: true, - SkipChangeCipherSpec: true, - SkipFinished: true, - }, - }, - flags: []string{ - "-implicit-handshake", - "-false-start", - "-handshake-never-done", - "-advertise-alpn", "\x03foo", - }, - shouldFail: true, - expectedError: ":UNEXPECTED_RECORD:", - }, - { - testType: serverTest, - name: "FailEarlyCallback", - flags: []string{"-fail-early-callback"}, - shouldFail: true, - expectedError: ":CONNECTION_REJECTED:", - expectedLocalError: "remote error: access denied", - }, - { - name: "WrongMessageType", - config: Config{ - Bugs: ProtocolBugs{ - WrongCertificateMessageType: true, - }, - }, - shouldFail: true, - expectedError: ":UNEXPECTED_MESSAGE:", - expectedLocalError: "remote error: unexpected message", - }, - { - protocol: dtls, - name: "WrongMessageType-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - WrongCertificateMessageType: true, - }, - }, - shouldFail: true, - expectedError: ":UNEXPECTED_MESSAGE:", - expectedLocalError: "remote error: unexpected message", - }, - { - protocol: dtls, - name: "FragmentMessageTypeMismatch-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: 2, - FragmentMessageTypeMismatch: true, - }, - }, - shouldFail: true, - expectedError: ":FRAGMENT_MISMATCH:", - }, - { - protocol: dtls, - name: "FragmentMessageLengthMismatch-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: 2, - FragmentMessageLengthMismatch: true, - }, - }, - shouldFail: true, - expectedError: ":FRAGMENT_MISMATCH:", - }, - { - protocol: dtls, - name: "SplitFragments-Header-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - SplitFragments: 2, - }, - }, - shouldFail: true, - expectedError: ":UNEXPECTED_MESSAGE:", - }, - { - protocol: dtls, - name: "SplitFragments-Boundary-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - SplitFragments: dtlsRecordHeaderLen, - }, - }, - shouldFail: true, - expectedError: ":EXCESSIVE_MESSAGE_SIZE:", - }, - { - protocol: dtls, - name: "SplitFragments-Body-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - SplitFragments: dtlsRecordHeaderLen + 1, - }, - }, - shouldFail: true, - expectedError: ":EXCESSIVE_MESSAGE_SIZE:", - }, - { - protocol: dtls, - name: "SendEmptyFragments-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - SendEmptyFragments: true, - }, - }, - }, - { - name: "UnsupportedCipherSuite", - config: Config{ - CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, - Bugs: ProtocolBugs{ - IgnorePeerCipherPreferences: true, - }, - }, - flags: []string{"-cipher", "DEFAULT:!RC4"}, - shouldFail: true, - expectedError: ":WRONG_CIPHER_RETURNED:", - }, - { - name: "UnsupportedCurve", - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - // BoringSSL implements P-224 but doesn't enable it by - // default. - CurvePreferences: []CurveID{CurveP224}, - Bugs: ProtocolBugs{ - IgnorePeerCurvePreferences: true, - }, - }, - shouldFail: true, - expectedError: ":WRONG_CURVE:", - }, - { - name: "BadFinished", - config: Config{ - Bugs: ProtocolBugs{ - BadFinished: true, - }, - }, - shouldFail: true, - expectedError: ":DIGEST_CHECK_FAILED:", - }, - { - name: "FalseStart-BadFinished", - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - NextProtos: []string{"foo"}, - Bugs: ProtocolBugs{ - BadFinished: true, - ExpectFalseStart: true, - }, - }, - flags: []string{ - "-false-start", - "-handshake-never-done", - "-advertise-alpn", "\x03foo", - }, - shimWritesFirst: true, - shouldFail: true, - expectedError: ":DIGEST_CHECK_FAILED:", - }, - { - name: "NoFalseStart-NoALPN", - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - Bugs: ProtocolBugs{ - ExpectFalseStart: true, - AlertBeforeFalseStartTest: alertAccessDenied, - }, - }, - flags: []string{ - "-false-start", - }, - shimWritesFirst: true, - shouldFail: true, - expectedError: ":TLSV1_ALERT_ACCESS_DENIED:", - expectedLocalError: "tls: peer did not false start: EOF", - }, - { - name: "NoFalseStart-NoAEAD", - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, - NextProtos: []string{"foo"}, - Bugs: ProtocolBugs{ - ExpectFalseStart: true, - AlertBeforeFalseStartTest: alertAccessDenied, - }, - }, - flags: []string{ - "-false-start", - "-advertise-alpn", "\x03foo", - }, - shimWritesFirst: true, - shouldFail: true, - expectedError: ":TLSV1_ALERT_ACCESS_DENIED:", - expectedLocalError: "tls: peer did not false start: EOF", - }, - { - name: "NoFalseStart-RSA", - config: Config{ - CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, - NextProtos: []string{"foo"}, - Bugs: ProtocolBugs{ - ExpectFalseStart: true, - AlertBeforeFalseStartTest: alertAccessDenied, - }, - }, - flags: []string{ - "-false-start", - "-advertise-alpn", "\x03foo", - }, - shimWritesFirst: true, - shouldFail: true, - expectedError: ":TLSV1_ALERT_ACCESS_DENIED:", - expectedLocalError: "tls: peer did not false start: EOF", - }, - { - name: "NoFalseStart-DHE_RSA", - config: Config{ - CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256}, - NextProtos: []string{"foo"}, - Bugs: ProtocolBugs{ - ExpectFalseStart: true, - AlertBeforeFalseStartTest: alertAccessDenied, - }, - }, - flags: []string{ - "-false-start", - "-advertise-alpn", "\x03foo", - }, - shimWritesFirst: true, - shouldFail: true, - expectedError: ":TLSV1_ALERT_ACCESS_DENIED:", - expectedLocalError: "tls: peer did not false start: EOF", - }, - { - testType: serverTest, - name: "NoSupportedCurves", - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - Bugs: ProtocolBugs{ - NoSupportedCurves: true, - }, - }, - }, - { - testType: serverTest, - name: "NoCommonCurves", - config: Config{ - CipherSuites: []uint16{ - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, - }, - CurvePreferences: []CurveID{CurveP224}, - }, - expectedCipher: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, - }, - { - protocol: dtls, - name: "SendSplitAlert-Sync", - config: Config{ - Bugs: ProtocolBugs{ - SendSplitAlert: true, - }, - }, - }, - { - protocol: dtls, - name: "SendSplitAlert-Async", - config: Config{ - Bugs: ProtocolBugs{ - SendSplitAlert: true, - }, - }, - flags: []string{"-async"}, - }, - { - protocol: dtls, - name: "PackDTLSHandshake", - config: Config{ - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: 2, - PackHandshakeFragments: 20, - PackHandshakeRecords: 200, - }, - }, - }, - { - testType: serverTest, - protocol: dtls, - name: "NoRC4-DTLS", - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}, - Bugs: ProtocolBugs{ - EnableAllCiphersInDTLS: true, - }, - }, - shouldFail: true, - expectedError: ":NO_SHARED_CIPHER:", - }, - { - name: "SendEmptyRecords-Pass", - sendEmptyRecords: 32, - }, - { - name: "SendEmptyRecords", - sendEmptyRecords: 33, - shouldFail: true, - expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:", - }, - { - name: "SendEmptyRecords-Async", - sendEmptyRecords: 33, - flags: []string{"-async"}, - shouldFail: true, - expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:", - }, - { - name: "SendWarningAlerts-Pass", - sendWarningAlerts: 4, - }, - { - protocol: dtls, - name: "SendWarningAlerts-DTLS-Pass", - sendWarningAlerts: 4, - }, - { - name: "SendWarningAlerts", - sendWarningAlerts: 5, - shouldFail: true, - expectedError: ":TOO_MANY_WARNING_ALERTS:", - }, - { - name: "SendWarningAlerts-Async", - sendWarningAlerts: 5, - flags: []string{"-async"}, - shouldFail: true, - expectedError: ":TOO_MANY_WARNING_ALERTS:", - }, - { - name: "EmptySessionID", - config: Config{ - SessionTicketsDisabled: true, - }, - noSessionCache: true, - flags: []string{"-expect-no-session"}, - }, - { - name: "Unclean-Shutdown", - config: Config{ - Bugs: ProtocolBugs{ - NoCloseNotify: true, - ExpectCloseNotify: true, - }, - }, - shimShutsDown: true, - flags: []string{"-check-close-notify"}, - shouldFail: true, - expectedError: "Unexpected SSL_shutdown result: -1 != 1", - }, - { - name: "Unclean-Shutdown-Ignored", - config: Config{ - Bugs: ProtocolBugs{ - NoCloseNotify: true, - }, - }, - shimShutsDown: true, - }, - { - name: "LargePlaintext", - config: Config{ - Bugs: ProtocolBugs{ - SendLargeRecords: true, - }, - }, - messageLen: maxPlaintext + 1, - shouldFail: true, - expectedError: ":DATA_LENGTH_TOO_LONG:", - }, - { - protocol: dtls, - name: "LargePlaintext-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - SendLargeRecords: true, - }, - }, - messageLen: maxPlaintext + 1, - shouldFail: true, - expectedError: ":DATA_LENGTH_TOO_LONG:", - }, - { - name: "LargeCiphertext", - config: Config{ - Bugs: ProtocolBugs{ - SendLargeRecords: true, - }, - }, - messageLen: maxPlaintext * 2, - shouldFail: true, - expectedError: ":ENCRYPTED_LENGTH_TOO_LONG:", - }, - { - protocol: dtls, - name: "LargeCiphertext-DTLS", - config: Config{ - Bugs: ProtocolBugs{ - SendLargeRecords: true, - }, - }, - messageLen: maxPlaintext * 2, - // Unlike the other four cases, DTLS drops records which - // are invalid before authentication, so the connection - // does not fail. - expectMessageDropped: true, - }, - } - testCases = append(testCases, basicTests...) -} - func addCipherSuiteTests() { for _, suite := range testCipherSuites { const psk = "12345" @@ -1988,10 +1679,6 @@ func addCipherSuiteTests() { "-psk", psk, "-psk-identity", pskIdentity) } - if hasComponent(suite.name, "NULL") { - // NULL ciphers must be explicitly enabled. - flags = append(flags, "-cipher", "DEFAULT:NULL-SHA") - } for _, ver := range tlsVersions { if ver.version < VersionTLS12 && isTLS12Only(suite.name) { @@ -2065,47 +1752,6 @@ func addCipherSuiteTests() { }) } } - - // Ensure both TLS and DTLS accept their maximum record sizes. - testCases = append(testCases, testCase{ - name: suite.name + "-LargeRecord", - config: Config{ - CipherSuites: []uint16{suite.id}, - Certificates: []Certificate{cert}, - PreSharedKey: []byte(psk), - PreSharedKeyIdentity: pskIdentity, - }, - flags: flags, - messageLen: maxPlaintext, - }) - testCases = append(testCases, testCase{ - name: suite.name + "-LargeRecord-Extra", - config: Config{ - CipherSuites: []uint16{suite.id}, - Certificates: []Certificate{cert}, - PreSharedKey: []byte(psk), - PreSharedKeyIdentity: pskIdentity, - Bugs: ProtocolBugs{ - SendLargeRecords: true, - }, - }, - flags: append(flags, "-microsoft-big-sslv3-buffer"), - messageLen: maxPlaintext + 16384, - }) - if isDTLSCipher(suite.name) { - testCases = append(testCases, testCase{ - protocol: dtls, - name: suite.name + "-LargeRecord-DTLS", - config: Config{ - CipherSuites: []uint16{suite.id}, - Certificates: []Certificate{cert}, - PreSharedKey: []byte(psk), - PreSharedKeyIdentity: pskIdentity, - }, - flags: flags, - messageLen: maxPlaintext, - }) - } } testCases = append(testCases, testCase{ @@ -2122,94 +1768,6 @@ func addCipherSuiteTests() { shouldFail: true, expectedError: "BAD_DH_P_LENGTH", }) - - // versionSpecificCiphersTest specifies a test for the TLS 1.0 and TLS - // 1.1 specific cipher suite settings. A server is setup with the given - // cipher lists and then a connection is made for each member of - // expectations. The cipher suite that the server selects must match - // the specified one. - var versionSpecificCiphersTest = []struct { - ciphersDefault, ciphersTLS10, ciphersTLS11 string - // expectations is a map from TLS version to cipher suite id. - expectations map[uint16]uint16 - }{ - { - // Test that the null case (where no version-specific ciphers are set) - // works as expected. - "RC4-SHA:AES128-SHA", // default ciphers - "", // no ciphers specifically for TLS ≥ 1.0 - "", // no ciphers specifically for TLS ≥ 1.1 - map[uint16]uint16{ - VersionSSL30: TLS_RSA_WITH_RC4_128_SHA, - VersionTLS10: TLS_RSA_WITH_RC4_128_SHA, - VersionTLS11: TLS_RSA_WITH_RC4_128_SHA, - VersionTLS12: TLS_RSA_WITH_RC4_128_SHA, - }, - }, - { - // With ciphers_tls10 set, TLS 1.0, 1.1 and 1.2 should get a different - // cipher. - "RC4-SHA:AES128-SHA", // default - "AES128-SHA", // these ciphers for TLS ≥ 1.0 - "", // no ciphers specifically for TLS ≥ 1.1 - map[uint16]uint16{ - VersionSSL30: TLS_RSA_WITH_RC4_128_SHA, - VersionTLS10: TLS_RSA_WITH_AES_128_CBC_SHA, - VersionTLS11: TLS_RSA_WITH_AES_128_CBC_SHA, - VersionTLS12: TLS_RSA_WITH_AES_128_CBC_SHA, - }, - }, - { - // With ciphers_tls11 set, TLS 1.1 and 1.2 should get a different - // cipher. - "RC4-SHA:AES128-SHA", // default - "", // no ciphers specifically for TLS ≥ 1.0 - "AES128-SHA", // these ciphers for TLS ≥ 1.1 - map[uint16]uint16{ - VersionSSL30: TLS_RSA_WITH_RC4_128_SHA, - VersionTLS10: TLS_RSA_WITH_RC4_128_SHA, - VersionTLS11: TLS_RSA_WITH_AES_128_CBC_SHA, - VersionTLS12: TLS_RSA_WITH_AES_128_CBC_SHA, - }, - }, - { - // With both ciphers_tls10 and ciphers_tls11 set, ciphers_tls11 should - // mask ciphers_tls10 for TLS 1.1 and 1.2. - "RC4-SHA:AES128-SHA", // default - "AES128-SHA", // these ciphers for TLS ≥ 1.0 - "AES256-SHA", // these ciphers for TLS ≥ 1.1 - map[uint16]uint16{ - VersionSSL30: TLS_RSA_WITH_RC4_128_SHA, - VersionTLS10: TLS_RSA_WITH_AES_128_CBC_SHA, - VersionTLS11: TLS_RSA_WITH_AES_256_CBC_SHA, - VersionTLS12: TLS_RSA_WITH_AES_256_CBC_SHA, - }, - }, - } - - for i, test := range versionSpecificCiphersTest { - for version, expectedCipherSuite := range test.expectations { - flags := []string{"-cipher", test.ciphersDefault} - if len(test.ciphersTLS10) > 0 { - flags = append(flags, "-cipher-tls10", test.ciphersTLS10) - } - if len(test.ciphersTLS11) > 0 { - flags = append(flags, "-cipher-tls11", test.ciphersTLS11) - } - - testCases = append(testCases, testCase{ - testType: serverTest, - name: fmt.Sprintf("VersionSpecificCiphersTest-%d-%x", i, version), - config: Config{ - MaxVersion: version, - MinVersion: version, - CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA}, - }, - flags: flags, - expectedCipher: expectedCipherSuite, - }) - } - } } func addBadECDSASignatureTests() { @@ -2279,8 +1837,7 @@ func addCBCSplittingTests() { MinVersion: VersionTLS10, CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, }, - messageLen: -1, // read until EOF - resumeSession: true, + messageLen: -1, // read until EOF flags: []string{ "-async", "-write-different-record-sizes", @@ -2325,8 +1882,8 @@ func addClientAuthTests() { ClientCAs: certPool, }, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), + "-cert-file", rsaCertificateFile, + "-key-file", rsaKeyFile, }, }) testCases = append(testCases, testCase{ @@ -2360,8 +1917,8 @@ func addClientAuthTests() { ClientCAs: certPool, }, flags: []string{ - "-cert-file", path.Join(*resourceDir, ecdsaCertificateFile), - "-key-file", path.Join(*resourceDir, ecdsaKeyFile), + "-cert-file", ecdsaCertificateFile, + "-key-file", ecdsaKeyFile, }, }) } @@ -2518,7 +2075,6 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) RenewTicketOnResume: true, }, }, - flags: []string{"-expect-ticket-renewal"}, resumeSession: true, }) tests = append(tests, testCase{ @@ -2567,42 +2123,10 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) ClientAuth: RequireAnyClientCert, }, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), + "-cert-file", rsaCertificateFile, + "-key-file", rsaKeyFile, }, }) - if async { - tests = append(tests, testCase{ - testType: clientTest, - name: "ClientAuth-Client-AsyncKey", - config: Config{ - ClientAuth: RequireAnyClientCert, - }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - "-use-async-private-key", - }, - }) - tests = append(tests, testCase{ - testType: serverTest, - name: "Basic-Server-RSAAsyncKey", - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - "-use-async-private-key", - }, - }) - tests = append(tests, testCase{ - testType: serverTest, - name: "Basic-Server-ECDSAAsyncKey", - flags: []string{ - "-cert-file", path.Join(*resourceDir, ecdsaCertificateFile), - "-key-file", path.Join(*resourceDir, ecdsaKeyFile), - "-use-async-private-key", - }, - }) - } tests = append(tests, testCase{ testType: serverTest, name: "ClientAuth-Server", @@ -2647,57 +2171,6 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) flags: []string{"-psk", "secret"}, }) - tests = append(tests, testCase{ - testType: clientTest, - name: "OCSPStapling-Client", - flags: []string{ - "-enable-ocsp-stapling", - "-expect-ocsp-response", - base64.StdEncoding.EncodeToString(testOCSPResponse), - "-verify-peer", - }, - resumeSession: true, - }) - - tests = append(tests, testCase{ - testType: serverTest, - name: "OCSPStapling-Server", - expectedOCSPResponse: testOCSPResponse, - flags: []string{ - "-ocsp-response", - base64.StdEncoding.EncodeToString(testOCSPResponse), - }, - resumeSession: true, - }) - - tests = append(tests, testCase{ - testType: clientTest, - name: "CertificateVerificationSucceed", - flags: []string{ - "-verify-peer", - }, - }) - - tests = append(tests, testCase{ - testType: clientTest, - name: "CertificateVerificationFail", - flags: []string{ - "-verify-fail", - "-verify-peer", - }, - shouldFail: true, - expectedError: ":CERTIFICATE_VERIFY_FAILED:", - }) - - tests = append(tests, testCase{ - testType: clientTest, - name: "CertificateVerificationSoftFail", - flags: []string{ - "-verify-fail", - "-expect-verify-result", - }, - }) - if protocol == tls { tests = append(tests, testCase{ name: "Renegotiate-Client", @@ -2819,7 +2292,7 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) config: Config{ RequestChannelID: true, }, - flags: []string{"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile)}, + flags: []string{"-send-channel-id", channelIDKeyFile}, resumeSession: true, expectChannelID: true, }) @@ -2838,33 +2311,6 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) resumeSession: true, expectChannelID: true, }) - - // Bidirectional shutdown with the runner initiating. - tests = append(tests, testCase{ - name: "Shutdown-Runner", - config: Config{ - Bugs: ProtocolBugs{ - ExpectCloseNotify: true, - }, - }, - flags: []string{"-check-close-notify"}, - }) - - // Bidirectional shutdown with the shim initiating. The runner, - // in the meantime, sends garbage before the close_notify which - // the shim must ignore. - tests = append(tests, testCase{ - name: "Shutdown-Shim", - config: Config{ - Bugs: ProtocolBugs{ - ExpectCloseNotify: true, - }, - }, - shimShutsDown: true, - sendEmptyRecords: 1, - sendWarningAlerts: 1, - flags: []string{"-check-close-notify"}, - }) } else { tests = append(tests, testCase{ name: "SkipHelloVerifyRequest", @@ -3275,70 +2721,6 @@ func addExtensionTests() { expectedNextProtoType: alpn, resumeSession: true, }) - var emptyString string - testCases = append(testCases, testCase{ - testType: clientTest, - name: "ALPNClient-EmptyProtocolName", - config: Config{ - NextProtos: []string{""}, - Bugs: ProtocolBugs{ - // A server returning an empty ALPN protocol - // should be rejected. - ALPNProtocol: &emptyString, - }, - }, - flags: []string{ - "-advertise-alpn", "\x03foo", - }, - shouldFail: true, - expectedError: ":PARSE_TLSEXT:", - }) - testCases = append(testCases, testCase{ - testType: serverTest, - name: "ALPNServer-EmptyProtocolName", - config: Config{ - // A ClientHello containing an empty ALPN protocol - // should be rejected. - NextProtos: []string{"foo", "", "baz"}, - }, - flags: []string{ - "-select-alpn", "foo", - }, - shouldFail: true, - expectedError: ":PARSE_TLSEXT:", - }) - // Test that negotiating both NPN and ALPN is forbidden. - testCases = append(testCases, testCase{ - name: "NegotiateALPNAndNPN", - config: Config{ - NextProtos: []string{"foo", "bar", "baz"}, - Bugs: ProtocolBugs{ - NegotiateALPNAndNPN: true, - }, - }, - flags: []string{ - "-advertise-alpn", "\x03foo", - "-select-next-proto", "foo", - }, - shouldFail: true, - expectedError: ":NEGOTIATED_BOTH_NPN_AND_ALPN:", - }) - testCases = append(testCases, testCase{ - name: "NegotiateALPNAndNPN-Swapped", - config: Config{ - NextProtos: []string{"foo", "bar", "baz"}, - Bugs: ProtocolBugs{ - NegotiateALPNAndNPN: true, - SwapNPNAndALPN: true, - }, - }, - flags: []string{ - "-advertise-alpn", "\x03foo", - "-select-next-proto", "foo", - }, - shouldFail: true, - expectedError: ":NEGOTIATED_BOTH_NPN_AND_ALPN:", - }) // Resume with a corrupt ticket. testCases = append(testCases, testCase{ testType: serverTest, @@ -3351,24 +2733,6 @@ func addExtensionTests() { resumeSession: true, expectResumeRejected: true, }) - // Test the ticket callback, with and without renewal. - testCases = append(testCases, testCase{ - testType: serverTest, - name: "TicketCallback", - resumeSession: true, - flags: []string{"-use-ticket-callback"}, - }) - testCases = append(testCases, testCase{ - testType: serverTest, - name: "TicketCallback-Renew", - config: Config{ - Bugs: ProtocolBugs{ - ExpectNewTicket: true, - }, - }, - flags: []string{"-use-ticket-callback", "-renew-ticket"}, - resumeSession: true, - }) // Resume with an oversized session id. testCases = append(testCases, testCase{ testType: serverTest, @@ -3458,39 +2822,22 @@ func addExtensionTests() { shouldFail: true, expectedError: ":BAD_SRTP_PROTECTION_PROFILE_LIST:", }) - // Test SCT list. + // Test OCSP stapling and SCT list. testCases = append(testCases, testCase{ - name: "SignedCertificateTimestampList-Client", - testType: clientTest, + name: "OCSPStapling", flags: []string{ - "-enable-signed-cert-timestamps", - "-expect-signed-cert-timestamps", - base64.StdEncoding.EncodeToString(testSCTList), + "-enable-ocsp-stapling", + "-expect-ocsp-response", + base64.StdEncoding.EncodeToString(testOCSPResponse), }, - resumeSession: true, }) testCases = append(testCases, testCase{ - name: "SignedCertificateTimestampList-Server", - testType: serverTest, + name: "SignedCertificateTimestampList", flags: []string{ - "-signed-cert-timestamps", + "-enable-signed-cert-timestamps", + "-expect-signed-cert-timestamps", base64.StdEncoding.EncodeToString(testSCTList), }, - expectedSCTList: testSCTList, - resumeSession: true, - }) - testCases = append(testCases, testCase{ - testType: clientTest, - name: "ClientHelloPadding", - config: Config{ - Bugs: ProtocolBugs{ - RequireClientHelloSize: 512, - }, - }, - // This hostname just needs to be long enough to push the - // ClientHello into F5's danger zone between 256 and 511 bytes - // long. - flags: []string{"-host-name", "01234567890123456789012345678901234567890123456789012345678901234567890123456789.com"}, }) } @@ -3609,33 +2956,7 @@ func addRenegotiationTests() { expectedError: ":NO_RENEGOTIATION:", expectedLocalError: "remote error: no renegotiation", }) - // The server shouldn't echo the renegotiation extension unless - // requested by the client. - testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-NoExt", - config: Config{ - Bugs: ProtocolBugs{ - NoRenegotiationInfo: true, - RequireRenegotiationInfo: true, - }, - }, - shouldFail: true, - expectedLocalError: "renegotiation extension missing", - }) - // The renegotiation SCSV should be sufficient for the server to echo - // the extension. - testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-NoExt-SCSV", - config: Config{ - Bugs: ProtocolBugs{ - NoRenegotiationInfo: true, - SendRenegotiationSCSV: true, - RequireRenegotiationInfo: true, - }, - }, - }) + // TODO(agl): test the renegotiation info SCSV. testCases = append(testCases, testCase{ name: "Renegotiate-Client", config: Config{ @@ -3668,7 +2989,8 @@ func addRenegotiationTests() { expectedError: ":RENEGOTIATION_MISMATCH:", }) testCases = append(testCases, testCase{ - name: "Renegotiate-Client-NoExt", + name: "Renegotiate-Client-NoExt", + renegotiate: true, config: Config{ Bugs: ProtocolBugs{ NoRenegotiationInfo: true, @@ -3721,19 +3043,6 @@ func addRenegotiationTests() { }, }, }) - testCases = append(testCases, testCase{ - name: "Renegotiate-FalseStart", - renegotiate: true, - config: Config{ - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - NextProtos: []string{"foo"}, - }, - flags: []string{ - "-false-start", - "-select-next-proto", "foo", - }, - shimWritesFirst: true, - }) } func addDTLSReplayTests() { @@ -3741,39 +3050,43 @@ func addDTLSReplayTests() { testCases = append(testCases, testCase{ protocol: dtls, name: "DTLS-Replay", - messageCount: 200, replayWrites: true, }) - // Test the incoming sequence number skipping by values larger + // Test the outgoing sequence number skipping by values larger // than the retransmit window. testCases = append(testCases, testCase{ protocol: dtls, name: "DTLS-Replay-LargeGaps", config: Config{ Bugs: ProtocolBugs{ - SequenceNumberMapping: func(in uint64) uint64 { - return in * 127 - }, + SequenceNumberIncrement: 127, }, }, - messageCount: 200, replayWrites: true, }) +} - // Test the incoming sequence number changing non-monotonically. +func addFastRadioPaddingTests() { + testCases = append(testCases, testCase{ + protocol: tls, + name: "FastRadio-Padding", + config: Config{ + Bugs: ProtocolBugs{ + RequireFastradioPadding: true, + }, + }, + flags: []string{"-fastradio-padding"}, + }) testCases = append(testCases, testCase{ protocol: dtls, - name: "DTLS-Replay-NonMonotonic", + name: "FastRadio-Padding-DTLS", config: Config{ Bugs: ProtocolBugs{ - SequenceNumberMapping: func(in uint64) uint64 { - return in ^ 31 - }, + RequireFastradioPadding: true, }, }, - messageCount: 200, - replayWrites: true, + flags: []string{"-fastradio-padding"}, }) } @@ -3803,8 +3116,8 @@ func addSigningHashTests() { }, }, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), + "-cert-file", rsaCertificateFile, + "-key-file", rsaKeyFile, }, }) @@ -3834,8 +3147,8 @@ func addSigningHashTests() { }, }, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), + "-cert-file", rsaCertificateFile, + "-key-file", rsaKeyFile, }, }) @@ -3865,8 +3178,8 @@ func addSigningHashTests() { }, }, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), + "-cert-file", rsaCertificateFile, + "-key-file", rsaKeyFile, }, }) @@ -3922,73 +3235,6 @@ func addSigningHashTests() { shouldFail: true, expectedError: ":WRONG_SIGNATURE_TYPE:", }) - - // Test that the agreed upon digest respects the client preferences and - // the server digests. - testCases = append(testCases, testCase{ - name: "Agree-Digest-Fallback", - config: Config{ - ClientAuth: RequireAnyClientCert, - SignatureAndHashes: []signatureAndHash{ - {signatureRSA, hashSHA512}, - {signatureRSA, hashSHA1}, - }, - }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, - digestPrefs: "SHA256", - expectedClientCertSignatureHash: hashSHA1, - }) - testCases = append(testCases, testCase{ - name: "Agree-Digest-SHA256", - config: Config{ - ClientAuth: RequireAnyClientCert, - SignatureAndHashes: []signatureAndHash{ - {signatureRSA, hashSHA1}, - {signatureRSA, hashSHA256}, - }, - }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, - digestPrefs: "SHA256,SHA1", - expectedClientCertSignatureHash: hashSHA256, - }) - testCases = append(testCases, testCase{ - name: "Agree-Digest-SHA1", - config: Config{ - ClientAuth: RequireAnyClientCert, - SignatureAndHashes: []signatureAndHash{ - {signatureRSA, hashSHA1}, - }, - }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, - digestPrefs: "SHA512,SHA256,SHA1", - expectedClientCertSignatureHash: hashSHA1, - }) - testCases = append(testCases, testCase{ - name: "Agree-Digest-Default", - config: Config{ - ClientAuth: RequireAnyClientCert, - SignatureAndHashes: []signatureAndHash{ - {signatureRSA, hashSHA256}, - {signatureECDSA, hashSHA256}, - {signatureRSA, hashSHA1}, - {signatureECDSA, hashSHA1}, - }, - }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, - expectedClientCertSignatureHash: hashSHA256, - }) } // timeouts is the retransmit schedule for BoringSSL. It doubles and @@ -4195,111 +3441,7 @@ func addTLSUniqueTests() { } } -func addCustomExtensionTests() { - expectedContents := "custom extension" - emptyString := "" - - for _, isClient := range []bool{false, true} { - suffix := "Server" - flag := "-enable-server-custom-extension" - testType := serverTest - if isClient { - suffix = "Client" - flag = "-enable-client-custom-extension" - testType = clientTest - } - - testCases = append(testCases, testCase{ - testType: testType, - name: "CustomExtensions-" + suffix, - config: Config{ - Bugs: ProtocolBugs{ - CustomExtension: expectedContents, - ExpectedCustomExtension: &expectedContents, - }, - }, - flags: []string{flag}, - }) - - // If the parse callback fails, the handshake should also fail. - testCases = append(testCases, testCase{ - testType: testType, - name: "CustomExtensions-ParseError-" + suffix, - config: Config{ - Bugs: ProtocolBugs{ - CustomExtension: expectedContents + "foo", - ExpectedCustomExtension: &expectedContents, - }, - }, - flags: []string{flag}, - shouldFail: true, - expectedError: ":CUSTOM_EXTENSION_ERROR:", - }) - - // If the add callback fails, the handshake should also fail. - testCases = append(testCases, testCase{ - testType: testType, - name: "CustomExtensions-FailAdd-" + suffix, - config: Config{ - Bugs: ProtocolBugs{ - CustomExtension: expectedContents, - ExpectedCustomExtension: &expectedContents, - }, - }, - flags: []string{flag, "-custom-extension-fail-add"}, - shouldFail: true, - expectedError: ":CUSTOM_EXTENSION_ERROR:", - }) - - // If the add callback returns zero, no extension should be - // added. - skipCustomExtension := expectedContents - if isClient { - // For the case where the client skips sending the - // custom extension, the server must not “echo” it. - skipCustomExtension = "" - } - testCases = append(testCases, testCase{ - testType: testType, - name: "CustomExtensions-Skip-" + suffix, - config: Config{ - Bugs: ProtocolBugs{ - CustomExtension: skipCustomExtension, - ExpectedCustomExtension: &emptyString, - }, - }, - flags: []string{flag, "-custom-extension-skip"}, - }) - } - - // The custom extension add callback should not be called if the client - // doesn't send the extension. - testCases = append(testCases, testCase{ - testType: serverTest, - name: "CustomExtensions-NotCalled-Server", - config: Config{ - Bugs: ProtocolBugs{ - ExpectedCustomExtension: &emptyString, - }, - }, - flags: []string{"-enable-server-custom-extension", "-custom-extension-fail-add"}, - }) - - // Test an unknown extension from the server. - testCases = append(testCases, testCase{ - testType: clientTest, - name: "UnknownExtension-Client", - config: Config{ - Bugs: ProtocolBugs{ - CustomExtension: expectedContents, - }, - }, - shouldFail: true, - expectedError: ":UNEXPECTED_EXTENSION:", - }) -} - -func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sync.WaitGroup) { +func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) { defer wg.Done() for test := range c { @@ -4307,11 +3449,11 @@ func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sy if *mallocTest < 0 { statusChan <- statusMsg{test: test, started: true} - err = runTest(test, shimPath, -1) + err = runTest(test, buildDir, -1) } else { for mallocNumToFail := int64(*mallocTest); ; mallocNumToFail++ { statusChan <- statusMsg{test: test, started: true} - if err = runTest(test, shimPath, mallocNumToFail); err != errMoreMallocs { + if err = runTest(test, buildDir, mallocNumToFail); err != errMoreMallocs { if err != nil { fmt.Printf("\n\nmalloc test failed at %d: %s\n", mallocNumToFail, err) } @@ -4373,10 +3515,12 @@ func statusPrinter(doneChan chan *testOutput, statusChan chan statusMsg, total i } func main() { + var flagTest *string = flag.String("test", "", "The name of a test to run, or empty to run all tests") + var flagNumWorkers *int = flag.Int("num-workers", runtime.NumCPU(), "The number of workers to run in parallel.") + var flagBuildDir *string = flag.String("build-dir", "../../../build", "The build directory to run the shim from.") + flag.Parse() - *resourceDir = path.Clean(*resourceDir) - addBasicTests() addCipherSuiteTests() addBadECDSASignatureTests() addCBCPaddingTests() @@ -4392,10 +3536,10 @@ func main() { addRenegotiationTests() addDTLSReplayTests() addSigningHashTests() + addFastRadioPaddingTests() addDTLSRetransmitTests() addExportKeyingMaterialTests() addTLSUniqueTests() - addCustomExtensionTests() for _, async := range []bool{false, true} { for _, splitHandshake := range []bool{false, true} { for _, protocol := range []protocol{tls, dtls} { @@ -4406,19 +3550,21 @@ func main() { var wg sync.WaitGroup - statusChan := make(chan statusMsg, *numWorkers) - testChan := make(chan *testCase, *numWorkers) + numWorkers := *flagNumWorkers + + statusChan := make(chan statusMsg, numWorkers) + testChan := make(chan *testCase, numWorkers) doneChan := make(chan *testOutput) go statusPrinter(doneChan, statusChan, len(testCases)) - for i := 0; i < *numWorkers; i++ { + for i := 0; i < numWorkers; i++ { wg.Add(1) - go worker(statusChan, testChan, *shimPath, &wg) + go worker(statusChan, testChan, *flagBuildDir, &wg) } for i := range testCases { - if len(*testToRun) == 0 || *testToRun == testCases[i].name { + if len(*flagTest) == 0 || *flagTest == testCases[i].name { testChan <- &testCases[i] } } diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc index 1c42b2e..363b6f3 100644 --- a/src/ssl/test/test_config.cc +++ b/src/ssl/test/test_config.cc @@ -65,9 +65,12 @@ const Flag<bool> kBoolFlags[] = { { "-expect-session-miss", &TestConfig::expect_session_miss }, { "-expect-extended-master-secret", &TestConfig::expect_extended_master_secret }, + { "-allow-unsafe-legacy-renegotiation", + &TestConfig::allow_unsafe_legacy_renegotiation }, { "-enable-ocsp-stapling", &TestConfig::enable_ocsp_stapling }, { "-enable-signed-cert-timestamps", &TestConfig::enable_signed_cert_timestamps }, + { "-fastradio-padding", &TestConfig::fastradio_padding }, { "-implicit-handshake", &TestConfig::implicit_handshake }, { "-use-early-callback", &TestConfig::use_early_callback }, { "-fail-early-callback", &TestConfig::fail_early_callback }, @@ -79,27 +82,9 @@ const Flag<bool> kBoolFlags[] = { { "-reject-peer-renegotiations", &TestConfig::reject_peer_renegotiations }, { "-no-legacy-server-connect", &TestConfig::no_legacy_server_connect }, { "-tls-unique", &TestConfig::tls_unique }, - { "-use-async-private-key", &TestConfig::use_async_private_key }, - { "-expect-ticket-renewal", &TestConfig::expect_ticket_renewal }, - { "-expect-no-session", &TestConfig::expect_no_session }, - { "-use-ticket-callback", &TestConfig::use_ticket_callback }, - { "-renew-ticket", &TestConfig::renew_ticket }, - { "-enable-client-custom-extension", - &TestConfig::enable_client_custom_extension }, - { "-enable-server-custom-extension", - &TestConfig::enable_server_custom_extension }, - { "-custom-extension-skip", &TestConfig::custom_extension_skip }, - { "-custom-extension-fail-add", &TestConfig::custom_extension_fail_add }, - { "-check-close-notify", &TestConfig::check_close_notify }, - { "-shim-shuts-down", &TestConfig::shim_shuts_down }, - { "-microsoft-big-sslv3-buffer", &TestConfig::microsoft_big_sslv3_buffer }, - { "-verify-fail", &TestConfig::verify_fail }, - { "-verify-peer", &TestConfig::verify_peer }, - { "-expect-verify-result", &TestConfig::expect_verify_result } }; const Flag<std::string> kStringFlags[] = { - { "-digest-prefs", &TestConfig::digest_prefs }, { "-key-file", &TestConfig::key_file }, { "-cert-file", &TestConfig::cert_file }, { "-expect-server-name", &TestConfig::expected_server_name }, @@ -116,8 +101,6 @@ const Flag<std::string> kStringFlags[] = { { "-psk-identity", &TestConfig::psk_identity }, { "-srtp-profiles", &TestConfig::srtp_profiles }, { "-cipher", &TestConfig::cipher }, - { "-cipher-tls10", &TestConfig::cipher_tls10 }, - { "-cipher-tls11", &TestConfig::cipher_tls11 }, { "-export-label", &TestConfig::export_label }, { "-export-context", &TestConfig::export_context }, }; @@ -128,8 +111,6 @@ const Flag<std::string> kBase64Flags[] = { { "-expect-ocsp-response", &TestConfig::expected_ocsp_response }, { "-expect-signed-cert-timestamps", &TestConfig::expected_signed_cert_timestamps }, - { "-ocsp-response", &TestConfig::ocsp_response }, - { "-signed-cert-timestamps", &TestConfig::signed_cert_timestamps }, }; const Flag<int> kIntFlags[] = { diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h index 9dea8e9..5d753c8 100644 --- a/src/ssl/test/test_config.h +++ b/src/ssl/test/test_config.h @@ -24,7 +24,6 @@ struct TestConfig { bool is_dtls = false; bool resume = false; bool fallback_scsv = false; - std::string digest_prefs; std::string key_file; std::string cert_file; std::string expected_server_name; @@ -55,11 +54,13 @@ struct TestConfig { bool expect_extended_master_secret = false; std::string psk; std::string psk_identity; + bool allow_unsafe_legacy_renegotiation = false; std::string srtp_profiles; bool enable_ocsp_stapling = false; std::string expected_ocsp_response; bool enable_signed_cert_timestamps = false; std::string expected_signed_cert_timestamps; + bool fastradio_padding = false; int min_version = 0; int max_version = 0; int mtu = 0; @@ -70,8 +71,6 @@ struct TestConfig { bool fail_ddos_callback = false; bool fail_second_ddos_callback = false; std::string cipher; - std::string cipher_tls10; - std::string cipher_tls11; bool handshake_never_done = false; int export_keying_material = 0; std::string export_label; @@ -80,23 +79,6 @@ struct TestConfig { bool reject_peer_renegotiations = false; bool no_legacy_server_connect = false; bool tls_unique = false; - bool use_async_private_key = false; - bool expect_ticket_renewal = false; - bool expect_no_session = false; - bool use_ticket_callback = false; - bool renew_ticket = false; - bool enable_client_custom_extension = false; - bool enable_server_custom_extension = false; - bool custom_extension_skip = false; - bool custom_extension_fail_add = false; - std::string ocsp_response; - bool check_close_notify = false; - bool shim_shuts_down = false; - bool microsoft_big_sslv3_buffer = false; - bool verify_fail = false; - bool verify_peer = false; - bool expect_verify_result = false; - std::string signed_cert_timestamps; }; bool ParseConfig(int argc, char **argv, TestConfig *out_config); diff --git a/src/ssl/tls_record.c b/src/ssl/tls_record.c deleted file mode 100644 index 36e31b4..0000000 --- a/src/ssl/tls_record.c +++ /dev/null @@ -1,338 +0,0 @@ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ -/* ==================================================================== - * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). */ - -#include <openssl/ssl.h> - -#include <assert.h> - -#include <openssl/bytestring.h> -#include <openssl/err.h> - -#include "internal.h" - - -/* kMaxEmptyRecords is the number of consecutive, empty records that will be - * processed. Without this limit an attacker could send empty records at a - * faster rate than we can process and cause record processing to loop - * forever. */ -static const uint8_t kMaxEmptyRecords = 32; - -size_t ssl_record_prefix_len(const SSL *ssl) { - if (SSL_IS_DTLS(ssl)) { - return DTLS1_RT_HEADER_LENGTH + - SSL_AEAD_CTX_explicit_nonce_len(ssl->aead_read_ctx); - } else { - return SSL3_RT_HEADER_LENGTH + - SSL_AEAD_CTX_explicit_nonce_len(ssl->aead_read_ctx); - } -} - -size_t ssl_seal_prefix_len(const SSL *ssl) { - if (SSL_IS_DTLS(ssl)) { - return DTLS1_RT_HEADER_LENGTH + - SSL_AEAD_CTX_explicit_nonce_len(ssl->aead_write_ctx); - } else { - size_t ret = SSL3_RT_HEADER_LENGTH + - SSL_AEAD_CTX_explicit_nonce_len(ssl->aead_write_ctx); - if (ssl->s3->need_record_splitting) { - ret += SSL3_RT_HEADER_LENGTH; - ret += ssl_cipher_get_record_split_len(ssl->aead_write_ctx->cipher); - } - return ret; - } -} - -size_t ssl_max_seal_overhead(const SSL *ssl) { - if (SSL_IS_DTLS(ssl)) { - return DTLS1_RT_HEADER_LENGTH + - SSL_AEAD_CTX_max_overhead(ssl->aead_write_ctx); - } else { - size_t ret = SSL3_RT_HEADER_LENGTH + - SSL_AEAD_CTX_max_overhead(ssl->aead_write_ctx); - if (ssl->s3->need_record_splitting) { - ret *= 2; - } - return ret; - } -} - -enum ssl_open_record_t tls_open_record( - SSL *ssl, uint8_t *out_type, uint8_t *out, size_t *out_len, - size_t *out_consumed, uint8_t *out_alert, size_t max_out, const uint8_t *in, - size_t in_len) { - CBS cbs; - CBS_init(&cbs, in, in_len); - - /* Decode the record header. */ - uint8_t type; - uint16_t version, ciphertext_len; - if (!CBS_get_u8(&cbs, &type) || - !CBS_get_u16(&cbs, &version) || - !CBS_get_u16(&cbs, &ciphertext_len)) { - *out_consumed = SSL3_RT_HEADER_LENGTH; - return ssl_open_record_partial; - } - - /* Check the version. */ - if ((ssl->s3->have_version && version != ssl->version) || - (version >> 8) != SSL3_VERSION_MAJOR) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_NUMBER); - *out_alert = SSL_AD_PROTOCOL_VERSION; - return ssl_open_record_error; - } - - /* Check the ciphertext length. */ - size_t extra = 0; - if (ssl->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) { - extra = SSL3_RT_MAX_EXTRA; - } - if (ciphertext_len > SSL3_RT_MAX_ENCRYPTED_LENGTH + extra) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ENCRYPTED_LENGTH_TOO_LONG); - *out_alert = SSL_AD_RECORD_OVERFLOW; - return ssl_open_record_error; - } - - /* Extract the body. */ - CBS body; - if (!CBS_get_bytes(&cbs, &body, ciphertext_len)) { - *out_consumed = SSL3_RT_HEADER_LENGTH + (size_t)ciphertext_len; - return ssl_open_record_partial; - } - - if (ssl->msg_callback != NULL) { - ssl->msg_callback(0 /* read */, 0, SSL3_RT_HEADER, in, - SSL3_RT_HEADER_LENGTH, ssl, ssl->msg_callback_arg); - } - - /* Decrypt the body. */ - size_t plaintext_len; - if (!SSL_AEAD_CTX_open(ssl->aead_read_ctx, out, &plaintext_len, max_out, - type, version, ssl->s3->read_sequence, CBS_data(&body), - CBS_len(&body))) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); - *out_alert = SSL_AD_BAD_RECORD_MAC; - return ssl_open_record_error; - } - if (!ssl3_record_sequence_update(ssl->s3->read_sequence, 8)) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return ssl_open_record_error; - } - - /* Check the plaintext length. */ - if (plaintext_len > SSL3_RT_MAX_PLAIN_LENGTH + extra) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG); - *out_alert = SSL_AD_RECORD_OVERFLOW; - return ssl_open_record_error; - } - - /* Limit the number of consecutive empty records. */ - if (plaintext_len == 0) { - ssl->s3->empty_record_count++; - if (ssl->s3->empty_record_count > kMaxEmptyRecords) { - OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_EMPTY_FRAGMENTS); - *out_alert = SSL_AD_UNEXPECTED_MESSAGE; - return ssl_open_record_error; - } - /* Apart from the limit, empty records are returned up to the caller. This - * allows the caller to reject records of the wrong type. */ - } else { - ssl->s3->empty_record_count = 0; - } - - *out_type = type; - *out_len = plaintext_len; - *out_consumed = in_len - CBS_len(&cbs); - return ssl_open_record_success; -} - -static int do_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, - size_t max_out, uint8_t type, const uint8_t *in, - size_t in_len) { - if (max_out < SSL3_RT_HEADER_LENGTH) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); - return 0; - } - /* Check the record header does not alias any part of the input. - * |SSL_AEAD_CTX_seal| will internally enforce other aliasing requirements. */ - if (in < out + SSL3_RT_HEADER_LENGTH && out < in + in_len) { - OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT); - return 0; - } - - out[0] = type; - - /* Some servers hang if initial ClientHello is larger than 256 bytes and - * record version number > TLS 1.0. */ - uint16_t wire_version = ssl->version; - if (!ssl->s3->have_version && ssl->version > SSL3_VERSION) { - wire_version = TLS1_VERSION; - } - out[1] = wire_version >> 8; - out[2] = wire_version & 0xff; - - size_t ciphertext_len; - if (!SSL_AEAD_CTX_seal(ssl->aead_write_ctx, out + SSL3_RT_HEADER_LENGTH, - &ciphertext_len, max_out - SSL3_RT_HEADER_LENGTH, - type, wire_version, ssl->s3->write_sequence, in, - in_len) || - !ssl3_record_sequence_update(ssl->s3->write_sequence, 8)) { - return 0; - } - - if (ciphertext_len >= 1 << 16) { - OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); - return 0; - } - out[3] = ciphertext_len >> 8; - out[4] = ciphertext_len & 0xff; - - *out_len = SSL3_RT_HEADER_LENGTH + ciphertext_len; - - if (ssl->msg_callback) { - ssl->msg_callback(1 /* write */, 0, SSL3_RT_HEADER, out, - SSL3_RT_HEADER_LENGTH, ssl, ssl->msg_callback_arg); - } - - return 1; -} - -int tls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, - uint8_t type, const uint8_t *in, size_t in_len) { - size_t frag_len = 0; - if (ssl->s3->need_record_splitting && type == SSL3_RT_APPLICATION_DATA && - in_len > 1) { - /* |do_seal_record| will notice if it clobbers |in[0]|, but not if it - * aliases the rest of |in|. */ - if (in + 1 <= out && out < in + in_len) { - OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT); - return 0; - } - /* Ensure |do_seal_record| does not write beyond |in[0]|. */ - size_t frag_max_out = max_out; - if (out <= in + 1 && in + 1 < out + frag_max_out) { - frag_max_out = (size_t)(in + 1 - out); - } - if (!do_seal_record(ssl, out, &frag_len, frag_max_out, type, in, 1)) { - return 0; - } - in++; - in_len--; - out += frag_len; - max_out -= frag_len; - - assert(SSL3_RT_HEADER_LENGTH + - ssl_cipher_get_record_split_len(ssl->aead_write_ctx->cipher) == - frag_len); - } - - if (!do_seal_record(ssl, out, out_len, max_out, type, in, in_len)) { - return 0; - } - *out_len += frag_len; - return 1; -} |