From e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Mon, 11 May 2015 17:20:37 -0700 Subject: external/boringssl: bump revision. This change bumps the BoringSSL revision to the current tip-of-tree. Change-Id: I91d5bf467e16e8d86cb19a4de873985f524e5faa --- src/ssl/CMakeLists.txt | 5 +- src/ssl/d1_both.c | 962 ++++++--------- src/ssl/d1_clnt.c | 30 +- src/ssl/d1_lib.c | 237 ++-- src/ssl/d1_meth.c | 47 +- src/ssl/d1_pkt.c | 554 ++------- src/ssl/d1_srtp.c | 7 +- src/ssl/d1_srvr.c | 96 +- src/ssl/internal.h | 1134 ++++++++++++++++++ src/ssl/pqueue/pqueue.c | 3 + src/ssl/pqueue/pqueue_test.c | 15 +- src/ssl/s3_both.c | 75 +- src/ssl/s3_clnt.c | 310 +++-- src/ssl/s3_enc.c | 38 +- src/ssl/s3_lib.c | 778 ++++--------- src/ssl/s3_meth.c | 9 +- src/ssl/s3_pkt.c | 472 ++++---- src/ssl/s3_srvr.c | 439 +++---- src/ssl/ssl_algs.c | 9 +- src/ssl/ssl_asn1.c | 53 +- src/ssl/ssl_cert.c | 254 ++-- src/ssl/ssl_ciph.c | 1421 ----------------------- src/ssl/ssl_cipher.c | 1362 ++++++++++++++++++++++ src/ssl/ssl_error.c | 566 --------- src/ssl/ssl_lib.c | 927 ++++++--------- src/ssl/ssl_locl.h | 1035 ----------------- src/ssl/ssl_rsa.c | 91 +- src/ssl/ssl_sess.c | 135 +-- src/ssl/ssl_stat.c | 18 +- src/ssl/ssl_test.c | 456 -------- src/ssl/ssl_test.cc | 509 ++++++++ src/ssl/ssl_txt.c | 5 +- src/ssl/t1_enc.c | 141 +-- src/ssl/t1_lib.c | 260 ++--- src/ssl/t1_reneg.c | 9 +- src/ssl/test/CMakeLists.txt | 3 - src/ssl/test/async_bio.cc | 62 +- src/ssl/test/async_bio.h | 18 +- src/ssl/test/bssl_shim.cc | 1079 ++++++++++------- src/ssl/test/malloc.cc | 19 +- src/ssl/test/packeted_bio.cc | 145 ++- src/ssl/test/packeted_bio.h | 28 +- src/ssl/test/runner/chacha20_poly1305.go | 159 +++ src/ssl/test/runner/chacha20_poly1305_test.go | 99 ++ src/ssl/test/runner/cipher_suites.go | 29 +- src/ssl/test/runner/common.go | 130 ++- src/ssl/test/runner/conn.go | 178 ++- src/ssl/test/runner/dtls.go | 288 +++-- src/ssl/test/runner/handshake_client.go | 111 +- src/ssl/test/runner/handshake_server.go | 75 +- src/ssl/test/runner/key_agreement.go | 81 +- src/ssl/test/runner/packet_adapter.go | 101 +- src/ssl/test/runner/poly1305.go | 1540 +++++++++++++++++++++++++ src/ssl/test/runner/prf.go | 4 +- src/ssl/test/runner/runner.go | 1084 +++++++++++++++-- src/ssl/test/runner/test_output.go | 79 ++ src/ssl/test/scoped_types.h | 28 + src/ssl/test/test_config.cc | 45 +- src/ssl/test/test_config.h | 69 +- 59 files changed, 9607 insertions(+), 8309 deletions(-) create mode 100644 src/ssl/internal.h delete mode 100644 src/ssl/ssl_ciph.c create mode 100644 src/ssl/ssl_cipher.c delete mode 100644 src/ssl/ssl_error.c delete mode 100644 src/ssl/ssl_locl.h delete mode 100644 src/ssl/ssl_test.c create mode 100644 src/ssl/ssl_test.cc create mode 100644 src/ssl/test/runner/chacha20_poly1305.go create mode 100644 src/ssl/test/runner/chacha20_poly1305_test.go create mode 100644 src/ssl/test/runner/poly1305.go create mode 100644 src/ssl/test/runner/test_output.go create mode 100644 src/ssl/test/scoped_types.h (limited to 'src/ssl') diff --git a/src/ssl/CMakeLists.txt b/src/ssl/CMakeLists.txt index 91bd5ea..9cc6de4 100644 --- a/src/ssl/CMakeLists.txt +++ b/src/ssl/CMakeLists.txt @@ -22,8 +22,7 @@ add_library( ssl_algs.c ssl_asn1.c ssl_cert.c - ssl_ciph.c - ssl_error.c + ssl_cipher.c ssl_lib.c ssl_rsa.c ssl_sess.c @@ -39,7 +38,7 @@ add_library( add_executable( ssl_test - ssl_test.c + ssl_test.cc ) target_link_libraries(ssl_test ssl crypto) diff --git a/src/ssl/d1_both.c b/src/ssl/d1_both.c index 5edc93f..662f518 100644 --- a/src/ssl/d1_both.c +++ b/src/ssl/d1_both.c @@ -124,44 +124,8 @@ #include #include -#include "ssl_locl.h" - -#define RSMBLY_BITMASK_SIZE(msg_len) (((msg_len) + 7) / 8) - -#define RSMBLY_BITMASK_MARK(bitmask, start, end) \ - { \ - if ((end) - (start) <= 8) { \ - long ii; \ - for (ii = (start); ii < (end); ii++) \ - bitmask[((ii) >> 3)] |= (1 << ((ii)&7)); \ - } else { \ - long ii; \ - bitmask[((start) >> 3)] |= bitmask_start_values[((start)&7)]; \ - for (ii = (((start) >> 3) + 1); ii < ((((end)-1)) >> 3); ii++) \ - bitmask[ii] = 0xff; \ - bitmask[(((end)-1) >> 3)] |= bitmask_end_values[((end)&7)]; \ - } \ - } - -#define RSMBLY_BITMASK_IS_COMPLETE(bitmask, msg_len, is_complete) \ - { \ - long ii; \ - assert((msg_len) > 0); \ - is_complete = 1; \ - if (bitmask[(((msg_len)-1) >> 3)] != bitmask_end_values[((msg_len)&7)]) \ - is_complete = 0; \ - if (is_complete) \ - for (ii = (((msg_len)-1) >> 3) - 1; ii >= 0; ii--) \ - if (bitmask[ii] != 0xff) { \ - is_complete = 0; \ - break; \ - } \ - } +#include "internal.h" -static const uint8_t bitmask_start_values[] = {0xff, 0xfe, 0xfc, 0xf8, - 0xf0, 0xe0, 0xc0, 0x80}; -static const uint8_t bitmask_end_values[] = {0xff, 0x01, 0x03, 0x07, - 0x0f, 0x1f, 0x3f, 0x7f}; /* TODO(davidben): 28 comes from the size of IP + UDP header. Is this reasonable * for these values? Notably, why is kMinMTU a function of the transport @@ -175,25 +139,30 @@ static const unsigned int kMinMTU = 256 - 28; * the underlying BIO supplies one. */ static const unsigned int kDefaultMTU = 1500 - 28; +/* kMaxHandshakeBuffer is the maximum number of handshake messages ahead of the + * current one to buffer. */ +static const unsigned int kHandshakeBufferSize = 10; + 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 long dtls1_get_message_fragment(SSL *s, int stn, long max, int *ok); static hm_fragment *dtls1_hm_fragment_new(unsigned long frag_len, int reassembly) { hm_fragment *frag = NULL; - unsigned char *buf = NULL; - unsigned char *bitmask = NULL; + uint8_t *buf = NULL; + uint8_t *bitmask = NULL; frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment)); if (frag == NULL) { + OPENSSL_PUT_ERROR(SSL, dtls1_hm_fragment_new, ERR_R_MALLOC_FAILURE); return NULL; } if (frag_len) { - buf = (unsigned char *)OPENSSL_malloc(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; } @@ -203,16 +172,22 @@ static hm_fragment *dtls1_hm_fragment_new(unsigned long frag_len, frag->fragment = buf; /* Initialize reassembly bitmask if necessary */ - if (reassembly) { - bitmask = (unsigned char *)OPENSSL_malloc(RSMBLY_BITMASK_SIZE(frag_len)); + 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); } OPENSSL_free(frag); return NULL; } - memset(bitmask, 0, RSMBLY_BITMASK_SIZE(frag_len)); + memset(bitmask, 0, bitmask_len); } frag->reassembly = bitmask; @@ -221,23 +196,65 @@ static hm_fragment *dtls1_hm_fragment_new(unsigned long frag_len, } void dtls1_hm_fragment_free(hm_fragment *frag) { - if (frag->msg_header.is_ccs) { - /* TODO(davidben): Simplify aead_write_ctx ownership, probably by just - * forbidding DTLS renego. */ - SSL_AEAD_CTX *aead_write_ctx = - frag->msg_header.saved_retransmit_state.aead_write_ctx; - if (aead_write_ctx) { - EVP_AEAD_CTX_cleanup(&aead_write_ctx->ctx); - OPENSSL_free(aead_write_ctx); + if (frag == NULL) { + return; + } + OPENSSL_free(frag->fragment); + OPENSSL_free(frag->reassembly); + OPENSSL_free(frag); +} + +#if !defined(inline) +#define inline __inline +#endif + +/* bit_range returns a |uint8_t| with bits |start|, inclusive, to |end|, + * exclusive, set. */ +static inline uint8_t bit_range(size_t start, size_t end) { + return (uint8_t)(~((1u << start) - 1) & ((1u << end) - 1)); +} + +/* dtls1_hm_fragment_mark marks bytes |start|, inclusive, to |end|, exclusive, + * as received in |frag|. If |frag| becomes complete, it clears + * |frag->reassembly|. The range must be within the bounds of |frag|'s message + * and |frag->reassembly| must not be NULL. */ +static void dtls1_hm_fragment_mark(hm_fragment *frag, size_t start, + size_t end) { + size_t i; + size_t msg_len = frag->msg_header.msg_len; + + if (frag->reassembly == NULL || start > end || end > msg_len) { + assert(0); + return; + } + /* A zero-length message will never have a pending reassembly. */ + assert(msg_len > 0); + + if ((start >> 3) == (end >> 3)) { + frag->reassembly[start >> 3] |= bit_range(start & 7, end & 7); + } else { + frag->reassembly[start >> 3] |= bit_range(start & 7, 8); + for (i = (start >> 3) + 1; i < (end >> 3); i++) { + frag->reassembly[i] = 0xff; + } + if ((end & 7) != 0) { + frag->reassembly[end >> 3] |= bit_range(0, end & 7); } } - if (frag->fragment) { - OPENSSL_free(frag->fragment); + + /* Check if the fragment is complete. */ + for (i = 0; i < (msg_len >> 3); i++) { + if (frag->reassembly[i] != 0xff) { + return; + } } - if (frag->reassembly) { - OPENSSL_free(frag->reassembly); + if ((msg_len & 7) != 0 && + frag->reassembly[msg_len >> 3] != bit_range(0, msg_len & 7)) { + return; } - OPENSSL_free(frag); + + OPENSSL_free(frag->reassembly); + frag->reassembly = NULL; } /* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or @@ -368,514 +385,279 @@ int dtls1_do_write(SSL *s, int type) { return 0; } - -/* Obtain handshake message of message type 'mt' (any if mt == -1), maximum - * acceptable body length 'max'. Read an entire handshake message. Handshake - * messages arrive in fragments. */ -long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, - int hash_message, int *ok) { - int i, al; - struct hm_header_st *msg_hdr; - uint8_t *p; - unsigned long msg_len; - - /* s3->tmp is used to store messages that are unexpected, caused - * by the absence of an optional handshake message */ - if (s->s3->tmp.reuse_message) { - /* A SSL_GET_MESSAGE_DONT_HASH_MESSAGE call cannot be combined - * with reuse_message; the SSL_GET_MESSAGE_DONT_HASH_MESSAGE - * would have to have been applied to the previous call. */ - assert(hash_message != SSL_GET_MESSAGE_DONT_HASH_MESSAGE); - s->s3->tmp.reuse_message = 0; - if (mt >= 0 && s->s3->tmp.message_type != mt) { - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, dtls1_get_message, SSL_R_UNEXPECTED_MESSAGE); - goto f_err; - } - *ok = 1; - s->init_msg = (uint8_t *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH; - s->init_num = (int)s->s3->tmp.message_size; - return s->init_num; - } - - msg_hdr = &s->d1->r_msg_hdr; - memset(msg_hdr, 0x00, sizeof(struct hm_header_st)); - -again: - i = dtls1_get_message_fragment(s, stn, max, ok); - if (i == DTLS1_HM_BAD_FRAGMENT || - i == DTLS1_HM_FRAGMENT_RETRY) { - /* bad fragment received */ - goto again; - } else if (i <= 0 && !*ok) { - return i; - } - - p = (uint8_t *)s->init_buf->data; - msg_len = msg_hdr->msg_len; - - /* reconstruct message header */ - *(p++) = msg_hdr->type; - l2n3(msg_len, p); - s2n(msg_hdr->seq, p); - l2n3(0, p); - l2n3(msg_len, p); - p -= DTLS1_HM_HEADER_LENGTH; - msg_len += DTLS1_HM_HEADER_LENGTH; - - s->init_msg = (uint8_t *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH; - - if (hash_message != SSL_GET_MESSAGE_DONT_HASH_MESSAGE) { - ssl3_hash_current_message(s); - } - if (s->msg_callback) { - s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, p, msg_len, s, - s->msg_callback_arg); +/* dtls1_is_next_message_complete returns one if the next handshake message is + * complete and zero otherwise. */ +static int dtls1_is_next_message_complete(SSL *s) { + pitem *item = pqueue_peek(s->d1->buffered_messages); + if (item == NULL) { + return 0; } - memset(msg_hdr, 0x00, sizeof(struct hm_header_st)); - - s->d1->handshake_read_seq++; + hm_fragment *frag = (hm_fragment *)item->data; + assert(s->d1->handshake_read_seq <= frag->msg_header.seq); - return s->init_num; - -f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - *ok = 0; - return -1; + return s->d1->handshake_read_seq == frag->msg_header.seq && + frag->reassembly == NULL; } -static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr, - int max) { - size_t frag_off, frag_len, msg_len; - - msg_len = msg_hdr->msg_len; - frag_off = msg_hdr->frag_off; - frag_len = msg_hdr->frag_len; - - /* sanity checking */ - if ((frag_off + frag_len) > msg_len) { - OPENSSL_PUT_ERROR(SSL, dtls1_preprocess_fragment, - SSL_R_EXCESSIVE_MESSAGE_SIZE); - return SSL_AD_ILLEGAL_PARAMETER; - } - - if ((frag_off + frag_len) > (unsigned long)max) { - OPENSSL_PUT_ERROR(SSL, dtls1_preprocess_fragment, - SSL_R_EXCESSIVE_MESSAGE_SIZE); - return SSL_AD_ILLEGAL_PARAMETER; - } - - if (s->d1->r_msg_hdr.frag_off == 0) { - /* first fragment */ - /* msg_len is limited to 2^24, but is effectively checked - * against max above */ - if (!BUF_MEM_grow_clean(s->init_buf, msg_len + DTLS1_HM_HEADER_LENGTH)) { - OPENSSL_PUT_ERROR(SSL, dtls1_preprocess_fragment, ERR_R_BUF_LIB); - return SSL_AD_INTERNAL_ERROR; +/* dtls1_discard_fragment_body discards a handshake fragment body of length + * |frag_len|. It returns one on success and zero on error. + * + * TODO(davidben): This function will go away when ssl_read_bytes is gone from + * the DTLS side. */ +static int dtls1_discard_fragment_body(SSL *s, size_t frag_len) { + uint8_t discard[256]; + while (frag_len > 0) { + size_t chunk = frag_len < sizeof(discard) ? frag_len : sizeof(discard); + int ret = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, discard, chunk, + 0); + if (ret != chunk) { + return 0; } - - s->s3->tmp.message_size = msg_len; - s->d1->r_msg_hdr.msg_len = msg_len; - s->s3->tmp.message_type = msg_hdr->type; - s->d1->r_msg_hdr.type = msg_hdr->type; - s->d1->r_msg_hdr.seq = msg_hdr->seq; - } else if (msg_len != s->d1->r_msg_hdr.msg_len) { - /* They must be playing with us! BTW, failure to enforce - * upper limit would open possibility for buffer overrun. */ - OPENSSL_PUT_ERROR(SSL, dtls1_preprocess_fragment, - SSL_R_EXCESSIVE_MESSAGE_SIZE); - return SSL_AD_ILLEGAL_PARAMETER; + frag_len -= chunk; } - - return 0; /* no error */ + return 1; } +/* dtls1_get_buffered_message returns the buffered message corresponding to + * |msg_hdr|. If none exists, it creates a new one and inserts it in the + * queue. Otherwise, it checks |msg_hdr| is consistent with the existing one. It + * returns NULL on failure. The caller does not take ownership of the result. */ +static hm_fragment *dtls1_get_buffered_message( + SSL *s, const struct hm_header_st *msg_hdr) { + uint8_t seq64be[8]; + memset(seq64be, 0, sizeof(seq64be)); + seq64be[6] = (uint8_t)(msg_hdr->seq >> 8); + seq64be[7] = (uint8_t)msg_hdr->seq; + pitem *item = pqueue_find(s->d1->buffered_messages, seq64be); -static int dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok) { - /* (0) check whether the desired fragment is available - * if so: - * (1) copy over the fragment to s->init_buf->data[] - * (2) update s->init_num */ - pitem *item; hm_fragment *frag; - int al; - unsigned long frag_len; - - *ok = 0; - item = pqueue_peek(s->d1->buffered_messages); if (item == NULL) { - return 0; - } - - frag = (hm_fragment *)item->data; - - /* Don't return if reassembly still in progress */ - if (frag->reassembly != NULL) { - return 0; - } - - if (s->d1->handshake_read_seq != frag->msg_header.seq) { - return 0; - } - - frag_len = frag->msg_header.frag_len; - pqueue_pop(s->d1->buffered_messages); - - al = dtls1_preprocess_fragment(s, &frag->msg_header, max); - - if (al == 0) { - /* no alert */ - uint8_t *p = (uint8_t *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH; - memcpy(&p[frag->msg_header.frag_off], frag->fragment, - frag->msg_header.frag_len); - } - - dtls1_hm_fragment_free(frag); - pitem_free(item); - - if (al == 0) { - *ok = 1; - return frag_len; + /* This is the first fragment from this message. */ + frag = dtls1_hm_fragment_new(msg_hdr->msg_len, + 1 /* reassembly buffer needed */); + if (frag == NULL) { + return NULL; + } + memcpy(&frag->msg_header, msg_hdr, sizeof(*msg_hdr)); + item = pitem_new(seq64be, frag); + if (item == NULL) { + dtls1_hm_fragment_free(frag); + return NULL; + } + item = pqueue_insert(s->d1->buffered_messages, item); + /* |pqueue_insert| fails iff a duplicate item is inserted, but |item| cannot + * be a duplicate. */ + assert(item != NULL); + } else { + frag = item->data; + assert(frag->msg_header.seq == msg_hdr->seq); + if (frag->msg_header.type != msg_hdr->type || + 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, dtls1_get_buffered_message, + SSL_R_FRAGMENT_MISMATCH); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + return NULL; + } } - - ssl3_send_alert(s, SSL3_AL_FATAL, al); - s->init_num = 0; - *ok = 0; - return -1; + return frag; } /* dtls1_max_handshake_message_len returns the maximum number of bytes * permitted in a DTLS handshake message for |s|. The minimum is 16KB, but may * be greater if the maximum certificate list size requires it. */ -static unsigned long dtls1_max_handshake_message_len(const SSL *s) { - unsigned long max_len = DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH; - if (max_len < (unsigned long)s->max_cert_list) { +static size_t dtls1_max_handshake_message_len(const SSL *s) { + size_t max_len = DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH; + if (max_len < s->max_cert_list) { return s->max_cert_list; } return max_len; } -static int dtls1_reassemble_fragment(SSL *s, const struct hm_header_st *msg_hdr, - int *ok) { - hm_fragment *frag = NULL; - pitem *item = NULL; - int i = -1, is_complete; - uint8_t seq64be[8]; - unsigned long frag_len = msg_hdr->frag_len; - - if ((msg_hdr->frag_off + frag_len) > msg_hdr->msg_len || - msg_hdr->msg_len > dtls1_max_handshake_message_len(s)) { - goto err; +/* 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. + * + * 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 = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, header, + DTLS1_HM_HEADER_LENGTH, 0); + if (ret <= 0) { + return ret; + } + if (ret != DTLS1_HM_HEADER_LENGTH) { + OPENSSL_PUT_ERROR(SSL, dtls1_process_fragment, SSL_R_UNEXPECTED_MESSAGE); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + return -1; + } + + /* Parse the message fragment header. */ + struct hm_header_st msg_hdr; + dtls1_get_message_header(header, &msg_hdr); + + 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)) { + 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; } - if (frag_len == 0) { - return DTLS1_HM_FRAGMENT_RETRY; + if (msg_hdr.seq < s->d1->handshake_read_seq || + msg_hdr.seq > (unsigned)s->d1->handshake_read_seq + + kHandshakeBufferSize) { + /* Ignore fragments from the past, or ones too far in the future. */ + if (!dtls1_discard_fragment_body(s, frag_len)) { + return -1; + } + return 1; } - /* Try to find item in queue */ - memset(seq64be, 0, sizeof(seq64be)); - seq64be[6] = (uint8_t)(msg_hdr->seq >> 8); - seq64be[7] = (uint8_t)msg_hdr->seq; - item = pqueue_find(s->d1->buffered_messages, seq64be); - - if (item == NULL) { - frag = dtls1_hm_fragment_new(msg_hdr->msg_len, 1); - if (frag == NULL) { - goto err; - } - memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr)); - frag->msg_header.frag_len = frag->msg_header.msg_len; - frag->msg_header.frag_off = 0; - } else { - frag = (hm_fragment *)item->data; - if (frag->msg_header.msg_len != msg_hdr->msg_len) { - item = NULL; - frag = NULL; - goto err; - } + hm_fragment *frag = dtls1_get_buffered_message(s, &msg_hdr); + if (frag == NULL) { + return -1; } + assert(frag->msg_header.msg_len == msg_len); - /* If message is already reassembled, this must be a - * retransmit and can be dropped. In this case item != NULL and so frag - * does not need to be freed. */ if (frag->reassembly == NULL) { - uint8_t devnull[256]; - - assert(item != NULL); - while (frag_len) { - i = s->method->ssl_read_bytes( - s, SSL3_RT_HANDSHAKE, devnull, - frag_len > sizeof(devnull) ? sizeof(devnull) : frag_len, 0); - if (i <= 0) { - goto err; - } - frag_len -= i; + /* The message is already assembled. */ + if (!dtls1_discard_fragment_body(s, frag_len)) { + return -1; } - return DTLS1_HM_FRAGMENT_RETRY; + return 1; } + assert(msg_len > 0); - /* read the body of the fragment (header has already been read */ - i = s->method->ssl_read_bytes( - s, SSL3_RT_HANDSHAKE, frag->fragment + msg_hdr->frag_off, frag_len, 0); - if ((unsigned long)i != frag_len) { - i = -1; - } - if (i <= 0) { - goto err; + /* Read the body of the fragment. */ + ret = s->method->ssl_read_bytes( + s, SSL3_RT_HANDSHAKE, frag->fragment + frag_off, frag_len, 0); + if (ret != frag_len) { + 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); - RSMBLY_BITMASK_MARK(frag->reassembly, (long)msg_hdr->frag_off, - (long)(msg_hdr->frag_off + frag_len)); - - RSMBLY_BITMASK_IS_COMPLETE(frag->reassembly, (long)msg_hdr->msg_len, - is_complete); + return 1; +} - if (is_complete) { - OPENSSL_free(frag->reassembly); - frag->reassembly = NULL; - } +/* dtls1_get_message reads a handshake message of message type |msg_type| (any + * if |msg_type| == -1), maximum acceptable body length |max|. Read an entire + * handshake message. Handshake messages arrive in fragments. */ +long dtls1_get_message(SSL *s, int st1, int stn, int msg_type, long max, + enum ssl_hash_message_t hash_message, int *ok) { + pitem *item = NULL; + hm_fragment *frag = NULL; + int al; - if (item == NULL) { - item = pitem_new(seq64be, frag); - if (item == NULL) { - i = -1; - goto err; + /* s3->tmp is used to store messages that are unexpected, caused + * by the absence of an optional handshake message */ + if (s->s3->tmp.reuse_message) { + /* A ssl_dont_hash_message call cannot be combined with reuse_message; the + * ssl_dont_hash_message would have to have been applied to the previous + * call. */ + assert(hash_message == ssl_hash_message); + 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, dtls1_get_message, SSL_R_UNEXPECTED_MESSAGE); + goto f_err; } - - item = pqueue_insert(s->d1->buffered_messages, item); - /* pqueue_insert fails iff a duplicate item is inserted. - * However, |item| cannot be a duplicate. If it were, - * |pqueue_find|, above, would have returned it and control - * would never have reached this branch. */ - assert(item != NULL); + *ok = 1; + s->init_msg = (uint8_t *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH; + s->init_num = (int)s->s3->tmp.message_size; + return s->init_num; } - return DTLS1_HM_FRAGMENT_RETRY; - -err: - if (frag != NULL && item == NULL) { - dtls1_hm_fragment_free(frag); + /* Process fragments until one is found. */ + while (!dtls1_is_next_message_complete(s)) { + int ret = dtls1_process_fragment(s); + if (ret <= 0) { + *ok = 0; + return ret; + } } - *ok = 0; - return i; -} -static int dtls1_process_out_of_seq_message(SSL *s, - const struct hm_header_st *msg_hdr, - int *ok) { - int i = -1; - hm_fragment *frag = NULL; - pitem *item = NULL; - uint8_t seq64be[8]; - unsigned long frag_len = msg_hdr->frag_len; + /* Read out the next complete handshake message. */ + item = pqueue_pop(s->d1->buffered_messages); + assert(item != NULL); + frag = (hm_fragment *)item->data; + assert(s->d1->handshake_read_seq == frag->msg_header.seq); + assert(frag->reassembly == NULL); - if ((msg_hdr->frag_off + frag_len) > msg_hdr->msg_len) { + if (frag->msg_header.msg_len > (size_t)max) { + OPENSSL_PUT_ERROR(SSL, dtls1_get_message, SSL_R_EXCESSIVE_MESSAGE_SIZE); goto err; } - /* Try to find item in queue, to prevent duplicate entries */ - memset(seq64be, 0, sizeof(seq64be)); - seq64be[6] = (uint8_t)(msg_hdr->seq >> 8); - seq64be[7] = (uint8_t)msg_hdr->seq; - item = pqueue_find(s->d1->buffered_messages, seq64be); - - /* If we already have an entry and this one is a fragment, - * don't discard it and rather try to reassemble it. */ - if (item != NULL && frag_len != msg_hdr->msg_len) { - item = NULL; - } - - /* Discard the message if sequence number was already there, is - * too far in the future, already in the queue or if we received - * a FINISHED before the SERVER_HELLO, which then must be a stale - * retransmit. */ - if (msg_hdr->seq <= s->d1->handshake_read_seq || - msg_hdr->seq > s->d1->handshake_read_seq + 10 || item != NULL || - (s->d1->handshake_read_seq == 0 && msg_hdr->type == SSL3_MT_FINISHED)) { - uint8_t devnull[256]; - - while (frag_len) { - i = s->method->ssl_read_bytes( - s, SSL3_RT_HANDSHAKE, devnull, - frag_len > sizeof(devnull) ? sizeof(devnull) : frag_len, 0); - if (i <= 0) { - goto err; - } - frag_len -= i; - } - } else { - if (frag_len != msg_hdr->msg_len) { - return dtls1_reassemble_fragment(s, msg_hdr, ok); - } - - if (frag_len > dtls1_max_handshake_message_len(s)) { - goto err; - } - - frag = dtls1_hm_fragment_new(frag_len, 0); - if (frag == NULL) { - goto err; - } - - memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr)); - - if (frag_len) { - /* read the body of the fragment (header has already been read */ - i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, frag->fragment, - frag_len, 0); - if ((unsigned long)i != frag_len) { - i = -1; - } - if (i <= 0) { - goto err; - } - } - - item = pitem_new(seq64be, frag); - if (item == NULL) { - goto err; - } - - item = pqueue_insert(s->d1->buffered_messages, item); - /* pqueue_insert fails iff a duplicate item is inserted. - * However, |item| cannot be a duplicate. If it were, - * |pqueue_find|, above, would have returned it. Then, either - * |frag_len| != |msg_hdr->msg_len| in which case |item| is set - * to NULL and it will have been processed with - * |dtls1_reassemble_fragment|, above, or the record will have - * been discarded. */ - assert(item != NULL); + CBB 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)) { + OPENSSL_PUT_ERROR(SSL, dtls1_get_message, ERR_R_MALLOC_FAILURE); + goto err; } - return DTLS1_HM_FRAGMENT_RETRY; - -err: - if (frag != NULL && item == NULL) { - dtls1_hm_fragment_free(frag); + /* 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 */) || + !CBB_add_u24(&cbb, frag->msg_header.msg_len) || + !CBB_add_bytes(&cbb, frag->fragment, frag->msg_header.msg_len) || + !CBB_finish(&cbb, NULL, &len)) { + CBB_cleanup(&cbb); + OPENSSL_PUT_ERROR(SSL, dtls1_get_message, ERR_R_INTERNAL_ERROR); + goto err; } - *ok = 0; - return i; -} - + assert(len == (size_t)frag->msg_header.msg_len + DTLS1_HM_HEADER_LENGTH); -static long dtls1_get_message_fragment(SSL *s, int stn, long max, int *ok) { - uint8_t wire[DTLS1_HM_HEADER_LENGTH]; - unsigned long len, frag_off, frag_len; - int i, al; - struct hm_header_st msg_hdr; - -redo: - /* see if we have the required fragment already */ - if ((frag_len = dtls1_retrieve_buffered_fragment(s, max, ok)) || *ok) { - if (*ok) { - s->init_num = frag_len; - } - return frag_len; - } + s->d1->handshake_read_seq++; - /* read handshake message header */ - i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, wire, - DTLS1_HM_HEADER_LENGTH, 0); - if (i <= 0) { - /* nbio, or an error */ - s->rwstate = SSL_READING; - *ok = 0; - return i; - } + /* TODO(davidben): This function has a lot of implicit outputs. Simplify the + * |ssl_get_message| API. */ + s->s3->tmp.message_type = frag->msg_header.type; + s->s3->tmp.message_size = frag->msg_header.msg_len; + s->init_msg = (uint8_t *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH; + s->init_num = frag->msg_header.msg_len; - /* Handshake fails if message header is incomplete */ - if (i != DTLS1_HM_HEADER_LENGTH) { + if (msg_type >= 0 && s->s3->tmp.message_type != msg_type) { al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, dtls1_get_message_fragment, - SSL_R_UNEXPECTED_MESSAGE); + OPENSSL_PUT_ERROR(SSL, dtls1_get_message, SSL_R_UNEXPECTED_MESSAGE); goto f_err; } - - /* parse the message fragment header */ - dtls1_get_message_header(wire, &msg_hdr); - - /* if this is a future (or stale) message it gets buffered - * (or dropped)--no further processing at this time. */ - if (msg_hdr.seq != s->d1->handshake_read_seq) { - return dtls1_process_out_of_seq_message(s, &msg_hdr, ok); - } - - len = msg_hdr.msg_len; - frag_off = msg_hdr.frag_off; - frag_len = msg_hdr.frag_len; - - if (frag_len && frag_len < len) { - return dtls1_reassemble_fragment(s, &msg_hdr, ok); + if (hash_message == ssl_hash_message && !ssl3_hash_current_message(s)) { + goto err; } - - if (!s->server && s->d1->r_msg_hdr.frag_off == 0 && - wire[0] == SSL3_MT_HELLO_REQUEST) { - /* The server may always send 'Hello Request' messages -- - * we are doing a handshake anyway now, so ignore them - * if their format is correct. Does not count for - * 'Finished' MAC. */ - if (wire[1] == 0 && wire[2] == 0 && wire[3] == 0) { - if (s->msg_callback) { - s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, wire, - DTLS1_HM_HEADER_LENGTH, s, s->msg_callback_arg); - } - - s->init_num = 0; - goto redo; - } else { - /* Incorrectly formated Hello request */ - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, dtls1_get_message_fragment, - SSL_R_UNEXPECTED_MESSAGE); - goto f_err; - } + if (s->msg_callback) { + s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data, + s->init_num + DTLS1_HM_HEADER_LENGTH, s, + s->msg_callback_arg); } - if ((al = dtls1_preprocess_fragment(s, &msg_hdr, max))) { - goto f_err; - } + pitem_free(item); + dtls1_hm_fragment_free(frag); - /* XDTLS: ressurect this when restart is in place */ s->state = stn; - - if (frag_len > 0) { - uint8_t *p = (uint8_t *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH; - - i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &p[frag_off], frag_len, - 0); - /* XDTLS: fix this--message fragments cannot span multiple packets */ - if (i <= 0) { - s->rwstate = SSL_READING; - *ok = 0; - return i; - } - } else { - i = 0; - } - - /* XDTLS: an incorrectly formatted fragment should cause the - * handshake to fail */ - if (i != (int)frag_len) { - al = SSL3_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, dtls1_get_message_fragment, - SSL3_AD_ILLEGAL_PARAMETER); - goto f_err; - } - *ok = 1; - - /* Note that s->init_num is *not* used as current offset in - * s->init_buf->data, but as a counter summing up fragments' - * lengths: as soon as they sum up to handshake packet - * length, we assume we have got all the fragments. */ - s->init_num = frag_len; - return frag_len; + return s->init_num; f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); - s->init_num = 0; - +err: + pitem_free(item); + dtls1_hm_fragment_free(frag); *ok = 0; return -1; } @@ -913,7 +695,7 @@ int dtls1_send_change_cipher_spec(SSL *s, int a, int b) { int dtls1_read_failed(SSL *s, int code) { if (code > 0) { - fprintf(stderr, "invalid state reached %s:%d", __FILE__, __LINE__); + assert(0); return 1; } @@ -929,7 +711,7 @@ int dtls1_read_failed(SSL *s, int code) { return code; } - return dtls1_handle_timeout(s); + return DTLSv1_handle_timeout(s); } int dtls1_get_queue_priority(unsigned short seq, int is_ccs) { @@ -944,23 +726,82 @@ int dtls1_get_queue_priority(unsigned short seq, int is_ccs) { return seq * 2 - is_ccs; } +static int dtls1_retransmit_message(SSL *s, hm_fragment *frag) { + int ret; + /* XDTLS: for now assuming that read/writes are blocking */ + unsigned long header_length; + uint8_t save_write_sequence[8]; + + /* assert(s->init_num == 0); + assert(s->init_off == 0); */ + + if (frag->msg_header.is_ccs) { + header_length = DTLS1_CCS_HEADER_LENGTH; + } else { + header_length = DTLS1_HM_HEADER_LENGTH; + } + + memcpy(s->init_buf->data, frag->fragment, + frag->msg_header.msg_len + header_length); + s->init_num = frag->msg_header.msg_len + header_length; + + dtls1_set_message_header(s, frag->msg_header.type, + frag->msg_header.msg_len, frag->msg_header.seq, + 0, frag->msg_header.frag_len); + + /* Save current state. */ + SSL_AEAD_CTX *aead_write_ctx = s->aead_write_ctx; + uint16_t epoch = s->d1->w_epoch; + + /* DTLS renegotiation is unsupported, so only epochs 0 (NULL cipher) and 1 + * (negotiated cipher) exist. */ + assert(epoch == 0 || epoch == 1); + assert(frag->msg_header.epoch <= epoch); + const int fragment_from_previous_epoch = (epoch == 1 && + frag->msg_header.epoch == 0); + if (fragment_from_previous_epoch) { + /* Rewind to the previous epoch. + * + * TODO(davidben): Instead of swapping out connection-global state, this + * logic should pass a "use previous epoch" parameter down to lower-level + * functions. */ + s->d1->w_epoch = frag->msg_header.epoch; + s->aead_write_ctx = NULL; + memcpy(save_write_sequence, s->s3->write_sequence, + sizeof(s->s3->write_sequence)); + memcpy(s->s3->write_sequence, s->d1->last_write_sequence, + sizeof(s->s3->write_sequence)); + } else { + /* Otherwise the messages must be from the same epoch. */ + assert(frag->msg_header.epoch == epoch); + } + + ret = dtls1_do_write(s, frag->msg_header.is_ccs ? SSL3_RT_CHANGE_CIPHER_SPEC + : SSL3_RT_HANDSHAKE); + + if (fragment_from_previous_epoch) { + /* Restore the current epoch. */ + s->aead_write_ctx = aead_write_ctx; + s->d1->w_epoch = epoch; + memcpy(s->d1->last_write_sequence, s->s3->write_sequence, + sizeof(s->s3->write_sequence)); + memcpy(s->s3->write_sequence, save_write_sequence, + sizeof(s->s3->write_sequence)); + } + + (void)BIO_flush(SSL_get_wbio(s)); + return ret; +} + + int dtls1_retransmit_buffered_messages(SSL *s) { pqueue sent = s->d1->sent_messages; - piterator iter; + piterator iter = pqueue_iterator(sent); pitem *item; - hm_fragment *frag; - int found = 0; - - iter = pqueue_iterator(sent); for (item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter)) { - frag = (hm_fragment *)item->data; - if (dtls1_retransmit_message( - s, (unsigned short)dtls1_get_queue_priority( - frag->msg_header.seq, frag->msg_header.is_ccs), - 0, &found) <= 0 && - found) { - fprintf(stderr, "dtls1_retransmit_message() failed\n"); + hm_fragment *frag = (hm_fragment *)item->data; + if (dtls1_retransmit_message(s, frag) <= 0) { return -1; } } @@ -998,11 +839,7 @@ int dtls1_buffer_message(SSL *s, int is_ccs) { frag->msg_header.frag_off = 0; frag->msg_header.frag_len = s->d1->w_msg_hdr.msg_len; frag->msg_header.is_ccs = is_ccs; - - /* save current state*/ - frag->msg_header.saved_retransmit_state.aead_write_ctx = s->aead_write_ctx; - frag->msg_header.saved_retransmit_state.session = s->session; - frag->msg_header.saved_retransmit_state.epoch = s->d1->w_epoch; + frag->msg_header.epoch = s->d1->w_epoch; memset(seq64be, 0, sizeof(seq64be)); seq64be[6] = (uint8_t)( @@ -1021,85 +858,6 @@ int dtls1_buffer_message(SSL *s, int is_ccs) { return 1; } -int dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off, - int *found) { - int ret; - /* XDTLS: for now assuming that read/writes are blocking */ - pitem *item; - hm_fragment *frag; - unsigned long header_length; - uint8_t seq64be[8]; - struct dtls1_retransmit_state saved_state; - uint8_t save_write_sequence[8]; - - /* assert(s->init_num == 0); - assert(s->init_off == 0); */ - - /* XDTLS: the requested message ought to be found, otherwise error */ - memset(seq64be, 0, sizeof(seq64be)); - seq64be[6] = (uint8_t)(seq >> 8); - seq64be[7] = (uint8_t)seq; - - item = pqueue_find(s->d1->sent_messages, seq64be); - if (item == NULL) { - fprintf(stderr, "retransmit: message %d non-existant\n", seq); - *found = 0; - return 0; - } - - *found = 1; - frag = (hm_fragment *)item->data; - - if (frag->msg_header.is_ccs) { - header_length = DTLS1_CCS_HEADER_LENGTH; - } else { - header_length = DTLS1_HM_HEADER_LENGTH; - } - - memcpy(s->init_buf->data, frag->fragment, - frag->msg_header.msg_len + header_length); - s->init_num = frag->msg_header.msg_len + header_length; - - dtls1_set_message_header(s, frag->msg_header.type, - frag->msg_header.msg_len, frag->msg_header.seq, - 0, frag->msg_header.frag_len); - - /* save current state */ - saved_state.aead_write_ctx = s->aead_write_ctx; - saved_state.session = s->session; - saved_state.epoch = s->d1->w_epoch; - - /* restore state in which the message was originally sent */ - s->aead_write_ctx = frag->msg_header.saved_retransmit_state.aead_write_ctx; - s->session = frag->msg_header.saved_retransmit_state.session; - s->d1->w_epoch = frag->msg_header.saved_retransmit_state.epoch; - - if (frag->msg_header.saved_retransmit_state.epoch == saved_state.epoch - 1) { - memcpy(save_write_sequence, s->s3->write_sequence, - sizeof(s->s3->write_sequence)); - memcpy(s->s3->write_sequence, s->d1->last_write_sequence, - sizeof(s->s3->write_sequence)); - } - - ret = dtls1_do_write(s, frag->msg_header.is_ccs ? SSL3_RT_CHANGE_CIPHER_SPEC - : SSL3_RT_HANDSHAKE); - - /* restore current state */ - s->aead_write_ctx = saved_state.aead_write_ctx; - s->session = saved_state.session; - s->d1->w_epoch = saved_state.epoch; - - if (frag->msg_header.saved_retransmit_state.epoch == saved_state.epoch - 1) { - memcpy(s->d1->last_write_sequence, s->s3->write_sequence, - sizeof(s->s3->write_sequence)); - memcpy(s->s3->write_sequence, save_write_sequence, - sizeof(s->s3->write_sequence)); - } - - (void)BIO_flush(SSL_get_wbio(s)); - return ret; -} - /* call this function when the buffered messages are no longer needed */ void dtls1_clear_record_buffer(SSL *s) { pitem *item; @@ -1160,12 +918,6 @@ void dtls1_get_message_header(uint8_t *data, n2l3(data, msg_hdr->frag_len); } -void dtls1_get_ccs_header(uint8_t *data, struct ccs_header_st *ccs_hdr) { - memset(ccs_hdr, 0x00, sizeof(struct ccs_header_st)); - - ccs_hdr->type = *(data++); -} - int dtls1_shutdown(SSL *s) { int ret; ret = ssl3_shutdown(s); diff --git a/src/ssl/d1_clnt.c b/src/ssl/d1_clnt.c index 3f9e814..1827a67 100644 --- a/src/ssl/d1_clnt.c +++ b/src/ssl/d1_clnt.c @@ -114,17 +114,19 @@ #include #include +#include #include #include #include #include +#include #include #include #include #include -#include "ssl_locl.h" +#include "internal.h" static int dtls1_get_hello_verify(SSL *s); @@ -156,7 +158,6 @@ int dtls1_connect(SSL *s) { case SSL_ST_RENEGOTIATE: s->renegotiate = 1; s->state = SSL_ST_CONNECT; - s->ctx->stats.sess_connect_renegotiate++; /* break */ case SSL_ST_CONNECT: case SSL_ST_BEFORE | SSL_ST_CONNECT: @@ -175,8 +176,7 @@ int dtls1_connect(SSL *s) { buf = NULL; } - if (!ssl3_setup_buffers(s) || - !ssl_init_wbio_buffer(s, 0)) { + if (!ssl_init_wbio_buffer(s, 0)) { ret = -1; goto end; } @@ -184,7 +184,6 @@ int dtls1_connect(SSL *s) { /* don't push the buffering BIO quite yet */ s->state = SSL3_ST_CW_CLNT_HELLO_A; - s->ctx->stats.sess_connect++; s->init_num = 0; s->d1->send_cookie = 0; s->hit = 0; @@ -458,12 +457,6 @@ int dtls1_connect(SSL *s) { case SSL3_ST_CW_FLUSH: s->rwstate = SSL_WRITING; if (BIO_flush(s->wbio) <= 0) { - /* If the write error was fatal, stop trying */ - if (!BIO_should_retry(s->wbio)) { - s->rwstate = SSL_NOTHING; - s->state = s->s3->tmp.next_state; - } - ret = -1; goto end; } @@ -483,15 +476,12 @@ int dtls1_connect(SSL *s) { s->new_session = 0; ssl_update_cache(s, SSL_SESS_CACHE_CLIENT); - if (s->hit) { - s->ctx->stats.sess_hit++; - } ret = 1; - s->ctx->stats.sess_connect_good++; - if (cb != NULL) + if (cb != NULL) { cb(s, SSL_CB_HANDSHAKE_DONE, 1); + } /* done with handshaking */ s->d1->handshake_read_seq = 0; @@ -519,9 +509,7 @@ int dtls1_connect(SSL *s) { end: s->in_handshake--; - if (buf != NULL) { - BUF_MEM_free(buf); - } + BUF_MEM_free(buf); if (cb != NULL) { cb(s, SSL_CB_CONNECT_EXIT, ret); } @@ -538,7 +526,7 @@ static int dtls1_get_hello_verify(SSL *s) { s, DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A, DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B, -1, /* Use the same maximum size as ssl3_get_server_hello. */ - 20000, SSL_GET_MESSAGE_HASH_MESSAGE, &ok); + 20000, ssl_hash_message, &ok); if (!ok) { return n; @@ -556,7 +544,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, ssl3_get_cert_status, 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 8244cb9..e53156f 100644 --- a/src/ssl/d1_lib.c +++ b/src/ssl/d1_lib.c @@ -58,6 +58,7 @@ #include #include +#include #if defined(OPENSSL_WINDOWS) #include @@ -70,51 +71,17 @@ #include #include -#include "ssl_locl.h" - -static void get_current_time(OPENSSL_timeval *t); -static OPENSSL_timeval *dtls1_get_timeout(SSL *s, OPENSSL_timeval *timeleft); -static void dtls1_set_handshake_header(SSL *s, int type, unsigned long len); -static int dtls1_handshake_write(SSL *s); - -const SSL3_ENC_METHOD DTLSv1_enc_data = { - tls1_enc, - tls1_prf, - tls1_setup_key_block, - tls1_generate_master_secret, - tls1_change_cipher_state, - tls1_final_finish_mac, - TLS1_FINISH_MAC_LENGTH, - tls1_cert_verify_mac, - TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE, - TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE, - tls1_alert_code, - tls1_export_keying_material, - SSL_ENC_FLAG_DTLS|SSL_ENC_FLAG_EXPLICIT_IV, - DTLS1_HM_HEADER_LENGTH, - dtls1_set_handshake_header, - dtls1_handshake_write, -}; - -const SSL3_ENC_METHOD DTLSv1_2_enc_data = { - tls1_enc, - tls1_prf, - tls1_setup_key_block, - tls1_generate_master_secret, - tls1_change_cipher_state, - tls1_final_finish_mac, - TLS1_FINISH_MAC_LENGTH, - tls1_cert_verify_mac, - TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE, - TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE, - tls1_alert_code, - tls1_export_keying_material, - SSL_ENC_FLAG_DTLS | SSL_ENC_FLAG_EXPLICIT_IV | SSL_ENC_FLAG_SIGALGS | - SSL_ENC_FLAG_SHA256_PRF | SSL_ENC_FLAG_TLS1_2_CIPHERS, - DTLS1_HM_HEADER_LENGTH, - dtls1_set_handshake_header, - dtls1_handshake_write, -}; +#include "internal.h" + +/* DTLS1_MTU_TIMEOUTS is the maximum number of timeouts to expire + * before starting to decrease the MTU. */ +#define DTLS1_MTU_TIMEOUTS 2 + +/* DTLS1_MAX_TIMEOUTS is the maximum number of timeouts to expire + * before failing the DTLS handshake. */ +#define DTLS1_MAX_TIMEOUTS 12 + +static void get_current_time(const SSL *ssl, struct timeval *out_clock); int dtls1_new(SSL *s) { DTLS1_STATE *d1; @@ -129,30 +96,12 @@ int dtls1_new(SSL *s) { } memset(d1, 0, sizeof *d1); - d1->unprocessed_rcds.q = pqueue_new(); - d1->processed_rcds.q = pqueue_new(); d1->buffered_messages = pqueue_new(); d1->sent_messages = pqueue_new(); - d1->buffered_app_data.q = pqueue_new(); - if (!d1->unprocessed_rcds.q || !d1->processed_rcds.q || - !d1->buffered_messages || !d1->sent_messages || - !d1->buffered_app_data.q) { - if (d1->unprocessed_rcds.q) { - pqueue_free(d1->unprocessed_rcds.q); - } - if (d1->processed_rcds.q) { - pqueue_free(d1->processed_rcds.q); - } - if (d1->buffered_messages) { - pqueue_free(d1->buffered_messages); - } - if (d1->sent_messages) { - pqueue_free(d1->sent_messages); - } - if (d1->buffered_app_data.q) { - pqueue_free(d1->buffered_app_data.q); - } + if (!d1->buffered_messages || !d1->sent_messages) { + pqueue_free(d1->buffered_messages); + pqueue_free(d1->sent_messages); OPENSSL_free(d1); ssl3_free(s); return 0; @@ -172,25 +121,6 @@ int dtls1_new(SSL *s) { static void dtls1_clear_queues(SSL *s) { pitem *item = NULL; hm_fragment *frag = NULL; - DTLS1_RECORD_DATA *rdata; - - while ((item = pqueue_pop(s->d1->unprocessed_rcds.q)) != NULL) { - rdata = (DTLS1_RECORD_DATA *)item->data; - if (rdata->rbuf.buf) { - OPENSSL_free(rdata->rbuf.buf); - } - OPENSSL_free(item->data); - pitem_free(item); - } - - while ((item = pqueue_pop(s->d1->processed_rcds.q)) != NULL) { - rdata = (DTLS1_RECORD_DATA *)item->data; - if (rdata->rbuf.buf) { - OPENSSL_free(rdata->rbuf.buf); - } - OPENSSL_free(item->data); - pitem_free(item); - } while ((item = pqueue_pop(s->d1->buffered_messages)) != NULL) { frag = (hm_fragment *)item->data; @@ -203,15 +133,6 @@ static void dtls1_clear_queues(SSL *s) { dtls1_hm_fragment_free(frag); pitem_free(item); } - - while ((item = pqueue_pop(s->d1->buffered_app_data.q)) != NULL) { - rdata = (DTLS1_RECORD_DATA *)item->data; - if (rdata->rbuf.buf) { - OPENSSL_free(rdata->rbuf.buf); - } - OPENSSL_free(item->data); - pitem_free(item); - } } void dtls1_free(SSL *s) { @@ -223,40 +144,15 @@ void dtls1_free(SSL *s) { dtls1_clear_queues(s); - pqueue_free(s->d1->unprocessed_rcds.q); - pqueue_free(s->d1->processed_rcds.q); pqueue_free(s->d1->buffered_messages); pqueue_free(s->d1->sent_messages); - pqueue_free(s->d1->buffered_app_data.q); OPENSSL_free(s->d1); s->d1 = NULL; } -long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg) { - int ret = 0; - - switch (cmd) { - case DTLS_CTRL_GET_TIMEOUT: - if (dtls1_get_timeout(s, (OPENSSL_timeval *)parg) != NULL) { - ret = 1; - } - break; - - case DTLS_CTRL_HANDLE_TIMEOUT: - ret = dtls1_handle_timeout(s); - break; - - default: - ret = ssl3_ctrl(s, cmd, larg, parg); - break; - } - - return ret; -} - -const SSL_CIPHER *dtls1_get_cipher(unsigned int u) { - const SSL_CIPHER *ciph = ssl3_get_cipher(u); +const SSL_CIPHER *dtls1_get_cipher(size_t i) { + const SSL_CIPHER *ciph = ssl3_get_cipher(i); /* DTLS does not support stream ciphers. */ if (ciph == NULL || ciph->algorithm_enc == SSL_RC4) { return NULL; @@ -272,7 +168,7 @@ void dtls1_start_timer(SSL *s) { } /* Set timeout to current time */ - get_current_time(&s->d1->next_timeout); + get_current_time(s, &s->d1->next_timeout); /* Add duration to current time */ s->d1->next_timeout.tv_sec += s->d1->timeout_duration; @@ -280,48 +176,51 @@ void dtls1_start_timer(SSL *s) { &s->d1->next_timeout); } -static OPENSSL_timeval *dtls1_get_timeout(SSL *s, OPENSSL_timeval *timeleft) { - OPENSSL_timeval timenow; +int DTLSv1_get_timeout(const SSL *ssl, struct timeval *out) { + if (!SSL_IS_DTLS(ssl)) { + return 0; + } /* If no timeout is set, just return NULL */ - if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0) { - return NULL; + if (ssl->d1->next_timeout.tv_sec == 0 && ssl->d1->next_timeout.tv_usec == 0) { + return 0; } /* Get current time */ - get_current_time(&timenow); + struct timeval timenow; + get_current_time(ssl, &timenow); /* If timer already expired, set remaining time to 0 */ - if (s->d1->next_timeout.tv_sec < timenow.tv_sec || - (s->d1->next_timeout.tv_sec == timenow.tv_sec && - s->d1->next_timeout.tv_usec <= timenow.tv_usec)) { - memset(timeleft, 0, sizeof(OPENSSL_timeval)); - return timeleft; + if (ssl->d1->next_timeout.tv_sec < timenow.tv_sec || + (ssl->d1->next_timeout.tv_sec == timenow.tv_sec && + ssl->d1->next_timeout.tv_usec <= timenow.tv_usec)) { + memset(out, 0, sizeof(struct timeval)); + return 1; } /* Calculate time left until timer expires */ - memcpy(timeleft, &s->d1->next_timeout, sizeof(OPENSSL_timeval)); - timeleft->tv_sec -= timenow.tv_sec; - timeleft->tv_usec -= timenow.tv_usec; - if (timeleft->tv_usec < 0) { - timeleft->tv_sec--; - timeleft->tv_usec += 1000000; + memcpy(out, &ssl->d1->next_timeout, sizeof(struct timeval)); + out->tv_sec -= timenow.tv_sec; + out->tv_usec -= timenow.tv_usec; + if (out->tv_usec < 0) { + out->tv_sec--; + out->tv_usec += 1000000; } /* If remaining time is less than 15 ms, set it to 0 to prevent issues * because of small devergences with socket timeouts. */ - if (timeleft->tv_sec == 0 && timeleft->tv_usec < 15000) { - memset(timeleft, 0, sizeof(OPENSSL_timeval)); + if (out->tv_sec == 0 && out->tv_usec < 15000) { + memset(out, 0, sizeof(struct timeval)); } - return timeleft; + return 1; } int dtls1_is_timer_expired(SSL *s) { - OPENSSL_timeval timeleft; + struct timeval timeleft; /* Get time left until timeout, return false if no timer running */ - if (dtls1_get_timeout(s, &timeleft) == NULL) { + if (!DTLSv1_get_timeout(s, &timeleft)) { return 0; } @@ -344,8 +243,8 @@ void dtls1_double_timeout(SSL *s) { void dtls1_stop_timer(SSL *s) { /* Reset everything */ - memset(&(s->d1->timeout), 0, sizeof(struct dtls1_timeout_st)); - memset(&s->d1->next_timeout, 0, sizeof(OPENSSL_timeval)); + s->d1->num_timeouts = 0; + memset(&s->d1->next_timeout, 0, sizeof(struct timeval)); s->d1->timeout_duration = 1; BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &s->d1->next_timeout); @@ -354,10 +253,10 @@ void dtls1_stop_timer(SSL *s) { } int dtls1_check_timeout_num(SSL *s) { - s->d1->timeout.num_alerts++; + s->d1->num_timeouts++; /* Reduce MTU after 2 unsuccessful retransmissions */ - if (s->d1->timeout.num_alerts > 2 && + if (s->d1->num_timeouts > DTLS1_MTU_TIMEOUTS && !(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) { long mtu = BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0, NULL); @@ -366,7 +265,7 @@ int dtls1_check_timeout_num(SSL *s) { } } - if (s->d1->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT) { + if (s->d1->num_timeouts > DTLS1_MAX_TIMEOUTS) { /* fail the connection, enough alerts have been sent */ OPENSSL_PUT_ERROR(SSL, dtls1_check_timeout_num, SSL_R_READ_TIMEOUT_EXPIRED); return -1; @@ -375,39 +274,43 @@ int dtls1_check_timeout_num(SSL *s) { return 0; } -int dtls1_handle_timeout(SSL *s) { +int DTLSv1_handle_timeout(SSL *ssl) { + if (!SSL_IS_DTLS(ssl)) { + return -1; + } + /* if no timer is expired, don't do anything */ - if (!dtls1_is_timer_expired(s)) { + if (!dtls1_is_timer_expired(ssl)) { return 0; } - dtls1_double_timeout(s); + dtls1_double_timeout(ssl); - if (dtls1_check_timeout_num(s) < 0) { + if (dtls1_check_timeout_num(ssl) < 0) { return -1; } - s->d1->timeout.read_timeouts++; - if (s->d1->timeout.read_timeouts > DTLS1_TMO_READ_COUNT) { - s->d1->timeout.read_timeouts = 1; - } - - dtls1_start_timer(s); - return dtls1_retransmit_buffered_messages(s); + dtls1_start_timer(ssl); + return dtls1_retransmit_buffered_messages(ssl); } -static void get_current_time(OPENSSL_timeval *t) { +static void get_current_time(const SSL *ssl, struct timeval *out_clock) { + if (ssl->ctx->current_time_cb != NULL) { + ssl->ctx->current_time_cb(ssl, out_clock); + return; + } + #if defined(OPENSSL_WINDOWS) struct _timeb time; _ftime(&time); - t->tv_sec = time.time; - t->tv_usec = time.millitm * 1000; + out_clock->tv_sec = time.time; + out_clock->tv_usec = time.millitm * 1000; #else - gettimeofday(t, NULL); + gettimeofday(out_clock, NULL); #endif } -static void dtls1_set_handshake_header(SSL *s, int htype, unsigned long len) { +int dtls1_set_handshake_header(SSL *s, int htype, unsigned long len) { uint8_t *message = (uint8_t *)s->init_buf->data; const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; uint8_t serialised_header[DTLS1_HM_HEADER_LENGTH]; @@ -430,10 +333,10 @@ static void 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); - ssl3_finish_mac(s, serialised_header, sizeof(serialised_header)); - ssl3_finish_mac(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); } -static int dtls1_handshake_write(SSL *s) { +int dtls1_handshake_write(SSL *s) { return dtls1_do_write(s, SSL3_RT_HANDSHAKE); } diff --git a/src/ssl/d1_meth.c b/src/ssl/d1_meth.c index a894222..a11fbdd 100644 --- a/src/ssl/d1_meth.c +++ b/src/ssl/d1_meth.c @@ -55,32 +55,33 @@ * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). */ -#include "ssl_locl.h" +#include "internal.h" static const SSL_PROTOCOL_METHOD DTLS_protocol_method = { - dtls1_new, - dtls1_free, - dtls1_accept, - dtls1_connect, - ssl3_read, - ssl3_peek, - ssl3_write, - dtls1_shutdown, - ssl3_renegotiate, - ssl3_renegotiate_check, - dtls1_get_message, - dtls1_read_bytes, - dtls1_write_app_data_bytes, - dtls1_dispatch_alert, - dtls1_ctrl, - ssl3_ctx_ctrl, - ssl3_pending, - ssl3_num_ciphers, - dtls1_get_cipher, - ssl_undefined_void_function, - ssl3_callback_ctrl, - ssl3_ctx_callback_ctrl, + 1 /* is_dtls */, + dtls1_new, + dtls1_free, + dtls1_accept, + dtls1_connect, + ssl3_read, + ssl3_peek, + ssl3_write, + dtls1_shutdown, + ssl3_renegotiate, + ssl3_renegotiate_check, + dtls1_get_message, + dtls1_read_bytes, + dtls1_write_app_data_bytes, + dtls1_dispatch_alert, + ssl3_ctrl, + ssl3_ctx_ctrl, + ssl3_pending, + ssl3_num_ciphers, + dtls1_get_cipher, + DTLS1_HM_HEADER_LENGTH, + dtls1_set_handshake_header, + dtls1_handshake_write, }; const SSL_METHOD *DTLS_method(void) { diff --git a/src/ssl/d1_pkt.c b/src/ssl/d1_pkt.c index a77ad4e..9e056ac 100644 --- a/src/ssl/d1_pkt.c +++ b/src/ssl/d1_pkt.c @@ -109,9 +109,9 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ -#include -#include #include +#include +#include #include #include @@ -119,7 +119,7 @@ #include #include -#include "ssl_locl.h" +#include "internal.h" /* mod 128 saturating subtract of two 64-bit values in big-endian order */ @@ -181,152 +181,12 @@ static int satsub64be(const uint8_t *v1, const uint8_t *v2) { } } -static int have_handshake_fragment(SSL *s, int type, uint8_t *buf, int len, - int peek); static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap); static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap); -static DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, - unsigned int *is_next_epoch); -static int dtls1_buffer_record(SSL *s, record_pqueue *q, - uint8_t *priority); static int dtls1_process_record(SSL *s); static int do_dtls1_write(SSL *s, int type, const uint8_t *buf, unsigned int len); -/* copy buffered record into SSL structure */ -static int dtls1_copy_record(SSL *s, pitem *item) { - DTLS1_RECORD_DATA *rdata; - - rdata = (DTLS1_RECORD_DATA *)item->data; - - if (s->s3->rbuf.buf != NULL) { - OPENSSL_free(s->s3->rbuf.buf); - } - - s->packet = rdata->packet; - s->packet_length = rdata->packet_length; - memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER)); - memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD)); - - /* Set proper sequence number for mac calculation */ - memcpy(&(s->s3->read_sequence[2]), &(rdata->packet[5]), 6); - - return 1; -} - -static int dtls1_buffer_record(SSL *s, record_pqueue *queue, - uint8_t *priority) { - DTLS1_RECORD_DATA *rdata; - pitem *item; - - /* Limit the size of the queue to prevent DOS attacks */ - if (pqueue_size(queue->q) >= 100) { - return 0; - } - - rdata = OPENSSL_malloc(sizeof(DTLS1_RECORD_DATA)); - item = pitem_new(priority, rdata); - if (rdata == NULL || item == NULL) { - if (rdata != NULL) { - OPENSSL_free(rdata); - } - if (item != NULL) { - pitem_free(item); - } - - OPENSSL_PUT_ERROR(SSL, dtls1_buffer_record, ERR_R_INTERNAL_ERROR); - return -1; - } - - rdata->packet = s->packet; - rdata->packet_length = s->packet_length; - memcpy(&(rdata->rbuf), &(s->s3->rbuf), sizeof(SSL3_BUFFER)); - memcpy(&(rdata->rrec), &(s->s3->rrec), sizeof(SSL3_RECORD)); - - item->data = rdata; - - s->packet = NULL; - s->packet_length = 0; - memset(&(s->s3->rbuf), 0, sizeof(SSL3_BUFFER)); - memset(&(s->s3->rrec), 0, sizeof(SSL3_RECORD)); - - if (!ssl3_setup_buffers(s)) { - goto internal_error; - } - - /* insert should not fail, since duplicates are dropped */ - if (pqueue_insert(queue->q, item) == NULL) { - goto internal_error; - } - - return 1; - -internal_error: - OPENSSL_PUT_ERROR(SSL, dtls1_buffer_record, ERR_R_INTERNAL_ERROR); - if (rdata->rbuf.buf != NULL) { - OPENSSL_free(rdata->rbuf.buf); - } - OPENSSL_free(rdata); - pitem_free(item); - return -1; -} - -static int dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue) { - pitem *item; - - item = pqueue_pop(queue->q); - if (item) { - dtls1_copy_record(s, item); - - OPENSSL_free(item->data); - pitem_free(item); - - return 1; - } - - return 0; -} - -/* retrieve a buffered record that belongs to the new epoch, i.e., not - * processed yet */ -#define dtls1_get_unprocessed_record(s) \ - dtls1_retrieve_buffered_record((s), &((s)->d1->unprocessed_rcds)) - -/* retrieve a buffered record that belongs to the current epoch, i.e., - * processed */ -#define dtls1_get_processed_record(s) \ - dtls1_retrieve_buffered_record((s), &((s)->d1->processed_rcds)) - -static int dtls1_process_buffered_records(SSL *s) { - pitem *item; - - item = pqueue_peek(s->d1->unprocessed_rcds.q); - if (item) { - /* Check if epoch is current. */ - if (s->d1->unprocessed_rcds.epoch != s->d1->r_epoch) { - return 1; /* Nothing to do. */ - } - - /* Process all the records. */ - while (pqueue_peek(s->d1->unprocessed_rcds.q)) { - dtls1_get_unprocessed_record(s); - if (!dtls1_process_record(s)) { - return 0; - } - if (dtls1_buffer_record(s, &(s->d1->processed_rcds), - s->s3->rrec.seq_num) < 0) { - return -1; - } - } - } - - /* sync epoch numbers once all the unprocessed records have been processed */ - s->d1->processed_rcds.epoch = s->d1->r_epoch; - s->d1->unprocessed_rcds.epoch = s->d1->r_epoch + 1; - - return 1; -} - static int dtls1_process_record(SSL *s) { int al; SSL3_RECORD *rr; @@ -405,28 +265,15 @@ int dtls1_get_record(SSL *s) { SSL3_RECORD *rr; unsigned char *p = NULL; unsigned short version; - DTLS1_BITMAP *bitmap; - unsigned int is_next_epoch; rr = &(s->s3->rrec); - /* The epoch may have changed. If so, process all the pending records. This - * is a non-blocking operation. */ - if (dtls1_process_buffered_records(s) < 0) { - return -1; - } - - /* If we're renegotiating, then there may be buffered records. */ - if (dtls1_get_processed_record(s)) { - return 1; - } - /* 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, s->s3->rbuf.len, 0); + 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 */ @@ -498,7 +345,7 @@ again: if (rr->length > s->packet_length - DTLS1_RT_HEADER_LENGTH) { /* now s->packet_length == DTLS1_RT_HEADER_LENGTH */ i = rr->length; - n = ssl3_read_n(s, i, i, 1); + n = ssl3_read_n(s, i, 1); if (n <= 0) { return n; /* error or non-blocking io */ } @@ -515,16 +362,17 @@ again: } s->rstate = SSL_ST_READ_HEADER; /* set state for later operations */ - /* match epochs. NULL means the packet is dropped on the floor */ - bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch); - if (bitmap == NULL) { + 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; /* dump this record */ - goto again; /* get another record */ + s->packet_length = 0; + goto again; } /* Check whether this is a repeat, or aged record. */ - if (!dtls1_record_replay_check(s, bitmap)) { + if (!dtls1_record_replay_check(s, &s->d1->bitmap)) { rr->length = 0; s->packet_length = 0; /* dump this record */ goto again; /* get another record */ @@ -535,28 +383,12 @@ again: goto again; } - /* If this record is from the next epoch (either HM or ALERT), - * and a handshake is currently in progress, buffer it since it - * cannot be processed at this time. - */ - if (is_next_epoch) { - if (SSL_in_init(s) || s->in_handshake) { - if (dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num) < 0) { - return -1; - } - dtls1_record_bitmap_update(s, bitmap); /* Mark receipt of record. */ - } - rr->length = 0; - s->packet_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, bitmap); /* Mark receipt of record. */ + dtls1_record_bitmap_update(s, &s->d1->bitmap); /* Mark receipt of record. */ return 1; } @@ -589,15 +421,11 @@ again: * none of our business */ int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek) { - int al, i, j, ret; + int al, i, ret; unsigned int n; SSL3_RECORD *rr; void (*cb)(const SSL *ssl, int type2, int val) = NULL; - if (s->s3->rbuf.buf == NULL && !ssl3_setup_buffers(s)) { - return -1; - } - /* XXX: check what the second '&& type' is about */ if ((type && (type != SSL3_RT_APPLICATION_DATA) && (type != SSL3_RT_HANDSHAKE) && type) || @@ -606,14 +434,6 @@ int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek) { return -1; } - /* check whether there's a handshake message (client hello?) waiting */ - ret = have_handshake_fragment(s, type, buf, len, peek); - if (ret) { - return ret; - } - - /* Now s->d1->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */ - if (!s->in_handshake && SSL_in_init(s)) { /* type == SSL3_RT_APPLICATION_DATA */ i = s->handshake_func(s); @@ -635,23 +455,8 @@ start: * s->s3->rrec.length - number of bytes. */ rr = &s->s3->rrec; - /* We are not handshaking and have no data yet, - * so process data buffered during the last handshake - * in advance, if any. - */ - if (s->state == SSL_ST_OK && rr->length == 0) { - pitem *item; - item = pqueue_pop(s->d1->buffered_app_data.q); - if (item) { - dtls1_copy_record(s, item); - - OPENSSL_free(item->data); - pitem_free(item); - } - } - /* Check for timeout */ - if (dtls1_handle_timeout(s) > 0) { + if (DTLSv1_handle_timeout(s) > 0) { goto start; } @@ -673,14 +478,11 @@ start: /* |change_cipher_spec is set when we receive a ChangeCipherSpec and reset by * ssl3_get_finished. */ - if (s->s3->change_cipher_spec && rr->type != SSL3_RT_HANDSHAKE) { - /* We now have application data between CCS and Finished. Most likely the - * packets were reordered on their way, so buffer the application data for - * later processing rather than dropping the connection. */ - if (dtls1_buffer_record(s, &(s->d1->buffered_app_data), rr->seq_num) < 0) { - OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, ERR_R_INTERNAL_ERROR); - return -1; - } + if (s->s3->change_cipher_spec && rr->type != SSL3_RT_HANDSHAKE && + rr->type != SSL3_RT_ALERT) { + /* We now have an unexpected record between CCS and Finished. Most likely + * the packets were reordered on their way. DTLS is unreliable, so drop the + * packet and expect the peer to retransmit. */ rr->length = 0; goto start; } @@ -729,118 +531,25 @@ start: return n; } - /* If we get here, then type != rr->type; if we have a handshake message, - * then it was unexpected (Hello Request or Client Hello). */ - - /* In case of record types for which we have 'fragment' storage, fill that so - * that we can process the data at a fixed place. */ - { - unsigned int k, dest_maxlen = 0; - uint8_t *dest = NULL; - unsigned int *dest_len = NULL; - - if (rr->type == SSL3_RT_HANDSHAKE) { - dest_maxlen = sizeof s->d1->handshake_fragment; - dest = s->d1->handshake_fragment; - dest_len = &s->d1->handshake_fragment_len; - } else if (rr->type == SSL3_RT_ALERT) { - dest_maxlen = sizeof(s->d1->alert_fragment); - dest = s->d1->alert_fragment; - dest_len = &s->d1->alert_fragment_len; - } - /* else it's a CCS message, or application data or wrong */ - else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC) { - /* Application data while renegotiating is allowed. Try again reading. */ - if (rr->type == SSL3_RT_APPLICATION_DATA) { - BIO *bio; - s->s3->in_read_app_data = 2; - bio = SSL_get_rbio(s); - s->rwstate = SSL_READING; - BIO_clear_retry_flags(bio); - BIO_set_retry_read(bio); - return -1; - } - - /* Not certain if this is the right error handling */ - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_UNEXPECTED_RECORD); - goto f_err; - } - - if (dest_maxlen > 0) { - /* XDTLS: In a pathalogical case, the Client Hello - * may be fragmented--don't always expect dest_maxlen bytes */ - if (rr->length < dest_maxlen) { - s->rstate = SSL_ST_READ_HEADER; - rr->length = 0; - goto start; - } - - /* now move 'n' bytes: */ - for (k = 0; k < dest_maxlen; k++) { - dest[k] = rr->data[rr->off++]; - rr->length--; - } - *dest_len = dest_maxlen; - } - } - - /* s->d1->handshake_fragment_len == 12 iff rr->type == SSL3_RT_HANDSHAKE; - * s->d1->alert_fragment_len == 7 iff rr->type == SSL3_RT_ALERT. - * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */ - - /* If we are a client, check for an incoming 'Hello Request': */ - if (!s->server && s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH && - s->d1->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST && - s->session != NULL && s->session->cipher != NULL) { - s->d1->handshake_fragment_len = 0; + /* If we get here, then type != rr->type. */ - if ((s->d1->handshake_fragment[1] != 0) || - (s->d1->handshake_fragment[2] != 0) || - (s->d1->handshake_fragment[3] != 0)) { + /* If an alert record, process one alert out of the record. Note that we allow + * a single record to contain multiple alerts. */ + if (rr->type == SSL3_RT_ALERT) { + /* Alerts may not be fragmented. */ + if (rr->length < 2) { al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_BAD_HELLO_REQUEST); + OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_BAD_ALERT); goto f_err; } - /* no need to check sequence number on HELLO REQUEST messages */ - - if (s->msg_callback) { - s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, - s->d1->handshake_fragment, 4, s, s->msg_callback_arg); - } - - if (SSL_is_init_finished(s) && !s->s3->renegotiate) { - s->d1->handshake_read_seq++; - s->new_session = 1; - ssl3_renegotiate(s); - if (ssl3_renegotiate_check(s)) { - i = s->handshake_func(s); - if (i < 0) { - return i; - } - if (i == 0) { - OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE); - return -1; - } - } - } - - /* we either finished a handshake or ignored the request, now try again to - * obtain the (application) data we were asked for */ - goto start; - } - - if (s->d1->alert_fragment_len >= DTLS1_AL_HEADER_LENGTH) { - int alert_level = s->d1->alert_fragment[0]; - int alert_descr = s->d1->alert_fragment[1]; - - s->d1->alert_fragment_len = 0; - if (s->msg_callback) { - s->msg_callback(0, s->version, SSL3_RT_ALERT, s->d1->alert_fragment, 2, s, + s->msg_callback(0, s->version, SSL3_RT_ALERT, &rr->data[rr->off], 2, s, s->msg_callback_arg); } + const uint8_t alert_level = rr->data[rr->off++]; + const uint8_t alert_descr = rr->data[rr->off++]; + rr->length -= 2; if (s->info_callback != NULL) { cb = s->info_callback; @@ -849,17 +558,17 @@ start: } if (cb != NULL) { - j = (alert_level << 8) | alert_descr; - cb(s, SSL_CB_READ_ALERT, j); + uint16_t alert = (alert_level << 8) | alert_descr; + cb(s, SSL_CB_READ_ALERT, alert); } - if (alert_level == 1) { /* warning */ + if (alert_level == SSL3_AL_WARNING) { s->s3->warn_alert = alert_descr; if (alert_descr == SSL_AD_CLOSE_NOTIFY) { s->shutdown |= SSL_RECEIVED_SHUTDOWN; return 0; } - } else if (alert_level == 2) { /* fatal */ + } else if (alert_level == SSL3_AL_FATAL) { char tmp[16]; s->rwstate = SSL_NOTHING; @@ -888,16 +597,9 @@ start: } if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) { - struct ccs_header_st ccs_hdr; - unsigned int ccs_hdr_len = DTLS1_CCS_HEADER_LENGTH; - - dtls1_get_ccs_header(rr->data, &ccs_hdr); - - /* 'Change Cipher Spec' is just a single byte, so we know - * exactly what the record payload has to look like */ - /* XDTLS: check that epoch is consistent */ - if ((rr->length != ccs_hdr_len) || (rr->off != 0) || - (rr->data[0] != SSL3_MT_CCS)) { + /* '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, dtls1_read_bytes, SSL_R_BAD_CHANGE_CIPHER_SPEC); goto f_err; @@ -930,91 +632,41 @@ start: goto start; } - /* Unexpected handshake message (Client Hello, or protocol violation) */ - if ((s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) && - !s->in_handshake) { - struct hm_header_st msg_hdr; - - /* this may just be a stale retransmit */ - dtls1_get_message_header(rr->data, &msg_hdr); - if (rr->epoch != s->d1->r_epoch) { - rr->length = 0; - goto start; + /* Unexpected handshake message. It may be a retransmitted Finished (the only + * post-CCS message). Otherwise, it's a pre-CCS handshake message from an + * unsupported renegotiation attempt. */ + 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, dtls1_read_bytes, SSL_R_BAD_HANDSHAKE_RECORD); + goto f_err; } + struct hm_header_st msg_hdr; + dtls1_get_message_header(&rr->data[rr->off], &msg_hdr); - /* If we are server, we may have a repeated FINISHED of the client here, - * then retransmit our CCS and FINISHED. */ + /* Ignore a stray Finished from the previous handshake. */ if (msg_hdr.type == SSL3_MT_FINISHED) { - if (dtls1_check_timeout_num(s) < 0) { - return -1; + if (msg_hdr.frag_off == 0) { + /* Retransmit our last flight of messages. If the peer sends the second + * Finished, they may not have received ours. Only do this for the + * first fragment, in case the Finished was fragmented. */ + if (dtls1_check_timeout_num(s) < 0) { + return -1; + } + + dtls1_retransmit_buffered_messages(s); } - dtls1_retransmit_buffered_messages(s); rr->length = 0; goto start; } - - if ((s->state & SSL_ST_MASK) == SSL_ST_OK) { - s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT; - s->renegotiate = 1; - s->new_session = 1; - } - i = s->handshake_func(s); - if (i < 0) { - return i; - } - if (i == 0) { - OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE); - return -1; - } - - goto start; } - switch (rr->type) { - default: - /* TLS just ignores unknown message types */ - if (s->version == TLS1_VERSION) { - rr->length = 0; - goto start; - } - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_UNEXPECTED_RECORD); - goto f_err; - - case SSL3_RT_CHANGE_CIPHER_SPEC: - case SSL3_RT_ALERT: - case SSL3_RT_HANDSHAKE: - /* we already handled all of these, with the possible exception of - * SSL3_RT_HANDSHAKE when s->in_handshake is set, but that should not - * happen when type != rr->type */ - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, ERR_R_INTERNAL_ERROR); - goto f_err; - - case SSL3_RT_APPLICATION_DATA: - /* At this point, we were expecting handshake data, but have application - * data. If the library was running inside ssl3_read() (i.e. - * in_read_app_data is set) and it makes sense to read application data - * at this point (session renegotiation not yet started), we will indulge - * it. */ - if (s->s3->in_read_app_data && (s->s3->total_renegotiations != 0) && - (((s->state & SSL_ST_CONNECT) && - (s->state >= SSL3_ST_CW_CLNT_HELLO_A) && - (s->state <= SSL3_ST_CR_SRVR_HELLO_A)) || - ((s->state & SSL_ST_ACCEPT) && - (s->state <= SSL3_ST_SW_HELLO_REQ_A) && - (s->state >= SSL3_ST_SR_CLNT_HELLO_A)))) { - s->s3->in_read_app_data = 2; - return -1; - } else { - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_UNEXPECTED_RECORD); - goto f_err; - } - } + /* We already handled these. */ + assert(rr->type != SSL3_RT_CHANGE_CIPHER_SPEC && rr->type != SSL3_RT_ALERT); - /* not reached */ + al = SSL_AD_UNEXPECTED_MESSAGE; + OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_UNEXPECTED_RECORD); f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); @@ -1047,35 +699,6 @@ int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len) { return i; } - -/* this only happens when a client hello is received and a handshake is - * started. */ -static int have_handshake_fragment(SSL *s, int type, uint8_t *buf, - int len, int peek) { - if (type == SSL3_RT_HANDSHAKE && s->d1->handshake_fragment_len > 0) { - /* (partially) satisfy request from storage */ - uint8_t *src = s->d1->handshake_fragment; - uint8_t *dst = buf; - unsigned int k, n; - - /* peek == 0 */ - n = 0; - while (len > 0 && s->d1->handshake_fragment_len > 0) { - *dst++ = *src++; - len--; - s->d1->handshake_fragment_len--; - n++; - } - /* move any remaining fragment bytes: */ - for (k = 0; k < s->d1->handshake_fragment_len; k++) { - s->d1->handshake_fragment[k] = *src++; - } - return n; - } - - return 0; -} - /* Call this to write data in records of type 'type' It will return <= 0 if not * all data has been sent or non-blocking IO. */ int dtls1_write_bytes(SSL *s, int type, const void *buf, int len) { @@ -1096,12 +719,9 @@ static int do_dtls1_write(SSL *s, int type, const uint8_t *buf, SSL3_RECORD *wr; SSL3_BUFFER *wb; - /* first check if there is a SSL3_BUFFER still being written - * out. This will happen with non blocking IO */ - if (s->s3->wbuf.left != 0) { - assert(0); /* XDTLS: want to see if we ever get here */ - return ssl3_write_pending(s, type, buf, len); - } + /* ssl3_write_pending drops the write if |BIO_write| fails in DTLS, so there + * is never pending data. */ + assert(s->s3->wbuf.left == 0); /* If we have an alert to send, lets send it */ if (s->s3->alert_dispatch) { @@ -1119,6 +739,9 @@ static int do_dtls1_write(SSL *s, int type, const uint8_t *buf, wr = &(s->s3->wrec); wb = &(s->s3->wbuf); + if (wb->buf == NULL && !ssl3_setup_write_buffer(s)) { + return -1; + } p = wb->buf + prefix_len; /* write the header */ @@ -1147,19 +770,14 @@ static int do_dtls1_write(SSL *s, int type, const uint8_t *buf, eivlen = s->aead_write_ctx->variable_nonce_len; } - /* lets setup the record stuff. */ - wr->data = p + eivlen; /* make room for IV in case of CBC */ - wr->length = (int)len; - wr->input = (unsigned char *)buf; - - /* we now 'read' from wr->input, wr->length bytes into wr->data */ - memcpy(wr->data, wr->input, wr->length); - wr->input = wr->data; - - /* this is true regardless of mac size */ + /* Assemble the input for |s->enc_method->enc|. The input is the plaintext + * with |eivlen| bytes of space prepended for the explicit nonce. */ wr->input = p; + wr->length = eivlen + len; + memcpy(p + eivlen, buf, len); + + /* Encrypt in-place, so the output also goes into |p|. */ wr->data = p; - wr->length += eivlen; if (!s->enc_method->enc(s, 1)) { goto err; @@ -1182,7 +800,9 @@ static int do_dtls1_write(SSL *s, int type, const uint8_t *buf, wr->type = type; /* not needed but helps for debugging */ wr->length += DTLS1_RT_HEADER_LENGTH; - ssl3_record_sequence_update(&(s->s3->write_sequence[0])); + if (!ssl3_record_sequence_update(&s->s3->write_sequence[2], 6)) { + goto err; + } /* now let's set up wb */ wb->left = prefix_len + wr->length; @@ -1285,23 +905,6 @@ int dtls1_dispatch_alert(SSL *s) { return i; } -static DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, - unsigned int *is_next_epoch) { - *is_next_epoch = 0; - - /* In current epoch, accept HM, CCS, DATA, & ALERT */ - if (rr->epoch == s->d1->r_epoch) { - return &s->d1->bitmap; - } else if (rr->epoch == (unsigned long)(s->d1->r_epoch + 1) && - (rr->type == SSL3_RT_HANDSHAKE || rr->type == SSL3_RT_ALERT)) { - /* Only HM and ALERT messages can be from the next epoch */ - *is_next_epoch = 1; - return &s->d1->next_bitmap; - } - - return NULL; -} - void dtls1_reset_seq_numbers(SSL *s, int rw) { uint8_t *seq; unsigned int seq_bytes = sizeof(s->s3->read_sequence); @@ -1309,8 +912,7 @@ void dtls1_reset_seq_numbers(SSL *s, int rw) { if (rw & SSL3_CC_READ) { seq = s->s3->read_sequence; s->d1->r_epoch++; - memcpy(&(s->d1->bitmap), &(s->d1->next_bitmap), sizeof(DTLS1_BITMAP)); - memset(&(s->d1->next_bitmap), 0x00, sizeof(DTLS1_BITMAP)); + memset(&s->d1->bitmap, 0, sizeof(DTLS1_BITMAP)); } else { seq = s->s3->write_sequence; memcpy(s->d1->last_write_sequence, seq, sizeof(s->s3->write_sequence)); diff --git a/src/ssl/d1_srtp.c b/src/ssl/d1_srtp.c index b85ff9b..5928fc8 100644 --- a/src/ssl/d1_srtp.c +++ b/src/ssl/d1_srtp.c @@ -115,12 +115,13 @@ */ #include +#include #include -#include #include +#include -#include "ssl_locl.h" +#include "internal.h" #include @@ -169,7 +170,7 @@ static int find_profile_by_num(unsigned profile_num, } static int ssl_ctx_make_profiles(const char *profiles_string, - STACK_OF(SRTP_PROTECTION_PROFILE) * *out) { + STACK_OF(SRTP_PROTECTION_PROFILE) **out) { STACK_OF(SRTP_PROTECTION_PROFILE) *profiles; const char *col; diff --git a/src/ssl/d1_srvr.c b/src/ssl/d1_srvr.c index 5bce98e..e314910 100644 --- a/src/ssl/d1_srvr.c +++ b/src/ssl/d1_srvr.c @@ -118,21 +118,20 @@ #include #include #include +#include #include #include #include #include #include -#include "ssl_locl.h" +#include "internal.h" -static int dtls1_send_hello_verify_request(SSL *s); - int dtls1_accept(SSL *s) { BUF_MEM *buf = NULL; void (*cb)(const SSL *ssl, int type, int val) = NULL; - unsigned long alg_a; + uint32_t alg_a; int ret = -1; int new_state, state, skip = 0; @@ -180,11 +179,6 @@ int dtls1_accept(SSL *s) { buf = NULL; } - if (!ssl3_setup_buffers(s)) { - ret = -1; - goto end; - } - s->init_num = 0; if (s->state != SSL_ST_RENEGOTIATE) { @@ -200,11 +194,9 @@ int dtls1_accept(SSL *s) { } s->state = SSL3_ST_SR_CLNT_HELLO_A; - s->ctx->stats.sess_accept++; } else { /* s->state == SSL_ST_RENEGOTIATE, * we will just send a * HelloRequest */ - s->ctx->stats.sess_accept_renegotiate++; s->state = SSL3_ST_SW_HELLO_REQ_A; } @@ -244,33 +236,10 @@ int dtls1_accept(SSL *s) { goto end; } dtls1_stop_timer(s); - - if (ret == 1 && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE)) { - s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A; - } else { - s->state = SSL3_ST_SW_SRVR_HELLO_A; - } - + s->state = SSL3_ST_SW_SRVR_HELLO_A; s->init_num = 0; break; - case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A: - case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B: - ret = dtls1_send_hello_verify_request(s); - if (ret <= 0) { - goto end; - } - s->state = SSL3_ST_SW_FLUSH; - s->s3->tmp.next_state = SSL3_ST_SR_CLNT_HELLO_A; - - /* HelloVerifyRequest resets Finished MAC */ - if (!ssl3_init_finished_mac(s)) { - OPENSSL_PUT_ERROR(SSL, dtls1_accept, ERR_R_INTERNAL_ERROR); - ret = -1; - goto end; - } - break; - case SSL3_ST_SW_SRVR_HELLO_A: case SSL3_ST_SW_SRVR_HELLO_B: s->renegotiate = 2; @@ -347,13 +316,6 @@ int dtls1_accept(SSL *s) { * don't request cert during re-negotiation: */ ((s->session->peer != NULL) && (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) || - /* never request cert in anonymous ciphersuites - * (see section "Certificate request" in SSL 3 drafts - * and in RFC 2246): */ - ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) && - /* ... except when the application insists on verification - * (against the specs, but s3_clnt.c accepts this for SSL 3) */ - !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) || /* With normal PSK Certificates and * Certificate Requests are omitted */ (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { @@ -368,12 +330,7 @@ int dtls1_accept(SSL *s) { if (ret <= 0) { goto end; } -#ifndef NETSCAPE_HANG_BUG s->state = SSL3_ST_SW_SRVR_DONE_A; -#else - s->state = SSL3_ST_SW_FLUSH; - s->s3->tmp.next_state = SSL3_ST_SR_CERT_A; -#endif s->init_num = 0; } break; @@ -393,12 +350,6 @@ int dtls1_accept(SSL *s) { case SSL3_ST_SW_FLUSH: s->rwstate = SSL_WRITING; if (BIO_flush(s->wbio) <= 0) { - /* If the write error was fatal, stop trying */ - if (!BIO_should_retry(s->wbio)) { - s->rwstate = SSL_NOTHING; - s->state = s->s3->tmp.next_state; - } - ret = -1; goto end; } @@ -527,8 +478,6 @@ int dtls1_accept(SSL *s) { ssl_update_cache(s, SSL_SESS_CACHE_SERVER); - s->ctx->stats.sess_accept_good++; - if (cb != NULL) { cb(s, SSL_CB_HANDSHAKE_DONE, 1); } @@ -562,44 +511,9 @@ int dtls1_accept(SSL *s) { end: s->in_handshake--; - if (buf != NULL) { - BUF_MEM_free(buf); - } + BUF_MEM_free(buf); if (cb != NULL) { cb(s, SSL_CB_ACCEPT_EXIT, ret); } return ret; } - -int dtls1_send_hello_verify_request(SSL *s) { - uint8_t *msg, *p; - - if (s->state == DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A) { - msg = p = ssl_handshake_start(s); - /* Always use DTLS 1.0 version: see RFC 6347 */ - *(p++) = DTLS1_VERSION >> 8; - *(p++) = DTLS1_VERSION & 0xFF; - - /* Inform the callback how much space is in the - * cookie's buffer. */ - s->d1->cookie_len = sizeof(s->d1->cookie); - - if (s->ctx->app_gen_cookie_cb == NULL || - s->ctx->app_gen_cookie_cb(s, s->d1->cookie, &(s->d1->cookie_len)) == - 0) { - OPENSSL_PUT_ERROR(SSL, dtls1_send_hello_verify_request, - ERR_R_INTERNAL_ERROR); - return 0; - } - - *(p++) = (uint8_t)s->d1->cookie_len; - memcpy(p, s->d1->cookie, s->d1->cookie_len); - p += s->d1->cookie_len; - - ssl_set_handshake_header(s, DTLS1_MT_HELLO_VERIFY_REQUEST, p - msg); - s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B; - } - - /* s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B */ - return ssl_do_write(s); -} diff --git a/src/ssl/internal.h b/src/ssl/internal.h new file mode 100644 index 0000000..3bd749d --- /dev/null +++ b/src/ssl/internal.h @@ -0,0 +1,1134 @@ +/* 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). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +#ifndef OPENSSL_HEADER_SSL_INTERNAL_H +#define OPENSSL_HEADER_SSL_INTERNAL_H + +#include + +#include +#include +#include +#include + +#if defined(OPENSSL_WINDOWS) +/* Windows defines struct timeval in winsock2.h. */ +#pragma warning(push, 3) +#include +#pragma warning(pop) +#else +#include +#endif + + +/* Cipher suites. */ + +/* Bits for |algorithm_mkey| (key exchange algorithm). */ +#define SSL_kRSA 0x00000001L +#define SSL_kDHE 0x00000002L +#define SSL_kECDHE 0x00000004L +/* SSL_kPSK is only set for plain PSK, not ECDHE_PSK. */ +#define SSL_kPSK 0x00000008L + +/* Bits for |algorithm_auth| (server authentication). */ +#define SSL_aRSA 0x00000001L +#define SSL_aECDSA 0x00000002L +/* SSL_aPSK is set for both PSK and ECDHE_PSK. */ +#define SSL_aPSK 0x00000004L + +/* Bits for |algorithm_enc| (symmetric encryption). */ +#define SSL_3DES 0x00000001L +#define SSL_RC4 0x00000002L +#define SSL_AES128 0x00000004L +#define SSL_AES256 0x00000008L +#define SSL_AES128GCM 0x00000010L +#define SSL_AES256GCM 0x00000020L +#define SSL_CHACHA20POLY1305 0x00000040L + +#define SSL_AES (SSL_AES128 | SSL_AES256 | SSL_AES128GCM | SSL_AES256GCM) + +/* Bits for |algorithm_mac| (symmetric authentication). */ +#define SSL_MD5 0x00000001L +#define SSL_SHA1 0x00000002L +#define SSL_SHA256 0x00000004L +#define SSL_SHA384 0x00000008L +/* SSL_AEAD is set for all AEADs. */ +#define SSL_AEAD 0x00000010L + +/* Bits for |algorithm_ssl| (protocol version). These denote the first protocol + * version which introduced the cipher. + * + * TODO(davidben): These are extremely confusing, both in code and in + * cipher rules. Try to remove them. */ +#define SSL_SSLV3 0x00000002L +#define SSL_TLSV1 SSL_SSLV3 +#define SSL_TLSV1_2 0x00000004L + +/* 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 + +#define TLS1_PRF_DGST_MASK (0xff << TLS1_PRF_DGST_SHIFT) + +#define TLS1_PRF_DGST_SHIFT 10 +#define TLS1_PRF_MD5 (SSL_HANDSHAKE_MAC_MD5 << TLS1_PRF_DGST_SHIFT) +#define TLS1_PRF_SHA1 (SSL_HANDSHAKE_MAC_SHA << TLS1_PRF_DGST_SHIFT) +#define TLS1_PRF_SHA256 (SSL_HANDSHAKE_MAC_SHA256 << TLS1_PRF_DGST_SHIFT) +#define TLS1_PRF_SHA384 (SSL_HANDSHAKE_MAC_SHA384 << TLS1_PRF_DGST_SHIFT) +#define TLS1_PRF (TLS1_PRF_MD5 | TLS1_PRF_SHA1) + +/* SSL_CIPHER_ALGORITHM2_AEAD is a flag in SSL_CIPHER.algorithm2 which + * indicates that the cipher is implemented via an EVP_AEAD. */ +#define SSL_CIPHER_ALGORITHM2_AEAD (1 << 23) + +/* 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 +#define SSL_FIPS 0x00000004L + +/* ssl_cipher_get_evp_aead sets |*out_aead| to point to the correct EVP_AEAD + * object for |cipher| protocol version |version|. It sets |*out_mac_secret_len| + * and |*out_fixed_iv_len| to the MAC key length and fixed IV length, + * respectively. The MAC key length is zero except for legacy block and stream + * ciphers. It returns 1 on success and 0 on error. */ +int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead, + size_t *out_mac_secret_len, + size_t *out_fixed_iv_len, + const SSL_CIPHER *cipher, uint16_t version); + +/* 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 + * |ssl_cipher_preference_list_st| containing the result. + * |*out_cipher_list_by_id| is set to a list of selected ciphers sorted by + * id. It returns |(*out_cipher_list)->ciphers| on success and NULL on + * failure. */ +STACK_OF(SSL_CIPHER) * +ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, + struct ssl_cipher_preference_list_st **out_cipher_list, + 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_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. + * Otherwise it returns 0. */ +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, 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); + + +/* Underdocumented functions. + * + * Functions below here haven't been touched up and may be underdocumented. */ + +#define c2l(c, l) \ + (l = ((unsigned long)(*((c)++))), l |= (((unsigned long)(*((c)++))) << 8), \ + l |= (((unsigned long)(*((c)++))) << 16), \ + l |= (((unsigned long)(*((c)++))) << 24)) + +/* NOTE - c is not incremented as per c2l */ +#define c2ln(c, l1, l2, n) \ + { \ + c += n; \ + l1 = l2 = 0; \ + switch (n) { \ + case 8: \ + l2 = ((unsigned long)(*(--(c)))) << 24; \ + case 7: \ + l2 |= ((unsigned long)(*(--(c)))) << 16; \ + case 6: \ + l2 |= ((unsigned long)(*(--(c)))) << 8; \ + case 5: \ + l2 |= ((unsigned long)(*(--(c)))); \ + case 4: \ + l1 = ((unsigned long)(*(--(c)))) << 24; \ + case 3: \ + l1 |= ((unsigned long)(*(--(c)))) << 16; \ + case 2: \ + l1 |= ((unsigned long)(*(--(c)))) << 8; \ + case 1: \ + l1 |= ((unsigned long)(*(--(c)))); \ + } \ + } + +#define l2c(l, c) \ + (*((c)++) = (uint8_t)(((l)) & 0xff), \ + *((c)++) = (uint8_t)(((l) >> 8) & 0xff), \ + *((c)++) = (uint8_t)(((l) >> 16) & 0xff), \ + *((c)++) = (uint8_t)(((l) >> 24) & 0xff)) + +#define n2l(c, l) \ + (l = ((unsigned long)(*((c)++))) << 24, \ + l |= ((unsigned long)(*((c)++))) << 16, \ + l |= ((unsigned long)(*((c)++))) << 8, l |= ((unsigned long)(*((c)++)))) + +#define l2n(l, c) \ + (*((c)++) = (uint8_t)(((l) >> 24) & 0xff), \ + *((c)++) = (uint8_t)(((l) >> 16) & 0xff), \ + *((c)++) = (uint8_t)(((l) >> 8) & 0xff), \ + *((c)++) = (uint8_t)(((l)) & 0xff)) + +#define l2n8(l, c) \ + (*((c)++) = (uint8_t)(((l) >> 56) & 0xff), \ + *((c)++) = (uint8_t)(((l) >> 48) & 0xff), \ + *((c)++) = (uint8_t)(((l) >> 40) & 0xff), \ + *((c)++) = (uint8_t)(((l) >> 32) & 0xff), \ + *((c)++) = (uint8_t)(((l) >> 24) & 0xff), \ + *((c)++) = (uint8_t)(((l) >> 16) & 0xff), \ + *((c)++) = (uint8_t)(((l) >> 8) & 0xff), \ + *((c)++) = (uint8_t)(((l)) & 0xff)) + +/* NOTE - c is not incremented as per l2c */ +#define l2cn(l1, l2, c, n) \ + { \ + c += n; \ + switch (n) { \ + case 8: \ + *(--(c)) = (uint8_t)(((l2) >> 24) & 0xff); \ + case 7: \ + *(--(c)) = (uint8_t)(((l2) >> 16) & 0xff); \ + case 6: \ + *(--(c)) = (uint8_t)(((l2) >> 8) & 0xff); \ + case 5: \ + *(--(c)) = (uint8_t)(((l2)) & 0xff); \ + case 4: \ + *(--(c)) = (uint8_t)(((l1) >> 24) & 0xff); \ + case 3: \ + *(--(c)) = (uint8_t)(((l1) >> 16) & 0xff); \ + case 2: \ + *(--(c)) = (uint8_t)(((l1) >> 8) & 0xff); \ + case 1: \ + *(--(c)) = (uint8_t)(((l1)) & 0xff); \ + } \ + } + +#define n2s(c, s) \ + ((s = (((unsigned int)(c[0])) << 8) | (((unsigned int)(c[1])))), c += 2) + +#define s2n(s, c) \ + ((c[0] = (uint8_t)(((s) >> 8) & 0xff), \ + c[1] = (uint8_t)(((s)) & 0xff)), \ + c += 2) + +#define n2l3(c, l) \ + ((l = (((unsigned long)(c[0])) << 16) | (((unsigned long)(c[1])) << 8) | \ + (((unsigned long)(c[2])))), \ + c += 3) + +#define l2n3(l, c) \ + ((c[0] = (uint8_t)(((l) >> 16) & 0xff), \ + c[1] = (uint8_t)(((l) >> 8) & 0xff), \ + c[2] = (uint8_t)(((l)) & 0xff)), \ + c += 3) + +/* LOCAL STUFF */ + +#define TLSEXT_CHANNEL_ID_SIZE 128 + +/* Check if an SSL structure is using DTLS */ +#define SSL_IS_DTLS(s) (s->method->is_dtls) +/* See if we need explicit IV */ +#define SSL_USE_EXPLICIT_IV(s) \ + (s->enc_method->enc_flags & SSL_ENC_FLAG_EXPLICIT_IV) +/* See if we use signature algorithms extension and signature algorithm before + * signatures. */ +#define SSL_USE_SIGALGS(s) (s->enc_method->enc_flags & SSL_ENC_FLAG_SIGALGS) +/* Allow TLS 1.2 ciphersuites: applies to DTLS 1.2 as well as TLS 1.2: may + * apply to others in future. */ +#define SSL_USE_TLS1_2_CIPHERS(s) \ + (s->enc_method->enc_flags & SSL_ENC_FLAG_TLS1_2_CIPHERS) +/* Determine if a client can use TLS 1.2 ciphersuites: can't rely on method + * flags because it may not be set to correct version yet. */ +#define SSL_CLIENT_USE_TLS1_2_CIPHERS(s) \ + ((SSL_IS_DTLS(s) && s->client_version <= DTLS1_2_VERSION) || \ + (!SSL_IS_DTLS(s) && s->client_version >= TLS1_2_VERSION)) + +/* SSL_kRSA <- RSA_ENC | (RSA_TMP & RSA_SIGN) | + * <- (EXPORT & (RSA_ENC | RSA_TMP) & RSA_SIGN) + * SSL_kDH <- DH_ENC & (RSA_ENC | RSA_SIGN | DSA_SIGN) + * SSL_kDHE <- RSA_ENC | RSA_SIGN | DSA_SIGN + * 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 +#define NAMED_CURVE_TYPE 3 + +enum ssl_hash_message_t { + ssl_dont_hash_message, + ssl_hash_message, +}; + +typedef struct cert_pkey_st { + X509 *x509; + EVP_PKEY *privatekey; + /* Chain for this certificate */ + STACK_OF(X509) *chain; +} CERT_PKEY; + +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. + * + * TODO(davidben): Remove these. They get checked twice: when sending the + * ClientHello and when processing the ServerHello. However, mask_ssl is a + * different value both times. mask_k and mask_a are not, but is a + * round-about way of checking the server's cipher was one of the advertised + * ones. (Currently it checks the masks and then the list of ciphers prior to + * applying the masks in ClientHello.) */ + uint32_t mask_k; + uint32_t mask_a; + uint32_t mask_ssl; + + DH *dh_tmp; + DH *(*dh_tmp_cb)(SSL *ssl, int is_export, int keysize); + + /* ecdh_nid, if not |NID_undef|, is the NID of the curve to use for ephemeral + * ECDH keys. If unset, |ecdh_tmp_cb| is consulted. */ + int ecdh_nid; + /* ecdh_tmp_cb is a callback for selecting the curve to use for ephemeral ECDH + * 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); + 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; + /* 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 + * can then examine any appropriate parameters and setup any + * certificates required. This allows advanced applications + * to select certificates on the fly: for example based on + * 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 { + STACK_OF(X509) *cert_chain; /* as received from peer (not for SSL2) */ + + /* The 'peer_...' members are used only by clients. */ + int peer_cert_type; + + CERT_PKEY *peer_key; /* points to an element of peer_pkeys (never NULL!) */ + CERT_PKEY peer_pkeys[SSL_PKEY_NUM]; + /* Obviously we don't have the private keys of these, + * so maybe we shouldn't even use the CERT_PKEY type here. */ + + 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 { + /* version, if non-zero, is the only protocol version acceptable to an + * SSL_CTX initialized from this method. */ + uint16_t version; + /* method is the underlying SSL_PROTOCOL_METHOD that initializes the + * SSL_CTX. */ + const SSL_PROTOCOL_METHOD *method; +}; + +/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ +struct ssl_protocol_method_st { + /* is_dtls is one if the protocol is DTLS and zero otherwise. */ + char is_dtls; + int (*ssl_new)(SSL *s); + void (*ssl_free)(SSL *s); + int (*ssl_accept)(SSL *s); + int (*ssl_connect)(SSL *s); + int (*ssl_read)(SSL *s, void *buf, int len); + int (*ssl_peek)(SSL *s, void *buf, int len); + int (*ssl_write)(SSL *s, const void *buf, int len); + int (*ssl_shutdown)(SSL *s); + int (*ssl_renegotiate)(SSL *s); + int (*ssl_renegotiate_check)(SSL *s); + long (*ssl_get_message)(SSL *s, int header_state, int body_state, + int msg_type, long max, + enum ssl_hash_message_t hash_message, int *ok); + int (*ssl_read_bytes)(SSL *s, int type, uint8_t *buf, int len, int peek); + int (*ssl_write_bytes)(SSL *s, int type, 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); + int (*ssl_pending)(const SSL *s); + size_t (*num_ciphers)(void); + const SSL_CIPHER *(*get_cipher)(size_t i); + /* Handshake header length */ + unsigned int hhlen; + /* Set the handshake header */ + int (*set_handshake_header)(SSL *s, int type, unsigned long len); + /* Write out handshake message */ + int (*do_write)(SSL *s); +}; + +/* This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff It is a bit + * of a mess of functions, but hell, think of it as an opaque structure. */ +struct ssl3_enc_method { + int (*enc)(SSL *, int); + int (*prf)(SSL *, uint8_t *, size_t, const uint8_t *, size_t, const char *, + size_t, const uint8_t *, size_t, const uint8_t *, size_t); + int (*setup_key_block)(SSL *); + int (*generate_master_secret)(SSL *, uint8_t *, const uint8_t *, size_t); + int (*change_cipher_state)(SSL *, int); + int (*final_finish_mac)(SSL *, const char *, int, uint8_t *); + int (*cert_verify_mac)(SSL *, int, uint8_t *); + const char *client_finished_label; + int client_finished_label_len; + const char *server_finished_label; + int server_finished_label_len; + int (*alert_value)(int); + int (*export_keying_material)(SSL *, uint8_t *, size_t, const char *, size_t, + const uint8_t *, size_t, int use_context); + /* Various flags indicating protocol version requirements */ + unsigned int enc_flags; +}; + +#define SSL_HM_HEADER_LENGTH(s) s->method->hhlen +#define ssl_handshake_start(s) \ + (((uint8_t *)s->init_buf->data) + s->method->hhlen) +#define ssl_set_handshake_header(s, htype, len) \ + s->method->set_handshake_header(s, htype, len) +#define ssl_do_write(s) s->method->do_write(s) + +/* Values for enc_flags */ + +/* Uses explicit IV for CBC mode */ +#define SSL_ENC_FLAG_EXPLICIT_IV 0x1 +/* Uses signature algorithms extension */ +#define SSL_ENC_FLAG_SIGALGS 0x2 +/* Uses SHA256 default PRF */ +#define SSL_ENC_FLAG_SHA256_PRF 0x4 +/* Allow TLS 1.2 ciphersuites: applies to DTLS 1.2 as well as TLS 1.2: + * may apply to others in future. */ +#define SSL_ENC_FLAG_TLS1_2_CIPHERS 0x8 + +/* ssl_aead_ctx_st contains information about an AEAD that is being used to + * encrypt an SSL connection. */ +struct ssl_aead_ctx_st { + EVP_AEAD_CTX ctx; + /* fixed_nonce contains any bytes of the nonce that are fixed for all + * records. */ + uint8_t fixed_nonce[8]; + uint8_t fixed_nonce_len, variable_nonce_len, tag_len; + /* variable_nonce_included_in_record is non-zero if the variable nonce + * for a record is included as a prefix before the ciphertext. */ + char variable_nonce_included_in_record; + /* random_variable_nonce is non-zero if the variable nonce is + * randomly generated, rather than derived from the sequence + * number. */ + char random_variable_nonce; + /* omit_length_in_ad is non-zero if the length should be omitted in the + * AEAD's ad parameter. */ + char omit_length_in_ad; + /* omit_version_in_ad is non-zero if the version should be omitted + * in the AEAD's ad parameter. */ + char omit_version_in_ad; +}; + +/* lengths of messages */ +#define DTLS1_COOKIE_LENGTH 256 + +#define DTLS1_RT_HEADER_LENGTH 13 + +#define DTLS1_HM_HEADER_LENGTH 12 + +#define DTLS1_CCS_HEADER_LENGTH 1 + +#define DTLS1_AL_HEADER_LENGTH 2 + +typedef struct dtls1_bitmap_st { + /* map is a bit mask of the last 64 sequence numbers. Bit + * |1< +#include #include #include @@ -104,6 +105,8 @@ void pqueue_free(pqueue_s *pq) { return; } + /* The queue must be empty. */ + assert(pq->items == NULL); OPENSSL_free(pq); } diff --git a/src/ssl/pqueue/pqueue_test.c b/src/ssl/pqueue/pqueue_test.c index c4b4b9d..cb688f7 100644 --- a/src/ssl/pqueue/pqueue_test.c +++ b/src/ssl/pqueue/pqueue_test.c @@ -19,6 +19,17 @@ #include +static void clear_and_free_queue(pqueue q) { + for (;;) { + pitem *item = pqueue_pop(q); + if (item == NULL) { + break; + } + pitem_free(item); + } + pqueue_free(q); +} + static int trivial(void) { pqueue q = pqueue_new(); if (q == NULL) { @@ -37,7 +48,7 @@ static int trivial(void) { return 0; } pitem_free(item); - pqueue_free(q); + clear_and_free_queue(q); return 1; } @@ -101,7 +112,7 @@ static int fixed_random(void) { } curr = next; } - pqueue_free(q); + clear_and_free_queue(q); return 1; } diff --git a/src/ssl/s3_both.c b/src/ssl/s3_both.c index a34d221..b78f6d3 100644 --- a/src/ssl/s3_both.c +++ b/src/ssl/s3_both.c @@ -116,6 +116,7 @@ #include #include +#include #include #include #include @@ -124,7 +125,7 @@ #include #include -#include "ssl_locl.h" +#include "internal.h" /* ssl3_do_write sends |s->init_buf| in records of type 'type' @@ -173,8 +174,7 @@ int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen) { return 0; } - /* Copy the finished so we can use it for - * renegotiation checks */ + /* Copy the finished so we can use it for renegotiation checks */ if (s->server) { assert(n <= EVP_MAX_MD_SIZE); memcpy(s->s3->previous_server_finished, s->s3->tmp.finish_md, n); @@ -185,7 +185,9 @@ int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen) { s->s3->previous_client_finished_len = n; } - ssl_set_handshake_header(s, SSL3_MT_FINISHED, n); + if (!ssl_set_handshake_header(s, SSL3_MT_FINISHED, n)) { + return 0; + } s->state = b; } @@ -224,7 +226,7 @@ int ssl3_get_finished(SSL *s, int a, int b) { message_len = s->method->ssl_get_message(s, a, b, SSL3_MT_FINISHED, EVP_MAX_MD_SIZE, - SSL_GET_MESSAGE_DONT_HASH_MESSAGE, &ok); + ssl_dont_hash_message, &ok); if (!ok) { return message_len; @@ -232,7 +234,9 @@ int ssl3_get_finished(SSL *s, int a, int b) { /* Snapshot the finished hash before incorporating the new message. */ ssl3_take_mac(s); - ssl3_hash_current_message(s); + if (!ssl3_hash_current_message(s)) { + goto err; + } /* If this occurs, we have missed a message. * TODO(davidben): Is this check now redundant with SSL3_FLAGS_EXPECT_CCS? */ @@ -273,6 +277,7 @@ int ssl3_get_finished(SSL *s, int a, int b) { f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); +err: return 0; } @@ -296,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); } -unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk) { +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, cpk, &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; } @@ -308,25 +319,24 @@ unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk) { p = ssl_handshake_start(s); l2n3(l, p); l += 3; - ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE, l); - return l + SSL_HM_HEADER_LENGTH(s); + return ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE, l); } /* Obtain handshake message of message type |msg_type| (any if |msg_type| == -1), * maximum acceptable body length |max|. The first four bytes (msg_type and * length) are read in state |header_state|, the body is read in state |body_state|. */ long ssl3_get_message(SSL *s, int header_state, int body_state, int msg_type, - long max, int hash_message, int *ok) { + long max, enum ssl_hash_message_t hash_message, int *ok) { uint8_t *p; unsigned long l; long n; int al; if (s->s3->tmp.reuse_message) { - /* A SSL_GET_MESSAGE_DONT_HASH_MESSAGE call cannot be combined with - * reuse_message; the SSL_GET_MESSAGE_DONT_HASH_MESSAGE would have to have - * been applied to the previous call. */ - assert(hash_message != SSL_GET_MESSAGE_DONT_HASH_MESSAGE); + /* A ssl_dont_hash_message call cannot be combined with reuse_message; the + * ssl_dont_hash_message would have to have been applied to the previous + * call. */ + assert(hash_message == ssl_hash_message); s->s3->tmp.reuse_message = 0; if (msg_type >= 0 && s->s3->tmp.message_type != msg_type) { al = SSL_AD_UNEXPECTED_MESSAGE; @@ -350,7 +360,6 @@ long ssl3_get_message(SSL *s, int header_state, int body_state, int msg_type, int bytes_read = s->method->ssl_read_bytes( s, SSL3_RT_HANDSHAKE, &p[s->init_num], 4 - s->init_num, 0); if (bytes_read <= 0) { - s->rwstate = SSL_READING; *ok = 0; return bytes_read; } @@ -416,8 +425,8 @@ long ssl3_get_message(SSL *s, int header_state, int body_state, int msg_type, } /* Feed this message into MAC computation. */ - if (hash_message != SSL_GET_MESSAGE_DONT_HASH_MESSAGE) { - ssl3_hash_current_message(s); + if (hash_message == ssl_hash_message && !ssl3_hash_current_message(s)) { + goto err; } if (s->msg_callback) { s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data, @@ -434,11 +443,12 @@ err: return -1; } -void ssl3_hash_current_message(SSL *s) { +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; - ssl3_finish_mac(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 @@ -586,8 +596,7 @@ int ssl3_setup_read_buffer(SSL *s) { #endif if (s->s3->rbuf.buf == NULL) { - len = SSL3_RT_MAX_PLAIN_LENGTH + SSL3_RT_MAX_ENCRYPTED_OVERHEAD + - headerlen + align; + 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; @@ -645,28 +654,16 @@ err: return 0; } - -int ssl3_setup_buffers(SSL *s) { - if (!ssl3_setup_read_buffer(s) || - !ssl3_setup_write_buffer(s)) { - return 0; - } - return 1; -} - int ssl3_release_write_buffer(SSL *s) { - if (s->s3->wbuf.buf != NULL) { - OPENSSL_free(s->s3->wbuf.buf); - s->s3->wbuf.buf = NULL; - } + OPENSSL_free(s->s3->wbuf.buf); + s->s3->wbuf.buf = NULL; return 1; } int ssl3_release_read_buffer(SSL *s) { - if (s->s3->rbuf.buf != NULL) { - OPENSSL_free(s->s3->rbuf.buf); - s->s3->rbuf.buf = NULL; - } + OPENSSL_free(s->s3->rbuf.buf); + s->s3->rbuf.buf = NULL; + s->packet = NULL; return 1; } diff --git a/src/ssl/s3_clnt.c b/src/ssl/s3_clnt.c index 231cc65..d01acae 100644 --- a/src/ssl/s3_clnt.c +++ b/src/ssl/s3_clnt.c @@ -150,20 +150,21 @@ #include #include +#include #include #include #include #include +#include #include #include #include #include #include -#include #include -#include "ssl_locl.h" +#include "internal.h" #include "../crypto/dh/internal.h" @@ -195,12 +196,21 @@ int ssl3_connect(SSL *s) { case SSL_ST_RENEGOTIATE: s->renegotiate = 1; s->state = SSL_ST_CONNECT; - s->ctx->stats.sess_connect_renegotiate++; /* fallthrough */ case SSL_ST_CONNECT: case SSL_ST_BEFORE | SSL_ST_CONNECT: - if (cb != NULL) + if (cb != NULL) { cb(s, SSL_CB_HANDSHAKE_START, 1); + } + + if ((s->version >> 8) != 3) { + /* TODO(davidben): Some consumers clear |s->version| to break the + * handshake in a callback. Remove this when they're using proper + * APIs. */ + OPENSSL_PUT_ERROR(SSL, ssl3_connect, ERR_R_INTERNAL_ERROR); + ret = -1; + goto end; + } if (s->init_buf == NULL) { buf = BUF_MEM_new(); @@ -214,8 +224,7 @@ int ssl3_connect(SSL *s) { buf = NULL; } - if (!ssl3_setup_buffers(s) || - !ssl_init_wbio_buffer(s, 0)) { + if (!ssl_init_wbio_buffer(s, 0)) { ret = -1; goto end; } @@ -229,7 +238,6 @@ int ssl3_connect(SSL *s) { } s->state = SSL3_ST_CW_CLNT_HELLO_A; - s->ctx->stats.sess_connect++; s->init_num = 0; break; @@ -389,12 +397,8 @@ int ssl3_connect(SSL *s) { s->init_num = 0; s->session->cipher = s->s3->tmp.new_cipher; - if (!s->enc_method->setup_key_block(s)) { - ret = -1; - goto end; - } - - if (!s->enc_method->change_cipher_state( + if (!s->enc_method->setup_key_block(s) || + !s->enc_method->change_cipher_state( s, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) { ret = -1; goto end; @@ -445,15 +449,16 @@ int ssl3_connect(SSL *s) { * hashes. */ if (s->s3->tlsext_channel_id_new) { ret = tls1_record_handshake_hashes_for_channel_id(s); - if (ret <= 0) + if (ret <= 0) { goto end; + } } - if ((SSL_get_mode(s) & SSL_MODE_HANDSHAKE_CUTTHROUGH) && - ssl3_can_cutthrough(s) && - /* no cutthrough on renegotiation (would complicate the state - * machine) */ + if ((SSL_get_mode(s) & SSL_MODE_ENABLE_FALSE_START) && + ssl3_can_false_start(s) && + /* No False Start on renegotiation (would complicate the state + * machine). */ s->s3->previous_server_finished_len == 0) { - s->s3->tmp.next_state = SSL3_ST_CUTTHROUGH_COMPLETE; + s->s3->tmp.next_state = SSL3_ST_FALSE_START; } else { /* Allow NewSessionTicket if ticket expected */ if (s->tlsext_ticket_expected) { @@ -522,13 +527,14 @@ int ssl3_connect(SSL *s) { s->state = s->s3->tmp.next_state; break; - case SSL3_ST_CUTTHROUGH_COMPLETE: + case SSL3_ST_FALSE_START: /* Allow NewSessionTicket if ticket expected */ if (s->tlsext_ticket_expected) { s->state = SSL3_ST_CR_SESSION_TICKET_A; } else { s->state = SSL3_ST_CR_CHANGE; } + s->s3->tmp.in_false_start = 1; ssl_free_wbio_buffer(s); ret = 1; @@ -538,10 +544,8 @@ int ssl3_connect(SSL *s) { /* clean a few things up */ ssl3_cleanup_key_block(s); - if (s->init_buf != NULL) { - BUF_MEM_free(s->init_buf); - s->init_buf = NULL; - } + BUF_MEM_free(s->init_buf); + s->init_buf = NULL; /* Remove write buffering now. */ ssl_free_wbio_buffer(s); @@ -549,15 +553,12 @@ int ssl3_connect(SSL *s) { s->init_num = 0; s->renegotiate = 0; s->new_session = 0; + s->s3->tmp.in_false_start = 0; ssl_update_cache(s, SSL_SESS_CACHE_CLIENT); - if (s->hit) { - s->ctx->stats.sess_hit++; - } ret = 1; /* s->server=0; */ - s->ctx->stats.sess_connect_good++; if (cb != NULL) { cb(s, SSL_CB_HANDSHAKE_DONE, 1); @@ -584,9 +585,7 @@ int ssl3_connect(SSL *s) { end: s->in_handshake--; - if (buf != NULL) { - BUF_MEM_free(buf); - } + BUF_MEM_free(buf); if (cb != NULL) { cb(s, SSL_CB_CONNECT_EXIT, ret); } @@ -625,8 +624,9 @@ int ssl3_send_client_hello(SSL *s) { /* If resending the ClientHello in DTLS after a HelloVerifyRequest, don't * renegerate the client_random. The random must be reused. */ - if (!SSL_IS_DTLS(s) || !s->d1->send_cookie) { - ssl_fill_hello_random(s, 0, p, sizeof(s->s3->client_random)); + if ((!SSL_IS_DTLS(s) || !s->d1->send_cookie) && + !ssl_fill_hello_random(s, 0, p, sizeof(s->s3->client_random))) { + goto err; } /* Do the message type and length last. Note: the final argument to @@ -720,7 +720,9 @@ int ssl3_send_client_hello(SSL *s) { } l = p - d; - ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l); + if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l)) { + goto err; + } s->state = SSL3_ST_CW_CLNT_HELLO_B; } @@ -732,7 +734,7 @@ err: } int ssl3_get_server_hello(SSL *s) { - STACK_OF(SSL_CIPHER) * sk; + STACK_OF(SSL_CIPHER) *sk; const SSL_CIPHER *c; CERT *ct = s->cert; int al = SSL_AD_INTERNAL_ERROR, ok; @@ -740,12 +742,12 @@ int ssl3_get_server_hello(SSL *s) { CBS server_hello, server_random, session_id; uint16_t server_version, cipher_suite; uint8_t compression_method; - unsigned long mask_ssl; + uint32_t mask_ssl; n = s->method->ssl_get_message(s, SSL3_ST_CR_SRVR_HELLO_A, SSL3_ST_CR_SRVR_HELLO_B, SSL3_MT_SERVER_HELLO, 20000, /* ?? */ - SSL_GET_MESSAGE_HASH_MESSAGE, &ok); + ssl_hash_message, &ok); if (!ok) { uint32_t err = ERR_peek_error(); @@ -858,24 +860,22 @@ int ssl3_get_server_hello(SSL *s) { goto f_err; } - if (s->hit && s->session->cipher != c) { - al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, - SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED); - goto f_err; + if (s->hit) { + if (s->session->cipher != c) { + al = SSL_AD_ILLEGAL_PARAMETER; + 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, ssl3_get_server_hello, + SSL_R_OLD_SESSION_VERSION_NOT_RETURNED); + goto f_err; + } } s->s3->tmp.new_cipher = c; - /* Most clients also require that the negotiated version match the session's - * version if resuming. However OpenSSL has historically not had the - * corresponding logic on the server, so this may not be compatible, - * depending on other factors. (Whether the ClientHello version is clamped to - * the session's version and whether the session cache is keyed on IP - * address.) - * - * TODO(davidben): See if we can still enforce this? Perhaps for the future - * TLS 1.3 and forward if this is fixed upstream. */ - /* Don't digest cached records if no sigalgs: we may need them for client * authentication. */ if (!SSL_USE_SIGALGS(s) && @@ -924,8 +924,8 @@ int ssl3_get_server_certificate(SSL *s) { const uint8_t *data; n = s->method->ssl_get_message(s, SSL3_ST_CR_CERT_A, SSL3_ST_CR_CERT_B, - SSL3_MT_CERTIFICATE, s->max_cert_list, - SSL_GET_MESSAGE_HASH_MESSAGE, &ok); + SSL3_MT_CERTIFICATE, (long)s->max_cert_list, + ssl_hash_message, &ok); if (!ok) { return n; @@ -988,9 +988,7 @@ int ssl3_get_server_certificate(SSL *s) { goto err; } - if (s->session->sess_cert) { - ssl_sess_cert_free(s->session->sess_cert); - } + ssl_sess_cert_free(s->session->sess_cert); s->session->sess_cert = sc; sc->cert_chain = sk; @@ -1028,17 +1026,11 @@ int ssl3_get_server_certificate(SSL *s) { goto f_err; } sc->peer_cert_type = i; - /* Why would the following ever happen? We just created sc a couple of lines - * ago. */ - if (sc->peer_pkeys[i].x509 != NULL) { - X509_free(sc->peer_pkeys[i].x509); - } + X509_free(sc->peer_pkeys[i].x509); sc->peer_pkeys[i].x509 = X509_up_ref(x); sc->peer_key = &(sc->peer_pkeys[i]); - if (s->session->peer != NULL) { - X509_free(s->session->peer); - } + X509_free(s->session->peer); s->session->peer = X509_up_ref(x); s->session->verify_result = s->verify_result; @@ -1075,7 +1067,7 @@ int ssl3_get_server_key_exchange(SSL *s) { * ServerKeyExchange message may be skipped */ n = s->method->ssl_get_message(s, SSL3_ST_CR_KEY_EXCH_A, SSL3_ST_CR_KEY_EXCH_B, -1, s->max_cert_list, - SSL_GET_MESSAGE_HASH_MESSAGE, &ok); + ssl_hash_message, &ok); if (!ok) { return n; } @@ -1096,14 +1088,15 @@ int ssl3_get_server_key_exchange(SSL *s) { * 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. */ - if (s->s3->tmp.peer_psk_identity_hint) { - OPENSSL_free(s->s3->tmp.peer_psk_identity_hint); - s->s3->tmp.peer_psk_identity_hint = NULL; - } + OPENSSL_free(s->s3->tmp.peer_psk_identity_hint); + s->s3->tmp.peer_psk_identity_hint = NULL; } s->s3->tmp.reuse_message = 1; return 1; @@ -1114,16 +1107,15 @@ int ssl3_get_server_key_exchange(SSL *s) { server_key_exchange_orig = server_key_exchange; if (s->session->sess_cert != NULL) { - if (s->session->sess_cert->peer_dh_tmp) { - DH_free(s->session->sess_cert->peer_dh_tmp); - s->session->sess_cert->peer_dh_tmp = NULL; - } - if (s->session->sess_cert->peer_ecdh_tmp) { - EC_KEY_free(s->session->sess_cert->peer_ecdh_tmp); - s->session->sess_cert->peer_ecdh_tmp = 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; @@ -1165,7 +1157,7 @@ int ssl3_get_server_key_exchange(SSL *s) { } } - if (alg_k & SSL_kEDH) { + if (alg_k & SSL_kDHE) { CBS dh_p, dh_g, dh_Ys; if (!CBS_get_u16_length_prefixed(&server_key_exchange, &dh_p) || @@ -1207,10 +1199,9 @@ int ssl3_get_server_key_exchange(SSL *s) { s->session->sess_cert->peer_dh_tmp = dh; dh = NULL; - } else if (alg_k & SSL_kEECDH) { + } else if (alg_k & SSL_kECDHE) { uint16_t curve_id; int curve_nid = 0; - EC_GROUP *ngroup; const EC_GROUP *group; CBS point; @@ -1231,20 +1222,12 @@ int ssl3_get_server_key_exchange(SSL *s) { goto f_err; } - ecdh = EC_KEY_new(); + ecdh = EC_KEY_new_by_curve_name(curve_nid); if (ecdh == NULL) { OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, - ERR_R_MALLOC_FAILURE); - goto err; - } - - ngroup = EC_GROUP_new_by_curve_name(curve_nid); - if (ngroup == NULL || - EC_KEY_set_group(ecdh, ngroup) == 0) { - OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, ERR_R_EC_LIB); + ERR_R_EC_LIB); goto err; } - EC_GROUP_free(ngroup); group = EC_KEY_get0_group(ecdh); @@ -1362,17 +1345,11 @@ f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); err: EVP_PKEY_free(pkey); - if (rsa != NULL) { - RSA_free(rsa); - } - if (dh != NULL) { - DH_free(dh); - } + RSA_free(rsa); + DH_free(dh); BN_CTX_free(bn_ctx); EC_POINT_free(srvr_ecpoint); - if (ecdh != NULL) { - EC_KEY_free(ecdh); - } + EC_KEY_free(ecdh); EVP_MD_CTX_cleanup(&md_ctx); return -1; } @@ -1393,7 +1370,7 @@ int ssl3_get_certificate_request(SSL *s) { n = s->method->ssl_get_message(s, SSL3_ST_CR_CERT_REQ_A, SSL3_ST_CR_CERT_REQ_B, -1, s->max_cert_list, - SSL_GET_MESSAGE_HASH_MESSAGE, &ok); + ssl_hash_message, &ok); if (!ok) { return n; @@ -1419,15 +1396,6 @@ int ssl3_get_certificate_request(SSL *s) { goto err; } - /* TLS does not like anon-DH with client cert */ - if (s->version > SSL3_VERSION && - (s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)) { - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); - OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, - SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER); - goto err; - } - CBS_init(&cbs, s->init_msg, n); ca_sk = sk_X509_NAME_new(ca_dn_cmp); @@ -1493,7 +1461,7 @@ int ssl3_get_certificate_request(SSL *s) { 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, ssl3_get_server_certificate, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, ERR_R_INTERNAL_ERROR); goto err; } @@ -1513,29 +1481,25 @@ int ssl3_get_certificate_request(SSL *s) { /* we should setup a certificate to return.... */ s->s3->tmp.cert_req = 1; - if (s->s3->tmp.ca_names != NULL) { - sk_X509_NAME_pop_free(s->s3->tmp.ca_names, X509_NAME_free); - } + sk_X509_NAME_pop_free(s->s3->tmp.ca_names, X509_NAME_free); s->s3->tmp.ca_names = ca_sk; ca_sk = NULL; ret = 1; err: - if (ca_sk != NULL) { - sk_X509_NAME_pop_free(ca_sk, X509_NAME_free); - } + sk_X509_NAME_pop_free(ca_sk, X509_NAME_free); return ret; } int ssl3_get_new_session_ticket(SSL *s) { - int ok, al, ret = 0; + int ok, al; long n; CBS new_session_ticket, ticket; n = s->method->ssl_get_message( s, SSL3_ST_CR_SESSION_TICKET_A, SSL3_ST_CR_SESSION_TICKET_B, - SSL3_MT_NEWSESSION_TICKET, 16384, SSL_GET_MESSAGE_HASH_MESSAGE, &ok); + SSL3_MT_NEWSESSION_TICKET, 16384, ssl_hash_message, &ok); if (!ok) { return n; @@ -1558,21 +1522,15 @@ int ssl3_get_new_session_ticket(SSL *s) { goto err; } - /* There are two ways to detect a resumed ticket sesion. One is to set an - * appropriate session ID and then the server must return a match in - * ServerHello. This allows the normal client session ID matching to work and - * we know much earlier that the ticket has been accepted. - * - * The other way is to set zero length session ID when the ticket is - * presented and rely on the handshake to determine session resumption. - * - * We choose the former approach because this fits in with assumptions - * elsewhere in OpenSSL. The session ID is set to the SHA256 (or SHA1 is - * SHA256 is disabled) hash of the ticket. */ - EVP_Digest(CBS_data(&ticket), CBS_len(&ticket), s->session->session_id, - &s->session->session_id_length, EVP_sha256(), NULL); - ret = 1; - return ret; + /* Generate a session ID for this session based on the session ticket. We use + * the session ID mechanism for detecting ticket resumption. This also fits in + * with assumptions elsewhere in OpenSSL.*/ + if (!EVP_Digest(CBS_data(&ticket), CBS_len(&ticket), s->session->session_id, + &s->session->session_id_length, EVP_sha256(), NULL)) { + goto err; + } + + return 1; f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); @@ -1588,12 +1546,19 @@ int ssl3_get_cert_status(SSL *s) { n = s->method->ssl_get_message( s, SSL3_ST_CR_CERT_STATUS_A, SSL3_ST_CR_CERT_STATUS_B, - SSL3_MT_CERTIFICATE_STATUS, 16384, SSL_GET_MESSAGE_HASH_MESSAGE, &ok); + -1, 16384, ssl_hash_message, &ok); if (!ok) { return n; } + if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE_STATUS) { + /* A server may send status_request in ServerHello and then change + * its mind about sending CertificateStatus. */ + s->s3->tmp.reuse_message = 1; + return 1; + } + CBS_init(&certificate_status, s->init_msg, n); if (!CBS_get_u8(&certificate_status, &status_type) || status_type != TLSEXT_STATUSTYPE_ocsp || @@ -1625,7 +1590,7 @@ int ssl3_get_server_done(SSL *s) { n = s->method->ssl_get_message(s, SSL3_ST_CR_SRVR_DONE_A, SSL3_ST_CR_SRVR_DONE_B, SSL3_MT_SERVER_DONE, 30, /* should be very small, like 0 :-) */ - SSL_GET_MESSAGE_HASH_MESSAGE, &ok); + ssl_hash_message, &ok); if (!ok) { return n; @@ -1645,8 +1610,8 @@ int ssl3_get_server_done(SSL *s) { int ssl3_send_client_key_exchange(SSL *s) { uint8_t *p; int n = 0; - unsigned long alg_k; - unsigned long alg_a; + uint32_t alg_k; + uint32_t alg_a; uint8_t *q; EVP_PKEY *pkey = NULL; EC_KEY *clnt_ecdh = NULL; @@ -1699,10 +1664,7 @@ int ssl3_send_client_key_exchange(SSL *s) { goto err; } - if (s->session->psk_identity != NULL) { - OPENSSL_free(s->session->psk_identity); - } - + OPENSSL_free(s->session->psk_identity); s->session->psk_identity = BUF_strdup(identity); if (s->session->psk_identity == NULL) { OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, @@ -1744,9 +1706,7 @@ int ssl3_send_client_key_exchange(SSL *s) { pkey->pkey.rsa == NULL) { OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR); - if (pkey != NULL) { - EVP_PKEY_free(pkey); - } + EVP_PKEY_free(pkey); goto err; } @@ -1785,7 +1745,7 @@ int ssl3_send_client_key_exchange(SSL *s) { if (s->version > SSL3_VERSION) { s2n(enc_pms_len, q); } - } else if (alg_k & SSL_kEDH) { + } else if (alg_k & SSL_kDHE) { DH *dh_srvr, *dh_clnt; SESS_CERT *scert = s->session->sess_cert; int dh_len; @@ -1841,7 +1801,7 @@ int ssl3_send_client_key_exchange(SSL *s) { n += 2 + pub_len; DH_free(dh_clnt); - } else if (alg_k & SSL_kEECDH) { + } else if (alg_k & SSL_kECDHE) { const EC_GROUP *srvr_group = NULL; EC_KEY *tkey; int field_size = 0, ecdh_len; @@ -1993,7 +1953,9 @@ int ssl3_send_client_key_exchange(SSL *s) { /* The message must be added to the finished hash before calculating the * master secret. */ - ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, n); + if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, n)) { + goto err; + } s->state = SSL3_ST_CW_KEY_EXCH_B; s->session->master_key_length = s->enc_method->generate_master_secret( @@ -2007,16 +1969,12 @@ int ssl3_send_client_key_exchange(SSL *s) { } /* SSL3_ST_CW_KEY_EXCH_B */ - return s->enc_method->do_write(s); + return s->method->do_write(s); err: BN_CTX_free(bn_ctx); - if (encodedPoint != NULL) { - OPENSSL_free(encodedPoint); - } - if (clnt_ecdh != NULL) { - EC_KEY_free(clnt_ecdh); - } + OPENSSL_free(encodedPoint); + EC_KEY_free(clnt_ecdh); EVP_PKEY_free(srvr_pub_pkey); if (pms) { OPENSSL_cleanse(pms, pms_len); @@ -2089,7 +2047,9 @@ int ssl3_send_cert_verify(SSL *s) { s2n(signature_length, p); n += signature_length + 2; - ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n); + if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n)) { + goto err; + } s->state = SSL3_ST_CW_CERT_VRFY_B; } @@ -2156,12 +2116,8 @@ int ssl3_send_client_certificate(SSL *s) { SSL_R_BAD_DATA_RETURNED_BY_CALLBACK); } - if (x509 != NULL) { - X509_free(x509); - } - if (pkey != NULL) { - EVP_PKEY_free(pkey); - } + X509_free(x509); + EVP_PKEY_free(pkey); if (i && !ssl3_has_client_certificate(s)) { i = 0; } @@ -2180,8 +2136,10 @@ int ssl3_send_client_certificate(SSL *s) { } if (s->state == SSL3_ST_CW_CERT_C) { - s->state = SSL3_ST_CW_CERT_D; - ssl3_output_cert_chain(s, (s->s3->tmp.cert_req == 2) ? NULL : s->cert->key); + CERT_PKEY *cert_pkey = (s->s3->tmp.cert_req == 2) ? NULL : s->cert->key; + if (!ssl3_output_cert_chain(s, cert_pkey)) { + return -1; + } } /* SSL3_ST_CW_CERT_D */ @@ -2246,7 +2204,7 @@ int ssl3_check_cert_and_algorithm(SSL *s) { goto f_err; } - if ((alg_k & SSL_kEDH) && + if ((alg_k & SSL_kDHE) && !(has_bits(i, EVP_PK_DH | EVP_PKT_EXCH) || dh != NULL)) { OPENSSL_PUT_ERROR(SSL, ssl3_check_cert_and_algorithm, SSL_R_MISSING_DH_KEY); goto f_err; @@ -2276,7 +2234,9 @@ int ssl3_send_next_proto(SSL *s) { memset(p, 0, padding_len); p += padding_len; - ssl_set_handshake_header(s, SSL3_MT_NEXT_PROTO, p - d); + if (!ssl_set_handshake_header(s, SSL3_MT_NEXT_PROTO, p - d)) { + return -1; + } s->state = SSL3_ST_CW_NEXT_PROTO_B; } @@ -2387,23 +2347,19 @@ int ssl3_send_channel_id(SSL *s) { goto err; } - ssl_set_handshake_header(s, SSL3_MT_ENCRYPTED_EXTENSIONS, - 2 + 2 + TLSEXT_CHANNEL_ID_SIZE); + if (!ssl_set_handshake_header(s, SSL3_MT_ENCRYPTED_EXTENSIONS, + 2 + 2 + TLSEXT_CHANNEL_ID_SIZE)) { + goto err; + } s->state = SSL3_ST_CW_CHANNEL_ID_B; ret = ssl_do_write(s); err: EVP_MD_CTX_cleanup(&md_ctx); - if (public_key) { - OPENSSL_free(public_key); - } - if (der_sig) { - OPENSSL_free(der_sig); - } - if (sig) { - ECDSA_SIG_free(sig); - } + OPENSSL_free(public_key); + OPENSSL_free(der_sig); + ECDSA_SIG_free(sig); return ret; } diff --git a/src/ssl/s3_enc.c b/src/ssl/s3_enc.c index 562cb84..fbe68da 100644 --- a/src/ssl/s3_enc.c +++ b/src/ssl/s3_enc.c @@ -133,8 +133,9 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. */ -#include #include +#include +#include #include #include @@ -142,7 +143,7 @@ #include #include -#include "ssl_locl.h" +#include "internal.h" static const uint8_t ssl3_pad_1[48] = { @@ -235,12 +236,8 @@ void ssl3_cleanup_key_block(SSL *s) { } int ssl3_init_finished_mac(SSL *s) { - if (s->s3->handshake_buffer) { - BIO_free(s->s3->handshake_buffer); - } - if (s->s3->handshake_dgst) { - ssl3_free_digest_list(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; @@ -264,12 +261,11 @@ void ssl3_free_digest_list(SSL *s) { s->s3->handshake_dgst = NULL; } -void ssl3_finish_mac(SSL *s, const uint8_t *buf, int len) { +int ssl3_finish_mac(SSL *s, const uint8_t *buf, int len) { int i; if (s->s3->handshake_buffer) { - BIO_write(s->s3->handshake_buffer, (void *)buf, len); - return; + return BIO_write(s->s3->handshake_buffer, (void *)buf, len) >= 0; } for (i = 0; i < SSL_MAX_DIGEST; i++) { @@ -277,12 +273,13 @@ void ssl3_finish_mac(SSL *s, const uint8_t *buf, int len) { EVP_DigestUpdate(s->s3->handshake_dgst[i], buf, len); } } + return 1; } int ssl3_digest_cached_records( SSL *s, enum should_free_handshake_buffer_t should_free_handshake_buffer) { int i; - long mask; + uint32_t mask; const EVP_MD *md; const uint8_t *hdata; size_t hdatalen; @@ -303,7 +300,7 @@ int ssl3_digest_cached_records( } /* Loop through bits of algorithm2 field and create MD_CTX-es */ - for (i = 0; ssl_get_handshake_digest(i, &mask, &md); i++) { + 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) { @@ -383,7 +380,7 @@ static int ssl3_handshake_mac(SSL *s, int md_nid, const char *sender, int len, EVP_MD_CTX_init(&ctx); if (!EVP_MD_CTX_copy_ex(&ctx, d)) { EVP_MD_CTX_cleanup(&ctx); - OPENSSL_PUT_ERROR(SSL, ssl3_generate_key_block, ERR_LIB_EVP); + OPENSSL_PUT_ERROR(SSL, ssl3_handshake_mac, ERR_LIB_EVP); return 0; } @@ -402,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, ssl3_generate_key_block, 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); @@ -415,15 +412,16 @@ static int ssl3_handshake_mac(SSL *s, int md_nid, const char *sender, int len, return ret; } -void ssl3_record_sequence_update(uint8_t *seq) { - int i; - - for (i = 7; i >= 0; i--) { +int ssl3_record_sequence_update(uint8_t *seq, size_t seq_len) { + size_t i; + for (i = seq_len - 1; i < seq_len; i--) { ++seq[i]; if (seq[i] != 0) { - break; + return 1; } } + OPENSSL_PUT_ERROR(SSL, ssl3_record_sequence_update, ERR_R_OVERFLOW); + return 0; } int ssl3_alert_code(int code) { diff --git a/src/ssl/s3_lib.c b/src/ssl/s3_lib.c index e0ccedc..674277f 100644 --- a/src/ssl/s3_lib.c +++ b/src/ssl/s3_lib.c @@ -148,14 +148,16 @@ #include #include +#include #include #include +#include #include #include #include -#include "ssl_locl.h" +#include "internal.h" #define SSL3_NUM_CIPHERS (sizeof(ssl3_ciphers) / sizeof(SSL_CIPHER)) @@ -165,77 +167,53 @@ const SSL_CIPHER ssl3_ciphers[] = { /* The RSA ciphers */ /* Cipher 04 */ { - 1, SSL3_TXT_RSA_RC4_128_MD5, SSL3_CK_RSA_RC4_128_MD5, SSL_kRSA, SSL_aRSA, + SSL3_TXT_RSA_RC4_128_MD5, SSL3_CK_RSA_RC4_128_MD5, SSL_kRSA, SSL_aRSA, SSL_RC4, SSL_MD5, SSL_SSLV3, SSL_MEDIUM, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, }, /* Cipher 05 */ { - 1, SSL3_TXT_RSA_RC4_128_SHA, SSL3_CK_RSA_RC4_128_SHA, SSL_kRSA, SSL_aRSA, + SSL3_TXT_RSA_RC4_128_SHA, SSL3_CK_RSA_RC4_128_SHA, SSL_kRSA, SSL_aRSA, SSL_RC4, SSL_SHA1, SSL_SSLV3, SSL_MEDIUM, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, }, /* Cipher 0A */ { - 1, SSL3_TXT_RSA_DES_192_CBC3_SHA, SSL3_CK_RSA_DES_192_CBC3_SHA, SSL_kRSA, + SSL3_TXT_RSA_DES_192_CBC3_SHA, SSL3_CK_RSA_DES_192_CBC3_SHA, SSL_kRSA, SSL_aRSA, SSL_3DES, SSL_SHA1, SSL_SSLV3, SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 112, 168, }, - /* The Ephemeral DH ciphers */ - - /* Cipher 18 */ - { - 1, SSL3_TXT_ADH_RC4_128_MD5, SSL3_CK_ADH_RC4_128_MD5, SSL_kEDH, SSL_aNULL, - SSL_RC4, SSL_MD5, SSL_SSLV3, SSL_MEDIUM, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, - }, - - /* New AES ciphersuites */ /* Cipher 2F */ { - 1, TLS1_TXT_RSA_WITH_AES_128_SHA, TLS1_CK_RSA_WITH_AES_128_SHA, SSL_kRSA, + TLS1_TXT_RSA_WITH_AES_128_SHA, TLS1_CK_RSA_WITH_AES_128_SHA, SSL_kRSA, SSL_aRSA, SSL_AES128, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, }, /* Cipher 33 */ { - 1, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA, TLS1_CK_DHE_RSA_WITH_AES_128_SHA, - SSL_kEDH, SSL_aRSA, SSL_AES128, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, - }, - - /* Cipher 34 */ - { - 1, TLS1_TXT_ADH_WITH_AES_128_SHA, TLS1_CK_ADH_WITH_AES_128_SHA, SSL_kEDH, - SSL_aNULL, SSL_AES128, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, + TLS1_TXT_DHE_RSA_WITH_AES_128_SHA, TLS1_CK_DHE_RSA_WITH_AES_128_SHA, + SSL_kDHE, SSL_aRSA, SSL_AES128, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, }, /* Cipher 35 */ { - 1, TLS1_TXT_RSA_WITH_AES_256_SHA, TLS1_CK_RSA_WITH_AES_256_SHA, SSL_kRSA, + TLS1_TXT_RSA_WITH_AES_256_SHA, TLS1_CK_RSA_WITH_AES_256_SHA, SSL_kRSA, SSL_aRSA, SSL_AES256, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256, }, /* Cipher 39 */ { - 1, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA, TLS1_CK_DHE_RSA_WITH_AES_256_SHA, - SSL_kEDH, SSL_aRSA, SSL_AES256, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256, - }, - - /* Cipher 3A */ - { - 1, TLS1_TXT_ADH_WITH_AES_256_SHA, TLS1_CK_ADH_WITH_AES_256_SHA, SSL_kEDH, - SSL_aNULL, SSL_AES256, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, + TLS1_TXT_DHE_RSA_WITH_AES_256_SHA, TLS1_CK_DHE_RSA_WITH_AES_256_SHA, + SSL_kDHE, SSL_aRSA, SSL_AES256, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256, }, @@ -244,65 +222,51 @@ const SSL_CIPHER ssl3_ciphers[] = { /* Cipher 3C */ { - 1, TLS1_TXT_RSA_WITH_AES_128_SHA256, TLS1_CK_RSA_WITH_AES_128_SHA256, + TLS1_TXT_RSA_WITH_AES_128_SHA256, TLS1_CK_RSA_WITH_AES_128_SHA256, SSL_kRSA, SSL_aRSA, SSL_AES128, SSL_SHA256, SSL_TLSV1_2, - SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, + SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 128, 128, }, /* Cipher 3D */ { - 1, TLS1_TXT_RSA_WITH_AES_256_SHA256, TLS1_CK_RSA_WITH_AES_256_SHA256, + TLS1_TXT_RSA_WITH_AES_256_SHA256, TLS1_CK_RSA_WITH_AES_256_SHA256, SSL_kRSA, SSL_aRSA, SSL_AES256, SSL_SHA256, SSL_TLSV1_2, - SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256, + SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 256, 256, }, /* Cipher 67 */ { - 1, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256, - TLS1_CK_DHE_RSA_WITH_AES_128_SHA256, SSL_kEDH, SSL_aRSA, SSL_AES128, + TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256, + TLS1_CK_DHE_RSA_WITH_AES_128_SHA256, SSL_kDHE, SSL_aRSA, SSL_AES128, SSL_SHA256, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, + SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 128, 128, }, /* Cipher 6B */ { - 1, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256, - TLS1_CK_DHE_RSA_WITH_AES_256_SHA256, SSL_kEDH, SSL_aRSA, SSL_AES256, + TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256, + TLS1_CK_DHE_RSA_WITH_AES_256_SHA256, SSL_kDHE, SSL_aRSA, SSL_AES256, SSL_SHA256, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256, - }, - - /* Cipher 6C */ - { - 1, TLS1_TXT_ADH_WITH_AES_128_SHA256, TLS1_CK_ADH_WITH_AES_128_SHA256, - SSL_kEDH, SSL_aNULL, SSL_AES128, SSL_SHA256, SSL_TLSV1_2, - SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, - }, - - /* Cipher 6D */ - { - 1, TLS1_TXT_ADH_WITH_AES_256_SHA256, TLS1_CK_ADH_WITH_AES_256_SHA256, - SSL_kEDH, SSL_aNULL, SSL_AES256, SSL_SHA256, SSL_TLSV1_2, - SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256, + SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 256, 256, }, /* Cipher 8A */ { - 1, TLS1_TXT_PSK_WITH_RC4_128_SHA, TLS1_CK_PSK_WITH_RC4_128_SHA, SSL_kPSK, + TLS1_TXT_PSK_WITH_RC4_128_SHA, TLS1_CK_PSK_WITH_RC4_128_SHA, SSL_kPSK, SSL_aPSK, SSL_RC4, SSL_SHA1, SSL_TLSV1, SSL_MEDIUM, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, }, /* Cipher 8C */ { - 1, TLS1_TXT_PSK_WITH_AES_128_CBC_SHA, TLS1_CK_PSK_WITH_AES_128_CBC_SHA, + TLS1_TXT_PSK_WITH_AES_128_CBC_SHA, TLS1_CK_PSK_WITH_AES_128_CBC_SHA, SSL_kPSK, SSL_aPSK, SSL_AES128, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, }, /* Cipher 8D */ { - 1, TLS1_TXT_PSK_WITH_AES_256_CBC_SHA, TLS1_CK_PSK_WITH_AES_256_CBC_SHA, + TLS1_TXT_PSK_WITH_AES_256_CBC_SHA, TLS1_CK_PSK_WITH_AES_256_CBC_SHA, SSL_kPSK, SSL_aPSK, SSL_AES256, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256, }, @@ -312,7 +276,7 @@ const SSL_CIPHER ssl3_ciphers[] = { /* Cipher 9C */ { - 1, TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256, + 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 | TLS1_PRF_SHA256 | SSL_CIPHER_ALGORITHM2_AEAD | @@ -322,7 +286,7 @@ const SSL_CIPHER ssl3_ciphers[] = { /* Cipher 9D */ { - 1, TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384, + 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 | TLS1_PRF_SHA384 | SSL_CIPHER_ALGORITHM2_AEAD | @@ -332,8 +296,8 @@ const SSL_CIPHER ssl3_ciphers[] = { /* Cipher 9E */ { - 1, TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256, - TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256, SSL_kEDH, SSL_aRSA, SSL_AES128GCM, + 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 | TLS1_PRF_SHA256 | SSL_CIPHER_ALGORITHM2_AEAD | SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, @@ -342,28 +306,8 @@ const SSL_CIPHER ssl3_ciphers[] = { /* Cipher 9F */ { - 1, TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384, - TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384, SSL_kEDH, SSL_aRSA, SSL_AES256GCM, - SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384 | SSL_CIPHER_ALGORITHM2_AEAD | - SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, - 256, 256, - }, - - /* Cipher A6 */ - { - 1, TLS1_TXT_ADH_WITH_AES_128_GCM_SHA256, - TLS1_CK_ADH_WITH_AES_128_GCM_SHA256, SSL_kEDH, SSL_aNULL, SSL_AES128GCM, - SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256 | SSL_CIPHER_ALGORITHM2_AEAD | - SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, - 128, 128, - }, - - /* Cipher A7 */ - { - 1, TLS1_TXT_ADH_WITH_AES_256_GCM_SHA384, - TLS1_CK_ADH_WITH_AES_256_GCM_SHA384, SSL_kEDH, SSL_aNULL, SSL_AES256GCM, + 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 | TLS1_PRF_SHA384 | SSL_CIPHER_ALGORITHM2_AEAD | SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, @@ -372,70 +316,47 @@ const SSL_CIPHER ssl3_ciphers[] = { /* Cipher C007 */ { - 1, TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA, - TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA, SSL_kEECDH, SSL_aECDSA, SSL_RC4, + TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA, + TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA, SSL_kECDHE, SSL_aECDSA, SSL_RC4, SSL_SHA1, SSL_TLSV1, SSL_MEDIUM, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, }, /* Cipher C009 */ { - 1, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, SSL_kEECDH, SSL_aECDSA, + TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, SSL_kECDHE, SSL_aECDSA, SSL_AES128, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, }, /* Cipher C00A */ { - 1, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, SSL_kEECDH, SSL_aECDSA, + TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, SSL_kECDHE, SSL_aECDSA, SSL_AES256, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256, }, /* Cipher C011 */ { - 1, TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA, TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA, - SSL_kEECDH, SSL_aRSA, SSL_RC4, SSL_SHA1, SSL_TLSV1, SSL_MEDIUM, + TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA, TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA, + SSL_kECDHE, SSL_aRSA, SSL_RC4, SSL_SHA1, SSL_TLSV1, SSL_MEDIUM, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, }, /* Cipher C013 */ { - 1, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA, - TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA, SSL_kEECDH, SSL_aRSA, SSL_AES128, + TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA, SSL_kECDHE, SSL_aRSA, SSL_AES128, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, }, /* Cipher C014 */ { - 1, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA, - TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA, SSL_kEECDH, SSL_aRSA, SSL_AES256, - SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256, - }, - - /* Cipher C016 */ - { - 1, TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA, TLS1_CK_ECDH_anon_WITH_RC4_128_SHA, - SSL_kEECDH, SSL_aNULL, SSL_RC4, SSL_SHA1, SSL_TLSV1, SSL_MEDIUM, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, - }, - - /* Cipher C018 */ - { - 1, TLS1_TXT_ECDH_anon_WITH_AES_128_CBC_SHA, - TLS1_CK_ECDH_anon_WITH_AES_128_CBC_SHA, SSL_kEECDH, SSL_aNULL, SSL_AES128, - SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, - }, - - /* Cipher C019 */ - { - 1, TLS1_TXT_ECDH_anon_WITH_AES_256_CBC_SHA, - TLS1_CK_ECDH_anon_WITH_AES_256_CBC_SHA, SSL_kEECDH, SSL_aNULL, SSL_AES256, + TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA, + TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA, SSL_kECDHE, SSL_aRSA, SSL_AES256, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256, }, @@ -445,32 +366,32 @@ const SSL_CIPHER ssl3_ciphers[] = { /* Cipher C023 */ { - 1, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_SHA256, - TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256, SSL_kEECDH, SSL_aECDSA, + TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_SHA256, + TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256, SSL_kECDHE, SSL_aECDSA, SSL_AES128, SSL_SHA256, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 128, 128, }, /* Cipher C024 */ { - 1, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_SHA384, - TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384, SSL_kEECDH, SSL_aECDSA, + TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_SHA384, + TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384, SSL_kECDHE, SSL_aECDSA, SSL_AES256, SSL_SHA384, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, 256, 256, }, /* Cipher C027 */ { - 1, TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256, - TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256, SSL_kEECDH, SSL_aRSA, SSL_AES128, + TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256, + TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256, SSL_kECDHE, SSL_aRSA, SSL_AES128, SSL_SHA256, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 128, 128, }, /* Cipher C028 */ { - 1, TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384, - TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384, SSL_kEECDH, SSL_aRSA, SSL_AES256, + TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384, + TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384, SSL_kECDHE, SSL_aRSA, SSL_AES256, SSL_SHA384, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, 256, 256, }, @@ -480,8 +401,8 @@ const SSL_CIPHER ssl3_ciphers[] = { /* Cipher C02B */ { - 1, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, SSL_kEECDH, SSL_aECDSA, + 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 | TLS1_PRF_SHA256 | SSL_CIPHER_ALGORITHM2_AEAD | SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, @@ -490,8 +411,8 @@ const SSL_CIPHER ssl3_ciphers[] = { /* Cipher C02C */ { - 1, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, SSL_kEECDH, SSL_aECDSA, + 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 | TLS1_PRF_SHA384 | SSL_CIPHER_ALGORITHM2_AEAD | SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, @@ -500,8 +421,8 @@ const SSL_CIPHER ssl3_ciphers[] = { /* Cipher C02F */ { - 1, TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, SSL_kEECDH, SSL_aRSA, + 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 | TLS1_PRF_SHA256 | SSL_CIPHER_ALGORITHM2_AEAD | SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, @@ -510,8 +431,8 @@ const SSL_CIPHER ssl3_ciphers[] = { /* Cipher C030 */ { - 1, TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, SSL_kEECDH, SSL_aRSA, + 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 | TLS1_PRF_SHA384 | SSL_CIPHER_ALGORITHM2_AEAD | SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, @@ -523,8 +444,8 @@ const SSL_CIPHER ssl3_ciphers[] = { /* Cipher CAFE */ { - 1, TLS1_TXT_ECDHE_PSK_WITH_AES_128_GCM_SHA256, - TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256, SSL_kEECDH, SSL_aPSK, + TLS1_TXT_ECDHE_PSK_WITH_AES_128_GCM_SHA256, + TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256, SSL_kECDHE, SSL_aPSK, SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH, SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256 | SSL_CIPHER_ALGORITHM2_AEAD | SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, @@ -532,24 +453,24 @@ const SSL_CIPHER ssl3_ciphers[] = { }, { - 1, TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305, - TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, SSL_kEECDH, SSL_aRSA, + 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 | TLS1_PRF_SHA256 | SSL_CIPHER_ALGORITHM2_AEAD, 256, 0, }, { - 1, TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, - TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, SSL_kEECDH, SSL_aECDSA, + TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, SSL_kECDHE, SSL_aECDSA, SSL_CHACHA20POLY1305, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH, SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256 | SSL_CIPHER_ALGORITHM2_AEAD, 256, 0, }, { - 1, TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305, - TLS1_CK_DHE_RSA_CHACHA20_POLY1305, SSL_kEDH, SSL_aRSA, + 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 | TLS1_PRF_SHA256 | SSL_CIPHER_ALGORITHM2_AEAD, 256, 0, @@ -563,27 +484,22 @@ const SSL3_ENC_METHOD SSLv3_enc_data = { tls1_generate_master_secret, tls1_change_cipher_state, ssl3_final_finish_mac, - MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH, ssl3_cert_verify_mac, SSL3_MD_CLIENT_FINISHED_CONST, 4, SSL3_MD_SERVER_FINISHED_CONST, 4, ssl3_alert_code, - (int (*)(SSL *, uint8_t *, size_t, const char *, size_t, const uint8_t *, - size_t, int use_context)) ssl_undefined_function, + tls1_export_keying_material, 0, - SSL3_HM_HEADER_LENGTH, - ssl3_set_handshake_header, - ssl3_handshake_write, }; -int ssl3_num_ciphers(void) { return SSL3_NUM_CIPHERS; } +size_t ssl3_num_ciphers(void) { return SSL3_NUM_CIPHERS; } -const SSL_CIPHER *ssl3_get_cipher(unsigned int u) { - if (u >= SSL3_NUM_CIPHERS) { +const SSL_CIPHER *ssl3_get_cipher(size_t i) { + if (i >= SSL3_NUM_CIPHERS) { return NULL; } - return &ssl3_ciphers[SSL3_NUM_CIPHERS - 1 - u]; + return &ssl3_ciphers[SSL3_NUM_CIPHERS - 1 - i]; } int ssl3_pending(const SSL *s) { @@ -595,7 +511,7 @@ int ssl3_pending(const SSL *s) { : 0; } -void ssl3_set_handshake_header(SSL *s, int htype, unsigned long len) { +int ssl3_set_handshake_header(SSL *s, int htype, unsigned long len) { uint8_t *p = (uint8_t *)s->init_buf->data; *(p++) = htype; l2n3(len, p); @@ -603,7 +519,7 @@ void ssl3_set_handshake_header(SSL *s, int htype, unsigned long len) { s->init_off = 0; /* Add the message to the handshake hash. */ - ssl3_finish_mac(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); } @@ -637,47 +553,21 @@ void ssl3_free(SSL *s) { return; } - if (s->s3->sniff_buffer != NULL) { - BUF_MEM_free(s->s3->sniff_buffer); - } + BUF_MEM_free(s->s3->sniff_buffer); ssl3_cleanup_key_block(s); - if (s->s3->rbuf.buf != NULL) { - ssl3_release_read_buffer(s); - } - if (s->s3->wbuf.buf != NULL) { - ssl3_release_write_buffer(s); - } - if (s->s3->tmp.dh != NULL) { - DH_free(s->s3->tmp.dh); - } - if (s->s3->tmp.ecdh != NULL) { - EC_KEY_free(s->s3->tmp.ecdh); - } - - if (s->s3->tmp.ca_names != NULL) { - sk_X509_NAME_pop_free(s->s3->tmp.ca_names, X509_NAME_free); - } - if (s->s3->tmp.certificate_types != NULL) { - OPENSSL_free(s->s3->tmp.certificate_types); - } - if (s->s3->tmp.peer_ecpointformatlist) { - OPENSSL_free(s->s3->tmp.peer_ecpointformatlist); - } - if (s->s3->tmp.peer_ellipticcurvelist) { - OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist); - } - if (s->s3->tmp.peer_psk_identity_hint) { - OPENSSL_free(s->s3->tmp.peer_psk_identity_hint); - } - if (s->s3->handshake_buffer) { - BIO_free(s->s3->handshake_buffer); - } - if (s->s3->handshake_dgst) { - ssl3_free_digest_list(s); - } - if (s->s3->alpn_selected) { - OPENSSL_free(s->s3->alpn_selected); - } + 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); + BIO_free(s->s3->handshake_buffer); + ssl3_free_digest_list(s); + OPENSSL_free(s->s3->alpn_selected); OPENSSL_cleanse(s->s3, sizeof *s->s3); OPENSSL_free(s->s3); @@ -686,145 +576,139 @@ void ssl3_free(SSL *s) { static int ssl3_set_req_cert_type(CERT *c, const uint8_t *p, size_t len); -long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) { - int ret = 0; +int SSL_session_reused(const SSL *ssl) { + return ssl->hit; +} - if (cmd == SSL_CTRL_SET_TMP_RSA || cmd == SSL_CTRL_SET_TMP_RSA_CB || - cmd == SSL_CTRL_SET_TMP_DH || cmd == SSL_CTRL_SET_TMP_DH_CB) { - if (!ssl_cert_inst(&s->cert)) { - OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_MALLOC_FAILURE); - return 0; - } - } +int SSL_total_renegotiations(const SSL *ssl) { + return ssl->s3->total_renegotiations; +} - switch (cmd) { - case SSL_CTRL_GET_SESSION_REUSED: - ret = s->hit; - break; +int SSL_num_renegotiations(const SSL *ssl) { + return SSL_total_renegotiations(ssl); +} - case SSL_CTRL_GET_CLIENT_CERT_REQUEST: - break; +int SSL_CTX_need_tmp_RSA(const SSL_CTX *ctx) { + return 0; +} - case SSL_CTRL_GET_NUM_RENEGOTIATIONS: - ret = s->s3->num_renegotiations; - break; +int SSL_need_rsa(const SSL *ssl) { + return 0; +} - case SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS: - ret = s->s3->num_renegotiations; - s->s3->num_renegotiations = 0; - break; +int SSL_CTX_set_tmp_rsa(SSL_CTX *ctx, const RSA *rsa) { + return 1; +} - case SSL_CTRL_GET_TOTAL_RENEGOTIATIONS: - ret = s->s3->total_renegotiations; - break; +int SSL_set_tmp_rsa(SSL *ssl, const RSA *rsa) { + return 1; +} - case SSL_CTRL_GET_FLAGS: - ret = (int)(s->s3->flags); - break; +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, SSL_CTX_set_tmp_dh, ERR_R_DH_LIB); + return 0; + } + return 1; +} - case SSL_CTRL_NEED_TMP_RSA: - /* Temporary RSA keys are never used. */ - ret = 0; - break; +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, SSL_set_tmp_dh, ERR_R_DH_LIB); + return 0; + } + return 1; +} - case SSL_CTRL_SET_TMP_RSA: - /* Temporary RSA keys are never used. */ - OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - break; +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, 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)); + return 1; +} - case SSL_CTRL_SET_TMP_RSA_CB: - OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return ret; +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, 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)); + return 1; +} - case SSL_CTRL_SET_TMP_DH: { - DH *dh = (DH *)parg; - if (dh == NULL) { - OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_PASSED_NULL_PARAMETER); - return ret; - } - dh = DHparams_dup(dh); - if (dh == NULL) { - OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_DH_LIB); - return ret; - } - if (!(s->options & SSL_OP_SINGLE_DH_USE) && !DH_generate_key(dh)) { - DH_free(dh); - OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_DH_LIB); - return ret; - } - if (s->cert->dh_tmp != NULL) { - DH_free(s->cert->dh_tmp); - } - s->cert->dh_tmp = dh; - ret = 1; - break; - } +int SSL_CTX_enable_tls_channel_id(SSL_CTX *ctx) { + ctx->tlsext_channel_id_enabled = 1; + return 1; +} - case SSL_CTRL_SET_TMP_DH_CB: - OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return ret; +int SSL_enable_tls_channel_id(SSL *ssl) { + ssl->tlsext_channel_id_enabled = 1; + return 1; +} - case SSL_CTRL_SET_TMP_ECDH: { - EC_KEY *ecdh = NULL; +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_CTX_set1_tls_channel_id, + SSL_R_CHANNEL_ID_NOT_P256); + return 0; + } + EVP_PKEY_free(ctx->tlsext_channel_id_private); + ctx->tlsext_channel_id_private = EVP_PKEY_up_ref(private_key); + return 1; +} - if (parg == NULL) { - OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_PASSED_NULL_PARAMETER); - return ret; - } - if (!EC_KEY_up_ref((EC_KEY *)parg)) { - OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_ECDH_LIB); - return ret; - } - ecdh = (EC_KEY *)parg; - if (!(s->options & SSL_OP_SINGLE_ECDH_USE) && !EC_KEY_generate_key(ecdh)) { - EC_KEY_free(ecdh); - OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_ECDH_LIB); - return ret; - } - if (s->cert->ecdh_tmp != NULL) { - EC_KEY_free(s->cert->ecdh_tmp); - } - s->cert->ecdh_tmp = ecdh; - ret = 1; - break; - } +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_set1_tls_channel_id, SSL_R_CHANNEL_ID_NOT_P256); + return 0; + } + EVP_PKEY_free(ssl->tlsext_channel_id_private); + ssl->tlsext_channel_id_private = EVP_PKEY_up_ref(private_key); + return 1; +} - case SSL_CTRL_SET_TMP_ECDH_CB: - OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return ret; +size_t SSL_get_tls_channel_id(SSL *ssl, uint8_t *out, size_t max_out) { + if (!ssl->s3->tlsext_channel_id_valid) { + return 0; + } + memcpy(out, ssl->s3->tlsext_channel_id, (max_out < 64) ? max_out : 64); + return 64; +} - case SSL_CTRL_SET_TLSEXT_HOSTNAME: - if (larg == TLSEXT_NAMETYPE_host_name) { - if (s->tlsext_hostname != NULL) { - OPENSSL_free(s->tlsext_hostname); - } - s->tlsext_hostname = NULL; +int SSL_set_tlsext_host_name(SSL *ssl, const char *name) { + OPENSSL_free(ssl->tlsext_hostname); + ssl->tlsext_hostname = NULL; - ret = 1; - if (parg == NULL) { - break; - } - if (strlen((char *)parg) > TLSEXT_MAXLEN_host_name) { - OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, SSL_R_SSL3_EXT_INVALID_SERVERNAME); - return 0; - } - s->tlsext_hostname = BUF_strdup((char *) parg); - if (s->tlsext_hostname == NULL) { - OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_INTERNAL_ERROR); - return 0; - } - } else { - OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, - SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE); - return 0; - } - break; + if (name == NULL) { + return 1; + } + if (strlen(name) > TLSEXT_MAXLEN_host_name) { + 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, SSL_set_tlsext_host_name, ERR_R_MALLOC_FAILURE); + return 0; + } + return 1; +} - case SSL_CTRL_SET_TLSEXT_DEBUG_ARG: - s->tlsext_debug_arg = parg; - ret = 1; - break; +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); @@ -870,10 +754,6 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) { return tls1_set_curves(&s->tlsext_ellipticcurvelist, &s->tlsext_ellipticcurvelist_length, parg, larg); - case SSL_CTRL_SET_ECDH_AUTO: - s->cert->ecdh_tmp_auto = larg; - return 1; - case SSL_CTRL_SET_SIGALGS: return tls1_set_sigalgs(s->cert, parg, larg, 0); @@ -943,65 +823,6 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) { return (int)s->s3->tmp.peer_ecpointformatlist_length; } - case SSL_CTRL_CHANNEL_ID: - s->tlsext_channel_id_enabled = 1; - ret = 1; - break; - - case SSL_CTRL_SET_CHANNEL_ID: - s->tlsext_channel_id_enabled = 1; - if (EVP_PKEY_bits(parg) != 256) { - OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, SSL_R_CHANNEL_ID_NOT_P256); - break; - } - if (s->tlsext_channel_id_private) { - EVP_PKEY_free(s->tlsext_channel_id_private); - } - s->tlsext_channel_id_private = EVP_PKEY_dup((EVP_PKEY *)parg); - ret = 1; - break; - - case SSL_CTRL_GET_CHANNEL_ID: - if (!s->s3->tlsext_channel_id_valid) { - break; - } - memcpy(parg, s->s3->tlsext_channel_id, larg < 64 ? larg : 64); - return 64; - - default: - break; - } - - return ret; -} - -long ssl3_callback_ctrl(SSL *s, int cmd, void (*fp)(void)) { - int ret = 0; - - if ((cmd == SSL_CTRL_SET_TMP_RSA_CB || cmd == SSL_CTRL_SET_TMP_DH_CB) && - !ssl_cert_inst(&s->cert)) { - OPENSSL_PUT_ERROR(SSL, ssl3_callback_ctrl, ERR_R_MALLOC_FAILURE); - return 0; - } - - switch (cmd) { - case SSL_CTRL_SET_TMP_RSA_CB: - /* Ignore the callback; temporary RSA keys are never used. */ - break; - - case SSL_CTRL_SET_TMP_DH_CB: - s->cert->dh_tmp_cb = (DH * (*)(SSL *, int, int))fp; - break; - - case SSL_CTRL_SET_TMP_ECDH_CB: - s->cert->ecdh_tmp_cb = (EC_KEY * (*)(SSL *, int, int))fp; - break; - - case SSL_CTRL_SET_TLSEXT_DEBUG_CB: - s->tlsext_debug_cb = - (void (*)(SSL *, int, int, uint8_t *, int, void *))fp; - break; - default: break; } @@ -1010,82 +831,7 @@ long ssl3_callback_ctrl(SSL *s, int cmd, void (*fp)(void)) { } long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) { - CERT *cert; - - cert = ctx->cert; - switch (cmd) { - case SSL_CTRL_NEED_TMP_RSA: - /* Temporary RSA keys are never used. */ - return 0; - - case SSL_CTRL_SET_TMP_RSA: - OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; - - case SSL_CTRL_SET_TMP_RSA_CB: - OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; - - case SSL_CTRL_SET_TMP_DH: { - DH *new = NULL, *dh; - - dh = (DH *)parg; - new = DHparams_dup(dh); - if (new == NULL) { - OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_DH_LIB); - return 0; - } - if (!(ctx->options & SSL_OP_SINGLE_DH_USE) && !DH_generate_key(new)) { - OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_DH_LIB); - DH_free(new); - return 0; - } - if (cert->dh_tmp != NULL) { - DH_free(cert->dh_tmp); - } - cert->dh_tmp = new; - return 1; - } - - case SSL_CTRL_SET_TMP_DH_CB: - OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; - - case SSL_CTRL_SET_TMP_ECDH: { - EC_KEY *ecdh = NULL; - - if (parg == NULL) { - OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_ECDH_LIB); - return 0; - } - ecdh = EC_KEY_dup((EC_KEY *)parg); - if (ecdh == NULL) { - OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_EC_LIB); - return 0; - } - if (!(ctx->options & SSL_OP_SINGLE_ECDH_USE) && - !EC_KEY_generate_key(ecdh)) { - EC_KEY_free(ecdh); - OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_ECDH_LIB); - return 0; - } - - if (cert->ecdh_tmp != NULL) { - EC_KEY_free(cert->ecdh_tmp); - } - cert->ecdh_tmp = ecdh; - return 1; - } - - case SSL_CTRL_SET_TMP_ECDH_CB: - OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; - - case SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG: - ctx->tlsext_servername_arg = parg; - break; - case SSL_CTRL_SET_TLSEXT_TICKET_KEYS: case SSL_CTRL_GET_TLSEXT_TICKET_KEYS: { uint8_t *keys = parg; @@ -1108,19 +854,10 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) { return 1; } - case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG: - ctx->tlsext_status_arg = parg; - return 1; - break; - case SSL_CTRL_SET_CURVES: return tls1_set_curves(&ctx->tlsext_ellipticcurvelist, &ctx->tlsext_ellipticcurvelist_length, parg, larg); - case SSL_CTRL_SET_ECDH_AUTO: - ctx->cert->ecdh_tmp_auto = larg; - return 1; - case SSL_CTRL_SET_SIGALGS: return tls1_set_sigalgs(ctx->cert, parg, larg, 0); @@ -1158,10 +895,8 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) { break; case SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS: - if (ctx->extra_certs) { - sk_X509_pop_free(ctx->extra_certs, X509_free); - ctx->extra_certs = NULL; - } + sk_X509_pop_free(ctx->extra_certs, X509_free); + ctx->extra_certs = NULL; break; case SSL_CTRL_CHAIN: @@ -1185,22 +920,6 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) { case SSL_CTRL_SELECT_CURRENT_CERT: return ssl_cert_select_current(ctx->cert, (X509 *)parg); - case SSL_CTRL_CHANNEL_ID: - ctx->tlsext_channel_id_enabled = 1; - return 1; - - case SSL_CTRL_SET_CHANNEL_ID: - ctx->tlsext_channel_id_enabled = 1; - if (EVP_PKEY_bits(parg) != 256) { - OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, SSL_R_CHANNEL_ID_NOT_P256); - break; - } - if (ctx->tlsext_channel_id_private) { - EVP_PKEY_free(ctx->tlsext_channel_id_private); - } - ctx->tlsext_channel_id_private = EVP_PKEY_dup((EVP_PKEY *)parg); - break; - default: return 0; } @@ -1208,41 +927,22 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) { return 1; } -long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void)) { - CERT *cert; - - cert = ctx->cert; - - switch (cmd) { - case SSL_CTRL_SET_TMP_RSA_CB: - /* Ignore the callback; temporary RSA keys are never used. */ - break; - - case SSL_CTRL_SET_TMP_DH_CB: - cert->dh_tmp_cb = (DH * (*)(SSL *, int, int))fp; - break; - - case SSL_CTRL_SET_TMP_ECDH_CB: - cert->ecdh_tmp_cb = (EC_KEY * (*)(SSL *, int, int))fp; - break; - - case SSL_CTRL_SET_TLSEXT_SERVERNAME_CB: - ctx->tlsext_servername_callback = (int (*)(SSL *, int *, void *))fp; - break; - - case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB: - ctx->tlsext_status_cb = (int (*)(SSL *, void *))fp; - break; - - case SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB: - ctx->tlsext_ticket_key_cb = (int ( - *)(SSL *, uint8_t *, uint8_t *, EVP_CIPHER_CTX *, HMAC_CTX *, int))fp; - break; +int SSL_CTX_set_tlsext_servername_callback( + SSL_CTX *ctx, int (*callback)(SSL *ssl, int *out_alert, void *arg)) { + ctx->tlsext_servername_callback = callback; + return 1; +} - default: - return 0; - } +int SSL_CTX_set_tlsext_servername_arg(SSL_CTX *ctx, void *arg) { + ctx->tlsext_servername_arg = arg; + 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, + int encrypt)) { + ctx->tlsext_ticket_key_cb = callback; return 1; } @@ -1261,7 +961,7 @@ const SSL_CIPHER *ssl3_get_cipher_by_value(uint16_t value) { /* ssl3_get_cipher_by_value returns the cipher value of |c|. */ uint16_t ssl3_get_cipher_value(const SSL_CIPHER *c) { - unsigned long id = c->id; + uint32_t id = c->id; /* All ciphers are SSLv3 now. */ assert((id & 0xff000000) == 0x03000000); return id & 0xffff; @@ -1285,14 +985,14 @@ struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *s) { } const SSL_CIPHER *ssl3_choose_cipher( - SSL *s, STACK_OF(SSL_CIPHER) * clnt, + SSL *s, STACK_OF(SSL_CIPHER) *clnt, struct ssl_cipher_preference_list_st *server_pref) { const SSL_CIPHER *c, *ret = NULL; STACK_OF(SSL_CIPHER) *srvr = server_pref->ciphers, *prio, *allow; size_t i; int ok; size_t cipher_index; - unsigned long alg_k, alg_a, mask_k, mask_a; + uint32_t alg_k, alg_a, mask_k, mask_a; /* in_group_flags will either be NULL, or will point to an array of bytes * which indicate equal-preference groups in the |prio| stack. See the * comment about |in_group_flags| in the |ssl_cipher_preference_list_st| @@ -1389,7 +1089,7 @@ int ssl3_get_req_cert_type(SSL *s, uint8_t *p) { } /* ECDSA certs can be used with RSA cipher suites as well so we don't need to - * check for SSL_kECDH or SSL_kEECDH. */ + * check for SSL_kECDH or SSL_kECDHE. */ if (s->version >= TLS1_VERSION && have_ecdsa_sign) { p[ret++] = TLS_CT_ECDSA_SIGN; } @@ -1398,12 +1098,10 @@ int ssl3_get_req_cert_type(SSL *s, uint8_t *p) { } static int ssl3_set_req_cert_type(CERT *c, const uint8_t *p, size_t len) { - if (c->client_certificate_types) { - OPENSSL_free(c->client_certificate_types); - c->client_certificate_types = NULL; - } - + OPENSSL_free(c->client_certificate_types); + c->client_certificate_types = NULL; c->num_client_certificate_types = 0; + if (!p || !len) { return 1; } @@ -1474,29 +1172,12 @@ int ssl3_write(SSL *s, const void *buf, int len) { } static int ssl3_read_internal(SSL *s, void *buf, int len, int peek) { - int ret; - ERR_clear_system_error(); if (s->s3->renegotiate) { ssl3_renegotiate_check(s); } - s->s3->in_read_app_data = 1; - ret = s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, buf, len, peek); - if (ret == -1 && s->s3->in_read_app_data == 2) { - /* ssl3_read_bytes decided to call s->handshake_func, which called - * ssl3_read_bytes to read handshake data. However, ssl3_read_bytes - * actually found application data and thinks that application data makes - * sense here; so disable handshake processing and try to read application - * data again. */ - s->in_handshake++; - ret = - s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, buf, len, peek); - s->in_handshake--; - } else { - s->s3->in_read_app_data = 0; - } - return ret; + return s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, buf, len, peek); } int ssl3_read(SSL *s, void *buf, int len) { @@ -1523,7 +1204,6 @@ int ssl3_renegotiate_check(SSL *s) { * need to go to SSL_ST_ACCEPT. */ s->state = SSL_ST_RENEGOTIATE; s->s3->renegotiate = 0; - s->s3->num_renegotiations++; s->s3->total_renegotiations++; return 1; } @@ -1533,9 +1213,9 @@ int ssl3_renegotiate_check(SSL *s) { /* If we are using default SHA1+MD5 algorithms switch to new SHA256 PRF and * handshake macs if required. */ -long ssl_get_algorithm2(SSL *s) { - static const unsigned long kMask = SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF; - long alg2 = s->s3->tmp.new_cipher->algorithm2; +uint32_t ssl_get_algorithm2(SSL *s) { + static const uint32_t kMask = SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF; + uint32_t alg2 = s->s3->tmp.new_cipher->algorithm2; if (s->enc_method->enc_flags & SSL_ENC_FLAG_SHA256_PRF && (alg2 & kMask) == kMask) { return SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256; diff --git a/src/ssl/s3_meth.c b/src/ssl/s3_meth.c index 5a25d7b..28b9051 100644 --- a/src/ssl/s3_meth.c +++ b/src/ssl/s3_meth.c @@ -54,10 +54,11 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ -#include "ssl_locl.h" +#include "internal.h" static const SSL_PROTOCOL_METHOD TLS_protocol_method = { + 0 /* is_dtls */, ssl3_new, ssl3_free, ssl3_accept, @@ -77,9 +78,9 @@ static const SSL_PROTOCOL_METHOD TLS_protocol_method = { ssl3_pending, ssl3_num_ciphers, ssl3_get_cipher, - ssl_undefined_void_function, - ssl3_callback_ctrl, - ssl3_ctx_callback_ctrl, + SSL3_HM_HEADER_LENGTH, + ssl3_set_handshake_header, + ssl3_handshake_write, }; const SSL_METHOD *TLS_method(void) { diff --git a/src/ssl/s3_pkt.c b/src/ssl/s3_pkt.c index 3a42c3a..c42d000 100644 --- a/src/ssl/s3_pkt.c +++ b/src/ssl/s3_pkt.c @@ -107,9 +107,9 @@ * Hudson (tjh@cryptsoft.com). */ #include -#include #include #include +#include #include #include @@ -117,23 +117,23 @@ #include #include -#include "ssl_locl.h" +#include "internal.h" static int do_ssl3_write(SSL *s, int type, const uint8_t *buf, unsigned int len, - char fragment, char is_fragment); + char fragment); static int ssl3_get_record(SSL *s); -int ssl3_read_n(SSL *s, int n, int max, int extend) { +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 |s->read_ahead| is set, |max| - * bytes may be stored in |rbuf| (plus |s->packet_length| bytes if |extend| - * is one.) */ + * |s->packet| and |s->packet_length|. (If |s->read_ahead| is set and |extend| + * is 0, additional bytes may be read into |rbuf|, up to the size of the + * buffer.) */ int i, len, left; - long align = 0; + uintptr_t align = 0; uint8_t *pkt; SSL3_BUFFER *rb; @@ -148,8 +148,8 @@ int ssl3_read_n(SSL *s, int n, int max, int extend) { left = rb->left; - align = (long)rb->buf + SSL3_RT_HEADER_LENGTH; - align = (-align) & (SSL3_ALIGN_PAYLOAD - 1); + align = (uintptr_t)rb->buf + SSL3_RT_HEADER_LENGTH; + align = (0 - align) & (SSL3_ALIGN_PAYLOAD - 1); if (!extend) { /* start with empty packet ... */ @@ -201,22 +201,14 @@ int ssl3_read_n(SSL *s, int n, int max, int extend) { rb->offset = len + align; } - assert(n <= (int)(rb->len - rb->offset)); if (n > (int)(rb->len - rb->offset)) { OPENSSL_PUT_ERROR(SSL, ssl3_read_n, ERR_R_INTERNAL_ERROR); return -1; } - if (!s->read_ahead) { - /* ignore max parameter */ - max = n; - } else { - if (max < n) { - max = n; - } - if (max > (int)(rb->len - rb->offset)) { - max = rb->len - rb->offset; - } + int max = n; + if (s->read_ahead && !extend) { + max = rb->len - rb->offset; } while (left < n) { @@ -233,8 +225,7 @@ int ssl3_read_n(SSL *s, int n, int max, int extend) { if (i <= 0) { rb->left = left; - if (s->mode & SSL_MODE_RELEASE_BUFFERS && !SSL_IS_DTLS(s) && - len + left == 0) { + if (len + left == 0) { ssl3_release_read_buffer(s); } return i; @@ -281,29 +272,21 @@ static int ssl3_get_record(SSL *s) { rr = &s->s3->rrec; - if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) { - extra = SSL3_RT_MAX_EXTRA; - } else { - extra = 0; - } - - if (extra && !s->s3->init_extra) { - /* An application error: SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER set after - * ssl3_setup_buffers() was done */ - OPENSSL_PUT_ERROR(SSL, ssl3_get_record, ERR_R_INTERNAL_ERROR); - return -1; - } - 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, s->s3->rbuf.len, 0); + 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); @@ -318,10 +301,6 @@ again: if (s->s3->have_version && version != s->version) { OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_WRONG_VERSION_NUMBER); - if ((s->version & 0xFF00) == (version & 0xFF00)) { - /* Send back error using their minor version number. */ - s->version = (unsigned short)version; - } al = SSL_AD_PROTOCOL_VERSION; goto f_err; } @@ -331,13 +310,18 @@ again: goto err; } - if (rr->length > s->s3->rbuf.len - SSL3_RT_HEADER_LENGTH) { + if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH + extra) { al = SSL_AD_RECORD_OVERFLOW; - OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_PACKET_LENGTH_TOO_LONG); + 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; } /* s->rstate == SSL_ST_READ_BODY, get and decode the data */ @@ -345,7 +329,7 @@ again: 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, i, 1); + 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|. */ @@ -367,13 +351,6 @@ again: /* We now have - encrypted [ MAC [ compressed [ plain ] ] ] * rr->length bytes of encrypted compressed stuff. */ - /* check is not needed I believe */ - 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; - } - /* decrypt in place in 'rr->input' */ rr->data = rr->input; @@ -431,7 +408,7 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) { tot = s->s3->wnum; s->s3->wnum = 0; - if (SSL_in_init(s) && !s->in_handshake) { + if (!s->in_handshake && SSL_in_init(s) && !SSL_in_false_start(s)) { i = s->handshake_func(s); if (i < 0) { return i; @@ -454,6 +431,7 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) { return -1; } + int record_split_done = 0; n = (len - tot); for (;;) { /* max contains the maximum number of bytes that we can put into a @@ -462,34 +440,27 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) { /* 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 (n > 1 && s->s3->need_record_splitting && - type == SSL3_RT_APPLICATION_DATA && !s->s3->record_split_done) { + 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 records that the splitting has been done in case we - * hit an SSL_WANT_WRITE condition. In that case, we don't need to do the - * split again. */ - s->s3->record_split_done = 1; + record_split_done = 1; } - if (n > max) { nw = max; } else { nw = n; } - i = do_ssl3_write(s, type, &(buf[tot]), nw, fragment, 0); + i = do_ssl3_write(s, type, &buf[tot], nw, fragment); if (i <= 0) { s->s3->wnum = tot; - s->s3->record_split_done = 0; return i; } if (i == (int)n || (type == SSL3_RT_APPLICATION_DATA && (s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE))) { - /* next chunk of data should get another prepended, one-byte fragment in - * ciphersuites with known-IV weakness. */ - s->s3->record_split_done = 0; return tot + i; } @@ -498,20 +469,92 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) { } } +/* 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, |s->s3->wrec| is updated to include + * the new record. */ +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. */ + if (!s->s3->have_version && s->version > SSL3_VERSION) { + out[1] = TLS1_VERSION >> 8; + out[2] = TLS1_VERSION & 0xff; + } else { + out[1] = s->version >> 8; + out[2] = s->version & 0xff; + } + + size_t explicit_nonce_len = 0; + if (s->aead_write_ctx != NULL && + s->aead_write_ctx->variable_nonce_included_in_record) { + explicit_nonce_len = s->aead_write_ctx->variable_nonce_len; + } + size_t max_overhead = 0; + if (s->aead_write_ctx != NULL) { + max_overhead = s->aead_write_ctx->tag_len; + } + + /* Assemble the input for |s->enc_method->enc|. The input is the plaintext + * with |explicit_nonce_len| bytes of space prepended for the explicit + * nonce. The input is copied into |out| and then encrypted in-place to take + * advantage of alignment. + * + * TODO(davidben): |tls1_enc| should accept its inputs and outputs directly + * rather than looking up in |wrec| and friends. The |max_overhead| bounds + * check would also be unnecessary if |max_out| were passed down. */ + SSL3_RECORD *wr = &s->s3->wrec; + size_t plaintext_len = in_len + explicit_nonce_len; + if (plaintext_len < in_len || plaintext_len > INT_MAX || + plaintext_len + max_overhead < plaintext_len) { + OPENSSL_PUT_ERROR(SSL, ssl3_seal_record, ERR_R_OVERFLOW); + return 0; + } + if (max_out - SSL3_RT_HEADER_LENGTH < plaintext_len + max_overhead) { + OPENSSL_PUT_ERROR(SSL, ssl3_seal_record, SSL_R_BUFFER_TOO_SMALL); + return 0; + } + wr->type = type; + wr->input = out + SSL3_RT_HEADER_LENGTH; + wr->data = wr->input; + wr->length = plaintext_len; + memcpy(wr->input + explicit_nonce_len, in, in_len); + + if (!s->enc_method->enc(s, 1)) { + return 0; + } + + /* |wr->length| has now been set to the ciphertext length. */ + if (wr->length >= 1 << 16) { + OPENSSL_PUT_ERROR(SSL, ssl3_seal_record, ERR_R_OVERFLOW); + return 0; + } + out[3] = wr->length >> 8; + out[4] = wr->length & 0xff; + *out_len = SSL3_RT_HEADER_LENGTH + (size_t)wr->length; + + 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. If |is_fragment| is true then - * this call resulted from do_ssl3_write calling itself in order to create that - * one byte fragment. */ + * 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, char is_fragment) { - uint8_t *p, *plen; - int i; - int prefix_len = 0; - int eivlen = 0; - long align = 0; - SSL3_RECORD *wr; - SSL3_BUFFER *wb = &(s->s3->wbuf); + 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 */ @@ -521,9 +564,9 @@ static int do_ssl3_write(SSL *s, int type, const uint8_t *buf, unsigned int len, /* If we have an alert to send, lets send it */ if (s->s3->alert_dispatch) { - i = s->method->ssl_dispatch_alert(s); - if (i <= 0) { - return i; + int ret = s->method->ssl_dispatch_alert(s); + if (ret <= 0) { + return ret; } /* if it went, fall through and send more stuff */ } @@ -535,122 +578,62 @@ static int do_ssl3_write(SSL *s, int type, const uint8_t *buf, unsigned int len, if (len == 0) { return 0; } - - wr = &s->s3->wrec; - - if (fragment) { - /* countermeasure against known-IV weakness in CBC ciphersuites (see - * http://www.openssl.org/~bodo/tls-cbc.txt) */ - prefix_len = do_ssl3_write(s, type, buf, 1 /* length */, 0 /* fragment */, - 1 /* is_fragment */); - if (prefix_len <= 0) { - goto err; - } - - if (prefix_len > - (SSL3_RT_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD)) { - /* insufficient space */ - OPENSSL_PUT_ERROR(SSL, do_ssl3_write, ERR_R_INTERNAL_ERROR); - goto err; - } - } - - if (is_fragment) { - /* The extra fragment would be couple of cipher blocks, and that will be a - * multiple of SSL3_ALIGN_PAYLOAD. So, if we want to align the real - * payload, we can just pretend that we have two headers and a byte. */ - align = (long)wb->buf + 2 * SSL3_RT_HEADER_LENGTH + 1; - align = (-align) & (SSL3_ALIGN_PAYLOAD - 1); - p = wb->buf + align; - wb->offset = align; - } else if (prefix_len) { - p = wb->buf + wb->offset + prefix_len; - } else { - align = (long)wb->buf + SSL3_RT_HEADER_LENGTH; - align = (-align) & (SSL3_ALIGN_PAYLOAD - 1); - p = wb->buf + align; - wb->offset = align; + if (len == 1) { + /* No sense in fragmenting a one-byte record. */ + fragment = 0; } - /* write the header */ - - *(p++) = type & 0xff; - wr->type = type; - - /* Some servers hang if initial ClientHello is larger than 256 bytes and - * record version number > TLS 1.0. */ - if (!s->s3->have_version && s->version > SSL3_VERSION) { - *(p++) = TLS1_VERSION >> 8; - *(p++) = TLS1_VERSION & 0xff; + /* 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 { - *(p++) = s->version >> 8; - *(p++) = s->version & 0xff; + align = (uintptr_t)wb->buf + SSL3_RT_HEADER_LENGTH; } - - /* field where we are to write out packet length */ - plen = p; - p += 2; - - /* Leave room for the variable nonce for AEADs which specify it explicitly. */ - if (s->aead_write_ctx != NULL && - s->aead_write_ctx->variable_nonce_included_in_record) { - eivlen = s->aead_write_ctx->variable_nonce_len; - } - - /* lets setup the record stuff. */ - wr->data = p + eivlen; - wr->length = (int)(len - (fragment != 0)); - wr->input = (uint8_t *)buf + (fragment != 0); - - /* we now 'read' from wr->input, wr->length bytes into wr->data */ - - memcpy(wr->data, wr->input, wr->length); - wr->input = wr->data; - - /* we should still have the output to wr->data and the input from wr->input. - * Length should be wr->length. wr->data still points in the wb->buf */ - - wr->input = p; - wr->data = p; - wr->length += eivlen; - - if (!s->enc_method->enc(s, 1)) { - goto err; - } - - /* record length after mac and block padding */ - s2n(wr->length, plen); - - if (s->msg_callback) { - s->msg_callback(1, 0, SSL3_RT_HEADER, plen - 5, 5, s, s->msg_callback_arg); + 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--; } - /* we should now have wr->data pointing to the encrypted data, which is - * wr->length long. */ - wr->type = type; /* not needed but helps for debugging */ - wr->length += SSL3_RT_HEADER_LENGTH; - - if (is_fragment) { - /* we are in a recursive call; just return the length, don't write out - * anything. */ - return wr->length; + assert((((uintptr_t)out + SSL3_RT_HEADER_LENGTH) & (SSL3_ALIGN_PAYLOAD - 1)) + == 0); + size_t ciphertext_len; + if (!ssl3_seal_record(s, out, &ciphertext_len, max_out, type, buf, len)) { + return -1; } + ciphertext_len += fragment_len; /* now let's set up wb */ - wb->left = prefix_len + wr->length; + 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); - -err: - return -1; + return ssl3_write_pending(s, type, orig_buf, orig_len); } /* if s->s3->wbuf.left != 0, we need to call this */ @@ -679,19 +662,19 @@ int ssl3_write_pending(SSL *s, int type, const uint8_t *buf, unsigned int len) { if (i == wb->left) { wb->left = 0; wb->offset += i; - if (s->mode & SSL_MODE_RELEASE_BUFFERS && !SSL_IS_DTLS(s)) { - ssl3_release_write_buffer(s); - } + 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 */ + /* 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; } @@ -741,15 +724,10 @@ int ssl3_expect_change_cipher_spec(SSL *s) { * none of our business */ int ssl3_read_bytes(SSL *s, int type, uint8_t *buf, int len, int peek) { - int al, i, j, ret; + int al, i, ret; unsigned int n; SSL3_RECORD *rr; void (*cb)(const SSL *ssl, int type2, int val) = NULL; - uint8_t alert_buffer[2]; - - if (s->s3->rbuf.buf == NULL && !ssl3_setup_read_buffer(s)) { - return -1; - } if ((type && type != SSL3_RT_APPLICATION_DATA && type != SSL3_RT_HANDSHAKE) || (peek && type != SSL3_RT_APPLICATION_DATA)) { @@ -780,8 +758,13 @@ int ssl3_read_bytes(SSL *s, int type, uint8_t *buf, int len, int peek) { /* Now s->s3->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */ - if (!s->in_handshake && SSL_in_init(s)) { - /* type == SSL3_RT_APPLICATION_DATA */ + /* This may require multiple iterations. False Start will cause + * |s->handshake_func| to signal success one step early, but the handshake + * must be completely finished before other modes are accepted. + * + * TODO(davidben): Move this check up to a higher level. */ + while (!s->in_handshake && SSL_in_init(s)) { + assert(type == SSL3_RT_APPLICATION_DATA); i = s->handshake_func(s); if (i < 0) { return i; @@ -811,9 +794,10 @@ start: /* we now have a packet which can be read and processed */ - if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec, - * reset by ssl3_get_finished */ - && rr->type != SSL3_RT_HANDSHAKE) { + /* |change_cipher_spec is set when we receive a ChangeCipherSpec and reset by + * ssl3_get_finished. */ + 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, ssl3_read_bytes, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED); @@ -866,7 +850,7 @@ start: if (rr->length == 0) { s->rstate = SSL_ST_READ_HEADER; rr->off = 0; - if (s->mode & SSL_MODE_RELEASE_BUFFERS && s->s3->rbuf.left == 0) { + if (s->s3->rbuf.left == 0) { ssl3_release_read_buffer(s); } } @@ -883,6 +867,14 @@ start: * that we can process the data at a fixed place. */ if (rr->type == SSL3_RT_HANDSHAKE) { + /* If peer renegotiations are disabled, all out-of-order handshake records + * are fatal. */ + if (s->reject_peer_renegotiations) { + al = SSL_AD_NO_RENEGOTIATION; + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_NO_RENEGOTIATION); + goto f_err; + } + const size_t size = sizeof(s->s3->handshake_fragment); const size_t avail = size - s->s3->handshake_fragment_len; const size_t todo = (rr->length < avail) ? rr->length : avail; @@ -894,17 +886,6 @@ start: if (s->s3->handshake_fragment_len < size) { goto start; /* fragment was too small */ } - } else if (rr->type == SSL3_RT_ALERT) { - /* Note that this will still allow multiple alerts to be processed in the - * same record */ - if (rr->length < sizeof(alert_buffer)) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_BAD_ALERT); - goto f_err; - } - memcpy(alert_buffer, &rr->data[rr->off], sizeof(alert_buffer)); - rr->off += sizeof(alert_buffer); - rr->length -= sizeof(alert_buffer); } /* s->s3->handshake_fragment_len == 4 iff rr->type == SSL3_RT_HANDSHAKE; @@ -947,14 +928,23 @@ start: goto start; } + /* If an alert record, process one alert out of the record. Note that we allow + * a single record to contain multiple alerts. */ if (rr->type == SSL3_RT_ALERT) { - const uint8_t alert_level = alert_buffer[0]; - const uint8_t alert_descr = alert_buffer[1]; + /* Alerts may not be fragmented. */ + if (rr->length < 2) { + al = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_BAD_ALERT); + goto f_err; + } if (s->msg_callback) { - s->msg_callback(0, s->version, SSL3_RT_ALERT, alert_buffer, 2, s, + s->msg_callback(0, s->version, SSL3_RT_ALERT, &rr->data[rr->off], 2, s, s->msg_callback_arg); } + const uint8_t alert_level = rr->data[rr->off++]; + const uint8_t alert_descr = rr->data[rr->off++]; + rr->length -= 2; if (s->info_callback != NULL) { cb = s->info_callback; @@ -963,12 +953,11 @@ start: } if (cb != NULL) { - j = (alert_level << 8) | alert_descr; - cb(s, SSL_CB_READ_ALERT, j); + uint16_t alert = (alert_level << 8) | alert_descr; + cb(s, SSL_CB_READ_ALERT, alert); } - if (alert_level == 1) { - /* warning */ + if (alert_level == SSL3_AL_WARNING) { s->s3->warn_alert = alert_descr; if (alert_descr == SSL_AD_CLOSE_NOTIFY) { s->shutdown |= SSL_RECEIVED_SHUTDOWN; @@ -987,8 +976,7 @@ start: OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_NO_RENEGOTIATION); goto f_err; } - } else if (alert_level == 2) { - /* fatal */ + } else if (alert_level == SSL3_AL_FATAL) { char tmp[16]; s->rwstate = SSL_NOTHING; @@ -1074,50 +1062,12 @@ start: goto start; } - switch (rr->type) { - default: - /* TLS up to v1.1 just ignores unknown message types. TLS v1.2 gives an - * unexpected message alert. */ - if (s->version >= TLS1_VERSION && s->version <= TLS1_1_VERSION) { - rr->length = 0; - goto start; - } - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_UNEXPECTED_RECORD); - goto f_err; - - case SSL3_RT_CHANGE_CIPHER_SPEC: - case SSL3_RT_ALERT: - case SSL3_RT_HANDSHAKE: - /* we already handled all of these, with the possible exception of - * SSL3_RT_HANDSHAKE when s->in_handshake is set, but that should not - * happen when type != rr->type */ - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, ERR_R_INTERNAL_ERROR); - goto f_err; + /* We already handled these. */ + assert(rr->type != SSL3_RT_CHANGE_CIPHER_SPEC && rr->type != SSL3_RT_ALERT && + rr->type != SSL3_RT_HANDSHAKE); - case SSL3_RT_APPLICATION_DATA: - /* At this point we were expecting handshake data but have application - * data. If the library was running inside ssl3_read() (i.e. - * |in_read_app_data| is set) and it makes sense to read application data - * at this point (session renegotiation not yet started), we will indulge - * it. */ - if (s->s3->in_read_app_data && s->s3->total_renegotiations != 0 && - (((s->state & SSL_ST_CONNECT) && - s->state >= SSL3_ST_CW_CLNT_HELLO_A && - s->state <= SSL3_ST_CR_SRVR_HELLO_A) || - ((s->state & SSL_ST_ACCEPT) && - s->state <= SSL3_ST_SW_HELLO_REQ_A && - s->state >= SSL3_ST_SR_CLNT_HELLO_A))) { - s->s3->in_read_app_data = 2; - return -1; - } else { - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_UNEXPECTED_RECORD); - goto f_err; - } - } - /* not reached */ + al = SSL_AD_UNEXPECTED_MESSAGE; + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_UNEXPECTED_RECORD); f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); @@ -1189,7 +1139,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, 0, 0); + 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 b346d14..3cc3032 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. */ -#define NETSCAPE_HANG_BUG - #include #include #include @@ -159,6 +157,7 @@ #include #include #include +#include #include #include #include @@ -168,7 +167,7 @@ #include #include -#include "ssl_locl.h" +#include "internal.h" #include "../crypto/internal.h" #include "../crypto/dh/internal.h" @@ -179,7 +178,7 @@ int ssl3_accept(SSL *s) { BUF_MEM *buf = NULL; - unsigned long alg_a; + uint32_t alg_a; void (*cb)(const SSL *ssl, int type, int val) = NULL; int ret = -1; int new_state, state, skip = 0; @@ -228,11 +227,6 @@ int ssl3_accept(SSL *s) { } s->init_num = 0; - if (!ssl3_setup_buffers(s)) { - ret = -1; - goto end; - } - if (!s->s3->send_connection_binding && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) { /* Server attempting to renegotiate with client that doesn't support @@ -244,7 +238,6 @@ int ssl3_accept(SSL *s) { goto end; } - s->ctx->stats.sess_accept_renegotiate++; s->state = SSL3_ST_SW_HELLO_REQ_A; break; @@ -278,6 +271,15 @@ int ssl3_accept(SSL *s) { cb(s, SSL_CB_HANDSHAKE_START, 1); } + if ((s->version >> 8) != 3) { + /* TODO(davidben): Some consumers clear |s->version| to break the + * handshake in a callback. Remove this when they're using proper + * APIs. */ + OPENSSL_PUT_ERROR(SSL, ssl3_accept, ERR_R_INTERNAL_ERROR); + ret = -1; + goto end; + } + if (s->init_buf == NULL) { buf = BUF_MEM_new(); if (!buf || !BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { @@ -289,6 +291,13 @@ int ssl3_accept(SSL *s) { } s->init_num = 0; + /* Enable a write buffer. This groups handshake messages within a flight + * into a single write. */ + if (!ssl_init_wbio_buffer(s, 1)) { + ret = -1; + goto end; + } + if (!ssl3_init_finished_mac(s)) { OPENSSL_PUT_ERROR(SSL, ssl3_accept, ERR_R_INTERNAL_ERROR); ret = -1; @@ -296,22 +305,10 @@ int ssl3_accept(SSL *s) { } if (!s->s3->have_version) { - /* This is the initial handshake. The record layer has not been - * initialized yet. Sniff for a V2ClientHello before reading a - * ClientHello normally. */ - assert(s->s3->rbuf.buf == NULL); - assert(s->s3->wbuf.buf == NULL); s->state = SSL3_ST_SR_INITIAL_BYTES; } else { - /* Enable a write buffer. This groups handshake messages within a - * flight into a single write. */ - if (!ssl3_setup_buffers(s) || !ssl_init_wbio_buffer(s, 1)) { - ret = -1; - goto end; - } s->state = SSL3_ST_SR_CLNT_HELLO_A; } - s->ctx->stats.sess_accept++; break; case SSL3_ST_SR_INITIAL_BYTES: @@ -337,14 +334,6 @@ int ssl3_accept(SSL *s) { case SSL3_ST_SR_CLNT_HELLO_D: s->shutdown = 0; ret = ssl3_get_client_hello(s); - if (ret == PENDING_SESSION) { - s->rwstate = SSL_PENDING_SESSION; - goto end; - } - if (ret == CERTIFICATE_SELECTION_PENDING) { - s->rwstate = SSL_CERTIFICATE_SELECTION_PENDING; - goto end; - } if (ret <= 0) { goto end; } @@ -404,8 +393,9 @@ int ssl3_accept(SSL *s) { if (ssl_cipher_requires_server_key_exchange(s->s3->tmp.new_cipher) || ((alg_a & SSL_aPSK) && s->psk_identity_hint)) { ret = ssl3_send_server_key_exchange(s); - if (ret <= 0) + if (ret <= 0) { goto end; + } } else { skip = 1; } @@ -425,13 +415,6 @@ int ssl3_accept(SSL *s) { * don't request cert during re-negotiation: */ ((s->session->peer != NULL) && (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) || - /* never request cert in anonymous ciphersuites - * (see section "Certificate request" in SSL 3 drafts - * and in RFC 2246): */ - ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) && - /* ... except when the application insists on verification - * (against the specs, but s3_clnt.c accepts this for SSL 3) */ - !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) || /* With normal PSK Certificates and * Certificate Requests are omitted */ (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { @@ -449,14 +432,7 @@ int ssl3_accept(SSL *s) { if (ret <= 0) { goto end; } -#ifndef NETSCAPE_HANG_BUG s->state = SSL3_ST_SW_SRVR_DONE_A; -#else - /* ServerHelloDone was already sent in the - * previous record. */ - s->state = SSL3_ST_SW_FLUSH; - s->s3->tmp.next_state = SSL3_ST_SR_CERT_A; -#endif s->init_num = 0; } break; @@ -659,7 +635,7 @@ int ssl3_accept(SSL *s) { /* If we aren't retaining peer certificates then we can discard it * now. */ - if (s->session->peer && s->ctx->retain_only_sha256_of_client_certs) { + if (s->ctx->retain_only_sha256_of_client_certs) { X509_free(s->session->peer); s->session->peer = NULL; } @@ -671,8 +647,6 @@ int ssl3_accept(SSL *s) { ssl_update_cache(s, SSL_SESS_CACHE_SERVER); - s->ctx->stats.sess_accept_good++; - if (cb != NULL) { cb(s, SSL_CB_HANDSHAKE_DONE, 1); } @@ -698,9 +672,7 @@ int ssl3_accept(SSL *s) { end: s->in_handshake--; - if (buf != NULL) { - BUF_MEM_free(buf); - } + BUF_MEM_free(buf); if (cb != NULL) { cb(s, SSL_CB_ACCEPT_EXIT, ret); } @@ -770,10 +742,12 @@ int ssl3_get_initial_bytes(SSL *s) { 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_buffers(s) || !ssl_init_wbio_buffer(s, 1)) { + 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; @@ -829,7 +803,10 @@ int ssl3_get_v2_client_hello(SSL *s) { /* The V2ClientHello without the length is incorporated into the Finished * hash. */ - ssl3_finish_mac(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) { s->msg_callback(0, SSL2_VERSION, 0, CBS_data(&v2_client_hello), CBS_len(&v2_client_hello), s, s->msg_callback_arg); @@ -913,11 +890,6 @@ int ssl3_get_v2_client_hello(SSL *s) { /* The handshake message header is 4 bytes. */ s->s3->tmp.message_size = len - 4; - /* Initialize the record layer. */ - if (!ssl3_setup_buffers(s) || !ssl_init_wbio_buffer(s, 1)) { - return -1; - } - /* Drop the sniff buffer. */ BUF_MEM_free(s->s3->sniff_buffer); s->s3->sniff_buffer = NULL; @@ -928,7 +900,9 @@ int ssl3_get_v2_client_hello(SSL *s) { int ssl3_send_hello_request(SSL *s) { if (s->state == SSL3_ST_SW_HELLO_REQ_A) { - ssl_set_handshake_header(s, SSL3_MT_HELLO_REQUEST, 0); + if (!ssl_set_handshake_header(s, SSL3_MT_HELLO_REQUEST, 0)) { + return -1; + } s->state = SSL3_ST_SW_HELLO_REQ_B; } @@ -956,31 +930,12 @@ int ssl3_get_client_hello(SSL *s) { n = s->method->ssl_get_message( s, SSL3_ST_SR_CLNT_HELLO_A, SSL3_ST_SR_CLNT_HELLO_B, SSL3_MT_CLIENT_HELLO, SSL3_RT_MAX_PLAIN_LENGTH, - SSL_GET_MESSAGE_HASH_MESSAGE, &ok); + ssl_hash_message, &ok); if (!ok) { return n; } - /* If we require cookies and this ClientHello doesn't contain one, just - * return since we do not want to allocate any memory yet. So check - * cookie length... */ - if (SSL_IS_DTLS(s) && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE)) { - uint8_t cookie_length; - - CBS_init(&client_hello, s->init_msg, n); - if (!CBS_skip(&client_hello, 2 + SSL3_RANDOM_SIZE) || - !CBS_get_u8_length_prefixed(&client_hello, &session_id) || - !CBS_get_u8(&client_hello, &cookie_length)) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_DECODE_ERROR); - goto f_err; - } - - if (cookie_length == 0) { - return 1; - } - } s->state = SSL3_ST_SR_CLNT_HELLO_C; /* fallthrough */ case SSL3_ST_SR_CLNT_HELLO_C: @@ -1006,7 +961,8 @@ int ssl3_get_client_hello(SSL *s) { s->state = SSL3_ST_SR_CLNT_HELLO_D; switch (s->ctx->select_certificate_cb(&early_ctx)) { case 0: - return CERTIFICATE_SELECTION_PENDING; + s->rwstate = SSL_CERTIFICATE_SELECTION_PENDING; + goto err; case -1: /* Connection rejected. */ @@ -1053,27 +1009,6 @@ int ssl3_get_client_hello(SSL *s) { OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_DECODE_ERROR); goto f_err; } - - /* Verify the cookie if appropriate option is set. */ - if ((SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) && CBS_len(&cookie) > 0) { - if (s->ctx->app_verify_cookie_cb != NULL) { - if (s->ctx->app_verify_cookie_cb(s, CBS_data(&cookie), - CBS_len(&cookie)) == 0) { - al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_COOKIE_MISMATCH); - goto f_err; - } - /* else cookie verification succeeded */ - } else if (!CBS_mem_equal(&cookie, s->d1->cookie, s->d1->cookie_len)) { - /* default verification */ - al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_COOKIE_MISMATCH); - goto f_err; - } - /* Set to -2 so if successful we return 2 and don't send - * HelloVerifyRequest. */ - ret = -2; - } } if (!s->s3->have_version) { @@ -1118,7 +1053,7 @@ int ssl3_get_client_hello(SSL *s) { } else { i = ssl_get_prev_session(s, &early_ctx); if (i == PENDING_SESSION) { - ret = PENDING_SESSION; + s->rwstate = SSL_PENDING_SESSION; goto err; } else if (i == -1) { goto err; @@ -1136,7 +1071,16 @@ int ssl3_get_client_hello(SSL *s) { } } + 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, ssl3_get_client_hello, SSL_R_CONNECTION_REJECTED); + goto f_err; + } + if (!CBS_get_u16_length_prefixed(&client_hello, &cipher_suites) || + CBS_len(&cipher_suites) == 0 || + CBS_len(&cipher_suites) % 2 != 0 || !CBS_get_u8_length_prefixed(&client_hello, &compression_methods) || CBS_len(&compression_methods) == 0) { al = SSL_AD_DECODE_ERROR; @@ -1144,28 +1088,16 @@ int ssl3_get_client_hello(SSL *s) { goto f_err; } - /* TODO(davidben): Per spec, cipher_suites can never be empty (specified at - * the ClientHello structure level). This logic allows it to be empty if - * resuming a session. Can we always require non-empty? If a client sends - * empty cipher_suites because it's resuming a session, it could always fail - * to resume a session, so it's unlikely to actually work. */ - if (CBS_len(&cipher_suites) == 0 && CBS_len(&session_id) != 0) { - /* We need a cipher if we are not resuming a session. */ - al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_NO_CIPHERS_SPECIFIED); - goto f_err; - } - ciphers = ssl_bytes_to_cipher_list(s, &cipher_suites); if (ciphers == NULL) { goto err; } /* If it is a hit, check that the cipher is in the list. */ - if (s->hit && CBS_len(&cipher_suites) > 0) { + if (s->hit) { size_t j; int found_cipher = 0; - unsigned long id = s->session->cipher->id; + uint32_t id = s->session->cipher->id; for (j = 0; j < sk_SSL_CIPHER_num(ciphers); j++) { c = sk_SSL_CIPHER_value(ciphers, j); @@ -1269,9 +1201,7 @@ int ssl3_get_client_hello(SSL *s) { } err: - if (ciphers != NULL) { - sk_SSL_CIPHER_free(ciphers); - } + sk_SSL_CIPHER_free(ciphers); return ret; } @@ -1285,7 +1215,7 @@ int ssl3_send_server_hello(SSL *s) { /* We only accept ChannelIDs on connections with ECDHE in order to avoid a * known attack while we fix ChannelID itself. */ if (s->s3->tlsext_channel_id_valid && - (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kEECDH) == 0) { + (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kECDHE) == 0) { s->s3->tlsext_channel_id_valid = 0; } @@ -1354,7 +1284,9 @@ int ssl3_send_server_hello(SSL *s) { /* do the header */ l = (p - d); - ssl_set_handshake_header(s, SSL3_MT_SERVER_HELLO, l); + if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_HELLO, l)) { + return -1; + } s->state = SSL3_ST_SW_SRVR_HELLO_B; } @@ -1364,7 +1296,9 @@ int ssl3_send_server_hello(SSL *s) { int ssl3_send_server_done(SSL *s) { if (s->state == SSL3_ST_SW_SRVR_DONE_A) { - ssl_set_handshake_header(s, SSL3_MT_SERVER_DONE, 0); + if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_DONE, 0)) { + return -1; + } s->state = SSL3_ST_SW_SRVR_DONE_B; } @@ -1374,7 +1308,7 @@ int ssl3_send_server_done(SSL *s) { int ssl3_send_server_key_exchange(SSL *s) { DH *dh = NULL, *dhp; - EC_KEY *ecdh = NULL, *ecdhp; + EC_KEY *ecdh = NULL; uint8_t *encodedPoint = NULL; int encodedlen = 0; uint16_t curve_id = 0; @@ -1384,8 +1318,8 @@ int ssl3_send_server_key_exchange(SSL *s) { EVP_PKEY *pkey; uint8_t *p, *d; int al, i; - unsigned long alg_k; - unsigned long alg_a; + uint32_t alg_k; + uint32_t alg_a; int n; CERT *cert; BIGNUM *r[4]; @@ -1414,7 +1348,7 @@ int ssl3_send_server_key_exchange(SSL *s) { n += 2 + psk_identity_hint_len; } - if (alg_k & SSL_kEDH) { + if (alg_k & SSL_kDHE) { dhp = cert->dh_tmp; if (dhp == NULL && s->cert->dh_tmp_cb != NULL) { dhp = s->cert->dh_tmp_cb(s, 0, 1024); @@ -1431,46 +1365,37 @@ int ssl3_send_server_key_exchange(SSL *s) { ERR_R_INTERNAL_ERROR); goto err; } - dh = DHparams_dup(dhp); if (dh == NULL) { OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_DH_LIB); goto err; } - s->s3->tmp.dh = dh; - if (dhp->pub_key == NULL || dhp->priv_key == NULL || - (s->options & SSL_OP_SINGLE_DH_USE)) { - if (!DH_generate_key(dh)) { - OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_DH_LIB); - goto err; - } - } else { - dh->pub_key = BN_dup(dhp->pub_key); - dh->priv_key = BN_dup(dhp->priv_key); - if (dh->pub_key == NULL || dh->priv_key == NULL) { - OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_DH_LIB); - goto err; - } + + if (!DH_generate_key(dh)) { + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_DH_LIB); + goto err; } r[0] = dh->p; r[1] = dh->g; r[2] = dh->pub_key; - } else if (alg_k & SSL_kEECDH) { - const EC_GROUP *group; - - ecdhp = cert->ecdh_tmp; - if (s->cert->ecdh_tmp_auto) { - /* Get NID of appropriate shared curve */ - int nid = tls1_get_shared_curve(s); - if (nid != NID_undef) { - ecdhp = EC_KEY_new_by_curve_name(nid); + } else if (alg_k & SSL_kECDHE) { + /* Determine the curve to use. */ + int nid = NID_undef; + if (cert->ecdh_nid != NID_undef) { + nid = cert->ecdh_nid; + } else if (cert->ecdh_tmp_cb != NULL) { + /* Note: |ecdh_tmp_cb| does NOT pass ownership of the result + * to the caller. */ + EC_KEY *template = s->cert->ecdh_tmp_cb(s, 0, 1024); + if (template != NULL && EC_KEY_get0_group(template) != NULL) { + nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(template)); } - } else if (ecdhp == NULL && s->cert->ecdh_tmp_cb) { - ecdhp = s->cert->ecdh_tmp_cb(s, 0, 1024); + } else { + nid = tls1_get_shared_curve(s); } - if (ecdhp == NULL) { + if (nid == NID_undef) { al = SSL_AD_HANDSHAKE_FAILURE; OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, SSL_R_MISSING_TMP_ECDH_KEY); @@ -1482,42 +1407,19 @@ int ssl3_send_server_key_exchange(SSL *s) { ERR_R_INTERNAL_ERROR); goto err; } - - /* Duplicate the ECDH structure. */ - if (ecdhp == NULL) { - OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_ECDH_LIB); + ecdh = EC_KEY_new_by_curve_name(nid); + if (ecdh == NULL) { goto err; } - - if (s->cert->ecdh_tmp_auto) { - ecdh = ecdhp; - } else { - ecdh = EC_KEY_dup(ecdhp); - if (ecdh == NULL) { - OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_ECDH_LIB); - goto err; - } - } - s->s3->tmp.ecdh = ecdh; - if (EC_KEY_get0_public_key(ecdh) == NULL || - EC_KEY_get0_private_key(ecdh) == NULL || - (s->options & SSL_OP_SINGLE_ECDH_USE)) { - if (!EC_KEY_generate_key(ecdh)) { - OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_ECDH_LIB); - goto err; - } - } - group = EC_KEY_get0_group(ecdh); - if (group == NULL || - EC_KEY_get0_public_key(ecdh) == NULL || - EC_KEY_get0_private_key(ecdh) == NULL) { + if (!EC_KEY_generate_key(ecdh)) { 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, ssl3_send_server_key_exchange, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE); @@ -1597,7 +1499,7 @@ int ssl3_send_server_key_exchange(SSL *s) { p += nr[i]; } - /* Note: ECDHE PSK ciphersuites use SSL_kEECDH and SSL_aPSK. When one of + /* Note: ECDHE PSK ciphersuites use SSL_kECDHE and SSL_aPSK. When one of * them is used, the server key exchange record needs to have both the * psk_identity_hint and the ServerECDHParams. */ if (alg_a & SSL_aPSK) { @@ -1609,7 +1511,7 @@ int ssl3_send_server_key_exchange(SSL *s) { } } - if (alg_k & SSL_kEECDH) { + if (alg_k & SSL_kECDHE) { /* We only support named (not generic) curves. In this situation, the * serverKeyExchange message has: * [1 byte CurveType], [2 byte CurveName] @@ -1667,7 +1569,9 @@ int ssl3_send_server_key_exchange(SSL *s) { } } - ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE, n); + if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE, n)) { + goto err; + } } s->state = SSL3_ST_SW_KEY_EXCH_B; @@ -1677,9 +1581,7 @@ int ssl3_send_server_key_exchange(SSL *s) { f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); err: - if (encodedPoint != NULL) { - OPENSSL_free(encodedPoint); - } + OPENSSL_free(encodedPoint); BN_CTX_free(bn_ctx); EVP_MD_CTX_cleanup(&md_ctx); return -1; @@ -1740,27 +1642,9 @@ int ssl3_send_certificate_request(SSL *s) { p = ssl_handshake_start(s) + off; s2n(nl, p); - ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_REQUEST, n); - -#ifdef NETSCAPE_HANG_BUG - if (!SSL_IS_DTLS(s)) { - /* Prepare a ServerHelloDone in the same record. This is to workaround a - * hang in Netscape. */ - if (!BUF_MEM_grow_clean(buf, s->init_num + 4)) { - OPENSSL_PUT_ERROR(SSL, ssl3_send_certificate_request, ERR_R_BUF_LIB); - goto err; - } - p = (uint8_t *)s->init_buf->data + s->init_num; - /* do the header */ - *(p++) = SSL3_MT_SERVER_DONE; - *(p++) = 0; - *(p++) = 0; - *(p++) = 0; - s->init_num += 4; - ssl3_finish_mac(s, p - 4, 4); + if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_REQUEST, n)) { + goto err; } -#endif - s->state = SSL3_ST_SW_CERT_REQ_B; } @@ -1775,8 +1659,8 @@ int ssl3_get_client_key_exchange(SSL *s) { int al, ok; long n; CBS client_key_exchange; - unsigned long alg_k; - unsigned long alg_a; + uint32_t alg_k; + uint32_t alg_a; uint8_t *premaster_secret = NULL; size_t premaster_secret_len = 0; RSA *rsa = NULL; @@ -1795,7 +1679,7 @@ int ssl3_get_client_key_exchange(SSL *s) { n = s->method->ssl_get_message(s, SSL3_ST_SR_KEY_EXCH_A, SSL3_ST_SR_KEY_EXCH_B, SSL3_MT_CLIENT_KEY_EXCHANGE, 2048, /* ??? */ - SSL_GET_MESSAGE_HASH_MESSAGE, &ok); + ssl_hash_message, &ok); if (!ok) { return n; @@ -1983,7 +1867,7 @@ int ssl3_get_client_key_exchange(SSL *s) { } premaster_secret_len = sizeof(rand_premaster_secret); - } else if (alg_k & SSL_kEDH) { + } else if (alg_k & SSL_kDHE) { CBS dh_Yc; int dh_len; @@ -2014,6 +1898,7 @@ int ssl3_get_client_key_exchange(SSL *s) { if (premaster_secret == NULL) { OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_MALLOC_FAILURE); + BN_clear_free(pub); goto err; } @@ -2030,7 +1915,7 @@ int ssl3_get_client_key_exchange(SSL *s) { pub = NULL; premaster_secret_len = dh_len; - } else if (alg_k & SSL_kEECDH) { + } else if (alg_k & SSL_kECDHE) { int field_size = 0, ecdh_len; const EC_KEY *tkey; const EC_GROUP *group; @@ -2191,14 +2076,10 @@ err: } OPENSSL_free(premaster_secret); } - if (decrypt_buf) { - OPENSSL_free(decrypt_buf); - } + OPENSSL_free(decrypt_buf); EVP_PKEY_free(clnt_pub_pkey); EC_POINT_free(clnt_ecpoint); - if (srvr_ecdh != NULL) { - EC_KEY_free(srvr_ecdh); - } + EC_KEY_free(srvr_ecdh); BN_CTX_free(bn_ctx); return -1; @@ -2229,7 +2110,7 @@ int ssl3_get_cert_verify(SSL *s) { n = s->method->ssl_get_message( s, SSL3_ST_SR_CERT_VRFY_A, SSL3_ST_SR_CERT_VRFY_B, SSL3_MT_CERTIFICATE_VERIFY, SSL3_RT_MAX_PLAIN_LENGTH, - SSL_GET_MESSAGE_DONT_HASH_MESSAGE, &ok); + ssl_dont_hash_message, &ok); if (!ok) { return n; @@ -2237,6 +2118,9 @@ int ssl3_get_cert_verify(SSL *s) { /* Filter out unsupported certificate types. */ pkey = X509_get_pubkey(peer); + if (pkey == NULL) { + goto err; + } if (!(X509_certificate_type(peer, pkey) & EVP_PKT_SIGN) || (pkey->type != EVP_PKEY_RSA && pkey->type != EVP_PKEY_EC)) { al = SSL_AD_UNSUPPORTED_CERTIFICATE; @@ -2264,7 +2148,9 @@ int ssl3_get_cert_verify(SSL *s) { !ssl3_digest_cached_records(s, free_handshake_buffer)) { goto err; } - ssl3_hash_current_message(s); + if (!ssl3_hash_current_message(s)) { + goto err; + } /* Parse and verify the signature. */ if (!CBS_get_u16_length_prefixed(&certificate_verify, &signature) || @@ -2311,8 +2197,7 @@ int ssl3_get_client_certificate(SSL *s) { int is_first_certificate = 1; n = s->method->ssl_get_message(s, SSL3_ST_SR_CERT_A, SSL3_ST_SR_CERT_B, -1, - s->max_cert_list, SSL_GET_MESSAGE_HASH_MESSAGE, - &ok); + (long)s->max_cert_list, ssl_hash_message, &ok); if (!ok) { return n; @@ -2433,11 +2318,7 @@ int ssl3_get_client_certificate(SSL *s) { } } - if (s->session->peer != NULL) { - /* This should not be needed */ - X509_free(s->session->peer); - } - + X509_free(s->session->peer); s->session->peer = sk_X509_shift(sk); s->session->verify_result = s->verify_result; @@ -2450,9 +2331,7 @@ int ssl3_get_client_certificate(SSL *s) { goto err; } } - if (s->session->sess_cert->cert_chain != NULL) { - sk_X509_pop_free(s->session->sess_cert->cert_chain, X509_free); - } + 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 */ @@ -2467,12 +2346,8 @@ int ssl3_get_client_certificate(SSL *s) { } err: - if (x != NULL) { - X509_free(x); - } - if (sk != NULL) { - sk_X509_pop_free(sk, X509_free); - } + X509_free(x); + sk_X509_pop_free(sk, X509_free); return ret; } @@ -2487,7 +2362,9 @@ int ssl3_send_server_certificate(SSL *s) { return 0; } - ssl3_output_cert_chain(s, cpk); + if (!ssl3_output_cert_chain(s, cpk)) { + return 0; + } s->state = SSL3_ST_SW_CERT_B; } @@ -2497,14 +2374,19 @@ int ssl3_send_server_certificate(SSL *s) { /* send a new session ticket (not necessarily for a new session) */ int ssl3_send_new_session_ticket(SSL *s) { + int ret = -1; + uint8_t *session = NULL; + size_t session_len; + EVP_CIPHER_CTX ctx; + HMAC_CTX hctx; + + EVP_CIPHER_CTX_init(&ctx); + HMAC_CTX_init(&hctx); + if (s->state == SSL3_ST_SW_SESSION_TICKET_A) { - uint8_t *session; - size_t session_len; uint8_t *p, *macstart; int len; unsigned int hlen; - EVP_CIPHER_CTX ctx; - HMAC_CTX hctx; SSL_CTX *tctx = s->initial_ctx; uint8_t iv[EVP_MAX_IV_LENGTH]; uint8_t key_name[16]; @@ -2515,7 +2397,7 @@ int ssl3_send_new_session_ticket(SSL *s) { /* Serialize the SSL_SESSION to be encoded into the ticket. */ if (!SSL_SESSION_to_bytes_for_ticket(s->session, &session, &session_len)) { - return -1; + goto err; } /* If the session is too long, emit a dummy value rather than abort the @@ -2525,6 +2407,7 @@ int ssl3_send_new_session_ticket(SSL *s) { const size_t placeholder_len = strlen(kTicketPlaceholder); OPENSSL_free(session); + session = NULL; p = ssl_handshake_start(s); /* Emit ticket_lifetime_hint. */ @@ -2535,7 +2418,9 @@ int ssl3_send_new_session_ticket(SSL *s) { p += placeholder_len; len = p - ssl_handshake_start(s); - ssl_set_handshake_header(s, SSL3_MT_NEWSESSION_TICKET, len); + if (!ssl_set_handshake_header(s, SSL3_MT_NEWSESSION_TICKET, len)) { + goto err; + } s->state = SSL3_ST_SW_SESSION_TICKET_B; return ssl_do_write(s); } @@ -2545,20 +2430,15 @@ int ssl3_send_new_session_ticket(SSL *s) { * max_ticket_overhead + * session_length */ if (!BUF_MEM_grow(s->init_buf, SSL_HM_HEADER_LENGTH(s) + 6 + max_ticket_overhead + session_len)) { - OPENSSL_free(session); - return -1; + goto err; } p = ssl_handshake_start(s); - EVP_CIPHER_CTX_init(&ctx); - HMAC_CTX_init(&hctx); /* Initialize HMAC and cipher contexts. If callback present it does all the * work otherwise use generated values from parent ctx. */ if (tctx->tlsext_ticket_key_cb) { - if (tctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx, &hctx, 1) < 0) { - OPENSSL_free(session); - EVP_CIPHER_CTX_cleanup(&ctx); - HMAC_CTX_cleanup(&hctx); - return -1; + if (tctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx, &hctx, + 1 /* encrypt */) < 0) { + goto err; } } else { if (!RAND_bytes(iv, 16) || @@ -2566,10 +2446,7 @@ int ssl3_send_new_session_ticket(SSL *s) { tctx->tlsext_tick_aes_key, iv) || !HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, tlsext_tick_md(), NULL)) { - OPENSSL_free(session); - EVP_CIPHER_CTX_cleanup(&ctx); - HMAC_CTX_cleanup(&hctx); - return -1; + goto err; } memcpy(key_name, tctx->tlsext_tick_key_name, 16); } @@ -2589,15 +2466,19 @@ int ssl3_send_new_session_ticket(SSL *s) { memcpy(p, iv, EVP_CIPHER_CTX_iv_length(&ctx)); p += EVP_CIPHER_CTX_iv_length(&ctx); /* Encrypt session data */ - EVP_EncryptUpdate(&ctx, p, &len, session, session_len); + if (!EVP_EncryptUpdate(&ctx, p, &len, session, session_len)) { + goto err; + } p += len; - EVP_EncryptFinal_ex(&ctx, p, &len); + if (!EVP_EncryptFinal_ex(&ctx, p, &len)) { + goto err; + } p += len; - EVP_CIPHER_CTX_cleanup(&ctx); - HMAC_Update(&hctx, macstart, p - macstart); - HMAC_Final(&hctx, p, &hlen); - HMAC_CTX_cleanup(&hctx); + if (!HMAC_Update(&hctx, macstart, p - macstart) || + !HMAC_Final(&hctx, p, &hlen)) { + goto err; + } p += hlen; /* Now write out lengths: p points to end of data written */ @@ -2606,13 +2487,20 @@ int ssl3_send_new_session_ticket(SSL *s) { /* Skip ticket lifetime hint */ p = ssl_handshake_start(s) + 4; s2n(len - 6, p); - ssl_set_handshake_header(s, SSL3_MT_NEWSESSION_TICKET, len); + if (!ssl_set_handshake_header(s, SSL3_MT_NEWSESSION_TICKET, len)) { + goto err; + } s->state = SSL3_ST_SW_SESSION_TICKET_B; - OPENSSL_free(session); } /* SSL3_ST_SW_SESSION_TICKET_B */ - return ssl_do_write(s); + ret = ssl_do_write(s); + +err: + OPENSSL_free(session); + EVP_CIPHER_CTX_cleanup(&ctx); + HMAC_CTX_cleanup(&hctx); + return ret; } /* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It @@ -2633,7 +2521,7 @@ int ssl3_get_next_proto(SSL *s) { n = s->method->ssl_get_message(s, SSL3_ST_SR_NEXT_PROTO_A, SSL3_ST_SR_NEXT_PROTO_B, SSL3_MT_NEXT_PROTO, 514, /* See the payload format below */ - SSL_GET_MESSAGE_HASH_MESSAGE, &ok); + ssl_hash_message, &ok); if (!ok) { return n; @@ -2688,7 +2576,7 @@ int ssl3_get_channel_id(SSL *s) { n = s->method->ssl_get_message( s, SSL3_ST_SR_CHANNEL_ID_A, SSL3_ST_SR_CHANNEL_ID_B, SSL3_MT_ENCRYPTED_EXTENSIONS, 2 + 2 + TLSEXT_CHANNEL_ID_SIZE, - SSL_GET_MESSAGE_DONT_HASH_MESSAGE, &ok); + ssl_dont_hash_message, &ok); if (!ok) { return n; @@ -2707,7 +2595,9 @@ int ssl3_get_channel_id(SSL *s) { EVP_MD_CTX_cleanup(&md_ctx); assert(channel_id_hash_len == SHA256_DIGEST_LENGTH); - ssl3_hash_current_message(s); + if (!ssl3_hash_current_message(s)) { + return -1; + } /* s->state doesn't reflect whether ChangeCipherSpec has been received in * this handshake, but s->s3->change_cipher_spec does (will be reset by @@ -2757,6 +2647,9 @@ int ssl3_get_channel_id(SSL *s) { BN_init(&y); sig.r = BN_new(); sig.s = BN_new(); + if (sig.r == NULL || sig.s == NULL) { + goto err; + } p = CBS_data(&extension); if (BN_bin2bn(p + 0, 32, &x) == NULL || @@ -2794,14 +2687,8 @@ err: BN_free(&y); BN_free(sig.r); BN_free(sig.s); - if (key) { - EC_KEY_free(key); - } - if (point) { - EC_POINT_free(point); - } - if (p256) { - EC_GROUP_free(p256); - } + EC_KEY_free(key); + EC_POINT_free(point); + EC_GROUP_free(p256); return ret; } diff --git a/src/ssl/ssl_algs.c b/src/ssl/ssl_algs.c index 6ec88bf..fda39a5 100644 --- a/src/ssl/ssl_algs.c +++ b/src/ssl/ssl_algs.c @@ -54,18 +54,13 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ -#include "ssl_locl.h" +#include "internal.h" #include -extern const ERR_STRING_DATA SSL_error_string_data[]; - int SSL_library_init(void) { CRYPTO_library_init(); - ERR_load_crypto_strings(); - ERR_load_strings(SSL_error_string_data); return 1; } -void SSL_load_error_strings(void) { -} +void SSL_load_error_strings(void) {} diff --git a/src/ssl/ssl_asn1.c b/src/ssl/ssl_asn1.c index d39da87..eb0c725 100644 --- a/src/ssl/ssl_asn1.c +++ b/src/ssl/ssl_asn1.c @@ -85,9 +85,10 @@ #include #include +#include #include -#include "ssl_locl.h" +#include "internal.h" /* An SSL_SESSION is serialized as the following ASN.1 structure: @@ -177,14 +178,14 @@ static int SSL_SESSION_to_bytes_full(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, i2d_SSL_SESSION, 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, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -192,7 +193,7 @@ static int SSL_SESSION_to_bytes_full(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, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -207,7 +208,7 @@ static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data, } if (!CBB_add_asn1(&session, &child, kPeerTag) || !CBB_add_space(&child, &buf, len)) { - OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } if (buf != NULL && i2d_X509(in->peer, &buf) < 0) { @@ -220,14 +221,14 @@ static int SSL_SESSION_to_bytes_full(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, i2d_SSL_SESSION, 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, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -237,7 +238,7 @@ static int SSL_SESSION_to_bytes_full(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, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -247,7 +248,7 @@ static int SSL_SESSION_to_bytes_full(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, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -255,7 +256,7 @@ static int SSL_SESSION_to_bytes_full(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, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -264,7 +265,7 @@ static int SSL_SESSION_to_bytes_full(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, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -273,7 +274,7 @@ static int SSL_SESSION_to_bytes_full(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, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -283,7 +284,7 @@ static int SSL_SESSION_to_bytes_full(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, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -293,7 +294,7 @@ static int SSL_SESSION_to_bytes_full(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, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -302,7 +303,7 @@ static int SSL_SESSION_to_bytes_full(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, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } @@ -311,13 +312,13 @@ static int SSL_SESSION_to_bytes_full(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, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } } if (!CBB_finish(&cbb, out_data, out_len)) { - OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE); goto err; } return 1; @@ -381,7 +382,7 @@ static int d2i_SSL_SESSION_get_string(CBS *cbs, char **out, unsigned tag) { OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, ERR_R_MALLOC_FAILURE); return 0; } - } else if (*out) { + } else { OPENSSL_free(*out); *out = NULL; } @@ -409,7 +410,7 @@ static int d2i_SSL_SESSION_get_octet_string(CBS *cbs, uint8_t **out_ptr, } SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) { - SSL_SESSION *ret = NULL; + SSL_SESSION *ret, *allocated = NULL; CBS 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; @@ -419,8 +420,8 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) { if (a && *a) { ret = *a; } else { - ret = SSL_SESSION_new(); - if (ret == NULL) { + ret = allocated = SSL_SESSION_new(); + if (allocated == NULL) { goto err; } } @@ -525,10 +526,8 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) { ret->time = session_time; ret->timeout = timeout; - if (ret->peer != NULL) { - X509_free(ret->peer); - ret->peer = NULL; - } + X509_free(ret->peer); + ret->peer = NULL; if (has_peer) { const uint8_t *ptr; ptr = CBS_data(&peer); @@ -584,8 +583,6 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) { return ret; err: - if (a && *a != ret) { - SSL_SESSION_free(ret); - } + SSL_SESSION_free(allocated); return NULL; } diff --git a/src/ssl/ssl_cert.c b/src/ssl/ssl_cert.c index 624c41a..770912b 100644 --- a/src/ssl/ssl_cert.c +++ b/src/ssl/ssl_cert.c @@ -112,7 +112,9 @@ * ECC cipher suite support in OpenSSL originally developed by * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. */ +#include #include +#include #include #include @@ -126,7 +128,7 @@ #include "../crypto/dh/internal.h" #include "../crypto/directory.h" -#include "ssl_locl.h" +#include "internal.h" int SSL_get_ex_data_X509_STORE_CTX_idx(void) { @@ -178,7 +180,6 @@ CERT *ssl_cert_dup(CERT *cert) { 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]]; @@ -213,15 +214,8 @@ CERT *ssl_cert_dup(CERT *cert) { } ret->dh_tmp_cb = cert->dh_tmp_cb; - if (cert->ecdh_tmp) { - ret->ecdh_tmp = EC_KEY_dup(cert->ecdh_tmp); - if (ret->ecdh_tmp == NULL) { - OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_EC_LIB); - goto err; - } - } + ret->ecdh_nid = cert->ecdh_nid; ret->ecdh_tmp_cb = cert->ecdh_tmp_cb; - ret->ecdh_tmp_auto = cert->ecdh_tmp_auto; for (i = 0; i < SSL_PKEY_NUM; i++) { CERT_PKEY *cpk = cert->pkeys + i; @@ -231,7 +225,7 @@ CERT *ssl_cert_dup(CERT *cert) { } if (cpk->privatekey != NULL) { - rpk->privatekey = EVP_PKEY_dup(cpk->privatekey); + rpk->privatekey = EVP_PKEY_up_ref(cpk->privatekey); } if (cpk->chain) { @@ -243,34 +237,24 @@ CERT *ssl_cert_dup(CERT *cert) { } } - /* Peer sigalgs set to NULL as we get these from handshake too */ - ret->peer_sigalgs = NULL; - ret->peer_sigalgslen = 0; - /* Configured sigalgs however we copy across */ - + /* Copy over signature algorithm configuration. */ if (cert->conf_sigalgs) { - ret->conf_sigalgs = OPENSSL_malloc(cert->conf_sigalgslen); + ret->conf_sigalgs = BUF_memdup(cert->conf_sigalgs, cert->conf_sigalgslen); if (!ret->conf_sigalgs) { goto err; } - memcpy(ret->conf_sigalgs, cert->conf_sigalgs, cert->conf_sigalgslen); ret->conf_sigalgslen = cert->conf_sigalgslen; - } else { - ret->conf_sigalgs = NULL; } if (cert->client_sigalgs) { - ret->client_sigalgs = OPENSSL_malloc(cert->client_sigalgslen); + ret->client_sigalgs = BUF_memdup(cert->client_sigalgs, + cert->client_sigalgslen); if (!ret->client_sigalgs) { goto err; } - memcpy(ret->client_sigalgs, cert->client_sigalgs, cert->client_sigalgslen); ret->client_sigalgslen = cert->client_sigalgslen; - } else { - ret->client_sigalgs = NULL; } - /* Shared sigalgs also NULL */ - ret->shared_sigalgs = NULL; + /* Copy any custom client certificate types */ if (cert->client_certificate_types) { ret->client_certificate_types = BUF_memdup( @@ -281,8 +265,6 @@ CERT *ssl_cert_dup(CERT *cert) { ret->num_client_certificate_types = cert->num_client_certificate_types; } - ret->cert_flags = cert->cert_flags; - ret->cert_cb = cert->cert_cb; ret->cert_cb_arg = cert->cert_cb_arg; @@ -296,8 +278,6 @@ CERT *ssl_cert_dup(CERT *cert) { ret->chain_store = cert->chain_store; } - ret->ciphers_raw = NULL; - return ret; err: @@ -334,79 +314,32 @@ void ssl_cert_free(CERT *c) { return; } - if (c->dh_tmp) { - DH_free(c->dh_tmp); - } - if (c->ecdh_tmp) { - EC_KEY_free(c->ecdh_tmp); - } + DH_free(c->dh_tmp); ssl_cert_clear_certs(c); - if (c->peer_sigalgs) { - OPENSSL_free(c->peer_sigalgs); - } - if (c->conf_sigalgs) { - OPENSSL_free(c->conf_sigalgs); - } - if (c->client_sigalgs) { - OPENSSL_free(c->client_sigalgs); - } - if (c->shared_sigalgs) { - OPENSSL_free(c->shared_sigalgs); - } - if (c->client_certificate_types) { - OPENSSL_free(c->client_certificate_types); - } - if (c->verify_store) { - X509_STORE_free(c->verify_store); - } - if (c->chain_store) { - X509_STORE_free(c->chain_store); - } - if (c->ciphers_raw) { - OPENSSL_free(c->ciphers_raw); - } + OPENSSL_free(c->peer_sigalgs); + 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_inst(CERT **o) { - /* Create a CERT if there isn't already one (which cannot really happen, as - * it is initially created in SSL_CTX_new; but the earlier code usually - * allows for that one being non-existant, so we follow that behaviour, as it - * might turn out that there actually is a reason for it -- but I'm not sure - * that *all* of the existing code could cope with s->cert being NULL, - * otherwise we could do without the initialization in SSL_CTX_new). */ - - if (o == NULL) { - OPENSSL_PUT_ERROR(SSL, ssl_cert_inst, ERR_R_PASSED_NULL_PARAMETER); - return 0; - } - if (*o == NULL) { - *o = ssl_cert_new(); - if (*o == NULL) { - OPENSSL_PUT_ERROR(SSL, ssl_cert_new, ERR_R_MALLOC_FAILURE); - return 0; - } - } - - return 1; -} - -int ssl_cert_set0_chain(CERT *c, STACK_OF(X509) * chain) { +int ssl_cert_set0_chain(CERT *c, STACK_OF(X509) *chain) { CERT_PKEY *cpk = c->key; if (!cpk) { return 0; } - if (cpk->chain) { - sk_X509_pop_free(cpk->chain, X509_free); - } + sk_X509_pop_free(cpk->chain, X509_free); cpk->chain = chain; return 1; } -int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) * chain) { - STACK_OF(X509) * dchain; +int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain) { + STACK_OF(X509) *dchain; if (!chain) { return ssl_cert_set0_chain(c, NULL); } @@ -499,22 +432,14 @@ void ssl_sess_cert_free(SESS_CERT *sc) { return; } - if (sc->cert_chain != NULL) { - sk_X509_pop_free(sc->cert_chain, X509_free); - } + sk_X509_pop_free(sc->cert_chain, X509_free); for (i = 0; i < SSL_PKEY_NUM; i++) { - if (sc->peer_pkeys[i].x509 != NULL) { - X509_free(sc->peer_pkeys[i].x509); - } + X509_free(sc->peer_pkeys[i].x509); } - if (sc->peer_dh_tmp != NULL) { - DH_free(sc->peer_dh_tmp); - } - if (sc->peer_ecdh_tmp != NULL) { - EC_KEY_free(sc->peer_ecdh_tmp); - } + DH_free(sc->peer_dh_tmp); + EC_KEY_free(sc->peer_ecdh_tmp); OPENSSL_free(sc); } @@ -524,7 +449,7 @@ int ssl_set_peer_cert_type(SESS_CERT *sc, int type) { return 1; } -int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) * sk) { +int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk) { X509 *x; int i; X509_STORE *verify_store; @@ -571,18 +496,15 @@ int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) * sk) { return i; } -static void set_client_CA_list(STACK_OF(X509_NAME) * *ca_list, - STACK_OF(X509_NAME) * name_list) { - if (*ca_list != NULL) { - sk_X509_NAME_pop_free(*ca_list, X509_NAME_free); - } - +static void set_client_CA_list(STACK_OF(X509_NAME) **ca_list, + STACK_OF(X509_NAME) *name_list) { + sk_X509_NAME_pop_free(*ca_list, X509_NAME_free); *ca_list = name_list; } -STACK_OF(X509_NAME) * SSL_dup_CA_list(STACK_OF(X509_NAME) * sk) { +STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk) { size_t i; - STACK_OF(X509_NAME) * ret; + STACK_OF(X509_NAME) *ret; X509_NAME *name; ret = sk_X509_NAME_new_null(); @@ -597,19 +519,19 @@ STACK_OF(X509_NAME) * SSL_dup_CA_list(STACK_OF(X509_NAME) * sk) { return ret; } -void SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) * 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) { +void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list) { set_client_CA_list(&(ctx->client_CA), name_list); } -STACK_OF(X509_NAME) * SSL_CTX_get_client_CA_list(const SSL_CTX *ctx) { +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 *s) { +STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s) { if (s->server) { if (s->client_CA != NULL) { return s->client_CA; @@ -625,7 +547,7 @@ STACK_OF(X509_NAME) * SSL_get_client_CA_list(const SSL *s) { } } -static int add_client_CA(STACK_OF(X509_NAME) * *sk, X509 *x) { +static int add_client_CA(STACK_OF(X509_NAME) **sk, X509 *x) { X509_NAME *name; if (x == NULL) { @@ -670,7 +592,7 @@ static int xname_cmp(const X509_NAME **a, const X509_NAME **b) { * * \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) { +STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) { BIO *in; X509 *x = NULL; X509_NAME *xn = NULL; @@ -719,21 +641,13 @@ STACK_OF(X509_NAME) * SSL_load_client_CA_file(const char *file) { if (0) { err: - if (ret != NULL) { - sk_X509_NAME_pop_free(ret, X509_NAME_free); - } + sk_X509_NAME_pop_free(ret, X509_NAME_free); ret = NULL; } - if (sk != NULL) { - sk_X509_NAME_free(sk); - } - if (in != NULL) { - BIO_free(in); - } - if (x != NULL) { - X509_free(x); - } + sk_X509_NAME_free(sk); + BIO_free(in); + X509_free(x); if (ret != NULL) { ERR_clear_error(); } @@ -747,7 +661,7 @@ STACK_OF(X509_NAME) * SSL_load_client_CA_file(const char *file) { * 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, +int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, const char *file) { BIO *in; X509 *x = NULL; @@ -794,12 +708,8 @@ int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) * stack, ret = 0; } - if (in != NULL) { - BIO_free(in); - } - if (x != NULL) { - X509_free(x); - } + BIO_free(in); + X509_free(x); (void) sk_X509_NAME_set_cmp_func(stack, oldcmp); @@ -815,7 +725,7 @@ int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) * stack, * 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, +int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, const char *dir) { OPENSSL_DIR_CTX *d = NULL; const char *filename; @@ -842,7 +752,7 @@ int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) * stack, } if (errno) { - OPENSSL_PUT_ERROR(SSL, SSL_add_file_cert_subjects_to_stack, ERR_R_SYS_LIB); + 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; } @@ -881,12 +791,13 @@ int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l) { int no_chain = 0; size_t i; - X509 *x = NULL; - STACK_OF(X509) * extra_certs; + X509 *x = cpk->x509; + STACK_OF(X509) *extra_certs; X509_STORE *chain_store; - if (cpk) { - x = cpk->x509; + if (x == NULL) { + OPENSSL_PUT_ERROR(SSL, ssl_add_cert_chain, SSL_R_NO_CERTIFICATE_SET); + return 0; } if (s->cert->chain_store) { @@ -906,44 +817,36 @@ int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l) { no_chain = 1; } - /* TLSv1 sends a chain with nothing in it, instead of an alert. */ - if (!BUF_MEM_grow_clean(buf, 10)) { - OPENSSL_PUT_ERROR(SSL, ssl_add_cert_chain, ERR_R_BUF_LIB); - return 0; - } + if (no_chain) { + if (!ssl_add_cert_to_buf(buf, l, x)) { + return 0; + } - if (x != NULL) { - if (no_chain) { + 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; } - } else { - X509_STORE_CTX xs_ctx; - - 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); - /* Don't leave errors in the queue */ - ERR_clear_error(); - for (i = 0; i < sk_X509_num(xs_ctx.chain); i++) { - x = sk_X509_value(xs_ctx.chain, i); - - if (!ssl_add_cert_to_buf(buf, l, x)) { - X509_STORE_CTX_cleanup(&xs_ctx); - return 0; - } - } - X509_STORE_CTX_cleanup(&xs_ctx); } - } + } else { + X509_STORE_CTX xs_ctx; - 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)) { + 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); + /* Don't leave errors in the queue */ + ERR_clear_error(); + for (i = 0; i < sk_X509_num(xs_ctx.chain); i++) { + x = sk_X509_value(xs_ctx.chain, i); + + if (!ssl_add_cert_to_buf(buf, l, x)) { + X509_STORE_CTX_cleanup(&xs_ctx); + return 0; + } + } + X509_STORE_CTX_cleanup(&xs_ctx); } return 1; @@ -956,7 +859,7 @@ int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags) { STACK_OF(X509) *chain = NULL, *untrusted = NULL; X509 *x; int i, rv = 0; - unsigned long error; + uint32_t error; if (!cpk->x509) { OPENSSL_PUT_ERROR(SSL, ssl_build_cert_chain, SSL_R_NO_CERTIFICATE_SET); @@ -1050,8 +953,9 @@ int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags) { } cpk->chain = chain; - if (rv == 0) + if (rv == 0) { rv = 1; + } err: if (flags & SSL_BUILD_CHAIN_FLAG_CHECK) { @@ -1069,9 +973,7 @@ int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref) { pstore = &c->verify_store; } - if (*pstore) { - X509_STORE_free(*pstore); - } + X509_STORE_free(*pstore); *pstore = store; if (ref && store) { diff --git a/src/ssl/ssl_ciph.c b/src/ssl/ssl_ciph.c deleted file mode 100644 index 60b9747..0000000 --- a/src/ssl/ssl_ciph.c +++ /dev/null @@ -1,1421 +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). - * - */ -/* ==================================================================== - * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. - * ECC cipher suite support in OpenSSL originally developed by - * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. - */ -/* ==================================================================== - * Copyright 2005 Nokia. All rights reserved. - * - * The portions of the attached software ("Contribution") is developed by - * Nokia Corporation and is licensed pursuant to the OpenSSL open source - * license. - * - * The Contribution, originally written by Mika Kousa and Pasi Eronen of - * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites - * support (see RFC 4279) to OpenSSL. - * - * No patent licenses or other rights except those expressly stated in - * the OpenSSL open source license shall be deemed granted or received - * expressly, by implication, estoppel, or otherwise. - * - * No assurances are provided by Nokia that the Contribution does not - * infringe the patent or other intellectual property rights of any third - * party or that the license provides you with all the necessary rights - * to make use of the Contribution. - * - * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN - * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA - * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY - * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR - * OTHERWISE. */ - -#include -#include - -#include -#include -#include -#include -#include - -#include "ssl_locl.h" - - -struct handshake_digest { - long 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 -#define CIPHER_ORD 4 -#define CIPHER_SPECIAL 5 - -typedef struct cipher_order_st { - const SSL_CIPHER *cipher; - int active; - int dead; - int in_group; - struct cipher_order_st *next, *prev; -} CIPHER_ORDER; - -static const SSL_CIPHER cipher_aliases[] = - { - {0, SSL_TXT_ALL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - - /* "COMPLEMENTOFDEFAULT" (does *not* include ciphersuites not found in - ALL!) */ - {0, SSL_TXT_CMPDEF, 0, SSL_kEDH | SSL_kEECDH, SSL_aNULL, 0, 0, 0, 0, 0, 0, - 0}, - - /* key exchange aliases - * (some of those using only a single bit here combine - * multiple key exchange algs according to the RFCs, - * e.g. kEDH combines DHE_DSS and DHE_RSA) */ - {0, SSL_TXT_kRSA, 0, SSL_kRSA, 0, 0, 0, 0, 0, 0, 0, 0}, - - {0, SSL_TXT_kEDH, 0, SSL_kEDH, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, SSL_TXT_DH, 0, SSL_kEDH, 0, 0, 0, 0, 0, 0, 0, 0}, - - {0, SSL_TXT_kEECDH, 0, SSL_kEECDH, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, SSL_TXT_ECDH, 0, SSL_kEECDH, 0, 0, 0, 0, 0, 0, 0, 0}, - - {0, SSL_TXT_kPSK, 0, SSL_kPSK, 0, 0, 0, 0, 0, 0, 0, 0}, - - /* server authentication aliases */ - {0, SSL_TXT_aRSA, 0, 0, SSL_aRSA, 0, 0, 0, 0, 0, 0, 0}, - {0, SSL_TXT_aNULL, 0, 0, SSL_aNULL, 0, 0, 0, 0, 0, 0, 0}, - {0, SSL_TXT_aECDSA, 0, 0, SSL_aECDSA, 0, 0, 0, 0, 0, 0, 0}, - {0, SSL_TXT_ECDSA, 0, 0, SSL_aECDSA, 0, 0, 0, 0, 0, 0, 0}, - {0, SSL_TXT_aPSK, 0, 0, SSL_aPSK, 0, 0, 0, 0, 0, 0, 0}, - - /* aliases combining key exchange and server authentication */ - {0, SSL_TXT_EDH, 0, SSL_kEDH, ~SSL_aNULL, 0, 0, 0, 0, 0, 0, 0}, - {0, SSL_TXT_EECDH, 0, SSL_kEECDH, ~SSL_aNULL, 0, 0, 0, 0, 0, 0, 0}, - {0, SSL_TXT_RSA, 0, SSL_kRSA, SSL_aRSA, 0, 0, 0, 0, 0, 0, 0}, - {0, SSL_TXT_ADH, 0, SSL_kEDH, SSL_aNULL, 0, 0, 0, 0, 0, 0, 0}, - {0, SSL_TXT_AECDH, 0, SSL_kEECDH, SSL_aNULL, 0, 0, 0, 0, 0, 0, 0}, - {0, SSL_TXT_PSK, 0, SSL_kPSK, SSL_aPSK, 0, 0, 0, 0, 0, 0, 0}, - - /* symmetric encryption aliases */ - {0, SSL_TXT_3DES, 0, 0, 0, SSL_3DES, 0, 0, 0, 0, 0, 0}, - {0, SSL_TXT_RC4, 0, 0, 0, SSL_RC4, 0, 0, 0, 0, 0, 0}, - {0, SSL_TXT_AES128, 0, 0, 0, SSL_AES128 | SSL_AES128GCM, 0, 0, 0, 0, 0, 0}, - {0, SSL_TXT_AES256, 0, 0, 0, SSL_AES256 | SSL_AES256GCM, 0, 0, 0, 0, 0, 0}, - {0, SSL_TXT_AES, 0, 0, 0, SSL_AES, 0, 0, 0, 0, 0, 0}, - {0, SSL_TXT_AES_GCM, 0, 0, 0, SSL_AES128GCM | SSL_AES256GCM, 0, 0, 0, 0, 0, - 0}, - {0, SSL_TXT_CHACHA20, 0, 0, 0, SSL_CHACHA20POLY1305, 0, 0, 0, 0, 0, 0}, - - /* MAC aliases */ - {0, SSL_TXT_MD5, 0, 0, 0, 0, SSL_MD5, 0, 0, 0, 0, 0}, - {0, SSL_TXT_SHA1, 0, 0, 0, 0, SSL_SHA1, 0, 0, 0, 0, 0}, - {0, SSL_TXT_SHA, 0, 0, 0, 0, SSL_SHA1, 0, 0, 0, 0, 0}, - {0, SSL_TXT_SHA256, 0, 0, 0, 0, SSL_SHA256, 0, 0, 0, 0, 0}, - {0, SSL_TXT_SHA384, 0, 0, 0, 0, SSL_SHA384, 0, 0, 0, 0, 0}, - - /* protocol version aliases */ - {0, SSL_TXT_SSLV3, 0, 0, 0, 0, 0, SSL_SSLV3, 0, 0, 0, 0}, - {0, SSL_TXT_TLSV1, 0, 0, 0, 0, 0, SSL_TLSV1, 0, 0, 0, 0}, - {0, SSL_TXT_TLSV1_2, 0, 0, 0, 0, 0, SSL_TLSV1_2, 0, 0, 0, 0}, - - /* strength classes */ - {0, SSL_TXT_MEDIUM, 0, 0, 0, 0, 0, 0, SSL_MEDIUM, 0, 0, 0}, - {0, SSL_TXT_HIGH, 0, 0, 0, 0, 0, 0, SSL_HIGH, 0, 0, 0}, - /* FIPS 140-2 approved ciphersuite */ - {0, SSL_TXT_FIPS, 0, 0, 0, 0, 0, 0, SSL_FIPS, 0, 0, 0}, -}; - -int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead, - size_t *out_mac_secret_len, - size_t *out_fixed_iv_len, - const SSL_CIPHER *cipher, uint16_t version) { - *out_aead = NULL; - *out_mac_secret_len = 0; - *out_fixed_iv_len = 0; - - switch (cipher->algorithm_enc) { - case SSL_AES128GCM: - *out_aead = EVP_aead_aes_128_gcm(); - *out_fixed_iv_len = 4; - return 1; - - case SSL_AES256GCM: - *out_aead = EVP_aead_aes_256_gcm(); - *out_fixed_iv_len = 4; - return 1; - - case SSL_CHACHA20POLY1305: - *out_aead = EVP_aead_chacha20_poly1305(); - *out_fixed_iv_len = 0; - return 1; - - case SSL_RC4: - switch (cipher->algorithm_mac) { - case SSL_MD5: - if (version == SSL3_VERSION) { - *out_aead = EVP_aead_rc4_md5_ssl3(); - } else { - *out_aead = EVP_aead_rc4_md5_tls(); - } - *out_mac_secret_len = MD5_DIGEST_LENGTH; - return 1; - case SSL_SHA1: - if (version == SSL3_VERSION) { - *out_aead = EVP_aead_rc4_sha1_ssl3(); - } else { - *out_aead = EVP_aead_rc4_sha1_tls(); - } - *out_mac_secret_len = SHA_DIGEST_LENGTH; - return 1; - default: - return 0; - } - - case SSL_AES128: - switch (cipher->algorithm_mac) { - case SSL_SHA1: - if (version == SSL3_VERSION) { - *out_aead = EVP_aead_aes_128_cbc_sha1_ssl3(); - *out_fixed_iv_len = 16; - } else if (version == TLS1_VERSION) { - *out_aead = EVP_aead_aes_128_cbc_sha1_tls_implicit_iv(); - *out_fixed_iv_len = 16; - } else { - *out_aead = EVP_aead_aes_128_cbc_sha1_tls(); - } - *out_mac_secret_len = SHA_DIGEST_LENGTH; - return 1; - case SSL_SHA256: - *out_aead = EVP_aead_aes_128_cbc_sha256_tls(); - *out_mac_secret_len = SHA256_DIGEST_LENGTH; - return 1; - default: - return 0; - } - - case SSL_AES256: - switch (cipher->algorithm_mac) { - case SSL_SHA1: - if (version == SSL3_VERSION) { - *out_aead = EVP_aead_aes_256_cbc_sha1_ssl3(); - *out_fixed_iv_len = 16; - } else if (version == TLS1_VERSION) { - *out_aead = EVP_aead_aes_256_cbc_sha1_tls_implicit_iv(); - *out_fixed_iv_len = 16; - } else { - *out_aead = EVP_aead_aes_256_cbc_sha1_tls(); - } - *out_mac_secret_len = SHA_DIGEST_LENGTH; - return 1; - case SSL_SHA256: - *out_aead = EVP_aead_aes_256_cbc_sha256_tls(); - *out_mac_secret_len = SHA256_DIGEST_LENGTH; - return 1; - case SSL_SHA384: - *out_aead = EVP_aead_aes_256_cbc_sha384_tls(); - *out_mac_secret_len = SHA384_DIGEST_LENGTH; - return 1; - default: - return 0; - } - - case SSL_3DES: - switch (cipher->algorithm_mac) { - case SSL_SHA1: - if (version == SSL3_VERSION) { - *out_aead = EVP_aead_des_ede3_cbc_sha1_ssl3(); - *out_fixed_iv_len = 8; - } else if (version == TLS1_VERSION) { - *out_aead = EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv(); - *out_fixed_iv_len = 8; - } else { - *out_aead = EVP_aead_des_ede3_cbc_sha1_tls(); - } - *out_mac_secret_len = SHA_DIGEST_LENGTH; - return 1; - default: - return 0; - } - - default: - return 0; - } -} - -int ssl_get_handshake_digest(size_t idx, long *mask, const EVP_MD **md) { - if (idx >= SSL_MAX_DIGEST) { - return 0; - } - *mask = ssl_handshake_digests[idx].mask; - *md = ssl_handshake_digests[idx].md_func(); - return 1; -} - -#define ITEM_SEP(a) \ - (((a) == ':') || ((a) == ' ') || ((a) == ';') || ((a) == ',')) - -static void ll_append_tail(CIPHER_ORDER **head, CIPHER_ORDER *curr, - CIPHER_ORDER **tail) { - if (curr == *tail) { - return; - } - if (curr == *head) { - *head = curr->next; - } - if (curr->prev != NULL) { - curr->prev->next = curr->next; - } - if (curr->next != NULL) { - curr->next->prev = curr->prev; - } - (*tail)->next = curr; - curr->prev = *tail; - curr->next = NULL; - *tail = curr; -} - -static void ll_append_head(CIPHER_ORDER **head, CIPHER_ORDER *curr, - CIPHER_ORDER **tail) { - if (curr == *head) { - return; - } - if (curr == *tail) { - *tail = curr->prev; - } - if (curr->next != NULL) { - curr->next->prev = curr->prev; - } - if (curr->prev != NULL) { - curr->prev->next = curr->next; - } - (*head)->prev = curr; - curr->next = *head; - curr->prev = NULL; - *head = curr; -} - -static void ssl_cipher_collect_ciphers(const SSL_PROTOCOL_METHOD *ssl_method, - int num_of_ciphers, - CIPHER_ORDER *co_list, - CIPHER_ORDER **head_p, - CIPHER_ORDER **tail_p) { - int i, co_list_num; - const SSL_CIPHER *c; - - /* We have num_of_ciphers descriptions compiled in, depending on the method - * selected (SSLv2 and/or SSLv3, TLSv1 etc). These will later be sorted in a - * linked list with at most num entries. */ - - /* Get the initial list of ciphers */ - co_list_num = 0; /* actual count of ciphers */ - for (i = 0; i < num_of_ciphers; i++) { - c = ssl_method->get_cipher(i); - /* drop those that use any of that is not available */ - if (c != NULL && c->valid) { - co_list[co_list_num].cipher = c; - co_list[co_list_num].next = NULL; - co_list[co_list_num].prev = NULL; - co_list[co_list_num].active = 0; - co_list[co_list_num].in_group = 0; - co_list_num++; - } - } - - /* Prepare linked list from list entries. */ - if (co_list_num > 0) { - co_list[0].prev = NULL; - - if (co_list_num > 1) { - co_list[0].next = &co_list[1]; - - for (i = 1; i < co_list_num - 1; i++) { - co_list[i].prev = &co_list[i - 1]; - co_list[i].next = &co_list[i + 1]; - } - - co_list[co_list_num - 1].prev = &co_list[co_list_num - 2]; - } - - co_list[co_list_num - 1].next = NULL; - - *head_p = &co_list[0]; - *tail_p = &co_list[co_list_num - 1]; - } -} - -static void ssl_cipher_collect_aliases(const SSL_CIPHER **ca_list, - int num_of_group_aliases, - CIPHER_ORDER *head) { - CIPHER_ORDER *ciph_curr; - const SSL_CIPHER **ca_curr; - int i; - - /* First, add the real ciphers as already collected. */ - ciph_curr = head; - ca_curr = ca_list; - while (ciph_curr != NULL) { - *ca_curr = ciph_curr->cipher; - ca_curr++; - ciph_curr = ciph_curr->next; - } - - /* Now we add the available ones from the cipher_aliases[] table. They - * represent either one or more algorithms, some of which in any affected - * category must be supported (set in enabled_mask), or represent a cipher - * strength value (will be added in any case because algorithms=0). */ - for (i = 0; i < num_of_group_aliases; i++) { - *ca_curr = cipher_aliases + i; - ca_curr++; - } - - *ca_curr = NULL; /* end of list */ -} - -static void ssl_cipher_apply_rule( - unsigned long cipher_id, unsigned long alg_mkey, unsigned long alg_auth, - unsigned long alg_enc, unsigned long alg_mac, unsigned long alg_ssl, - unsigned long algo_strength, int rule, int strength_bits, int in_group, - CIPHER_ORDER **head_p, CIPHER_ORDER **tail_p) { - CIPHER_ORDER *head, *tail, *curr, *next, *last; - const SSL_CIPHER *cp; - int reverse = 0; - - if (rule == CIPHER_DEL) { - /* needed to maintain sorting between currently deleted ciphers */ - reverse = 1; - } - - head = *head_p; - tail = *tail_p; - - if (reverse) { - next = tail; - last = head; - } else { - next = head; - last = tail; - } - - curr = NULL; - for (;;) { - if (curr == last) { - break; - } - - curr = next; - if (curr == NULL) { - break; - } - - next = reverse ? curr->prev : curr->next; - cp = curr->cipher; - - /* Selection criteria is either the value of strength_bits - * or the algorithms used. */ - if (strength_bits >= 0) { - if (strength_bits != cp->strength_bits) { - continue; - } - } else { - if ((alg_mkey && !(alg_mkey & cp->algorithm_mkey)) || - (alg_auth && !(alg_auth & cp->algorithm_auth)) || - (alg_enc && !(alg_enc & cp->algorithm_enc)) || - (alg_mac && !(alg_mac & cp->algorithm_mac)) || - (alg_ssl && !(alg_ssl & cp->algorithm_ssl)) || - (algo_strength && !(algo_strength & cp->algo_strength))) { - continue; - } - } - - /* add the cipher if it has not been added yet. */ - if (rule == CIPHER_ADD) { - /* reverse == 0 */ - if (!curr->active) { - ll_append_tail(&head, curr, &tail); - curr->active = 1; - curr->in_group = in_group; - } - } - - /* Move the added cipher to this location */ - else if (rule == CIPHER_ORD) { - /* reverse == 0 */ - if (curr->active) { - ll_append_tail(&head, curr, &tail); - curr->in_group = 0; - } - } else if (rule == CIPHER_DEL) { - /* reverse == 1 */ - if (curr->active) { - /* most recently deleted ciphersuites get best positions - * for any future CIPHER_ADD (note that the CIPHER_DEL loop - * works in reverse to maintain the order) */ - ll_append_head(&head, curr, &tail); - curr->active = 0; - curr->in_group = 0; - } - } else if (rule == CIPHER_KILL) { - /* reverse == 0 */ - if (head == curr) { - head = curr->next; - } else { - curr->prev->next = curr->next; - } - - if (tail == curr) { - tail = curr->prev; - } - curr->active = 0; - if (curr->next != NULL) { - curr->next->prev = curr->prev; - } - if (curr->prev != NULL) { - curr->prev->next = curr->next; - } - curr->next = NULL; - curr->prev = NULL; - } - } - - *head_p = head; - *tail_p = tail; -} - -static int ssl_cipher_strength_sort(CIPHER_ORDER **head_p, - CIPHER_ORDER **tail_p) { - int max_strength_bits, i, *number_uses; - CIPHER_ORDER *curr; - - /* This routine sorts the ciphers with descending strength. The sorting must - * keep the pre-sorted sequence, so we apply the normal sorting routine as - * '+' movement to the end of the list. */ - max_strength_bits = 0; - curr = *head_p; - while (curr != NULL) { - if (curr->active && curr->cipher->strength_bits > max_strength_bits) { - max_strength_bits = curr->cipher->strength_bits; - } - curr = curr->next; - } - - number_uses = OPENSSL_malloc((max_strength_bits + 1) * sizeof(int)); - if (!number_uses) { - OPENSSL_PUT_ERROR(SSL, ssl_cipher_strength_sort, ERR_R_MALLOC_FAILURE); - return 0; - } - memset(number_uses, 0, (max_strength_bits + 1) * sizeof(int)); - - /* Now find the strength_bits values actually used. */ - curr = *head_p; - while (curr != NULL) { - if (curr->active) { - number_uses[curr->cipher->strength_bits]++; - } - curr = curr->next; - } - - /* Go through the list of used strength_bits values in descending order. */ - for (i = max_strength_bits; i >= 0; i--) { - if (number_uses[i] > 0) { - ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ORD, i, 0, head_p, - tail_p); - } - } - - OPENSSL_free(number_uses); - return 1; -} - -static int ssl_cipher_process_rulestr(const char *rule_str, - CIPHER_ORDER **head_p, - CIPHER_ORDER **tail_p, - const SSL_CIPHER **ca_list) { - unsigned long alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, algo_strength; - const char *l, *buf; - int j, multi, found, rule, retval, ok, buflen, in_group = 0, has_group = 0; - unsigned long cipher_id = 0; - char ch; - - retval = 1; - l = rule_str; - for (;;) { - ch = *l; - - if (ch == '\0') { - break; /* done */ - } - - if (in_group) { - if (ch == ']') { - if (!in_group) { - OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, - SSL_R_UNEXPECTED_GROUP_CLOSE); - retval = found = in_group = 0; - break; - } - if (*tail_p) { - (*tail_p)->in_group = 0; - } - in_group = 0; - l++; - continue; - } - - if (ch == '|') { - rule = CIPHER_ADD; - l++; - continue; - } else if (!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') && - !(ch >= '0' && ch <= '9')) { - OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, - SSL_R_UNEXPECTED_OPERATOR_IN_GROUP); - retval = found = in_group = 0; - break; - } else { - rule = CIPHER_ADD; - } - } else if (ch == '-') { - rule = CIPHER_DEL; - l++; - } else if (ch == '+') { - rule = CIPHER_ORD; - l++; - } else if (ch == '!') { - rule = CIPHER_KILL; - l++; - } else if (ch == '@') { - rule = CIPHER_SPECIAL; - l++; - } else if (ch == '[') { - if (in_group) { - OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_NESTED_GROUP); - retval = found = in_group = 0; - break; - } - in_group = 1; - has_group = 1; - l++; - continue; - } else { - rule = CIPHER_ADD; - } - - /* 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_cipher_process_rulestr, - SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS); - retval = found = in_group = 0; - break; - } - - if (ITEM_SEP(ch)) { - l++; - continue; - } - - alg_mkey = 0; - alg_auth = 0; - alg_enc = 0; - alg_mac = 0; - alg_ssl = 0; - algo_strength = 0; - - for (;;) { - ch = *l; - buf = l; - buflen = 0; - while (((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9')) || - ((ch >= 'a') && (ch <= 'z')) || (ch == '-') || (ch == '.')) { - ch = *(++l); - buflen++; - } - - if (buflen == 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_cipher_process_rulestr, - SSL_R_INVALID_COMMAND); - retval = found = in_group = 0; - l++; - break; - } - - if (rule == CIPHER_SPECIAL) { - found = 0; /* unused -- avoid compiler warning */ - break; /* special treatment */ - } - - /* check for multi-part specification */ - if (ch == '+') { - multi = 1; - l++; - } else { - multi = 0; - } - - /* Now search for the cipher alias in the ca_list. Be careful with the - * strncmp, because the "buflen" limitation will make the rule "ADH:SOME" - * and the cipher "ADH-MY-CIPHER" look like a match for buflen=3. So - * additionally check whether the cipher name found has the correct - * length. We can save a strlen() call: just checking for the '\0' at the - * right place is sufficient, we have to strncmp() anyway. (We cannot use - * strcmp(), because buf is not '\0' terminated.) */ - j = found = 0; - cipher_id = 0; - while (ca_list[j]) { - if (!strncmp(buf, ca_list[j]->name, buflen) && - (ca_list[j]->name[buflen] == '\0')) { - found = 1; - break; - } else { - j++; - } - } - - if (!found) { - break; /* ignore this entry */ - } - - if (ca_list[j]->algorithm_mkey) { - if (alg_mkey) { - alg_mkey &= ca_list[j]->algorithm_mkey; - if (!alg_mkey) { - found = 0; - break; - } - } else { - alg_mkey = ca_list[j]->algorithm_mkey; - } - } - - if (ca_list[j]->algorithm_auth) { - if (alg_auth) { - alg_auth &= ca_list[j]->algorithm_auth; - if (!alg_auth) { - found = 0; - break; - } - } else { - alg_auth = ca_list[j]->algorithm_auth; - } - } - - if (ca_list[j]->algorithm_enc) { - if (alg_enc) { - alg_enc &= ca_list[j]->algorithm_enc; - if (!alg_enc) { - found = 0; - break; - } - } else { - alg_enc = ca_list[j]->algorithm_enc; - } - } - - if (ca_list[j]->algorithm_mac) { - if (alg_mac) { - alg_mac &= ca_list[j]->algorithm_mac; - if (!alg_mac) { - found = 0; - break; - } - } else { - alg_mac = ca_list[j]->algorithm_mac; - } - } - - if (ca_list[j]->algo_strength) { - if (algo_strength) { - algo_strength &= ca_list[j]->algo_strength; - if (!algo_strength) { - found = 0; - break; - } - } else { - algo_strength |= ca_list[j]->algo_strength; - } - } - - if (ca_list[j]->valid) { - /* explicit ciphersuite found; its protocol version does not become - * part of the search pattern! */ - cipher_id = ca_list[j]->id; - } else { - /* not an explicit ciphersuite; only in this case, the protocol version - * is considered part of the search pattern. */ - if (ca_list[j]->algorithm_ssl) { - if (alg_ssl) { - alg_ssl &= ca_list[j]->algorithm_ssl; - if (!alg_ssl) { - found = 0; - break; - } - } else { - alg_ssl = ca_list[j]->algorithm_ssl; - } - } - } - - if (!multi) { - break; - } - } - - /* Ok, we have the rule, now apply it. */ - if (rule == CIPHER_SPECIAL) { - /* special command */ - ok = 0; - if (buflen == 8 && !strncmp(buf, "STRENGTH", 8)) { - ok = ssl_cipher_strength_sort(head_p, tail_p); - } else { - OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, - SSL_R_INVALID_COMMAND); - } - - if (ok == 0) { - retval = 0; - } - - /* We do not support any "multi" options together with "@", so throw away - * the rest of the command, if any left, until end or ':' is found. */ - while (*l != '\0' && !ITEM_SEP(*l)) { - l++; - } - } else if (found) { - ssl_cipher_apply_rule(cipher_id, alg_mkey, alg_auth, alg_enc, alg_mac, - alg_ssl, algo_strength, rule, -1, in_group, head_p, - tail_p); - } else { - while (*l != '\0' && !ITEM_SEP(*l)) { - l++; - } - } - } - - if (in_group) { - OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_INVALID_COMMAND); - retval = 0; - } - - return retval; -} - -STACK_OF(SSL_CIPHER) * -ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, - struct ssl_cipher_preference_list_st **cipher_list, - STACK_OF(SSL_CIPHER) * *cipher_list_by_id, - const char *rule_str, CERT *c) { - int ok, num_of_ciphers, num_of_alias_max, num_of_group_aliases; - STACK_OF(SSL_CIPHER) *cipherstack = NULL, *tmp_cipher_list = NULL; - const char *rule_p; - CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr; - const SSL_CIPHER **ca_list = NULL; - uint8_t *in_group_flags = NULL; - unsigned int num_in_group_flags = 0; - struct ssl_cipher_preference_list_st *pref_list = NULL; - - /* Return with error if nothing to do. */ - if (rule_str == NULL || cipher_list == NULL) { - return NULL; - } - - /* Now we have to collect the available ciphers from the compiled in ciphers. - * We cannot get more than the number compiled in, so it is used for - * allocation. */ - num_of_ciphers = ssl_method->num_ciphers(); - co_list = - (CIPHER_ORDER *)OPENSSL_malloc(sizeof(CIPHER_ORDER) * num_of_ciphers); - if (co_list == NULL) { - OPENSSL_PUT_ERROR(SSL, ssl_create_cipher_list, ERR_R_MALLOC_FAILURE); - return NULL; - } - - ssl_cipher_collect_ciphers(ssl_method, num_of_ciphers, co_list, &head, &tail); - - /* Now arrange all ciphers by preference: - * TODO(davidben): Compute this order once and copy it. */ - - /* Everything else being equal, prefer ECDHE_ECDSA then ECDHE_RSA over other - * key exchange mechanisms */ - ssl_cipher_apply_rule(0, SSL_kEECDH, SSL_aECDSA, 0, 0, 0, 0, CIPHER_ADD, -1, - 0, &head, &tail); - ssl_cipher_apply_rule(0, SSL_kEECDH, 0, 0, 0, 0, 0, CIPHER_ADD, -1, 0, &head, - &tail); - ssl_cipher_apply_rule(0, SSL_kEECDH, 0, 0, 0, 0, 0, CIPHER_DEL, -1, 0, &head, - &tail); - - /* Order the bulk ciphers. First the preferred AEAD ciphers. We prefer - * CHACHA20 unless there is hardware support for fast and constant-time - * AES_GCM. */ - if (EVP_has_aes_hardware()) { - ssl_cipher_apply_rule(0, 0, 0, SSL_AES256GCM, 0, 0, 0, CIPHER_ADD, -1, 0, - &head, &tail); - ssl_cipher_apply_rule(0, 0, 0, SSL_AES128GCM, 0, 0, 0, CIPHER_ADD, -1, 0, - &head, &tail); - ssl_cipher_apply_rule(0, 0, 0, SSL_CHACHA20POLY1305, 0, 0, 0, CIPHER_ADD, - -1, 0, &head, &tail); - } else { - ssl_cipher_apply_rule(0, 0, 0, SSL_CHACHA20POLY1305, 0, 0, 0, CIPHER_ADD, - -1, 0, &head, &tail); - ssl_cipher_apply_rule(0, 0, 0, SSL_AES256GCM, 0, 0, 0, CIPHER_ADD, -1, 0, - &head, &tail); - ssl_cipher_apply_rule(0, 0, 0, SSL_AES128GCM, 0, 0, 0, CIPHER_ADD, -1, 0, - &head, &tail); - } - - /* Then the legacy non-AEAD ciphers: AES_256_CBC, AES-128_CBC, RC4_128_SHA, - * RC4_128_MD5, 3DES_EDE_CBC_SHA. */ - ssl_cipher_apply_rule(0, 0, 0, SSL_AES256, 0, 0, 0, CIPHER_ADD, -1, 0, &head, - &tail); - ssl_cipher_apply_rule(0, 0, 0, SSL_AES128, 0, 0, 0, CIPHER_ADD, -1, 0, &head, - &tail); - ssl_cipher_apply_rule(0, 0, 0, SSL_RC4, ~SSL_MD5, 0, 0, CIPHER_ADD, -1, 0, - &head, &tail); - ssl_cipher_apply_rule(0, 0, 0, SSL_RC4, SSL_MD5, 0, 0, CIPHER_ADD, -1, 0, - &head, &tail); - ssl_cipher_apply_rule(0, 0, 0, SSL_3DES, 0, 0, 0, CIPHER_ADD, -1, 0, &head, - &tail); - - /* Temporarily enable everything else for sorting */ - ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ADD, -1, 0, &head, &tail); - - /* Move ciphers without forward secrecy to the end. */ - ssl_cipher_apply_rule(0, ~(SSL_kEDH | SSL_kEECDH), 0, 0, 0, 0, 0, CIPHER_ORD, - -1, 0, &head, &tail); - - /* Move anonymous ciphers to the end. Usually, these will remain disabled. - * (For applications that allow them, they aren't too bad, but we prefer - * authenticated ciphers.) - * TODO(davidben): Remove them altogether? */ - ssl_cipher_apply_rule(0, 0, SSL_aNULL, 0, 0, 0, 0, CIPHER_ORD, -1, 0, &head, - &tail); - - /* Now disable everything (maintaining the ordering!) */ - ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_DEL, -1, 0, &head, &tail); - - /* We also need cipher aliases for selecting based on the rule_str. There - * might be two types of entries in the rule_str: 1) names of ciphers - * themselves 2) aliases for groups of ciphers. For 1) we need the available - * ciphers and for 2) the cipher groups of cipher_aliases added together in - * one list (otherwise we would be happy with just the cipher_aliases - * table). */ - num_of_group_aliases = sizeof(cipher_aliases) / sizeof(SSL_CIPHER); - num_of_alias_max = num_of_ciphers + num_of_group_aliases + 1; - ca_list = OPENSSL_malloc(sizeof(SSL_CIPHER *) * num_of_alias_max); - if (ca_list == NULL) { - OPENSSL_PUT_ERROR(SSL, ssl_create_cipher_list, ERR_R_MALLOC_FAILURE); - goto err; - } - ssl_cipher_collect_aliases(ca_list, num_of_group_aliases, head); - - /* If the rule_string begins with DEFAULT, apply the default rule before - * using the (possibly available) additional rules. */ - ok = 1; - rule_p = rule_str; - if (strncmp(rule_str, "DEFAULT", 7) == 0) { - ok = ssl_cipher_process_rulestr(SSL_DEFAULT_CIPHER_LIST, &head, &tail, - ca_list); - rule_p += 7; - if (*rule_p == ':') { - rule_p++; - } - } - - if (ok && strlen(rule_p) > 0) { - ok = ssl_cipher_process_rulestr(rule_p, &head, &tail, ca_list); - } - - OPENSSL_free((void *)ca_list); /* Not needed anymore */ - - if (!ok) { - goto err; - } - - /* Allocate new "cipherstack" for the result, return with error - * if we cannot get one. */ - cipherstack = sk_SSL_CIPHER_new_null(); - if (cipherstack == NULL) { - goto err; - } - - in_group_flags = OPENSSL_malloc(num_of_ciphers); - if (!in_group_flags) { - goto err; - } - - /* The cipher selection for the list is done. The ciphers are added - * to the resulting precedence to the STACK_OF(SSL_CIPHER). */ - for (curr = head; curr != NULL; curr = curr->next) { - if (curr->active) { - if (!sk_SSL_CIPHER_push(cipherstack, curr->cipher)) { - goto err; - } - in_group_flags[num_in_group_flags++] = curr->in_group; - } - } - OPENSSL_free(co_list); /* Not needed any longer */ - co_list = NULL; - - tmp_cipher_list = sk_SSL_CIPHER_dup(cipherstack); - if (tmp_cipher_list == NULL) { - goto err; - } - pref_list = OPENSSL_malloc(sizeof(struct ssl_cipher_preference_list_st)); - if (!pref_list) { - goto err; - } - pref_list->ciphers = cipherstack; - pref_list->in_group_flags = OPENSSL_malloc(num_in_group_flags); - if (!pref_list->in_group_flags) { - goto err; - } - memcpy(pref_list->in_group_flags, in_group_flags, num_in_group_flags); - OPENSSL_free(in_group_flags); - in_group_flags = NULL; - if (*cipher_list != NULL) { - ssl_cipher_preference_list_free(*cipher_list); - } - *cipher_list = pref_list; - pref_list = NULL; - - if (cipher_list_by_id != NULL) { - if (*cipher_list_by_id != NULL) { - sk_SSL_CIPHER_free(*cipher_list_by_id); - } - *cipher_list_by_id = tmp_cipher_list; - tmp_cipher_list = NULL; - (void) sk_SSL_CIPHER_set_cmp_func(*cipher_list_by_id, ssl_cipher_ptr_id_cmp); - - sk_SSL_CIPHER_sort(*cipher_list_by_id); - } else { - sk_SSL_CIPHER_free(tmp_cipher_list); - tmp_cipher_list = NULL; - } - - return cipherstack; - -err: - if (co_list) { - OPENSSL_free(co_list); - } - if (in_group_flags) { - OPENSSL_free(in_group_flags); - } - if (cipherstack) { - sk_SSL_CIPHER_free(cipherstack); - } - if (tmp_cipher_list) { - sk_SSL_CIPHER_free(tmp_cipher_list); - } - if (pref_list && pref_list->in_group_flags) { - OPENSSL_free(pref_list->in_group_flags); - } - if (pref_list) { - OPENSSL_free(pref_list); - } - return NULL; -} - -const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, - int len) { - const char *ver; - const char *kx, *au, *enc, *mac; - unsigned long alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl; - static const char *format = "%-23s %s Kx=%-8s Au=%-4s Enc=%-9s Mac=%-4s\n"; - - alg_mkey = cipher->algorithm_mkey; - alg_auth = cipher->algorithm_auth; - alg_enc = cipher->algorithm_enc; - alg_mac = cipher->algorithm_mac; - alg_ssl = cipher->algorithm_ssl; - - if (alg_ssl & SSL_SSLV3) { - ver = "SSLv3"; - } else if (alg_ssl & SSL_TLSV1_2) { - ver = "TLSv1.2"; - } else { - ver = "unknown"; - } - - switch (alg_mkey) { - case SSL_kRSA: - kx = "RSA"; - break; - - case SSL_kEDH: - kx = "DH"; - break; - - case SSL_kEECDH: - kx = "ECDH"; - break; - - case SSL_kPSK: - kx = "PSK"; - break; - - default: - kx = "unknown"; - } - - switch (alg_auth) { - case SSL_aRSA: - au = "RSA"; - break; - - case SSL_aNULL: - au = "None"; - break; - - case SSL_aECDSA: - au = "ECDSA"; - break; - - case SSL_aPSK: - au = "PSK"; - break; - - default: - au = "unknown"; - break; - } - - switch (alg_enc) { - case SSL_3DES: - enc = "3DES(168)"; - break; - - case SSL_RC4: - enc = "RC4(128)"; - break; - - case SSL_AES128: - enc = "AES(128)"; - break; - - case SSL_AES256: - enc = "AES(256)"; - break; - - case SSL_AES128GCM: - enc = "AESGCM(128)"; - break; - - case SSL_AES256GCM: - enc = "AESGCM(256)"; - break; - - case SSL_CHACHA20POLY1305: - enc = "ChaCha20-Poly1305"; - break; - - default: - enc = "unknown"; - break; - } - - switch (alg_mac) { - case SSL_MD5: - mac = "MD5"; - break; - - case SSL_SHA1: - mac = "SHA1"; - break; - - case SSL_SHA256: - mac = "SHA256"; - break; - - case SSL_SHA384: - mac = "SHA384"; - break; - - case SSL_AEAD: - mac = "AEAD"; - break; - - default: - mac = "unknown"; - break; - } - - if (buf == NULL) { - len = 128; - buf = OPENSSL_malloc(len); - if (buf == NULL) - return "OPENSSL_malloc Error"; - } else if (len < 128) { - return "Buffer too small"; - } - - BIO_snprintf(buf, len, format, cipher->name, ver, kx, au, enc, mac); - return buf; -} - -int SSL_CIPHER_is_AES(const SSL_CIPHER *c) { - return (c->algorithm_enc & SSL_AES) != 0; -} - -int SSL_CIPHER_has_MD5_HMAC(const SSL_CIPHER *c) { - return (c->algorithm_mac & SSL_MD5) != 0; -} - -int SSL_CIPHER_is_AESGCM(const SSL_CIPHER *c) { - return (c->algorithm_mac & (SSL_AES128GCM | SSL_AES256GCM)) != 0; -} - -int SSL_CIPHER_is_CHACHA20POLY1305(const SSL_CIPHER *c) { - return (c->algorithm_enc & SSL_CHACHA20POLY1305) != 0; -} - -const char *SSL_CIPHER_get_version(const SSL_CIPHER *c) { - int i; - - if (c == NULL) { - return "(NONE)"; - } - - i = (int)(c->id >> 24L); - if (i == 3) { - return "TLSv1/SSLv3"; - } else if (i == 2) { - return "SSLv2"; - } else { - return "unknown"; - } -} - -/* return the actual cipher being used */ -const char *SSL_CIPHER_get_name(const SSL_CIPHER *c) { - if (c != NULL) { - return c->name; - } - - return "(NONE)"; -} - -const char *SSL_CIPHER_get_kx_name(const SSL_CIPHER *cipher) { - if (cipher == NULL) { - return ""; - } - - switch (cipher->algorithm_mkey) { - case SSL_kRSA: - return SSL_TXT_RSA; - - case SSL_kEDH: - switch (cipher->algorithm_auth) { - case SSL_aRSA: - return "DHE_" SSL_TXT_RSA; - case SSL_aNULL: - return SSL_TXT_DH "_anon"; - default: - return "UNKNOWN"; - } - - case SSL_kEECDH: - switch (cipher->algorithm_auth) { - case SSL_aECDSA: - return "ECDHE_" SSL_TXT_ECDSA; - case SSL_aRSA: - return "ECDHE_" SSL_TXT_RSA; - case SSL_aNULL: - return SSL_TXT_ECDH "_anon"; - default: - return "UNKNOWN"; - } - - default: - return "UNKNOWN"; - } -} - -/* number of bits for symmetric cipher */ -int SSL_CIPHER_get_bits(const SSL_CIPHER *c, int *alg_bits) { - int ret = 0; - - if (c != NULL) { - if (alg_bits != NULL) { - *alg_bits = c->alg_bits; - } - ret = c->strength_bits; - } - - return ret; -} - -unsigned long SSL_CIPHER_get_id(const SSL_CIPHER *c) { return c->id; } - -void *SSL_COMP_get_compression_methods(void) { return NULL; } - -int SSL_COMP_add_compression_method(int id, void *cm) { return 1; } - -const char *SSL_COMP_get_name(const void *comp) { return NULL; } - -/* For a cipher return the index corresponding to the certificate type */ -int ssl_cipher_get_cert_index(const SSL_CIPHER *c) { - unsigned long alg_a = c->algorithm_auth; - - if (alg_a & SSL_aECDSA) { - return SSL_PKEY_ECC; - } else if (alg_a & SSL_aRSA) { - return SSL_PKEY_RSA_ENC; - } - - return -1; -} - -/* ssl_cipher_has_server_public_key returns 1 if |cipher| involves a server - * public key in the key exchange, sent in a server Certificate message. - * Otherwise it returns 0. */ -int ssl_cipher_has_server_public_key(const SSL_CIPHER *cipher) { - /* Anonymous ciphers do not include a server certificate. */ - if (cipher->algorithm_auth & SSL_aNULL) { - return 0; - } - - /* Neither do PSK ciphers, except for RSA_PSK. */ - if ((cipher->algorithm_auth & SSL_aPSK) && - !(cipher->algorithm_mkey & SSL_kRSA)) { - return 0; - } - - /* All other ciphers include it. */ - return 1; -} - -/* 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, 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) { - /* Ephemeral Diffie-Hellman key exchanges require a ServerKeyExchange. */ - if (cipher->algorithm_mkey & SSL_kEDH || cipher->algorithm_mkey & SSL_kEECDH) { - return 1; - } - - /* It is optional in all others. */ - return 0; -} diff --git a/src/ssl/ssl_cipher.c b/src/ssl/ssl_cipher.c new file mode 100644 index 0000000..2cafeb9 --- /dev/null +++ b/src/ssl/ssl_cipher.c @@ -0,0 +1,1362 @@ +/* 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). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +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 +#define CIPHER_ORD 4 +#define CIPHER_SPECIAL 5 + +typedef struct cipher_order_st { + const SSL_CIPHER *cipher; + int active; + int in_group; + struct cipher_order_st *next, *prev; +} CIPHER_ORDER; + +typedef struct cipher_alias_st { + /* name is the name of the cipher alias. */ + const char *name; + + /* The following fields are bitmasks for the corresponding fields on + * |SSL_CIPHER|. A cipher matches a cipher alias iff, for each bitmask, the + * bit corresponding to the cipher's value is set to 1. If any bitmask is + * all zeroes, the alias matches nothing. Use |~0u| for the default value. */ + uint32_t algorithm_mkey; + uint32_t algorithm_auth; + uint32_t algorithm_enc; + uint32_t algorithm_mac; + uint32_t algorithm_ssl; + uint32_t algo_strength; +} CIPHER_ALIAS; + +static const CIPHER_ALIAS kCipherAliases[] = + { + {SSL_TXT_ALL, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u}, + + /* The "COMPLEMENTOFDEFAULT" rule is omitted. It matches nothing. */ + + /* key exchange aliases + * (some of those using only a single bit here combine + * multiple key exchange algs according to the RFCs, + * e.g. kEDH combines DHE_DSS and DHE_RSA) */ + {SSL_TXT_kRSA, SSL_kRSA, ~0u, ~0u, ~0u, ~0u, ~0u}, + + {SSL_TXT_kDHE, SSL_kDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, + {SSL_TXT_kEDH, SSL_kDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, + {SSL_TXT_DH, SSL_kDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, + + {SSL_TXT_kECDHE, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, + {SSL_TXT_kEECDH, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, + {SSL_TXT_ECDH, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, + + {SSL_TXT_kPSK, SSL_kPSK, ~0u, ~0u, ~0u, ~0u, ~0u}, + + /* server authentication aliases */ + {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}, + + /* aliases combining key exchange and server authentication */ + {SSL_TXT_DHE, SSL_kDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, + {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, ~0u, ~0u, ~0u, ~0u}, + {SSL_TXT_PSK, SSL_kPSK, SSL_aPSK, ~0u, ~0u, ~0u, ~0u}, + + /* symmetric encryption aliases */ + {SSL_TXT_3DES, ~0u, ~0u, SSL_3DES, ~0u, ~0u, ~0u}, + {SSL_TXT_RC4, ~0u, ~0u, SSL_RC4, ~0u, ~0u, ~0u}, + {SSL_TXT_AES128, ~0u, ~0u, SSL_AES128 | SSL_AES128GCM, ~0u, ~0u, ~0u}, + {SSL_TXT_AES256, ~0u, ~0u, SSL_AES256 | SSL_AES256GCM, ~0u, ~0u, ~0u}, + {SSL_TXT_AES, ~0u, ~0u, SSL_AES, ~0u, ~0u, ~0u}, + {SSL_TXT_AES_GCM, ~0u, ~0u, SSL_AES128GCM | SSL_AES256GCM, ~0u, ~0u, ~0u}, + {SSL_TXT_CHACHA20, ~0u, ~0u, SSL_CHACHA20POLY1305, ~0u, ~0u, ~0u}, + + /* MAC aliases */ + {SSL_TXT_MD5, ~0u, ~0u, ~0u, SSL_MD5, ~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, ~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, ~0u, ~0u, ~0u, SSL_FIPS}, +}; + +#define NUM_CIPHER_ALIASES (sizeof(kCipherAliases) / sizeof(kCipherAliases[0])) + +int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead, + size_t *out_mac_secret_len, + size_t *out_fixed_iv_len, + const SSL_CIPHER *cipher, uint16_t version) { + *out_aead = NULL; + *out_mac_secret_len = 0; + *out_fixed_iv_len = 0; + + switch (cipher->algorithm_enc) { + case SSL_AES128GCM: + *out_aead = EVP_aead_aes_128_gcm(); + *out_fixed_iv_len = 4; + return 1; + + case SSL_AES256GCM: + *out_aead = EVP_aead_aes_256_gcm(); + *out_fixed_iv_len = 4; + return 1; + + case SSL_CHACHA20POLY1305: + *out_aead = EVP_aead_chacha20_poly1305(); + *out_fixed_iv_len = 0; + return 1; + + case SSL_RC4: + switch (cipher->algorithm_mac) { + case SSL_MD5: + if (version == SSL3_VERSION) { + *out_aead = EVP_aead_rc4_md5_ssl3(); + } else { + *out_aead = EVP_aead_rc4_md5_tls(); + } + *out_mac_secret_len = MD5_DIGEST_LENGTH; + return 1; + case SSL_SHA1: + if (version == SSL3_VERSION) { + *out_aead = EVP_aead_rc4_sha1_ssl3(); + } else { + *out_aead = EVP_aead_rc4_sha1_tls(); + } + *out_mac_secret_len = SHA_DIGEST_LENGTH; + return 1; + default: + return 0; + } + + case SSL_AES128: + switch (cipher->algorithm_mac) { + case SSL_SHA1: + if (version == SSL3_VERSION) { + *out_aead = EVP_aead_aes_128_cbc_sha1_ssl3(); + *out_fixed_iv_len = 16; + } else if (version == TLS1_VERSION) { + *out_aead = EVP_aead_aes_128_cbc_sha1_tls_implicit_iv(); + *out_fixed_iv_len = 16; + } else { + *out_aead = EVP_aead_aes_128_cbc_sha1_tls(); + } + *out_mac_secret_len = SHA_DIGEST_LENGTH; + return 1; + case SSL_SHA256: + *out_aead = EVP_aead_aes_128_cbc_sha256_tls(); + *out_mac_secret_len = SHA256_DIGEST_LENGTH; + return 1; + default: + return 0; + } + + case SSL_AES256: + switch (cipher->algorithm_mac) { + case SSL_SHA1: + if (version == SSL3_VERSION) { + *out_aead = EVP_aead_aes_256_cbc_sha1_ssl3(); + *out_fixed_iv_len = 16; + } else if (version == TLS1_VERSION) { + *out_aead = EVP_aead_aes_256_cbc_sha1_tls_implicit_iv(); + *out_fixed_iv_len = 16; + } else { + *out_aead = EVP_aead_aes_256_cbc_sha1_tls(); + } + *out_mac_secret_len = SHA_DIGEST_LENGTH; + return 1; + case SSL_SHA256: + *out_aead = EVP_aead_aes_256_cbc_sha256_tls(); + *out_mac_secret_len = SHA256_DIGEST_LENGTH; + return 1; + case SSL_SHA384: + *out_aead = EVP_aead_aes_256_cbc_sha384_tls(); + *out_mac_secret_len = SHA384_DIGEST_LENGTH; + return 1; + default: + return 0; + } + + case SSL_3DES: + switch (cipher->algorithm_mac) { + case SSL_SHA1: + if (version == SSL3_VERSION) { + *out_aead = EVP_aead_des_ede3_cbc_sha1_ssl3(); + *out_fixed_iv_len = 8; + } else if (version == TLS1_VERSION) { + *out_aead = EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv(); + *out_fixed_iv_len = 8; + } else { + *out_aead = EVP_aead_des_ede3_cbc_sha1_tls(); + } + *out_mac_secret_len = SHA_DIGEST_LENGTH; + return 1; + default: + return 0; + } + + default: + return 0; + } +} + +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) \ + (((a) == ':') || ((a) == ' ') || ((a) == ';') || ((a) == ',')) + +/* rule_equals returns one iff the NUL-terminated string |rule| is equal to the + * |buf_len| bytes at |buf|. */ +static int rule_equals(const char *rule, const char *buf, size_t buf_len) { + /* |strncmp| alone only checks that |buf| is a prefix of |rule|. */ + return strncmp(rule, buf, buf_len) == 0 && rule[buf_len] == '\0'; +} + +static void ll_append_tail(CIPHER_ORDER **head, CIPHER_ORDER *curr, + CIPHER_ORDER **tail) { + if (curr == *tail) { + return; + } + if (curr == *head) { + *head = curr->next; + } + if (curr->prev != NULL) { + curr->prev->next = curr->next; + } + if (curr->next != NULL) { + curr->next->prev = curr->prev; + } + (*tail)->next = curr; + curr->prev = *tail; + curr->next = NULL; + *tail = curr; +} + +static void ll_append_head(CIPHER_ORDER **head, CIPHER_ORDER *curr, + CIPHER_ORDER **tail) { + if (curr == *head) { + return; + } + if (curr == *tail) { + *tail = curr->prev; + } + if (curr->next != NULL) { + curr->next->prev = curr->prev; + } + if (curr->prev != NULL) { + curr->prev->next = curr->next; + } + (*head)->prev = curr; + curr->next = *head; + curr->prev = NULL; + *head = curr; +} + +static void ssl_cipher_collect_ciphers(const SSL_PROTOCOL_METHOD *ssl_method, + size_t num_of_ciphers, + CIPHER_ORDER *co_list, + CIPHER_ORDER **head_p, + CIPHER_ORDER **tail_p) { + size_t i, co_list_num; + + /* We have num_of_ciphers descriptions compiled in, depending on the method + * selected (SSLv2 and/or SSLv3, TLSv1 etc). These will later be sorted in a + * linked list with at most num entries. */ + + /* Get the initial list of ciphers */ + co_list_num = 0; /* actual count of ciphers */ + for (i = 0; i < num_of_ciphers; i++) { + const SSL_CIPHER *c = ssl_method->get_cipher(i); + if (c != NULL) { + co_list[co_list_num].cipher = c; + co_list[co_list_num].next = NULL; + co_list[co_list_num].prev = NULL; + co_list[co_list_num].active = 0; + co_list[co_list_num].in_group = 0; + co_list_num++; + } + } + + /* Prepare linked list from list entries. */ + if (co_list_num > 0) { + co_list[0].prev = NULL; + + if (co_list_num > 1) { + co_list[0].next = &co_list[1]; + + for (i = 1; i < co_list_num - 1; i++) { + co_list[i].prev = &co_list[i - 1]; + co_list[i].next = &co_list[i + 1]; + } + + co_list[co_list_num - 1].prev = &co_list[co_list_num - 2]; + } + + co_list[co_list_num - 1].next = NULL; + + *head_p = &co_list[0]; + *tail_p = &co_list[co_list_num - 1]; + } +} + +/* ssl_cipher_apply_rule applies the rule type |rule| to ciphers matching its + * parameters in the linked list from |*head_p| to |*tail_p|. It writes the new + * head and tail of the list to |*head_p| and |*tail_p|, respectively. + * + * - If |cipher_id| is non-zero, only that cipher is selected. + * - Otherwise, if |strength_bits| is non-negative, it selects ciphers + * of that strength. + * - Otherwise, it selects ciphers that match each bitmasks in |alg_*| and + * |algo_strength|. */ +static void ssl_cipher_apply_rule( + uint32_t cipher_id, uint32_t alg_mkey, uint32_t alg_auth, + uint32_t alg_enc, uint32_t alg_mac, uint32_t alg_ssl, + uint32_t algo_strength, int rule, int strength_bits, int in_group, + CIPHER_ORDER **head_p, CIPHER_ORDER **tail_p) { + CIPHER_ORDER *head, *tail, *curr, *next, *last; + const SSL_CIPHER *cp; + int reverse = 0; + + if (cipher_id == 0 && strength_bits == -1 && + (alg_mkey == 0 || alg_auth == 0 || alg_enc == 0 || alg_mac == 0 || + alg_ssl == 0 || algo_strength == 0)) { + /* The rule matches nothing, so bail early. */ + return; + } + + if (rule == CIPHER_DEL) { + /* needed to maintain sorting between currently deleted ciphers */ + reverse = 1; + } + + head = *head_p; + tail = *tail_p; + + if (reverse) { + next = tail; + last = head; + } else { + next = head; + last = tail; + } + + curr = NULL; + for (;;) { + if (curr == last) { + break; + } + + curr = next; + if (curr == NULL) { + break; + } + + next = reverse ? curr->prev : curr->next; + cp = curr->cipher; + + /* Selection criteria is either a specific cipher, the value of + * |strength_bits|, or the algorithms used. */ + if (cipher_id != 0) { + if (cipher_id != cp->id) { + continue; + } + } else if (strength_bits >= 0) { + if (strength_bits != cp->strength_bits) { + continue; + } + } else if (!(alg_mkey & cp->algorithm_mkey) || + !(alg_auth & cp->algorithm_auth) || + !(alg_enc & cp->algorithm_enc) || + !(alg_mac & cp->algorithm_mac) || + !(alg_ssl & cp->algorithm_ssl) || + !(algo_strength & cp->algo_strength)) { + continue; + } + + /* add the cipher if it has not been added yet. */ + if (rule == CIPHER_ADD) { + /* reverse == 0 */ + if (!curr->active) { + ll_append_tail(&head, curr, &tail); + curr->active = 1; + curr->in_group = in_group; + } + } + + /* Move the added cipher to this location */ + else if (rule == CIPHER_ORD) { + /* reverse == 0 */ + if (curr->active) { + ll_append_tail(&head, curr, &tail); + curr->in_group = 0; + } + } else if (rule == CIPHER_DEL) { + /* reverse == 1 */ + if (curr->active) { + /* most recently deleted ciphersuites get best positions + * for any future CIPHER_ADD (note that the CIPHER_DEL loop + * works in reverse to maintain the order) */ + ll_append_head(&head, curr, &tail); + curr->active = 0; + curr->in_group = 0; + } + } else if (rule == CIPHER_KILL) { + /* reverse == 0 */ + if (head == curr) { + head = curr->next; + } else { + curr->prev->next = curr->next; + } + + if (tail == curr) { + tail = curr->prev; + } + curr->active = 0; + if (curr->next != NULL) { + curr->next->prev = curr->prev; + } + if (curr->prev != NULL) { + curr->prev->next = curr->next; + } + curr->next = NULL; + curr->prev = NULL; + } + } + + *head_p = head; + *tail_p = tail; +} + +static int ssl_cipher_strength_sort(CIPHER_ORDER **head_p, + CIPHER_ORDER **tail_p) { + int max_strength_bits, i, *number_uses; + CIPHER_ORDER *curr; + + /* This routine sorts the ciphers with descending strength. The sorting must + * keep the pre-sorted sequence, so we apply the normal sorting routine as + * '+' movement to the end of the list. */ + max_strength_bits = 0; + curr = *head_p; + while (curr != NULL) { + if (curr->active && curr->cipher->strength_bits > max_strength_bits) { + max_strength_bits = curr->cipher->strength_bits; + } + curr = curr->next; + } + + number_uses = OPENSSL_malloc((max_strength_bits + 1) * sizeof(int)); + if (!number_uses) { + OPENSSL_PUT_ERROR(SSL, ssl_cipher_strength_sort, ERR_R_MALLOC_FAILURE); + return 0; + } + memset(number_uses, 0, (max_strength_bits + 1) * sizeof(int)); + + /* Now find the strength_bits values actually used. */ + curr = *head_p; + while (curr != NULL) { + if (curr->active) { + number_uses[curr->cipher->strength_bits]++; + } + curr = curr->next; + } + + /* Go through the list of used strength_bits values in descending order. */ + for (i = max_strength_bits; i >= 0; i--) { + if (number_uses[i] > 0) { + ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ORD, i, 0, head_p, + tail_p); + } + } + + OPENSSL_free(number_uses); + return 1; +} + +static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, + const char *rule_str, + CIPHER_ORDER **head_p, + CIPHER_ORDER **tail_p) { + uint32_t alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, algo_strength; + const char *l, *buf; + int multi, rule, retval, ok, in_group = 0, has_group = 0; + size_t j, buf_len; + uint32_t cipher_id; + char ch; + + retval = 1; + l = rule_str; + for (;;) { + ch = *l; + + if (ch == '\0') { + break; /* done */ + } + + if (in_group) { + if (ch == ']') { + if (*tail_p) { + (*tail_p)->in_group = 0; + } + in_group = 0; + l++; + continue; + } + + if (ch == '|') { + rule = CIPHER_ADD; + l++; + continue; + } else if (!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') && + !(ch >= '0' && ch <= '9')) { + OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, + SSL_R_UNEXPECTED_OPERATOR_IN_GROUP); + retval = in_group = 0; + break; + } else { + rule = CIPHER_ADD; + } + } else if (ch == '-') { + rule = CIPHER_DEL; + l++; + } else if (ch == '+') { + rule = CIPHER_ORD; + l++; + } else if (ch == '!') { + rule = CIPHER_KILL; + l++; + } else if (ch == '@') { + rule = CIPHER_SPECIAL; + l++; + } else if (ch == '[') { + if (in_group) { + OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_NESTED_GROUP); + retval = in_group = 0; + break; + } + in_group = 1; + has_group = 1; + l++; + continue; + } else { + rule = CIPHER_ADD; + } + + /* 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_cipher_process_rulestr, + SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS); + retval = in_group = 0; + break; + } + + if (ITEM_SEP(ch)) { + l++; + continue; + } + + multi = 0; + cipher_id = 0; + alg_mkey = ~0u; + alg_auth = ~0u; + alg_enc = ~0u; + alg_mac = ~0u; + alg_ssl = ~0u; + algo_strength = ~0u; + + for (;;) { + ch = *l; + buf = l; + buf_len = 0; + while (((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9')) || + ((ch >= 'a') && (ch <= 'z')) || (ch == '-') || (ch == '.')) { + ch = *(++l); + buf_len++; + } + + 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_cipher_process_rulestr, + SSL_R_INVALID_COMMAND); + retval = in_group = 0; + l++; + break; + } + + if (rule == CIPHER_SPECIAL) { + break; + } + + /* Look for a matching exact cipher. These aren't allowed in multipart + * rules. */ + if (!multi && ch != '+') { + size_t num_ciphers = ssl_method->num_ciphers(); + for (j = 0; j < num_ciphers; j++) { + const SSL_CIPHER *cipher = ssl_method->get_cipher(j); + if (cipher != NULL && rule_equals(cipher->name, buf, buf_len)) { + cipher_id = cipher->id; + break; + } + } + } + if (cipher_id == 0) { + /* If not an exact cipher, look for a matching cipher alias. */ + for (j = 0; j < NUM_CIPHER_ALIASES; j++) { + if (rule_equals(kCipherAliases[j].name, buf, buf_len)) { + alg_mkey &= kCipherAliases[j].algorithm_mkey; + alg_auth &= kCipherAliases[j].algorithm_auth; + alg_enc &= kCipherAliases[j].algorithm_enc; + alg_mac &= kCipherAliases[j].algorithm_mac; + alg_ssl &= kCipherAliases[j].algorithm_ssl; + algo_strength &= kCipherAliases[j].algo_strength; + break; + } + } + if (j == NUM_CIPHER_ALIASES) { + alg_mkey = alg_auth = alg_enc = alg_mac = alg_ssl = algo_strength = 0; + } + } + + /* Check for a multipart rule. */ + if (ch != '+') { + break; + } + l++; + multi = 1; + } + + /* Ok, we have the rule, now apply it. */ + if (rule == CIPHER_SPECIAL) { + /* special command */ + ok = 0; + if (buf_len == 8 && !strncmp(buf, "STRENGTH", 8)) { + ok = ssl_cipher_strength_sort(head_p, tail_p); + } else { + OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, + SSL_R_INVALID_COMMAND); + } + + if (ok == 0) { + retval = 0; + } + + /* We do not support any "multi" options together with "@", so throw away + * the rest of the command, if any left, until end or ':' is found. */ + while (*l != '\0' && !ITEM_SEP(*l)) { + l++; + } + } else { + ssl_cipher_apply_rule(cipher_id, alg_mkey, alg_auth, alg_enc, alg_mac, + alg_ssl, algo_strength, rule, -1, in_group, head_p, + tail_p); + } + } + + if (in_group) { + OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_INVALID_COMMAND); + retval = 0; + } + + return retval; +} + +STACK_OF(SSL_CIPHER) * +ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, + struct ssl_cipher_preference_list_st **out_cipher_list, + STACK_OF(SSL_CIPHER) **out_cipher_list_by_id, + const char *rule_str) { + int ok; + size_t num_of_ciphers; + STACK_OF(SSL_CIPHER) *cipherstack = NULL, *tmp_cipher_list = NULL; + const char *rule_p; + CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr; + uint8_t *in_group_flags = NULL; + unsigned int num_in_group_flags = 0; + struct ssl_cipher_preference_list_st *pref_list = NULL; + + /* Return with error if nothing to do. */ + if (rule_str == NULL || out_cipher_list == NULL) { + return NULL; + } + + /* Now we have to collect the available ciphers from the compiled in ciphers. + * We cannot get more than the number compiled in, so it is used for + * allocation. */ + num_of_ciphers = ssl_method->num_ciphers(); + co_list = + (CIPHER_ORDER *)OPENSSL_malloc(sizeof(CIPHER_ORDER) * num_of_ciphers); + if (co_list == NULL) { + OPENSSL_PUT_ERROR(SSL, ssl_create_cipher_list, ERR_R_MALLOC_FAILURE); + return NULL; + } + + ssl_cipher_collect_ciphers(ssl_method, num_of_ciphers, co_list, &head, &tail); + + /* Now arrange all ciphers by preference: + * TODO(davidben): Compute this order once and copy it. */ + + /* Everything else being equal, prefer ECDHE_ECDSA then ECDHE_RSA over other + * key exchange mechanisms */ + ssl_cipher_apply_rule(0, SSL_kECDHE, SSL_aECDSA, ~0u, ~0u, ~0u, ~0u, + CIPHER_ADD, -1, 0, &head, &tail); + ssl_cipher_apply_rule(0, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u, CIPHER_ADD, -1, + 0, &head, &tail); + ssl_cipher_apply_rule(0, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u, CIPHER_DEL, -1, + 0, &head, &tail); + + /* Order the bulk ciphers. First the preferred AEAD ciphers. We prefer + * CHACHA20 unless there is hardware support for fast and constant-time + * AES_GCM. */ + if (EVP_has_aes_hardware()) { + ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256GCM, ~0u, ~0u, ~0u, CIPHER_ADD, + -1, 0, &head, &tail); + ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128GCM, ~0u, ~0u, ~0u, CIPHER_ADD, + -1, 0, &head, &tail); + ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_CHACHA20POLY1305, ~0u, ~0u, ~0u, + CIPHER_ADD, -1, 0, &head, &tail); + } else { + ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_CHACHA20POLY1305, ~0u, ~0u, ~0u, + CIPHER_ADD, -1, 0, &head, &tail); + ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256GCM, ~0u, ~0u, ~0u, CIPHER_ADD, + -1, 0, &head, &tail); + ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128GCM, ~0u, ~0u, ~0u, CIPHER_ADD, + -1, 0, &head, &tail); + } + + /* Then the legacy non-AEAD ciphers: AES_256_CBC, AES-128_CBC, RC4_128_SHA, + * RC4_128_MD5, 3DES_EDE_CBC_SHA. */ + ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256, ~0u, ~0u, ~0u, CIPHER_ADD, -1, + 0, &head, &tail); + ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128, ~0u, ~0u, ~0u, CIPHER_ADD, -1, + 0, &head, &tail); + ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_RC4, ~SSL_MD5, ~0u, ~0u, CIPHER_ADD, + -1, 0, &head, &tail); + ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_RC4, SSL_MD5, ~0u, ~0u, CIPHER_ADD, -1, + 0, &head, &tail); + ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_3DES, ~0u, ~0u, ~0u, CIPHER_ADD, -1, 0, + &head, &tail); + + /* Temporarily enable everything else for sorting */ + ssl_cipher_apply_rule(0, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, CIPHER_ADD, -1, 0, + &head, &tail); + + /* Move ciphers without forward secrecy to the end. */ + ssl_cipher_apply_rule(0, ~(SSL_kDHE | SSL_kECDHE), ~0u, ~0u, ~0u, ~0u, ~0u, + CIPHER_ORD, -1, 0, &head, &tail); + + /* Now disable everything (maintaining the ordering!) */ + ssl_cipher_apply_rule(0, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, CIPHER_DEL, -1, 0, + &head, &tail); + + /* If the rule_string begins with DEFAULT, apply the default rule before + * using the (possibly available) additional rules. */ + ok = 1; + rule_p = rule_str; + if (strncmp(rule_str, "DEFAULT", 7) == 0) { + ok = ssl_cipher_process_rulestr(ssl_method, SSL_DEFAULT_CIPHER_LIST, &head, + &tail); + rule_p += 7; + if (*rule_p == ':') { + rule_p++; + } + } + + if (ok && strlen(rule_p) > 0) { + ok = ssl_cipher_process_rulestr(ssl_method, rule_p, &head, &tail); + } + + if (!ok) { + goto err; + } + + /* Allocate new "cipherstack" for the result, return with error + * if we cannot get one. */ + cipherstack = sk_SSL_CIPHER_new_null(); + if (cipherstack == NULL) { + goto err; + } + + in_group_flags = OPENSSL_malloc(num_of_ciphers); + if (!in_group_flags) { + goto err; + } + + /* The cipher selection for the list is done. The ciphers are added + * to the resulting precedence to the STACK_OF(SSL_CIPHER). */ + for (curr = head; curr != NULL; curr = curr->next) { + if (curr->active) { + if (!sk_SSL_CIPHER_push(cipherstack, curr->cipher)) { + goto err; + } + in_group_flags[num_in_group_flags++] = curr->in_group; + } + } + OPENSSL_free(co_list); /* Not needed any longer */ + co_list = NULL; + + tmp_cipher_list = sk_SSL_CIPHER_dup(cipherstack); + if (tmp_cipher_list == NULL) { + goto err; + } + pref_list = OPENSSL_malloc(sizeof(struct ssl_cipher_preference_list_st)); + if (!pref_list) { + goto err; + } + pref_list->ciphers = cipherstack; + pref_list->in_group_flags = OPENSSL_malloc(num_in_group_flags); + if (!pref_list->in_group_flags) { + goto err; + } + memcpy(pref_list->in_group_flags, in_group_flags, num_in_group_flags); + OPENSSL_free(in_group_flags); + in_group_flags = NULL; + if (*out_cipher_list != NULL) { + ssl_cipher_preference_list_free(*out_cipher_list); + } + *out_cipher_list = pref_list; + pref_list = NULL; + + if (out_cipher_list_by_id != NULL) { + sk_SSL_CIPHER_free(*out_cipher_list_by_id); + *out_cipher_list_by_id = tmp_cipher_list; + tmp_cipher_list = NULL; + (void) sk_SSL_CIPHER_set_cmp_func(*out_cipher_list_by_id, + ssl_cipher_ptr_id_cmp); + + sk_SSL_CIPHER_sort(*out_cipher_list_by_id); + } else { + sk_SSL_CIPHER_free(tmp_cipher_list); + tmp_cipher_list = NULL; + } + + return cipherstack; + +err: + OPENSSL_free(co_list); + OPENSSL_free(in_group_flags); + sk_SSL_CIPHER_free(cipherstack); + sk_SSL_CIPHER_free(tmp_cipher_list); + if (pref_list) { + OPENSSL_free(pref_list->in_group_flags); + } + OPENSSL_free(pref_list); + return NULL; +} + +uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *cipher) { return cipher->id; } + +int SSL_CIPHER_is_AES(const SSL_CIPHER *cipher) { + return (cipher->algorithm_enc & SSL_AES) != 0; +} + +int SSL_CIPHER_has_MD5_HMAC(const SSL_CIPHER *cipher) { + return (cipher->algorithm_mac & SSL_MD5) != 0; +} + +int SSL_CIPHER_is_AESGCM(const SSL_CIPHER *cipher) { + 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; +} + +/* return the actual cipher being used */ +const char *SSL_CIPHER_get_name(const SSL_CIPHER *cipher) { + if (cipher != NULL) { + return cipher->name; + } + + return "(NONE)"; +} + +const char *SSL_CIPHER_get_kx_name(const SSL_CIPHER *cipher) { + if (cipher == NULL) { + return ""; + } + + switch (cipher->algorithm_mkey) { + case SSL_kRSA: + return "RSA"; + + case SSL_kDHE: + switch (cipher->algorithm_auth) { + case SSL_aRSA: + return "DHE_RSA"; + default: + assert(0); + return "UNKNOWN"; + } + + case SSL_kECDHE: + switch (cipher->algorithm_auth) { + case SSL_aECDSA: + return "ECDHE_ECDSA"; + case SSL_aRSA: + return "ECDHE_RSA"; + case SSL_aPSK: + return "ECDHE_PSK"; + default: + assert(0); + return "UNKNOWN"; + } + + case SSL_kPSK: + assert(cipher->algorithm_auth == SSL_aPSK); + return "PSK"; + + default: + assert(0); + return "UNKNOWN"; + } +} + +static const char *ssl_cipher_get_enc_name(const SSL_CIPHER *cipher) { + switch (cipher->algorithm_enc) { + case SSL_3DES: + return "3DES_EDE_CBC"; + case SSL_RC4: + return "RC4"; + case SSL_AES128: + return "AES_128_CBC"; + case SSL_AES256: + return "AES_256_CBC"; + case SSL_AES128GCM: + return "AES_128_GCM"; + case SSL_AES256GCM: + return "AES_256_GCM"; + case SSL_CHACHA20POLY1305: + return "CHACHA20_POLY1305"; + break; + default: + assert(0); + return "UNKNOWN"; + } +} + +static const char *ssl_cipher_get_prf_name(const SSL_CIPHER *cipher) { + if ((cipher->algorithm2 & TLS1_PRF) == TLS1_PRF) { + /* 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 & TLS1_PRF_SHA256) { + return "SHA256"; + } else if (cipher->algorithm2 & TLS1_PRF_SHA384) { + return "SHA384"; + } else { + assert(0); + return "UNKNOWN"; + } +} + +char *SSL_CIPHER_get_rfc_name(const SSL_CIPHER *cipher) { + if (cipher == NULL) { + return NULL; + } + + const char *kx_name = SSL_CIPHER_get_kx_name(cipher); + const char *enc_name = ssl_cipher_get_enc_name(cipher); + const char *prf_name = ssl_cipher_get_prf_name(cipher); + + /* The final name is TLS_{kx_name}_WITH_{enc_name}_{prf_name}. */ + size_t len = 4 + strlen(kx_name) + 6 + strlen(enc_name) + 1 + + strlen(prf_name) + 1; + char *ret = OPENSSL_malloc(len); + if (ret == NULL) { + return NULL; + } + if (BUF_strlcpy(ret, "TLS_", len) >= len || + BUF_strlcat(ret, kx_name, len) >= len || + BUF_strlcat(ret, "_WITH_", len) >= len || + BUF_strlcat(ret, enc_name, len) >= len || + BUF_strlcat(ret, "_", len) >= len || + BUF_strlcat(ret, prf_name, len) >= len) { + assert(0); + OPENSSL_free(ret); + return NULL; + } + assert(strlen(ret) + 1 == len); + return ret; +} + +int SSL_CIPHER_get_bits(const SSL_CIPHER *cipher, int *out_alg_bits) { + if (cipher == NULL) { + return 0; + } + + if (out_alg_bits != NULL) { + *out_alg_bits = cipher->alg_bits; + } + return cipher->strength_bits; +} + +const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, + int len) { + const char *ver; + const char *kx, *au, *enc, *mac; + uint32_t alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl; + static const char *format = "%-23s %s Kx=%-8s Au=%-4s Enc=%-9s Mac=%-4s\n"; + + alg_mkey = cipher->algorithm_mkey; + alg_auth = cipher->algorithm_auth; + alg_enc = cipher->algorithm_enc; + alg_mac = cipher->algorithm_mac; + alg_ssl = cipher->algorithm_ssl; + + if (alg_ssl & SSL_SSLV3) { + ver = "SSLv3"; + } else if (alg_ssl & SSL_TLSV1_2) { + ver = "TLSv1.2"; + } else { + ver = "unknown"; + } + + switch (alg_mkey) { + case SSL_kRSA: + kx = "RSA"; + break; + + case SSL_kDHE: + kx = "DH"; + break; + + case SSL_kECDHE: + kx = "ECDH"; + break; + + case SSL_kPSK: + kx = "PSK"; + break; + + default: + kx = "unknown"; + } + + switch (alg_auth) { + case SSL_aRSA: + au = "RSA"; + break; + + case SSL_aECDSA: + au = "ECDSA"; + break; + + case SSL_aPSK: + au = "PSK"; + break; + + default: + au = "unknown"; + break; + } + + switch (alg_enc) { + case SSL_3DES: + enc = "3DES(168)"; + break; + + case SSL_RC4: + enc = "RC4(128)"; + break; + + case SSL_AES128: + enc = "AES(128)"; + break; + + case SSL_AES256: + enc = "AES(256)"; + break; + + case SSL_AES128GCM: + enc = "AESGCM(128)"; + break; + + case SSL_AES256GCM: + enc = "AESGCM(256)"; + break; + + case SSL_CHACHA20POLY1305: + enc = "ChaCha20-Poly1305"; + break; + + default: + enc = "unknown"; + break; + } + + switch (alg_mac) { + case SSL_MD5: + mac = "MD5"; + break; + + case SSL_SHA1: + mac = "SHA1"; + break; + + case SSL_SHA256: + mac = "SHA256"; + break; + + case SSL_SHA384: + mac = "SHA384"; + break; + + case SSL_AEAD: + mac = "AEAD"; + break; + + default: + mac = "unknown"; + break; + } + + if (buf == NULL) { + len = 128; + buf = OPENSSL_malloc(len); + if (buf == NULL) { + return NULL; + } + } else if (len < 128) { + return "Buffer too small"; + } + + BIO_snprintf(buf, len, format, cipher->name, ver, kx, au, enc, mac); + return buf; +} + +const char *SSL_CIPHER_get_version(const SSL_CIPHER *cipher) { + return "TLSv1/SSLv3"; +} + +void *SSL_COMP_get_compression_methods(void) { return NULL; } + +int SSL_COMP_add_compression_method(int id, void *cm) { return 1; } + +const char *SSL_COMP_get_name(const void *comp) { return NULL; } + +int ssl_cipher_get_cert_index(const SSL_CIPHER *cipher) { + uint32_t alg_a = cipher->algorithm_auth; + + if (alg_a & SSL_aECDSA) { + return SSL_PKEY_ECC; + } else if (alg_a & SSL_aRSA) { + return SSL_PKEY_RSA_ENC; + } + + return -1; +} + +int ssl_cipher_has_server_public_key(const SSL_CIPHER *cipher) { + /* 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; + } + + /* All other ciphers include it. */ + return 1; +} + +int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher) { + /* Ephemeral Diffie-Hellman key exchanges require a ServerKeyExchange. */ + if (cipher->algorithm_mkey & SSL_kDHE || cipher->algorithm_mkey & SSL_kECDHE) { + return 1; + } + + /* It is optional in all others. */ + return 0; +} diff --git a/src/ssl/ssl_error.c b/src/ssl/ssl_error.c deleted file mode 100644 index 2ffb9e6..0000000 --- a/src/ssl/ssl_error.c +++ /dev/null @@ -1,566 +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 - -#include - -const ERR_STRING_DATA SSL_error_string_data[] = { - {ERR_PACK(ERR_LIB_SSL, SSL_F_D2I_SSL_SESSION, 0), "D2I_SSL_SESSION"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_check_private_key, 0), "SSL_CTX_check_private_key"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_new, 0), "SSL_CTX_new"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_set_cipher_list, 0), "SSL_CTX_set_cipher_list"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_set_cipher_list_tls11, 0), "SSL_CTX_set_cipher_list_tls11"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_set_session_id_context, 0), "SSL_CTX_set_session_id_context"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_set_ssl_version, 0), "SSL_CTX_set_ssl_version"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_PrivateKey, 0), "SSL_CTX_use_PrivateKey"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_PrivateKey_ASN1, 0), "SSL_CTX_use_PrivateKey_ASN1"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_PrivateKey_file, 0), "SSL_CTX_use_PrivateKey_file"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_RSAPrivateKey, 0), "SSL_CTX_use_RSAPrivateKey"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_RSAPrivateKey_ASN1, 0), "SSL_CTX_use_RSAPrivateKey_ASN1"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_RSAPrivateKey_file, 0), "SSL_CTX_use_RSAPrivateKey_file"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_authz, 0), "SSL_CTX_use_authz"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_certificate, 0), "SSL_CTX_use_certificate"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_certificate_ASN1, 0), "SSL_CTX_use_certificate_ASN1"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_certificate_chain_file, 0), "SSL_CTX_use_certificate_chain_file"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_certificate_file, 0), "SSL_CTX_use_certificate_file"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_psk_identity_hint, 0), "SSL_CTX_use_psk_identity_hint"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_new, 0), "SSL_SESSION_new"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_print_fp, 0), "SSL_SESSION_print_fp"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_set1_id_context, 0), "SSL_SESSION_set1_id_context"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_to_bytes_full, 0), "SSL_SESSION_to_bytes_full"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_accept, 0), "SSL_accept"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_add_dir_cert_subjects_to_stack, 0), "SSL_add_dir_cert_subjects_to_stack"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_add_file_cert_subjects_to_stack, 0), "SSL_add_file_cert_subjects_to_stack"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_check_private_key, 0), "SSL_check_private_key"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_clear, 0), "SSL_clear"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_connect, 0), "SSL_connect"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_do_handshake, 0), "SSL_do_handshake"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_load_client_CA_file, 0), "SSL_load_client_CA_file"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_new, 0), "SSL_new"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_peek, 0), "SSL_peek"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_read, 0), "SSL_read"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_set_cipher_list, 0), "SSL_set_cipher_list"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_set_fd, 0), "SSL_set_fd"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_set_rfd, 0), "SSL_set_rfd"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_set_session, 0), "SSL_set_session"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_set_session_id_context, 0), "SSL_set_session_id_context"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_set_session_ticket_ext, 0), "SSL_set_session_ticket_ext"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_set_wfd, 0), "SSL_set_wfd"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_shutdown, 0), "SSL_shutdown"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_PrivateKey, 0), "SSL_use_PrivateKey"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_PrivateKey_ASN1, 0), "SSL_use_PrivateKey_ASN1"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_PrivateKey_file, 0), "SSL_use_PrivateKey_file"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_RSAPrivateKey, 0), "SSL_use_RSAPrivateKey"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_RSAPrivateKey_ASN1, 0), "SSL_use_RSAPrivateKey_ASN1"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_RSAPrivateKey_file, 0), "SSL_use_RSAPrivateKey_file"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_authz, 0), "SSL_use_authz"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_certificate, 0), "SSL_use_certificate"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_certificate_ASN1, 0), "SSL_use_certificate_ASN1"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_certificate_file, 0), "SSL_use_certificate_file"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_psk_identity_hint, 0), "SSL_use_psk_identity_hint"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_write, 0), "SSL_write"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_authz_find_data, 0), "authz_find_data"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_check_suiteb_cipher_list, 0), "check_suiteb_cipher_list"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_d2i_SSL_SESSION, 0), "d2i_SSL_SESSION"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_d2i_SSL_SESSION_get_octet_string, 0), "d2i_SSL_SESSION_get_octet_string"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_d2i_SSL_SESSION_get_string, 0), "d2i_SSL_SESSION_get_string"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_do_dtls1_write, 0), "do_dtls1_write"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_do_ssl3_write, 0), "do_ssl3_write"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_accept, 0), "dtls1_accept"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_buffer_record, 0), "dtls1_buffer_record"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_check_timeout_num, 0), "dtls1_check_timeout_num"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_connect, 0), "dtls1_connect"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_do_write, 0), "dtls1_do_write"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_get_hello_verify, 0), "dtls1_get_hello_verify"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_get_message, 0), "dtls1_get_message"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_get_message_fragment, 0), "dtls1_get_message_fragment"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_heartbeat, 0), "dtls1_heartbeat"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_preprocess_fragment, 0), "dtls1_preprocess_fragment"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_process_record, 0), "dtls1_process_record"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_read_bytes, 0), "dtls1_read_bytes"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_send_hello_verify_request, 0), "dtls1_send_hello_verify_request"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_write_app_data_bytes, 0), "dtls1_write_app_data_bytes"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_fclose, 0), "fclose"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_fprintf, 0), "fprintf"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_i2d_SSL_SESSION, 0), "i2d_SSL_SESSION"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_printf, 0), "printf"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_read_authz, 0), "read_authz"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_accept, 0), "ssl23_accept"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_client_hello, 0), "ssl23_client_hello"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_connect, 0), "ssl23_connect"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_get_client_hello, 0), "ssl23_get_client_hello"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_get_server_hello, 0), "ssl23_get_server_hello"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_get_v2_client_hello, 0), "ssl23_get_v2_client_hello"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_peek, 0), "ssl23_peek"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_read, 0), "ssl23_read"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_write, 0), "ssl23_write"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_accept, 0), "ssl3_accept"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_callback_ctrl, 0), "ssl3_callback_ctrl"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_cert_verify_hash, 0), "ssl3_cert_verify_hash"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_change_cipher_state, 0), "ssl3_change_cipher_state"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_check_cert_and_algorithm, 0), "ssl3_check_cert_and_algorithm"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_check_client_hello, 0), "ssl3_check_client_hello"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_connect, 0), "ssl3_connect"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_ctrl, 0), "ssl3_ctrl"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_ctx_ctrl, 0), "ssl3_ctx_ctrl"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_digest_cached_records, 0), "ssl3_digest_cached_records"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_do_change_cipher_spec, 0), "ssl3_do_change_cipher_spec"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_expect_change_cipher_spec, 0), "ssl3_expect_change_cipher_spec"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_generate_key_block, 0), "ssl3_generate_key_block"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_cert_status, 0), "ssl3_get_cert_status"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_cert_verify, 0), "ssl3_get_cert_verify"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_certificate_request, 0), "ssl3_get_certificate_request"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_channel_id, 0), "ssl3_get_channel_id"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_client_certificate, 0), "ssl3_get_client_certificate"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_client_hello, 0), "ssl3_get_client_hello"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_client_key_exchange, 0), "ssl3_get_client_key_exchange"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_finished, 0), "ssl3_get_finished"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_initial_bytes, 0), "ssl3_get_initial_bytes"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_message, 0), "ssl3_get_message"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_new_session_ticket, 0), "ssl3_get_new_session_ticket"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_next_proto, 0), "ssl3_get_next_proto"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_record, 0), "ssl3_get_record"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_server_certificate, 0), "ssl3_get_server_certificate"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_server_done, 0), "ssl3_get_server_done"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_server_hello, 0), "ssl3_get_server_hello"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_server_key_exchange, 0), "ssl3_get_server_key_exchange"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_v2_client_hello, 0), "ssl3_get_v2_client_hello"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_handshake_mac, 0), "ssl3_handshake_mac"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_prf, 0), "ssl3_prf"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_read_bytes, 0), "ssl3_read_bytes"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_read_n, 0), "ssl3_read_n"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_cert_verify, 0), "ssl3_send_cert_verify"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_certificate_request, 0), "ssl3_send_certificate_request"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_channel_id, 0), "ssl3_send_channel_id"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_certificate, 0), "ssl3_send_client_certificate"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_hello, 0), "ssl3_send_client_hello"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_key_exchange, 0), "ssl3_send_client_key_exchange"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_new_session_ticket, 0), "ssl3_send_new_session_ticket"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_certificate, 0), "ssl3_send_server_certificate"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_hello, 0), "ssl3_send_server_hello"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_key_exchange, 0), "ssl3_send_server_key_exchange"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_setup_key_block, 0), "ssl3_setup_key_block"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_setup_read_buffer, 0), "ssl3_setup_read_buffer"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_setup_write_buffer, 0), "ssl3_setup_write_buffer"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_write_bytes, 0), "ssl3_write_bytes"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_write_pending, 0), "ssl3_write_pending"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_add_cert_chain, 0), "ssl_add_cert_chain"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_add_cert_to_buf, 0), "ssl_add_cert_to_buf"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_add_clienthello_renegotiate_ext, 0), "ssl_add_clienthello_renegotiate_ext"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_add_clienthello_tlsext, 0), "ssl_add_clienthello_tlsext"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_add_clienthello_use_srtp_ext, 0), "ssl_add_clienthello_use_srtp_ext"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_add_serverhello_renegotiate_ext, 0), "ssl_add_serverhello_renegotiate_ext"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_add_serverhello_tlsext, 0), "ssl_add_serverhello_tlsext"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_add_serverhello_use_srtp_ext, 0), "ssl_add_serverhello_use_srtp_ext"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_bad_method, 0), "ssl_bad_method"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_build_cert_chain, 0), "ssl_build_cert_chain"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_bytes_to_cipher_list, 0), "ssl_bytes_to_cipher_list"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_cert_dup, 0), "ssl_cert_dup"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_cert_inst, 0), "ssl_cert_inst"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_cert_new, 0), "ssl_cert_new"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_check_serverhello_tlsext, 0), "ssl_check_serverhello_tlsext"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_check_srvr_ecc_cert_and_alg, 0), "ssl_check_srvr_ecc_cert_and_alg"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_cipher_process_rulestr, 0), "ssl_cipher_process_rulestr"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_cipher_strength_sort, 0), "ssl_cipher_strength_sort"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_create_cipher_list, 0), "ssl_create_cipher_list"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_ctx_log_master_secret, 0), "ssl_ctx_log_master_secret"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_ctx_log_rsa_client_key_exchange, 0), "ssl_ctx_log_rsa_client_key_exchange"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_ctx_make_profiles, 0), "ssl_ctx_make_profiles"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_get_new_session, 0), "ssl_get_new_session"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_get_prev_session, 0), "ssl_get_prev_session"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_get_server_cert_index, 0), "ssl_get_server_cert_index"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_get_sign_pkey, 0), "ssl_get_sign_pkey"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_init_wbio_buffer, 0), "ssl_init_wbio_buffer"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_new, 0), "ssl_new"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_parse_clienthello_renegotiate_ext, 0), "ssl_parse_clienthello_renegotiate_ext"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_parse_clienthello_tlsext, 0), "ssl_parse_clienthello_tlsext"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_parse_clienthello_use_srtp_ext, 0), "ssl_parse_clienthello_use_srtp_ext"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_parse_serverhello_renegotiate_ext, 0), "ssl_parse_serverhello_renegotiate_ext"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_parse_serverhello_tlsext, 0), "ssl_parse_serverhello_tlsext"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_parse_serverhello_use_srtp_ext, 0), "ssl_parse_serverhello_use_srtp_ext"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_prepare_clienthello_tlsext, 0), "ssl_prepare_clienthello_tlsext"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_scan_clienthello_tlsext, 0), "ssl_scan_clienthello_tlsext"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_scan_serverhello_tlsext, 0), "ssl_scan_serverhello_tlsext"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_sess_cert_new, 0), "ssl_sess_cert_new"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_set_authz, 0), "ssl_set_authz"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_set_cert, 0), "ssl_set_cert"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_set_pkey, 0), "ssl_set_pkey"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_undefined_const_function, 0), "ssl_undefined_const_function"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_undefined_function, 0), "ssl_undefined_function"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_undefined_void_function, 0), "ssl_undefined_void_function"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_verify_cert_chain, 0), "ssl_verify_cert_chain"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_tls12_check_peer_sigalg, 0), "tls12_check_peer_sigalg"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_aead_ctx_init, 0), "tls1_aead_ctx_init"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_cert_verify_mac, 0), "tls1_cert_verify_mac"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_change_cipher_state, 0), "tls1_change_cipher_state"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_change_cipher_state_aead, 0), "tls1_change_cipher_state_aead"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_change_cipher_state_cipher, 0), "tls1_change_cipher_state_cipher"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_check_duplicate_extensions, 0), "tls1_check_duplicate_extensions"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_enc, 0), "tls1_enc"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_export_keying_material, 0), "tls1_export_keying_material"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_get_server_supplemental_data, 0), "tls1_get_server_supplemental_data"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_heartbeat, 0), "tls1_heartbeat"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_prf, 0), "tls1_prf"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_send_server_supplemental_data, 0), "tls1_send_server_supplemental_data"}, - {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_setup_key_block, 0), "tls1_setup_key_block"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_APP_DATA_IN_HANDSHAKE), "APP_DATA_IN_HANDSHAKE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT), "ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_AUTHZ_DATA_TOO_LARGE), "AUTHZ_DATA_TOO_LARGE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_ALERT), "BAD_ALERT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_ALERT_RECORD), "BAD_ALERT_RECORD"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_AUTHENTICATION_TYPE), "BAD_AUTHENTICATION_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CHANGE_CIPHER_SPEC), "BAD_CHANGE_CIPHER_SPEC"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CHECKSUM), "BAD_CHECKSUM"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA), "BAD_DATA"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK), "BAD_DATA_RETURNED_BY_CALLBACK"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DECOMPRESSION), "BAD_DECOMPRESSION"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DH_G_LENGTH), "BAD_DH_G_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DH_PUB_KEY_LENGTH), "BAD_DH_PUB_KEY_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DH_P_LENGTH), "BAD_DH_P_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DIGEST_LENGTH), "BAD_DIGEST_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DSA_SIGNATURE), "BAD_DSA_SIGNATURE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_ECC_CERT), "BAD_ECC_CERT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_ECDSA_SIGNATURE), "BAD_ECDSA_SIGNATURE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_ECPOINT), "BAD_ECPOINT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_HANDSHAKE_LENGTH), "BAD_HANDSHAKE_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_HELLO_REQUEST), "BAD_HELLO_REQUEST"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_LENGTH), "BAD_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_MAC_DECODE), "BAD_MAC_DECODE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_MAC_LENGTH), "BAD_MAC_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_MESSAGE_TYPE), "BAD_MESSAGE_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PACKET_LENGTH), "BAD_PACKET_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PROTOCOL_VERSION_NUMBER), "BAD_PROTOCOL_VERSION_NUMBER"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH), "BAD_PSK_IDENTITY_HINT_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_RESPONSE_ARGUMENT), "BAD_RESPONSE_ARGUMENT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_RSA_DECRYPT), "BAD_RSA_DECRYPT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_RSA_ENCRYPT), "BAD_RSA_ENCRYPT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_RSA_E_LENGTH), "BAD_RSA_E_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_RSA_MODULUS_LENGTH), "BAD_RSA_MODULUS_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_RSA_SIGNATURE), "BAD_RSA_SIGNATURE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SIGNATURE), "BAD_SIGNATURE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRP_A_LENGTH), "BAD_SRP_A_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRP_B_LENGTH), "BAD_SRP_B_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRP_G_LENGTH), "BAD_SRP_G_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRP_N_LENGTH), "BAD_SRP_N_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRP_S_LENGTH), "BAD_SRP_S_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRTP_MKI_VALUE), "BAD_SRTP_MKI_VALUE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST), "BAD_SRTP_PROTECTION_PROFILE_LIST"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SSL_FILETYPE), "BAD_SSL_FILETYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SSL_SESSION_ID_LENGTH), "BAD_SSL_SESSION_ID_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_STATE), "BAD_STATE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_VALUE), "BAD_VALUE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_WRITE_RETRY), "BAD_WRITE_RETRY"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BIO_NOT_SET), "BIO_NOT_SET"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BLOCK_CIPHER_PAD_IS_WRONG), "BLOCK_CIPHER_PAD_IS_WRONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BN_LIB), "BN_LIB"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CANNOT_SERIALIZE_PUBLIC_KEY), "CANNOT_SERIALIZE_PUBLIC_KEY"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CA_DN_LENGTH_MISMATCH), "CA_DN_LENGTH_MISMATCH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CA_DN_TOO_LONG), "CA_DN_TOO_LONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CCS_RECEIVED_EARLY), "CCS_RECEIVED_EARLY"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CERTIFICATE_VERIFY_FAILED), "CERTIFICATE_VERIFY_FAILED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CERT_CB_ERROR), "CERT_CB_ERROR"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CERT_LENGTH_MISMATCH), "CERT_LENGTH_MISMATCH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CHALLENGE_IS_DIFFERENT), "CHALLENGE_IS_DIFFERENT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CHANNEL_ID_NOT_P256), "CHANNEL_ID_NOT_P256"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CHANNEL_ID_SIGNATURE_INVALID), "CHANNEL_ID_SIGNATURE_INVALID"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CIPHER_CODE_WRONG_LENGTH), "CIPHER_CODE_WRONG_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CIPHER_OR_HASH_UNAVAILABLE), "CIPHER_OR_HASH_UNAVAILABLE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CIPHER_TABLE_SRC_ERROR), "CIPHER_TABLE_SRC_ERROR"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CLIENTHELLO_PARSE_FAILED), "CLIENTHELLO_PARSE_FAILED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CLIENTHELLO_TLSEXT), "CLIENTHELLO_TLSEXT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSED_LENGTH_TOO_LONG), "COMPRESSED_LENGTH_TOO_LONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSION_DISABLED), "COMPRESSION_DISABLED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSION_FAILURE), "COMPRESSION_FAILURE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE), "COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSION_LIBRARY_ERROR), "COMPRESSION_LIBRARY_ERROR"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CONNECTION_ID_IS_DIFFERENT), "CONNECTION_ID_IS_DIFFERENT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CONNECTION_REJECTED), "CONNECTION_REJECTED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CONNECTION_TYPE_NOT_SET), "CONNECTION_TYPE_NOT_SET"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COOKIE_MISMATCH), "COOKIE_MISMATCH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_D2I_ECDSA_SIG), "D2I_ECDSA_SIG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED), "DATA_BETWEEN_CCS_AND_FINISHED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DATA_LENGTH_TOO_LONG), "DATA_LENGTH_TOO_LONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DECODE_ERROR), "DECODE_ERROR"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DECRYPTION_FAILED), "DECRYPTION_FAILED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC), "DECRYPTION_FAILED_OR_BAD_RECORD_MAC"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG), "DH_PUBLIC_VALUE_LENGTH_IS_WRONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DIGEST_CHECK_FAILED), "DIGEST_CHECK_FAILED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DTLS_MESSAGE_TOO_BIG), "DTLS_MESSAGE_TOO_BIG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DUPLICATE_COMPRESSION_ID), "DUPLICATE_COMPRESSION_ID"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT), "ECC_CERT_NOT_FOR_KEY_AGREEMENT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ECC_CERT_NOT_FOR_SIGNING), "ECC_CERT_NOT_FOR_SIGNING"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE), "ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE), "ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER), "ECGROUP_TOO_LARGE_FOR_CIPHER"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST), "EMPTY_SRTP_PROTECTION_PROFILE_LIST"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ENCRYPTED_LENGTH_TOO_LONG), "ENCRYPTED_LENGTH_TOO_LONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ERROR_GENERATING_TMP_RSA_KEY), "ERROR_GENERATING_TMP_RSA_KEY"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST), "ERROR_IN_RECEIVED_CIPHER_LIST"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EVP_DIGESTSIGNFINAL_FAILED), "EVP_DIGESTSIGNFINAL_FAILED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EVP_DIGESTSIGNINIT_FAILED), "EVP_DIGESTSIGNINIT_FAILED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXCESSIVE_MESSAGE_SIZE), "EXCESSIVE_MESSAGE_SIZE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXTRA_DATA_IN_MESSAGE), "EXTRA_DATA_IN_MESSAGE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_GOST_NOT_SUPPORTED), "GOST_NOT_SUPPORTED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_GOT_A_FIN_BEFORE_A_CCS), "GOT_A_FIN_BEFORE_A_CCS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_GOT_CHANNEL_ID_BEFORE_A_CCS), "GOT_CHANNEL_ID_BEFORE_A_CCS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS), "GOT_NEXT_PROTO_BEFORE_A_CCS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION), "GOT_NEXT_PROTO_WITHOUT_EXTENSION"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO), "HANDSHAKE_FAILURE_ON_CLIENT_HELLO"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_HANDSHAKE_RECORD_BEFORE_CCS), "HANDSHAKE_RECORD_BEFORE_CCS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_HTTPS_PROXY_REQUEST), "HTTPS_PROXY_REQUEST"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_HTTP_REQUEST), "HTTP_REQUEST"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ILLEGAL_PADDING), "ILLEGAL_PADDING"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ILLEGAL_SUITEB_DIGEST), "ILLEGAL_SUITEB_DIGEST"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INAPPROPRIATE_FALLBACK), "INAPPROPRIATE_FALLBACK"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INCONSISTENT_COMPRESSION), "INCONSISTENT_COMPRESSION"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_AUDIT_PROOF), "INVALID_AUDIT_PROOF"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_AUTHZ_DATA), "INVALID_AUTHZ_DATA"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CHALLENGE_LENGTH), "INVALID_CHALLENGE_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_COMMAND), "INVALID_COMMAND"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_COMPRESSION_ALGORITHM), "INVALID_COMPRESSION_ALGORITHM"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_MESSAGE), "INVALID_MESSAGE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_NULL_CMD_NAME), "INVALID_NULL_CMD_NAME"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_PURPOSE), "INVALID_PURPOSE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SERVERINFO_DATA), "INVALID_SERVERINFO_DATA"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SRP_USERNAME), "INVALID_SRP_USERNAME"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SSL_SESSION), "INVALID_SSL_SESSION"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_STATUS_RESPONSE), "INVALID_STATUS_RESPONSE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_TICKET_KEYS_LENGTH), "INVALID_TICKET_KEYS_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_TRUST), "INVALID_TRUST"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KEY_ARG_TOO_LONG), "KEY_ARG_TOO_LONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5), "KRB5"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_C_CC_PRINC), "KRB5_C_CC_PRINC"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_C_GET_CRED), "KRB5_C_GET_CRED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_C_INIT), "KRB5_C_INIT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_C_MK_REQ), "KRB5_C_MK_REQ"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_S_BAD_TICKET), "KRB5_S_BAD_TICKET"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_S_INIT), "KRB5_S_INIT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_S_RD_REQ), "KRB5_S_RD_REQ"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_S_TKT_EXPIRED), "KRB5_S_TKT_EXPIRED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_S_TKT_NYV), "KRB5_S_TKT_NYV"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_S_TKT_SKEW), "KRB5_S_TKT_SKEW"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LENGTH_MISMATCH), "LENGTH_MISMATCH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LENGTH_TOO_SHORT), "LENGTH_TOO_SHORT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LIBRARY_BUG), "LIBRARY_BUG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LIBRARY_HAS_NO_CIPHERS), "LIBRARY_HAS_NO_CIPHERS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MESSAGE_TOO_LONG), "MESSAGE_TOO_LONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_DH_DSA_CERT), "MISSING_DH_DSA_CERT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_DH_KEY), "MISSING_DH_KEY"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_DH_RSA_CERT), "MISSING_DH_RSA_CERT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_DSA_SIGNING_CERT), "MISSING_DSA_SIGNING_CERT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_ECDH_CERT), "MISSING_ECDH_CERT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_ECDSA_SIGNING_CERT), "MISSING_ECDSA_SIGNING_CERT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_EXPORT_TMP_DH_KEY), "MISSING_EXPORT_TMP_DH_KEY"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_EXPORT_TMP_RSA_KEY), "MISSING_EXPORT_TMP_RSA_KEY"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_CERTIFICATE), "MISSING_RSA_CERTIFICATE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_ENCRYPTING_CERT), "MISSING_RSA_ENCRYPTING_CERT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_SIGNING_CERT), "MISSING_RSA_SIGNING_CERT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_SRP_PARAM), "MISSING_SRP_PARAM"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_TMP_DH_KEY), "MISSING_TMP_DH_KEY"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_TMP_ECDH_KEY), "MISSING_TMP_ECDH_KEY"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_TMP_RSA_KEY), "MISSING_TMP_RSA_KEY"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_TMP_RSA_PKEY), "MISSING_TMP_RSA_PKEY"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_VERIFY_MESSAGE), "MISSING_VERIFY_MESSAGE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS), "MIXED_SPECIAL_OPERATOR_WITH_GROUPS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MTU_TOO_SMALL), "MTU_TOO_SMALL"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MULTIPLE_SGC_RESTARTS), "MULTIPLE_SGC_RESTARTS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NESTED_GROUP), "NESTED_GROUP"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NON_SSLV2_INITIAL_PACKET), "NON_SSLV2_INITIAL_PACKET"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATES_RETURNED), "NO_CERTIFICATES_RETURNED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATE_ASSIGNED), "NO_CERTIFICATE_ASSIGNED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATE_RETURNED), "NO_CERTIFICATE_RETURNED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATE_SET), "NO_CERTIFICATE_SET"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATE_SPECIFIED), "NO_CERTIFICATE_SPECIFIED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CIPHERS_AVAILABLE), "NO_CIPHERS_AVAILABLE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CIPHERS_PASSED), "NO_CIPHERS_PASSED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CIPHERS_SPECIFIED), "NO_CIPHERS_SPECIFIED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CIPHER_LIST), "NO_CIPHER_LIST"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CIPHER_MATCH), "NO_CIPHER_MATCH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CLIENT_CERT_METHOD), "NO_CLIENT_CERT_METHOD"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CLIENT_CERT_RECEIVED), "NO_CLIENT_CERT_RECEIVED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_COMPRESSION_SPECIFIED), "NO_COMPRESSION_SPECIFIED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER), "NO_GOST_CERTIFICATE_SENT_BY_PEER"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_METHOD_SPECIFIED), "NO_METHOD_SPECIFIED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_P256_SUPPORT), "NO_P256_SUPPORT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_PEM_EXTENSIONS), "NO_PEM_EXTENSIONS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_PRIVATEKEY), "NO_PRIVATEKEY"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_PRIVATE_KEY_ASSIGNED), "NO_PRIVATE_KEY_ASSIGNED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_PROTOCOLS_AVAILABLE), "NO_PROTOCOLS_AVAILABLE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_PUBLICKEY), "NO_PUBLICKEY"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_RENEGOTIATION), "NO_RENEGOTIATION"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_REQUIRED_DIGEST), "NO_REQUIRED_DIGEST"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SHARED_CIPHER), "NO_SHARED_CIPHER"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SHARED_SIGATURE_ALGORITHMS), "NO_SHARED_SIGATURE_ALGORITHMS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SRTP_PROFILES), "NO_SRTP_PROFILES"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_VERIFY_CALLBACK), "NO_VERIFY_CALLBACK"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NULL_SSL_CTX), "NULL_SSL_CTX"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NULL_SSL_METHOD_PASSED), "NULL_SSL_METHOD_PASSED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED), "OLD_SESSION_CIPHER_NOT_RETURNED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED), "OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE), "ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE), "ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE), "ONLY_TLS_ALLOWED_IN_FIPS_MODE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_OPAQUE_PRF_INPUT_TOO_LONG), "OPAQUE_PRF_INPUT_TOO_LONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PACKET_LENGTH_TOO_LONG), "PACKET_LENGTH_TOO_LONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PARSE_TLSEXT), "PARSE_TLSEXT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PATH_TOO_LONG), "PATH_TOO_LONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE), "PEER_DID_NOT_RETURN_A_CERTIFICATE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEER_ERROR), "PEER_ERROR"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEER_ERROR_CERTIFICATE), "PEER_ERROR_CERTIFICATE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEER_ERROR_NO_CERTIFICATE), "PEER_ERROR_NO_CERTIFICATE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEER_ERROR_NO_CIPHER), "PEER_ERROR_NO_CIPHER"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE), "PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEM_NAME_BAD_PREFIX), "PEM_NAME_BAD_PREFIX"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEM_NAME_TOO_SHORT), "PEM_NAME_TOO_SHORT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PRE_MAC_LENGTH_TOO_LONG), "PRE_MAC_LENGTH_TOO_LONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS), "PROBLEMS_MAPPING_CIPHER_FUNCTIONS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PROTOCOL_IS_SHUTDOWN), "PROTOCOL_IS_SHUTDOWN"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PSK_IDENTITY_NOT_FOUND), "PSK_IDENTITY_NOT_FOUND"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PSK_NO_CLIENT_CB), "PSK_NO_CLIENT_CB"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PSK_NO_SERVER_CB), "PSK_NO_SERVER_CB"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PUBLIC_KEY_ENCRYPT_ERROR), "PUBLIC_KEY_ENCRYPT_ERROR"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PUBLIC_KEY_IS_NOT_RSA), "PUBLIC_KEY_IS_NOT_RSA"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PUBLIC_KEY_NOT_RSA), "PUBLIC_KEY_NOT_RSA"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_READ_BIO_NOT_SET), "READ_BIO_NOT_SET"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_READ_TIMEOUT_EXPIRED), "READ_TIMEOUT_EXPIRED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_READ_WRONG_PACKET_TYPE), "READ_WRONG_PACKET_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RECORD_LENGTH_MISMATCH), "RECORD_LENGTH_MISMATCH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RECORD_TOO_LARGE), "RECORD_TOO_LARGE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RECORD_TOO_SMALL), "RECORD_TOO_SMALL"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RENEGOTIATE_EXT_TOO_LONG), "RENEGOTIATE_EXT_TOO_LONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RENEGOTIATION_ENCODING_ERR), "RENEGOTIATION_ENCODING_ERR"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RENEGOTIATION_MISMATCH), "RENEGOTIATION_MISMATCH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REQUIRED_CIPHER_MISSING), "REQUIRED_CIPHER_MISSING"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING), "REQUIRED_COMPRESSSION_ALGORITHM_MISSING"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REUSE_CERT_LENGTH_NOT_ZERO), "REUSE_CERT_LENGTH_NOT_ZERO"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REUSE_CERT_TYPE_NOT_ZERO), "REUSE_CERT_TYPE_NOT_ZERO"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REUSE_CIPHER_LIST_NOT_ZERO), "REUSE_CIPHER_LIST_NOT_ZERO"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING), "SCSV_RECEIVED_WHEN_RENEGOTIATING"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SERVERHELLO_TLSEXT), "SERVERHELLO_TLSEXT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED), "SESSION_ID_CONTEXT_UNINITIALIZED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SESSION_MAY_NOT_BE_CREATED), "SESSION_MAY_NOT_BE_CREATED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ), "SHORT_READ"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SIGNATURE_ALGORITHMS_ERROR), "SIGNATURE_ALGORITHMS_ERROR"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE), "SIGNATURE_FOR_NON_SIGNING_CERTIFICATE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SRP_A_CALC), "SRP_A_CALC"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES), "SRTP_COULD_NOT_ALLOCATE_PROFILES"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG), "SRTP_PROTECTION_PROFILE_LIST_TOO_LONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE), "SRTP_UNKNOWN_PROTECTION_PROFILE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL23_DOING_SESSION_ID_REUSE), "SSL23_DOING_SESSION_ID_REUSE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL2_CONNECTION_ID_TOO_LONG), "SSL2_CONNECTION_ID_TOO_LONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT), "SSL3_EXT_INVALID_ECPOINTFORMAT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_EXT_INVALID_SERVERNAME), "SSL3_EXT_INVALID_SERVERNAME"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE), "SSL3_EXT_INVALID_SERVERNAME_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_SESSION_ID_TOO_LONG), "SSL3_SESSION_ID_TOO_LONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_SESSION_ID_TOO_SHORT), "SSL3_SESSION_ID_TOO_SHORT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_BAD_CERTIFICATE), "SSLV3_ALERT_BAD_CERTIFICATE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_BAD_RECORD_MAC), "SSLV3_ALERT_BAD_RECORD_MAC"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED), "SSLV3_ALERT_CERTIFICATE_EXPIRED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED), "SSLV3_ALERT_CERTIFICATE_REVOKED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN), "SSLV3_ALERT_CERTIFICATE_UNKNOWN"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CLOSE_NOTIFY), "SSLV3_ALERT_CLOSE_NOTIFY"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE), "SSLV3_ALERT_DECOMPRESSION_FAILURE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE), "SSLV3_ALERT_HANDSHAKE_FAILURE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER), "SSLV3_ALERT_ILLEGAL_PARAMETER"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_NO_CERTIFICATE), "SSLV3_ALERT_NO_CERTIFICATE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE), "SSLV3_ALERT_UNEXPECTED_MESSAGE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE), "SSLV3_ALERT_UNSUPPORTED_CERTIFICATE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION), "SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_HANDSHAKE_FAILURE), "SSL_HANDSHAKE_FAILURE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS), "SSL_LIBRARY_HAS_NO_CIPHERS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_CALLBACK_FAILED), "SSL_SESSION_ID_CALLBACK_FAILED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_CONFLICT), "SSL_SESSION_ID_CONFLICT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG), "SSL_SESSION_ID_CONTEXT_TOO_LONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH), "SSL_SESSION_ID_HAS_BAD_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_IS_DIFFERENT), "SSL_SESSION_ID_IS_DIFFERENT"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_ACCESS_DENIED), "TLSV1_ALERT_ACCESS_DENIED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_DECODE_ERROR), "TLSV1_ALERT_DECODE_ERROR"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_DECRYPTION_FAILED), "TLSV1_ALERT_DECRYPTION_FAILED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_DECRYPT_ERROR), "TLSV1_ALERT_DECRYPT_ERROR"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION), "TLSV1_ALERT_EXPORT_RESTRICTION"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK), "TLSV1_ALERT_INAPPROPRIATE_FALLBACK"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY), "TLSV1_ALERT_INSUFFICIENT_SECURITY"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_INTERNAL_ERROR), "TLSV1_ALERT_INTERNAL_ERROR"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_NO_RENEGOTIATION), "TLSV1_ALERT_NO_RENEGOTIATION"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_PROTOCOL_VERSION), "TLSV1_ALERT_PROTOCOL_VERSION"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_RECORD_OVERFLOW), "TLSV1_ALERT_RECORD_OVERFLOW"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_UNKNOWN_CA), "TLSV1_ALERT_UNKNOWN_CA"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_USER_CANCELLED), "TLSV1_ALERT_USER_CANCELLED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE), "TLSV1_BAD_CERTIFICATE_HASH_VALUE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE), "TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE), "TLSV1_CERTIFICATE_UNOBTAINABLE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_UNRECOGNIZED_NAME), "TLSV1_UNRECOGNIZED_NAME"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_UNSUPPORTED_EXTENSION), "TLSV1_UNSUPPORTED_EXTENSION"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER), "TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL), "TLS_ILLEGAL_EXPORTER_LABEL"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST), "TLS_INVALID_ECPOINTFORMAT_LIST"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST), "TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG), "TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TOO_MANY_EMPTY_FRAGMENTS), "TOO_MANY_EMPTY_FRAGMENTS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER), "TRIED_TO_USE_UNSUPPORTED_CIPHER"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_DECODE_DH_CERTS), "UNABLE_TO_DECODE_DH_CERTS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_DECODE_ECDH_CERTS), "UNABLE_TO_DECODE_ECDH_CERTS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY), "UNABLE_TO_EXTRACT_PUBLIC_KEY"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_FIND_DH_PARAMETERS), "UNABLE_TO_FIND_DH_PARAMETERS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS), "UNABLE_TO_FIND_ECDH_PARAMETERS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS), "UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_FIND_SSL_METHOD), "UNABLE_TO_FIND_SSL_METHOD"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES), "UNABLE_TO_LOAD_SSL2_MD5_ROUTINES"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES), "UNABLE_TO_LOAD_SSL3_MD5_ROUTINES"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES), "UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_GROUP_CLOSE), "UNEXPECTED_GROUP_CLOSE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_MESSAGE), "UNEXPECTED_MESSAGE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_OPERATOR_IN_GROUP), "UNEXPECTED_OPERATOR_IN_GROUP"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_RECORD), "UNEXPECTED_RECORD"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNINITIALIZED), "UNINITIALIZED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_ALERT_TYPE), "UNKNOWN_ALERT_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_AUTHZ_DATA_TYPE), "UNKNOWN_AUTHZ_DATA_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_CERTIFICATE_TYPE), "UNKNOWN_CERTIFICATE_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_CIPHER_RETURNED), "UNKNOWN_CIPHER_RETURNED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_CIPHER_TYPE), "UNKNOWN_CIPHER_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_CMD_NAME), "UNKNOWN_CMD_NAME"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_DIGEST), "UNKNOWN_DIGEST"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE), "UNKNOWN_KEY_EXCHANGE_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_PKEY_TYPE), "UNKNOWN_PKEY_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_PROTOCOL), "UNKNOWN_PROTOCOL"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_REMOTE_ERROR_TYPE), "UNKNOWN_REMOTE_ERROR_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_SSL_VERSION), "UNKNOWN_SSL_VERSION"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_STATE), "UNKNOWN_STATE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_SUPPLEMENTAL_DATA_TYPE), "UNKNOWN_SUPPLEMENTAL_DATA_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNPROCESSED_HANDSHAKE_DATA), "UNPROCESSED_HANDSHAKE_DATA"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED), "UNSAFE_LEGACY_RENEGOTIATION_DISABLED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_CIPHER), "UNSUPPORTED_CIPHER"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM), "UNSUPPORTED_COMPRESSION_ALGORITHM"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_DIGEST_TYPE), "UNSUPPORTED_DIGEST_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE), "UNSUPPORTED_ELLIPTIC_CURVE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_PROTOCOL), "UNSUPPORTED_PROTOCOL"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_SSL_VERSION), "UNSUPPORTED_SSL_VERSION"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_STATUS_TYPE), "UNSUPPORTED_STATUS_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_USE_SRTP_NOT_NEGOTIATED), "USE_SRTP_NOT_NEGOTIATED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRITE_BIO_NOT_SET), "WRITE_BIO_NOT_SET"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CERTIFICATE_TYPE), "WRONG_CERTIFICATE_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CIPHER_RETURNED), "WRONG_CIPHER_RETURNED"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CURVE), "WRONG_CURVE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_MESSAGE_TYPE), "WRONG_MESSAGE_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_NUMBER_OF_KEY_BITS), "WRONG_NUMBER_OF_KEY_BITS"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_LENGTH), "WRONG_SIGNATURE_LENGTH"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_SIZE), "WRONG_SIGNATURE_SIZE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_TYPE), "WRONG_SIGNATURE_TYPE"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SSL_VERSION), "WRONG_SSL_VERSION"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_VERSION_NUMBER), "WRONG_VERSION_NUMBER"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_X509_LIB), "X509_LIB"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS), "X509_VERIFICATION_SETUP_PROBLEMS"}, - {0, NULL}, -}; diff --git a/src/ssl/ssl_lib.c b/src/ssl/ssl_lib.c index 35eb1ec..6c8e2c9 100644 --- a/src/ssl/ssl_lib.c +++ b/src/ssl/ssl_lib.c @@ -138,19 +138,22 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. */ -#include #include +#include +#include #include #include -#include +#include #include #include #include #include #include -#include "ssl_locl.h" +#include "internal.h" +#include "../crypto/internal.h" + /* Some error codes are special. Ensure the make_errors.go script never * regresses this. */ @@ -158,6 +161,12 @@ OPENSSL_COMPILE_ASSERT(SSL_R_TLSV1_ALERT_NO_RENEGOTIATION == SSL_AD_NO_RENEGOTIATION + SSL_AD_REASON_OFFSET, ssl_alert_reason_code_mismatch); +/* 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; +static CRYPTO_EX_DATA_CLASS g_ex_data_class_ssl_ctx = CRYPTO_EX_DATA_CLASS_INIT; + int SSL_clear(SSL *s) { if (s->method == NULL) { OPENSSL_PUT_ERROR(SSL, SSL_clear, SSL_R_NO_METHOD_SPECIFIED); @@ -199,21 +208,17 @@ int SSL_clear(SSL *s) { s->rwstate = SSL_NOTHING; s->rstate = SSL_ST_READ_HEADER; - if (s->init_buf != NULL) { - BUF_MEM_free(s->init_buf); - s->init_buf = NULL; - } + BUF_MEM_free(s->init_buf); + s->init_buf = NULL; s->packet = NULL; s->packet_length = 0; ssl_clear_cipher_ctx(s); - if (s->next_proto_negotiated) { - OPENSSL_free(s->next_proto_negotiated); - s->next_proto_negotiated = NULL; - s->next_proto_negotiated_len = 0; - } + OPENSSL_free(s->next_proto_negotiated); + s->next_proto_negotiated = NULL; + s->next_proto_negotiated_len = 0; /* The s->d1->mtu is simultaneously configuration (preserved across * clear) and connection-specific state (gets reset). @@ -265,21 +270,9 @@ SSL *SSL_new(SSL_CTX *ctx) { s->mode = ctx->mode; s->max_cert_list = ctx->max_cert_list; - if (ctx->cert != NULL) { - /* Earlier library versions used to copy the pointer to the CERT, not its - * contents; only when setting new parameters for the per-SSL copy, - * ssl_cert_new would be called (and the direct reference to the - * per-SSL_CTX settings would be lost, but those still were indirectly - * accessed for various purposes, and for that reason they used to be known - * as s->ctx->default_cert). Now we don't look at the SSL_CTX's CERT after - * having duplicated it once. */ - - s->cert = ssl_cert_dup(ctx->cert); - if (s->cert == NULL) { - goto err; - } - } else { - s->cert = NULL; /* Cannot really happen (see SSL_CTX_new) */ + s->cert = ssl_cert_dup(ctx->cert); + if (s->cert == NULL) { + goto err; } s->read_ahead = ctx->read_ahead; @@ -302,8 +295,6 @@ SSL *SSL_new(SSL_CTX *ctx) { CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX); s->ctx = ctx; - s->tlsext_debug_cb = 0; - s->tlsext_debug_arg = NULL; s->tlsext_ticket_expected = 0; CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX); s->initial_ctx = ctx; @@ -345,12 +336,10 @@ SSL *SSL_new(SSL_CTX *ctx) { s->enc_method = ssl3_get_enc_method(s->version); assert(s->enc_method != NULL); - s->references = 1; - s->rwstate = SSL_NOTHING; s->rstate = SSL_ST_READ_HEADER; - CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data); + CRYPTO_new_ex_data(&g_ex_data_class_ssl, s, &s->ex_data); s->psk_identity_hint = NULL; if (ctx->psk_identity_hint) { @@ -364,7 +353,8 @@ SSL *SSL_new(SSL_CTX *ctx) { s->tlsext_channel_id_enabled = ctx->tlsext_channel_id_enabled; if (ctx->tlsext_channel_id_private) { - s->tlsext_channel_id_private = EVP_PKEY_dup(ctx->tlsext_channel_id_private); + s->tlsext_channel_id_private = + EVP_PKEY_up_ref(ctx->tlsext_channel_id_private); } s->signed_cert_timestamps_enabled = s->ctx->signed_cert_timestamps_enabled; @@ -373,9 +363,7 @@ SSL *SSL_new(SSL_CTX *ctx) { return s; err: - if (s != NULL) { - SSL_free(s); - } + SSL_free(s); OPENSSL_PUT_ERROR(SSL, SSL_new, ERR_R_MALLOC_FAILURE); return NULL; @@ -415,9 +403,7 @@ int SSL_CTX_set_generate_session_id(SSL_CTX *ctx, GEN_SESSION_CB cb) { } int SSL_set_generate_session_id(SSL *ssl, GEN_SESSION_CB cb) { - CRYPTO_w_lock(CRYPTO_LOCK_SSL); ssl->generate_session_id = cb; - CRYPTO_w_unlock(CRYPTO_LOCK_SSL); return 1; } @@ -470,6 +456,9 @@ int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm) { void ssl_cipher_preference_list_free( struct ssl_cipher_preference_list_st *cipher_list) { + if (cipher_list == NULL) { + return; + } sk_SSL_CIPHER_free(cipher_list->ciphers); OPENSSL_free(cipher_list->in_group_flags); OPENSSL_free(cipher_list); @@ -499,17 +488,12 @@ struct ssl_cipher_preference_list_st *ssl_cipher_preference_list_dup( return ret; err: - if (ret && ret->ciphers) { - sk_SSL_CIPHER_free(ret->ciphers); - } - if (ret) { - OPENSSL_free(ret); - } + ssl_cipher_preference_list_free(ret); return NULL; } struct ssl_cipher_preference_list_st *ssl_cipher_preference_list_from_ciphers( - STACK_OF(SSL_CIPHER) * ciphers) { + STACK_OF(SSL_CIPHER) *ciphers) { struct ssl_cipher_preference_list_st *ret = NULL; size_t n = sk_SSL_CIPHER_num(ciphers); @@ -531,12 +515,7 @@ struct ssl_cipher_preference_list_st *ssl_cipher_preference_list_from_ciphers( return ret; err: - if (ret && ret->ciphers) { - sk_SSL_CIPHER_free(ret->ciphers); - } - if (ret) { - OPENSSL_free(ret); - } + ssl_cipher_preference_list_free(ret); return NULL; } @@ -547,22 +526,13 @@ X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl) { return ssl->param; } void SSL_certs_clear(SSL *s) { ssl_cert_clear_certs(s->cert); } void SSL_free(SSL *s) { - int i; - if (s == NULL) { return; } - i = CRYPTO_add(&s->references, -1, CRYPTO_LOCK_SSL); - if (i > 0) { - return; - } - - if (s->param) { - X509_VERIFY_PARAM_free(s->param); - } + X509_VERIFY_PARAM_free(s->param); - CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data); + CRYPTO_free_ex_data(&g_ex_data_class_ssl, s, &s->ex_data); if (s->bbio != NULL) { /* If the buffering BIO is in place, pop it off */ @@ -573,74 +543,40 @@ void SSL_free(SSL *s) { s->bbio = NULL; } - if (s->rbio != NULL) { - BIO_free_all(s->rbio); - } - - if (s->wbio != NULL && s->wbio != s->rbio) { + int free_wbio = s->wbio != s->rbio; + BIO_free_all(s->rbio); + if (free_wbio) { BIO_free_all(s->wbio); } - if (s->init_buf != NULL) { - BUF_MEM_free(s->init_buf); - } + BUF_MEM_free(s->init_buf); /* add extra stuff */ - if (s->cipher_list != NULL) { - ssl_cipher_preference_list_free(s->cipher_list); - } - if (s->cipher_list_by_id != NULL) { - sk_SSL_CIPHER_free(s->cipher_list_by_id); - } + ssl_cipher_preference_list_free(s->cipher_list); + sk_SSL_CIPHER_free(s->cipher_list_by_id); - if (s->session != NULL) { - ssl_clear_bad_session(s); - SSL_SESSION_free(s->session); - } + ssl_clear_bad_session(s); + SSL_SESSION_free(s->session); ssl_clear_cipher_ctx(s); - if (s->cert != NULL) { - ssl_cert_free(s->cert); - } + ssl_cert_free(s->cert); - if (s->tlsext_hostname) { - OPENSSL_free(s->tlsext_hostname); - } - if (s->initial_ctx) { - SSL_CTX_free(s->initial_ctx); - } - if (s->tlsext_ecpointformatlist) { - OPENSSL_free(s->tlsext_ecpointformatlist); - } - if (s->tlsext_ellipticcurvelist) { - OPENSSL_free(s->tlsext_ellipticcurvelist); - } - if (s->alpn_client_proto_list) { - OPENSSL_free(s->alpn_client_proto_list); - } - if (s->tlsext_channel_id_private) { - EVP_PKEY_free(s->tlsext_channel_id_private); - } - if (s->psk_identity_hint) { - OPENSSL_free(s->psk_identity_hint); - } - if (s->client_CA != NULL) { - sk_X509_NAME_pop_free(s->client_CA, X509_NAME_free); - } - if (s->next_proto_negotiated) { - OPENSSL_free(s->next_proto_negotiated); - } - if (s->srtp_profiles) { - sk_SRTP_PROTECTION_PROFILE_free(s->srtp_profiles); - } + OPENSSL_free(s->tlsext_hostname); + SSL_CTX_free(s->initial_ctx); + OPENSSL_free(s->tlsext_ecpointformatlist); + OPENSSL_free(s->tlsext_ellipticcurvelist); + OPENSSL_free(s->alpn_client_proto_list); + EVP_PKEY_free(s->tlsext_channel_id_private); + OPENSSL_free(s->psk_identity_hint); + sk_X509_NAME_pop_free(s->client_CA, X509_NAME_free); + OPENSSL_free(s->next_proto_negotiated); + sk_SRTP_PROTECTION_PROFILE_free(s->srtp_profiles); if (s->method != NULL) { s->method->ssl_free(s); } - if (s->ctx) { - SSL_CTX_free(s->ctx); - } + SSL_CTX_free(s->ctx); OPENSSL_free(s); } @@ -654,10 +590,10 @@ void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio) { } } - if (s->rbio != NULL && s->rbio != rbio) { + if (s->rbio != rbio) { BIO_free_all(s->rbio); } - if (s->wbio != NULL && s->wbio != wbio && s->rbio != s->wbio) { + if (s->wbio != wbio && s->rbio != s->wbio) { BIO_free_all(s->wbio); } s->rbio = rbio; @@ -822,10 +758,14 @@ void SSL_set_verify_depth(SSL *s, int depth) { X509_VERIFY_PARAM_set_depth(s->param, depth); } -void SSL_set_read_ahead(SSL *s, int yes) { s->read_ahead = yes; } +int SSL_CTX_get_read_ahead(const SSL_CTX *ctx) { return ctx->read_ahead; } int SSL_get_read_ahead(const SSL *s) { return s->read_ahead; } +void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes) { ctx->read_ahead = !!yes; } + +void SSL_set_read_ahead(SSL *s, int yes) { s->read_ahead = !!yes; } + int SSL_pending(const SSL *s) { /* SSL_pending cannot work properly if read-ahead is enabled * (SSL_[CTX_]ctrl(..., SSL_CTRL_SET_READ_AHEAD, 1, NULL)), and it is @@ -851,8 +791,8 @@ X509 *SSL_get_peer_certificate(const SSL *s) { return X509_up_ref(r); } -STACK_OF(X509) * SSL_get_peer_cert_chain(const SSL *s) { - STACK_OF(X509) * 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; @@ -919,7 +859,7 @@ int SSL_accept(SSL *s) { } if (s->handshake_func != s->method->ssl_accept) { - OPENSSL_PUT_ERROR(SSL, SSL_connect, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_accept, ERR_R_INTERNAL_ERROR); return -1; } @@ -1005,20 +945,17 @@ int SSL_shutdown(SSL *s) { } int SSL_renegotiate(SSL *s) { - if (s->renegotiate == 0) { - s->renegotiate = 1; + if (SSL_IS_DTLS(s)) { + /* Renegotiation is not supported for DTLS. */ + OPENSSL_PUT_ERROR(SSL, SSL_renegotiate, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; } - s->new_session = 1; - return s->method->ssl_renegotiate(s); -} - -int SSL_renegotiate_abbreviated(SSL *s) { if (s->renegotiate == 0) { s->renegotiate = 1; } - s->new_session = 0; + s->new_session = 1; return s->method->ssl_renegotiate(s); } @@ -1028,221 +965,140 @@ int SSL_renegotiate_pending(SSL *s) { return s->renegotiate != 0; } -long SSL_ctrl(SSL *s, int cmd, long larg, void *parg) { - long l; - - switch (cmd) { - case SSL_CTRL_GET_READ_AHEAD: - return s->read_ahead; - - case SSL_CTRL_SET_READ_AHEAD: - l = s->read_ahead; - s->read_ahead = larg; - return l; - - case SSL_CTRL_SET_MSG_CALLBACK_ARG: - s->msg_callback_arg = parg; - return 1; - - case SSL_CTRL_OPTIONS: - return s->options |= larg; +uint32_t SSL_CTX_set_options(SSL_CTX *ctx, uint32_t options) { + ctx->options |= options; + return ctx->options; +} - case SSL_CTRL_CLEAR_OPTIONS: - return s->options &= ~larg; +uint32_t SSL_set_options(SSL *ssl, uint32_t options) { + ssl->options |= options; + return ssl->options; +} - case SSL_CTRL_MODE: - return s->mode |= larg; +uint32_t SSL_CTX_clear_options(SSL_CTX *ctx, uint32_t options) { + ctx->options &= ~options; + return ctx->options; +} - case SSL_CTRL_CLEAR_MODE: - return s->mode &= ~larg; +uint32_t SSL_clear_options(SSL *ssl, uint32_t options) { + ssl->options &= ~options; + return ssl->options; +} - case SSL_CTRL_GET_MAX_CERT_LIST: - return s->max_cert_list; +uint32_t SSL_CTX_get_options(const SSL_CTX *ctx) { return ctx->options; } - case SSL_CTRL_SET_MAX_CERT_LIST: - l = s->max_cert_list; - s->max_cert_list = larg; - return l; +uint32_t SSL_get_options(const SSL *ssl) { return ssl->options; } - case SSL_CTRL_SET_MTU: - if (larg < (long)dtls1_min_mtu()) { - return 0; - } - if (SSL_IS_DTLS(s)) { - s->d1->mtu = larg; - return larg; - } - return 0; +uint32_t SSL_CTX_set_mode(SSL_CTX *ctx, uint32_t mode) { + ctx->mode |= mode; + return ctx->mode; +} - case SSL_CTRL_SET_MAX_SEND_FRAGMENT: - if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH) { - return 0; - } - s->max_send_fragment = larg; - return 1; +uint32_t SSL_set_mode(SSL *ssl, uint32_t mode) { + ssl->mode |= mode; + return ssl->mode; +} - case SSL_CTRL_GET_RI_SUPPORT: - if (s->s3) { - return s->s3->send_connection_binding; - } - return 0; +uint32_t SSL_CTX_clear_mode(SSL_CTX *ctx, uint32_t mode) { + ctx->mode &= ~mode; + return ctx->mode; +} - case SSL_CTRL_CERT_FLAGS: - return s->cert->cert_flags |= larg; +uint32_t SSL_clear_mode(SSL *ssl, uint32_t mode) { + ssl->mode &= ~mode; + return ssl->mode; +} - case SSL_CTRL_CLEAR_CERT_FLAGS: - return s->cert->cert_flags &= ~larg; +uint32_t SSL_CTX_get_mode(const SSL_CTX *ctx) { return ctx->mode; } - case SSL_CTRL_GET_RAW_CIPHERLIST: - if (parg) { - if (s->cert->ciphers_raw == NULL) { - return 0; - } - *(uint8_t **)parg = s->cert->ciphers_raw; - return (int)s->cert->ciphers_rawlen; - } +uint32_t SSL_get_mode(const SSL *ssl) { return ssl->mode; } - /* Passing a NULL |parg| returns the size of a single - * cipher suite value. */ - return 2; +size_t SSL_CTX_get_max_cert_list(const SSL_CTX *ctx) { + return ctx->max_cert_list; +} - default: - return s->method->ssl_ctrl(s, cmd, larg, parg); +void SSL_CTX_set_max_cert_list(SSL_CTX *ctx, size_t max_cert_list) { + if (max_cert_list > kMaxHandshakeSize) { + max_cert_list = kMaxHandshakeSize; } + ctx->max_cert_list = (uint32_t)max_cert_list; } -long SSL_callback_ctrl(SSL *s, int cmd, void (*fp)(void)) { - switch (cmd) { - case SSL_CTRL_SET_MSG_CALLBACK: - s->msg_callback = - (void (*)(int write_p, int version, int content_type, const void *buf, - size_t len, SSL *ssl, void *arg))(fp); - return 1; +size_t SSL_get_max_cert_list(const SSL *ssl) { + return ssl->max_cert_list; +} - default: - return s->method->ssl_callback_ctrl(s, cmd, fp); +void SSL_set_max_cert_list(SSL *ssl, size_t max_cert_list) { + if (max_cert_list > kMaxHandshakeSize) { + max_cert_list = kMaxHandshakeSize; } + ssl->max_cert_list = (uint32_t)max_cert_list; } -LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx) { return ctx->sessions; } - -long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) { - long l; - - switch (cmd) { - case SSL_CTRL_GET_READ_AHEAD: - return ctx->read_ahead; - - case SSL_CTRL_SET_READ_AHEAD: - l = ctx->read_ahead; - ctx->read_ahead = larg; - return l; - - case SSL_CTRL_SET_MSG_CALLBACK_ARG: - ctx->msg_callback_arg = parg; - return 1; - - case SSL_CTRL_GET_MAX_CERT_LIST: - return ctx->max_cert_list; - - case SSL_CTRL_SET_MAX_CERT_LIST: - l = ctx->max_cert_list; - ctx->max_cert_list = larg; - return l; - - case SSL_CTRL_SET_SESS_CACHE_SIZE: - l = ctx->session_cache_size; - ctx->session_cache_size = larg; - return l; - - case SSL_CTRL_GET_SESS_CACHE_SIZE: - return ctx->session_cache_size; - - case SSL_CTRL_SET_SESS_CACHE_MODE: - l = ctx->session_cache_mode; - ctx->session_cache_mode = larg; - return l; - - case SSL_CTRL_GET_SESS_CACHE_MODE: - return ctx->session_cache_mode; - - case SSL_CTRL_SESS_NUMBER: - return lh_SSL_SESSION_num_items(ctx->sessions); - - case SSL_CTRL_SESS_CONNECT: - return ctx->stats.sess_connect; - - case SSL_CTRL_SESS_CONNECT_GOOD: - return ctx->stats.sess_connect_good; - - case SSL_CTRL_SESS_CONNECT_RENEGOTIATE: - return ctx->stats.sess_connect_renegotiate; - - case SSL_CTRL_SESS_ACCEPT: - return ctx->stats.sess_accept; - - case SSL_CTRL_SESS_ACCEPT_GOOD: - return ctx->stats.sess_accept_good; - - case SSL_CTRL_SESS_ACCEPT_RENEGOTIATE: - return ctx->stats.sess_accept_renegotiate; - - case SSL_CTRL_SESS_HIT: - return ctx->stats.sess_hit; - - case SSL_CTRL_SESS_CB_HIT: - return ctx->stats.sess_cb_hit; - - case SSL_CTRL_SESS_MISSES: - return ctx->stats.sess_miss; - - case SSL_CTRL_SESS_TIMEOUTS: - return ctx->stats.sess_timeout; +void SSL_CTX_set_max_send_fragment(SSL_CTX *ctx, size_t max_send_fragment) { + if (max_send_fragment < 512) { + max_send_fragment = 512; + } + if (max_send_fragment > SSL3_RT_MAX_PLAIN_LENGTH) { + max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH; + } + ctx->max_send_fragment = (uint16_t)max_send_fragment; +} - case SSL_CTRL_SESS_CACHE_FULL: - return ctx->stats.sess_cache_full; +void SSL_set_max_send_fragment(SSL *ssl, size_t max_send_fragment) { + if (max_send_fragment < 512) { + max_send_fragment = 512; + } + if (max_send_fragment > SSL3_RT_MAX_PLAIN_LENGTH) { + max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH; + } + ssl->max_send_fragment = (uint16_t)max_send_fragment; +} - case SSL_CTRL_OPTIONS: - return ctx->options |= larg; +int SSL_set_mtu(SSL *ssl, unsigned mtu) { + if (!SSL_IS_DTLS(ssl) || mtu < dtls1_min_mtu()) { + return 0; + } + ssl->d1->mtu = mtu; + return 1; +} - case SSL_CTRL_CLEAR_OPTIONS: - return ctx->options &= ~larg; +int SSL_get_secure_renegotiation_support(const SSL *ssl) { + return ssl->s3->send_connection_binding; +} - case SSL_CTRL_MODE: - return ctx->mode |= larg; +long SSL_ctrl(SSL *s, int cmd, long larg, void *parg) { + return s->method->ssl_ctrl(s, cmd, larg, parg); +} - case SSL_CTRL_CLEAR_MODE: - return ctx->mode &= ~larg; +LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx) { return ctx->sessions; } - case SSL_CTRL_SET_MAX_SEND_FRAGMENT: - if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH) { - return 0; - } - ctx->max_send_fragment = larg; - return 1; +size_t SSL_CTX_sess_number(const SSL_CTX *ctx) { + return lh_SSL_SESSION_num_items(ctx->sessions); +} - case SSL_CTRL_CERT_FLAGS: - return ctx->cert->cert_flags |= larg; +unsigned long SSL_CTX_sess_set_cache_size(SSL_CTX *ctx, unsigned long size) { + unsigned long ret = ctx->session_cache_size; + ctx->session_cache_size = size; + return ret; +} - case SSL_CTRL_CLEAR_CERT_FLAGS: - return ctx->cert->cert_flags &= ~larg; +unsigned long SSL_CTX_sess_get_cache_size(const SSL_CTX *ctx) { + return ctx->session_cache_size; +} - default: - return ctx->method->ssl_ctx_ctrl(ctx, cmd, larg, parg); - } +int SSL_CTX_set_session_cache_mode(SSL_CTX *ctx, int mode) { + int ret = ctx->session_cache_mode; + ctx->session_cache_mode = mode; + return ret; } -long SSL_CTX_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void)) { - switch (cmd) { - case SSL_CTRL_SET_MSG_CALLBACK: - ctx->msg_callback = - (void (*)(int write_p, int version, int content_type, const void *buf, - size_t len, SSL *ssl, void *arg))(fp); - return 1; +int SSL_CTX_get_session_cache_mode(const SSL_CTX *ctx) { + return ctx->session_cache_mode; +} - default: - return ctx->method->ssl_ctx_callback_ctrl(ctx, cmd, fp); - } +long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) { + return ctx->method->ssl_ctx_ctrl(ctx, cmd, larg, parg); } int ssl_cipher_id_cmp(const void *in_a, const void *in_b) { @@ -1275,7 +1131,7 @@ int ssl_cipher_ptr_id_cmp(const SSL_CIPHER **ap, const SSL_CIPHER **bp) { /* 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) { +STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s) { if (s == NULL) { return NULL; } @@ -1298,7 +1154,7 @@ STACK_OF(SSL_CIPHER) * SSL_get_ciphers(const SSL *s) { /* return a STACK of the ciphers available for the SSL and in order of * algorithm id */ -STACK_OF(SSL_CIPHER) * ssl_get_ciphers_by_id(SSL *s) { +STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s) { if (s == NULL) { return NULL; } @@ -1317,7 +1173,7 @@ STACK_OF(SSL_CIPHER) * ssl_get_ciphers_by_id(SSL *s) { /* The old interface to get the same thing as SSL_get_ciphers() */ const char *SSL_get_cipher_list(const SSL *s, int n) { const SSL_CIPHER *c; - STACK_OF(SSL_CIPHER) * sk; + STACK_OF(SSL_CIPHER) *sk; if (s == NULL) { return NULL; @@ -1341,7 +1197,7 @@ int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) { STACK_OF(SSL_CIPHER) *sk; sk = ssl_create_cipher_list(ctx->method, &ctx->cipher_list, - &ctx->cipher_list_by_id, str, ctx->cert); + &ctx->cipher_list_by_id, str); /* ssl_create_cipher_list may return an empty stack if it was unable to find * a cipher matching the given rule string (for example if the rule string * specifies a cipher which has been disabled). This is not an error as far @@ -1360,8 +1216,7 @@ int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) { int SSL_CTX_set_cipher_list_tls11(SSL_CTX *ctx, const char *str) { STACK_OF(SSL_CIPHER) *sk; - sk = ssl_create_cipher_list(ctx->method, &ctx->cipher_list_tls11, NULL, str, - ctx->cert); + sk = ssl_create_cipher_list(ctx->method, &ctx->cipher_list_tls11, NULL, str); if (sk == NULL) { return 0; } else if (sk_SSL_CIPHER_num(sk) == 0) { @@ -1378,7 +1233,7 @@ int SSL_set_cipher_list(SSL *s, const char *str) { STACK_OF(SSL_CIPHER) *sk; sk = ssl_create_cipher_list(s->ctx->method, &s->cipher_list, - &s->cipher_list_by_id, str, s->cert); + &s->cipher_list_by_id, str); /* see comment in SSL_CTX_set_cipher_list */ if (sk == NULL) { @@ -1435,7 +1290,7 @@ int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, uint8_t *p) { STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) { CBS cipher_suites = *cbs; const SSL_CIPHER *c; - STACK_OF(SSL_CIPHER) * sk; + STACK_OF(SSL_CIPHER) *sk; if (s->s3) { s->s3->send_connection_binding = 0; @@ -1453,12 +1308,6 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) { goto err; } - if (!CBS_stow(&cipher_suites, &s->cert->ciphers_raw, - &s->cert->ciphers_rawlen)) { - OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, ERR_R_MALLOC_FAILURE); - goto err; - } - while (CBS_len(&cipher_suites) > 0) { uint16_t cipher_suite; @@ -1503,9 +1352,7 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) { return sk; err: - if (sk != NULL) { - sk_SSL_CIPHER_free(sk); - } + sk_SSL_CIPHER_free(sk); return NULL; } @@ -1691,17 +1538,9 @@ void SSL_CTX_set_next_proto_select_cb( ctx->next_proto_select_cb_arg = arg; } -/* SSL_CTX_set_alpn_protos sets the ALPN protocol list on |ctx| to |protos|. - * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit - * length-prefixed strings). - * - * Returns 0 on success. */ int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const uint8_t *protos, unsigned protos_len) { - if (ctx->alpn_client_proto_list) { - OPENSSL_free(ctx->alpn_client_proto_list); - } - + OPENSSL_free(ctx->alpn_client_proto_list); ctx->alpn_client_proto_list = BUF_memdup(protos, protos_len); if (!ctx->alpn_client_proto_list) { return 1; @@ -1711,16 +1550,8 @@ int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const uint8_t *protos, return 0; } -/* SSL_set_alpn_protos sets the ALPN protocol list on |ssl| to |protos|. - * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit - * length-prefixed strings). - * - * Returns 0 on success. */ int SSL_set_alpn_protos(SSL *ssl, const uint8_t *protos, unsigned protos_len) { - if (ssl->alpn_client_proto_list) { - OPENSSL_free(ssl->alpn_client_proto_list); - } - + OPENSSL_free(ssl->alpn_client_proto_list); ssl->alpn_client_proto_list = BUF_memdup(protos, protos_len); if (!ssl->alpn_client_proto_list) { return 1; @@ -1759,15 +1590,16 @@ void SSL_get0_alpn_selected(const SSL *ssl, const uint8_t **data, } } -int SSL_export_keying_material(SSL *s, uint8_t *out, size_t olen, - const char *label, size_t llen, const uint8_t *p, - size_t plen, int use_context) { +int SSL_export_keying_material(SSL *s, uint8_t *out, size_t out_len, + const char *label, size_t label_len, + const uint8_t *context, size_t context_len, + int use_context) { if (s->version < TLS1_VERSION) { - return -1; + return 0; } - return s->enc_method->export_keying_material(s, out, olen, label, llen, p, - plen, use_context); + return s->enc_method->export_keying_material( + s, out, out_len, label, label_len, context, context_len, use_context); } static uint32_t ssl_session_hash(const SSL_SESSION *a) { @@ -1833,8 +1665,6 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) { ret->get_session_cb = 0; ret->generate_session_id = 0; - memset((char *)&ret->stats, 0, sizeof(ret->stats)); - ret->references = 1; ret->quiet_shutdown = 0; @@ -1858,8 +1688,6 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) { ret->default_passwd_callback = 0; ret->default_passwd_callback_userdata = NULL; ret->client_cert_cb = 0; - ret->app_gen_cookie_cb = 0; - ret->app_verify_cookie_cb = 0; ret->sessions = lh_SSL_SESSION_new(ssl_session_hash, ssl_session_cmp); if (ret->sessions == NULL) { @@ -1871,8 +1699,7 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) { } ssl_create_cipher_list(ret->method, &ret->cipher_list, - &ret->cipher_list_by_id, SSL_DEFAULT_CIPHER_LIST, - ret->cert); + &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); @@ -1889,7 +1716,7 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) { goto err; } - CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_CTX, ret, &ret->ex_data); + CRYPTO_new_ex_data(&g_ex_data_class_ssl_ctx, ret, &ret->ex_data); ret->extra_certs = NULL; @@ -1904,9 +1731,6 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) { ret->options |= SSL_OP_NO_TICKET; } - ret->tlsext_status_cb = 0; - ret->tlsext_status_arg = NULL; - ret->next_protos_advertised_cb = 0; ret->next_proto_select_cb = 0; ret->psk_identity_hint = NULL; @@ -1929,27 +1753,17 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) { err: OPENSSL_PUT_ERROR(SSL, SSL_CTX_new, ERR_R_MALLOC_FAILURE); err2: - if (ret != NULL) { - SSL_CTX_free(ret); - } + SSL_CTX_free(ret); return NULL; } -void SSL_CTX_free(SSL_CTX *a) { - int i; - - if (a == NULL) { +void SSL_CTX_free(SSL_CTX *ctx) { + if (ctx == NULL || + CRYPTO_add(&ctx->references, -1, CRYPTO_LOCK_SSL_CTX) > 0) { return; } - i = CRYPTO_add(&a->references, -1, CRYPTO_LOCK_SSL_CTX); - if (i > 0) { - return; - } - - if (a->param) { - X509_VERIFY_PARAM_free(a->param); - } + 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 @@ -1957,59 +1771,27 @@ void SSL_CTX_free(SSL_CTX *a) { * 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].) */ - if (a->sessions != NULL) { - SSL_CTX_flush_sessions(a, 0); - } + SSL_CTX_flush_sessions(ctx, 0); - CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_CTX, a, &a->ex_data); + CRYPTO_free_ex_data(&g_ex_data_class_ssl_ctx, ctx, &ctx->ex_data); - if (a->sessions != NULL) { - lh_SSL_SESSION_free(a->sessions); - } - if (a->cert_store != NULL) { - X509_STORE_free(a->cert_store); - } - if (a->cipher_list != NULL) { - ssl_cipher_preference_list_free(a->cipher_list); - } - if (a->cipher_list_by_id != NULL) { - sk_SSL_CIPHER_free(a->cipher_list_by_id); - } - if (a->cipher_list_tls11 != NULL) { - ssl_cipher_preference_list_free(a->cipher_list_tls11); - } - if (a->cert != NULL) { - ssl_cert_free(a->cert); - } - if (a->client_CA != NULL) { - sk_X509_NAME_pop_free(a->client_CA, X509_NAME_free); - } - if (a->extra_certs != NULL) { - sk_X509_pop_free(a->extra_certs, X509_free); - } - if (a->srtp_profiles) { - sk_SRTP_PROTECTION_PROFILE_free(a->srtp_profiles); - } - if (a->psk_identity_hint) { - OPENSSL_free(a->psk_identity_hint); - } - if (a->tlsext_ecpointformatlist) { - OPENSSL_free(a->tlsext_ecpointformatlist); - } - if (a->tlsext_ellipticcurvelist) { - OPENSSL_free(a->tlsext_ellipticcurvelist); - } - if (a->alpn_client_proto_list != NULL) { - OPENSSL_free(a->alpn_client_proto_list); - } - if (a->tlsext_channel_id_private) { - EVP_PKEY_free(a->tlsext_channel_id_private); - } - if (a->keylog_bio) { - BIO_free(a->keylog_bio); - } + 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(a); + OPENSSL_free(ctx); } void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb) { @@ -2051,13 +1833,12 @@ static int ssl_has_key(SSL *s, size_t idx) { return cpk->x509 && cpk->privatekey; } -void ssl_get_compatible_server_ciphers(SSL *s, unsigned long *out_mask_k, - unsigned long *out_mask_a) { +void ssl_get_compatible_server_ciphers(SSL *s, uint32_t *out_mask_k, + uint32_t *out_mask_a) { CERT *c = s->cert; int rsa_enc, rsa_sign, dh_tmp; - unsigned long mask_k, mask_a; + uint32_t mask_k, mask_a; int have_ecc_cert, ecdsa_ok; - int have_ecdh_tmp; X509 *x; if (c == NULL) { @@ -2069,7 +1850,6 @@ void ssl_get_compatible_server_ciphers(SSL *s, unsigned long *out_mask_k, dh_tmp = (c->dh_tmp != NULL || c->dh_tmp_cb != NULL); - have_ecdh_tmp = (c->ecdh_tmp || c->ecdh_tmp_cb || c->ecdh_tmp_auto); 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); @@ -2080,14 +1860,12 @@ void ssl_get_compatible_server_ciphers(SSL *s, unsigned long *out_mask_k, mask_k |= SSL_kRSA; } if (dh_tmp) { - mask_k |= SSL_kEDH; + mask_k |= SSL_kDHE; } if (rsa_enc || rsa_sign) { mask_a |= SSL_aRSA; } - mask_a |= SSL_aNULL; - /* 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) { @@ -2107,8 +1885,8 @@ void ssl_get_compatible_server_ciphers(SSL *s, unsigned long *out_mask_k, /* If we are considering an ECC cipher suite that uses an ephemeral EC * key, check it. */ - if (have_ecdh_tmp && tls1_check_ec_tmp_key(s)) { - mask_k |= SSL_kEECDH; + if (tls1_check_ec_tmp_key(s)) { + mask_k |= SSL_kECDHE; } /* PSK requires a server callback. */ @@ -2126,11 +1904,9 @@ void ssl_get_compatible_server_ciphers(SSL *s, unsigned long *out_mask_k, (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage))) int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s) { - unsigned long alg_a; - int signature_nid = 0, md_nid = 0, pk_nid = 0; const SSL_CIPHER *cs = s->s3->tmp.new_cipher; - - alg_a = cs->algorithm_auth; + 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); @@ -2175,13 +1951,10 @@ CERT_PKEY *ssl_get_server_send_pkey(const SSL *s) { } EVP_PKEY *ssl_get_sign_pkey(SSL *s, const SSL_CIPHER *cipher) { - unsigned long alg_a; - CERT *c; + uint32_t alg_a = cipher->algorithm_auth; + CERT *c = s->cert; int idx = -1; - alg_a = cipher->algorithm_auth; - c = s->cert; - if (alg_a & SSL_aRSA) { if (c->pkeys[SSL_PKEY_RSA_SIGN].privatekey != NULL) { idx = SSL_PKEY_RSA_SIGN; @@ -2202,56 +1975,62 @@ EVP_PKEY *ssl_get_sign_pkey(SSL *s, const SSL_CIPHER *cipher) { } void ssl_update_cache(SSL *s, int mode) { - int i; - - /* If the session_id_length is 0, we are not supposed to cache it, and it - * would be rather hard to do anyway :-) */ + /* Never cache sessions with empty session IDs. */ if (s->session->session_id_length == 0) { return; } - i = s->initial_ctx->session_cache_mode; - if ((i & mode) && !s->hit && - ((i & SSL_SESS_CACHE_NO_INTERNAL_STORE) || - SSL_CTX_add_session(s->initial_ctx, s->session)) && - s->initial_ctx->new_session_cb != NULL) { - CRYPTO_add(&s->session->references, 1, CRYPTO_LOCK_SSL_SESSION); - if (!s->initial_ctx->new_session_cb(s, s->session)) { + SSL_CTX *ctx = s->initial_ctx; + if ((ctx->session_cache_mode & mode) == mode && !s->hit && + ((ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_STORE) || + SSL_CTX_add_session(ctx, s->session)) && + ctx->new_session_cb != NULL) { + /* Note: |new_session_cb| is called whether the internal session cache is + * used or not. */ + if (!ctx->new_session_cb(s, SSL_SESSION_up_ref(s->session))) { SSL_SESSION_free(s->session); } } - /* auto flush every 255 connections */ - if ((!(i & SSL_SESS_CACHE_NO_AUTO_CLEAR)) && ((i & mode) == mode)) { - if ((((mode & SSL_SESS_CACHE_CLIENT) - ? s->initial_ctx->stats.sess_connect_good - : s->initial_ctx->stats.sess_accept_good) & - 0xff) == 0xff) { - SSL_CTX_flush_sessions(s->initial_ctx, (unsigned long)time(NULL)); + if (!(ctx->session_cache_mode & SSL_SESS_CACHE_NO_AUTO_CLEAR) && + !(ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_STORE) && + (ctx->session_cache_mode & mode) == mode) { + /* Automatically flush the internal session cache every 255 connections. */ + int flush_cache = 0; + CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + ctx->handshakes_since_cache_flush++; + if (ctx->handshakes_since_cache_flush >= 255) { + flush_cache = 1; + ctx->handshakes_since_cache_flush = 0; + } + CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); + + if (flush_cache) { + SSL_CTX_flush_sessions(ctx, (unsigned long)time(NULL)); } } } -int SSL_get_error(const SSL *s, int i) { +int SSL_get_error(const SSL *s, int ret_code) { int reason; - unsigned long l; + uint32_t err; BIO *bio; - if (i > 0) { + 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 */ - l = ERR_peek_error(); - if (l != 0) { - if (ERR_GET_LIB(l) == ERR_LIB_SYS) { + err = ERR_peek_error(); + if (err != 0) { + if (ERR_GET_LIB(err) == ERR_LIB_SYS) { return SSL_ERROR_SYSCALL; } return SSL_ERROR_SSL; } - if (i == 0) { + 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. */ @@ -2371,24 +2150,6 @@ void SSL_set_connect_state(SSL *s) { ssl_clear_cipher_ctx(s); } -int ssl_undefined_function(SSL *s) { - OPENSSL_PUT_ERROR(SSL, ssl_undefined_function, - ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; -} - -int ssl_undefined_void_function(void) { - OPENSSL_PUT_ERROR(SSL, ssl_undefined_void_function, - ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; -} - -int ssl_undefined_const_function(const SSL *s) { - OPENSSL_PUT_ERROR(SSL, ssl_undefined_const_function, - ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; -} - static const char *ssl_get_version(int version) { switch (version) { case TLS1_2_VERSION: @@ -2403,6 +2164,12 @@ static const char *ssl_get_version(int version) { case SSL3_VERSION: return "SSLv3"; + case DTLS1_VERSION: + return "DTLSv1"; + + case DTLS1_2_VERSION: + return "DTLSv1.2"; + default: return "unknown"; } @@ -2552,15 +2319,11 @@ SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx) { ctx = ssl->initial_ctx; } - if (ssl->cert != NULL) { - ssl_cert_free(ssl->cert); - } - + ssl_cert_free(ssl->cert); ssl->cert = ssl_cert_dup(ctx->cert); + CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX); - if (ssl->ctx != NULL) { - SSL_CTX_free(ssl->ctx); /* decrement reference count */ - } + SSL_CTX_free(ssl->ctx); /* decrement reference count */ ssl->ctx = ctx; ssl->sid_ctx_length = ctx->sid_ctx_length; @@ -2599,8 +2362,12 @@ long SSL_get_verify_result(const SSL *ssl) { return ssl->verify_result; } int SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) { - return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, argl, argp, new_func, - dup_func, free_func); + int index; + if (!CRYPTO_get_ex_new_index(&g_ex_data_class_ssl, &index, argl, argp, + new_func, dup_func, free_func)) { + return -1; + } + return index; } int SSL_set_ex_data(SSL *s, int idx, void *arg) { @@ -2614,8 +2381,12 @@ void *SSL_get_ex_data(const SSL *s, int idx) { int SSL_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) { - return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_CTX, argl, argp, new_func, - dup_func, free_func); + int index; + if (!CRYPTO_get_ex_new_index(&g_ex_data_class_ssl_ctx, &index, argl, argp, + new_func, dup_func, free_func)) { + return -1; + } + return index; } int SSL_CTX_set_ex_data(SSL_CTX *s, int idx, void *arg) { @@ -2633,9 +2404,7 @@ X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) { } void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store) { - if (ctx->cert_store != NULL) { - X509_STORE_free(ctx->cert_store); - } + X509_STORE_free(ctx->cert_store); ctx->cert_store = store; } @@ -2644,35 +2413,33 @@ int SSL_want(const SSL *s) { return s->rwstate; } void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx, RSA *(*cb)(SSL *ssl, int is_export, int keylength)) { - SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TMP_RSA_CB, (void (*)(void))cb); } void SSL_set_tmp_rsa_callback(SSL *ssl, RSA *(*cb)(SSL *ssl, int is_export, int keylength)) { - SSL_callback_ctrl(ssl, SSL_CTRL_SET_TMP_RSA_CB, (void (*)(void))cb); } void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx, - DH *(*dh)(SSL *ssl, int is_export, - int keylength)) { - SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TMP_DH_CB, (void (*)(void))dh); + DH *(*callback)(SSL *ssl, int is_export, + int keylength)) { + ctx->cert->dh_tmp_cb = callback; } -void SSL_set_tmp_dh_callback(SSL *ssl, DH *(*dh)(SSL *ssl, int is_export, - int keylength)) { - SSL_callback_ctrl(ssl, SSL_CTRL_SET_TMP_DH_CB, (void (*)(void))dh); +void SSL_set_tmp_dh_callback(SSL *ssl, DH *(*callback)(SSL *ssl, int is_export, + int keylength)) { + ssl->cert->dh_tmp_cb = callback; } void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx, - EC_KEY *(*ecdh)(SSL *ssl, int is_export, - int keylength)) { - SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TMP_ECDH_CB, (void (*)(void))ecdh); + EC_KEY *(*callback)(SSL *ssl, int is_export, + int keylength)) { + ctx->cert->ecdh_tmp_cb = callback; } void SSL_set_tmp_ecdh_callback(SSL *ssl, - EC_KEY *(*ecdh)(SSL *ssl, int is_export, - int keylength)) { - SSL_callback_ctrl(ssl, SSL_CTRL_SET_TMP_ECDH_CB, (void (*)(void))ecdh); + EC_KEY *(*callback)(SSL *ssl, int is_export, + int keylength)) { + ssl->cert->ecdh_tmp_cb = callback; } int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint) { @@ -2682,9 +2449,7 @@ int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint) { return 0; } - if (ctx->psk_identity_hint != NULL) { - OPENSSL_free(ctx->psk_identity_hint); - } + OPENSSL_free(ctx->psk_identity_hint); if (identity_hint != NULL) { ctx->psk_identity_hint = BUF_strdup(identity_hint); @@ -2710,10 +2475,8 @@ int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint) { } /* Clear currently configured hint, if any. */ - if (s->psk_identity_hint != NULL) { - OPENSSL_free(s->psk_identity_hint); - s->psk_identity_hint = NULL; - } + OPENSSL_free(s->psk_identity_hint); + s->psk_identity_hint = NULL; if (identity_hint != NULL) { s->psk_identity_hint = BUF_strdup(identity_hint); @@ -2786,19 +2549,26 @@ void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)) { - SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb); + ctx->msg_callback = cb; +} + +void SSL_CTX_set_msg_callback_arg(SSL_CTX *ctx, void *arg) { + ctx->msg_callback_arg = arg; } + void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)) { - SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb); + ssl->msg_callback = cb; +} + +void SSL_set_msg_callback_arg(SSL *ssl, void *arg) { + ssl->msg_callback_arg = arg; } void SSL_CTX_set_keylog_bio(SSL_CTX *ctx, BIO *keylog_bio) { - if (ctx->keylog_bio != NULL) { - BIO_free(ctx->keylog_bio); - } + BIO_free(ctx->keylog_bio); ctx->keylog_bio = keylog_bio; } @@ -2904,19 +2674,12 @@ int ssl_ctx_log_master_secret(SSL_CTX *ctx, const uint8_t *client_random, return ret; } +int SSL_in_false_start(const SSL *s) { + return s->s3->tmp.in_false_start; +} + int SSL_cutthrough_complete(const SSL *s) { - return ( - !s->server && /* cutthrough only applies to clients */ - !s->hit && /* full-handshake */ - s->version >= SSL3_VERSION && - s->s3->in_read_app_data == 0 && /* cutthrough only applies to write() */ - (SSL_get_mode((SSL *)s) & - SSL_MODE_HANDSHAKE_CUTTHROUGH) && /* cutthrough enabled */ - ssl3_can_cutthrough(s) && /* cutthrough allowed */ - s->s3->previous_server_finished_len == - 0 && /* not a renegotiation handshake */ - (s->state == SSL3_ST_CR_SESSION_TICKET_A || /* ready to write app-data*/ - s->state == SSL3_ST_CR_CHANGE || s->state == SSL3_ST_CR_FINISHED_A)); + return SSL_in_false_start(s); } void SSL_get_structure_sizes(size_t *ssl_size, size_t *ssl_ctx_size, @@ -2926,27 +2689,18 @@ void SSL_get_structure_sizes(size_t *ssl_size, size_t *ssl_ctx_size, *ssl_session_size = sizeof(SSL_SESSION); } -int ssl3_can_cutthrough(const SSL *s) { - const SSL_CIPHER *c; - - /* require a strong enough cipher */ - if (SSL_get_cipher_bits(s, NULL) < 128) { - return 0; - } - - /* require ALPN or NPN extension */ - if (!s->s3->alpn_selected && !s->s3->next_proto_neg_seen) { - return 0; - } - - /* require a forward-secret cipher */ - c = SSL_get_current_cipher(s); - if (!c || - (c->algorithm_mkey != SSL_kEDH && c->algorithm_mkey != SSL_kEECDH)) { - return 0; - } +int ssl3_can_false_start(const SSL *s) { + const SSL_CIPHER *const cipher = SSL_get_current_cipher(s); - return 1; + /* False Start only for TLS 1.2 with an ECDHE+AEAD cipher and ALPN or NPN. */ + return !SSL_IS_DTLS(s) && + SSL_version(s) >= TLS1_2_VERSION && + (s->s3->alpn_selected || s->s3->next_proto_neg_seen) && + cipher != NULL && + cipher->algorithm_mkey == SSL_kECDHE && + (cipher->algorithm_enc == SSL_AES128GCM || + cipher->algorithm_enc == SSL_AES256GCM || + cipher->algorithm_enc == SSL_CHACHA20POLY1305); } const SSL3_ENC_METHOD *ssl3_get_enc_method(uint16_t version) { @@ -2957,18 +2711,14 @@ const SSL3_ENC_METHOD *ssl3_get_enc_method(uint16_t version) { case TLS1_VERSION: return &TLSv1_enc_data; + case DTLS1_VERSION: case TLS1_1_VERSION: return &TLSv1_1_enc_data; + case DTLS1_2_VERSION: case TLS1_2_VERSION: return &TLSv1_2_enc_data; - case DTLS1_VERSION: - return &DTLSv1_enc_data; - - case DTLS1_2_VERSION: - return &DTLSv1_2_enc_data; - default: return NULL; } @@ -3016,7 +2766,7 @@ uint16_t ssl3_get_mutual_version(SSL *s, uint16_t client_version) { if (client_version <= DTLS1_2_VERSION && !(s->options & SSL_OP_NO_DTLSv1_2)) { version = DTLS1_2_VERSION; } else if (client_version <= DTLS1_VERSION && - !(s->options & SSL_OP_NO_DTLSv1)) { + !(s->options & SSL_OP_NO_DTLSv1)) { version = DTLS1_VERSION; } @@ -3051,7 +2801,7 @@ uint16_t ssl3_get_mutual_version(SSL *s, uint16_t client_version) { } uint16_t ssl3_get_max_client_version(SSL *s) { - unsigned long options = s->options; + uint32_t options = s->options; uint16_t version = 0; /* OpenSSL's API for controlling versions entails blacklisting individual @@ -3169,6 +2919,41 @@ int SSL_cache_hit(SSL *s) { return s->hit; } 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->reject_peer_renegotiations = !!reject; +} + +const SSL_CIPHER *SSL_get_cipher_by_value(uint16_t value) { + return ssl3_get_cipher_by_value(value); +} + +int SSL_get_rc4_state(const SSL *ssl, const RC4_KEY **read_key, + const RC4_KEY **write_key) { + if (ssl->aead_read_ctx == NULL || ssl->aead_write_ctx == NULL) { + return 0; + } + + return EVP_AEAD_CTX_get_rc4_state(&ssl->aead_read_ctx->ctx, read_key) && + EVP_AEAD_CTX_get_rc4_state(&ssl->aead_write_ctx->ctx, write_key); +} + +int SSL_CTX_sess_connect(const SSL_CTX *ctx) { return 0; } +int SSL_CTX_sess_connect_good(const SSL_CTX *ctx) { return 0; } +int SSL_CTX_sess_connect_renegotiate(const SSL_CTX *ctx) { return 0; } +int SSL_CTX_sess_accept(const SSL_CTX *ctx) { return 0; } +int SSL_CTX_sess_accept_renegotiate(const SSL_CTX *ctx) { return 0; } +int SSL_CTX_sess_accept_good(const SSL_CTX *ctx) { return 0; } +int SSL_CTX_sess_hits(const SSL_CTX *ctx) { return 0; } +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; } diff --git a/src/ssl/ssl_locl.h b/src/ssl/ssl_locl.h deleted file mode 100644 index a0c323c..0000000 --- a/src/ssl/ssl_locl.h +++ /dev/null @@ -1,1035 +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). - * - */ -/* ==================================================================== - * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. - * ECC cipher suite support in OpenSSL originally developed by - * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. - */ -/* ==================================================================== - * Copyright 2005 Nokia. All rights reserved. - * - * The portions of the attached software ("Contribution") is developed by - * Nokia Corporation and is licensed pursuant to the OpenSSL open source - * license. - * - * The Contribution, originally written by Mika Kousa and Pasi Eronen of - * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites - * support (see RFC 4279) to OpenSSL. - * - * No patent licenses or other rights except those expressly stated in - * the OpenSSL open source license shall be deemed granted or received - * expressly, by implication, estoppel, or otherwise. - * - * No assurances are provided by Nokia that the Contribution does not - * infringe the patent or other intellectual property rights of any third - * party or that the license provides you with all the necessary rights - * to make use of the Contribution. - * - * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN - * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA - * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY - * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR - * OTHERWISE. - */ - -#ifndef HEADER_SSL_LOCL_H -#define HEADER_SSL_LOCL_H - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - - -#define c2l(c, l) \ - (l = ((unsigned long)(*((c)++))), l |= (((unsigned long)(*((c)++))) << 8), \ - l |= (((unsigned long)(*((c)++))) << 16), \ - l |= (((unsigned long)(*((c)++))) << 24)) - -/* NOTE - c is not incremented as per c2l */ -#define c2ln(c, l1, l2, n) \ - { \ - c += n; \ - l1 = l2 = 0; \ - switch (n) { \ - case 8: \ - l2 = ((unsigned long)(*(--(c)))) << 24; \ - case 7: \ - l2 |= ((unsigned long)(*(--(c)))) << 16; \ - case 6: \ - l2 |= ((unsigned long)(*(--(c)))) << 8; \ - case 5: \ - l2 |= ((unsigned long)(*(--(c)))); \ - case 4: \ - l1 = ((unsigned long)(*(--(c)))) << 24; \ - case 3: \ - l1 |= ((unsigned long)(*(--(c)))) << 16; \ - case 2: \ - l1 |= ((unsigned long)(*(--(c)))) << 8; \ - case 1: \ - l1 |= ((unsigned long)(*(--(c)))); \ - } \ - } - -#define l2c(l, c) \ - (*((c)++) = (uint8_t)(((l)) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 8) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 16) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 24) & 0xff)) - -#define n2l(c, l) \ - (l = ((unsigned long)(*((c)++))) << 24, \ - l |= ((unsigned long)(*((c)++))) << 16, \ - l |= ((unsigned long)(*((c)++))) << 8, l |= ((unsigned long)(*((c)++)))) - -#define l2n(l, c) \ - (*((c)++) = (uint8_t)(((l) >> 24) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 16) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 8) & 0xff), \ - *((c)++) = (uint8_t)(((l)) & 0xff)) - -#define l2n8(l, c) \ - (*((c)++) = (uint8_t)(((l) >> 56) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 48) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 40) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 32) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 24) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 16) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 8) & 0xff), \ - *((c)++) = (uint8_t)(((l)) & 0xff)) - -/* NOTE - c is not incremented as per l2c */ -#define l2cn(l1, l2, c, n) \ - { \ - c += n; \ - switch (n) { \ - case 8: \ - *(--(c)) = (uint8_t)(((l2) >> 24) & 0xff); \ - case 7: \ - *(--(c)) = (uint8_t)(((l2) >> 16) & 0xff); \ - case 6: \ - *(--(c)) = (uint8_t)(((l2) >> 8) & 0xff); \ - case 5: \ - *(--(c)) = (uint8_t)(((l2)) & 0xff); \ - case 4: \ - *(--(c)) = (uint8_t)(((l1) >> 24) & 0xff); \ - case 3: \ - *(--(c)) = (uint8_t)(((l1) >> 16) & 0xff); \ - case 2: \ - *(--(c)) = (uint8_t)(((l1) >> 8) & 0xff); \ - case 1: \ - *(--(c)) = (uint8_t)(((l1)) & 0xff); \ - } \ - } - -#define n2s(c, s) \ - ((s = (((unsigned int)(c[0])) << 8) | (((unsigned int)(c[1])))), c += 2) - -#define s2n(s, c) \ - ((c[0] = (uint8_t)(((s) >> 8) & 0xff), \ - c[1] = (uint8_t)(((s)) & 0xff)), \ - c += 2) - -#define n2l3(c, l) \ - ((l = (((unsigned long)(c[0])) << 16) | (((unsigned long)(c[1])) << 8) | \ - (((unsigned long)(c[2])))), \ - c += 3) - -#define l2n3(l, c) \ - ((c[0] = (uint8_t)(((l) >> 16) & 0xff), \ - c[1] = (uint8_t)(((l) >> 8) & 0xff), \ - c[2] = (uint8_t)(((l)) & 0xff)), \ - c += 3) - -/* LOCAL STUFF */ - -#define SSL_DECRYPT 0 -#define SSL_ENCRYPT 1 - -#define TWO_BYTE_BIT 0x80 -#define SEC_ESC_BIT 0x40 -#define TWO_BYTE_MASK 0x7fff -#define THREE_BYTE_MASK 0x3fff - -#define INC32(a) ((a) = ((a) + 1) & 0xffffffffL) -#define DEC32(a) ((a) = ((a)-1) & 0xffffffffL) -#define MAX_MAC_SIZE 20 /* up from 16 for SSLv3 */ - -/* Define the Bitmasks for SSL_CIPHER.algorithms. - * - * This bits are used packed as dense as possible. If new methods/ciphers etc - * will be added, the bits a likely to change, so this information is for - * internal library use only, even though SSL_CIPHER.algorithms can be publicly - * accessed. Use the according functions for cipher management instead. - * - * The bit mask handling in the selection and sorting scheme in - * ssl_create_cipher_list() has only limited capabilities, reflecting that the - * different entities within are mutually exclusive: - * ONLY ONE BIT PER MASK CAN BE SET AT A TIME. */ - -/* Bits for algorithm_mkey (key exchange algorithm) */ -#define SSL_kRSA 0x00000001L /* RSA key exchange */ -#define SSL_kEDH 0x00000002L /* tmp DH key no DH cert */ -#define SSL_kEECDH 0x00000004L /* ephemeral ECDH */ -#define SSL_kPSK 0x00000008L /* PSK */ - -/* Bits for algorithm_auth (server authentication) */ -#define SSL_aRSA 0x00000001L /* RSA auth */ -#define SSL_aNULL 0x00000002L /* no auth (i.e. use ADH or AECDH) */ -#define SSL_aECDSA 0x00000004L /* ECDSA auth*/ -#define SSL_aPSK 0x00000008L /* PSK auth */ - -/* Bits for algorithm_enc (symmetric encryption) */ -#define SSL_3DES 0x00000001L -#define SSL_RC4 0x00000002L -#define SSL_AES128 0x00000004L -#define SSL_AES256 0x00000008L -#define SSL_AES128GCM 0x00000010L -#define SSL_AES256GCM 0x00000020L -#define SSL_CHACHA20POLY1305 0x00000040L - -#define SSL_AES (SSL_AES128 | SSL_AES256 | SSL_AES128GCM | SSL_AES256GCM) - -/* Bits for algorithm_mac (symmetric authentication) */ - -#define SSL_MD5 0x00000001L -#define SSL_SHA1 0x00000002L -#define SSL_SHA256 0x00000004L -#define SSL_SHA384 0x00000008L -/* Not a real MAC, just an indication it is part of cipher */ -#define SSL_AEAD 0x00000010L - -/* Bits for algorithm_ssl (protocol version) */ -#define SSL_SSLV3 0x00000002L -#define SSL_TLSV1 SSL_SSLV3 /* for now */ -#define SSL_TLSV1_2 0x00000004L - -/* 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) - -/* When adding new digest in the ssl_ciph.c and increment SSM_MD_NUM_IDX - * make sure to update this constant too */ -#define SSL_MAX_DIGEST 4 - -#define TLS1_PRF_DGST_MASK (0xff << TLS1_PRF_DGST_SHIFT) - -#define TLS1_PRF_DGST_SHIFT 10 -#define TLS1_PRF_MD5 (SSL_HANDSHAKE_MAC_MD5 << TLS1_PRF_DGST_SHIFT) -#define TLS1_PRF_SHA1 (SSL_HANDSHAKE_MAC_SHA << TLS1_PRF_DGST_SHIFT) -#define TLS1_PRF_SHA256 (SSL_HANDSHAKE_MAC_SHA256 << TLS1_PRF_DGST_SHIFT) -#define TLS1_PRF_SHA384 (SSL_HANDSHAKE_MAC_SHA384 << TLS1_PRF_DGST_SHIFT) -#define TLS1_PRF (TLS1_PRF_MD5 | TLS1_PRF_SHA1) - -#define TLSEXT_CHANNEL_ID_SIZE 128 - -/* SSL_CIPHER_ALGORITHM2_AEAD is a flag in SSL_CIPHER.algorithm2 which - * indicates that the cipher is implemented via an EVP_AEAD. */ -#define SSL_CIPHER_ALGORITHM2_AEAD (1 << 23) - -/* 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) - -/* Cipher strength information. */ -#define SSL_MEDIUM 0x00000001L -#define SSL_HIGH 0x00000002L -#define SSL_FIPS 0x00000004L - -/* we have used 000001ff - 23 bits left to go */ - -/* Check if an SSL structure is using DTLS */ -#define SSL_IS_DTLS(s) (s->enc_method->enc_flags & SSL_ENC_FLAG_DTLS) -/* See if we need explicit IV */ -#define SSL_USE_EXPLICIT_IV(s) \ - (s->enc_method->enc_flags & SSL_ENC_FLAG_EXPLICIT_IV) -/* See if we use signature algorithms extension and signature algorithm before - * signatures. */ -#define SSL_USE_SIGALGS(s) (s->enc_method->enc_flags & SSL_ENC_FLAG_SIGALGS) -/* Allow TLS 1.2 ciphersuites: applies to DTLS 1.2 as well as TLS 1.2: may - * apply to others in future. */ -#define SSL_USE_TLS1_2_CIPHERS(s) \ - (s->enc_method->enc_flags & SSL_ENC_FLAG_TLS1_2_CIPHERS) -/* Determine if a client can use TLS 1.2 ciphersuites: can't rely on method - * flags because it may not be set to correct version yet. */ -#define SSL_CLIENT_USE_TLS1_2_CIPHERS(s) \ - ((SSL_IS_DTLS(s) && s->client_version <= DTLS1_2_VERSION) || \ - (!SSL_IS_DTLS(s) && s->client_version >= TLS1_2_VERSION)) - -/* Mostly for SSLv3 */ -#define SSL_PKEY_RSA_ENC 0 -#define SSL_PKEY_RSA_SIGN 1 -#define SSL_PKEY_ECC 2 -#define SSL_PKEY_NUM 3 - -/* SSL_kRSA <- RSA_ENC | (RSA_TMP & RSA_SIGN) | - * <- (EXPORT & (RSA_ENC | RSA_TMP) & RSA_SIGN) - * SSL_kDH <- DH_ENC & (RSA_ENC | RSA_SIGN | DSA_SIGN) - * SSL_kEDH <- RSA_ENC | RSA_SIGN | DSA_SIGN - * SSL_aRSA <- RSA_ENC | RSA_SIGN - * SSL_aDSS <- DSA_SIGN */ - -#define PENDING_SESSION -10000 -#define CERTIFICATE_SELECTION_PENDING -10001 - -/* From RFC4492, used in encoding the curve type in ECParameters */ -#define EXPLICIT_PRIME_CURVE_TYPE 1 -#define EXPLICIT_CHAR2_CURVE_TYPE 2 -#define NAMED_CURVE_TYPE 3 - -/* Values for the |hash_message| parameter of |s->method->ssl_get_message|. */ -#define SSL_GET_MESSAGE_DONT_HASH_MESSAGE 0 -#define SSL_GET_MESSAGE_HASH_MESSAGE 1 - -typedef struct cert_pkey_st { - X509 *x509; - EVP_PKEY *privatekey; - /* Chain for this certificate */ - STACK_OF(X509) * chain; -} CERT_PKEY; - -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. - * - * TODO(davidben): Remove these. They get checked twice: when sending the - * ClientHello and when processing the ServerHello. However, mask_ssl is a - * different value both times. mask_k and mask_a are not, but is a - * round-about way of checking the server's cipher was one of the advertised - * ones. (Currently it checks the masks and then the list of ciphers prior to - * applying the masks in ClientHello.) */ - unsigned long mask_k; - unsigned long mask_a; - unsigned long mask_ssl; - - DH *dh_tmp; - DH *(*dh_tmp_cb)(SSL *ssl, int is_export, int keysize); - EC_KEY *ecdh_tmp; - /* Callback for generating ephemeral ECDH keys */ - EC_KEY *(*ecdh_tmp_cb)(SSL *ssl, int is_export, int keysize); - /* Select ECDH parameters automatically */ - int ecdh_tmp_auto; - /* Flags related to certificates */ - unsigned int cert_flags; - 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; - /* 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 - * can then examine any appropriate parameters and setup any - * certificates required. This allows advanced applications - * to select certificates on the fly: for example based on - * 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; - - /* Raw values of the cipher list from a client */ - uint8_t *ciphers_raw; - size_t ciphers_rawlen; -} CERT; - -typedef struct sess_cert_st { - STACK_OF(X509) * cert_chain; /* as received from peer (not for SSL2) */ - - /* The 'peer_...' members are used only by clients. */ - int peer_cert_type; - - CERT_PKEY *peer_key; /* points to an element of peer_pkeys (never NULL!) */ - CERT_PKEY peer_pkeys[SSL_PKEY_NUM]; - /* Obviously we don't have the private keys of these, - * so maybe we shouldn't even use the CERT_PKEY type here. */ - - 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 { - /* version, if non-zero, is the only protocol version acceptable to an - * SSL_CTX initialized from this method. */ - uint16_t version; - /* method is the underlying SSL_PROTOCOL_METHOD that initializes the - * SSL_CTX. */ - const SSL_PROTOCOL_METHOD *method; -}; - -/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ -struct ssl_protocol_method_st { - int (*ssl_new)(SSL *s); - void (*ssl_free)(SSL *s); - int (*ssl_accept)(SSL *s); - int (*ssl_connect)(SSL *s); - int (*ssl_read)(SSL *s, void *buf, int len); - int (*ssl_peek)(SSL *s, void *buf, int len); - int (*ssl_write)(SSL *s, const void *buf, int len); - int (*ssl_shutdown)(SSL *s); - int (*ssl_renegotiate)(SSL *s); - int (*ssl_renegotiate_check)(SSL *s); - long (*ssl_get_message)(SSL *s, int header_state, int body_state, - int msg_type, long max, int hash_message, int *ok); - int (*ssl_read_bytes)(SSL *s, int type, uint8_t *buf, int len, int peek); - int (*ssl_write_bytes)(SSL *s, int type, 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); - int (*ssl_pending)(const SSL *s); - int (*num_ciphers)(void); - const SSL_CIPHER *(*get_cipher)(unsigned ncipher); - int (*ssl_version)(void); - long (*ssl_callback_ctrl)(SSL *s, int cb_id, void (*fp)(void)); - long (*ssl_ctx_callback_ctrl)(SSL_CTX *s, int cb_id, void (*fp)(void)); -}; - -/* This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff It is a bit - * of a mess of functions, but hell, think of it as an opaque structure. */ -struct ssl3_enc_method { - int (*enc)(SSL *, int); - int (*prf)(SSL *, uint8_t *, size_t, const uint8_t *, size_t, const char *, - size_t, const uint8_t *, size_t, const uint8_t *, size_t); - int (*setup_key_block)(SSL *); - int (*generate_master_secret)(SSL *, uint8_t *, const uint8_t *, size_t); - int (*change_cipher_state)(SSL *, int); - int (*final_finish_mac)(SSL *, const char *, int, uint8_t *); - int finish_mac_length; - int (*cert_verify_mac)(SSL *, int, uint8_t *); - const char *client_finished_label; - int client_finished_label_len; - const char *server_finished_label; - int server_finished_label_len; - int (*alert_value)(int); - int (*export_keying_material)(SSL *, uint8_t *, size_t, const char *, size_t, - const uint8_t *, size_t, int use_context); - /* Various flags indicating protocol version requirements */ - unsigned int enc_flags; - /* Handshake header length */ - unsigned int hhlen; - /* Set the handshake header */ - void (*set_handshake_header)(SSL *s, int type, unsigned long len); - /* Write out handshake message */ - int (*do_write)(SSL *s); -}; - -#define SSL_HM_HEADER_LENGTH(s) s->enc_method->hhlen -#define ssl_handshake_start(s) \ - (((uint8_t *)s->init_buf->data) + s->enc_method->hhlen) -#define ssl_set_handshake_header(s, htype, len) \ - s->enc_method->set_handshake_header(s, htype, len) -#define ssl_do_write(s) s->enc_method->do_write(s) - -/* Values for enc_flags */ - -/* Uses explicit IV for CBC mode */ -#define SSL_ENC_FLAG_EXPLICIT_IV 0x1 -/* Uses signature algorithms extension */ -#define SSL_ENC_FLAG_SIGALGS 0x2 -/* Uses SHA256 default PRF */ -#define SSL_ENC_FLAG_SHA256_PRF 0x4 -/* Is DTLS */ -#define SSL_ENC_FLAG_DTLS 0x8 -/* Allow TLS 1.2 ciphersuites: applies to DTLS 1.2 as well as TLS 1.2: - * may apply to others in future. */ -#define SSL_ENC_FLAG_TLS1_2_CIPHERS 0x10 - -/* ssl_aead_ctx_st contains information about an AEAD that is being used to - * encrypt an SSL connection. */ -struct ssl_aead_ctx_st { - EVP_AEAD_CTX ctx; - /* fixed_nonce contains any bytes of the nonce that are fixed for all - * records. */ - uint8_t fixed_nonce[8]; - uint8_t fixed_nonce_len, variable_nonce_len, tag_len; - /* variable_nonce_included_in_record is non-zero if the variable nonce - * for a record is included as a prefix before the ciphertext. */ - char variable_nonce_included_in_record; - /* random_variable_nonce is non-zero if the variable nonce is - * randomly generated, rather than derived from the sequence - * number. */ - char random_variable_nonce; - /* omit_length_in_ad is non-zero if the length should be omitted in the - * AEAD's ad parameter. */ - char omit_length_in_ad; - /* omit_version_in_ad is non-zero if the version should be omitted - * in the AEAD's ad parameter. */ - char omit_version_in_ad; -}; - -extern const SSL_CIPHER ssl3_ciphers[]; - -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 SSL3_ENC_METHOD DTLSv1_enc_data; -extern const SSL3_ENC_METHOD DTLSv1_2_enc_data; - -void ssl_clear_cipher_ctx(SSL *s); -int ssl_clear_bad_session(SSL *s); -CERT *ssl_cert_new(void); -CERT *ssl_cert_dup(CERT *cert); -int ssl_cert_inst(CERT **o); -void ssl_cert_clear_certs(CERT *c); -void ssl_cert_free(CERT *c); -SESS_CERT *ssl_sess_cert_new(void); -void ssl_sess_cert_free(SESS_CERT *sc); -int ssl_set_peer_cert_type(SESS_CERT *c, int type); -int ssl_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx); -int ssl_cipher_id_cmp(const void *in_a, const void *in_b); -int ssl_cipher_ptr_id_cmp(const SSL_CIPHER **ap, const SSL_CIPHER **bp); -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); -STACK_OF(SSL_CIPHER) * - ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *meth, - struct ssl_cipher_preference_list_st **pref, - STACK_OF(SSL_CIPHER) * *sorted, const char *rule_str, - CERT *c); -struct ssl_cipher_preference_list_st *ssl_cipher_preference_list_dup( - struct ssl_cipher_preference_list_st *cipher_list); -void ssl_cipher_preference_list_free( - struct ssl_cipher_preference_list_st *cipher_list); -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); - -/* ssl_cipher_get_evp_aead sets |*out_aead| to point to the correct EVP_AEAD -* object for |cipher| protocol version |version|. It sets |*out_mac_secret_len| -* and |*out_fixed_iv_len| to the MAC key length and fixed IV length, -* respectively. The MAC key length is zero except for legacy block and stream -* ciphers. It returns 1 on success and 0 on error. */ -int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead, - size_t *out_mac_secret_len, - size_t *out_fixed_iv_len, - const SSL_CIPHER *cipher, uint16_t version); - -int ssl_get_handshake_digest(size_t i, long *mask, const EVP_MD **md); -int ssl_cipher_get_cert_index(const SSL_CIPHER *c); -int ssl_cipher_has_server_public_key(const SSL_CIPHER *cipher); -int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher); - -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); -int ssl_undefined_function(SSL *s); -int ssl_undefined_void_function(void); -int ssl_undefined_const_function(const SSL *s); -CERT_PKEY *ssl_get_server_send_pkey(const SSL *s); -EVP_PKEY *ssl_get_sign_pkey(SSL *s, const SSL_CIPHER *c); -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 - * and current ClientHello parameters of |s|. It sets |*out_mask_k| to the key - * exchange mask and |*out_mask_a| to the authentication mask. */ -void ssl_get_compatible_server_ciphers(SSL *s, unsigned long *out_mask_k, - unsigned long *out_mask_a); - -STACK_OF(SSL_CIPHER) * ssl_get_ciphers_by_id(SSL *s); -int ssl_verify_alarm_type(long type); -int ssl_fill_hello_random(SSL *s, int server, uint8_t *field, size_t len); - -const SSL_CIPHER *ssl3_get_cipher_by_value(uint16_t value); -uint16_t ssl3_get_cipher_value(const SSL_CIPHER *c); -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_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, - 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); -void ssl3_cleanup_key_block(SSL *s); -int ssl3_do_write(SSL *s, int type); -int ssl3_send_alert(SSL *s, int level, int desc); -int ssl3_get_req_cert_type(SSL *s, uint8_t *p); -long ssl3_get_message(SSL *s, int header_state, int body_state, int msg_type, - long max, int hash_message, int *ok); - -/* ssl3_hash_current_message incorporates the current handshake message into - * the handshake hash. */ -void 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 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, EVP_PKEY *pkey); - -int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen); -int ssl3_num_ciphers(void); -const SSL_CIPHER *ssl3_get_cipher(unsigned int u); -int ssl3_renegotiate(SSL *ssl); -int ssl3_renegotiate_check(SSL *ssl); -int ssl3_dispatch_alert(SSL *s); -int ssl3_expect_change_cipher_spec(SSL *s); -int ssl3_read_bytes(SSL *s, int type, uint8_t *buf, int len, int peek); -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); -void ssl3_finish_mac(SSL *s, const uint8_t *buf, int len); -void ssl3_free_digest_list(SSL *s); -unsigned long 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_buffers(SSL *s); -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); -int ssl3_read(SSL *s, void *buf, int len); -int ssl3_peek(SSL *s, void *buf, int len); -int ssl3_write(SSL *s, const void *buf, int len); -int ssl3_shutdown(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); -long ssl3_callback_ctrl(SSL *s, int cmd, void (*fp)(void)); -long ssl3_ctx_callback_ctrl(SSL_CTX *s, int cmd, void (*fp)(void)); -int ssl3_pending(const SSL *s); - -void ssl3_record_sequence_update(uint8_t *seq); -int ssl3_do_change_cipher_spec(SSL *ssl); - -void ssl3_set_handshake_header(SSL *s, int htype, unsigned long len); -int ssl3_handshake_write(SSL *s); - -int dtls1_do_write(SSL *s, int type); -int ssl3_read_n(SSL *s, int n, int max, int extend); -int dtls1_read_bytes(SSL *s, int type, uint8_t *buf, int len, int peek); -int ssl3_write_pending(SSL *s, int type, const uint8_t *buf, unsigned int len); -void dtls1_set_message_header(SSL *s, uint8_t mt, unsigned long len, - unsigned short seq_num, unsigned long frag_off, - unsigned long frag_len); - -int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf, int len); -int dtls1_write_bytes(SSL *s, int type, const void *buf, int len); - -int dtls1_send_change_cipher_spec(SSL *s, int a, int b); -int dtls1_send_finished(SSL *s, int a, int b, const char *sender, int slen); -int dtls1_read_failed(SSL *s, int code); -int dtls1_buffer_message(SSL *s, int ccs); -int dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off, - int *found); -int dtls1_get_queue_priority(unsigned short seq, int is_ccs); -int dtls1_retransmit_buffered_messages(SSL *s); -void dtls1_clear_record_buffer(SSL *s); -void dtls1_get_message_header(uint8_t *data, struct hm_header_st *msg_hdr); -void dtls1_get_ccs_header(uint8_t *data, struct ccs_header_st *ccs_hdr); -void dtls1_reset_seq_numbers(SSL *s, int rw); -int dtls1_check_timeout_num(SSL *s); -int dtls1_handle_timeout(SSL *s); -const SSL_CIPHER *dtls1_get_cipher(unsigned int u); -void dtls1_start_timer(SSL *s); -void dtls1_stop_timer(SSL *s); -int dtls1_is_timer_expired(SSL *s); -void dtls1_double_timeout(SSL *s); -unsigned int dtls1_min_mtu(void); -void dtls1_hm_fragment_free(hm_fragment *frag); - -/* some client-only functions */ -int ssl3_send_client_hello(SSL *s); -int ssl3_get_server_hello(SSL *s); -int ssl3_get_certificate_request(SSL *s); -int ssl3_get_new_session_ticket(SSL *s); -int ssl3_get_cert_status(SSL *s); -int ssl3_get_server_done(SSL *s); -int ssl3_send_cert_verify(SSL *s); -int ssl3_send_client_certificate(SSL *s); -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 dtls1_client_hello(SSL *s); - -/* some server-only functions */ -int ssl3_get_initial_bytes(SSL *s); -int ssl3_get_v2_client_hello(SSL *s); -int ssl3_get_client_hello(SSL *s); -int ssl3_send_server_hello(SSL *s); -int ssl3_send_hello_request(SSL *s); -int ssl3_send_server_key_exchange(SSL *s); -int ssl3_send_certificate_request(SSL *s); -int ssl3_send_server_done(SSL *s); -int ssl3_get_client_certificate(SSL *s); -int ssl3_get_client_key_exchange(SSL *s); -int ssl3_get_cert_verify(SSL *s); -int ssl3_get_next_proto(SSL *s); -int ssl3_get_channel_id(SSL *s); - -int dtls1_new(SSL *s); -int dtls1_accept(SSL *s); -int dtls1_connect(SSL *s); -void dtls1_free(SSL *s); -long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg); -int dtls1_shutdown(SSL *s); - -long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, - int 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); -void ssl_free_wbio_buffer(SSL *s); - -/* tls1_prf computes the TLS PRF function for |s| as described in RFC 5246, - * section 5 and RFC 2246 section 5. It writes |out_len| bytes to |out|, using - * |secret| as the secret and |label| as the label. |seed1| and |seed2| are - * concatenated to form the seed parameter. It returns one on success and zero - * on failure. */ -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); - -int tls1_change_cipher_state(SSL *s, int which); -int tls1_setup_key_block(SSL *s); -int tls1_enc(SSL *s, int snd); -int tls1_handshake_digest(SSL *s, uint8_t *out, size_t out_len); -int tls1_final_finish_mac(SSL *s, const char *str, int slen, uint8_t *p); -int tls1_cert_verify_mac(SSL *s, int md_nid, uint8_t *p); -int tls1_generate_master_secret(SSL *s, uint8_t *out, const uint8_t *premaster, - size_t premaster_len); -int tls1_export_keying_material(SSL *s, uint8_t *out, size_t olen, - const char *label, size_t llen, - const uint8_t *p, size_t plen, int use_context); -int tls1_alert_code(int code); -int ssl3_alert_code(int code); -int ssl_ok(SSL *s); - -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_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 - * zero on error. */ -int tls1_check_curve(SSL *s, CBS *cbs, uint16_t *out_curve_id); - -/* tls1_get_shared_curve returns the NID of the first preferred shared curve - * between client and server preferences. If none can be found, it returns - * NID_undef. */ -int tls1_get_shared_curve(SSL *s); - -/* tls1_set_curves converts the array of |ncurves| NIDs pointed to by |curves| - * into a newly allocated array of TLS curve IDs. On success, the function - * returns one and writes the array to |*out_curve_ids| and its size to - * |*out_curve_ids_len|. Otherwise, it returns zero. */ -int tls1_set_curves(uint16_t **out_curve_ids, size_t *out_curve_ids_len, - const int *curves, size_t ncurves); - -/* tls1_check_ec_cert returns one if |x| is an ECC certificate with curve and - * point format compatible with the client's preferences. Otherwise it returns - * zero. */ -int tls1_check_ec_cert(SSL *s, X509 *x); - -/* tls1_check_ec_tmp_key returns one if the EC temporary key is compatible with - * client extensions and zero otherwise. */ -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 *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); - -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); - -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|. */ -int ssl_ctx_log_rsa_client_key_exchange(SSL_CTX *ctx, - const uint8_t *encrypted_premaster, - size_t encrypted_premaster_len, - const uint8_t *premaster, - size_t premaster_len); - -/* ssl_ctx_log_master_secret logs |master| to |ctx|, if logging is enabled. It - * returns one on success and zero on failure. The entry is identified by - * |client_random|. */ -int ssl_ctx_log_master_secret(SSL_CTX *ctx, const uint8_t *client_random, - size_t client_random_len, const uint8_t *master, - size_t master_len); - -int ssl3_can_cutthrough(const SSL *s); - -/* ssl3_get_enc_method returns the SSL3_ENC_METHOD corresponding to - * |version|. */ -const SSL3_ENC_METHOD *ssl3_get_enc_method(uint16_t version); - -/* ssl3_get_max_server_version returns the maximum SSL/TLS version number - * supported by |s| as a server, or zero if all versions are disabled. */ -uint16_t ssl3_get_max_server_version(const SSL *s); - -/* ssl3_get_mutual_version selects the protocol version on |s| for a client - * which advertises |client_version|. If no suitable version exists, it returns - * zero. */ -uint16_t ssl3_get_mutual_version(SSL *s, uint16_t client_version); - -/* ssl3_get_max_client_version returns the maximum protocol version configured - * for the client. It is guaranteed that the set of allowed versions at or below - * this maximum version is contiguous. If all versions are disabled, it returns - * zero. */ -uint16_t ssl3_get_max_client_version(SSL *s); - -/* ssl3_is_version_enabled returns one if |version| is an enabled protocol - * version for |s| and zero otherwise. */ -int ssl3_is_version_enabled(SSL *s, uint16_t version); - -/* ssl3_version_from_wire maps |wire_version| to a protocol version. For - * SSLv3/TLS, the version is returned as-is. For DTLS, the corresponding TLS - * version is used. Note that this mapping is not injective but preserves - * comparisons. - * - * TODO(davidben): To normalize some DTLS-specific code, move away from using - * the wire version except at API boundaries. */ -uint16_t ssl3_version_from_wire(SSL *s, uint16_t wire_version); - -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); -long ssl_get_algorithm2(SSL *s); -int tls1_process_sigalgs(SSL *s, const CBS *sigalgs); - -/* 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 diff --git a/src/ssl/ssl_rsa.c b/src/ssl/ssl_rsa.c index 3d1bc62..87f4c1c 100644 --- a/src/ssl/ssl_rsa.c +++ b/src/ssl/ssl_rsa.c @@ -64,7 +64,7 @@ #include #include -#include "ssl_locl.h" +#include "internal.h" static int ssl_set_cert(CERT *c, X509 *x509); static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey); @@ -74,10 +74,6 @@ int SSL_use_certificate(SSL *ssl, X509 *x) { OPENSSL_PUT_ERROR(SSL, SSL_use_certificate, ERR_R_PASSED_NULL_PARAMETER); return 0; } - if (!ssl_cert_inst(&ssl->cert)) { - OPENSSL_PUT_ERROR(SSL, SSL_use_certificate, ERR_R_MALLOC_FAILURE); - return 0; - } return ssl_set_cert(ssl->cert, x); } @@ -118,12 +114,8 @@ int SSL_use_certificate_file(SSL *ssl, const char *file, int type) { ret = SSL_use_certificate(ssl, x); end: - if (x != NULL) { - X509_free(x); - } - if (in != NULL) { - BIO_free(in); - } + X509_free(x); + BIO_free(in); return ret; } @@ -152,11 +144,6 @@ int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) { return 0; } - if (!ssl_cert_inst(&ssl->cert)) { - OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey, ERR_R_MALLOC_FAILURE); - return 0; - } - pkey = EVP_PKEY_new(); if (pkey == NULL) { OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey, ERR_R_EVP_LIB); @@ -182,12 +169,6 @@ static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) { } if (c->pkeys[i].x509 != NULL) { - EVP_PKEY *pktmp; - pktmp = X509_get_pubkey(c->pkeys[i].x509); - EVP_PKEY_copy_parameters(pktmp, pkey); - EVP_PKEY_free(pktmp); - ERR_clear_error(); - /* 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) && @@ -198,10 +179,8 @@ static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) { } } - if (c->pkeys[i].privatekey != NULL) { - EVP_PKEY_free(c->pkeys[i].privatekey); - } - c->pkeys[i].privatekey = EVP_PKEY_dup(pkey); + EVP_PKEY_free(c->pkeys[i].privatekey); + c->pkeys[i].privatekey = EVP_PKEY_up_ref(pkey); c->key = &(c->pkeys[i]); return 1; @@ -244,9 +223,7 @@ int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type) { RSA_free(rsa); end: - if (in != NULL) { - BIO_free(in); - } + BIO_free(in); return ret; } @@ -275,11 +252,6 @@ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) { return 0; } - if (!ssl_cert_inst(&ssl->cert)) { - OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey, ERR_R_MALLOC_FAILURE); - return 0; - } - ret = ssl_set_pkey(ssl->cert, pkey); return ret; } @@ -320,9 +292,7 @@ int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type) { EVP_PKEY_free(pkey); end: - if (in != NULL) { - BIO_free(in); - } + BIO_free(in); return ret; } @@ -349,10 +319,6 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) { ERR_R_PASSED_NULL_PARAMETER); return 0; } - if (!ssl_cert_inst(&ctx->cert)) { - OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate, ERR_R_MALLOC_FAILURE); - return 0; - } return ssl_set_cert(ctx->cert, x); } @@ -375,9 +341,6 @@ static int ssl_set_cert(CERT *c, X509 *x) { } if (c->pkeys[i].privatekey != NULL) { - EVP_PKEY_copy_parameters(pkey, c->pkeys[i].privatekey); - ERR_clear_error(); - /* 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->pkeys[i].privatekey) && @@ -394,9 +357,7 @@ static int ssl_set_cert(CERT *c, X509 *x) { EVP_PKEY_free(pkey); - if (c->pkeys[i].x509 != NULL) { - X509_free(c->pkeys[i].x509); - } + X509_free(c->pkeys[i].x509); c->pkeys[i].x509 = X509_up_ref(x); c->key = &(c->pkeys[i]); @@ -441,12 +402,8 @@ int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) { ret = SSL_CTX_use_certificate(ctx, x); end: - if (x != NULL) { - X509_free(x); - } - if (in != NULL) { - BIO_free(in); - } + X509_free(x); + BIO_free(in); return ret; } @@ -475,11 +432,6 @@ int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa) { return 0; } - if (!ssl_cert_inst(&ctx->cert)) { - OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey, ERR_R_MALLOC_FAILURE); - return 0; - } - pkey = EVP_PKEY_new(); if (pkey == NULL) { OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey, ERR_R_EVP_LIB); @@ -531,9 +483,7 @@ int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type) { RSA_free(rsa); end: - if (in != NULL) { - BIO_free(in); - } + BIO_free(in); return ret; } @@ -560,11 +510,6 @@ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) { return 0; } - if (!ssl_cert_inst(&ctx->cert)) { - OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey, ERR_R_MALLOC_FAILURE); - return 0; - } - return ssl_set_pkey(ctx->cert, pkey); } @@ -604,9 +549,7 @@ int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) { EVP_PKEY_free(pkey); end: - if (in != NULL) { - BIO_free(in); - } + BIO_free(in); return ret; } @@ -668,7 +611,7 @@ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) { * certificates. */ X509 *ca; int r; - unsigned long err; + uint32_t err; SSL_CTX_clear_chain_certs(ctx); @@ -697,11 +640,7 @@ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) { } end: - if (x != NULL) { - X509_free(x); - } - if (in != NULL) { - BIO_free(in); - } + X509_free(x); + BIO_free(in); return ret; } diff --git a/src/ssl/ssl_sess.c b/src/ssl/ssl_sess.c index c5069d8..3eb428f 100644 --- a/src/ssl/ssl_sess.c +++ b/src/ssl/ssl_sess.c @@ -134,22 +134,26 @@ * OTHERWISE. */ #include +#include -#include #include #include #include #include -#include "ssl_locl.h" +#include "internal.h" +#include "../crypto/internal.h" + /* The address of this is a magic value, a pointer to which is returned by * SSL_magic_pending_session_ptr(). It allows a session callback to indicate * 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; + 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 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) { @@ -164,25 +168,18 @@ SSL_SESSION *SSL_get_session(const SSL *ssl) SSL_SESSION *SSL_get1_session(SSL *ssl) { /* variant of SSL_get_session: caller really gets something */ - SSL_SESSION *sess; - /* Need to lock this all up rather than just use CRYPTO_add so that - * somebody doesn't free ssl->session between when we check it's - * non-null and when we up the reference count. */ - CRYPTO_w_lock(CRYPTO_LOCK_SSL_SESSION); - sess = ssl->session; - if (sess) { - sess->references++; - } - CRYPTO_w_unlock(CRYPTO_LOCK_SSL_SESSION); - - return sess; + return SSL_SESSION_up_ref(ssl->session); } int SSL_SESSION_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) { - return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_SESSION, argl, argp, - new_func, dup_func, free_func); + int index; + if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp, new_func, + dup_func, free_func)) { + return -1; + } + return index; } int SSL_SESSION_set_ex_data(SSL_SESSION *s, int idx, void *arg) { @@ -207,7 +204,7 @@ SSL_SESSION *SSL_SESSION_new(void) { ss->references = 1; ss->timeout = SSL_DEFAULT_SESSION_TIMEOUT; ss->time = (unsigned long)time(NULL); - CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data); + CRYPTO_new_ex_data(&g_ex_data_class, ss, &ss->ex_data); return ss; } @@ -275,10 +272,8 @@ int ssl_get_new_session(SSL *s, int session) { ss->timeout = s->initial_ctx->session_timeout; } - if (s->session != NULL) { - SSL_SESSION_free(s->session); - s->session = NULL; - } + SSL_SESSION_free(s->session); + s->session = NULL; if (session) { if (s->version == SSL3_VERSION || s->version == TLS1_VERSION || @@ -425,15 +420,9 @@ int ssl_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx) { } memcpy(data.session_id, ctx->session_id, ctx->session_id_len); CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); - ret = lh_SSL_SESSION_retrieve(s->initial_ctx->sessions, &data); - if (ret != NULL) { - /* don't allow other threads to steal it: */ - CRYPTO_add(&ret->references, 1, CRYPTO_LOCK_SSL_SESSION); - } + ret = SSL_SESSION_up_ref(lh_SSL_SESSION_retrieve(s->initial_ctx->sessions, + &data)); CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); - if (ret == NULL) { - s->initial_ctx->stats.sess_miss++; - } } if (try_session_cache && ret == NULL && @@ -448,14 +437,13 @@ int ssl_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx) { * unwind the stack and figure out the session asynchronously. */ return PENDING_SESSION; } - s->initial_ctx->stats.sess_cb_hit++; /* 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) { - CRYPTO_add(&ret->references, 1, CRYPTO_LOCK_SSL_SESSION); + SSL_SESSION_up_ref(ret); } /* Add the externally cached session to the internal cache as well if and @@ -499,7 +487,6 @@ int ssl_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx) { if (ret->timeout < (long)(time(NULL) - ret->time)) { /* timeout */ - s->initial_ctx->stats.sess_timeout++; if (try_session_cache) { /* session was from the cache, so remove it */ SSL_CTX_remove_session(s->initial_ctx, ret); @@ -507,11 +494,7 @@ int ssl_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx) { goto err; } - s->initial_ctx->stats.sess_hit++; - - if (s->session != NULL) { - SSL_SESSION_free(s->session); - } + SSL_SESSION_free(s->session); s->session = ret; s->verify_result = s->session->verify_result; return 1; @@ -538,7 +521,7 @@ int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) { /* 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 */ - CRYPTO_add(&c->references, 1, CRYPTO_LOCK_SSL_SESSION); + SSL_SESSION_up_ref(c); /* if session c is in already in cache, we take back the increment later */ CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); @@ -579,7 +562,6 @@ int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) { if (!remove_session_lock(ctx, ctx->session_cache_tail, 0)) { break; } - ctx->stats.sess_cache_full++; } } } @@ -623,45 +605,32 @@ static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lock) { return ret; } -void SSL_SESSION_free(SSL_SESSION *ss) { - int i; - - if (ss == NULL) { - return; +SSL_SESSION *SSL_SESSION_up_ref(SSL_SESSION *session) { + if (session) { + CRYPTO_add(&session->references, 1, CRYPTO_LOCK_SSL_SESSION); } + return session; +} - i = CRYPTO_add(&ss->references, -1, CRYPTO_LOCK_SSL_SESSION); - if (i > 0) { +void SSL_SESSION_free(SSL_SESSION *session) { + if (session == NULL || + CRYPTO_add(&session->references, -1, CRYPTO_LOCK_SSL_SESSION) > 0) { return; } - CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data); + CRYPTO_free_ex_data(&g_ex_data_class, session, &session->ex_data); - OPENSSL_cleanse(ss->master_key, sizeof ss->master_key); - OPENSSL_cleanse(ss->session_id, sizeof ss->session_id); - if (ss->sess_cert != NULL) { - ssl_sess_cert_free(ss->sess_cert); - } - if (ss->peer != NULL) { - X509_free(ss->peer); - } - if (ss->tlsext_hostname != NULL) { - OPENSSL_free(ss->tlsext_hostname); - } - if (ss->tlsext_tick != NULL) { - OPENSSL_free(ss->tlsext_tick); - } - if (ss->tlsext_signed_cert_timestamp_list != NULL) { - OPENSSL_free(ss->tlsext_signed_cert_timestamp_list); - } - if (ss->ocsp_response != NULL) { - OPENSSL_free(ss->ocsp_response); - } - if (ss->psk_identity != NULL) { - OPENSSL_free(ss->psk_identity); - } - OPENSSL_cleanse(ss, sizeof(*ss)); - OPENSSL_free(ss); + 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) { @@ -669,12 +638,10 @@ int SSL_set_session(SSL *s, SSL_SESSION *session) { return 1; } - if (s->session != NULL) { - SSL_SESSION_free(s->session); - } + SSL_SESSION_free(s->session); s->session = session; if (session != NULL) { - CRYPTO_add(&session->references, 1, CRYPTO_LOCK_SSL_SESSION); + SSL_SESSION_up_ref(session); s->verify_result = session->verify_result; } @@ -753,7 +720,7 @@ long SSL_CTX_get_timeout(const SSL_CTX *s) { typedef struct timeout_param_st { SSL_CTX *ctx; long time; - LHASH_OF(SSL_SESSION) * cache; + LHASH_OF(SSL_SESSION) *cache; } TIMEOUT_PARAM; static void timeout_doall_arg(SSL_SESSION *sess, void *void_param) { @@ -896,18 +863,6 @@ int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx))(SSL *ssl, X509 **x509, return ctx->client_cert_cb; } -void SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, - int (*cb)(SSL *ssl, uint8_t *cookie, - size_t *cookie_len)) { - ctx->app_gen_cookie_cb = cb; -} - -void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, - int (*cb)(SSL *ssl, const uint8_t *cookie, - size_t cookie_len)) { - ctx->app_verify_cookie_cb = cb; -} - void SSL_CTX_set_channel_id_cb(SSL_CTX *ctx, void (*cb)(SSL *ssl, EVP_PKEY **pkey)) { ctx->channel_id_cb = cb; diff --git a/src/ssl/ssl_stat.c b/src/ssl/ssl_stat.c index 450ed7c..8bed9ad 100644 --- a/src/ssl/ssl_stat.c +++ b/src/ssl/ssl_stat.c @@ -83,7 +83,7 @@ */ #include -#include "ssl_locl.h" +#include "internal.h" const char *SSL_state_string_long(const SSL *s) { const char *str; @@ -382,14 +382,6 @@ const char *SSL_state_string_long(const SSL *s) { str = "DTLS1 read hello verify request B"; break; - case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A: - str = "DTLS1 write hello verify request A"; - break; - - case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B: - str = "DTLS1 write hello verify request B"; - break; - default: str = "unknown state"; break; @@ -691,14 +683,6 @@ const char *SSL_state_string(const SSL *s) { str = "DRCHVB"; break; - case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A: - str = "DWCHVA"; - break; - - case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B: - str = "DWCHVB"; - break; - default: str = "UNKWN "; break; diff --git a/src/ssl/ssl_test.c b/src/ssl/ssl_test.c deleted file mode 100644 index 70291a2..0000000 --- a/src/ssl/ssl_test.c +++ /dev/null @@ -1,456 +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 -#include - -#include -#include -#include -#include - -typedef struct { - int id; - int in_group_flag; -} EXPECTED_CIPHER; - -typedef struct { - /* The rule string to apply. */ - const char *rule; - /* The list of expected ciphers, in order, terminated with -1. */ - const EXPECTED_CIPHER *expected; -} CIPHER_TEST; - -/* Selecting individual ciphers should work. */ -static const char kRule1[] = - "ECDHE-ECDSA-CHACHA20-POLY1305:" - "ECDHE-RSA-CHACHA20-POLY1305:" - "ECDHE-ECDSA-AES128-GCM-SHA256:" - "ECDHE-RSA-AES128-GCM-SHA256"; - -static const EXPECTED_CIPHER kExpected1[] = { - { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, - { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, - { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, - { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, - { -1, -1 }, -}; - -/* + reorders selected ciphers to the end, keeping their relative - * order. */ -static const char kRule2[] = - "ECDHE-ECDSA-CHACHA20-POLY1305:" - "ECDHE-RSA-CHACHA20-POLY1305:" - "ECDHE-ECDSA-AES128-GCM-SHA256:" - "ECDHE-RSA-AES128-GCM-SHA256:" - "+aRSA"; - -static const EXPECTED_CIPHER kExpected2[] = { - { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, - { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, - { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, - { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, - { -1, -1 }, -}; - -/* ! banishes ciphers from future selections. */ -static const char kRule3[] = - "!aRSA:" - "ECDHE-ECDSA-CHACHA20-POLY1305:" - "ECDHE-RSA-CHACHA20-POLY1305:" - "ECDHE-ECDSA-AES128-GCM-SHA256:" - "ECDHE-RSA-AES128-GCM-SHA256"; - -static const EXPECTED_CIPHER kExpected3[] = { - { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, - { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, - { -1, -1 }, -}; - -/* Multiple masks can be ANDed in a single rule. */ -static const char kRule4[] = "kRSA+AESGCM+AES128"; - -static const EXPECTED_CIPHER kExpected4[] = { - { TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0 }, - { -1, -1 }, -}; - -/* - removes selected ciphers, but preserves their order for future - * selections. Select AES_128_GCM, but order the key exchanges RSA, - * DHE_RSA, ECDHE_RSA. */ -static const char kRule5[] = - "ALL:-kEECDH:-kEDH:-kRSA:-ALL:" - "AESGCM+AES128+aRSA"; - -static const EXPECTED_CIPHER kExpected5[] = { - { TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0 }, - { TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, - { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, - { -1, -1 }, -}; - -/* Unknown selectors are no-ops. */ -static const char kRule6[] = - "ECDHE-ECDSA-CHACHA20-POLY1305:" - "ECDHE-RSA-CHACHA20-POLY1305:" - "ECDHE-ECDSA-AES128-GCM-SHA256:" - "ECDHE-RSA-AES128-GCM-SHA256:" - "BOGUS1:-BOGUS2:+BOGUS3:!BOGUS4"; - -static const EXPECTED_CIPHER kExpected6[] = { - { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, - { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, - { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, - { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, - { -1, -1 }, -}; - -/* Square brackets specify equi-preference groups. */ -static const char kRule7[] = - "[ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES128-GCM-SHA256]:" - "[ECDHE-RSA-CHACHA20-POLY1305]:" - "ECDHE-RSA-AES128-GCM-SHA256"; - -static const EXPECTED_CIPHER kExpected7[] = { - { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 1 }, - { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, - { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, - { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, - { -1, -1 }, -}; - -/* @STRENGTH performs a stable strength-sort of the selected - * ciphers and only the selected ciphers. */ -static const char kRule8[] = - /* To simplify things, banish all but {ECDHE_RSA,RSA} x - * {CHACHA20,AES_256_CBC,AES_128_CBC,RC4} x SHA1. */ - "!kEDH:!AESGCM:!3DES:!SHA256:!MD5:!SHA384:" - /* Order some ciphers backwards by strength. */ - "ALL:-CHACHA20:-AES256:-AES128:-RC4:-ALL:" - /* Select ECDHE ones and sort them by strength. Ties should resolve - * based on the order above. */ - "kEECDH:@STRENGTH:-ALL:" - /* Now bring back everything uses RSA. ECDHE_RSA should be first, - * sorted by strength. Then RSA, backwards by strength. */ - "aRSA"; - -static const EXPECTED_CIPHER kExpected8[] = { - { TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA, 0 }, - { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, - { TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA, 0 }, - { TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA, 0 }, - { SSL3_CK_RSA_RC4_128_SHA, 0 }, - { TLS1_CK_RSA_WITH_AES_128_SHA, 0 }, - { TLS1_CK_RSA_WITH_AES_256_SHA, 0 }, - { -1, -1 }, -}; - -static CIPHER_TEST kCipherTests[] = { - { kRule1, kExpected1 }, - { kRule2, kExpected2 }, - { kRule3, kExpected3 }, - { kRule4, kExpected4 }, - { kRule5, kExpected5 }, - { kRule6, kExpected6 }, - { kRule7, kExpected7 }, - { kRule8, kExpected8 }, - { NULL, NULL }, -}; - -static const char *kBadRules[] = { - /* Invalid brackets. */ - "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256", - "RSA]", - "[[RSA]]", - /* Operators inside brackets */ - "[+RSA]", - /* Unknown directive. */ - "@BOGUS", - /* Empty cipher lists error at SSL_CTX_set_cipher_list. */ - "", - "BOGUS", - /* Invalid command. */ - "?BAR", - /* Special operators are not allowed if groups are used. */ - "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:+FOO", - "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:!FOO", - "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:-FOO", - "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:@STRENGTH", - NULL, -}; - -static void print_cipher_preference_list( - struct ssl_cipher_preference_list_st *list) { - size_t i; - int in_group = 0; - for (i = 0; i < sk_SSL_CIPHER_num(list->ciphers); i++) { - const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(list->ciphers, i); - if (!in_group && list->in_group_flags[i]) { - fprintf(stderr, "\t[\n"); - in_group = 1; - } - fprintf(stderr, "\t"); - if (in_group) { - fprintf(stderr, " "); - } - fprintf(stderr, "%s\n", SSL_CIPHER_get_name(cipher)); - if (in_group && !list->in_group_flags[i]) { - fprintf(stderr, "\t]\n"); - in_group = 0; - } - } -} - -static int test_cipher_rule(CIPHER_TEST *t) { - int ret = 0; - SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method()); - size_t i; - - if (!SSL_CTX_set_cipher_list(ctx, t->rule)) { - fprintf(stderr, "Error testing cipher rule '%s'\n", t->rule); - BIO_print_errors_fp(stderr); - goto done; - } - - /* Compare the two lists. */ - for (i = 0; i < sk_SSL_CIPHER_num(ctx->cipher_list->ciphers); i++) { - const SSL_CIPHER *cipher = - sk_SSL_CIPHER_value(ctx->cipher_list->ciphers, i); - if (t->expected[i].id != SSL_CIPHER_get_id(cipher) || - t->expected[i].in_group_flag != ctx->cipher_list->in_group_flags[i]) { - fprintf(stderr, "Error: cipher rule '%s' evaluted to:\n", t->rule); - print_cipher_preference_list(ctx->cipher_list); - goto done; - } - } - - if (t->expected[i].id != -1) { - fprintf(stderr, "Error: cipher rule '%s' evaluted to:\n", t->rule); - print_cipher_preference_list(ctx->cipher_list); - goto done; - } - - ret = 1; -done: - SSL_CTX_free(ctx); - return ret; -} - -static int test_cipher_rules(void) { - size_t i; - for (i = 0; kCipherTests[i].rule != NULL; i++) { - if (!test_cipher_rule(&kCipherTests[i])) { - return 0; - } - } - - for (i = 0; kBadRules[i] != NULL; i++) { - SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method()); - if (SSL_CTX_set_cipher_list(ctx, kBadRules[i])) { - fprintf(stderr, "Cipher rule '%s' unexpectedly succeeded\n", kBadRules[i]); - return 0; - } - ERR_clear_error(); - SSL_CTX_free(ctx); - } - - return 1; -} - -/* kOpenSSLSession is a serialized SSL_SESSION generated from openssl - * s_client -sess_out. */ -static const char kOpenSSLSession[] = - "MIIFpQIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ" - "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH" - "IWoJoQYCBFRDO46iBAICASyjggR6MIIEdjCCA16gAwIBAgIIK9dUvsPWSlUwDQYJ" - "KoZIhvcNAQEFBQAwSTELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMx" - "JTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3JpdHkgRzIwHhcNMTQxMDA4" - "MTIwNzU3WhcNMTUwMTA2MDAwMDAwWjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwK" - "Q2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzETMBEGA1UECgwKR29v" - "Z2xlIEluYzEXMBUGA1UEAwwOd3d3Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEB" - "AQUAA4IBDwAwggEKAoIBAQCcKeLrplAC+Lofy8t/wDwtB6eu72CVp0cJ4V3lknN6" - "huH9ct6FFk70oRIh/VBNBBz900jYy+7111Jm1b8iqOTQ9aT5C7SEhNcQFJvqzH3e" - "MPkb6ZSWGm1yGF7MCQTGQXF20Sk/O16FSjAynU/b3oJmOctcycWYkY0ytS/k3LBu" - "Id45PJaoMqjB0WypqvNeJHC3q5JjCB4RP7Nfx5jjHSrCMhw8lUMW4EaDxjaR9KDh" - "PLgjsk+LDIySRSRDaCQGhEOWLJZVLzLo4N6/UlctCHEllpBUSvEOyFga52qroGjg" - "rf3WOQ925MFwzd6AK+Ich0gDRg8sQfdLH5OuP1cfLfU1AgMBAAGjggFBMIIBPTAd" - "BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdv" - "b2dsZS5jb20waAYIKwYBBQUHAQEEXDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtp" - "Lmdvb2dsZS5jb20vR0lBRzIuY3J0MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50" - "czEuZ29vZ2xlLmNvbS9vY3NwMB0GA1UdDgQWBBQ7a+CcxsZByOpc+xpYFcIbnUMZ" - "hTAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEv" - "MBcGA1UdIAQQMA4wDAYKKwYBBAHWeQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRw" - "Oi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCa" - "OXCBdoqUy5bxyq+Wrh1zsyyCFim1PH5VU2+yvDSWrgDY8ibRGJmfff3r4Lud5kal" - "dKs9k8YlKD3ITG7P0YT/Rk8hLgfEuLcq5cc0xqmE42xJ+Eo2uzq9rYorc5emMCxf" - "5L0TJOXZqHQpOEcuptZQ4OjdYMfSxk5UzueUhA3ogZKRcRkdB3WeWRp+nYRhx4St" - "o2rt2A0MKmY9165GHUqMK9YaaXHDXqBu7Sefr1uSoAP9gyIJKeihMivsGqJ1TD6Z" - "cc6LMe+dN2P8cZEQHtD1y296ul4Mivqk3jatUVL8/hCwgch9A8O4PGZq9WqBfEWm" - "IyHh1dPtbg1lOXdYCWtjpAIEAKUDAgEUqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36S" - "YTcLEkXqKwOBfF9vE4KX0NxeLwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9B" - "sNHM362zZnY27GpTw+Kwd751CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yE" - "OTDKPNj3+inbMaVigtK4PLyPq+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdA" - "i4gv7Y5oliyn"; - -/* kCustomSession is a custom serialized SSL_SESSION generated by - * filling in missing fields from |kOpenSSLSession|. This includes - * providing |peer_sha256|, so |peer| is not serialized. */ -static const char kCustomSession[] = - "MIIBdgIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ" - "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH" - "IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tqAcE" - "BXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXqKwOBfF9vE4KX0Nxe" - "LwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362zZnY27GpTw+Kwd751" - "CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3+inbMaVigtK4PLyP" - "q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG" - "BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBLADBAEF"; - -static int decode_base64(uint8_t **out, size_t *out_len, const char *in) { - size_t len; - - if (!EVP_DecodedLength(&len, strlen(in))) { - fprintf(stderr, "EVP_DecodedLength failed\n"); - return 0; - } - - *out = OPENSSL_malloc(len); - if (*out == NULL) { - fprintf(stderr, "malloc failed\n"); - return 0; - } - - if (!EVP_DecodeBase64(*out, out_len, len, (const uint8_t *)in, - strlen(in))) { - fprintf(stderr, "EVP_DecodeBase64 failed\n"); - OPENSSL_free(*out); - *out = NULL; - return 0; - } - return 1; -} - -static int test_ssl_session_asn1(const char *input_b64) { - int ret = 0, len; - size_t input_len, encoded_len; - uint8_t *input = NULL, *encoded = NULL; - const uint8_t *cptr; - uint8_t *ptr; - SSL_SESSION *session = NULL; - - /* Decode the input. */ - if (!decode_base64(&input, &input_len, input_b64)) { - goto done; - } - - /* Verify the SSL_SESSION decodes. */ - cptr = input; - session = d2i_SSL_SESSION(NULL, &cptr, input_len); - if (session == NULL || cptr != input + input_len) { - fprintf(stderr, "d2i_SSL_SESSION failed\n"); - goto done; - } - - /* Verify the SSL_SESSION encoding round-trips. */ - if (!SSL_SESSION_to_bytes(session, &encoded, &encoded_len)) { - fprintf(stderr, "SSL_SESSION_to_bytes failed\n"); - goto done; - } - if (encoded_len != input_len || - memcmp(input, encoded, input_len) != 0) { - fprintf(stderr, "SSL_SESSION_to_bytes did not round-trip\n"); - goto done; - } - OPENSSL_free(encoded); - encoded = NULL; - - /* Verify the SSL_SESSION encoding round-trips via the legacy API. */ - len = i2d_SSL_SESSION(session, NULL); - if (len < 0 || (size_t)len != input_len) { - fprintf(stderr, "i2d_SSL_SESSION(NULL) returned invalid length\n"); - goto done; - } - - encoded = OPENSSL_malloc(input_len); - if (encoded == NULL) { - fprintf(stderr, "malloc failed\n"); - goto done; - } - ptr = encoded; - len = i2d_SSL_SESSION(session, &ptr); - if (len < 0 || (size_t)len != input_len) { - fprintf(stderr, "i2d_SSL_SESSION returned invalid length\n"); - goto done; - } - if (ptr != encoded + input_len) { - fprintf(stderr, "i2d_SSL_SESSION did not advance ptr correctly\n"); - goto done; - } - if (memcmp(input, encoded, input_len) != 0) { - fprintf(stderr, "i2d_SSL_SESSION did not round-trip\n"); - goto done; - } - - ret = 1; - - done: - if (!ret) { - BIO_print_errors_fp(stderr); - } - - if (session) { - SSL_SESSION_free(session); - } - if (input) { - OPENSSL_free(input); - } - if (encoded) { - OPENSSL_free(encoded); - } - return ret; -} - -int test_default_version(uint16_t version, const SSL_METHOD *(*method)(void)) { - SSL_CTX *ctx; - int ret; - - ctx = SSL_CTX_new(method()); - if (ctx == NULL) { - return 0; - } - - ret = ctx->min_version == version && ctx->max_version == version; - SSL_CTX_free(ctx); - return ret; -} - -int main(void) { - SSL_library_init(); - - if (!test_cipher_rules() || - !test_ssl_session_asn1(kOpenSSLSession) || - !test_ssl_session_asn1(kCustomSession) || - !test_default_version(0, &TLS_method) || - !test_default_version(SSL3_VERSION, &SSLv3_method) || - !test_default_version(TLS1_VERSION, &TLSv1_method) || - !test_default_version(TLS1_1_VERSION, &TLSv1_1_method) || - !test_default_version(TLS1_2_VERSION, &TLSv1_2_method) || - !test_default_version(0, &DTLS_method) || - !test_default_version(DTLS1_VERSION, &DTLSv1_method) || - !test_default_version(DTLS1_2_VERSION, &DTLSv1_2_method)) { - return 1; - } - - printf("PASS\n"); - return 0; -} diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc new file mode 100644 index 0000000..7886304 --- /dev/null +++ b/src/ssl/ssl_test.cc @@ -0,0 +1,509 @@ +/* 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 +#include + +#include +#include + +#include +#include +#include +#include + +#include "test/scoped_types.h" + +struct ExpectedCipher { + unsigned long id; + int in_group_flag; +}; + +struct CipherTest { + // The rule string to apply. + const char *rule; + // The list of expected ciphers, in order, terminated with -1. + const ExpectedCipher *expected; +}; + +// Selecting individual ciphers should work. +static const char kRule1[] = + "ECDHE-ECDSA-CHACHA20-POLY1305:" + "ECDHE-RSA-CHACHA20-POLY1305:" + "ECDHE-ECDSA-AES128-GCM-SHA256:" + "ECDHE-RSA-AES128-GCM-SHA256"; + +static const ExpectedCipher kExpected1[] = { + { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, + { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, + { 0, 0 }, +}; + +// + reorders selected ciphers to the end, keeping their relative +// order. +static const char kRule2[] = + "ECDHE-ECDSA-CHACHA20-POLY1305:" + "ECDHE-RSA-CHACHA20-POLY1305:" + "ECDHE-ECDSA-AES128-GCM-SHA256:" + "ECDHE-RSA-AES128-GCM-SHA256:" + "+aRSA"; + +static const ExpectedCipher kExpected2[] = { + { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, + { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, + { 0, 0 }, +}; + +// ! banishes ciphers from future selections. +static const char kRule3[] = + "!aRSA:" + "ECDHE-ECDSA-CHACHA20-POLY1305:" + "ECDHE-RSA-CHACHA20-POLY1305:" + "ECDHE-ECDSA-AES128-GCM-SHA256:" + "ECDHE-RSA-AES128-GCM-SHA256"; + +static const ExpectedCipher kExpected3[] = { + { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, + { 0, 0 }, +}; + +// Multiple masks can be ANDed in a single rule. +static const char kRule4[] = "kRSA+AESGCM+AES128"; + +static const ExpectedCipher kExpected4[] = { + { TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0 }, + { 0, 0 }, +}; + +// - removes selected ciphers, but preserves their order for future +// selections. Select AES_128_GCM, but order the key exchanges RSA, +// DHE_RSA, ECDHE_RSA. +static const char kRule5[] = + "ALL:-kECDHE:-kDHE:-kRSA:-ALL:" + "AESGCM+AES128+aRSA"; + +static const ExpectedCipher kExpected5[] = { + { TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0 }, + { TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, + { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, + { 0, 0 }, +}; + +// Unknown selectors are no-ops. +static const char kRule6[] = + "ECDHE-ECDSA-CHACHA20-POLY1305:" + "ECDHE-RSA-CHACHA20-POLY1305:" + "ECDHE-ECDSA-AES128-GCM-SHA256:" + "ECDHE-RSA-AES128-GCM-SHA256:" + "BOGUS1:-BOGUS2:+BOGUS3:!BOGUS4"; + +static const ExpectedCipher kExpected6[] = { + { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, + { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, + { 0, 0 }, +}; + +// Square brackets specify equi-preference groups. +static const char kRule7[] = + "[ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES128-GCM-SHA256]:" + "[ECDHE-RSA-CHACHA20-POLY1305]:" + "ECDHE-RSA-AES128-GCM-SHA256"; + +static const ExpectedCipher kExpected7[] = { + { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 1 }, + { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, + { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, + { 0, 0 }, +}; + +// @STRENGTH performs a stable strength-sort of the selected +// ciphers and only the selected ciphers. +static const char kRule8[] = + // To simplify things, banish all but {ECDHE_RSA,RSA} x + // {CHACHA20,AES_256_CBC,AES_128_CBC,RC4} x SHA1. + "!kEDH:!AESGCM:!3DES:!SHA256:!MD5:!SHA384:" + // Order some ciphers backwards by strength. + "ALL:-CHACHA20:-AES256:-AES128:-RC4:-ALL:" + // Select ECDHE ones and sort them by strength. Ties should resolve + // based on the order above. + "kECDHE:@STRENGTH:-ALL:" + // Now bring back everything uses RSA. ECDHE_RSA should be first, + // sorted by strength. Then RSA, backwards by strength. + "aRSA"; + +static const ExpectedCipher kExpected8[] = { + { TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA, 0 }, + { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA, 0 }, + { TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA, 0 }, + { SSL3_CK_RSA_RC4_128_SHA, 0 }, + { TLS1_CK_RSA_WITH_AES_128_SHA, 0 }, + { TLS1_CK_RSA_WITH_AES_256_SHA, 0 }, + { 0, 0 }, +}; + +// Exact ciphers may not be used in multi-part rules; they are treated +// as unknown aliases. +static const char kRule9[] = + "ECDHE-ECDSA-CHACHA20-POLY1305:" + "ECDHE-RSA-CHACHA20-POLY1305:" + "!ECDHE-RSA-CHACHA20-POLY1305+RSA:" + "!ECDSA+ECDHE-ECDSA-CHACHA20-POLY1305"; + +static const ExpectedCipher kExpected9[] = { + { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, + { 0, 0 }, +}; + +static CipherTest kCipherTests[] = { + { kRule1, kExpected1 }, + { kRule2, kExpected2 }, + { kRule3, kExpected3 }, + { kRule4, kExpected4 }, + { kRule5, kExpected5 }, + { kRule6, kExpected6 }, + { kRule7, kExpected7 }, + { kRule8, kExpected8 }, + { kRule9, kExpected9 }, + { NULL, NULL }, +}; + +static const char *kBadRules[] = { + // Invalid brackets. + "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256", + "RSA]", + "[[RSA]]", + // Operators inside brackets. + "[+RSA]", + // Unknown directive. + "@BOGUS", + // Empty cipher lists error at SSL_CTX_set_cipher_list. + "", + "BOGUS", + // COMPLEMENTOFDEFAULT is empty. + "COMPLEMENTOFDEFAULT", + // Invalid command. + "?BAR", + // Special operators are not allowed if groups are used. + "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:+FOO", + "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:!FOO", + "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:-FOO", + "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:@STRENGTH", + 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++) { + const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(list->ciphers, i); + if (!in_group && list->in_group_flags[i]) { + fprintf(stderr, "\t[\n"); + in_group = true; + } + fprintf(stderr, "\t"); + if (in_group) { + fprintf(stderr, " "); + } + fprintf(stderr, "%s\n", SSL_CIPHER_get_name(cipher)); + if (in_group && !list->in_group_flags[i]) { + fprintf(stderr, "\t]\n"); + in_group = false; + } + } +} + +static bool TestCipherRule(CipherTest *t) { + ScopedSSL_CTX ctx(SSL_CTX_new(TLS_method())); + if (!ctx) { + return false; + } + + if (!SSL_CTX_set_cipher_list(ctx.get(), t->rule)) { + fprintf(stderr, "Error testing cipher rule '%s'\n", t->rule); + return false; + } + + // Compare the two lists. + size_t i; + for (i = 0; i < sk_SSL_CIPHER_num(ctx->cipher_list->ciphers); i++) { + const SSL_CIPHER *cipher = + sk_SSL_CIPHER_value(ctx->cipher_list->ciphers, i); + if (t->expected[i].id != SSL_CIPHER_get_id(cipher) || + t->expected[i].in_group_flag != ctx->cipher_list->in_group_flags[i]) { + fprintf(stderr, "Error: cipher rule '%s' evaluated to:\n", t->rule); + PrintCipherPreferenceList(ctx->cipher_list); + return false; + } + } + + if (t->expected[i].id != 0) { + fprintf(stderr, "Error: cipher rule '%s' evaluated to:\n", t->rule); + PrintCipherPreferenceList(ctx->cipher_list); + return false; + } + + return true; +} + +static bool TestCipherRules() { + for (size_t i = 0; kCipherTests[i].rule != NULL; i++) { + if (!TestCipherRule(&kCipherTests[i])) { + return false; + } + } + + for (size_t i = 0; kBadRules[i] != NULL; i++) { + ScopedSSL_CTX ctx(SSL_CTX_new(SSLv23_server_method())); + if (!ctx) { + return false; + } + if (SSL_CTX_set_cipher_list(ctx.get(), kBadRules[i])) { + fprintf(stderr, "Cipher rule '%s' unexpectedly succeeded\n", kBadRules[i]); + return false; + } + ERR_clear_error(); + } + + return true; +} + +// kOpenSSLSession is a serialized SSL_SESSION generated from openssl +// s_client -sess_out. +static const char kOpenSSLSession[] = + "MIIFpQIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ" + "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH" + "IWoJoQYCBFRDO46iBAICASyjggR6MIIEdjCCA16gAwIBAgIIK9dUvsPWSlUwDQYJ" + "KoZIhvcNAQEFBQAwSTELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMx" + "JTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3JpdHkgRzIwHhcNMTQxMDA4" + "MTIwNzU3WhcNMTUwMTA2MDAwMDAwWjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwK" + "Q2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzETMBEGA1UECgwKR29v" + "Z2xlIEluYzEXMBUGA1UEAwwOd3d3Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEB" + "AQUAA4IBDwAwggEKAoIBAQCcKeLrplAC+Lofy8t/wDwtB6eu72CVp0cJ4V3lknN6" + "huH9ct6FFk70oRIh/VBNBBz900jYy+7111Jm1b8iqOTQ9aT5C7SEhNcQFJvqzH3e" + "MPkb6ZSWGm1yGF7MCQTGQXF20Sk/O16FSjAynU/b3oJmOctcycWYkY0ytS/k3LBu" + "Id45PJaoMqjB0WypqvNeJHC3q5JjCB4RP7Nfx5jjHSrCMhw8lUMW4EaDxjaR9KDh" + "PLgjsk+LDIySRSRDaCQGhEOWLJZVLzLo4N6/UlctCHEllpBUSvEOyFga52qroGjg" + "rf3WOQ925MFwzd6AK+Ich0gDRg8sQfdLH5OuP1cfLfU1AgMBAAGjggFBMIIBPTAd" + "BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdv" + "b2dsZS5jb20waAYIKwYBBQUHAQEEXDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtp" + "Lmdvb2dsZS5jb20vR0lBRzIuY3J0MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50" + "czEuZ29vZ2xlLmNvbS9vY3NwMB0GA1UdDgQWBBQ7a+CcxsZByOpc+xpYFcIbnUMZ" + "hTAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEv" + "MBcGA1UdIAQQMA4wDAYKKwYBBAHWeQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRw" + "Oi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCa" + "OXCBdoqUy5bxyq+Wrh1zsyyCFim1PH5VU2+yvDSWrgDY8ibRGJmfff3r4Lud5kal" + "dKs9k8YlKD3ITG7P0YT/Rk8hLgfEuLcq5cc0xqmE42xJ+Eo2uzq9rYorc5emMCxf" + "5L0TJOXZqHQpOEcuptZQ4OjdYMfSxk5UzueUhA3ogZKRcRkdB3WeWRp+nYRhx4St" + "o2rt2A0MKmY9165GHUqMK9YaaXHDXqBu7Sefr1uSoAP9gyIJKeihMivsGqJ1TD6Z" + "cc6LMe+dN2P8cZEQHtD1y296ul4Mivqk3jatUVL8/hCwgch9A8O4PGZq9WqBfEWm" + "IyHh1dPtbg1lOXdYCWtjpAIEAKUDAgEUqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36S" + "YTcLEkXqKwOBfF9vE4KX0NxeLwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9B" + "sNHM362zZnY27GpTw+Kwd751CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yE" + "OTDKPNj3+inbMaVigtK4PLyPq+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdA" + "i4gv7Y5oliyn"; + +// kCustomSession is a custom serialized SSL_SESSION generated by +// filling in missing fields from |kOpenSSLSession|. This includes +// providing |peer_sha256|, so |peer| is not serialized. +static const char kCustomSession[] = + "MIIBdgIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ" + "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH" + "IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tqAcE" + "BXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXqKwOBfF9vE4KX0Nxe" + "LwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362zZnY27GpTw+Kwd751" + "CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3+inbMaVigtK4PLyP" + "q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG" + "BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBLADBAEF"; + +static bool DecodeBase64(std::vector *out, const char *in) { + size_t len; + if (!EVP_DecodedLength(&len, strlen(in))) { + fprintf(stderr, "EVP_DecodedLength failed\n"); + return false; + } + + out->resize(len); + if (!EVP_DecodeBase64(bssl::vector_data(out), &len, len, (const uint8_t *)in, + strlen(in))) { + fprintf(stderr, "EVP_DecodeBase64 failed\n"); + return false; + } + out->resize(len); + return true; +} + +static bool TestSSL_SESSIONEncoding(const char *input_b64) { + const uint8_t *cptr; + uint8_t *ptr; + + // Decode the input. + std::vector input; + if (!DecodeBase64(&input, input_b64)) { + return false; + } + + // Verify the SSL_SESSION decodes. + cptr = bssl::vector_data(&input); + ScopedSSL_SESSION session(d2i_SSL_SESSION(NULL, &cptr, input.size())); + if (!session || cptr != bssl::vector_data(&input) + input.size()) { + fprintf(stderr, "d2i_SSL_SESSION failed\n"); + return false; + } + + // Verify the SSL_SESSION encoding round-trips. + size_t encoded_len; + ScopedOpenSSLBytes encoded; + uint8_t *encoded_raw; + if (!SSL_SESSION_to_bytes(session.get(), &encoded_raw, &encoded_len)) { + fprintf(stderr, "SSL_SESSION_to_bytes failed\n"); + return false; + } + encoded.reset(encoded_raw); + 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"); + return false; + } + + // Verify the SSL_SESSION encoding round-trips via the legacy API. + int len = i2d_SSL_SESSION(session.get(), NULL); + if (len < 0 || (size_t)len != input.size()) { + fprintf(stderr, "i2d_SSL_SESSION(NULL) returned invalid length\n"); + return false; + } + + encoded.reset((uint8_t *)OPENSSL_malloc(input.size())); + if (!encoded) { + fprintf(stderr, "malloc failed\n"); + return false; + } + + ptr = encoded.get(); + len = i2d_SSL_SESSION(session.get(), &ptr); + if (len < 0 || (size_t)len != input.size()) { + fprintf(stderr, "i2d_SSL_SESSION returned invalid length\n"); + return false; + } + if (ptr != encoded.get() + input.size()) { + fprintf(stderr, "i2d_SSL_SESSION did not advance ptr correctly\n"); + return false; + } + if (memcmp(bssl::vector_data(&input), encoded.get(), input.size()) != 0) { + fprintf(stderr, "i2d_SSL_SESSION did not round-trip\n"); + return false; + } + + return true; +} + +static bool TestDefaultVersion(uint16_t version, + const SSL_METHOD *(*method)(void)) { + ScopedSSL_CTX ctx(SSL_CTX_new(method())); + if (!ctx) { + return false; + } + return ctx->min_version == version && ctx->max_version == version; +} + +static bool CipherGetRFCName(std::string *out, uint16_t value) { + const SSL_CIPHER *cipher = SSL_get_cipher_by_value(value); + if (cipher == NULL) { + return false; + } + ScopedOpenSSLString rfc_name(SSL_CIPHER_get_rfc_name(cipher)); + out->assign(rfc_name.get()); + return true; +} + +typedef struct { + int id; + const char *rfc_name; +} CIPHER_RFC_NAME_TEST; + +static const CIPHER_RFC_NAME_TEST kCipherRFCNameTests[] = { + { SSL3_CK_RSA_DES_192_CBC3_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA" }, + { SSL3_CK_RSA_RC4_128_MD5, "TLS_RSA_WITH_RC4_MD5" }, + { TLS1_CK_RSA_WITH_AES_128_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA" }, + { TLS1_CK_DHE_RSA_WITH_AES_256_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA" }, + { TLS1_CK_DHE_RSA_WITH_AES_256_SHA256, + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256" }, + { TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256, + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" }, + { TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384, + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384" }, + { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" }, + { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" }, + { TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" }, + { TLS1_CK_PSK_WITH_RC4_128_SHA, "TLS_PSK_WITH_RC4_SHA" }, + // These names are non-standard: + { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" }, + { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" }, + { TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256, + "TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256" }, +}; + +static bool TestCipherGetRFCName(void) { + for (size_t i = 0; + i < sizeof(kCipherRFCNameTests) / sizeof(kCipherRFCNameTests[0]); i++) { + const CIPHER_RFC_NAME_TEST *test = &kCipherRFCNameTests[i]; + std::string rfc_name; + if (!CipherGetRFCName(&rfc_name, test->id & 0xffff)) { + fprintf(stderr, "SSL_CIPHER_get_rfc_name failed\n"); + return false; + } + if (rfc_name != test->rfc_name) { + fprintf(stderr, "SSL_CIPHER_get_rfc_name: got '%s', wanted '%s'\n", + rfc_name.c_str(), test->rfc_name); + return false; + } + } + return true; +} + +int main(void) { + SSL_library_init(); + + if (!TestCipherRules() || + !TestSSL_SESSIONEncoding(kOpenSSLSession) || + !TestSSL_SESSIONEncoding(kCustomSession) || + !TestDefaultVersion(0, &TLS_method) || + !TestDefaultVersion(SSL3_VERSION, &SSLv3_method) || + !TestDefaultVersion(TLS1_VERSION, &TLSv1_method) || + !TestDefaultVersion(TLS1_1_VERSION, &TLSv1_1_method) || + !TestDefaultVersion(TLS1_2_VERSION, &TLSv1_2_method) || + !TestDefaultVersion(0, &DTLS_method) || + !TestDefaultVersion(DTLS1_VERSION, &DTLSv1_method) || + !TestDefaultVersion(DTLS1_2_VERSION, &DTLSv1_2_method) || + !TestCipherGetRFCName()) { + ERR_print_errors_fp(stderr); + return 1; + } + + printf("PASS\n"); + return 0; +} diff --git a/src/ssl/ssl_txt.c b/src/ssl/ssl_txt.c index c950ce8..2275f16 100644 --- a/src/ssl/ssl_txt.c +++ b/src/ssl/ssl_txt.c @@ -87,7 +87,7 @@ #include #include -#include "ssl_locl.h" +#include "internal.h" int SSL_SESSION_print_fp(FILE *fp, const SSL_SESSION *x) { @@ -145,8 +145,9 @@ int SSL_SESSION_print(BIO *bp, const SSL_SESSION *x) { } for (i = 0; i < x->session_id_length; i++) { - if (BIO_printf(bp, "%02X", x->session_id[i]) <= 0) + if (BIO_printf(bp, "%02X", x->session_id[i]) <= 0) { goto err; + } } if (BIO_puts(bp, "\n Session-ID-ctx: ") <= 0) { diff --git a/src/ssl/t1_enc.c b/src/ssl/t1_enc.c index 014bc88..3eaffe7 100644 --- a/src/ssl/t1_enc.c +++ b/src/ssl/t1_enc.c @@ -133,8 +133,9 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. */ -#include #include +#include +#include #include #include @@ -144,7 +145,7 @@ #include #include -#include "ssl_locl.h" +#include "internal.h" /* tls1_P_hash computes the TLS P_ function as described in RFC 5246, @@ -225,7 +226,7 @@ int tls1_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret, const uint8_t *seed2, size_t seed2_len) { size_t idx, len, count, i; const uint8_t *S1; - long m; + uint32_t m; const EVP_MD *md; int ret = 0; uint8_t *tmp; @@ -243,7 +244,7 @@ int tls1_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret, /* Count number of digests and partition |secret| evenly. */ count = 0; - for (idx = 0; ssl_get_handshake_digest(idx, &m, &md); idx++) { + for (idx = 0; ssl_get_handshake_digest(&m, &md, idx); idx++) { if ((m << TLS1_PRF_DGST_SHIFT) & ssl_get_algorithm2(s)) { count++; } @@ -258,7 +259,7 @@ int tls1_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret, } S1 = secret; memset(out, 0, out_len); - for (idx = 0; ssl_get_handshake_digest(idx, &m, &md); idx++) { + for (idx = 0; ssl_get_handshake_digest(&m, &md, idx); idx++) { if ((m << TLS1_PRF_DGST_SHIFT) & ssl_get_algorithm2(s)) { /* If |count| is 2 and |secret_len| is odd, |secret| is partitioned into * two halves with an overlapping byte. */ @@ -340,14 +341,12 @@ static int tls1_change_cipher_state_aead(SSL *s, char is_read, } aead_ctx = s->aead_read_ctx; } else { - /* When updating the cipher state for DTLS, we do not wish to overwrite the - * old ones because DTLS stores pointers to them in order to implement - * retransmission. See dtls1_hm_fragment_free. - * - * TODO(davidben): Simplify aead_write_ctx ownership, probably by just - * forbidding DTLS renego. */ - if (SSL_IS_DTLS(s)) { - s->aead_write_ctx = NULL; + if (SSL_IS_DTLS(s) && s->aead_write_ctx != NULL) { + /* DTLS renegotiation is unsupported, so a CCS can only switch away from + * the NULL cipher. This simplifies renegotiation. */ + OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state_aead, + ERR_R_INTERNAL_ERROR); + return 0; } if (!tls1_aead_ctx_init(&s->aead_write_ctx)) { return 0; @@ -355,8 +354,9 @@ static int tls1_change_cipher_state_aead(SSL *s, char is_read, aead_ctx = s->aead_write_ctx; } - if (!EVP_AEAD_CTX_init(&aead_ctx->ctx, aead, key, key_len, - EVP_AEAD_DEFAULT_TAG_LENGTH, NULL /* engine */)) { + if (!EVP_AEAD_CTX_init_with_direction( + &aead_ctx->ctx, aead, key, key_len, EVP_AEAD_DEFAULT_TAG_LENGTH, + is_read ? evp_aead_open : evp_aead_seal)) { OPENSSL_free(aead_ctx); if (is_read) { s->aead_read_ctx = NULL; @@ -578,7 +578,7 @@ int tls1_enc(SSL *s, int send) { aead = s->aead_read_ctx; } - if (s->session == NULL || aead == NULL) { + if (aead == NULL) { /* Handle the initial NULL cipher. */ memmove(rec->data, rec->input, rec->length); rec->input = rec->data; @@ -598,13 +598,9 @@ int tls1_enc(SSL *s, int send) { memcpy(p, &seq[2], 6); memcpy(ad, dtlsseq, 8); } else { - int i; memcpy(ad, seq, 8); - for (i = 7; i >= 0; i--) { - ++seq[i]; - if (seq[i] != 0) { - break; - } + if (!ssl3_record_sequence_update(seq, 8)) { + return 0; } } @@ -739,7 +735,10 @@ int tls1_cert_verify_mac(SSL *s, int md_nid, uint8_t *out) { } EVP_MD_CTX_init(&ctx); - EVP_MD_CTX_copy_ex(&ctx, d); + if (!EVP_MD_CTX_copy_ex(&ctx, d)) { + EVP_MD_CTX_cleanup(&ctx); + return 0; + } EVP_DigestFinal_ex(&ctx, out, &ret); EVP_MD_CTX_cleanup(&ctx); @@ -756,11 +755,11 @@ int tls1_handshake_digest(SSL *s, uint8_t *out, size_t out_len) { EVP_MD_CTX ctx; int err = 0, len = 0; size_t i; - long mask; + uint32_t mask; EVP_MD_CTX_init(&ctx); - for (i = 0; ssl_get_handshake_digest(i, &mask, &md); i++) { + 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]; @@ -863,82 +862,42 @@ int tls1_generate_master_secret(SSL *s, uint8_t *out, const uint8_t *premaster, return SSL3_MASTER_SECRET_SIZE; } -int tls1_export_keying_material(SSL *s, uint8_t *out, size_t olen, - const char *label, size_t llen, - const uint8_t *context, size_t contextlen, +int tls1_export_keying_material(SSL *s, uint8_t *out, size_t out_len, + const char *label, size_t label_len, + const uint8_t *context, size_t context_len, int use_context) { - uint8_t *val = NULL; - size_t vallen, currentvalpos; - int ret; - - /* construct PRF arguments we construct the PRF argument ourself rather than - * passing separate values into the TLS PRF to ensure that the concatenation - * of values does not create a prohibited label. */ - vallen = llen + SSL3_RANDOM_SIZE * 2; - if (use_context) { - vallen += 2 + contextlen; - } - - val = OPENSSL_malloc(vallen); - if (val == NULL) { - goto err2; + if (!s->s3->have_version || s->version == SSL3_VERSION) { + OPENSSL_PUT_ERROR(SSL, tls1_export_keying_material, + ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; } - currentvalpos = 0; - memcpy(val + currentvalpos, (uint8_t *)label, llen); - currentvalpos += llen; - memcpy(val + currentvalpos, s->s3->client_random, SSL3_RANDOM_SIZE); - currentvalpos += SSL3_RANDOM_SIZE; - memcpy(val + currentvalpos, s->s3->server_random, SSL3_RANDOM_SIZE); - currentvalpos += SSL3_RANDOM_SIZE; - + size_t seed_len = 2 * SSL3_RANDOM_SIZE; if (use_context) { - val[currentvalpos] = (contextlen >> 8) & 0xff; - currentvalpos++; - val[currentvalpos] = contextlen & 0xff; - currentvalpos++; - if (contextlen > 0 || context != NULL) { - memcpy(val + currentvalpos, context, contextlen); + if (context_len >= 1u << 16) { + OPENSSL_PUT_ERROR(SSL, tls1_export_keying_material, ERR_R_OVERFLOW); + return 0; } + seed_len += 2 + context_len; } - - /* disallow prohibited labels note that SSL3_RANDOM_SIZE > max(prohibited - * label len) = 15, so size of val > max(prohibited label len) = 15 and the - * comparisons won't have buffer overflow. */ - if (memcmp(val, TLS_MD_CLIENT_FINISH_CONST, - TLS_MD_CLIENT_FINISH_CONST_SIZE) == 0 || - memcmp(val, TLS_MD_SERVER_FINISH_CONST, - TLS_MD_SERVER_FINISH_CONST_SIZE) == 0 || - memcmp(val, TLS_MD_MASTER_SECRET_CONST, - TLS_MD_MASTER_SECRET_CONST_SIZE) == 0 || - memcmp(val, TLS_MD_KEY_EXPANSION_CONST, - TLS_MD_KEY_EXPANSION_CONST_SIZE) == 0) { - goto err1; + uint8_t *seed = OPENSSL_malloc(seed_len); + if (seed == NULL) { + OPENSSL_PUT_ERROR(SSL, tls1_export_keying_material, ERR_R_MALLOC_FAILURE); + return 0; } - /* SSL_export_keying_material is not implemented for SSLv3, so passing - * everything through the label parameter works. */ - assert(s->version != SSL3_VERSION); - ret = s->enc_method->prf(s, out, olen, s->session->master_key, - s->session->master_key_length, (const char *)val, - vallen, NULL, 0, NULL, 0); - goto out; - -err1: - OPENSSL_PUT_ERROR(SSL, tls1_export_keying_material, - SSL_R_TLS_ILLEGAL_EXPORTER_LABEL); - ret = 0; - goto out; - -err2: - OPENSSL_PUT_ERROR(SSL, tls1_export_keying_material, ERR_R_MALLOC_FAILURE); - ret = 0; - -out: - if (val != NULL) { - OPENSSL_free(val); + memcpy(seed, s->s3->client_random, SSL3_RANDOM_SIZE); + memcpy(seed + SSL3_RANDOM_SIZE, s->s3->server_random, SSL3_RANDOM_SIZE); + if (use_context) { + seed[2 * SSL3_RANDOM_SIZE] = (uint8_t)(context_len >> 8); + seed[2 * SSL3_RANDOM_SIZE + 1] = (uint8_t)context_len; + memcpy(seed + 2 * SSL3_RANDOM_SIZE + 2, context, context_len); } + int ret = s->enc_method->prf(s, out, out_len, s->session->master_key, + s->session->master_key_length, label, label_len, + seed, seed_len, NULL, 0); + OPENSSL_free(seed); return ret; } diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c index e26351b..433a647 100644 --- a/src/ssl/t1_lib.c +++ b/src/ssl/t1_lib.c @@ -106,18 +106,20 @@ * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). */ +#include #include #include -#include +#include #include +#include #include #include #include #include #include -#include "ssl_locl.h" +#include "internal.h" static int tls_decrypt_ticket(SSL *s, const uint8_t *tick, int ticklen, @@ -133,16 +135,12 @@ const SSL3_ENC_METHOD TLSv1_enc_data = { tls1_generate_master_secret, tls1_change_cipher_state, tls1_final_finish_mac, - TLS1_FINISH_MAC_LENGTH, tls1_cert_verify_mac, TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE, TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE, tls1_alert_code, tls1_export_keying_material, 0, - SSL3_HM_HEADER_LENGTH, - ssl3_set_handshake_header, - ssl3_handshake_write, }; const SSL3_ENC_METHOD TLSv1_1_enc_data = { @@ -152,16 +150,12 @@ const SSL3_ENC_METHOD TLSv1_1_enc_data = { tls1_generate_master_secret, tls1_change_cipher_state, tls1_final_finish_mac, - TLS1_FINISH_MAC_LENGTH, tls1_cert_verify_mac, TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE, TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE, tls1_alert_code, tls1_export_keying_material, SSL_ENC_FLAG_EXPLICIT_IV, - SSL3_HM_HEADER_LENGTH, - ssl3_set_handshake_header, - ssl3_handshake_write, }; const SSL3_ENC_METHOD TLSv1_2_enc_data = { @@ -171,7 +165,6 @@ const SSL3_ENC_METHOD TLSv1_2_enc_data = { tls1_generate_master_secret, tls1_change_cipher_state, tls1_final_finish_mac, - TLS1_FINISH_MAC_LENGTH, tls1_cert_verify_mac, TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE, TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE, @@ -179,9 +172,6 @@ const SSL3_ENC_METHOD TLSv1_2_enc_data = { tls1_export_keying_material, SSL_ENC_FLAG_EXPLICIT_IV|SSL_ENC_FLAG_SIGALGS|SSL_ENC_FLAG_SHA256_PRF |SSL_ENC_FLAG_TLS1_2_CIPHERS, - SSL3_HM_HEADER_LENGTH, - ssl3_set_handshake_header, - ssl3_handshake_write, }; static int compare_uint16_t(const void *p1, const void *p2) { @@ -255,8 +245,7 @@ static int tls1_check_duplicate_extensions(const CBS *cbs) { ret = 1; done: - if (extension_types) - OPENSSL_free(extension_types); + OPENSSL_free(extension_types); return ret; } @@ -367,7 +356,7 @@ static const uint8_t ecformats_default[] = { }; static const uint16_t eccurves_default[] = { - 23, /* X9_64_prime256v1 */ + 23, /* X9_62_prime256v1 */ 24, /* secp384r1 */ }; @@ -399,6 +388,9 @@ static void tls1_get_curvelist(SSL *s, int get_peer_curves, const uint16_t **out_curve_ids, size_t *out_curve_ids_len) { if (get_peer_curves) { + /* Only clients send a curve list, so this function is only called + * on the server. */ + assert(s->server); *out_curve_ids = s->s3->tmp.peer_ellipticcurvelist; *out_curve_ids_len = s->s3->tmp.peer_ellipticcurvelist_length; return; @@ -437,22 +429,38 @@ int tls1_check_curve(SSL *s, CBS *cbs, uint16_t *out_curve_id) { } int tls1_get_shared_curve(SSL *s) { - const uint16_t *pref, *supp; - size_t preflen, supplen, i, j; + const uint16_t *curves, *peer_curves, *pref, *supp; + size_t curves_len, peer_curves_len, pref_len, supp_len, i, j; /* Can't do anything on client side */ if (s->server == 0) { return NID_undef; } - /* Return first preference shared curve */ - tls1_get_curvelist(s, !!(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE), &supp, - &supplen); - tls1_get_curvelist(s, !(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE), &pref, - &preflen); + tls1_get_curvelist(s, 0 /* local curves */, &curves, &curves_len); + tls1_get_curvelist(s, 1 /* peer curves */, &peer_curves, &peer_curves_len); + + if (peer_curves_len == 0) { + /* Clients are not required to send a supported_curves extension. In this + * case, the server is free to pick any curve it likes. See RFC 4492, + * section 4, paragraph 3. */ + return (curves_len == 0) ? NID_undef : tls1_ec_curve_id2nid(curves[0]); + } + + if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { + pref = curves; + pref_len = curves_len; + supp = peer_curves; + supp_len = peer_curves_len; + } else { + pref = peer_curves; + pref_len = peer_curves_len; + supp = curves; + supp_len = curves_len; + } - for (i = 0; i < preflen; i++) { - for (j = 0; j < supplen; j++) { + for (i = 0; i < pref_len; i++) { + for (j = 0; j < supp_len; j++) { if (pref[i] == supp[j]) { return tls1_ec_curve_id2nid(pref[i]); } @@ -479,9 +487,7 @@ int tls1_set_curves(uint16_t **out_curve_ids, size_t *out_curve_ids_len, } } - if (*out_curve_ids) { - OPENSSL_free(*out_curve_ids); - } + OPENSSL_free(*out_curve_ids); *out_curve_ids = curve_ids; *out_curve_ids_len = ncurves; @@ -556,11 +562,23 @@ static int tls1_check_point_format(SSL *s, uint8_t comp_id) { * preferences are checked; the peer (the server) does not send preferences. */ static int tls1_check_curve_id(SSL *s, uint16_t curve_id) { const uint16_t *curves; - size_t curves_len, i, j; + size_t curves_len, i, get_peer_curves; /* Check against our list, then the peer's list. */ - for (j = 0; j <= 1; j++) { - tls1_get_curvelist(s, j, &curves, &curves_len); + for (get_peer_curves = 0; get_peer_curves <= 1; get_peer_curves++) { + if (get_peer_curves && !s->server) { + /* Servers do not present a preference list so, if we are a client, only + * check our list. */ + continue; + } + + tls1_get_curvelist(s, get_peer_curves, &curves, &curves_len); + if (get_peer_curves && curves_len == 0) { + /* Clients are not required to send a supported_curves extension. In this + * case, the server is free to pick any curve it likes. See RFC 4492, + * section 4, paragraph 3. */ + continue; + } for (i = 0; i < curves_len; i++) { if (curves[i] == curve_id) { break; @@ -570,12 +588,6 @@ static int tls1_check_curve_id(SSL *s, uint16_t curve_id) { if (i == curves_len) { return 0; } - - /* Servers do not present a preference list so, if we are a client, only - * check our list. */ - if (!s->server) { - return 1; - } } return 1; @@ -610,30 +622,27 @@ int tls1_check_ec_cert(SSL *s, X509 *x) { ret = 1; done: - if (pkey) { - EVP_PKEY_free(pkey); - } + EVP_PKEY_free(pkey); return ret; } int tls1_check_ec_tmp_key(SSL *s) { - uint16_t curve_id; - EC_KEY *ec = s->cert->ecdh_tmp; - - if (s->cert->ecdh_tmp_auto) { - /* Need a shared curve */ - return tls1_get_shared_curve(s) != NID_undef; + if (s->cert->ecdh_nid != NID_undef) { + /* If the curve is preconfigured, ECDH is acceptable iff the peer supports + * the curve. */ + uint16_t curve_id; + return tls1_ec_nid2curve_id(&curve_id, s->cert->ecdh_nid) && + tls1_check_curve_id(s, curve_id); } - if (!ec) { - if (s->cert->ecdh_tmp_cb) { - return 1; - } - return 0; + if (s->cert->ecdh_tmp_cb != NULL) { + /* Assume the callback will provide an acceptable curve. */ + return 1; } - return tls1_curve_params_from_ec_key(&curve_id, NULL, ec) && - tls1_check_curve_id(s, curve_id); + /* Otherwise, the curve gets selected automatically. ECDH is acceptable iff + * there is a shared curve. */ + return tls1_get_shared_curve(s) != NID_undef; } /* List of supported signature algorithms and hashes. Should make this @@ -803,7 +812,7 @@ uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit, if (s->version >= TLS1_VERSION || SSL_IS_DTLS(s)) { size_t i; - unsigned long alg_k, alg_a; + 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++) { @@ -811,7 +820,7 @@ uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit, alg_k = c->algorithm_mkey; alg_a = c->algorithm_auth; - if ((alg_k & SSL_kEECDH) || (alg_a & SSL_aECDSA)) { + if ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)) { using_ecc = 1; break; } @@ -1117,9 +1126,9 @@ uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit) { uint8_t *orig = buf; uint8_t *ret = buf; int next_proto_neg_seen; - unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey; - unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth; - int using_ecc = (alg_k & SSL_kEECDH) || (alg_a & SSL_aECDSA); + 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); /* don't add extensions for SSLv3, unless doing secure renegotiation */ @@ -1331,9 +1340,7 @@ static int tls1_alpn_handle_client_hello(SSL *s, CBS *cbs, int *out_alert) { 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) { - if (s->s3->alpn_selected) { - OPENSSL_free(s->s3->alpn_selected); - } + 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; @@ -1359,35 +1366,27 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) { s->s3->tmp.certificate_status_expected = 0; s->s3->tmp.extended_master_secret = 0; - if (s->s3->alpn_selected) { - OPENSSL_free(s->s3->alpn_selected); - s->s3->alpn_selected = NULL; - } + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = NULL; /* Clear any signature algorithms extension received */ - if (s->cert->peer_sigalgs) { - OPENSSL_free(s->cert->peer_sigalgs); - s->cert->peer_sigalgs = NULL; - } + OPENSSL_free(s->cert->peer_sigalgs); + s->cert->peer_sigalgs = NULL; + s->cert->peer_sigalgslen = 0; /* Clear any shared signature algorithms */ - if (s->cert->shared_sigalgs) { - OPENSSL_free(s->cert->shared_sigalgs); - s->cert->shared_sigalgs = NULL; - } + OPENSSL_free(s->cert->shared_sigalgs); + s->cert->shared_sigalgs = NULL; + s->cert->shared_sigalgslen = 0; /* Clear ECC extensions */ - if (s->s3->tmp.peer_ecpointformatlist != 0) { - OPENSSL_free(s->s3->tmp.peer_ecpointformatlist); - s->s3->tmp.peer_ecpointformatlist = NULL; - s->s3->tmp.peer_ecpointformatlist_length = 0; - } + OPENSSL_free(s->s3->tmp.peer_ecpointformatlist); + s->s3->tmp.peer_ecpointformatlist = NULL; + s->s3->tmp.peer_ecpointformatlist_length = 0; - if (s->s3->tmp.peer_ellipticcurvelist != 0) { - OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist); - s->s3->tmp.peer_ellipticcurvelist = NULL; - s->s3->tmp.peer_ellipticcurvelist_length = 0; - } + OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist); + s->s3->tmp.peer_ellipticcurvelist = NULL; + s->s3->tmp.peer_ellipticcurvelist_length = 0; /* There may be no extensions. */ if (CBS_len(cbs) == 0) { @@ -1412,11 +1411,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) { return 0; } - if (s->tlsext_debug_cb) { - s->tlsext_debug_cb(s, 0, type, (uint8_t *)CBS_data(&extension), - CBS_len(&extension), s->tlsext_debug_arg); - } - /* The servername extension is treated as follows: - Only the hostname type is supported with a maximum length of 255. @@ -1529,10 +1523,8 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) { return 0; } - if (s->s3->tmp.peer_ellipticcurvelist) { - OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist); - s->s3->tmp.peer_ellipticcurvelist_length = 0; - } + OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist); + s->s3->tmp.peer_ellipticcurvelist_length = 0; s->s3->tmp.peer_ellipticcurvelist = (uint16_t *)OPENSSL_malloc(CBS_len(&elliptic_curve_list)); @@ -1586,7 +1578,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) { } /* If sigalgs received and no shared algorithms fatal error. */ if (s->cert->peer_sigalgs && !s->cert->shared_sigalgs) { - OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, + OPENSSL_PUT_ERROR(SSL, ssl_scan_clienthello_tlsext, SSL_R_NO_SHARED_SIGATURE_ALGORITHMS); *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; @@ -1714,17 +1706,13 @@ static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) { s->s3->tmp.extended_master_secret = 0; s->srtp_profile = NULL; - if (s->s3->alpn_selected) { - OPENSSL_free(s->s3->alpn_selected); - s->s3->alpn_selected = NULL; - } + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = NULL; /* Clear ECC extensions */ - if (s->s3->tmp.peer_ecpointformatlist != 0) { - OPENSSL_free(s->s3->tmp.peer_ecpointformatlist); - s->s3->tmp.peer_ecpointformatlist = NULL; - s->s3->tmp.peer_ecpointformatlist_length = 0; - } + OPENSSL_free(s->s3->tmp.peer_ecpointformatlist); + s->s3->tmp.peer_ecpointformatlist = NULL; + s->s3->tmp.peer_ecpointformatlist_length = 0; /* There may be no extensions. */ if (CBS_len(cbs) == 0) { @@ -1749,11 +1737,6 @@ static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) { return 0; } - if (s->tlsext_debug_cb) { - s->tlsext_debug_cb(s, 1, type, (uint8_t *)CBS_data(&extension), - CBS_len(&extension), s->tlsext_debug_arg); - } - if (type == TLSEXT_TYPE_server_name) { /* The extension must be empty. */ if (CBS_len(&extension) != 0) { @@ -1987,9 +1970,9 @@ static int ssl_check_serverhello_tlsext(SSL *s) { /* 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. */ - unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey; - unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth; - if (((alg_k & SSL_kEECDH) || (alg_a & SSL_aECDSA)) && + 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); @@ -2001,7 +1984,7 @@ static int ssl_check_serverhello_tlsext(SSL *s) { ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg); } else if (s->initial_ctx != NULL && - s->initial_ctx->tlsext_servername_callback != 0) { + s->initial_ctx->tlsext_servername_callback != 0) { ret = s->initial_ctx->tlsext_servername_callback( s, &al, s->initial_ctx->tlsext_servername_arg); } @@ -2133,8 +2116,11 @@ static int tls_decrypt_ticket(SSL *s, const uint8_t *etick, int eticklen, EVP_CIPHER_CTX ctx; SSL_CTX *tctx = s->initial_ctx; - /* Need at least keyname + iv + some encrypted data */ - if (eticklen < 48) { + /* 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 (eticklen < 16 + EVP_MAX_IV_LENGTH) { return 2; } @@ -2143,7 +2129,8 @@ static int tls_decrypt_ticket(SSL *s, const uint8_t *etick, int eticklen, 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); + int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16, &ctx, &hctx, + 0 /* decrypt */); if (rv < 0) { return -1; } @@ -2168,13 +2155,13 @@ static int tls_decrypt_ticket(SSL *s, const uint8_t *etick, int eticklen, } } - /* Attempt to process session ticket, first conduct sanity and integrity - * checks on ticket. */ + /* First, check the MAC. The MAC is at the end of the ticket. */ mlen = HMAC_size(&hctx); - if (mlen < 0) { + 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. */ HMAC_CTX_cleanup(&hctx); EVP_CIPHER_CTX_cleanup(&ctx); - return -1; + return 2; } eticklen -= mlen; /* Check HMAC of encrypted ticket */ @@ -2407,10 +2394,9 @@ static int tls1_set_shared_sigalgs(SSL *s) { TLS_SIGALGS *salgs = NULL; CERT *c = s->cert; - if (c->shared_sigalgs) { - OPENSSL_free(c->shared_sigalgs); - c->shared_sigalgs = NULL; - } + 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) { @@ -2460,21 +2446,12 @@ int tls1_process_sigalgs(SSL *s, const CBS *sigalgs) { return 1; } - /* Length must be even */ - if (CBS_len(sigalgs) % 2 != 0) { - return 0; - } - - /* Should never happen */ - if (!c) { - return 0; - } - - if (!CBS_stow(sigalgs, &c->peer_sigalgs, &c->peer_sigalgslen)) { + if (CBS_len(sigalgs) % 2 != 0 || + !CBS_stow(sigalgs, &c->peer_sigalgs, &c->peer_sigalgslen) || + !tls1_set_shared_sigalgs(s)) { return 0; } - tls1_set_shared_sigalgs(s); return 1; } @@ -2583,7 +2560,10 @@ int tls1_channel_id_hash(EVP_MD_CTX *md, SSL *s) { if (s->s3->handshake_dgst[i] == NULL) { continue; } - EVP_MD_CTX_copy_ex(&ctx, s->s3->handshake_dgst[i]); + 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); } @@ -2650,15 +2630,11 @@ int tls1_set_sigalgs(CERT *c, const int *psig_nids, size_t salglen, } if (client) { - if (c->client_sigalgs) { - OPENSSL_free(c->client_sigalgs); - } + OPENSSL_free(c->client_sigalgs); c->client_sigalgs = sigalgs; c->client_sigalgslen = salglen; } else { - if (c->conf_sigalgs) { - OPENSSL_free(c->conf_sigalgs); - } + OPENSSL_free(c->conf_sigalgs); c->conf_sigalgs = sigalgs; c->conf_sigalgslen = salglen; } diff --git a/src/ssl/t1_reneg.c b/src/ssl/t1_reneg.c index 2d9fbc0..d0009c1 100644 --- a/src/ssl/t1_reneg.c +++ b/src/ssl/t1_reneg.c @@ -106,14 +106,14 @@ * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). */ -#include #include +#include +#include #include -#include #include -#include "ssl_locl.h" +#include "internal.h" /* Add the client's renegotiation binding */ @@ -170,8 +170,7 @@ 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) { + 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; diff --git a/src/ssl/test/CMakeLists.txt b/src/ssl/test/CMakeLists.txt index 9992360..a0d7a5e 100644 --- a/src/ssl/test/CMakeLists.txt +++ b/src/ssl/test/CMakeLists.txt @@ -11,6 +11,3 @@ add_executable( ) target_link_libraries(bssl_shim ssl crypto) -if (NOT APPLE AND NOT WIN32) - target_link_libraries(bssl_shim dl) -endif() diff --git a/src/ssl/test/async_bio.cc b/src/ssl/test/async_bio.cc index c007ffa..0534845 100644 --- a/src/ssl/test/async_bio.cc +++ b/src/ssl/test/async_bio.cc @@ -22,23 +22,23 @@ namespace { -extern const BIO_METHOD async_bio_method; +extern const BIO_METHOD g_async_bio_method; -struct async_bio { +struct AsyncBio { bool datagram; size_t read_quota; size_t write_quota; }; -async_bio *get_data(BIO *bio) { - if (bio->method != &async_bio_method) { +AsyncBio *GetData(BIO *bio) { + if (bio->method != &g_async_bio_method) { return NULL; } - return (async_bio *)bio->ptr; + return (AsyncBio *)bio->ptr; } -static int async_write(BIO *bio, const char *in, int inl) { - async_bio *a = get_data(bio); +static int AsyncWrite(BIO *bio, const char *in, int inl) { + AsyncBio *a = GetData(bio); if (a == NULL || bio->next_bio == NULL) { return 0; } @@ -69,8 +69,8 @@ static int async_write(BIO *bio, const char *in, int inl) { return ret; } -static int async_read(BIO *bio, char *out, int outl) { - async_bio *a = get_data(bio); +static int AsyncRead(BIO *bio, char *out, int outl) { + AsyncBio *a = GetData(bio); if (a == NULL || bio->next_bio == NULL) { return 0; } @@ -95,7 +95,7 @@ static int async_read(BIO *bio, char *out, int outl) { return ret; } -static long async_ctrl(BIO *bio, int cmd, long num, void *ptr) { +static long AsyncCtrl(BIO *bio, int cmd, long num, void *ptr) { if (bio->next_bio == NULL) { return 0; } @@ -105,8 +105,8 @@ static long async_ctrl(BIO *bio, int cmd, long num, void *ptr) { return ret; } -static int async_new(BIO *bio) { - async_bio *a = (async_bio *)OPENSSL_malloc(sizeof(*a)); +static int AsyncNew(BIO *bio) { + AsyncBio *a = (AsyncBio *)OPENSSL_malloc(sizeof(*a)); if (a == NULL) { return 0; } @@ -116,7 +116,7 @@ static int async_new(BIO *bio) { return 1; } -static int async_free(BIO *bio) { +static int AsyncFree(BIO *bio) { if (bio == NULL) { return 0; } @@ -128,51 +128,51 @@ static int async_free(BIO *bio) { return 1; } -static long async_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) { +static long AsyncCallbackCtrl(BIO *bio, int cmd, bio_info_cb fp) { if (bio->next_bio == NULL) { return 0; } return BIO_callback_ctrl(bio->next_bio, cmd, fp); } -const BIO_METHOD async_bio_method = { +const BIO_METHOD g_async_bio_method = { BIO_TYPE_FILTER, "async bio", - async_write, - async_read, + AsyncWrite, + AsyncRead, NULL /* puts */, NULL /* gets */, - async_ctrl, - async_new, - async_free, - async_callback_ctrl, + AsyncCtrl, + AsyncNew, + AsyncFree, + AsyncCallbackCtrl, }; } // namespace -BIO *async_bio_create() { - return BIO_new(&async_bio_method); +ScopedBIO AsyncBioCreate() { + return ScopedBIO(BIO_new(&g_async_bio_method)); } -BIO *async_bio_create_datagram() { - BIO *ret = BIO_new(&async_bio_method); +ScopedBIO AsyncBioCreateDatagram() { + ScopedBIO ret(BIO_new(&g_async_bio_method)); if (!ret) { - return NULL; + return nullptr; } - get_data(ret)->datagram = true; + GetData(ret.get())->datagram = true; return ret; } -void async_bio_allow_read(BIO *bio, size_t count) { - async_bio *a = get_data(bio); +void AsyncBioAllowRead(BIO *bio, size_t count) { + AsyncBio *a = GetData(bio); if (a == NULL) { return; } a->read_quota += count; } -void async_bio_allow_write(BIO *bio, size_t count) { - async_bio *a = get_data(bio); +void AsyncBioAllowWrite(BIO *bio, size_t count) { + AsyncBio *a = GetData(bio); if (a == NULL) { return; } diff --git a/src/ssl/test/async_bio.h b/src/ssl/test/async_bio.h index 2904036..1ccdf9b 100644 --- a/src/ssl/test/async_bio.h +++ b/src/ssl/test/async_bio.h @@ -17,24 +17,26 @@ #include +#include "../../crypto/test/scoped_types.h" -// async_bio_create creates a filter BIO for testing asynchronous state + +// AsyncBioCreate creates a filter BIO for testing asynchronous state // machines which consume a stream socket. Reads and writes will fail // and return EAGAIN unless explicitly allowed. Each async BIO has a // read quota and a write quota. Initially both are zero. As each is // incremented, bytes are allowed to flow through the BIO. -BIO *async_bio_create(); +ScopedBIO AsyncBioCreate(); -// async_bio_create_datagram creates a filter BIO for testing for +// AsyncBioCreateDatagram creates a filter BIO for testing for // asynchronous state machines which consume datagram sockets. The read // and write quota count in packets rather than bytes. -BIO *async_bio_create_datagram(); +ScopedBIO AsyncBioCreateDatagram(); -// async_bio_allow_read increments |bio|'s read quota by |count|. -void async_bio_allow_read(BIO *bio, size_t count); +// AsyncBioAllowRead increments |bio|'s read quota by |count|. +void AsyncBioAllowRead(BIO *bio, size_t count); -// async_bio_allow_write increments |bio|'s write quota by |count|. -void async_bio_allow_write(BIO *bio, size_t count); +// AsyncBioAllowWrite increments |bio|'s write quota by |count|. +void AsyncBioAllowWrite(BIO *bio, size_t count); #endif // HEADER_ASYNC_BIO diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc index 37891b9..1cf96f2 100644 --- a/src/ssl/test/bssl_shim.cc +++ b/src/ssl/test/bssl_shim.cc @@ -17,9 +17,19 @@ #if !defined(OPENSSL_WINDOWS) #include #include +#include #include #include +#include #include +#else +#include +#pragma warning(push, 3) +#include +#include +#pragma warning(pop) + +#pragma comment(lib, "Ws2_32.lib") #endif #include @@ -28,126 +38,198 @@ #include #include #include +#include #include +#include +#include + +#include "../../crypto/test/scoped_types.h" #include "async_bio.h" #include "packeted_bio.h" +#include "scoped_types.h" #include "test_config.h" -static int usage(const char *program) { - fprintf(stderr, "Usage: %s [flags...]\n", - program); + +#if !defined(OPENSSL_WINDOWS) +static int closesocket(int sock) { + return close(sock); +} + +static void PrintSocketError(const char *func) { + perror(func); +} +#else +static void PrintSocketError(const char *func) { + fprintf(stderr, "%s: %d\n", func, WSAGetLastError()); +} +#endif + +static int Usage(const char *program) { + fprintf(stderr, "Usage: %s [flags...]\n", program); return 1; } -static int g_ex_data_index = 0; +struct TestState { + TestState() { + // MSVC cannot initialize these inline. + memset(&clock, 0, sizeof(clock)); + memset(&clock_delta, 0, sizeof(clock_delta)); + } + + // async_bio is async BIO which pauses reads and writes. + BIO *async_bio = nullptr; + // clock is the current time for the SSL connection. + timeval clock; + // clock_delta is how far the clock advanced in the most recent failed + // |BIO_read|. + timeval clock_delta; + ScopedEVP_PKEY channel_id; + bool cert_ready = false; + ScopedSSL_SESSION session; + ScopedSSL_SESSION pending_session; + bool early_callback_called = false; + bool handshake_done = false; +}; + +static void TestStateExFree(void *parent, void *ptr, CRYPTO_EX_DATA *ad, + int index, long argl, void *argp) { + delete ((TestState *)ptr); +} + +static int g_config_index = 0; +static int g_state_index = 0; static bool SetConfigPtr(SSL *ssl, const TestConfig *config) { - return SSL_set_ex_data(ssl, g_ex_data_index, (void *)config) == 1; + return SSL_set_ex_data(ssl, g_config_index, (void *)config) == 1; } -static const TestConfig *GetConfigPtr(SSL *ssl) { - return (const TestConfig *)SSL_get_ex_data(ssl, g_ex_data_index); +static const TestConfig *GetConfigPtr(const SSL *ssl) { + return (const TestConfig *)SSL_get_ex_data(ssl, g_config_index); } -static EVP_PKEY *LoadPrivateKey(const std::string &file) { - BIO *bio = BIO_new(BIO_s_file()); - if (bio == NULL) { - return NULL; +static bool SetTestState(SSL *ssl, std::unique_ptr async) { + if (SSL_set_ex_data(ssl, g_state_index, (void *)async.get()) == 1) { + async.release(); + return true; } - if (!BIO_read_filename(bio, file.c_str())) { - BIO_free(bio); - return NULL; + return false; +} + +static TestState *GetTestState(const SSL *ssl) { + return (TestState *)SSL_get_ex_data(ssl, g_state_index); +} + +static ScopedEVP_PKEY LoadPrivateKey(const std::string &file) { + ScopedBIO bio(BIO_new(BIO_s_file())); + if (!bio || !BIO_read_filename(bio.get(), file.c_str())) { + return nullptr; } - EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); - BIO_free(bio); + ScopedEVP_PKEY pkey(PEM_read_bio_PrivateKey(bio.get(), NULL, NULL, NULL)); return pkey; } -static int early_callback_called = 0; - -static int select_certificate_callback(const struct ssl_early_callback_ctx *ctx) { - early_callback_called = 1; +static bool InstallCertificate(SSL *ssl) { + const TestConfig *config = GetConfigPtr(ssl); + 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; + } + return true; +} +static int SelectCertificateCallback(const struct ssl_early_callback_ctx *ctx) { const TestConfig *config = GetConfigPtr(ctx->ssl); + GetTestState(ctx->ssl)->early_callback_called = true; - if (config->expected_server_name.empty()) { - return 1; - } + if (!config->expected_server_name.empty()) { + const uint8_t *extension_data; + size_t extension_len; + CBS extension, server_name_list, host_name; + uint8_t name_type; + + if (!SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_server_name, + &extension_data, + &extension_len)) { + fprintf(stderr, "Could not find server_name extension.\n"); + return -1; + } - const uint8_t *extension_data; - size_t extension_len; - CBS extension, server_name_list, host_name; - uint8_t name_type; + CBS_init(&extension, extension_data, extension_len); + if (!CBS_get_u16_length_prefixed(&extension, &server_name_list) || + CBS_len(&extension) != 0 || + !CBS_get_u8(&server_name_list, &name_type) || + name_type != TLSEXT_NAMETYPE_host_name || + !CBS_get_u16_length_prefixed(&server_name_list, &host_name) || + CBS_len(&server_name_list) != 0) { + fprintf(stderr, "Could not decode server_name extension.\n"); + return -1; + } - if (!SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_server_name, - &extension_data, - &extension_len)) { - fprintf(stderr, "Could not find server_name extension.\n"); - return -1; + if (!CBS_mem_equal(&host_name, + (const uint8_t*)config->expected_server_name.data(), + config->expected_server_name.size())) { + fprintf(stderr, "Server name mismatch.\n"); + } } - CBS_init(&extension, extension_data, extension_len); - if (!CBS_get_u16_length_prefixed(&extension, &server_name_list) || - CBS_len(&extension) != 0 || - !CBS_get_u8(&server_name_list, &name_type) || - name_type != TLSEXT_NAMETYPE_host_name || - !CBS_get_u16_length_prefixed(&server_name_list, &host_name) || - CBS_len(&server_name_list) != 0) { - fprintf(stderr, "Could not decode server_name extension.\n"); + if (config->fail_early_callback) { return -1; } - if (!CBS_mem_equal(&host_name, - (const uint8_t*)config->expected_server_name.data(), - config->expected_server_name.size())) { - fprintf(stderr, "Server name mismatch.\n"); + // Install the certificate in the early callback. + if (config->use_early_callback) { + if (config->async) { + // Install the certificate asynchronously. + return 0; + } + if (!InstallCertificate(ctx->ssl)) { + return -1; + } } - return 1; } -static int skip_verify(int preverify_ok, X509_STORE_CTX *store_ctx) { +static int SkipVerify(int preverify_ok, X509_STORE_CTX *store_ctx) { return 1; } -static int next_protos_advertised_callback(SSL *ssl, - const uint8_t **out, - unsigned int *out_len, - void *arg) { +static int NextProtosAdvertisedCallback(SSL *ssl, const uint8_t **out, + unsigned int *out_len, void *arg) { const TestConfig *config = GetConfigPtr(ssl); - if (config->advertise_npn.empty()) + if (config->advertise_npn.empty()) { return SSL_TLSEXT_ERR_NOACK; + } *out = (const uint8_t*)config->advertise_npn.data(); *out_len = config->advertise_npn.size(); return SSL_TLSEXT_ERR_OK; } -static int next_proto_select_callback(SSL* ssl, - uint8_t** out, - uint8_t* outlen, - const uint8_t* in, - unsigned inlen, - void* arg) { +static int NextProtoSelectCallback(SSL* ssl, uint8_t** out, uint8_t* outlen, + const uint8_t* in, unsigned inlen, void* arg) { const TestConfig *config = GetConfigPtr(ssl); - if (config->select_next_proto.empty()) + if (config->select_next_proto.empty()) { return SSL_TLSEXT_ERR_NOACK; + } *out = (uint8_t*)config->select_next_proto.data(); *outlen = config->select_next_proto.size(); return SSL_TLSEXT_ERR_OK; } -static int alpn_select_callback(SSL* ssl, - const uint8_t** out, - uint8_t* outlen, - const uint8_t* in, - unsigned inlen, - void* arg) { +static int AlpnSelectCallback(SSL* ssl, const uint8_t** out, uint8_t* outlen, + const uint8_t* in, unsigned inlen, void* arg) { const TestConfig *config = GetConfigPtr(ssl); - if (config->select_alpn.empty()) + if (config->select_alpn.empty()) { return SSL_TLSEXT_ERR_NOACK; + } if (!config->expected_advertised_alpn.empty() && (config->expected_advertised_alpn.size() != inlen || @@ -162,34 +244,10 @@ static int alpn_select_callback(SSL* ssl, return SSL_TLSEXT_ERR_OK; } -static int cookie_generate_callback(SSL *ssl, uint8_t *cookie, size_t *cookie_len) { - if (*cookie_len < 32) { - fprintf(stderr, "Insufficient space for cookie\n"); - return 0; - } - *cookie_len = 32; - memset(cookie, 42, *cookie_len); - return 1; -} - -static int cookie_verify_callback(SSL *ssl, const uint8_t *cookie, size_t cookie_len) { - if (cookie_len != 32) { - fprintf(stderr, "Cookie length mismatch.\n"); - return 0; - } - for (size_t i = 0; i < cookie_len; i++) { - if (cookie[i] != 42) { - fprintf(stderr, "Cookie mismatch.\n"); - return 0; - } - } - return 1; -} - -static unsigned psk_client_callback(SSL *ssl, const char *hint, - char *out_identity, - unsigned max_identity_len, - uint8_t *out_psk, unsigned max_psk_len) { +static unsigned PskClientCallback(SSL *ssl, const char *hint, + char *out_identity, + unsigned max_identity_len, + uint8_t *out_psk, unsigned max_psk_len) { const TestConfig *config = GetConfigPtr(ssl); if (strcmp(hint ? hint : "", config->psk_identity.c_str()) != 0) { @@ -210,8 +268,8 @@ static unsigned psk_client_callback(SSL *ssl, const char *hint, return config->psk.size(); } -static unsigned psk_server_callback(SSL *ssl, const char *identity, - uint8_t *out_psk, unsigned max_psk_len) { +static unsigned PskServerCallback(SSL *ssl, const char *identity, + uint8_t *out_psk, unsigned max_psk_len) { const TestConfig *config = GetConfigPtr(ssl); if (strcmp(identity, config->psk_identity.c_str()) != 0) { @@ -228,13 +286,124 @@ static unsigned psk_server_callback(SSL *ssl, const char *identity, return config->psk.size(); } -static SSL_CTX *setup_ctx(const TestConfig *config) { - SSL_CTX *ssl_ctx = NULL; - DH *dh = NULL; +static void CurrentTimeCallback(const SSL *ssl, timeval *out_clock) { + *out_clock = GetTestState(ssl)->clock; +} - ssl_ctx = SSL_CTX_new(config->is_dtls ? DTLS_method() : TLS_method()); - if (ssl_ctx == NULL) { - goto err; +static void ChannelIdCallback(SSL *ssl, EVP_PKEY **out_pkey) { + *out_pkey = GetTestState(ssl)->channel_id.release(); +} + +static int CertCallback(SSL *ssl, void *arg) { + if (!GetTestState(ssl)->cert_ready) { + return -1; + } + if (!InstallCertificate(ssl)) { + return 0; + } + return 1; +} + +static SSL_SESSION *GetSessionCallback(SSL *ssl, uint8_t *data, int len, + int *copy) { + TestState *async_state = GetTestState(ssl); + if (async_state->session) { + *copy = 0; + return async_state->session.release(); + } else if (async_state->pending_session) { + return SSL_magic_pending_session_ptr(); + } else { + return NULL; + } +} + +static int DDoSCallback(const struct ssl_early_callback_ctx *early_context) { + const TestConfig *config = GetConfigPtr(early_context->ssl); + static int callback_num = 0; + + callback_num++; + if (config->fail_ddos_callback || + (config->fail_second_ddos_callback && callback_num == 2)) { + return 0; + } + return 1; +} + +static void InfoCallback(const SSL *ssl, int type, int val) { + if (type == SSL_CB_HANDSHAKE_DONE) { + if (GetConfigPtr(ssl)->handshake_never_done) { + fprintf(stderr, "handshake completed\n"); + // Abort before any expected error code is printed, to ensure the overall + // test fails. + abort(); + } + GetTestState(ssl)->handshake_done = true; + } +} + +// Connect returns a new socket connected to localhost on |port| or -1 on +// error. +static int Connect(uint16_t port) { + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == -1) { + PrintSocketError("socket"); + return -1; + } + int nodelay = 1; + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, + reinterpret_cast(&nodelay), sizeof(nodelay)) != 0) { + PrintSocketError("setsockopt"); + closesocket(sock); + return -1; + } + sockaddr_in sin; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + if (!inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr)) { + PrintSocketError("inet_pton"); + closesocket(sock); + return -1; + } + if (connect(sock, reinterpret_cast(&sin), + sizeof(sin)) != 0) { + PrintSocketError("connect"); + closesocket(sock); + return -1; + } + return sock; +} + +class SocketCloser { + public: + explicit SocketCloser(int sock) : sock_(sock) {} + ~SocketCloser() { + // Half-close and drain the socket before releasing it. This seems to be + // necessary for graceful shutdown on Windows. It will also avoid write + // failures in the test runner. +#if defined(OPENSSL_WINDOWS) + shutdown(sock_, SD_SEND); +#else + shutdown(sock_, SHUT_WR); +#endif + while (true) { + char buf[1024]; + if (recv(sock_, buf, sizeof(buf), 0) <= 0) { + break; + } + } + closesocket(sock_); + } + + private: + const int sock_; +}; + +static ScopedSSL_CTX SetupCtx(const TestConfig *config) { + ScopedSSL_CTX ssl_ctx(SSL_CTX_new( + config->is_dtls ? DTLS_method() : TLS_method())); + if (!ssl_ctx) { + return nullptr; } if (config->is_dtls) { @@ -242,376 +411,473 @@ static SSL_CTX *setup_ctx(const TestConfig *config) { // // TODO(davidben): this should not be necessary. DTLS code should only // expect a datagram BIO. - SSL_CTX_set_read_ahead(ssl_ctx, 1); + SSL_CTX_set_read_ahead(ssl_ctx.get(), 1); } - if (!SSL_CTX_set_ecdh_auto(ssl_ctx, 1)) { - goto err; + if (!SSL_CTX_set_cipher_list(ssl_ctx.get(), "ALL")) { + return nullptr; } - if (!SSL_CTX_set_cipher_list(ssl_ctx, "ALL")) { - goto err; + ScopedDH dh(DH_get_2048_256(NULL)); + if (!dh || !SSL_CTX_set_tmp_dh(ssl_ctx.get(), dh.get())) { + return nullptr; } - dh = DH_get_2048_256(NULL); - if (dh == NULL || - !SSL_CTX_set_tmp_dh(ssl_ctx, dh)) { - goto err; + if (config->async && config->is_server) { + // Disable the internal session cache. To test asynchronous session lookup, + // we use an external session cache. + SSL_CTX_set_session_cache_mode( + ssl_ctx.get(), SSL_SESS_CACHE_BOTH | SSL_SESS_CACHE_NO_INTERNAL); + SSL_CTX_sess_set_get_cb(ssl_ctx.get(), GetSessionCallback); + } else { + SSL_CTX_set_session_cache_mode(ssl_ctx.get(), SSL_SESS_CACHE_BOTH); } - SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_BOTH); - - ssl_ctx->select_certificate_cb = select_certificate_callback; + ssl_ctx->select_certificate_cb = SelectCertificateCallback; SSL_CTX_set_next_protos_advertised_cb( - ssl_ctx, next_protos_advertised_callback, NULL); + ssl_ctx.get(), NextProtosAdvertisedCallback, NULL); if (!config->select_next_proto.empty()) { - SSL_CTX_set_next_proto_select_cb(ssl_ctx, next_proto_select_callback, NULL); + SSL_CTX_set_next_proto_select_cb(ssl_ctx.get(), NextProtoSelectCallback, + NULL); } if (!config->select_alpn.empty()) { - SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_callback, NULL); + SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), AlpnSelectCallback, NULL); } - SSL_CTX_set_cookie_generate_cb(ssl_ctx, cookie_generate_callback); - SSL_CTX_set_cookie_verify_cb(ssl_ctx, cookie_verify_callback); - ssl_ctx->tlsext_channel_id_enabled_new = 1; + SSL_CTX_set_channel_id_cb(ssl_ctx.get(), ChannelIdCallback); - DH_free(dh); - return ssl_ctx; + ssl_ctx->current_time_cb = CurrentTimeCallback; - err: - if (dh != NULL) { - DH_free(dh); - } - if (ssl_ctx != NULL) { - SSL_CTX_free(ssl_ctx); - } - return NULL; + SSL_CTX_set_info_callback(ssl_ctx.get(), InfoCallback); + + return ssl_ctx; } -static int retry_async(SSL *ssl, int ret, BIO *bio) { +// RetryAsync is called after a failed operation on |ssl| with return code +// |ret|. If the operation should be retried, it simulates one asynchronous +// event and returns true. Otherwise it returns false. +static bool RetryAsync(SSL *ssl, int ret) { // No error; don't retry. if (ret >= 0) { - return 0; + return false; + } + + TestState *test_state = GetTestState(ssl); + if (test_state->clock_delta.tv_usec != 0 || + test_state->clock_delta.tv_sec != 0) { + // Process the timeout and retry. + test_state->clock.tv_usec += test_state->clock_delta.tv_usec; + test_state->clock.tv_sec += test_state->clock.tv_usec / 1000000; + test_state->clock.tv_usec %= 1000000; + test_state->clock.tv_sec += test_state->clock_delta.tv_sec; + memset(&test_state->clock_delta, 0, sizeof(test_state->clock_delta)); + + if (DTLSv1_handle_timeout(ssl) < 0) { + fprintf(stderr, "Error retransmitting.\n"); + return false; + } + return true; } + // See if we needed to read or write more. If so, allow one byte through on // the appropriate end to maximally stress the state machine. - int err = SSL_get_error(ssl, ret); - if (err == SSL_ERROR_WANT_READ) { - async_bio_allow_read(bio, 1); - return 1; - } else if (err == SSL_ERROR_WANT_WRITE) { - async_bio_allow_write(bio, 1); - return 1; + switch (SSL_get_error(ssl, ret)) { + case SSL_ERROR_WANT_READ: + AsyncBioAllowRead(test_state->async_bio, 1); + return true; + case SSL_ERROR_WANT_WRITE: + AsyncBioAllowWrite(test_state->async_bio, 1); + return true; + case SSL_ERROR_WANT_CHANNEL_ID_LOOKUP: { + ScopedEVP_PKEY pkey = LoadPrivateKey(GetConfigPtr(ssl)->send_channel_id); + if (!pkey) { + return false; + } + test_state->channel_id = std::move(pkey); + return true; + } + case SSL_ERROR_WANT_X509_LOOKUP: + test_state->cert_ready = true; + return true; + case SSL_ERROR_PENDING_SESSION: + test_state->session = std::move(test_state->pending_session); + return true; + case SSL_ERROR_PENDING_CERTIFICATE: + // The handshake will resume without a second call to the early callback. + return InstallCertificate(ssl); + default: + return false; } - return 0; } -static int do_exchange(SSL_SESSION **out_session, - SSL_CTX *ssl_ctx, - const TestConfig *config, - bool is_resume, - int fd, - SSL_SESSION *session) { - early_callback_called = 0; +// DoRead reads from |ssl|, resolving any asynchronous operations. It returns +// the result value of the final |SSL_read| call. +static int DoRead(SSL *ssl, uint8_t *out, size_t max_out) { + const TestConfig *config = GetConfigPtr(ssl); + int ret; + do { + ret = SSL_read(ssl, out, max_out); + } while (config->async && RetryAsync(ssl, ret)); + return ret; +} - SSL *ssl = SSL_new(ssl_ctx); - if (ssl == NULL) { - BIO_print_errors_fp(stdout); - return 1; - } +// WriteAll writes |in_len| bytes from |in| to |ssl|, resolving any asynchronous +// operations. It returns the result of the final |SSL_write| call. +static int WriteAll(SSL *ssl, const uint8_t *in, size_t in_len) { + const TestConfig *config = GetConfigPtr(ssl); + int ret; + do { + ret = SSL_write(ssl, in, in_len); + if (ret > 0) { + in += ret; + in_len -= ret; + } + } while ((config->async && RetryAsync(ssl, ret)) || (ret > 0 && in_len > 0)); + return ret; +} - if (!SetConfigPtr(ssl, config)) { - BIO_print_errors_fp(stdout); - return 1; +// 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 +// previous exchange. +static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx, + const TestConfig *config, bool is_resume, + SSL_SESSION *session) { + ScopedSSL ssl(SSL_new(ssl_ctx)); + if (!ssl) { + return false; } - if (config->fallback_scsv) { - if (!SSL_enable_fallback_scsv(ssl)) { - BIO_print_errors_fp(stdout); - return 1; - } + if (!SetConfigPtr(ssl.get(), config) || + !SetTestState(ssl.get(), std::unique_ptr(new TestState))) { + return false; } - if (!config->key_file.empty()) { - if (!SSL_use_PrivateKey_file(ssl, config->key_file.c_str(), - SSL_FILETYPE_PEM)) { - BIO_print_errors_fp(stdout); - return 1; - } + + if (config->fallback_scsv && + !SSL_set_mode(ssl.get(), SSL_MODE_SEND_FALLBACK_SCSV)) { + return false; } - if (!config->cert_file.empty()) { - if (!SSL_use_certificate_file(ssl, config->cert_file.c_str(), - SSL_FILETYPE_PEM)) { - BIO_print_errors_fp(stdout); - return 1; + if (!config->use_early_callback) { + if (config->async) { + // TODO(davidben): Also test |s->ctx->client_cert_cb| on the client. + SSL_set_cert_cb(ssl.get(), CertCallback, NULL); + } else if (!InstallCertificate(ssl.get())) { + return false; } } if (config->require_any_client_certificate) { - SSL_set_verify(ssl, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, - skip_verify); + SSL_set_verify(ssl.get(), SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + SkipVerify); } if (config->false_start) { - SSL_set_mode(ssl, SSL_MODE_HANDSHAKE_CUTTHROUGH); + SSL_set_mode(ssl.get(), SSL_MODE_ENABLE_FALSE_START); } if (config->cbc_record_splitting) { - SSL_set_mode(ssl, SSL_MODE_CBC_RECORD_SPLITTING); + SSL_set_mode(ssl.get(), SSL_MODE_CBC_RECORD_SPLITTING); } if (config->partial_write) { - SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE); + SSL_set_mode(ssl.get(), SSL_MODE_ENABLE_PARTIAL_WRITE); } if (config->no_tls12) { - SSL_set_options(ssl, SSL_OP_NO_TLSv1_2); + SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1_2); } if (config->no_tls11) { - SSL_set_options(ssl, SSL_OP_NO_TLSv1_1); + SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1_1); } if (config->no_tls1) { - SSL_set_options(ssl, SSL_OP_NO_TLSv1); + SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1); } if (config->no_ssl3) { - SSL_set_options(ssl, SSL_OP_NO_SSLv3); - } - if (config->cookie_exchange) { - SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE); + SSL_set_options(ssl.get(), SSL_OP_NO_SSLv3); } if (config->tls_d5_bug) { - SSL_set_options(ssl, SSL_OP_TLS_D5_BUG); + SSL_set_options(ssl.get(), SSL_OP_TLS_D5_BUG); } if (config->allow_unsafe_legacy_renegotiation) { - SSL_set_options(ssl, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); + SSL_set_options(ssl.get(), SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); } if (!config->expected_channel_id.empty()) { - SSL_enable_tls_channel_id(ssl); + SSL_enable_tls_channel_id(ssl.get()); } if (!config->send_channel_id.empty()) { - EVP_PKEY *pkey = LoadPrivateKey(config->send_channel_id); - if (pkey == NULL) { - BIO_print_errors_fp(stdout); - return 1; - } - SSL_enable_tls_channel_id(ssl); - if (!SSL_set1_tls_channel_id(ssl, pkey)) { - EVP_PKEY_free(pkey); - BIO_print_errors_fp(stdout); - return 1; + SSL_enable_tls_channel_id(ssl.get()); + if (!config->async) { + // The async case will be supplied by |ChannelIdCallback|. + ScopedEVP_PKEY pkey = LoadPrivateKey(config->send_channel_id); + if (!pkey || !SSL_set1_tls_channel_id(ssl.get(), pkey.get())) { + return false; + } } - EVP_PKEY_free(pkey); } - if (!config->host_name.empty()) { - SSL_set_tlsext_host_name(ssl, config->host_name.c_str()); + if (!config->host_name.empty() && + !SSL_set_tlsext_host_name(ssl.get(), config->host_name.c_str())) { + return false; } - if (!config->advertise_alpn.empty()) { - SSL_set_alpn_protos(ssl, (const uint8_t *)config->advertise_alpn.data(), - config->advertise_alpn.size()); + if (!config->advertise_alpn.empty() && + SSL_set_alpn_protos(ssl.get(), + (const uint8_t *)config->advertise_alpn.data(), + config->advertise_alpn.size()) != 0) { + return false; } if (!config->psk.empty()) { - SSL_set_psk_client_callback(ssl, psk_client_callback); - SSL_set_psk_server_callback(ssl, psk_server_callback); + SSL_set_psk_client_callback(ssl.get(), PskClientCallback); + SSL_set_psk_server_callback(ssl.get(), PskServerCallback); } if (!config->psk_identity.empty() && - !SSL_use_psk_identity_hint(ssl, config->psk_identity.c_str())) { - BIO_print_errors_fp(stdout); - return 1; + !SSL_use_psk_identity_hint(ssl.get(), config->psk_identity.c_str())) { + return false; } if (!config->srtp_profiles.empty() && - !SSL_set_srtp_profiles(ssl, config->srtp_profiles.c_str())) { - BIO_print_errors_fp(stdout); - return 1; + !SSL_set_srtp_profiles(ssl.get(), config->srtp_profiles.c_str())) { + return false; } if (config->enable_ocsp_stapling && - !SSL_enable_ocsp_stapling(ssl)) { - BIO_print_errors_fp(stdout); - return 1; + !SSL_enable_ocsp_stapling(ssl.get())) { + return false; } if (config->enable_signed_cert_timestamps && - !SSL_enable_signed_cert_timestamps(ssl)) { - BIO_print_errors_fp(stdout); - return 1; + !SSL_enable_signed_cert_timestamps(ssl.get())) { + return false; } - SSL_enable_fastradio_padding(ssl, config->fastradio_padding); + SSL_enable_fastradio_padding(ssl.get(), config->fastradio_padding); if (config->min_version != 0) { - SSL_set_min_version(ssl, (uint16_t)config->min_version); + SSL_set_min_version(ssl.get(), (uint16_t)config->min_version); } if (config->max_version != 0) { - SSL_set_max_version(ssl, (uint16_t)config->max_version); + SSL_set_max_version(ssl.get(), (uint16_t)config->max_version); } if (config->mtu != 0) { - SSL_set_options(ssl, SSL_OP_NO_QUERY_MTU); - SSL_set_mtu(ssl, config->mtu); + SSL_set_options(ssl.get(), SSL_OP_NO_QUERY_MTU); + SSL_set_mtu(ssl.get(), config->mtu); + } + 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) { + SSL_set_reject_peer_renegotiations(ssl.get(), 1); } - BIO *bio = BIO_new_fd(fd, 1 /* take ownership */); - if (bio == NULL) { - BIO_print_errors_fp(stdout); - return 1; + int sock = Connect(config->port); + if (sock == -1) { + return false; + } + SocketCloser closer(sock); + + ScopedBIO bio(BIO_new_socket(sock, BIO_NOCLOSE)); + if (!bio) { + return false; } if (config->is_dtls) { - BIO *packeted = packeted_bio_create(); - BIO_push(packeted, bio); - bio = packeted; + ScopedBIO packeted = + PacketedBioCreate(&GetTestState(ssl.get())->clock_delta); + BIO_push(packeted.get(), bio.release()); + bio = std::move(packeted); } if (config->async) { - BIO *async = - config->is_dtls ? async_bio_create_datagram() : async_bio_create(); - BIO_push(async, bio); - bio = async; + ScopedBIO async_scoped = + config->is_dtls ? AsyncBioCreateDatagram() : AsyncBioCreate(); + BIO_push(async_scoped.get(), bio.release()); + GetTestState(ssl.get())->async_bio = async_scoped.get(); + bio = std::move(async_scoped); } - SSL_set_bio(ssl, bio, bio); + SSL_set_bio(ssl.get(), bio.get(), bio.get()); + bio.release(); // SSL_set_bio takes ownership. if (session != NULL) { - if (SSL_set_session(ssl, session) != 1) { - fprintf(stderr, "failed to set session\n"); - return 2; + if (!config->is_server) { + if (SSL_set_session(ssl.get(), session) != 1) { + return false; + } + } else if (config->async) { + // The internal session cache is disabled, so install the session + // manually. + GetTestState(ssl.get())->pending_session.reset( + SSL_SESSION_up_ref(session)); } } int ret; - do { + if (config->implicit_handshake) { if (config->is_server) { - ret = SSL_accept(ssl); + SSL_set_accept_state(ssl.get()); } else { - ret = SSL_connect(ssl); + SSL_set_connect_state(ssl.get()); + } + } else { + do { + if (config->is_server) { + ret = SSL_accept(ssl.get()); + } else { + ret = SSL_connect(ssl.get()); + } + } while (config->async && RetryAsync(ssl.get(), ret)); + if (ret != 1) { + return false; } - } while (config->async && retry_async(ssl, ret, bio)); - if (ret != 1) { - SSL_free(ssl); - BIO_print_errors_fp(stdout); - return 2; - } - if (is_resume && (!!SSL_session_reused(ssl) == config->expect_session_miss)) { - fprintf(stderr, "session was%s reused\n", - SSL_session_reused(ssl) ? "" : " not"); - return 2; - } + 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; + } - 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 2; + 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 (!early_callback_called) { + if (config->is_server && !GetTestState(ssl.get())->early_callback_called) { fprintf(stderr, "early callback not called\n"); - return 2; + return false; } - } - if (!config->expected_certificate_types.empty()) { - uint8_t *certificate_types; - int num_certificate_types = - SSL_get0_certificate_types(ssl, &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 2; + 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_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 2; + 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_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 2; + 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_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 2; + 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.size() != 64 || - memcmp(config->expected_channel_id.data(), - channel_id, 64) != 0) { - fprintf(stderr, "channel id mismatch\n"); - return 2; + + 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 2; + 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 2; + 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, &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 2; + 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->renegotiate) { if (config->async) { - fprintf(stderr, "--renegotiate is not supported with --async.\n"); - return 2; + fprintf(stderr, "-renegotiate is not supported with -async.\n"); + return false; + } + if (config->implicit_handshake) { + fprintf(stderr, "-renegotiate is not supported with -implicit-handshake.\n"); + return false; } - SSL_renegotiate(ssl); + SSL_renegotiate(ssl.get()); - ret = SSL_do_handshake(ssl); + ret = SSL_do_handshake(ssl.get()); if (ret != 1) { - SSL_free(ssl); - BIO_print_errors_fp(stdout); - return 2; + return false; } - SSL_set_state(ssl, SSL_ST_ACCEPT); - ret = SSL_do_handshake(ssl); + SSL_set_state(ssl.get(), SSL_ST_ACCEPT); + ret = SSL_do_handshake(ssl.get()); if (ret != 1) { - SSL_free(ssl); - BIO_print_errors_fp(stdout); - return 2; + return false; + } + } + + if (config->export_keying_material > 0) { + std::vector result( + static_cast(config->export_keying_material)); + if (!SSL_export_keying_material( + ssl.get(), result.data(), result.size(), + config->export_label.data(), config->export_label.size(), + reinterpret_cast(config->export_context.data()), + config->export_context.size(), config->use_export_context)) { + fprintf(stderr, "failed to export keying material\n"); + return false; + } + if (WriteAll(ssl.get(), result.data(), result.size()) < 0) { + return false; } } if (config->write_different_record_sizes) { if (config->is_dtls) { fprintf(stderr, "write_different_record_sizes not supported for DTLS\n"); - return 6; + return false; } // This mode writes a number of different record sizes in an attempt to // trip up the CBC record splitting code. @@ -621,138 +887,123 @@ static int do_exchange(SSL_SESSION **out_session, 0, 1, 255, 256, 257, 16383, 16384, 16385, 32767, 32768, 32769}; for (size_t i = 0; i < sizeof(kRecordSizes) / sizeof(kRecordSizes[0]); i++) { - int w; const size_t len = kRecordSizes[i]; - size_t off = 0; - if (len > sizeof(buf)) { fprintf(stderr, "Bad kRecordSizes value.\n"); - return 5; + return false; } - - do { - w = SSL_write(ssl, buf + off, len - off); - if (w > 0) { - off += (size_t) w; - } - } while ((config->async && retry_async(ssl, w, bio)) || - (w > 0 && off < len)); - - if (w < 0 || off != len) { - SSL_free(ssl); - BIO_print_errors_fp(stdout); - return 4; + if (WriteAll(ssl.get(), buf, len) < 0) { + return false; } } } else { if (config->shim_writes_first) { - int w; - do { - w = SSL_write(ssl, "hello", 5); - } while (config->async && retry_async(ssl, w, bio)); + if (WriteAll(ssl.get(), reinterpret_cast("hello"), + 5) < 0) { + return false; + } } for (;;) { uint8_t buf[512]; - int n; - do { - n = SSL_read(ssl, buf, sizeof(buf)); - } while (config->async && retry_async(ssl, n, bio)); - int err = SSL_get_error(ssl, n); + 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 3; + return false; } - /* Accept shutdowns with or without close_notify. - * TODO(davidben): Write tests which distinguish these two cases. */ + // 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 3; + return false; } - SSL_free(ssl); - BIO_print_errors_fp(stdout); - return 3; + return false; } - /* Successfully read data. */ + // Successfully read data. if (n <= 0) { fprintf(stderr, "Invalid SSL_get_error output\n"); - return 3; + 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; } - int w; - do { - w = SSL_write(ssl, buf, n); - } while (config->async && retry_async(ssl, w, bio)); - if (w != n) { - SSL_free(ssl); - BIO_print_errors_fp(stdout); - return 4; + if (WriteAll(ssl.get(), buf, n) < 0) { + return false; } } } if (out_session) { - *out_session = SSL_get1_session(ssl); + out_session->reset(SSL_get1_session(ssl.get())); } - SSL_shutdown(ssl); - SSL_free(ssl); - return 0; + SSL_shutdown(ssl.get()); + return true; } int main(int argc, char **argv) { -#if !defined(OPENSSL_WINDOWS) +#if defined(OPENSSL_WINDOWS) + /* Initialize Winsock. */ + WORD wsa_version = MAKEWORD(2, 2); + WSADATA wsa_data; + int wsa_err = WSAStartup(wsa_version, &wsa_data); + if (wsa_err != 0) { + fprintf(stderr, "WSAStartup failed: %d\n", wsa_err); + return 1; + } + if (wsa_data.wVersion != wsa_version) { + fprintf(stderr, "Didn't get expected version: %x\n", wsa_data.wVersion); + return 1; + } +#else signal(SIGPIPE, SIG_IGN); #endif if (!SSL_library_init()) { return 1; } - g_ex_data_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); - if (g_ex_data_index < 0) { + g_config_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); + g_state_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, TestStateExFree); + if (g_config_index < 0 || g_state_index < 0) { return 1; } TestConfig config; if (!ParseConfig(argc - 1, argv + 1, &config)) { - return usage(argv[0]); + return Usage(argv[0]); } - SSL_CTX *ssl_ctx = setup_ctx(&config); - if (ssl_ctx == NULL) { - BIO_print_errors_fp(stdout); + ScopedSSL_CTX ssl_ctx = SetupCtx(&config); + if (!ssl_ctx) { + ERR_print_errors_fp(stderr); return 1; } - SSL_SESSION *session = NULL; - int ret = do_exchange(&session, - ssl_ctx, &config, - false /* is_resume */, - 3 /* fd */, NULL /* session */); - if (ret != 0) { - goto out; + ScopedSSL_SESSION session; + if (!DoExchange(&session, ssl_ctx.get(), &config, false /* is_resume */, + NULL /* session */)) { + ERR_print_errors_fp(stderr); + return 1; } - if (config.resume) { - ret = do_exchange(NULL, - ssl_ctx, &config, - true /* is_resume */, - 4 /* fd */, - config.is_server ? NULL : session); - if (ret != 0) { - goto out; - } + if (config.resume && + !DoExchange(NULL, ssl_ctx.get(), &config, true /* is_resume */, + session.get())) { + ERR_print_errors_fp(stderr); + return 1; } - ret = 0; - -out: - SSL_SESSION_free(session); - SSL_CTX_free(ssl_ctx); - return ret; + return 0; } diff --git a/src/ssl/test/malloc.cc b/src/ssl/test/malloc.cc index 6cc0b33..2ec5582 100644 --- a/src/ssl/test/malloc.cc +++ b/src/ssl/test/malloc.cc @@ -14,15 +14,24 @@ #include +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +#define OPENSSL_ASAN +#endif +#endif + // This file isn't built on ARM or Aarch64 because we link statically in those -// builds and trying to override malloc in a static link doesn't work. -#if defined(__linux__) && !defined(OPENSSL_ARM) && !defined(OPENSSL_AARCH64) +// builds and trying to override malloc in a static link doesn't work. It's also +// disabled on ASan builds as this interferes with ASan's malloc interceptor. +// +// TODO(davidben): See if this and ASan's interceptors can be made to coexist. +#if defined(__linux__) && !defined(OPENSSL_ARM) && \ + !defined(OPENSSL_AARCH64) && !defined(OPENSSL_ASAN) #include +#include #include #include -#include -#include #include @@ -127,4 +136,4 @@ void *realloc(void *ptr, size_t size) { } // extern "C" -#endif /* defined(linux) && !ARM && !AARCH64 */ +#endif /* defined(linux) && !ARM && !AARCH64 && !ASAN */ diff --git a/src/ssl/test/packeted_bio.cc b/src/ssl/test/packeted_bio.cc index 93b2164..e831082 100644 --- a/src/ssl/test/packeted_bio.cc +++ b/src/ssl/test/packeted_bio.cc @@ -15,7 +15,8 @@ #include "packeted_bio.h" #include -#include +#include +#include #include #include @@ -23,58 +24,135 @@ namespace { -extern const BIO_METHOD packeted_bio_method; +extern const BIO_METHOD g_packeted_bio_method; + +const uint8_t kOpcodePacket = 'P'; +const uint8_t kOpcodeTimeout = 'T'; +const uint8_t kOpcodeTimeoutAck = 't'; + +// ReadAll reads |len| bytes from |bio| into |out|. It returns 1 on success and +// 0 or -1 on error. +static int ReadAll(BIO *bio, uint8_t *out, size_t len) { + while (len > 0) { + int chunk_len = INT_MAX; + if (len <= INT_MAX) { + chunk_len = (int)len; + } + int ret = BIO_read(bio, out, chunk_len); + if (ret <= 0) { + return ret; + } + out += ret; + len -= ret; + } + return 1; +} -static int packeted_write(BIO *bio, const char *in, int inl) { +static int PacketedWrite(BIO *bio, const char *in, int inl) { if (bio->next_bio == NULL) { return 0; } BIO_clear_retry_flags(bio); - // Write the length prefix. - uint8_t len_bytes[4]; - len_bytes[0] = (inl >> 24) & 0xff; - len_bytes[1] = (inl >> 16) & 0xff; - len_bytes[2] = (inl >> 8) & 0xff; - len_bytes[3] = inl & 0xff; - int ret = BIO_write(bio->next_bio, len_bytes, sizeof(len_bytes)); + // Write the header. + uint8_t header[5]; + header[0] = kOpcodePacket; + header[1] = (inl >> 24) & 0xff; + header[2] = (inl >> 16) & 0xff; + header[3] = (inl >> 8) & 0xff; + header[4] = inl & 0xff; + int ret = BIO_write(bio->next_bio, header, sizeof(header)); if (ret <= 0) { BIO_copy_next_retry(bio); return ret; } - // Write the buffer. BIOs for which this operation fails are not supported. + // Write the buffer. ret = BIO_write(bio->next_bio, in, inl); + if (ret < 0 || (inl > 0 && ret == 0)) { + BIO_copy_next_retry(bio); + return ret; + } assert(ret == inl); return ret; } -static int packeted_read(BIO *bio, char *out, int outl) { +static int PacketedRead(BIO *bio, char *out, int outl) { if (bio->next_bio == NULL) { return 0; } BIO_clear_retry_flags(bio); + // Read the opcode. + uint8_t opcode; + int ret = ReadAll(bio->next_bio, &opcode, sizeof(opcode)); + if (ret <= 0) { + BIO_copy_next_retry(bio); + return ret; + } + + if (opcode == kOpcodeTimeout) { + // Process the timeout. + uint8_t buf[8]; + ret = ReadAll(bio->next_bio, buf, sizeof(buf)); + if (ret <= 0) { + BIO_copy_next_retry(bio); + return ret; + } + uint64_t timeout = (static_cast(buf[0]) << 56) | + (static_cast(buf[1]) << 48) | + (static_cast(buf[2]) << 40) | + (static_cast(buf[3]) << 32) | + (static_cast(buf[4]) << 24) | + (static_cast(buf[5]) << 16) | + (static_cast(buf[6]) << 8) | + static_cast(buf[7]); + timeout /= 1000; // Convert nanoseconds to microseconds. + timeval *out_timeout = reinterpret_cast(bio->ptr); + assert(out_timeout->tv_usec == 0); + assert(out_timeout->tv_sec == 0); + out_timeout->tv_usec = timeout % 1000000; + out_timeout->tv_sec = timeout / 1000000; + + // Send an ACK to the peer. + ret = BIO_write(bio->next_bio, &kOpcodeTimeoutAck, 1); + if (ret <= 0) { + return ret; + } + assert(ret == 1); + + // Signal to the caller to retry the read, after processing the + // new clock. + BIO_set_retry_read(bio); + return -1; + } + + if (opcode != kOpcodePacket) { + fprintf(stderr, "Unknown opcode, %u\n", opcode); + return -1; + } + // Read the length prefix. uint8_t len_bytes[4]; - int ret = BIO_read(bio->next_bio, &len_bytes, sizeof(len_bytes)); + ret = ReadAll(bio->next_bio, len_bytes, sizeof(len_bytes)); if (ret <= 0) { BIO_copy_next_retry(bio); return ret; } - // BIOs for which a partial length comes back are not supported. - assert(ret == 4); uint32_t len = (len_bytes[0] << 24) | (len_bytes[1] << 16) | (len_bytes[2] << 8) | len_bytes[3]; - char *buf = (char *)OPENSSL_malloc(len); + uint8_t *buf = (uint8_t *)OPENSSL_malloc(len); if (buf == NULL) { return -1; } - ret = BIO_read(bio->next_bio, buf, len); - assert(ret == (int)len); + ret = ReadAll(bio->next_bio, buf, len); + if (ret <= 0) { + fprintf(stderr, "Packeted BIO was truncated\n"); + return -1; + } if (outl > (int)len) { outl = len; @@ -84,7 +162,7 @@ static int packeted_read(BIO *bio, char *out, int outl) { return outl; } -static long packeted_ctrl(BIO *bio, int cmd, long num, void *ptr) { +static long PacketedCtrl(BIO *bio, int cmd, long num, void *ptr) { if (bio->next_bio == NULL) { return 0; } @@ -94,12 +172,12 @@ static long packeted_ctrl(BIO *bio, int cmd, long num, void *ptr) { return ret; } -static int packeted_new(BIO *bio) { +static int PacketedNew(BIO *bio) { bio->init = 1; return 1; } -static int packeted_free(BIO *bio) { +static int PacketedFree(BIO *bio) { if (bio == NULL) { return 0; } @@ -108,28 +186,33 @@ static int packeted_free(BIO *bio) { return 1; } -static long packeted_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) { +static long PacketedCallbackCtrl(BIO *bio, int cmd, bio_info_cb fp) { if (bio->next_bio == NULL) { return 0; } return BIO_callback_ctrl(bio->next_bio, cmd, fp); } -const BIO_METHOD packeted_bio_method = { +const BIO_METHOD g_packeted_bio_method = { BIO_TYPE_FILTER, "packeted bio", - packeted_write, - packeted_read, + PacketedWrite, + PacketedRead, NULL /* puts */, NULL /* gets */, - packeted_ctrl, - packeted_new, - packeted_free, - packeted_callback_ctrl, + PacketedCtrl, + PacketedNew, + PacketedFree, + PacketedCallbackCtrl, }; } // namespace -BIO *packeted_bio_create() { - return BIO_new(&packeted_bio_method); +ScopedBIO PacketedBioCreate(timeval *out_timeout) { + ScopedBIO bio(BIO_new(&g_packeted_bio_method)); + if (!bio) { + return nullptr; + } + bio->ptr = out_timeout; + return bio; } diff --git a/src/ssl/test/packeted_bio.h b/src/ssl/test/packeted_bio.h index 384bd64..30697a5 100644 --- a/src/ssl/test/packeted_bio.h +++ b/src/ssl/test/packeted_bio.h @@ -15,18 +15,30 @@ #ifndef HEADER_PACKETED_BIO #define HEADER_PACKETED_BIO +#include #include +#include "../../crypto/test/scoped_types.h" -// packeted_bio_create creates a filter BIO for testing protocols which expect -// datagram BIOs. It implements a reliable datagram socket and reads and writes -// packets by prefixing each packet with a big-endian 32-bit length. It must be -// layered over a reliable blocking stream BIO. +#if defined(OPENSSL_WINDOWS) +#pragma warning(push, 3) +#include +#pragma warning(pop) +#else +#include +#endif + + +// PacketedBioCreate creates a filter BIO which implements a reliable in-order +// blocking datagram socket. The resulting BIO, on |BIO_read|, may simulate a +// timeout which sets |*out_timeout| to the timeout and fails the read. +// |*out_timeout| must be zero on entry to |BIO_read|; it is an error to not +// apply the timeout before the next |BIO_read|. // -// Note: packeted_bio_create exists because a SOCK_DGRAM socketpair on OS X is -// does not block the caller, unlike on Linux. Writes simply fail with -// ENOBUFS. POSIX also does not guarantee that such sockets are reliable. -BIO *packeted_bio_create(); +// Note: The read timeout simulation is intended to be used with the async BIO +// wrapper. It doesn't simulate BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, used in DTLS's +// blocking mode. +ScopedBIO PacketedBioCreate(timeval *out_timeout); #endif // HEADER_PACKETED_BIO diff --git a/src/ssl/test/runner/chacha20_poly1305.go b/src/ssl/test/runner/chacha20_poly1305.go new file mode 100644 index 0000000..42911d4 --- /dev/null +++ b/src/ssl/test/runner/chacha20_poly1305.go @@ -0,0 +1,159 @@ +package main + +import ( + "crypto/cipher" + "crypto/subtle" + "encoding/binary" + "errors" +) + +// See draft-agl-tls-chacha20poly1305-04 and +// draft-irtf-cfrg-chacha20-poly1305-10. Where the two differ, the +// draft-agl-tls-chacha20poly1305-04 variant is implemented. + +func leftRotate(a uint32, n uint) uint32 { + return (a << n) | (a >> (32 - n)) +} + +func chaChaQuarterRound(state *[16]uint32, a, b, c, d int) { + state[a] += state[b] + state[d] = leftRotate(state[d]^state[a], 16) + + state[c] += state[d] + state[b] = leftRotate(state[b]^state[c], 12) + + state[a] += state[b] + state[d] = leftRotate(state[d]^state[a], 8) + + state[c] += state[d] + state[b] = leftRotate(state[b]^state[c], 7) +} + +func chaCha20Block(state *[16]uint32, out []byte) { + var workingState [16]uint32 + copy(workingState[:], state[:]) + for i := 0; i < 10; i++ { + chaChaQuarterRound(&workingState, 0, 4, 8, 12) + chaChaQuarterRound(&workingState, 1, 5, 9, 13) + chaChaQuarterRound(&workingState, 2, 6, 10, 14) + chaChaQuarterRound(&workingState, 3, 7, 11, 15) + chaChaQuarterRound(&workingState, 0, 5, 10, 15) + chaChaQuarterRound(&workingState, 1, 6, 11, 12) + chaChaQuarterRound(&workingState, 2, 7, 8, 13) + chaChaQuarterRound(&workingState, 3, 4, 9, 14) + } + for i := 0; i < 16; i++ { + binary.LittleEndian.PutUint32(out[i*4:i*4+4], workingState[i]+state[i]) + } +} + +// sliceForAppend takes a slice and a requested number of bytes. It returns a +// slice with the contents of the given slice followed by that many bytes and a +// second slice that aliases into it and contains only the extra bytes. If the +// original slice has sufficient capacity then no allocation is performed. +func sliceForAppend(in []byte, n int) (head, tail []byte) { + if total := len(in) + n; cap(in) >= total { + head = in[:total] + } else { + head = make([]byte, total) + copy(head, in) + } + tail = head[len(in):] + return +} + +type chaCha20Poly1305 struct { + key [32]byte +} + +func newChaCha20Poly1305(key []byte) (cipher.AEAD, error) { + if len(key) != 32 { + return nil, errors.New("bad key length") + } + aead := new(chaCha20Poly1305) + copy(aead.key[:], key) + return aead, nil +} + +func (c *chaCha20Poly1305) NonceSize() int { return 8 } +func (c *chaCha20Poly1305) Overhead() int { return 16 } + +func (c *chaCha20Poly1305) chaCha20(out, in, nonce []byte, counter uint64) { + var state [16]uint32 + state[0] = 0x61707865 + state[1] = 0x3320646e + state[2] = 0x79622d32 + state[3] = 0x6b206574 + for i := 0; i < 8; i++ { + state[4+i] = binary.LittleEndian.Uint32(c.key[i*4 : i*4+4]) + } + state[14] = binary.LittleEndian.Uint32(nonce[0:4]) + state[15] = binary.LittleEndian.Uint32(nonce[4:8]) + + for i := 0; i < len(in); i += 64 { + state[12] = uint32(counter & 0xffffffff) + state[13] = uint32(counter >> 32) + + var tmp [64]byte + chaCha20Block(&state, tmp[:]) + count := 64 + if len(in)-i < count { + count = len(in) - i + } + for j := 0; j < count; j++ { + out[i+j] = in[i+j] ^ tmp[j] + } + + counter++ + } +} + +func (c *chaCha20Poly1305) poly1305(tag *[16]byte, nonce, ciphertext, additionalData []byte) { + input := make([]byte, 0, len(additionalData)+8+len(ciphertext)+8) + input = append(input, additionalData...) + input, out := sliceForAppend(input, 8) + binary.LittleEndian.PutUint64(out, uint64(len(additionalData))) + input = append(input, ciphertext...) + input, out = sliceForAppend(input, 8) + binary.LittleEndian.PutUint64(out, uint64(len(ciphertext))) + + var poly1305Key [32]byte + c.chaCha20(poly1305Key[:], poly1305Key[:], nonce, 0) + + poly1305Sum(tag, input, &poly1305Key) +} + +func (c *chaCha20Poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte { + if len(nonce) != 8 { + panic("Bad nonce length") + } + + ret, out := sliceForAppend(dst, len(plaintext)+16) + c.chaCha20(out[:len(plaintext)], plaintext, nonce, 1) + + var tag [16]byte + c.poly1305(&tag, nonce, out[:len(plaintext)], additionalData) + copy(out[len(plaintext):], tag[:]) + + return ret +} + +func (c *chaCha20Poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { + if len(nonce) != 8 { + panic("Bad nonce length") + } + if len(ciphertext) < 16 { + return nil, errors.New("chacha20: message authentication failed") + } + plaintextLen := len(ciphertext) - 16 + + var tag [16]byte + c.poly1305(&tag, nonce, ciphertext[:plaintextLen], additionalData) + if subtle.ConstantTimeCompare(tag[:], ciphertext[plaintextLen:]) != 1 { + return nil, errors.New("chacha20: message authentication failed") + } + + ret, out := sliceForAppend(dst, plaintextLen) + c.chaCha20(out, ciphertext[:plaintextLen], nonce, 1) + return ret, nil +} diff --git a/src/ssl/test/runner/chacha20_poly1305_test.go b/src/ssl/test/runner/chacha20_poly1305_test.go new file mode 100644 index 0000000..726f482 --- /dev/null +++ b/src/ssl/test/runner/chacha20_poly1305_test.go @@ -0,0 +1,99 @@ +package main + +import ( + "bytes" + "encoding/hex" + "testing" +) + +// See draft-irtf-cfrg-chacha20-poly1305-10, section 2.1.1. +func TestChaChaQuarterRound(t *testing.T) { + state := [16]uint32{0x11111111, 0x01020304, 0x9b8d6f43, 0x01234567} + chaChaQuarterRound(&state, 0, 1, 2, 3) + + a, b, c, d := state[0], state[1], state[2], state[3] + if a != 0xea2a92f4 || b != 0xcb1cf8ce || c != 0x4581472e || d != 0x5881c4bb { + t.Errorf("Incorrect results: %x", state) + } +} + +// See draft-irtf-cfrg-chacha20-poly1305-10, section 2.2.1. +func TestChaChaQuarterRoundState(t *testing.T) { + state := [16]uint32{ + 0x879531e0, 0xc5ecf37d, 0x516461b1, 0xc9a62f8a, + 0x44c20ef3, 0x3390af7f, 0xd9fc690b, 0x2a5f714c, + 0x53372767, 0xb00a5631, 0x974c541a, 0x359e9963, + 0x5c971061, 0x3d631689, 0x2098d9d6, 0x91dbd320, + } + chaChaQuarterRound(&state, 2, 7, 8, 13) + + expected := [16]uint32{ + 0x879531e0, 0xc5ecf37d, 0xbdb886dc, 0xc9a62f8a, + 0x44c20ef3, 0x3390af7f, 0xd9fc690b, 0xcfacafd2, + 0xe46bea80, 0xb00a5631, 0x974c541a, 0x359e9963, + 0x5c971061, 0xccc07c79, 0x2098d9d6, 0x91dbd320, + } + for i := range state { + if state[i] != expected[i] { + t.Errorf("Mismatch at %d: %x vs %x", i, state, expected) + } + } +} + +// See draft-irtf-cfrg-chacha20-poly1305-10, section 2.3.2. +func TestChaCha20Block(t *testing.T) { + state := [16]uint32{ + 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574, + 0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c, + 0x13121110, 0x17161514, 0x1b1a1918, 0x1f1e1d1c, + 0x00000001, 0x09000000, 0x4a000000, 0x00000000, + } + out := make([]byte, 64) + chaCha20Block(&state, out) + + expected := []byte{ + 0x10, 0xf1, 0xe7, 0xe4, 0xd1, 0x3b, 0x59, 0x15, + 0x50, 0x0f, 0xdd, 0x1f, 0xa3, 0x20, 0x71, 0xc4, + 0xc7, 0xd1, 0xf4, 0xc7, 0x33, 0xc0, 0x68, 0x03, + 0x04, 0x22, 0xaa, 0x9a, 0xc3, 0xd4, 0x6c, 0x4e, + 0xd2, 0x82, 0x64, 0x46, 0x07, 0x9f, 0xaa, 0x09, + 0x14, 0xc2, 0xd7, 0x05, 0xd9, 0x8b, 0x02, 0xa2, + 0xb5, 0x12, 0x9c, 0xd1, 0xde, 0x16, 0x4e, 0xb9, + 0xcb, 0xd0, 0x83, 0xe8, 0xa2, 0x50, 0x3c, 0x4e, + } + if !bytes.Equal(out, expected) { + t.Errorf("Got %x, wanted %x", out, expected) + } +} + +// See draft-agl-tls-chacha20poly1305-04, section 7. +func TestChaCha20Poly1305(t *testing.T) { + key, _ := hex.DecodeString("4290bcb154173531f314af57f3be3b5006da371ece272afa1b5dbdd1100a1007") + input, _ := hex.DecodeString("86d09974840bded2a5ca") + nonce, _ := hex.DecodeString("cd7cf67be39c794a") + ad, _ := hex.DecodeString("87e229d4500845a079c0") + output, _ := hex.DecodeString("e3e446f7ede9a19b62a4677dabf4e3d24b876bb284753896e1d6") + + aead, err := newChaCha20Poly1305(key) + if err != nil { + t.Fatal(err) + } + + out, err := aead.Open(nil, nonce, output, ad) + if err != nil { + t.Errorf("Open failed: %s", err) + } else if !bytes.Equal(out, input) { + t.Errorf("Open gave %x, wanted %x", out, input) + } + + out = aead.Seal(nil, nonce, input, ad) + if !bytes.Equal(out, output) { + t.Errorf("Open gave %x, wanted %x", out, output) + } + + out[0]++ + _, err = aead.Open(nil, nonce, out, ad) + if err == nil { + t.Errorf("Open on malformed data unexpectedly succeeded") + } +} diff --git a/src/ssl/test/runner/cipher_suites.go b/src/ssl/test/runner/cipher_suites.go index 89e75c8..162c0c0 100644 --- a/src/ssl/test/runner/cipher_suites.go +++ b/src/ssl/test/runner/cipher_suites.go @@ -62,6 +62,11 @@ const ( suitePSK ) +type tlsAead struct { + cipher.AEAD + explicitNonce bool +} + // A cipherSuite is a specific combination of key agreement, cipher and MAC // function. All cipher suites currently assume RSA key agreement. type cipherSuite struct { @@ -75,12 +80,14 @@ type cipherSuite struct { flags int cipher func(key, iv []byte, isRead bool) interface{} mac func(version uint16, macKey []byte) macFunction - aead func(key, fixedNonce []byte) cipher.AEAD + aead func(key, fixedNonce []byte) *tlsAead } var cipherSuites = []*cipherSuite{ // Ciphersuite order is chosen so that ECDHE comes before plain RSA // and RC4 comes before AES (because of the Lucky13 attack). + {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadCHACHA20POLY1305}, + {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 0, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadCHACHA20POLY1305}, {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM}, {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM}, {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, @@ -95,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}, @@ -216,7 +224,7 @@ func (f *fixedNonceAEAD) Open(out, nonce, plaintext, additionalData []byte) ([]b return f.aead.Open(out, f.openNonce, plaintext, additionalData) } -func aeadAESGCM(key, fixedNonce []byte) cipher.AEAD { +func aeadAESGCM(key, fixedNonce []byte) *tlsAead { aes, err := aes.NewCipher(key) if err != nil { panic(err) @@ -230,7 +238,15 @@ func aeadAESGCM(key, fixedNonce []byte) cipher.AEAD { copy(nonce1, fixedNonce) copy(nonce2, fixedNonce) - return &fixedNonceAEAD{nonce1, nonce2, aead} + return &tlsAead{&fixedNonceAEAD{nonce1, nonce2, aead}, true} +} + +func aeadCHACHA20POLY1305(key, fixedNonce []byte) *tlsAead { + aead, err := newChaCha20Poly1305(key) + if err != nil { + panic(err) + } + return &tlsAead{aead, false} } // ssl30MAC implements the SSLv3 MAC function, as defined in @@ -289,7 +305,7 @@ func (s tls10MAC) MAC(digestBuf, seq, header, length, data []byte) []byte { } func rsaKA(version uint16) keyAgreement { - return &rsaKeyAgreement{} + return &rsaKeyAgreement{version: version} } func ecdheECDSAKA(version uint16) keyAgreement { @@ -391,5 +407,8 @@ const ( // Additional cipher suite IDs, not IANA-assigned. const ( - TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0xcafe + 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 7aaf9a2..4ac7250 100644 --- a/src/ssl/test/runner/common.go +++ b/src/ssl/test/runner/common.go @@ -97,6 +97,7 @@ const ( type CurveID uint16 const ( + CurveP224 CurveID = 21 CurveP256 CurveID = 23 CurveP384 CurveID = 24 CurveP521 CurveID = 25 @@ -429,15 +430,32 @@ type ProtocolBugs struct { // ServerKeyExchange. UnauthenticatedECDH bool + // SkipHelloVerifyRequest causes a DTLS server to skip the + // HelloVerifyRequest message. + SkipHelloVerifyRequest bool + + // SkipCertificateStatus, if true, causes the server to skip the + // CertificateStatus message. This is legal because CertificateStatus is + // optional, even with a status_request in ServerHello. + SkipCertificateStatus bool + // SkipServerKeyExchange causes the server to skip sending // ServerKeyExchange messages. SkipServerKeyExchange bool + // SkipNewSessionTicket causes the server to skip sending the + // NewSessionTicket message despite promising to in ServerHello. + SkipNewSessionTicket bool + // SkipChangeCipherSpec causes the implementation to skip // sending the ChangeCipherSpec message (and adjusting cipher // state accordingly for the Finished message). SkipChangeCipherSpec bool + // SkipFinished causes the implementation to skip sending the Finished + // message. + SkipFinished bool + // EarlyChangeCipherSpec causes the client to send an early // ChangeCipherSpec message before the ClientKeyExchange. A value of // zero disables this behavior. One and two configure variants for 0.9.8 @@ -449,10 +467,6 @@ type ProtocolBugs struct { // messages. FragmentAcrossChangeCipherSpec bool - // SkipNewSessionTicket causes the server to skip sending the - // NewSessionTicket message despite promising to in ServerHello. - SkipNewSessionTicket bool - // SendV2ClientHello causes the client to send a V2ClientHello // instead of a normal ClientHello. SendV2ClientHello bool @@ -475,8 +489,9 @@ type ProtocolBugs struct { // two records. FragmentAlert bool - // SendSpuriousAlert will cause an spurious, unwanted alert to be sent. - SendSpuriousAlert bool + // SendSpuriousAlert, if non-zero, will cause an spurious, unwanted + // alert to be sent. + SendSpuriousAlert alert // RsaClientKeyExchangeVersion, if non-zero, causes the client to send a // ClientKeyExchange with the specified version rather than the @@ -491,16 +506,19 @@ type ProtocolBugs struct { // TLS version in the ClientHello than the maximum supported version. SendClientVersion uint16 - // SkipHelloVerifyRequest causes a DTLS server to skip the - // HelloVerifyRequest message. - SkipHelloVerifyRequest bool - // ExpectFalseStart causes the server to, on full handshakes, // expect the peer to False Start; the server Finished message // isn't sent until we receive an application data record // from the peer. ExpectFalseStart bool + // AlertBeforeFalseStartTest, if non-zero, causes the server to, on full + // handshakes, send an alert just before reading the application data + // record to test False Start. This can be used in a negative False + // Start test to determine whether the peer processed the alert (and + // closed the connection) before or after sending app data. + AlertBeforeFalseStartTest alert + // SSL3RSAKeyExchange causes the client to always send an RSA // ClientKeyExchange message without the two-byte length // prefix, as if it were SSL3. @@ -557,9 +575,10 @@ type ProtocolBugs struct { // retransmit at the record layer. SequenceNumberIncrement uint64 - // RSAServerKeyExchange, if true, causes the server to send a - // ServerKeyExchange message in the plain RSA key exchange. - RSAServerKeyExchange bool + // RSAEphemeralKey, if true, causes the server to send a + // ServerKeyExchange message containing an ephemeral key (as in + // RSA_EXPORT) in the plain RSA key exchange. + RSAEphemeralKey bool // SRTPMasterKeyIdentifer, if not empty, is the SRTP MKI value that the // client offers when negotiating SRTP. MKI support is still missing so @@ -578,6 +597,10 @@ type ProtocolBugs struct { // still be enforced. NoSignatureAndHashes bool + // NoSupportedCurves, if true, causes the client to omit the + // supported_curves extension. + NoSupportedCurves bool + // RequireSameRenegoClientVersion, if true, causes the server // to require that all ClientHellos match in offered version // across a renego. @@ -603,6 +626,87 @@ type ProtocolBugs struct { // AppDataAfterChangeCipherSpec, if not null, causes application data to // be sent immediately after ChangeCipherSpec. AppDataAfterChangeCipherSpec []byte + + // AlertAfterChangeCipherSpec, if non-zero, causes an alert to be sent + // immediately after ChangeCipherSpec. + AlertAfterChangeCipherSpec alert + + // TimeoutSchedule is the schedule of packet drops and simulated + // timeouts for before each handshake leg from the peer. + TimeoutSchedule []time.Duration + + // PacketAdaptor is the packetAdaptor to use to simulate timeouts. + PacketAdaptor *packetAdaptor + + // ReorderHandshakeFragments, if true, causes handshake fragments in + // DTLS to overlap and be sent in the wrong order. It also causes + // pre-CCS flights to be sent twice. (Post-CCS flights consist of + // Finished and will trigger a spurious retransmit.) + ReorderHandshakeFragments bool + + // MixCompleteMessageWithFragments, if true, causes handshake + // messages in DTLS to redundantly both fragment the message + // and include a copy of the full one. + MixCompleteMessageWithFragments bool + + // SendInvalidRecordType, if true, causes a record with an invalid + // content type to be sent immediately following the handshake. + SendInvalidRecordType bool + + // WrongCertificateMessageType, if true, causes Certificate message to + // be sent with the wrong message type. + WrongCertificateMessageType bool + + // FragmentMessageTypeMismatch, if true, causes all non-initial + // handshake fragments in DTLS to have the wrong message type. + FragmentMessageTypeMismatch bool + + // FragmentMessageLengthMismatch, if true, causes all non-initial + // handshake fragments in DTLS to have the wrong message length. + FragmentMessageLengthMismatch bool + + // 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. + SendEmptyFragments bool + + // NeverResumeOnRenego, if true, causes renegotiations to always be full + // handshakes. + NeverResumeOnRenego bool + + // NoSignatureAlgorithmsOnRenego, if true, causes renegotiations to omit + // the signature_algorithms extension. + NoSignatureAlgorithmsOnRenego bool + + // IgnorePeerCipherPreferences, if true, causes the peer's cipher + // preferences to be ignored. + IgnorePeerCipherPreferences bool + + // IgnorePeerSignatureAlgorithmPreferences, if true, causes the peer's + // signature algorithm preferences to be ignored. + IgnorePeerSignatureAlgorithmPreferences bool + + // IgnorePeerCurvePreferences, if true, causes the peer's curve + // 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 } func (c *Config) serverInit() { diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go index d4a6817..fd198ca 100644 --- a/src/ssl/test/runner/conn.go +++ b/src/ssl/test/runner/conn.go @@ -37,14 +37,16 @@ type Conn struct { handshakeComplete bool didResume bool // whether this connection was a session resumption extendedMasterSecret bool // whether this session used an extended master secret - cipherSuite uint16 + cipherSuite *cipherSuite ocspResponse []byte // stapled OCSP response peerCertificates []*x509.Certificate // verifiedChains contains the certificate chains that we built, as // opposed to the ones presented by the server. verifiedChains [][]*x509.Certificate // serverName contains the server name indicated by the client, if any. - serverName string + serverName string + clientRandom, serverRandom [32]byte + masterSecret [48]byte clientProtocol string clientProtocolFallback bool @@ -69,8 +71,9 @@ type Conn struct { // DTLS state sendHandshakeSeq uint16 recvHandshakeSeq uint16 - handMsg []byte // pending assembled handshake message - handMsgLen int // handshake message length, not including the header + handMsg []byte // pending assembled handshake message + handMsgLen int // handshake message length, not including the header + pendingFragments [][]byte // pending outgoing handshake fragments. tmp [16]byte } @@ -131,6 +134,7 @@ type halfConn struct { nextCipher interface{} // next encryption state nextMac macFunction // next MAC algorithm + nextSeq [6]byte // next epoch's starting sequence number in DTLS // used to save allocating a new buffer for each MAC. inDigestBuf, outDigestBuf []byte @@ -200,10 +204,20 @@ func (hc *halfConn) incSeq(isOutgoing bool) { } } -// incEpoch resets the sequence number. In DTLS, it increments the -// epoch half of the sequence number. +// incNextSeq increments the starting sequence number for the next epoch. +func (hc *halfConn) incNextSeq() { + for i := len(hc.nextSeq) - 1; i >= 0; i-- { + hc.nextSeq[i]++ + if hc.nextSeq[i] != 0 { + return + } + } + panic("TLS: sequence number wraparound") +} + +// incEpoch resets the sequence number. In DTLS, it also increments the epoch +// half of the sequence number. func (hc *halfConn) incEpoch() { - limit := 0 if hc.isDTLS { for i := 1; i >= 0; i-- { hc.seq[i]++ @@ -214,11 +228,14 @@ func (hc *halfConn) incEpoch() { panic("TLS: epoch number wraparound") } } - limit = 2 - } - seq := hc.seq[limit:] - for i := range seq { - seq[i] = 0 + copy(hc.seq[2:], hc.nextSeq[:]) + for i := range hc.nextSeq { + hc.nextSeq[i] = 0 + } + } else { + for i := range hc.seq { + hc.seq[i] = 0 + } } } @@ -321,13 +338,16 @@ func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert) switch c := hc.cipher.(type) { case cipher.Stream: c.XORKeyStream(payload, payload) - case cipher.AEAD: - explicitIVLen = 8 - if len(payload) < explicitIVLen { - return false, 0, alertBadRecordMAC + case *tlsAead: + nonce := seq + if c.explicitNonce { + explicitIVLen = 8 + if len(payload) < explicitIVLen { + return false, 0, alertBadRecordMAC + } + nonce = payload[:8] + payload = payload[8:] } - nonce := payload[:8] - payload = payload[8:] var additionalData [13]byte copy(additionalData[:], seq) @@ -451,10 +471,13 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) { switch c := hc.cipher.(type) { case cipher.Stream: c.XORKeyStream(payload, payload) - case cipher.AEAD: + case *tlsAead: payloadLen := len(b.data) - recordHeaderLen - explicitIVLen b.resize(len(b.data) + c.Overhead()) - nonce := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen] + nonce := hc.seq[:] + if c.explicitNonce { + nonce = b.data[recordHeaderLen : recordHeaderLen+explicitIVLen] + } payload := b.data[recordHeaderLen+explicitIVLen:] payload = payload[:payloadLen] @@ -756,11 +779,8 @@ Again: if typ != want { // A client might need to process a HelloRequest from // the server, thus receiving a handshake message when - // application data is expected is ok. Moreover, a DTLS - // peer who sends Finished second may retransmit the - // final leg. BoringSSL retrainsmits on an internal - // timer, so this may also occur in test code. - if !c.isClient && !c.isDTLS { + // application data is expected is ok. + if !c.isClient { return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation)) } } @@ -817,6 +837,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) } @@ -851,7 +878,7 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) { } } if explicitIVLen == 0 { - if _, ok := c.out.cipher.(cipher.AEAD); ok { + if aead, ok := c.out.cipher.(*tlsAead); ok && aead.explicitNonce { explicitIVLen = 8 // The AES-GCM construction in TLS has an // explicit nonce so that the nonce can be @@ -1003,6 +1030,67 @@ func (c *Conn) readHandshake() (interface{}, error) { return m, nil } +// skipPacket processes all the DTLS records in packet. It updates +// sequence number expectations but otherwise ignores them. +func (c *Conn) skipPacket(packet []byte) error { + for len(packet) > 0 { + // 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 + // simplicity and because a previous test with one shorter + // timeout schedule would have done so.) + epoch := packet[3:5] + seq := packet[5:11] + length := uint16(packet[11])<<8 | uint16(packet[12]) + if bytes.Equal(c.in.seq[:2], epoch) { + if !bytes.Equal(c.in.seq[2:], seq) { + return errors.New("tls: sequence mismatch") + } + c.in.incSeq(false) + } else { + if !bytes.Equal(c.in.nextSeq[:], seq) { + return errors.New("tls: sequence mismatch") + } + c.in.incNextSeq() + } + packet = packet[13+length:] + } + return nil +} + +// simulatePacketLoss simulates the loss of a handshake leg from the +// peer based on the schedule in c.config.Bugs. If resendFunc is +// non-nil, it is called after each simulated timeout to retransmit +// handshake messages from the local end. This is used in cases where +// the peer retransmits on a stale Finished rather than a timeout. +func (c *Conn) simulatePacketLoss(resendFunc func()) error { + if len(c.config.Bugs.TimeoutSchedule) == 0 { + return nil + } + if !c.isDTLS { + return errors.New("tls: TimeoutSchedule may only be set in DTLS") + } + if c.config.Bugs.PacketAdaptor == nil { + return errors.New("tls: TimeoutSchedule set without PacketAdapter") + } + for _, timeout := range c.config.Bugs.TimeoutSchedule { + // Simulate a timeout. + packets, err := c.config.Bugs.PacketAdaptor.SendReadTimeout(timeout) + if err != nil { + return err + } + for _, packet := range packets { + if err := c.skipPacket(packet); err != nil { + return err + } + } + if resendFunc != nil { + resendFunc() + } + } + return nil +} + // Write writes data to the connection. func (c *Conn) Write(b []byte) (int, error) { if err := c.Handshake(); err != nil { @@ -1020,8 +1108,8 @@ func (c *Conn) Write(b []byte) (int, error) { return 0, alertInternalError } - if c.config.Bugs.SendSpuriousAlert { - c.sendAlertLocked(alertRecordOverflow) + if c.config.Bugs.SendSpuriousAlert != 0 { + c.sendAlertLocked(c.config.Bugs.SendSpuriousAlert) } // SSL 3.0 and TLS 1.0 are susceptible to a chosen-plaintext @@ -1096,9 +1184,9 @@ func (c *Conn) Read(b []byte) (n int, err error) { // Soft error, like EAGAIN return 0, err } - if c.hand.Len() > 0 && !c.isDTLS { + if c.hand.Len() > 0 { // We received handshake bytes, indicating the - // start of a renegotiation or a DTLS retransmit. + // start of a renegotiation. if err := c.handleRenegotiation(); err != nil { return 0, err } @@ -1177,6 +1265,9 @@ func (c *Conn) Handshake() error { } else { c.handshakeErr = c.serverHandshake() } + if c.handshakeErr == nil && c.config.Bugs.SendInvalidRecordType { + c.writeRecord(recordType(42), []byte("invalid record")) + } return c.handshakeErr } @@ -1193,7 +1284,7 @@ func (c *Conn) ConnectionState() ConnectionState { state.DidResume = c.didResume state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback state.NegotiatedProtocolFromALPN = c.usedALPN - state.CipherSuite = c.cipherSuite + state.CipherSuite = c.cipherSuite.id state.PeerCertificates = c.peerCertificates state.VerifiedChains = c.verifiedChains state.ServerName = c.serverName @@ -1227,3 +1318,28 @@ func (c *Conn) VerifyHostname(host string) error { } return c.peerCertificates[0].VerifyHostname(host) } + +// ExportKeyingMaterial exports keying material from the current connection +// state, as per RFC 5705. +func (c *Conn) ExportKeyingMaterial(length int, label, context []byte, useContext bool) ([]byte, error) { + c.handshakeMutex.Lock() + defer c.handshakeMutex.Unlock() + if !c.handshakeComplete { + return nil, errors.New("tls: handshake has not yet been performed") + } + + seedLen := len(c.clientRandom) + len(c.serverRandom) + if useContext { + seedLen += 2 + len(context) + } + seed := make([]byte, 0, seedLen) + seed = append(seed, c.clientRandom[:]...) + seed = append(seed, c.serverRandom[:]...) + if useContext { + seed = append(seed, byte(len(context)>>8), byte(len(context))) + seed = append(seed, context...) + } + result := make([]byte, length) + prfForVersion(c.vers, c.cipherSuite)(result, c.masterSecret[:], label, seed) + return result, nil +} diff --git a/src/ssl/test/runner/dtls.go b/src/ssl/test/runner/dtls.go index a395980..85c4247 100644 --- a/src/ssl/test/runner/dtls.go +++ b/src/ssl/test/runner/dtls.go @@ -16,10 +16,10 @@ package main import ( "bytes" - "crypto/cipher" "errors" "fmt" "io" + "math/rand" "net" ) @@ -38,7 +38,6 @@ func wireToVersion(vers uint16, isDTLS bool) uint16 { } func (c *Conn) dtlsDoReadRecord(want recordType) (recordType, *block, error) { -Again: recordHeaderLen := dtlsRecordHeaderLen if c.rawInput == nil { @@ -82,13 +81,6 @@ Again: } } seq := b.data[3:11] - if !bytes.Equal(seq[:2], c.in.seq[:2]) { - // If the epoch didn't match, silently drop the record. - // BoringSSL retransmits on an internal timer, so it may flakily - // revisit the previous epoch if retransmiting ChangeCipherSpec - // and Finished. - goto Again - } // For test purposes, we assume a reliable channel. Require // that the explicit sequence number matches the incrementing // one we maintain. A real implementation would maintain a @@ -113,127 +105,196 @@ Again: return typ, b, nil } +func (c *Conn) makeFragment(header, data []byte, fragOffset, fragLen int) []byte { + fragment := make([]byte, 0, 12+fragLen) + fragment = append(fragment, header...) + fragment = append(fragment, byte(c.sendHandshakeSeq>>8), byte(c.sendHandshakeSeq)) + fragment = append(fragment, byte(fragOffset>>16), byte(fragOffset>>8), byte(fragOffset)) + fragment = append(fragment, byte(fragLen>>16), byte(fragLen>>8), byte(fragLen)) + fragment = append(fragment, data[fragOffset:fragOffset+fragLen]...) + return fragment +} + func (c *Conn) dtlsWriteRecord(typ recordType, data []byte) (n int, err error) { - recordHeaderLen := dtlsRecordHeaderLen + if typ != recordTypeHandshake { + // Only handshake messages are fragmented. + return c.dtlsWriteRawRecord(typ, data) + } + maxLen := c.config.Bugs.MaxHandshakeRecordLength if maxLen <= 0 { maxLen = 1024 } - b := c.out.newBlock() + // Handshake messages have to be modified to include fragment + // offset and length and with the header replicated. Save the + // TLS header here. + // + // TODO(davidben): This assumes that data contains exactly one + // handshake message. This is incompatible with + // FragmentAcrossChangeCipherSpec. (Which is unfortunate + // because OpenSSL's DTLS implementation will probably accept + // such fragmentation and could do with a fix + tests.) + header := data[:4] + data = data[4:] - var header []byte - if typ == recordTypeHandshake { - // Handshake messages have to be modified to include - // fragment offset and length and with the header - // replicated. Save the header here. - // - // TODO(davidben): This assumes that data contains - // exactly one handshake message. This is incompatible - // with FragmentAcrossChangeCipherSpec. (Which is - // unfortunate because OpenSSL's DTLS implementation - // will probably accept such fragmentation and could - // do with a fix + tests.) - if len(data) < 4 { - // This should not happen. - panic(data) - } - header = data[:4] - data = data[4:] + isFinished := header[0] == typeFinished + + if c.config.Bugs.SendEmptyFragments { + fragment := c.makeFragment(header, data, 0, 0) + c.pendingFragments = append(c.pendingFragments, fragment) } firstRun := true - for firstRun || len(data) > 0 { + fragOffset := 0 + for firstRun || fragOffset < len(data) { firstRun = false - m := len(data) - var fragment []byte - // Handshake messages get fragmented. Other records we - // pass-through as is. DTLS should be a packet - // interface. - if typ == recordTypeHandshake { - if m > maxLen { - m = maxLen - } + fragLen := len(data) - fragOffset + if fragLen > maxLen { + fragLen = maxLen + } - // Standard handshake header. - fragment = make([]byte, 0, 12+m) - fragment = append(fragment, header...) - // message_seq - fragment = append(fragment, byte(c.sendHandshakeSeq>>8), byte(c.sendHandshakeSeq)) - // fragment_offset - fragment = append(fragment, byte(n>>16), byte(n>>8), byte(n)) - // fragment_length - fragment = append(fragment, byte(m>>16), byte(m>>8), byte(m)) - fragment = append(fragment, data[:m]...) - } else { - fragment = data[:m] + fragment := c.makeFragment(header, data, fragOffset, fragLen) + if c.config.Bugs.FragmentMessageTypeMismatch && fragOffset > 0 { + fragment[0]++ + } + if c.config.Bugs.FragmentMessageLengthMismatch && fragOffset > 0 { + fragment[3]++ } - // Send the fragment. - explicitIVLen := 0 - explicitIVIsSeq := false + // Buffer the fragment for later. They will be sent (and + // reordered) on flush. + c.pendingFragments = append(c.pendingFragments, fragment) + if c.config.Bugs.ReorderHandshakeFragments { + // Don't duplicate Finished to avoid the peer + // interpreting it as a retransmit request. + if !isFinished { + c.pendingFragments = append(c.pendingFragments, fragment) + } - if cbc, ok := c.out.cipher.(cbcMode); ok { - // Block cipher modes have an explicit IV. - explicitIVLen = cbc.BlockSize() - } else if _, ok := c.out.cipher.(cipher.AEAD); ok { - explicitIVLen = 8 - // The AES-GCM construction in TLS has an - // explicit nonce so that the nonce can be - // random. However, the nonce is only 8 bytes - // which is too small for a secure, random - // nonce. Therefore we use the sequence number - // as the nonce. - explicitIVIsSeq = true - } else if c.out.cipher != nil { - panic("Unknown cipher") + if fragLen > (maxLen+1)/2 { + // Overlap each fragment by half. + fragLen = (maxLen + 1) / 2 + } } - b.resize(recordHeaderLen + explicitIVLen + len(fragment)) - b.data[0] = byte(typ) - vers := c.vers - if vers == 0 { - // Some TLS servers fail if the record version is - // greater than TLS 1.0 for the initial ClientHello. - vers = VersionTLS10 + fragOffset += fragLen + n += fragLen + } + if !isFinished && c.config.Bugs.MixCompleteMessageWithFragments { + fragment := c.makeFragment(header, data, 0, len(data)) + c.pendingFragments = append(c.pendingFragments, fragment) + } + + // Increment the handshake sequence number for the next + // handshake message. + c.sendHandshakeSeq++ + return +} + +func (c *Conn) dtlsFlushHandshake() error { + if !c.isDTLS { + return nil + } + + var fragments [][]byte + fragments, c.pendingFragments = c.pendingFragments, fragments + + if c.config.Bugs.ReorderHandshakeFragments { + perm := rand.New(rand.NewSource(0)).Perm(len(fragments)) + tmp := make([][]byte, len(fragments)) + for i := range tmp { + tmp[i] = fragments[perm[i]] } - vers = versionToWire(vers, c.isDTLS) - 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.seq[0:]) - b.data[11] = byte(len(fragment) >> 8) - b.data[12] = byte(len(fragment)) - if explicitIVLen > 0 { - explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen] - if explicitIVIsSeq { - copy(explicitIV, c.out.seq[:]) - } else { - if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil { - break - } + fragments = tmp + } + + // Send them all. + for _, fragment := range fragments { + if c.config.Bugs.SplitFragmentHeader { + if _, err := c.dtlsWriteRawRecord(recordTypeHandshake, fragment[:2]); err != nil { + return err } + fragment = fragment[2:] + } else if c.config.Bugs.SplitFragmentBody && len(fragment) > 12 { + if _, err := c.dtlsWriteRawRecord(recordTypeHandshake, fragment[:13]); err != nil { + return err + } + fragment = fragment[13:] } - copy(b.data[recordHeaderLen+explicitIVLen:], fragment) - c.out.encrypt(b, explicitIVLen) // TODO(davidben): A real DTLS implementation needs to - // retransmit handshake messages. For testing - // purposes, we don't actually care. - _, err = c.conn.Write(b.data) - if err != nil { - break + // retransmit handshake messages. For testing purposes, we don't + // actually care. + if _, err := c.dtlsWriteRawRecord(recordTypeHandshake, fragment); err != nil { + return err } - n += m - data = data[m:] } - c.out.freeBlock(b) + return nil +} - // Increment the handshake sequence number for the next - // handshake message. - if typ == recordTypeHandshake { - c.sendHandshakeSeq++ +func (c *Conn) dtlsWriteRawRecord(typ recordType, data []byte) (n int, err error) { + recordHeaderLen := dtlsRecordHeaderLen + maxLen := c.config.Bugs.MaxHandshakeRecordLength + if maxLen <= 0 { + maxLen = 1024 } + b := c.out.newBlock() + + explicitIVLen := 0 + explicitIVIsSeq := false + + if cbc, ok := c.out.cipher.(cbcMode); ok { + // Block cipher modes have an explicit IV. + explicitIVLen = cbc.BlockSize() + } else if aead, ok := c.out.cipher.(*tlsAead); ok { + if aead.explicitNonce { + explicitIVLen = 8 + // The AES-GCM construction in TLS has an explicit nonce so that + // the nonce can be random. However, the nonce is only 8 bytes + // which is too small for a secure, random nonce. Therefore we + // use the sequence number as the nonce. + explicitIVIsSeq = true + } + } else if c.out.cipher != nil { + panic("Unknown cipher") + } + b.resize(recordHeaderLen + explicitIVLen + len(data)) + b.data[0] = byte(typ) + vers := c.vers + if vers == 0 { + // Some TLS servers fail if the record version is greater than + // TLS 1.0 for the initial ClientHello. + vers = VersionTLS10 + } + vers = versionToWire(vers, c.isDTLS) + 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.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.seq[:]) + } else { + if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil { + return + } + } + } + copy(b.data[recordHeaderLen+explicitIVLen:], data) + c.out.encrypt(b, explicitIVLen) + + _, err = c.conn.Write(b.data) + if err != nil { + return + } + n = len(data) + + c.out.freeBlock(b) + if typ == recordTypeChangeCipherSpec { err = c.out.changeCipherSpec(c.config) if err != nil { @@ -250,9 +311,9 @@ func (c *Conn) dtlsWriteRecord(typ recordType, data []byte) (n int, err error) { func (c *Conn) dtlsDoReadHandshake() ([]byte, error) { // Assemble a full handshake message. For test purposes, this - // implementation assumes fragments arrive in order, but tolerates - // retransmits. It may need to be cleverer if we ever test BoringSSL's - // retransmit behavior. + // implementation assumes fragments arrive in order. It may + // need to be cleverer if we ever test BoringSSL's retransmit + // behavior. for len(c.handMsg) < 4+c.handMsgLen { // Get a new handshake record if the previous has been // exhausted. @@ -281,16 +342,9 @@ func (c *Conn) dtlsDoReadHandshake() ([]byte, error) { } fragment := c.hand.Next(fragLen) - if fragSeq < c.recvHandshakeSeq { - // BoringSSL retransmits based on an internal timer, so - // it may flakily retransmit part of a handshake - // message. Ignore those fragments. - // - // TODO(davidben): Revise this if BoringSSL's retransmit - // logic is made more deterministic. - continue - } else if fragSeq > c.recvHandshakeSeq { - return nil, errors.New("dtls: handshake messages sent out of order") + // Check it's a fragment for the right message. + if fragSeq != c.recvHandshakeSeq { + return nil, errors.New("dtls: bad handshake sequence number") } // Check that the length is consistent. diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go index f297fc1..0dac05d 100644 --- a/src/ssl/test/runner/handshake_client.go +++ b/src/ssl/test/runner/handshake_client.go @@ -6,7 +6,6 @@ package main import ( "bytes" - "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rsa" @@ -22,13 +21,14 @@ import ( ) type clientHandshakeState struct { - c *Conn - serverHello *serverHelloMsg - hello *clientHelloMsg - suite *cipherSuite - finishedHash finishedHash - masterSecret []byte - session *ClientSessionState + c *Conn + serverHello *serverHelloMsg + hello *clientHelloMsg + suite *cipherSuite + finishedHash finishedHash + masterSecret []byte + session *ClientSessionState + finishedBytes []byte } func (c *Conn) clientHandshake() error { @@ -83,6 +83,10 @@ func (c *Conn) clientHandshake() error { hello.extendedMasterSecret = false } + if c.config.Bugs.NoSupportedCurves { + hello.supportedCurves = nil + } + if len(c.clientVerify) > 0 && !c.config.Bugs.EmptyRenegotiationInfo { if c.config.Bugs.BadRenegotiationInfo { hello.secureRenegotiation = append(hello.secureRenegotiation, c.clientVerify...) @@ -129,13 +133,16 @@ NextCipherSuite: return errors.New("tls: short read from Rand: " + err.Error()) } - if hello.vers >= VersionTLS12 && !c.config.Bugs.NoSignatureAndHashes { + if hello.vers >= VersionTLS12 && !c.config.Bugs.NoSignatureAndHashes && (c.cipherSuite == nil || !c.config.Bugs.NoSignatureAlgorithmsOnRenego) { hello.signatureAndHashes = c.config.signatureAndHashesForClient() } var session *ClientSessionState var cacheKey string sessionCache := c.config.ClientSessionCache + if c.config.Bugs.NeverResumeOnRenego && c.cipherSuite != nil { + sessionCache = nil + } if sessionCache != nil { hello.ticketSupported = !c.config.SessionTicketsDisabled @@ -213,7 +220,11 @@ NextCipherSuite: helloBytes = hello.marshal() c.writeRecord(recordTypeHandshake, helloBytes) } + c.dtlsFlushHandshake() + if err := c.simulatePacketLoss(nil); err != nil { + return err + } msg, err := c.readHandshake() if err != nil { return err @@ -233,7 +244,11 @@ NextCipherSuite: hello.cookie = helloVerifyRequest.cookie helloBytes = hello.marshal() c.writeRecord(recordTypeHandshake, helloBytes) + c.dtlsFlushHandshake() + if err := c.simulatePacketLoss(nil); err != nil { + return err + } msg, err = c.readHandshake() if err != nil { return err @@ -317,6 +332,15 @@ NextCipherSuite: if err := hs.sendFinished(isResume); err != nil { return err } + // Most retransmits are triggered by a timeout, but the final + // leg of the handshake is retransmited upon re-receiving a + // Finished. + if err := c.simulatePacketLoss(func() { + c.writeRecord(recordTypeHandshake, hs.finishedBytes) + c.dtlsFlushHandshake() + }); err != nil { + return err + } if err := hs.readSessionTicket(); err != nil { return err } @@ -331,7 +355,10 @@ NextCipherSuite: c.didResume = isResume c.handshakeComplete = true - c.cipherSuite = suite.id + c.cipherSuite = suite + copy(c.clientRandom[:], hs.hello.random) + copy(c.serverRandom[:], hs.serverHello.random) + copy(c.masterSecret[:], hs.masterSecret) return nil } @@ -559,33 +586,39 @@ func (hs *clientHandshakeState) doFullHandshake() error { hasSignatureAndHash: c.vers >= VersionTLS12, } + // Determine the hash to sign. + var signatureType uint8 + switch c.config.Certificates[0].PrivateKey.(type) { + case *ecdsa.PrivateKey: + signatureType = signatureECDSA + case *rsa.PrivateKey: + signatureType = signatureRSA + default: + c.sendAlert(alertInternalError) + return errors.New("unknown private key type") + } + if c.config.Bugs.IgnorePeerSignatureAlgorithmPreferences { + certReq.signatureAndHashes = c.config.signatureAndHashesForClient() + } + certVerify.signatureAndHash, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.signatureAndHashes, c.config.signatureAndHashesForClient(), signatureType) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + digest, hashFunc, err := hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash, hs.masterSecret) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + switch key := c.config.Certificates[0].PrivateKey.(type) { case *ecdsa.PrivateKey: - certVerify.signatureAndHash, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.signatureAndHashes, signatureECDSA) - if err != nil { - break - } - var digest []byte - digest, _, err = hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash, hs.masterSecret) - if err != nil { - break - } var r, s *big.Int r, s, err = ecdsa.Sign(c.config.rand(), key, digest) if err == nil { signed, err = asn1.Marshal(ecdsaSignature{r, s}) } case *rsa.PrivateKey: - certVerify.signatureAndHash, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.signatureAndHashes, signatureRSA) - if err != nil { - break - } - var digest []byte - var hashFunc crypto.Hash - digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash, hs.masterSecret) - if err != nil { - break - } signed, err = rsa.SignPKCS1v15(c.config.rand(), key, hashFunc, digest) default: err = errors.New("unknown private key type") @@ -599,6 +632,7 @@ func (hs *clientHandshakeState) doFullHandshake() error { hs.writeClientHash(certVerify.marshal()) c.writeRecord(recordTypeHandshake, certVerify.marshal()) } + c.dtlsFlushHandshake() hs.finishedHash.discardHandshakeBuffer() @@ -825,15 +859,19 @@ func (hs *clientHandshakeState) sendFinished(isResume bool) error { } else { finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret) } + if c.config.Bugs.BadFinished { + finished.verifyData[0]++ + } c.clientVerify = append(c.clientVerify[:0], finished.verifyData...) - finishedBytes := finished.marshal() - hs.writeHash(finishedBytes, seqno) - postCCSBytes = append(postCCSBytes, finishedBytes...) + hs.finishedBytes = finished.marshal() + hs.writeHash(hs.finishedBytes, seqno) + postCCSBytes = append(postCCSBytes, hs.finishedBytes...) if c.config.Bugs.FragmentAcrossChangeCipherSpec { c.writeRecord(recordTypeHandshake, postCCSBytes[:5]) postCCSBytes = postCCSBytes[5:] } + c.dtlsFlushHandshake() if !c.config.Bugs.SkipChangeCipherSpec && c.config.Bugs.EarlyChangeCipherSpec == 0 { @@ -843,8 +881,15 @@ func (hs *clientHandshakeState) sendFinished(isResume bool) error { if c.config.Bugs.AppDataAfterChangeCipherSpec != nil { c.writeRecord(recordTypeApplicationData, c.config.Bugs.AppDataAfterChangeCipherSpec) } + if c.config.Bugs.AlertAfterChangeCipherSpec != 0 { + c.sendAlert(c.config.Bugs.AlertAfterChangeCipherSpec) + return errors.New("tls: simulating post-CCS alert") + } - c.writeRecord(recordTypeHandshake, postCCSBytes) + if !c.config.Bugs.SkipFinished { + c.writeRecord(recordTypeHandshake, postCCSBytes) + c.dtlsFlushHandshake() + } return nil } diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go index 1234a57..59ed9df 100644 --- a/src/ssl/test/runner/handshake_server.go +++ b/src/ssl/test/runner/handshake_server.go @@ -33,6 +33,7 @@ type serverHandshakeState struct { masterSecret []byte certsFromClient [][]byte cert *Certificate + finishedBytes []byte } // serverHandshake performs a TLS handshake as a server. @@ -71,6 +72,15 @@ func (c *Conn) serverHandshake() error { if err := hs.sendFinished(); err != nil { return err } + // Most retransmits are triggered by a timeout, but the final + // leg of the handshake is retransmited upon re-receiving a + // Finished. + if err := c.simulatePacketLoss(func() { + c.writeRecord(recordTypeHandshake, hs.finishedBytes) + c.dtlsFlushHandshake() + }); err != nil { + return err + } if err := hs.readFinished(isResume); err != nil { return err } @@ -87,9 +97,12 @@ func (c *Conn) serverHandshake() error { if err := hs.readFinished(isResume); err != nil { return err } + if c.config.Bugs.AlertBeforeFalseStartTest != 0 { + c.sendAlert(c.config.Bugs.AlertBeforeFalseStartTest) + } if c.config.Bugs.ExpectFalseStart { if err := c.readRecord(recordTypeApplicationData); err != nil { - return err + return fmt.Errorf("tls: peer did not false start: %s", err) } } if err := hs.sendSessionTicket(); err != nil { @@ -100,6 +113,9 @@ func (c *Conn) serverHandshake() error { } } c.handshakeComplete = true + copy(c.clientRandom[:], hs.clientHello.random) + copy(c.serverRandom[:], hs.hello.random) + copy(c.masterSecret[:], hs.masterSecret) return nil } @@ -110,6 +126,9 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) { config := hs.c.config c := hs.c + if err := c.simulatePacketLoss(nil); err != nil { + return false, err + } msg, err := c.readHandshake() if err != nil { return false, err @@ -136,7 +155,11 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) { return false, errors.New("dtls: short read from Rand: " + err.Error()) } c.writeRecord(recordTypeHandshake, helloVerifyRequest.marshal()) + c.dtlsFlushHandshake() + if err := c.simulatePacketLoss(nil); err != nil { + return false, err + } msg, err := c.readHandshake() if err != nil { return false, err @@ -176,6 +199,9 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) { if c.clientVersion < VersionTLS12 && len(hs.clientHello.signatureAndHashes) > 0 { return false, fmt.Errorf("tls: client included signature_algorithms before TLS 1.2") } + if config.Bugs.IgnorePeerSignatureAlgorithmPreferences { + hs.clientHello.signatureAndHashes = config.signatureAndHashesForServer() + } c.vers, ok = config.mutualVersion(hs.clientHello.vers) if !ok { @@ -189,6 +215,9 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) { supportedCurve := false preferredCurves := config.curvePreferences() + if config.Bugs.IgnorePeerCurvePreferences { + hs.clientHello.supportedCurves = preferredCurves + } Curves: for _, curve := range hs.clientHello.supportedCurves { for _, supported := range preferredCurves { @@ -323,6 +352,9 @@ Curves: return false, errors.New("tls: fallback SCSV found when not expected") } + if config.Bugs.IgnorePeerCipherPreferences { + hs.clientHello.cipherSuites = c.config.cipherSuites() + } var preferenceList, supportedList []uint16 if c.config.PreferServerCipherSuites { preferenceList = c.config.cipherSuites() @@ -350,6 +382,10 @@ Curves: func (hs *serverHandshakeState) checkForResumption() bool { c := hs.c + if c.config.Bugs.NeverResumeOnRenego && c.cipherSuite != nil { + return false + } + if len(hs.clientHello.sessionTicket) > 0 { if c.config.SessionTicketsDisabled { return false @@ -410,6 +446,9 @@ func (hs *serverHandshakeState) doResumeHandshake() error { c := hs.c hs.hello.cipherSuite = hs.suite.id + if c.config.Bugs.SendCipherSuite != 0 { + hs.hello.cipherSuite = c.config.Bugs.SendCipherSuite + } // We echo the client's session ID in the ServerHello to let it know // that we're doing a resumption. hs.hello.sessionId = hs.clientHello.sessionId @@ -473,12 +512,16 @@ func (hs *serverHandshakeState) doFullHandshake() error { certMsg := new(certificateMsg) certMsg.certificates = hs.cert.Certificate if !config.Bugs.UnauthenticatedECDH { - hs.writeServerHash(certMsg.marshal()) - c.writeRecord(recordTypeHandshake, certMsg.marshal()) + certMsgBytes := certMsg.marshal() + if config.Bugs.WrongCertificateMessageType { + certMsgBytes[0] += 42 + } + hs.writeServerHash(certMsgBytes) + c.writeRecord(recordTypeHandshake, certMsgBytes) } } - if hs.hello.ocspStapling { + if hs.hello.ocspStapling && !c.config.Bugs.SkipCertificateStatus { certStatus := new(certificateStatusMsg) certStatus.statusType = statusTypeOCSP certStatus.response = hs.cert.OCSPStaple @@ -530,9 +573,13 @@ func (hs *serverHandshakeState) doFullHandshake() error { helloDone := new(serverHelloDoneMsg) hs.writeServerHash(helloDone.marshal()) c.writeRecord(recordTypeHandshake, helloDone.marshal()) + c.dtlsFlushHandshake() var pub crypto.PublicKey // public key for client auth, if any + if err := c.simulatePacketLoss(nil); err != nil { + return err + } msg, err := c.readHandshake() if err != nil { return err @@ -811,14 +858,19 @@ func (hs *serverHandshakeState) sendFinished() error { finished := new(finishedMsg) finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret) + if c.config.Bugs.BadFinished { + finished.verifyData[0]++ + } c.serverVerify = append(c.serverVerify[:0], finished.verifyData...) - postCCSBytes := finished.marshal() - hs.writeServerHash(postCCSBytes) + hs.finishedBytes = finished.marshal() + hs.writeServerHash(hs.finishedBytes) + postCCSBytes := hs.finishedBytes if c.config.Bugs.FragmentAcrossChangeCipherSpec { c.writeRecord(recordTypeHandshake, postCCSBytes[:5]) postCCSBytes = postCCSBytes[5:] } + c.dtlsFlushHandshake() if !c.config.Bugs.SkipChangeCipherSpec { c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) @@ -827,10 +879,17 @@ func (hs *serverHandshakeState) sendFinished() error { if c.config.Bugs.AppDataAfterChangeCipherSpec != nil { c.writeRecord(recordTypeApplicationData, c.config.Bugs.AppDataAfterChangeCipherSpec) } + if c.config.Bugs.AlertAfterChangeCipherSpec != 0 { + c.sendAlert(c.config.Bugs.AlertAfterChangeCipherSpec) + return errors.New("tls: simulating post-CCS alert") + } - c.writeRecord(recordTypeHandshake, postCCSBytes) + if !c.config.Bugs.SkipFinished { + c.writeRecord(recordTypeHandshake, postCCSBytes) + c.dtlsFlushHandshake() + } - c.cipherSuite = hs.suite.id + c.cipherSuite = hs.suite return nil } diff --git a/src/ssl/test/runner/key_agreement.go b/src/ssl/test/runner/key_agreement.go index 116dfd8..5e44b54 100644 --- a/src/ssl/test/runner/key_agreement.go +++ b/src/ssl/test/runner/key_agreement.go @@ -25,19 +25,73 @@ var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message") // rsaKeyAgreement implements the standard TLS key agreement where the client // encrypts the pre-master secret to the server's public key. type rsaKeyAgreement struct { + version uint16 clientVersion uint16 + exportKey *rsa.PrivateKey } func (ka *rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { // Save the client version for comparison later. ka.clientVersion = versionToWire(clientHello.vers, clientHello.isDTLS) - if config.Bugs.RSAServerKeyExchange { - // Send an empty ServerKeyExchange message. - return &serverKeyExchangeMsg{}, nil + if !config.Bugs.RSAEphemeralKey { + return nil, nil } - return nil, nil + // Generate an ephemeral RSA key to use instead of the real + // one, as in RSA_EXPORT. + key, err := rsa.GenerateKey(config.rand(), 512) + if err != nil { + return nil, err + } + ka.exportKey = key + + modulus := key.N.Bytes() + exponent := big.NewInt(int64(key.E)).Bytes() + serverRSAParams := make([]byte, 0, 2+len(modulus)+2+len(exponent)) + serverRSAParams = append(serverRSAParams, byte(len(modulus)>>8), byte(len(modulus))) + serverRSAParams = append(serverRSAParams, modulus...) + serverRSAParams = append(serverRSAParams, byte(len(exponent)>>8), byte(len(exponent))) + serverRSAParams = append(serverRSAParams, exponent...) + + var tls12HashId uint8 + if ka.version >= VersionTLS12 { + if tls12HashId, err = pickTLS12HashForSignature(signatureRSA, clientHello.signatureAndHashes, config.signatureAndHashesForServer()); err != nil { + return nil, err + } + } + + digest, hashFunc, err := hashForServerKeyExchange(signatureRSA, tls12HashId, ka.version, clientHello.random, hello.random, serverRSAParams) + if err != nil { + return nil, err + } + privKey, ok := cert.PrivateKey.(*rsa.PrivateKey) + if !ok { + return nil, errors.New("RSA ephemeral key requires an RSA server private key") + } + sig, err := rsa.SignPKCS1v15(config.rand(), privKey, hashFunc, digest) + if err != nil { + return nil, errors.New("failed to sign RSA parameters: " + err.Error()) + } + + skx := new(serverKeyExchangeMsg) + sigAndHashLen := 0 + if ka.version >= VersionTLS12 { + sigAndHashLen = 2 + } + skx.key = make([]byte, len(serverRSAParams)+sigAndHashLen+2+len(sig)) + copy(skx.key, serverRSAParams) + k := skx.key[len(serverRSAParams):] + if ka.version >= VersionTLS12 { + k[0] = tls12HashId + k[1] = signatureRSA + k = k[2:] + } + k[0] = byte(len(sig) >> 8) + k[1] = byte(len(sig)) + copy(k[2:], sig) + + return skx, nil } func (ka *rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { @@ -60,7 +114,11 @@ func (ka *rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certif ciphertext = ckx.ciphertext[2:] } - err = rsa.DecryptPKCS1v15SessionKey(config.rand(), cert.PrivateKey.(*rsa.PrivateKey), ciphertext, preMasterSecret) + key := cert.PrivateKey.(*rsa.PrivateKey) + if ka.exportKey != nil { + key = ka.exportKey + } + err = rsa.DecryptPKCS1v15SessionKey(config.rand(), key, ciphertext, preMasterSecret) if err != nil { return nil, err } @@ -154,20 +212,19 @@ func hashForServerKeyExchange(sigType, hashFunc uint8, version uint16, slices .. // pickTLS12HashForSignature returns a TLS 1.2 hash identifier for signing a // ServerKeyExchange given the signature type being used and the client's // advertized list of supported signature and hash combinations. -func pickTLS12HashForSignature(sigType uint8, clientSignatureAndHashes []signatureAndHash) (uint8, error) { - if len(clientSignatureAndHashes) == 0 { +func pickTLS12HashForSignature(sigType uint8, clientList, serverList []signatureAndHash) (uint8, error) { + if len(clientList) == 0 { // If the client didn't specify any signature_algorithms // extension then we can assume that it supports SHA1. See // http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 return hashSHA1, nil } - for _, sigAndHash := range clientSignatureAndHashes { + for _, sigAndHash := range clientList { if sigAndHash.signature != sigType { continue } - switch sigAndHash.hash { - case hashSHA1, hashSHA256: + if isSupportedSignatureAndHash(sigAndHash, serverList) { return sigAndHash.hash, nil } } @@ -177,6 +234,8 @@ func pickTLS12HashForSignature(sigType uint8, clientSignatureAndHashes []signatu func curveForCurveID(id CurveID) (elliptic.Curve, bool) { switch id { + case CurveP224: + return elliptic.P224(), true case CurveP256: return elliptic.P256(), true case CurveP384: @@ -221,7 +280,7 @@ func (ka *signedKeyAgreement) signParameters(config *Config, cert *Certificate, var tls12HashId uint8 var err error if ka.version >= VersionTLS12 { - if tls12HashId, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil { + if tls12HashId, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes, config.signatureAndHashesForServer()); err != nil { return nil, err } } diff --git a/src/ssl/test/runner/packet_adapter.go b/src/ssl/test/runner/packet_adapter.go index 671b413..bbcd388 100644 --- a/src/ssl/test/runner/packet_adapter.go +++ b/src/ssl/test/runner/packet_adapter.go @@ -6,50 +6,115 @@ package main import ( "encoding/binary" - "errors" + "fmt" + "io" "net" + "time" ) +// opcodePacket signals a packet, encoded with a 32-bit length prefix, followed +// by the payload. +const opcodePacket = byte('P') + +// opcodeTimeout signals a read timeout, encoded by a 64-bit number of +// nanoseconds. On receipt, the peer should reply with +// opcodeTimeoutAck. opcodeTimeout may only be sent by the Go side. +const opcodeTimeout = byte('T') + +// opcodeTimeoutAck acknowledges a read timeout. This opcode has no payload and +// may only be sent by the C side. Timeout ACKs act as a synchronization point +// at the timeout, to bracket one flight of messages from C. +const opcodeTimeoutAck = byte('t') + type packetAdaptor struct { net.Conn } -// newPacketAdaptor wraps a reliable streaming net.Conn into a -// reliable packet-based net.Conn. Every packet is encoded with a -// 32-bit length prefix as a framing layer. -func newPacketAdaptor(conn net.Conn) net.Conn { +// newPacketAdaptor wraps a reliable streaming net.Conn into a reliable +// packet-based net.Conn. The stream contains packets and control commands, +// distinguished by a one byte opcode. +func newPacketAdaptor(conn net.Conn) *packetAdaptor { return &packetAdaptor{conn} } -func (p *packetAdaptor) Read(b []byte) (int, error) { +func (p *packetAdaptor) readOpcode() (byte, error) { + out := make([]byte, 1) + if _, err := io.ReadFull(p.Conn, out); err != nil { + return 0, err + } + return out[0], nil +} + +func (p *packetAdaptor) readPacketBody() ([]byte, error) { var length uint32 if err := binary.Read(p.Conn, binary.BigEndian, &length); err != nil { - return 0, err + return nil, err } out := make([]byte, length) - n, err := p.Conn.Read(out) + if _, err := io.ReadFull(p.Conn, out); err != nil { + return nil, err + } + return out, nil +} + +func (p *packetAdaptor) Read(b []byte) (int, error) { + opcode, err := p.readOpcode() if err != nil { return 0, err } - if n != int(length) { - return 0, errors.New("internal error: length mismatch!") + if opcode != opcodePacket { + return 0, fmt.Errorf("unexpected opcode '%d'", opcode) + } + out, err := p.readPacketBody() + if err != nil { + return 0, err } return copy(b, out), nil } func (p *packetAdaptor) Write(b []byte) (int, error) { - length := uint32(len(b)) - if err := binary.Write(p.Conn, binary.BigEndian, length); err != nil { + payload := make([]byte, 1+4+len(b)) + payload[0] = opcodePacket + binary.BigEndian.PutUint32(payload[1:5], uint32(len(b))) + copy(payload[5:], b) + if _, err := p.Conn.Write(payload); err != nil { return 0, err } - n, err := p.Conn.Write(b) - if err != nil { - return 0, err + return len(b), nil +} + +// SendReadTimeout instructs the peer to simulate a read timeout. It then waits +// for acknowledgement of the timeout, buffering any packets received since +// then. The packets are then returned. +func (p *packetAdaptor) SendReadTimeout(d time.Duration) ([][]byte, error) { + payload := make([]byte, 1+8) + payload[0] = opcodeTimeout + binary.BigEndian.PutUint64(payload[1:], uint64(d.Nanoseconds())) + if _, err := p.Conn.Write(payload); err != nil { + return nil, err } - if n != len(b) { - return 0, errors.New("internal error: length mismatch!") + + var packets [][]byte + for { + opcode, err := p.readOpcode() + if err != nil { + return nil, err + } + switch opcode { + case opcodeTimeoutAck: + // Done! Return the packets buffered and continue. + return packets, nil + case opcodePacket: + // Buffer the packet for the caller to process. + packet, err := p.readPacketBody() + if err != nil { + return nil, err + } + packets = append(packets, packet) + default: + return nil, fmt.Errorf("unexpected opcode '%d'", opcode) + } } - return len(b), nil } type replayAdaptor struct { diff --git a/src/ssl/test/runner/poly1305.go b/src/ssl/test/runner/poly1305.go new file mode 100644 index 0000000..51a1009 --- /dev/null +++ b/src/ssl/test/runner/poly1305.go @@ -0,0 +1,1540 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// Based on original, public domain implementation from NaCl by D. J. +// Bernstein. + +import ( + "crypto/subtle" + "math" +) + +const ( + alpham80 = 0.00000000558793544769287109375 + alpham48 = 24.0 + alpham16 = 103079215104.0 + alpha0 = 6755399441055744.0 + alpha18 = 1770887431076116955136.0 + alpha32 = 29014219670751100192948224.0 + alpha50 = 7605903601369376408980219232256.0 + alpha64 = 124615124604835863084731911901282304.0 + alpha82 = 32667107224410092492483962313449748299776.0 + alpha96 = 535217884764734955396857238543560676143529984.0 + alpha112 = 35076039295941670036888435985190792471742381031424.0 + alpha130 = 9194973245195333150150082162901855101712434733101613056.0 + scale = 0.0000000000000000000000000000000000000036734198463196484624023016788195177431833298649127735047148490821200539357960224151611328125 + offset0 = 6755408030990331.0 + offset1 = 29014256564239239022116864.0 + offset2 = 124615283061160854719918951570079744.0 + offset3 = 535219245894202480694386063513315216128475136.0 +) + +// poly1305Verify returns true if mac is a valid authenticator for m with the +// given key. +func poly1305Verify(mac *[16]byte, m []byte, key *[32]byte) bool { + var tmp [16]byte + poly1305Sum(&tmp, m, key) + return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1 +} + +// poly1305Sum generates an authenticator for m using a one-time key and puts +// the 16-byte result into out. Authenticating two different messages with the +// same key allows an attacker to forge messages at will. +func poly1305Sum(out *[16]byte, m []byte, key *[32]byte) { + r := key + s := key[16:] + var ( + y7 float64 + y6 float64 + y1 float64 + y0 float64 + y5 float64 + y4 float64 + x7 float64 + x6 float64 + x1 float64 + x0 float64 + y3 float64 + y2 float64 + x5 float64 + r3lowx0 float64 + x4 float64 + r0lowx6 float64 + x3 float64 + r3highx0 float64 + x2 float64 + r0highx6 float64 + r0lowx0 float64 + sr1lowx6 float64 + r0highx0 float64 + sr1highx6 float64 + sr3low float64 + r1lowx0 float64 + sr2lowx6 float64 + r1highx0 float64 + sr2highx6 float64 + r2lowx0 float64 + sr3lowx6 float64 + r2highx0 float64 + sr3highx6 float64 + r1highx4 float64 + r1lowx4 float64 + r0highx4 float64 + r0lowx4 float64 + sr3highx4 float64 + sr3lowx4 float64 + sr2highx4 float64 + sr2lowx4 float64 + r0lowx2 float64 + r0highx2 float64 + r1lowx2 float64 + r1highx2 float64 + r2lowx2 float64 + r2highx2 float64 + sr3lowx2 float64 + sr3highx2 float64 + z0 float64 + z1 float64 + z2 float64 + z3 float64 + m0 int64 + m1 int64 + m2 int64 + m3 int64 + m00 uint32 + m01 uint32 + m02 uint32 + m03 uint32 + m10 uint32 + m11 uint32 + m12 uint32 + m13 uint32 + m20 uint32 + m21 uint32 + m22 uint32 + m23 uint32 + m30 uint32 + m31 uint32 + m32 uint32 + m33 uint64 + lbelow2 int32 + lbelow3 int32 + lbelow4 int32 + lbelow5 int32 + lbelow6 int32 + lbelow7 int32 + lbelow8 int32 + lbelow9 int32 + lbelow10 int32 + lbelow11 int32 + lbelow12 int32 + lbelow13 int32 + lbelow14 int32 + lbelow15 int32 + s00 uint32 + s01 uint32 + s02 uint32 + s03 uint32 + s10 uint32 + s11 uint32 + s12 uint32 + s13 uint32 + s20 uint32 + s21 uint32 + s22 uint32 + s23 uint32 + s30 uint32 + s31 uint32 + s32 uint32 + s33 uint32 + bits32 uint64 + f uint64 + f0 uint64 + f1 uint64 + f2 uint64 + f3 uint64 + f4 uint64 + g uint64 + g0 uint64 + g1 uint64 + g2 uint64 + g3 uint64 + g4 uint64 + ) + + var p int32 + + l := int32(len(m)) + + r00 := uint32(r[0]) + + r01 := uint32(r[1]) + + r02 := uint32(r[2]) + r0 := int64(2151) + + r03 := uint32(r[3]) + r03 &= 15 + r0 <<= 51 + + r10 := uint32(r[4]) + r10 &= 252 + r01 <<= 8 + r0 += int64(r00) + + r11 := uint32(r[5]) + r02 <<= 16 + r0 += int64(r01) + + r12 := uint32(r[6]) + r03 <<= 24 + r0 += int64(r02) + + r13 := uint32(r[7]) + r13 &= 15 + r1 := int64(2215) + r0 += int64(r03) + + d0 := r0 + r1 <<= 51 + r2 := int64(2279) + + r20 := uint32(r[8]) + r20 &= 252 + r11 <<= 8 + r1 += int64(r10) + + r21 := uint32(r[9]) + r12 <<= 16 + r1 += int64(r11) + + r22 := uint32(r[10]) + r13 <<= 24 + r1 += int64(r12) + + r23 := uint32(r[11]) + r23 &= 15 + r2 <<= 51 + r1 += int64(r13) + + d1 := r1 + r21 <<= 8 + r2 += int64(r20) + + r30 := uint32(r[12]) + r30 &= 252 + r22 <<= 16 + r2 += int64(r21) + + r31 := uint32(r[13]) + r23 <<= 24 + r2 += int64(r22) + + r32 := uint32(r[14]) + r2 += int64(r23) + r3 := int64(2343) + + d2 := r2 + r3 <<= 51 + + r33 := uint32(r[15]) + r33 &= 15 + r31 <<= 8 + r3 += int64(r30) + + r32 <<= 16 + r3 += int64(r31) + + r33 <<= 24 + r3 += int64(r32) + + r3 += int64(r33) + h0 := alpha32 - alpha32 + + d3 := r3 + h1 := alpha32 - alpha32 + + h2 := alpha32 - alpha32 + + h3 := alpha32 - alpha32 + + h4 := alpha32 - alpha32 + + r0low := math.Float64frombits(uint64(d0)) + h5 := alpha32 - alpha32 + + r1low := math.Float64frombits(uint64(d1)) + h6 := alpha32 - alpha32 + + r2low := math.Float64frombits(uint64(d2)) + h7 := alpha32 - alpha32 + + r0low -= alpha0 + + r1low -= alpha32 + + r2low -= alpha64 + + r0high := r0low + alpha18 + + r3low := math.Float64frombits(uint64(d3)) + + r1high := r1low + alpha50 + sr1low := scale * r1low + + r2high := r2low + alpha82 + sr2low := scale * r2low + + r0high -= alpha18 + r0high_stack := r0high + + r3low -= alpha96 + + r1high -= alpha50 + r1high_stack := r1high + + sr1high := sr1low + alpham80 + + r0low -= r0high + + r2high -= alpha82 + sr3low = scale * r3low + + sr2high := sr2low + alpham48 + + r1low -= r1high + r1low_stack := r1low + + sr1high -= alpham80 + sr1high_stack := sr1high + + r2low -= r2high + r2low_stack := r2low + + sr2high -= alpham48 + sr2high_stack := sr2high + + r3high := r3low + alpha112 + r0low_stack := r0low + + sr1low -= sr1high + sr1low_stack := sr1low + + sr3high := sr3low + alpham16 + r2high_stack := r2high + + sr2low -= sr2high + sr2low_stack := sr2low + + r3high -= alpha112 + r3high_stack := r3high + + sr3high -= alpham16 + sr3high_stack := sr3high + + r3low -= r3high + r3low_stack := r3low + + sr3low -= sr3high + sr3low_stack := sr3low + + if l < 16 { + goto addatmost15bytes + } + + m00 = uint32(m[p+0]) + m0 = 2151 + + m0 <<= 51 + m1 = 2215 + m01 = uint32(m[p+1]) + + m1 <<= 51 + m2 = 2279 + m02 = uint32(m[p+2]) + + m2 <<= 51 + m3 = 2343 + m03 = uint32(m[p+3]) + + m10 = uint32(m[p+4]) + m01 <<= 8 + m0 += int64(m00) + + m11 = uint32(m[p+5]) + m02 <<= 16 + m0 += int64(m01) + + m12 = uint32(m[p+6]) + m03 <<= 24 + m0 += int64(m02) + + m13 = uint32(m[p+7]) + m3 <<= 51 + m0 += int64(m03) + + m20 = uint32(m[p+8]) + m11 <<= 8 + m1 += int64(m10) + + m21 = uint32(m[p+9]) + m12 <<= 16 + m1 += int64(m11) + + m22 = uint32(m[p+10]) + m13 <<= 24 + m1 += int64(m12) + + m23 = uint32(m[p+11]) + m1 += int64(m13) + + m30 = uint32(m[p+12]) + m21 <<= 8 + m2 += int64(m20) + + m31 = uint32(m[p+13]) + m22 <<= 16 + m2 += int64(m21) + + m32 = uint32(m[p+14]) + m23 <<= 24 + m2 += int64(m22) + + m33 = uint64(m[p+15]) + m2 += int64(m23) + + d0 = m0 + m31 <<= 8 + m3 += int64(m30) + + d1 = m1 + m32 <<= 16 + m3 += int64(m31) + + d2 = m2 + m33 += 256 + + m33 <<= 24 + m3 += int64(m32) + + m3 += int64(m33) + d3 = m3 + + p += 16 + l -= 16 + + z0 = math.Float64frombits(uint64(d0)) + + z1 = math.Float64frombits(uint64(d1)) + + z2 = math.Float64frombits(uint64(d2)) + + z3 = math.Float64frombits(uint64(d3)) + + z0 -= alpha0 + + z1 -= alpha32 + + z2 -= alpha64 + + z3 -= alpha96 + + h0 += z0 + + h1 += z1 + + h3 += z2 + + h5 += z3 + + if l < 16 { + goto multiplyaddatmost15bytes + } + +multiplyaddatleast16bytes: + + m2 = 2279 + m20 = uint32(m[p+8]) + y7 = h7 + alpha130 + + m2 <<= 51 + m3 = 2343 + m21 = uint32(m[p+9]) + y6 = h6 + alpha130 + + m3 <<= 51 + m0 = 2151 + m22 = uint32(m[p+10]) + y1 = h1 + alpha32 + + m0 <<= 51 + m1 = 2215 + m23 = uint32(m[p+11]) + y0 = h0 + alpha32 + + m1 <<= 51 + m30 = uint32(m[p+12]) + y7 -= alpha130 + + m21 <<= 8 + m2 += int64(m20) + m31 = uint32(m[p+13]) + y6 -= alpha130 + + m22 <<= 16 + m2 += int64(m21) + m32 = uint32(m[p+14]) + y1 -= alpha32 + + m23 <<= 24 + m2 += int64(m22) + m33 = uint64(m[p+15]) + y0 -= alpha32 + + m2 += int64(m23) + m00 = uint32(m[p+0]) + y5 = h5 + alpha96 + + m31 <<= 8 + m3 += int64(m30) + m01 = uint32(m[p+1]) + y4 = h4 + alpha96 + + m32 <<= 16 + m02 = uint32(m[p+2]) + x7 = h7 - y7 + y7 *= scale + + m33 += 256 + m03 = uint32(m[p+3]) + x6 = h6 - y6 + y6 *= scale + + m33 <<= 24 + m3 += int64(m31) + m10 = uint32(m[p+4]) + x1 = h1 - y1 + + m01 <<= 8 + m3 += int64(m32) + m11 = uint32(m[p+5]) + x0 = h0 - y0 + + m3 += int64(m33) + m0 += int64(m00) + m12 = uint32(m[p+6]) + y5 -= alpha96 + + m02 <<= 16 + m0 += int64(m01) + m13 = uint32(m[p+7]) + y4 -= alpha96 + + m03 <<= 24 + m0 += int64(m02) + d2 = m2 + x1 += y7 + + m0 += int64(m03) + d3 = m3 + x0 += y6 + + m11 <<= 8 + m1 += int64(m10) + d0 = m0 + x7 += y5 + + m12 <<= 16 + m1 += int64(m11) + x6 += y4 + + m13 <<= 24 + m1 += int64(m12) + y3 = h3 + alpha64 + + m1 += int64(m13) + d1 = m1 + y2 = h2 + alpha64 + + x0 += x1 + + x6 += x7 + + y3 -= alpha64 + r3low = r3low_stack + + y2 -= alpha64 + r0low = r0low_stack + + x5 = h5 - y5 + r3lowx0 = r3low * x0 + r3high = r3high_stack + + x4 = h4 - y4 + r0lowx6 = r0low * x6 + r0high = r0high_stack + + x3 = h3 - y3 + r3highx0 = r3high * x0 + sr1low = sr1low_stack + + x2 = h2 - y2 + r0highx6 = r0high * x6 + sr1high = sr1high_stack + + x5 += y3 + r0lowx0 = r0low * x0 + r1low = r1low_stack + + h6 = r3lowx0 + r0lowx6 + sr1lowx6 = sr1low * x6 + r1high = r1high_stack + + x4 += y2 + r0highx0 = r0high * x0 + sr2low = sr2low_stack + + h7 = r3highx0 + r0highx6 + sr1highx6 = sr1high * x6 + sr2high = sr2high_stack + + x3 += y1 + r1lowx0 = r1low * x0 + r2low = r2low_stack + + h0 = r0lowx0 + sr1lowx6 + sr2lowx6 = sr2low * x6 + r2high = r2high_stack + + x2 += y0 + r1highx0 = r1high * x0 + sr3low = sr3low_stack + + h1 = r0highx0 + sr1highx6 + sr2highx6 = sr2high * x6 + sr3high = sr3high_stack + + x4 += x5 + r2lowx0 = r2low * x0 + z2 = math.Float64frombits(uint64(d2)) + + h2 = r1lowx0 + sr2lowx6 + sr3lowx6 = sr3low * x6 + + x2 += x3 + r2highx0 = r2high * x0 + z3 = math.Float64frombits(uint64(d3)) + + h3 = r1highx0 + sr2highx6 + sr3highx6 = sr3high * x6 + + r1highx4 = r1high * x4 + z2 -= alpha64 + + h4 = r2lowx0 + sr3lowx6 + r1lowx4 = r1low * x4 + + r0highx4 = r0high * x4 + z3 -= alpha96 + + h5 = r2highx0 + sr3highx6 + r0lowx4 = r0low * x4 + + h7 += r1highx4 + sr3highx4 = sr3high * x4 + + h6 += r1lowx4 + sr3lowx4 = sr3low * x4 + + h5 += r0highx4 + sr2highx4 = sr2high * x4 + + h4 += r0lowx4 + sr2lowx4 = sr2low * x4 + + h3 += sr3highx4 + r0lowx2 = r0low * x2 + + h2 += sr3lowx4 + r0highx2 = r0high * x2 + + h1 += sr2highx4 + r1lowx2 = r1low * x2 + + h0 += sr2lowx4 + r1highx2 = r1high * x2 + + h2 += r0lowx2 + r2lowx2 = r2low * x2 + + h3 += r0highx2 + r2highx2 = r2high * x2 + + h4 += r1lowx2 + sr3lowx2 = sr3low * x2 + + h5 += r1highx2 + sr3highx2 = sr3high * x2 + + p += 16 + l -= 16 + h6 += r2lowx2 + + h7 += r2highx2 + + z1 = math.Float64frombits(uint64(d1)) + h0 += sr3lowx2 + + z0 = math.Float64frombits(uint64(d0)) + h1 += sr3highx2 + + z1 -= alpha32 + + z0 -= alpha0 + + h5 += z3 + + h3 += z2 + + h1 += z1 + + h0 += z0 + + if l >= 16 { + goto multiplyaddatleast16bytes + } + +multiplyaddatmost15bytes: + + y7 = h7 + alpha130 + + y6 = h6 + alpha130 + + y1 = h1 + alpha32 + + y0 = h0 + alpha32 + + y7 -= alpha130 + + y6 -= alpha130 + + y1 -= alpha32 + + y0 -= alpha32 + + y5 = h5 + alpha96 + + y4 = h4 + alpha96 + + x7 = h7 - y7 + y7 *= scale + + x6 = h6 - y6 + y6 *= scale + + x1 = h1 - y1 + + x0 = h0 - y0 + + y5 -= alpha96 + + y4 -= alpha96 + + x1 += y7 + + x0 += y6 + + x7 += y5 + + x6 += y4 + + y3 = h3 + alpha64 + + y2 = h2 + alpha64 + + x0 += x1 + + x6 += x7 + + y3 -= alpha64 + r3low = r3low_stack + + y2 -= alpha64 + r0low = r0low_stack + + x5 = h5 - y5 + r3lowx0 = r3low * x0 + r3high = r3high_stack + + x4 = h4 - y4 + r0lowx6 = r0low * x6 + r0high = r0high_stack + + x3 = h3 - y3 + r3highx0 = r3high * x0 + sr1low = sr1low_stack + + x2 = h2 - y2 + r0highx6 = r0high * x6 + sr1high = sr1high_stack + + x5 += y3 + r0lowx0 = r0low * x0 + r1low = r1low_stack + + h6 = r3lowx0 + r0lowx6 + sr1lowx6 = sr1low * x6 + r1high = r1high_stack + + x4 += y2 + r0highx0 = r0high * x0 + sr2low = sr2low_stack + + h7 = r3highx0 + r0highx6 + sr1highx6 = sr1high * x6 + sr2high = sr2high_stack + + x3 += y1 + r1lowx0 = r1low * x0 + r2low = r2low_stack + + h0 = r0lowx0 + sr1lowx6 + sr2lowx6 = sr2low * x6 + r2high = r2high_stack + + x2 += y0 + r1highx0 = r1high * x0 + sr3low = sr3low_stack + + h1 = r0highx0 + sr1highx6 + sr2highx6 = sr2high * x6 + sr3high = sr3high_stack + + x4 += x5 + r2lowx0 = r2low * x0 + + h2 = r1lowx0 + sr2lowx6 + sr3lowx6 = sr3low * x6 + + x2 += x3 + r2highx0 = r2high * x0 + + h3 = r1highx0 + sr2highx6 + sr3highx6 = sr3high * x6 + + r1highx4 = r1high * x4 + + h4 = r2lowx0 + sr3lowx6 + r1lowx4 = r1low * x4 + + r0highx4 = r0high * x4 + + h5 = r2highx0 + sr3highx6 + r0lowx4 = r0low * x4 + + h7 += r1highx4 + sr3highx4 = sr3high * x4 + + h6 += r1lowx4 + sr3lowx4 = sr3low * x4 + + h5 += r0highx4 + sr2highx4 = sr2high * x4 + + h4 += r0lowx4 + sr2lowx4 = sr2low * x4 + + h3 += sr3highx4 + r0lowx2 = r0low * x2 + + h2 += sr3lowx4 + r0highx2 = r0high * x2 + + h1 += sr2highx4 + r1lowx2 = r1low * x2 + + h0 += sr2lowx4 + r1highx2 = r1high * x2 + + h2 += r0lowx2 + r2lowx2 = r2low * x2 + + h3 += r0highx2 + r2highx2 = r2high * x2 + + h4 += r1lowx2 + sr3lowx2 = sr3low * x2 + + h5 += r1highx2 + sr3highx2 = sr3high * x2 + + h6 += r2lowx2 + + h7 += r2highx2 + + h0 += sr3lowx2 + + h1 += sr3highx2 + +addatmost15bytes: + + if l == 0 { + goto nomorebytes + } + + lbelow2 = l - 2 + + lbelow3 = l - 3 + + lbelow2 >>= 31 + lbelow4 = l - 4 + + m00 = uint32(m[p+0]) + lbelow3 >>= 31 + p += lbelow2 + + m01 = uint32(m[p+1]) + lbelow4 >>= 31 + p += lbelow3 + + m02 = uint32(m[p+2]) + p += lbelow4 + m0 = 2151 + + m03 = uint32(m[p+3]) + m0 <<= 51 + m1 = 2215 + + m0 += int64(m00) + m01 &^= uint32(lbelow2) + + m02 &^= uint32(lbelow3) + m01 -= uint32(lbelow2) + + m01 <<= 8 + m03 &^= uint32(lbelow4) + + m0 += int64(m01) + lbelow2 -= lbelow3 + + m02 += uint32(lbelow2) + lbelow3 -= lbelow4 + + m02 <<= 16 + m03 += uint32(lbelow3) + + m03 <<= 24 + m0 += int64(m02) + + m0 += int64(m03) + lbelow5 = l - 5 + + lbelow6 = l - 6 + lbelow7 = l - 7 + + lbelow5 >>= 31 + lbelow8 = l - 8 + + lbelow6 >>= 31 + p += lbelow5 + + m10 = uint32(m[p+4]) + lbelow7 >>= 31 + p += lbelow6 + + m11 = uint32(m[p+5]) + lbelow8 >>= 31 + p += lbelow7 + + m12 = uint32(m[p+6]) + m1 <<= 51 + p += lbelow8 + + m13 = uint32(m[p+7]) + m10 &^= uint32(lbelow5) + lbelow4 -= lbelow5 + + m10 += uint32(lbelow4) + lbelow5 -= lbelow6 + + m11 &^= uint32(lbelow6) + m11 += uint32(lbelow5) + + m11 <<= 8 + m1 += int64(m10) + + m1 += int64(m11) + m12 &^= uint32(lbelow7) + + lbelow6 -= lbelow7 + m13 &^= uint32(lbelow8) + + m12 += uint32(lbelow6) + lbelow7 -= lbelow8 + + m12 <<= 16 + m13 += uint32(lbelow7) + + m13 <<= 24 + m1 += int64(m12) + + m1 += int64(m13) + m2 = 2279 + + lbelow9 = l - 9 + m3 = 2343 + + lbelow10 = l - 10 + lbelow11 = l - 11 + + lbelow9 >>= 31 + lbelow12 = l - 12 + + lbelow10 >>= 31 + p += lbelow9 + + m20 = uint32(m[p+8]) + lbelow11 >>= 31 + p += lbelow10 + + m21 = uint32(m[p+9]) + lbelow12 >>= 31 + p += lbelow11 + + m22 = uint32(m[p+10]) + m2 <<= 51 + p += lbelow12 + + m23 = uint32(m[p+11]) + m20 &^= uint32(lbelow9) + lbelow8 -= lbelow9 + + m20 += uint32(lbelow8) + lbelow9 -= lbelow10 + + m21 &^= uint32(lbelow10) + m21 += uint32(lbelow9) + + m21 <<= 8 + m2 += int64(m20) + + m2 += int64(m21) + m22 &^= uint32(lbelow11) + + lbelow10 -= lbelow11 + m23 &^= uint32(lbelow12) + + m22 += uint32(lbelow10) + lbelow11 -= lbelow12 + + m22 <<= 16 + m23 += uint32(lbelow11) + + m23 <<= 24 + m2 += int64(m22) + + m3 <<= 51 + lbelow13 = l - 13 + + lbelow13 >>= 31 + lbelow14 = l - 14 + + lbelow14 >>= 31 + p += lbelow13 + lbelow15 = l - 15 + + m30 = uint32(m[p+12]) + lbelow15 >>= 31 + p += lbelow14 + + m31 = uint32(m[p+13]) + p += lbelow15 + m2 += int64(m23) + + m32 = uint32(m[p+14]) + m30 &^= uint32(lbelow13) + lbelow12 -= lbelow13 + + m30 += uint32(lbelow12) + lbelow13 -= lbelow14 + + m3 += int64(m30) + m31 &^= uint32(lbelow14) + + m31 += uint32(lbelow13) + m32 &^= uint32(lbelow15) + + m31 <<= 8 + lbelow14 -= lbelow15 + + m3 += int64(m31) + m32 += uint32(lbelow14) + d0 = m0 + + m32 <<= 16 + m33 = uint64(lbelow15 + 1) + d1 = m1 + + m33 <<= 24 + m3 += int64(m32) + d2 = m2 + + m3 += int64(m33) + d3 = m3 + + z3 = math.Float64frombits(uint64(d3)) + + z2 = math.Float64frombits(uint64(d2)) + + z1 = math.Float64frombits(uint64(d1)) + + z0 = math.Float64frombits(uint64(d0)) + + z3 -= alpha96 + + z2 -= alpha64 + + z1 -= alpha32 + + z0 -= alpha0 + + h5 += z3 + + h3 += z2 + + h1 += z1 + + h0 += z0 + + y7 = h7 + alpha130 + + y6 = h6 + alpha130 + + y1 = h1 + alpha32 + + y0 = h0 + alpha32 + + y7 -= alpha130 + + y6 -= alpha130 + + y1 -= alpha32 + + y0 -= alpha32 + + y5 = h5 + alpha96 + + y4 = h4 + alpha96 + + x7 = h7 - y7 + y7 *= scale + + x6 = h6 - y6 + y6 *= scale + + x1 = h1 - y1 + + x0 = h0 - y0 + + y5 -= alpha96 + + y4 -= alpha96 + + x1 += y7 + + x0 += y6 + + x7 += y5 + + x6 += y4 + + y3 = h3 + alpha64 + + y2 = h2 + alpha64 + + x0 += x1 + + x6 += x7 + + y3 -= alpha64 + r3low = r3low_stack + + y2 -= alpha64 + r0low = r0low_stack + + x5 = h5 - y5 + r3lowx0 = r3low * x0 + r3high = r3high_stack + + x4 = h4 - y4 + r0lowx6 = r0low * x6 + r0high = r0high_stack + + x3 = h3 - y3 + r3highx0 = r3high * x0 + sr1low = sr1low_stack + + x2 = h2 - y2 + r0highx6 = r0high * x6 + sr1high = sr1high_stack + + x5 += y3 + r0lowx0 = r0low * x0 + r1low = r1low_stack + + h6 = r3lowx0 + r0lowx6 + sr1lowx6 = sr1low * x6 + r1high = r1high_stack + + x4 += y2 + r0highx0 = r0high * x0 + sr2low = sr2low_stack + + h7 = r3highx0 + r0highx6 + sr1highx6 = sr1high * x6 + sr2high = sr2high_stack + + x3 += y1 + r1lowx0 = r1low * x0 + r2low = r2low_stack + + h0 = r0lowx0 + sr1lowx6 + sr2lowx6 = sr2low * x6 + r2high = r2high_stack + + x2 += y0 + r1highx0 = r1high * x0 + sr3low = sr3low_stack + + h1 = r0highx0 + sr1highx6 + sr2highx6 = sr2high * x6 + sr3high = sr3high_stack + + x4 += x5 + r2lowx0 = r2low * x0 + + h2 = r1lowx0 + sr2lowx6 + sr3lowx6 = sr3low * x6 + + x2 += x3 + r2highx0 = r2high * x0 + + h3 = r1highx0 + sr2highx6 + sr3highx6 = sr3high * x6 + + r1highx4 = r1high * x4 + + h4 = r2lowx0 + sr3lowx6 + r1lowx4 = r1low * x4 + + r0highx4 = r0high * x4 + + h5 = r2highx0 + sr3highx6 + r0lowx4 = r0low * x4 + + h7 += r1highx4 + sr3highx4 = sr3high * x4 + + h6 += r1lowx4 + sr3lowx4 = sr3low * x4 + + h5 += r0highx4 + sr2highx4 = sr2high * x4 + + h4 += r0lowx4 + sr2lowx4 = sr2low * x4 + + h3 += sr3highx4 + r0lowx2 = r0low * x2 + + h2 += sr3lowx4 + r0highx2 = r0high * x2 + + h1 += sr2highx4 + r1lowx2 = r1low * x2 + + h0 += sr2lowx4 + r1highx2 = r1high * x2 + + h2 += r0lowx2 + r2lowx2 = r2low * x2 + + h3 += r0highx2 + r2highx2 = r2high * x2 + + h4 += r1lowx2 + sr3lowx2 = sr3low * x2 + + h5 += r1highx2 + sr3highx2 = sr3high * x2 + + h6 += r2lowx2 + + h7 += r2highx2 + + h0 += sr3lowx2 + + h1 += sr3highx2 + +nomorebytes: + + y7 = h7 + alpha130 + + y0 = h0 + alpha32 + + y1 = h1 + alpha32 + + y2 = h2 + alpha64 + + y7 -= alpha130 + + y3 = h3 + alpha64 + + y4 = h4 + alpha96 + + y5 = h5 + alpha96 + + x7 = h7 - y7 + y7 *= scale + + y0 -= alpha32 + + y1 -= alpha32 + + y2 -= alpha64 + + h6 += x7 + + y3 -= alpha64 + + y4 -= alpha96 + + y5 -= alpha96 + + y6 = h6 + alpha130 + + x0 = h0 - y0 + + x1 = h1 - y1 + + x2 = h2 - y2 + + y6 -= alpha130 + + x0 += y7 + + x3 = h3 - y3 + + x4 = h4 - y4 + + x5 = h5 - y5 + + x6 = h6 - y6 + + y6 *= scale + + x2 += y0 + + x3 += y1 + + x4 += y2 + + x0 += y6 + + x5 += y3 + + x6 += y4 + + x2 += x3 + + x0 += x1 + + x4 += x5 + + x6 += y5 + + x2 += offset1 + d1 = int64(math.Float64bits(x2)) + + x0 += offset0 + d0 = int64(math.Float64bits(x0)) + + x4 += offset2 + d2 = int64(math.Float64bits(x4)) + + x6 += offset3 + d3 = int64(math.Float64bits(x6)) + + f0 = uint64(d0) + + f1 = uint64(d1) + bits32 = math.MaxUint64 + + f2 = uint64(d2) + bits32 >>= 32 + + f3 = uint64(d3) + f = f0 >> 32 + + f0 &= bits32 + f &= 255 + + f1 += f + g0 = f0 + 5 + + g = g0 >> 32 + g0 &= bits32 + + f = f1 >> 32 + f1 &= bits32 + + f &= 255 + g1 = f1 + g + + g = g1 >> 32 + f2 += f + + f = f2 >> 32 + g1 &= bits32 + + f2 &= bits32 + f &= 255 + + f3 += f + g2 = f2 + g + + g = g2 >> 32 + g2 &= bits32 + + f4 = f3 >> 32 + f3 &= bits32 + + f4 &= 255 + g3 = f3 + g + + g = g3 >> 32 + g3 &= bits32 + + g4 = f4 + g + + g4 = g4 - 4 + s00 = uint32(s[0]) + + f = uint64(int64(g4) >> 63) + s01 = uint32(s[1]) + + f0 &= f + g0 &^= f + s02 = uint32(s[2]) + + f1 &= f + f0 |= g0 + s03 = uint32(s[3]) + + g1 &^= f + f2 &= f + s10 = uint32(s[4]) + + f3 &= f + g2 &^= f + s11 = uint32(s[5]) + + g3 &^= f + f1 |= g1 + s12 = uint32(s[6]) + + f2 |= g2 + f3 |= g3 + s13 = uint32(s[7]) + + s01 <<= 8 + f0 += uint64(s00) + s20 = uint32(s[8]) + + s02 <<= 16 + f0 += uint64(s01) + s21 = uint32(s[9]) + + s03 <<= 24 + f0 += uint64(s02) + s22 = uint32(s[10]) + + s11 <<= 8 + f1 += uint64(s10) + s23 = uint32(s[11]) + + s12 <<= 16 + f1 += uint64(s11) + s30 = uint32(s[12]) + + s13 <<= 24 + f1 += uint64(s12) + s31 = uint32(s[13]) + + f0 += uint64(s03) + f1 += uint64(s13) + s32 = uint32(s[14]) + + s21 <<= 8 + f2 += uint64(s20) + s33 = uint32(s[15]) + + s22 <<= 16 + f2 += uint64(s21) + + s23 <<= 24 + f2 += uint64(s22) + + s31 <<= 8 + f3 += uint64(s30) + + s32 <<= 16 + f3 += uint64(s31) + + s33 <<= 24 + f3 += uint64(s32) + + f2 += uint64(s23) + f3 += uint64(s33) + + out[0] = byte(f0) + f0 >>= 8 + out[1] = byte(f0) + f0 >>= 8 + out[2] = byte(f0) + f0 >>= 8 + out[3] = byte(f0) + f0 >>= 8 + f1 += f0 + + out[4] = byte(f1) + f1 >>= 8 + out[5] = byte(f1) + f1 >>= 8 + out[6] = byte(f1) + f1 >>= 8 + out[7] = byte(f1) + f1 >>= 8 + f2 += f1 + + out[8] = byte(f2) + f2 >>= 8 + out[9] = byte(f2) + f2 >>= 8 + out[10] = byte(f2) + f2 >>= 8 + out[11] = byte(f2) + f2 >>= 8 + f3 += f2 + + out[12] = byte(f3) + f3 >>= 8 + out[13] = byte(f3) + f3 >>= 8 + out[14] = byte(f3) + f3 >>= 8 + out[15] = byte(f3) +} diff --git a/src/ssl/test/runner/prf.go b/src/ssl/test/runner/prf.go index 75a8933..d445e76 100644 --- a/src/ssl/test/runner/prf.go +++ b/src/ssl/test/runner/prf.go @@ -323,14 +323,14 @@ func (h finishedHash) serverSum(masterSecret []byte) []byte { // selectClientCertSignatureAlgorithm returns a signatureAndHash to sign a // client's CertificateVerify with, or an error if none can be found. -func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []signatureAndHash, sigType uint8) (signatureAndHash, error) { +func (h finishedHash) selectClientCertSignatureAlgorithm(serverList, clientList []signatureAndHash, sigType uint8) (signatureAndHash, error) { if h.version < VersionTLS12 { // Nothing to negotiate before TLS 1.2. return signatureAndHash{signature: sigType}, nil } for _, v := range serverList { - if v.signature == sigType && v.hash == hashSHA256 { + if v.signature == sigType && isSupportedSignatureAndHash(v, clientList) { return v, nil } } diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go index aaa2a4d..ec2fede 100644 --- a/src/ssl/test/runner/runner.go +++ b/src/ssl/test/runner/runner.go @@ -20,14 +20,17 @@ import ( "strings" "sync" "syscall" + "time" ) var ( - useValgrind = flag.Bool("valgrind", false, "If true, run code under valgrind") - useGDB = flag.Bool("gdb", false, "If true, run BoringSSL code under gdb") - flagDebug *bool = flag.Bool("debug", false, "Hexdump the contents of the connection") - mallocTest *int64 = flag.Int64("malloc-test", -1, "If non-negative, run each test with each malloc in turn failing from the given number onwards.") - mallocTestDebug *bool = 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.") + useValgrind = flag.Bool("valgrind", false, "If true, run code under valgrind") + useGDB = flag.Bool("gdb", false, "If true, run BoringSSL code under gdb") + flagDebug = flag.Bool("debug", false, "Hexdump the contents of the connection") + mallocTest = flag.Int64("malloc-test", -1, "If non-negative, run each test with each malloc in turn failing from the given number onwards.") + 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.") ) const ( @@ -132,6 +135,9 @@ type testCase struct { // expectedResumeVersion, if non-zero, specifies the TLS version that // must be negotiated on resumption. If zero, expectedVersion is used. expectedResumeVersion uint16 + // expectedCipher, if non-zero, specifies the TLS cipher suite that + // should be negotiated. + expectedCipher uint16 // expectChannelID controls whether the connection should have // negotiated a Channel ID with channelIDKey. expectChannelID bool @@ -181,6 +187,12 @@ type testCase struct { // damageFirstWrite, if true, configures the underlying transport to // damage the final byte of the first application data write. damageFirstWrite bool + // exportKeyingMaterial, if non-zero, configures the test to exchange + // keying material and verify they match. + exportKeyingMaterial int + exportLabel string + exportContext string + useExportContext bool // flags, if not empty, contains a list of command-line flags that will // be passed to the shim program. flags []string @@ -292,6 +304,18 @@ var testCases = []testCase{ 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}, @@ -376,11 +400,47 @@ var testCases = []testCase{ }, { 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: 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, @@ -536,11 +596,11 @@ var testCases = []testCase{ expectedError: ":WRONG_CIPHER_RETURNED:", }, { - name: "RSAServerKeyExchange", + name: "RSAEphemeralKey", config: Config{ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, Bugs: ProtocolBugs{ - RSAServerKeyExchange: true, + RSAEphemeralKey: true, }, }, shouldFail: true, @@ -650,6 +710,380 @@ var testCases = []testCase{ 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, }, } @@ -665,7 +1099,8 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i } if test.protocol == dtls { - conn = newPacketAdaptor(conn) + config.Bugs.PacketAdaptor = newPacketAdaptor(conn) + conn = config.Bugs.PacketAdaptor if test.replayWrites { conn = newReplayAdaptor(conn) } @@ -713,6 +1148,10 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i return fmt.Errorf("got version %x, expected %x", vers, expectedVersion) } + if cipher := tlsConn.ConnectionState().CipherSuite; test.expectedCipher != 0 && cipher != test.expectedCipher { + return fmt.Errorf("got cipher %x, expected %x", cipher, test.expectedCipher) + } + if test.expectChannelID { channelID := tlsConn.ConnectionState().ChannelID if channelID == nil { @@ -741,6 +1180,20 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i return fmt.Errorf("SRTP profile mismatch: got %d, wanted %d", p, test.expectedSRTPProtectionProfile) } + if test.exportKeyingMaterial > 0 { + actual := make([]byte, test.exportKeyingMaterial) + if _, err := io.ReadFull(tlsConn, actual); err != nil { + return err + } + expected, err := tlsConn.ExportKeyingMaterial(test.exportKeyingMaterial, []byte(test.exportLabel), []byte(test.exportContext), test.useExportContext) + if err != nil { + return err + } + if !bytes.Equal(actual, expected) { + return fmt.Errorf("keying material mismatch") + } + } + if test.shimWritesFirst { var buf [5]byte _, err := io.ReadFull(tlsConn, buf[:]) @@ -778,21 +1231,14 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i return err } - var testMessage []byte - if config.Bugs.AppDataAfterChangeCipherSpec != nil { - // We've already sent a message. Expect the shim to echo it - // back. - testMessage = config.Bugs.AppDataAfterChangeCipherSpec - } else { - if messageLen == 0 { - messageLen = 32 - } - testMessage = make([]byte, messageLen) - for i := range testMessage { - testMessage[i] = 0x42 - } - tlsConn.Write(testMessage) + if messageLen == 0 { + messageLen = 32 + } + testMessage := make([]byte, messageLen) + for i := range testMessage { + testMessage[i] = 0x42 } + tlsConn.Write(testMessage) buf := make([]byte, len(testMessage)) if test.protocol == dtls { @@ -833,32 +1279,11 @@ func valgrindOf(dbAttach bool, path string, args ...string) *exec.Cmd { } func gdbOf(path string, args ...string) *exec.Cmd { - xtermArgs := []string{"-e", "gdb", "--args"} - xtermArgs = append(xtermArgs, path) - xtermArgs = append(xtermArgs, args...) - - return exec.Command("xterm", xtermArgs...) -} - -func openSocketPair() (shimEnd *os.File, conn net.Conn) { - socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0) - if err != nil { - panic(err) - } - - syscall.CloseOnExec(socks[0]) - syscall.CloseOnExec(socks[1]) - shimEnd = os.NewFile(uintptr(socks[0]), "shim end") - connFile := os.NewFile(uintptr(socks[1]), "our end") - conn, err = net.FileConn(connFile) - if err != nil { - panic(err) - } - connFile.Close() - if err != nil { - panic(err) - } - return shimEnd, conn + xtermArgs := []string{"-e", "gdb", "--args"} + xtermArgs = append(xtermArgs, path) + xtermArgs = append(xtermArgs, args...) + + return exec.Command("xterm", xtermArgs...) } type moreMallocsError struct{} @@ -869,16 +1294,45 @@ func (moreMallocsError) Error() string { var errMoreMallocs = moreMallocsError{} +// accept accepts a connection from listener, unless waitChan signals a process +// exit first. +func acceptOrWait(listener net.Listener, waitChan chan error) (net.Conn, error) { + type connOrError struct { + conn net.Conn + err error + } + connChan := make(chan connOrError, 1) + go func() { + conn, err := listener.Accept() + connChan <- connOrError{conn, err} + close(connChan) + }() + select { + case result := <-connChan: + return result.conn, result.err + case childErr := <-waitChan: + waitChan <- childErr + return nil, fmt.Errorf("child exited early: %s", childErr) + } +} + 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) } - shimEnd, conn := openSocketPair() - shimEndResume, connResume := openSocketPair() + listener, err := net.ListenTCP("tcp4", &net.TCPAddr{IP: net.IP{127, 0, 0, 1}}) + if err != nil { + panic(err) + } + defer func() { + if listener != nil { + listener.Close() + } + }() shim_path := path.Join(buildDir, "ssl/test/bssl_shim") - var flags []string + flags := []string{"-port", strconv.Itoa(listener.Addr().(*net.TCPAddr).Port)} if test.testType == serverTest { flags = append(flags, "-server") @@ -909,6 +1363,15 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error { flags = append(flags, "-shim-writes-first") } + if test.exportKeyingMaterial > 0 { + flags = append(flags, "-export-keying-material", strconv.Itoa(test.exportKeyingMaterial)) + flags = append(flags, "-export-label", test.exportLabel) + flags = append(flags, "-export-context", test.exportContext) + if test.useExportContext { + flags = append(flags, "-use-export-context") + } + } + flags = append(flags, test.flags...) var shim *exec.Cmd @@ -919,13 +1382,13 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error { } else { shim = exec.Command(shim_path, flags...) } - shim.ExtraFiles = []*os.File{shimEnd, shimEndResume} shim.Stdin = os.Stdin var stdoutBuf, stderrBuf bytes.Buffer shim.Stdout = &stdoutBuf shim.Stderr = &stderrBuf if mallocNumToFail >= 0 { - shim.Env = []string{"MALLOC_NUMBER_TO_FAIL=" + strconv.FormatInt(mallocNumToFail, 10)} + 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_ABORT_ON_FAIL=1") } @@ -935,8 +1398,8 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error { if err := shim.Start(); err != nil { panic(err) } - shimEnd.Close() - shimEndResume.Close() + waitChan := make(chan error, 1) + go func() { waitChan <- shim.Wait() }() config := test.config config.ClientSessionCache = NewLRUClientSessionCache(1) @@ -945,16 +1408,27 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error { if len(config.Certificates) == 0 { config.Certificates = []Certificate{getRSACertificate()} } + } else { + // Supply a ServerName to ensure a constant session cache key, + // rather than falling back to net.Conn.RemoteAddr. + if len(config.ServerName) == 0 { + config.ServerName = "test" + } } - err := doExchange(test, &config, conn, test.messageLen, - false /* not a resumption */) - conn.Close() + conn, err := acceptOrWait(listener, waitChan) + if err == nil { + err = doExchange(test, &config, conn, test.messageLen, false /* not a resumption */) + conn.Close() + } if err == nil && test.resumeSession { var resumeConfig Config if test.resumeConfig != nil { resumeConfig = *test.resumeConfig + if len(resumeConfig.ServerName) == 0 { + resumeConfig.ServerName = config.ServerName + } if len(resumeConfig.Certificates) == 0 { resumeConfig.Certificates = []Certificate{getRSACertificate()} } @@ -966,12 +1440,20 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error { } else { resumeConfig = config } - err = doExchange(test, &resumeConfig, connResume, test.messageLen, - true /* resumption */) + var connResume net.Conn + connResume, err = acceptOrWait(listener, waitChan) + if err == nil { + err = doExchange(test, &resumeConfig, connResume, test.messageLen, true /* resumption */) + connResume.Close() + } } - connResume.Close() - childErr := shim.Wait() + // Close the listener now. This is to avoid hangs should the shim try to + // open more connections than expected. + listener.Close() + listener = nil + + childErr := <-waitChan if exitError, ok := childErr.(*exec.ExitError); ok { if exitError.Sys().(syscall.WaitStatus).ExitStatus() == 88 { return errMoreMallocs @@ -981,7 +1463,7 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error { stdout := string(stdoutBuf.Bytes()) stderr := string(stderrBuf.Bytes()) failed := err != nil || childErr != nil - correctFailure := len(test.expectedError) == 0 || strings.Contains(stdout, test.expectedError) + correctFailure := len(test.expectedError) == 0 || strings.Contains(stderr, test.expectedError) localError := "none" if err != nil { localError = err.Error() @@ -1008,10 +1490,10 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error { panic("internal error") } - return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s", msg, localError, childError, string(stdoutBuf.Bytes()), stderr) + return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s", msg, localError, childError, stdout, stderr) } - if !*useValgrind && len(stderr) > 0 { + if !*useValgrind && !failed && len(stderr) > 0 { println(stderr) } @@ -1047,12 +1529,14 @@ 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}, {"ECDHE-ECDSA-AES256-GCM", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384}, {"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}, {"ECDHE-ECDSA-AES256-SHA384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384}, + {"ECDHE-ECDSA-CHACHA20-POLY1305", TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256}, {"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA}, {"ECDHE-PSK-AES128-GCM-SHA256", TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256}, {"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, @@ -1061,6 +1545,7 @@ var testCipherSuites = []struct { {"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384}, {"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, {"ECDHE-RSA-AES256-SHA384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384}, + {"ECDHE-RSA-CHACHA20-POLY1305", TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, {"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA}, {"PSK-AES128-CBC-SHA", TLS_PSK_WITH_AES_128_CBC_SHA}, {"PSK-AES256-CBC-SHA", TLS_PSK_WITH_AES_256_CBC_SHA}, @@ -1076,7 +1561,8 @@ func hasComponent(suiteName, component string) bool { func isTLS12Only(suiteName string) bool { return hasComponent(suiteName, "GCM") || hasComponent(suiteName, "SHA256") || - hasComponent(suiteName, "SHA384") + hasComponent(suiteName, "SHA384") || + hasComponent(suiteName, "POLY1305") } func isDTLSCipher(suiteName string) bool { @@ -1454,6 +1940,17 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) }) testCases = append(testCases, testCase{ protocol: protocol, + name: "Basic-Client-Implicit" + suffix, + config: Config{ + Bugs: ProtocolBugs{ + MaxHandshakeRecordLength: maxHandshakeRecordLength, + }, + }, + flags: append(flags, "-implicit-handshake"), + resumeSession: true, + }) + testCases = append(testCases, testCase{ + protocol: protocol, testType: serverTest, name: "Basic-Server" + suffix, config: Config{ @@ -1477,6 +1974,30 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) flags: flags, resumeSession: true, }) + testCases = append(testCases, testCase{ + protocol: protocol, + testType: serverTest, + name: "Basic-Server-Implicit" + suffix, + config: Config{ + Bugs: ProtocolBugs{ + MaxHandshakeRecordLength: maxHandshakeRecordLength, + }, + }, + flags: append(flags, "-implicit-handshake"), + resumeSession: true, + }) + testCases = append(testCases, testCase{ + protocol: protocol, + testType: serverTest, + name: "Basic-Server-EarlyCallback" + suffix, + config: Config{ + Bugs: ProtocolBugs{ + MaxHandshakeRecordLength: maxHandshakeRecordLength, + }, + }, + flags: append(flags, "-use-early-callback"), + resumeSession: true, + }) // TLS client auth. testCases = append(testCases, testCase{ @@ -1588,6 +2109,8 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) expectedNextProtoType: npn, }) + // TODO(davidben): Add tests for when False Start doesn't trigger. + // Client does False Start and negotiates NPN. testCases = append(testCases, testCase{ protocol: protocol, @@ -1626,9 +2149,27 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) resumeSession: true, }) + // Client does False Start but doesn't explicitly call + // SSL_connect. + testCases = append(testCases, testCase{ + protocol: protocol, + name: "FalseStart-Implicit" + suffix, + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + NextProtos: []string{"foo"}, + Bugs: ProtocolBugs{ + MaxHandshakeRecordLength: maxHandshakeRecordLength, + }, + }, + flags: append(flags, + "-implicit-handshake", + "-false-start", + "-advertise-alpn", "\x03foo"), + }) + // False Start without session tickets. testCases = append(testCases, testCase{ - name: "FalseStart-SessionTicketsDisabled", + name: "FalseStart-SessionTicketsDisabled" + suffix, config: Config{ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, NextProtos: []string{"foo"}, @@ -1710,17 +2251,36 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) }, flags: flags, }) + } +} + +func addDDoSCallbackTests() { + // DDoS callback. + + for _, resume := range []bool{false, true} { + suffix := "Resume" + if resume { + suffix = "No" + suffix + } testCases = append(testCases, testCase{ - testType: serverTest, - protocol: protocol, - name: "CookieExchange" + suffix, - config: Config{ - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, - }, - flags: append(flags, "-cookie-exchange"), + testType: serverTest, + name: "Server-DDoS-OK-" + suffix, + flags: []string{"-install-ddos-callback"}, + resumeSession: resume, + }) + + failFlag := "-fail-ddos-callback" + if resume { + failFlag = "-fail-second-ddos-callback" + } + testCases = append(testCases, testCase{ + testType: serverTest, + name: "Server-DDoS-Reject-" + suffix, + flags: []string{"-install-ddos-callback", failFlag}, + resumeSession: resume, + shouldFail: true, + expectedError: ":CONNECTION_REJECTED:", }) } } @@ -1976,7 +2536,7 @@ func addExtensionTests() { }) testCases = append(testCases, testCase{ testType: clientTest, - name: "ServerNameExtensionClient", + name: "ServerNameExtensionClientMismatch", config: Config{ Bugs: ProtocolBugs{ ExpectServerName: "mismatch.com", @@ -1988,7 +2548,7 @@ func addExtensionTests() { }) testCases = append(testCases, testCase{ testType: clientTest, - name: "ServerNameExtensionClient", + name: "ServerNameExtensionClientMissing", config: Config{ Bugs: ProtocolBugs{ ExpectServerName: "missing.com", @@ -2201,27 +2761,40 @@ func addResumptionVersionTests() { suffix += "-DTLS" } - testCases = append(testCases, testCase{ - protocol: protocol, - name: "Resume-Client" + suffix, - resumeSession: true, - config: Config{ - MaxVersion: sessionVers.version, - CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, - Bugs: ProtocolBugs{ - AllowSessionVersionMismatch: true, + if sessionVers.version == resumeVers.version { + testCases = append(testCases, testCase{ + protocol: protocol, + name: "Resume-Client" + suffix, + resumeSession: true, + config: Config{ + MaxVersion: sessionVers.version, + CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, }, - }, - expectedVersion: sessionVers.version, - resumeConfig: &Config{ - MaxVersion: resumeVers.version, - CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, - Bugs: ProtocolBugs{ - AllowSessionVersionMismatch: true, + expectedVersion: sessionVers.version, + expectedResumeVersion: resumeVers.version, + }) + } else { + testCases = append(testCases, testCase{ + protocol: protocol, + name: "Resume-Client-Mismatch" + suffix, + resumeSession: true, + config: Config{ + MaxVersion: sessionVers.version, + CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, }, - }, - expectedResumeVersion: resumeVers.version, - }) + expectedVersion: sessionVers.version, + resumeConfig: &Config{ + MaxVersion: resumeVers.version, + CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, + Bugs: ProtocolBugs{ + AllowSessionVersionMismatch: true, + }, + }, + expectedResumeVersion: resumeVers.version, + shouldFail: true, + expectedError: ":OLD_SESSION_VERSION_NOT_RETURNED:", + }) + } testCases = append(testCases, testCase{ protocol: protocol, @@ -2265,6 +2838,22 @@ func addResumptionVersionTests() { } } } + + testCases = append(testCases, testCase{ + name: "Resume-Client-CipherMismatch", + resumeSession: true, + config: Config{ + CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, + }, + resumeConfig: &Config{ + CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, + Bugs: ProtocolBugs{ + SendCipherSuite: TLS_RSA_WITH_AES_128_CBC_SHA, + }, + }, + shouldFail: true, + expectedError: ":OLD_SESSION_CIPHER_NOT_RETURNED:", + }) } func addRenegotiationTests() { @@ -2276,6 +2865,17 @@ func addRenegotiationTests() { }) testCases = append(testCases, testCase{ testType: serverTest, + name: "Renegotiate-Server-Full", + config: Config{ + Bugs: ProtocolBugs{ + NeverResumeOnRenego: true, + }, + }, + flags: []string{"-renegotiate"}, + shimWritesFirst: true, + }) + testCases = append(testCases, testCase{ + testType: serverTest, name: "Renegotiate-Server-EmptyExt", config: Config{ Bugs: ProtocolBugs{ @@ -2328,12 +2928,43 @@ func addRenegotiationTests() { }, flags: []string{"-allow-unsafe-legacy-renegotiation"}, }) + testCases = append(testCases, testCase{ + testType: serverTest, + name: "Renegotiate-Server-ClientInitiated-Forbidden", + renegotiate: true, + flags: []string{"-reject-peer-renegotiations"}, + shouldFail: true, + expectedError: ":NO_RENEGOTIATION:", + expectedLocalError: "remote error: no renegotiation", + }) + // Regression test for CVE-2015-0291. + testCases = append(testCases, testCase{ + testType: serverTest, + name: "Renegotiate-Server-NoSignatureAlgorithms", + config: Config{ + Bugs: ProtocolBugs{ + NeverResumeOnRenego: true, + NoSignatureAlgorithmsOnRenego: true, + }, + }, + flags: []string{"-renegotiate"}, + shimWritesFirst: true, + }) // TODO(agl): test the renegotiation info SCSV. testCases = append(testCases, testCase{ name: "Renegotiate-Client", renegotiate: true, }) testCases = append(testCases, testCase{ + name: "Renegotiate-Client-Full", + config: Config{ + Bugs: ProtocolBugs{ + NeverResumeOnRenego: true, + }, + }, + renegotiate: true, + }) + testCases = append(testCases, testCase{ name: "Renegotiate-Client-EmptyExt", renegotiate: true, config: Config{ @@ -2372,6 +3003,14 @@ func addRenegotiationTests() { renegotiateCiphers: []uint16{TLS_RSA_WITH_RC4_128_SHA}, }) testCases = append(testCases, testCase{ + name: "Renegotiate-Client-Forbidden", + renegotiate: true, + flags: []string{"-reject-peer-renegotiations"}, + shouldFail: true, + expectedError: ":NO_RENEGOTIATION:", + expectedLocalError: "remote error: no renegotiation", + }) + testCases = append(testCases, testCase{ name: "Renegotiate-SameClientVersion", renegotiate: true, config: Config{ @@ -2418,7 +3057,7 @@ func addFastRadioPaddingTests() { }) testCases = append(testCases, testCase{ protocol: dtls, - name: "FastRadio-Padding", + name: "FastRadio-Padding-DTLS", config: Config{ Bugs: ProtocolBugs{ RequireFastradioPadding: true, @@ -2534,6 +3173,196 @@ func addSigningHashTests() { }, }, }) + + // Test that hash preferences are enforced. BoringSSL defaults to + // rejecting MD5 signatures. + testCases = append(testCases, testCase{ + testType: serverTest, + name: "SigningHash-ClientAuth-Enforced", + config: Config{ + Certificates: []Certificate{rsaCertificate}, + SignatureAndHashes: []signatureAndHash{ + {signatureRSA, hashMD5}, + // Advertise SHA-1 so the handshake will + // proceed, but the shim's preferences will be + // ignored in CertificateVerify generation, so + // MD5 will be chosen. + {signatureRSA, hashSHA1}, + }, + Bugs: ProtocolBugs{ + IgnorePeerSignatureAlgorithmPreferences: true, + }, + }, + flags: []string{"-require-any-client-certificate"}, + shouldFail: true, + expectedError: ":WRONG_SIGNATURE_TYPE:", + }) + + testCases = append(testCases, testCase{ + name: "SigningHash-ServerKeyExchange-Enforced", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + SignatureAndHashes: []signatureAndHash{ + {signatureRSA, hashMD5}, + }, + Bugs: ProtocolBugs{ + IgnorePeerSignatureAlgorithmPreferences: true, + }, + }, + shouldFail: true, + expectedError: ":WRONG_SIGNATURE_TYPE:", + }) +} + +// timeouts is the retransmit schedule for BoringSSL. It doubles and +// caps at 60 seconds. On the 13th timeout, it gives up. +var timeouts = []time.Duration{ + 1 * time.Second, + 2 * time.Second, + 4 * time.Second, + 8 * time.Second, + 16 * time.Second, + 32 * time.Second, + 60 * time.Second, + 60 * time.Second, + 60 * time.Second, + 60 * time.Second, + 60 * time.Second, + 60 * time.Second, + 60 * time.Second, +} + +func addDTLSRetransmitTests() { + // Test that this is indeed the timeout schedule. Stress all + // four patterns of handshake. + for i := 1; i < len(timeouts); i++ { + number := strconv.Itoa(i) + testCases = append(testCases, testCase{ + protocol: dtls, + name: "DTLS-Retransmit-Client-" + number, + config: Config{ + Bugs: ProtocolBugs{ + TimeoutSchedule: timeouts[:i], + }, + }, + resumeSession: true, + flags: []string{"-async"}, + }) + testCases = append(testCases, testCase{ + protocol: dtls, + testType: serverTest, + name: "DTLS-Retransmit-Server-" + number, + config: Config{ + Bugs: ProtocolBugs{ + TimeoutSchedule: timeouts[:i], + }, + }, + resumeSession: true, + flags: []string{"-async"}, + }) + } + + // Test that exceeding the timeout schedule hits a read + // timeout. + testCases = append(testCases, testCase{ + protocol: dtls, + name: "DTLS-Retransmit-Timeout", + config: Config{ + Bugs: ProtocolBugs{ + TimeoutSchedule: timeouts, + }, + }, + resumeSession: true, + flags: []string{"-async"}, + shouldFail: true, + expectedError: ":READ_TIMEOUT_EXPIRED:", + }) + + // Test that timeout handling has a fudge factor, due to API + // problems. + testCases = append(testCases, testCase{ + protocol: dtls, + name: "DTLS-Retransmit-Fudge", + config: Config{ + Bugs: ProtocolBugs{ + TimeoutSchedule: []time.Duration{ + timeouts[0] - 10*time.Millisecond, + }, + }, + }, + resumeSession: true, + flags: []string{"-async"}, + }) + + // Test that the final Finished retransmitting isn't + // duplicated if the peer badly fragments everything. + testCases = append(testCases, testCase{ + testType: serverTest, + protocol: dtls, + name: "DTLS-Retransmit-Fragmented", + config: Config{ + Bugs: ProtocolBugs{ + TimeoutSchedule: []time.Duration{timeouts[0]}, + MaxHandshakeRecordLength: 2, + }, + }, + flags: []string{"-async"}, + }) +} + +func addExportKeyingMaterialTests() { + for _, vers := range tlsVersions { + if vers.version == VersionSSL30 { + continue + } + testCases = append(testCases, testCase{ + name: "ExportKeyingMaterial-" + vers.name, + config: Config{ + MaxVersion: vers.version, + }, + exportKeyingMaterial: 1024, + exportLabel: "label", + exportContext: "context", + useExportContext: true, + }) + testCases = append(testCases, testCase{ + name: "ExportKeyingMaterial-NoContext-" + vers.name, + config: Config{ + MaxVersion: vers.version, + }, + exportKeyingMaterial: 1024, + }) + testCases = append(testCases, testCase{ + name: "ExportKeyingMaterial-EmptyContext-" + vers.name, + config: Config{ + MaxVersion: vers.version, + }, + exportKeyingMaterial: 1024, + useExportContext: true, + }) + testCases = append(testCases, testCase{ + name: "ExportKeyingMaterial-Small-" + vers.name, + config: Config{ + MaxVersion: vers.version, + }, + exportKeyingMaterial: 1, + exportLabel: "label", + exportContext: "context", + useExportContext: true, + }) + } + testCases = append(testCases, testCase{ + name: "ExportKeyingMaterial-SSL3", + config: Config{ + MaxVersion: VersionSSL30, + }, + exportKeyingMaterial: 1024, + exportLabel: "label", + exportContext: "context", + useExportContext: true, + shouldFail: true, + expectedError: "failed to export keying material", + }) } func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) { @@ -2566,27 +3395,47 @@ type statusMsg struct { err error } -func statusPrinter(doneChan chan struct{}, statusChan chan statusMsg, total int) { +func statusPrinter(doneChan chan *testOutput, statusChan chan statusMsg, total int) { var started, done, failed, lineLen int - defer close(doneChan) + testOutput := newTestOutput() for msg := range statusChan { + if !*pipe { + // Erase the previous status line. + var erase string + for i := 0; i < lineLen; i++ { + erase += "\b \b" + } + fmt.Print(erase) + } + if msg.started { started++ } else { done++ - } - fmt.Printf("\x1b[%dD\x1b[K", lineLen) + if msg.err != nil { + fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err) + failed++ + testOutput.addResult(msg.test.name, "FAIL") + } else { + if *pipe { + // Print each test instead of a status line. + fmt.Printf("PASSED (%s)\n", msg.test.name) + } + testOutput.addResult(msg.test.name, "PASS") + } + } - if msg.err != nil { - fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err) - failed++ + if !*pipe { + // Print a new status line. + line := fmt.Sprintf("%d/%d/%d/%d", failed, done, started, total) + lineLen = len(line) + os.Stdout.WriteString(line) } - line := fmt.Sprintf("%d/%d/%d/%d", failed, done, started, total) - lineLen = len(line) - os.Stdout.WriteString(line) } + + doneChan <- testOutput } func main() { @@ -2601,6 +3450,7 @@ func main() { addCBCPaddingTests() addCBCSplittingTests() addClientAuthTests() + addDDoSCallbackTests() addVersionNegotiationTests() addMinimumVersionTests() addD5BugTests() @@ -2611,6 +3461,8 @@ func main() { addDTLSReplayTests() addSigningHashTests() addFastRadioPaddingTests() + addDTLSRetransmitTests() + addExportKeyingMaterialTests() for _, async := range []bool{false, true} { for _, splitHandshake := range []bool{false, true} { for _, protocol := range []protocol{tls, dtls} { @@ -2625,7 +3477,7 @@ func main() { statusChan := make(chan statusMsg, numWorkers) testChan := make(chan *testCase, numWorkers) - doneChan := make(chan struct{}) + doneChan := make(chan *testOutput) go statusPrinter(doneChan, statusChan, len(testCases)) @@ -2643,7 +3495,17 @@ func main() { close(testChan) wg.Wait() close(statusChan) - <-doneChan + testOutput := <-doneChan fmt.Printf("\n") + + if *jsonOutput != "" { + if err := testOutput.writeTo(*jsonOutput); err != nil { + fmt.Fprintf(os.Stderr, "Error: %s\n", err) + } + } + + if !testOutput.allPassed { + os.Exit(1) + } } diff --git a/src/ssl/test/runner/test_output.go b/src/ssl/test/runner/test_output.go new file mode 100644 index 0000000..bcb7a93 --- /dev/null +++ b/src/ssl/test/runner/test_output.go @@ -0,0 +1,79 @@ +/* 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. */ + +package main + +import ( + "encoding/json" + "os" + "time" +) + +// testOutput is a representation of Chromium's JSON test result format. See +// https://www.chromium.org/developers/the-json-test-results-format +type testOutput struct { + Version int `json:"version"` + Interrupted bool `json:"interrupted"` + PathDelimiter string `json:"path_delimiter"` + SecondsSinceEpoch float64 `json:"seconds_since_epoch"` + NumFailuresByType map[string]int `json:"num_failures_by_type"` + Tests map[string]testResult `json:"tests"` + allPassed bool +} + +type testResult struct { + Actual string `json:"actual"` + Expected string `json:"expected"` + IsUnexpected bool `json:"is_unexpected"` +} + +func newTestOutput() *testOutput { + return &testOutput{ + Version: 3, + PathDelimiter: ".", + SecondsSinceEpoch: float64(time.Now().UnixNano()) / float64(time.Second/time.Nanosecond), + NumFailuresByType: make(map[string]int), + Tests: make(map[string]testResult), + allPassed: true, + } +} + +func (t *testOutput) addResult(name, result string) { + if _, found := t.Tests[name]; found { + panic(name) + } + t.Tests[name] = testResult{ + Actual: result, + Expected: "PASS", + IsUnexpected: result != "PASS", + } + t.NumFailuresByType[result]++ + if result != "PASS" { + t.allPassed = false + } +} + +func (t *testOutput) writeTo(name string) error { + file, err := os.Create(name) + if err != nil { + return err + } + defer file.Close() + out, err := json.MarshalIndent(t, "", " ") + if err != nil { + return err + } + _, err = file.Write(out) + return err +} diff --git a/src/ssl/test/scoped_types.h b/src/ssl/test/scoped_types.h new file mode 100644 index 0000000..7e92cee --- /dev/null +++ b/src/ssl/test/scoped_types.h @@ -0,0 +1,28 @@ +/* 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. */ + +#ifndef OPENSSL_HEADER_SSL_TEST_SCOPED_TYPES_H +#define OPENSSL_HEADER_SSL_TEST_SCOPED_TYPES_H + +#include + +#include "../../crypto/test/scoped_types.h" + + +using ScopedSSL = ScopedOpenSSLType; +using ScopedSSL_CTX = ScopedOpenSSLType; +using ScopedSSL_SESSION = ScopedOpenSSLType; + + +#endif // OPENSSL_HEADER_SSL_TEST_SCOPED_TYPES_H diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc index c032d96..25906f7 100644 --- a/src/ssl/test/test_config.cc +++ b/src/ssl/test/test_config.cc @@ -60,7 +60,6 @@ const Flag kBoolFlags[] = { { "-no-tls11", &TestConfig::no_tls11 }, { "-no-tls1", &TestConfig::no_tls1 }, { "-no-ssl3", &TestConfig::no_ssl3 }, - { "-cookie-exchange", &TestConfig::cookie_exchange }, { "-shim-writes-first", &TestConfig::shim_writes_first }, { "-tls-d5-bug", &TestConfig::tls_d5_bug }, { "-expect-session-miss", &TestConfig::expect_session_miss }, @@ -73,6 +72,15 @@ const Flag kBoolFlags[] = { { "-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 }, + { "-install-ddos-callback", &TestConfig::install_ddos_callback }, + { "-fail-ddos-callback", &TestConfig::fail_ddos_callback }, + { "-fail-second-ddos-callback", &TestConfig::fail_second_ddos_callback }, + { "-handshake-never-done", &TestConfig::handshake_never_done }, + { "-use-export-context", &TestConfig::use_export_context }, + { "-reject-peer-renegotiations", &TestConfig::reject_peer_renegotiations }, }; const Flag kStringFlags[] = { @@ -91,6 +99,9 @@ const Flag kStringFlags[] = { { "-psk", &TestConfig::psk }, { "-psk-identity", &TestConfig::psk_identity }, { "-srtp-profiles", &TestConfig::srtp_profiles }, + { "-cipher", &TestConfig::cipher }, + { "-export-label", &TestConfig::export_label }, + { "-export-context", &TestConfig::export_context }, }; const Flag kBase64Flags[] = { @@ -102,43 +113,15 @@ const Flag kBase64Flags[] = { }; const Flag kIntFlags[] = { + { "-port", &TestConfig::port }, { "-min-version", &TestConfig::min_version }, { "-max-version", &TestConfig::max_version }, { "-mtu", &TestConfig::mtu }, + { "-export-keying-material", &TestConfig::export_keying_material }, }; } // namespace -TestConfig::TestConfig() - : is_server(false), - is_dtls(false), - resume(false), - fallback_scsv(false), - require_any_client_certificate(false), - false_start(false), - async(false), - write_different_record_sizes(false), - cbc_record_splitting(false), - partial_write(false), - no_tls12(false), - no_tls11(false), - no_tls1(false), - no_ssl3(false), - cookie_exchange(false), - shim_writes_first(false), - tls_d5_bug(false), - expect_session_miss(false), - expect_extended_master_secret(false), - renegotiate(false), - allow_unsafe_legacy_renegotiation(false), - enable_ocsp_stapling(false), - enable_signed_cert_timestamps(false), - fastradio_padding(false), - min_version(0), - max_version(0), - mtu(0) { -} - bool ParseConfig(int argc, char **argv, TestConfig *out_config) { for (int i = 0; i < argc; i++) { bool *bool_field = FindField(out_config, kBoolFlags, argv[i]); diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h index ba54227..f107a0f 100644 --- a/src/ssl/test/test_config.h +++ b/src/ssl/test/test_config.h @@ -19,54 +19,65 @@ struct TestConfig { - TestConfig(); - - bool is_server; - bool is_dtls; - bool resume; - bool fallback_scsv; + int port = 0; + bool is_server = false; + bool is_dtls = false; + bool resume = false; + bool fallback_scsv = false; std::string key_file; std::string cert_file; std::string expected_server_name; std::string expected_certificate_types; - bool require_any_client_certificate; + bool require_any_client_certificate = false; std::string advertise_npn; std::string expected_next_proto; - bool false_start; + bool false_start = false; std::string select_next_proto; - bool async; - bool write_different_record_sizes; - bool cbc_record_splitting; - bool partial_write; - bool no_tls12; - bool no_tls11; - bool no_tls1; - bool no_ssl3; - bool cookie_exchange; + bool async = false; + bool write_different_record_sizes = false; + bool cbc_record_splitting = false; + bool partial_write = false; + bool no_tls12 = false; + bool no_tls11 = false; + bool no_tls1 = false; + bool no_ssl3 = false; std::string expected_channel_id; std::string send_channel_id; - bool shim_writes_first; - bool tls_d5_bug; + bool shim_writes_first = false; + bool tls_d5_bug = false; std::string host_name; std::string advertise_alpn; std::string expected_alpn; std::string expected_advertised_alpn; std::string select_alpn; - bool expect_session_miss; - bool expect_extended_master_secret; + bool expect_session_miss = false; + bool expect_extended_master_secret = false; std::string psk; std::string psk_identity; - bool renegotiate; - bool allow_unsafe_legacy_renegotiation; + bool renegotiate = false; + bool allow_unsafe_legacy_renegotiation = false; std::string srtp_profiles; - bool enable_ocsp_stapling; + bool enable_ocsp_stapling = false; std::string expected_ocsp_response; - bool enable_signed_cert_timestamps; + bool enable_signed_cert_timestamps = false; std::string expected_signed_cert_timestamps; - bool fastradio_padding; - int min_version; - int max_version; - int mtu; + bool fastradio_padding = false; + int min_version = 0; + int max_version = 0; + int mtu = 0; + bool implicit_handshake = false; + bool use_early_callback = false; + bool fail_early_callback = false; + bool install_ddos_callback = false; + bool fail_ddos_callback = false; + bool fail_second_ddos_callback = false; + std::string cipher; + bool handshake_never_done = false; + int export_keying_material = 0; + std::string export_label; + std::string export_context; + bool use_export_context = false; + bool reject_peer_renegotiations = false; }; bool ParseConfig(int argc, char **argv, TestConfig *out_config); -- cgit v1.1