external/boringssl: bump revision.
This change bumps the BoringSSL revision to the current tip-of-tree.
Change-Id: I91d5bf467e16e8d86cb19a4de873985f524e5faa
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 @@
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_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 <openssl/rand.h>
#include <openssl/x509.h>
-#include "ssl_locl.h"
+#include "internal.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; \
- } \
- }
-
-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 @@
* 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 @@
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 @@
}
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,26 +385,189 @@
return 0;
}
+/* 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;
+ }
-/* 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;
+ hm_fragment *frag = (hm_fragment *)item->data;
+ assert(s->d1->handshake_read_seq <= frag->msg_header.seq);
+
+ return s->d1->handshake_read_seq == frag->msg_header.seq &&
+ frag->reassembly == NULL;
+}
+
+/* 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;
+ }
+ frag_len -= chunk;
+ }
+ 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);
+
+ hm_fragment *frag;
+ if (item == NULL) {
+ /* 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;
+ }
+ }
+ 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 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;
+}
+
+/* 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 (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;
+ }
+
+ hm_fragment *frag = dtls1_get_buffered_message(s, &msg_hdr);
+ if (frag == NULL) {
+ return -1;
+ }
+ assert(frag->msg_header.msg_len == msg_len);
+
+ if (frag->reassembly == NULL) {
+ /* The message is already assembled. */
+ if (!dtls1_discard_fragment_body(s, frag_len)) {
+ return -1;
+ }
+ return 1;
+ }
+ assert(msg_len > 0);
+
+ /* 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);
+
+ return 1;
+}
+
+/* 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;
/* 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);
+ /* 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 (mt >= 0 && s->s3->tmp.message_type != mt) {
+ 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;
@@ -398,484 +578,86 @@
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;
+ /* 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;
+ }
}
- p = (uint8_t *)s->init_buf->data;
- msg_len = msg_hdr->msg_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);
- /* 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);
+ if (frag->msg_header.msg_len > (size_t)max) {
+ OPENSSL_PUT_ERROR(SSL, dtls1_get_message, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ goto err;
}
- memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
+ 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;
+ }
+
+ /* 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;
+ }
+ assert(len == (size_t)frag->msg_header.msg_len + DTLS1_HM_HEADER_LENGTH);
s->d1->handshake_read_seq++;
+ /* 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;
+
+ 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;
+ }
+ 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,
+ s->init_num + DTLS1_HM_HEADER_LENGTH, s,
+ s->msg_callback_arg);
+ }
+
+ pitem_free(item);
+ dtls1_hm_fragment_free(frag);
+
+ s->state = stn;
+ *ok = 1;
return s->init_num;
f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
- *ok = 0;
- return -1;
-}
-
-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;
- }
-
- 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;
- }
-
- return 0; /* no error */
-}
-
-
-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);
+err:
pitem_free(item);
-
- if (al == 0) {
- *ok = 1;
- return frag_len;
- }
-
- ssl3_send_alert(s, SSL3_AL_FATAL, al);
- s->init_num = 0;
- *ok = 0;
- return -1;
-}
-
-/* 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) {
- 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;
- }
-
- if (frag_len == 0) {
- return DTLS1_HM_FRAGMENT_RETRY;
- }
-
- /* 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;
- }
- }
-
- /* 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;
- }
- return DTLS1_HM_FRAGMENT_RETRY;
- }
-
- /* 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;
- }
-
- 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);
-
- if (is_complete) {
- OPENSSL_free(frag->reassembly);
- frag->reassembly = NULL;
- }
-
- if (item == NULL) {
- item = pitem_new(seq64be, frag);
- if (item == NULL) {
- i = -1;
- 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 and control
- * would never have reached this branch. */
- assert(item != NULL);
- }
-
- return DTLS1_HM_FRAGMENT_RETRY;
-
-err:
- if (frag != NULL && item == NULL) {
- dtls1_hm_fragment_free(frag);
- }
- *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;
-
- if ((msg_hdr->frag_off + frag_len) > msg_hdr->msg_len) {
- 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);
- }
-
- return DTLS1_HM_FRAGMENT_RETRY;
-
-err:
- if (frag != NULL && item == NULL) {
- dtls1_hm_fragment_free(frag);
- }
- *ok = 0;
- return i;
-}
-
-
-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;
- }
-
- /* 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;
- }
-
- /* Handshake fails if message header is incomplete */
- if (i != DTLS1_HM_HEADER_LENGTH) {
- al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, dtls1_get_message_fragment,
- 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 (!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 ((al = dtls1_preprocess_fragment(s, &msg_hdr, max))) {
- goto f_err;
- }
-
- /* 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;
-
-f_err:
- ssl3_send_alert(s, SSL3_AL_FATAL, al);
- s->init_num = 0;
-
+ dtls1_hm_fragment_free(frag);
*ok = 0;
return -1;
}
@@ -913,7 +695,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 <assert.h>
#include <stdio.h>
+#include <string.h>
#include <openssl/bn.h>
#include <openssl/buf.h>
#include <openssl/dh.h>
#include <openssl/evp.h>
+#include <openssl/err.h>
#include <openssl/md5.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/rand.h>
-#include "ssl_locl.h"
+#include "internal.h"
static int dtls1_get_hello_verify(SSL *s);
@@ -156,7 +158,6 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
!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 <limits.h>
#include <stdio.h>
+#include <string.h>
#if defined(OPENSSL_WINDOWS)
#include <sys/timeb.h>
@@ -70,51 +71,17 @@
#include <openssl/mem.h>
#include <openssl/obj.h>
-#include "ssl_locl.h"
+#include "internal.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);
+/* DTLS1_MTU_TIMEOUTS is the maximum number of timeouts to expire
+ * before starting to decrease the MTU. */
+#define DTLS1_MTU_TIMEOUTS 2
-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,
-};
+/* DTLS1_MAX_TIMEOUTS is the maximum number of timeouts to expire
+ * before failing the DTLS handshake. */
+#define DTLS1_MAX_TIMEOUTS 12
-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,
-};
+static void get_current_time(const SSL *ssl, struct timeval *out_clock);
int dtls1_new(SSL *s) {
DTLS1_STATE *d1;
@@ -129,30 +96,12 @@
}
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 @@
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 @@
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 @@
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 @@
}
/* 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 @@
&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_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 @@
}
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 @@
}
}
- 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 @@
return 0;
}
-int dtls1_handle_timeout(SSL *s) {
- /* if no timer is expired, don't do anything */
- if (!dtls1_is_timer_expired(s)) {
- return 0;
- }
-
- dtls1_double_timeout(s);
-
- if (dtls1_check_timeout_num(s) < 0) {
+int DTLSv1_handle_timeout(SSL *ssl) {
+ if (!SSL_IS_DTLS(ssl)) {
return -1;
}
- s->d1->timeout.read_timeouts++;
- if (s->d1->timeout.read_timeouts > DTLS1_TMO_READ_COUNT) {
- s->d1->timeout.read_timeouts = 1;
+ /* if no timer is expired, don't do anything */
+ if (!dtls1_is_timer_expired(ssl)) {
+ return 0;
}
- dtls1_start_timer(s);
- return dtls1_retransmit_buffered_messages(s);
+ dtls1_double_timeout(ssl);
+
+ if (dtls1_check_timeout_num(ssl) < 0) {
+ return -1;
+ }
+
+ 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 @@
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 <stdio.h>
-#include <errno.h>
#include <assert.h>
+#include <stdio.h>
+#include <string.h>
#include <openssl/buf.h>
#include <openssl/mem.h>
@@ -119,7 +119,7 @@
#include <openssl/err.h>
#include <openssl/rand.h>
-#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 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 @@
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 @@
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 @@
}
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 @@
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 @@
* 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 @@
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 @@
* 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 @@
/* |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 @@
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). */
+ /* If we get here, then type != rr->type. */
- /* 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 ((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 @@
}
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 @@
}
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 @@
goto start;
}
- /* Unexpected handshake message (Client Hello, or protocol violation) */
- if ((s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) &&
- !s->in_handshake) {
+ /* 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);
- /* 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;
- }
-
- /* 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;
+ /* We already handled these. */
+ assert(rr->type != SSL3_RT_CHANGE_CIPHER_SPEC && rr->type != SSL3_RT_ALERT);
- 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;
- }
- }
-
- /* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 <stdio.h>
+#include <string.h>
#include <openssl/bytestring.h>
-#include <openssl/obj.h>
#include <openssl/err.h>
+#include <openssl/obj.h>
-#include "ssl_locl.h"
+#include "internal.h"
#include <openssl/srtp.h>
@@ -169,7 +170,7 @@
}
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 <openssl/bn.h>
#include <openssl/buf.h>
#include <openssl/dh.h>
+#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/md5.h>
#include <openssl/obj.h>
#include <openssl/rand.h>
#include <openssl/x509.h>
-#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 @@
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 @@
}
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 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
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/ssl_locl.h b/src/ssl/internal.h
similarity index 79%
rename from src/ssl/ssl_locl.h
rename to src/ssl/internal.h
index a0c323c..3bd749d 100644
--- a/src/ssl/ssl_locl.h
+++ b/src/ssl/internal.h
@@ -139,25 +139,161 @@
* OTHERWISE.
*/
-#ifndef HEADER_SSL_LOCL_H
-#define HEADER_SSL_LOCL_H
+#ifndef OPENSSL_HEADER_SSL_INTERNAL_H
+#define OPENSSL_HEADER_SSL_INTERNAL_H
#include <openssl/base.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
#include <openssl/aead.h>
-#include <openssl/bio.h>
-#include <openssl/buf.h>
-#include <openssl/dsa.h>
-#include <openssl/err.h>
-#include <openssl/rsa.h>
+#include <openssl/pqueue.h>
#include <openssl/ssl.h>
#include <openssl/stack.h>
+#if defined(OPENSSL_WINDOWS)
+/* Windows defines struct timeval in winsock2.h. */
+#pragma warning(push, 3)
+#include <winsock2.h>
+#pragma warning(pop)
+#else
+#include <sys/types.h>
+#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), \
@@ -261,110 +397,10 @@
/* 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)
+#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)
@@ -381,36 +417,30 @@
((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_kDHE <- 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
+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;
+ STACK_OF(X509) *chain;
} CERT_PKEY;
typedef struct cert_st {
@@ -428,19 +458,20 @@
* 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;
+ 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);
- EC_KEY *ecdh_tmp;
- /* Callback for generating ephemeral ECDH keys */
+
+ /* 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);
- /* 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
@@ -488,14 +519,10 @@
* 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) */
+ STACK_OF(X509) *cert_chain; /* as received from peer (not for SSL2) */
/* The 'peer_...' members are used only by clients. */
int peer_cert_type;
@@ -535,6 +562,8 @@
/* 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);
@@ -546,18 +575,22 @@
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 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);
- 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));
+ 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
@@ -570,7 +603,6 @@
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;
@@ -581,20 +613,14 @@
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_HM_HEADER_LENGTH(s) s->method->hhlen
#define ssl_handshake_start(s) \
- (((uint8_t *)s->init_buf->data) + s->enc_method->hhlen)
+ (((uint8_t *)s->init_buf->data) + s->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)
+ s->method->set_handshake_header(s, htype, len)
+#define ssl_do_write(s) s->method->do_write(s)
/* Values for enc_flags */
@@ -604,11 +630,9 @@
#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
+#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. */
@@ -633,20 +657,117 @@
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<<i| corresponds to |max_seq_num - i|. */
+ uint64_t map;
+ /* max_seq_num is the largest sequence number seen so far. It
+ * is a 64-bit value in big-endian encoding. */
+ uint8_t max_seq_num[8];
+} DTLS1_BITMAP;
+
+/* TODO(davidben): This structure is used for both incoming messages and
+ * outgoing messages. |is_ccs| and |epoch| are only used in the latter and
+ * should be moved elsewhere. */
+struct hm_header_st {
+ uint8_t type;
+ uint32_t msg_len;
+ uint16_t seq;
+ uint32_t frag_off;
+ uint32_t frag_len;
+ int is_ccs;
+ /* epoch, for buffered outgoing messages, is the epoch the message was
+ * originally sent in. */
+ uint16_t epoch;
+};
+
+/* TODO(davidben): This structure is used for both incoming messages and
+ * outgoing messages. |fragment| and |reassembly| are only used in the former
+ * and should be moved elsewhere. */
+typedef struct hm_fragment_st {
+ struct hm_header_st msg_header;
+ uint8_t *fragment;
+ uint8_t *reassembly;
+} hm_fragment;
+
+typedef struct dtls1_state_st {
+ /* send_cookie is true if we are resending the ClientHello
+ * with a cookie from a HelloVerifyRequest. */
+ unsigned int send_cookie;
+
+ uint8_t cookie[DTLS1_COOKIE_LENGTH];
+ size_t cookie_len;
+
+ /* The current data and handshake epoch. This is initially undefined, and
+ * starts at zero once the initial handshake is completed. */
+ uint16_t r_epoch;
+ uint16_t w_epoch;
+
+ /* records being received in the current epoch */
+ DTLS1_BITMAP bitmap;
+
+ /* handshake message numbers */
+ uint16_t handshake_write_seq;
+ uint16_t next_handshake_write_seq;
+
+ uint16_t handshake_read_seq;
+
+ /* save last sequence number for retransmissions */
+ uint8_t last_write_sequence[8];
+
+ /* buffered_messages is a priority queue of incoming handshake messages that
+ * have yet to be processed.
+ *
+ * TODO(davidben): This data structure may as well be a ring buffer of fixed
+ * size. */
+ pqueue buffered_messages;
+
+ /* send_messages is a priority queue of outgoing handshake messages sent in
+ * the most recent handshake flight.
+ *
+ * TODO(davidben): This data structure may as well be a STACK_OF(T). */
+ pqueue sent_messages;
+
+ unsigned int mtu; /* max DTLS packet size */
+
+ struct hm_header_st w_msg_hdr;
+
+ /* num_timeouts is the number of times the retransmit timer has fired since
+ * the last time it was reset. */
+ unsigned int num_timeouts;
+
+ /* Indicates when the last handshake msg or heartbeat sent will
+ * timeout. */
+ struct timeval next_timeout;
+
+ /* Timeout duration */
+ unsigned short timeout_duration;
+
+ unsigned int change_cipher_spec_ok;
+} DTLS1_STATE;
+
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);
@@ -655,50 +776,27 @@
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);
+STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs);
+int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, uint8_t *p);
struct ssl_cipher_preference_list_st *ssl_cipher_preference_list_dup(
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);
+ 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_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_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);
@@ -707,10 +805,10 @@
* 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);
+void ssl_get_compatible_server_ciphers(SSL *s, uint32_t *out_mask_k,
+ uint32_t *out_mask_a);
-STACK_OF(SSL_CIPHER) * ssl_get_ciphers_by_id(SSL *s);
+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);
@@ -731,11 +829,11 @@
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);
+ long max, enum ssl_hash_message_t 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_hash_current_message incorporates the current handshake message into the
+ * handshake hash. It returns one on success and zero on allocation failure. */
+int ssl3_hash_current_message(SSL *s);
/* ssl3_cert_verify_hash writes the CertificateVerify hash into the bytes
* pointed to by |out| and writes the number of bytes to |*out_len|. |out| must
@@ -747,8 +845,8 @@
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);
+size_t ssl3_num_ciphers(void);
+const SSL_CIPHER *ssl3_get_cipher(size_t i);
int ssl3_renegotiate(SSL *ssl);
int ssl3_renegotiate_check(SSL *ssl);
int ssl3_dispatch_alert(SSL *s);
@@ -757,13 +855,12 @@
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);
+int 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);
+int ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk);
const SSL_CIPHER *ssl3_choose_cipher(
- SSL *ssl, STACK_OF(SSL_CIPHER) * clnt,
+ 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);
@@ -785,18 +882,19 @@
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);
+/* ssl3_record_sequence_update increments the sequence number in |seq|. It
+ * returns one on success and zero on wraparound. */
+int ssl3_record_sequence_update(uint8_t *seq, size_t seq_len);
+
int ssl3_do_change_cipher_spec(SSL *ssl);
-void ssl3_set_handshake_header(SSL *s, int htype, unsigned long len);
+int 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 ssl3_read_n(SSL *s, int n, 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,
@@ -810,17 +908,16 @@
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);
+int dtls1_set_handshake_header(SSL *s, int type, unsigned long len);
+int dtls1_handshake_write(SSL *s);
+
+const SSL_CIPHER *dtls1_get_cipher(size_t i);
void dtls1_start_timer(SSL *s);
void dtls1_stop_timer(SSL *s);
int dtls1_is_timer_expired(SSL *s);
@@ -866,11 +963,10 @@
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);
+ enum ssl_hash_message_t hash_message, int *ok);
int dtls1_get_record(SSL *s);
int dtls1_dispatch_alert(SSL *s);
@@ -895,9 +991,10 @@
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_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);
int tls1_alert_code(int code);
int ssl3_alert_code(int code);
int ssl_ok(SSL *s);
@@ -975,7 +1072,9 @@
size_t client_random_len, const uint8_t *master,
size_t master_len);
-int ssl3_can_cutthrough(const SSL *s);
+/* ssl3_can_false_start returns one if |s| is allowed to False Start and zero
+ * otherwise. */
+int ssl3_can_false_start(const SSL *s);
/* ssl3_get_enc_method returns the SSL3_ENC_METHOD corresponding to
* |version|. */
@@ -1015,7 +1114,7 @@
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);
+uint32_t ssl_get_algorithm2(SSL *s);
int tls1_process_sigalgs(SSL *s, const CBS *sigalgs);
/* tls1_choose_signing_digest returns a digest for use with |pkey| based on the
@@ -1032,4 +1131,4 @@
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
+#endif /* OPENSSL_HEADER_SSL_INTERNAL_H */
diff --git a/src/ssl/pqueue/pqueue.c b/src/ssl/pqueue/pqueue.c
index ecaa139..14bd9b6 100644
--- a/src/ssl/pqueue/pqueue.c
+++ b/src/ssl/pqueue/pqueue.c
@@ -56,6 +56,7 @@
#include <openssl/pqueue.h>
+#include <assert.h>
#include <string.h>
#include <openssl/mem.h>
@@ -104,6 +105,8 @@
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 <openssl/ssl.h>
+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 @@
return 0;
}
pitem_free(item);
- pqueue_free(q);
+ clear_and_free_queue(q);
return 1;
}
@@ -101,7 +112,7 @@
}
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 <string.h>
#include <openssl/buf.h>
+#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
#include <openssl/md5.h>
@@ -124,7 +125,7 @@
#include <openssl/sha.h>
#include <openssl/x509.h>
-#include "ssl_locl.h"
+#include "internal.h"
/* ssl3_do_write sends |s->init_buf| in records of type 'type'
@@ -173,8 +174,7 @@
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 @@
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 @@
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 @@
/* 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 @@
f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
+err:
return 0;
}
@@ -296,11 +301,17 @@
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 @@
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 @@
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 @@
}
/* 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 @@
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 @@
#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 @@
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 <assert.h>
#include <stdio.h>
+#include <string.h>
#include <openssl/buf.h>
#include <openssl/bytestring.h>
#include <openssl/rand.h>
#include <openssl/obj.h>
+#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
#include <openssl/md5.h>
#include <openssl/dh.h>
#include <openssl/bn.h>
-#include <openssl/engine.h>
#include <openssl/x509.h>
-#include "ssl_locl.h"
+#include "internal.h"
#include "../crypto/dh/internal.h"
@@ -195,12 +196,21 @@
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 @@
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 @@
}
s->state = SSL3_ST_CW_CLNT_HELLO_A;
- s->ctx->stats.sess_connect++;
s->init_num = 0;
break;
@@ -389,12 +397,8 @@
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 @@
* 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 @@
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 @@
/* 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 @@
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 @@
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 @@
/* 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 @@
}
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
* 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 @@
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 @@
}
}
- 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 @@
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,21 +1222,13 @@
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);
+ ERR_R_EC_LIB);
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);
- goto err;
- }
- EC_GROUP_free(ngroup);
-
group = EC_KEY_get0_group(ecdh);
/* Next, get the encoded ECPoint */
@@ -1362,17 +1345,11 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
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_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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
}
/* 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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 <stdio.h>
#include <assert.h>
+#include <stdio.h>
+#include <string.h>
#include <openssl/err.h>
#include <openssl/evp.h>
@@ -142,7 +143,7 @@
#include <openssl/md5.h>
#include <openssl/obj.h>
-#include "ssl_locl.h"
+#include "internal.h"
static const uint8_t ssl3_pad_1[48] = {
@@ -235,12 +236,8 @@
}
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 @@
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 @@
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 @@
}
/* 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 @@
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 @@
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 @@
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 <assert.h>
#include <stdio.h>
+#include <string.h>
#include <openssl/buf.h>
#include <openssl/dh.h>
+#include <openssl/err.h>
#include <openssl/md5.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
-#include "ssl_locl.h"
+#include "internal.h"
#define SSL3_NUM_CIPHERS (sizeof(ssl3_ciphers) / sizeof(SSL_CIPHER))
@@ -165,77 +167,53 @@
/* 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 @@
/* 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 @@
/* 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 @@
/* 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 @@
/* 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 @@
/* 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 @@
/* 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 @@
/* 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 @@
/* 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 @@
/* 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 @@
/* 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 @@
/* 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 @@
/* 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 @@
},
{
- 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 @@
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 @@
: 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 @@
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 @@
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);
- }
+ ssl3_release_read_buffer(s);
+ ssl3_release_write_buffer(s);
+ DH_free(s->s3->tmp.dh);
+ 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);
- }
+ 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 @@
static int ssl3_set_req_cert_type(CERT *c, const uint8_t *p, size_t len);
+int SSL_session_reused(const SSL *ssl) {
+ return ssl->hit;
+}
+
+int SSL_total_renegotiations(const SSL *ssl) {
+ return ssl->s3->total_renegotiations;
+}
+
+int SSL_num_renegotiations(const SSL *ssl) {
+ return SSL_total_renegotiations(ssl);
+}
+
+int SSL_CTX_need_tmp_RSA(const SSL_CTX *ctx) {
+ return 0;
+}
+
+int SSL_need_rsa(const SSL *ssl) {
+ return 0;
+}
+
+int SSL_CTX_set_tmp_rsa(SSL_CTX *ctx, const RSA *rsa) {
+ return 1;
+}
+
+int SSL_set_tmp_rsa(SSL *ssl, const RSA *rsa) {
+ return 1;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+int SSL_CTX_enable_tls_channel_id(SSL_CTX *ctx) {
+ ctx->tlsext_channel_id_enabled = 1;
+ return 1;
+}
+
+int SSL_enable_tls_channel_id(SSL *ssl) {
+ ssl->tlsext_channel_id_enabled = 1;
+ return 1;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+int SSL_set_tlsext_host_name(SSL *ssl, const char *name) {
+ OPENSSL_free(ssl->tlsext_hostname);
+ ssl->tlsext_hostname = NULL;
+
+ 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;
+}
+
long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) {
int ret = 0;
- 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;
- }
- }
-
switch (cmd) {
- case SSL_CTRL_GET_SESSION_REUSED:
- ret = s->hit;
- break;
-
- case SSL_CTRL_GET_CLIENT_CERT_REQUEST:
- break;
-
- case SSL_CTRL_GET_NUM_RENEGOTIATIONS:
- ret = s->s3->num_renegotiations;
- break;
-
- case SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS:
- ret = s->s3->num_renegotiations;
- s->s3->num_renegotiations = 0;
- break;
-
- case SSL_CTRL_GET_TOTAL_RENEGOTIATIONS:
- ret = s->s3->total_renegotiations;
- break;
-
- case SSL_CTRL_GET_FLAGS:
- ret = (int)(s->s3->flags);
- break;
-
- case SSL_CTRL_NEED_TMP_RSA:
- /* Temporary RSA keys are never used. */
- ret = 0;
- break;
-
- 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;
-
- case SSL_CTRL_SET_TMP_RSA_CB:
- OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return ret;
-
- 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;
- }
-
- case SSL_CTRL_SET_TMP_DH_CB:
- OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return ret;
-
- case SSL_CTRL_SET_TMP_ECDH: {
- EC_KEY *ecdh = NULL;
-
- 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;
- }
-
- case SSL_CTRL_SET_TMP_ECDH_CB:
- OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return ret;
-
- 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;
-
- 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;
-
- case SSL_CTRL_SET_TLSEXT_DEBUG_ARG:
- s->tlsext_debug_arg = parg;
- ret = 1;
- break;
-
case SSL_CTRL_CHAIN:
if (larg) {
return ssl_cert_set1_chain(s->cert, (STACK_OF(X509) *)parg);
@@ -870,10 +754,6 @@
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 @@
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_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 @@
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 @@
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 @@
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 @@
return 1;
}
-long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void)) {
- CERT *cert;
+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;
+}
- cert = ctx->cert;
+int SSL_CTX_set_tlsext_servername_arg(SSL_CTX *ctx, void *arg) {
+ ctx->tlsext_servername_arg = arg;
+ return 1;
+}
- 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;
-
- default:
- return 0;
- }
-
+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 @@
/* 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 @@
}
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 @@
}
/* 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 @@
}
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 @@
}
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 @@
* 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 @@
/* 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 @@
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 <assert.h>
-#include <errno.h>
#include <limits.h>
#include <stdio.h>
+#include <string.h>
#include <openssl/buf.h>
#include <openssl/err.h>
@@ -117,23 +117,23 @@
#include <openssl/mem.h>
#include <openssl/rand.h>
-#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
/* 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 @@
}
}
+/* 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 @@
/* 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 @@
if (len == 0) {
return 0;
}
+ if (len == 1) {
+ /* No sense in fragmenting a one-byte record. */
+ fragment = 0;
+ }
- wr = &s->s3->wrec;
-
+ /* Align the output so the ciphertext is aligned to |SSL3_ALIGN_PAYLOAD|. */
+ uintptr_t align;
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;
+ /* Only CBC-mode ciphers require fragmenting. CBC-mode ciphertext is a
+ * multiple of the block size which we may assume is aligned. Thus we only
+ * need to account for a second copy of the record header. */
+ align = (uintptr_t)wb->buf + 2 * SSL3_RT_HEADER_LENGTH;
} else {
- align = (long)wb->buf + SSL3_RT_HEADER_LENGTH;
- align = (-align) & (SSL3_ALIGN_PAYLOAD - 1);
- p = wb->buf + align;
- wb->offset = align;
+ align = (uintptr_t)wb->buf + SSL3_RT_HEADER_LENGTH;
+ }
+ align = (0 - align) & (SSL3_ALIGN_PAYLOAD - 1);
+ uint8_t *out = wb->buf + align;
+ wb->offset = align;
+ size_t max_out = wb->len - wb->offset;
+
+ const uint8_t *orig_buf = buf;
+ unsigned int orig_len = len;
+ size_t fragment_len = 0;
+ if (fragment) {
+ /* Write the first byte in its own record as a countermeasure against
+ * known-IV weaknesses in CBC ciphersuites. (See
+ * http://www.openssl.org/~bodo/tls-cbc.txt.) */
+ if (!ssl3_seal_record(s, out, &fragment_len, max_out, type, buf, 1)) {
+ return -1;
+ }
+ out += fragment_len;
+ max_out -= fragment_len;
+ buf++;
+ len--;
}
- /* 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;
- } else {
- *(p++) = s->version >> 8;
- *(p++) = s->version & 0xff;
+ 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;
}
-
- /* 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);
- }
-
- /* 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;
- }
+ 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 @@
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 @@
* 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 @@
/* 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 @@
/* 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 @@
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 @@
* 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 @@
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 @@
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 @@
}
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 @@
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 @@
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;
+ /* 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_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;
-
- 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 @@
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 <assert.h>
#include <stdio.h>
#include <string.h>
@@ -159,6 +157,7 @@
#include <openssl/dh.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
+#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/md5.h>
@@ -168,7 +167,7 @@
#include <openssl/sha.h>
#include <openssl/x509.h>
-#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 @@
}
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 @@
goto end;
}
- s->ctx->stats.sess_accept_renegotiate++;
s->state = SSL3_ST_SW_HELLO_REQ_A;
break;
@@ -278,6 +271,15 @@
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 @@
}
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 @@
}
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 @@
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 @@
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 @@
* 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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
/* 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 @@
/* 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_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 @@
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 @@
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 @@
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 @@
} 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 @@
}
}
+ 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 @@
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 @@
}
err:
- if (ciphers != NULL) {
- sk_SSL_CIPHER_free(ciphers);
- }
+ sk_SSL_CIPHER_free(ciphers);
return ret;
}
@@ -1285,7 +1215,7 @@
/* 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 @@
/* 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_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_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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
- 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 @@
}
}
- 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 @@
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 @@
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 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 @@
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 @@
}
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 @@
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 @@
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 @@
}
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 @@
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 @@
/* 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 @@
!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 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 @@
}
}
- 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 @@
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 @@
}
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 @@
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 @@
/* 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 @@
/* 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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 <openssl/crypto.h>
-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 <openssl/bytestring.h>
#include <openssl/err.h>
+#include <openssl/mem.h>
#include <openssl/x509.h>
-#include "ssl_locl.h"
+#include "internal.h"
/* An SSL_SESSION is serialized as the following ASN.1 structure:
@@ -177,14 +178,14 @@
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 @@
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 @@
}
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 @@
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 @@
!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 @@
!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 @@
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 @@
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 @@
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 @@
!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 @@
!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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 <errno.h>
#include <stdio.h>
+#include <string.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
@@ -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 @@
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 @@
}
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 @@
}
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 @@
}
}
- /* 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 @@
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 @@
ret->chain_store = cert->chain_store;
}
- ret->ciphers_raw = NULL;
-
return ret;
err:
@@ -334,79 +314,32 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
-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 @@
*
* \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 @@
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 @@
* 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 @@
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 @@
* 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 @@
}
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 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 @@
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 (x != NULL) {
- if (no_chain) {
- 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);
- }
- }
-
- for (i = 0; i < sk_X509_num(extra_certs); i++) {
- x = sk_X509_value(extra_certs, i);
+ if (no_chain) {
if (!ssl_add_cert_to_buf(buf, l, x)) {
return 0;
}
+
+ 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);
}
return 1;
@@ -956,7 +859,7 @@
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 @@
}
cpk->chain = chain;
- if (rv == 0)
+ if (rv == 0) {
rv = 1;
+ }
err:
if (flags & SSL_BUILD_CHAIN_FLAG_CHECK) {
@@ -1069,9 +973,7 @@
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_cipher.c
similarity index 64%
rename from src/ssl/ssl_ciph.c
rename to src/ssl/ssl_cipher.c
index 60b9747..2cafeb9 100644
--- a/src/ssl/ssl_ciph.c
+++ b/src/ssl/ssl_cipher.c
@@ -138,20 +138,22 @@
* OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
* OTHERWISE. */
-#include <stdio.h>
#include <assert.h>
+#include <stdio.h>
+#include <string.h>
-#include <openssl/engine.h>
+#include <openssl/buf.h>
+#include <openssl/err.h>
#include <openssl/md5.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
#include <openssl/sha.h>
+#include <openssl/stack.h>
-#include "ssl_locl.h"
+#include "internal.h"
struct handshake_digest {
- long mask;
+ uint32_t mask;
const EVP_MD *(*md_func)(void);
};
@@ -171,78 +173,92 @@
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},
+typedef struct cipher_alias_st {
+ /* name is the name of the cipher alias. */
+ const char *name;
- /* "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},
+ /* 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) */
- {0, SSL_TXT_kRSA, 0, SSL_kRSA, 0, 0, 0, 0, 0, 0, 0, 0},
+ {SSL_TXT_kRSA, SSL_kRSA, ~0u, ~0u, ~0u, ~0u, ~0u},
- {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},
+ {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},
- {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},
+ {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},
- {0, SSL_TXT_kPSK, 0, SSL_kPSK, 0, 0, 0, 0, 0, 0, 0, 0},
+ {SSL_TXT_kPSK, SSL_kPSK, ~0u, ~0u, ~0u, ~0u, ~0u},
/* 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},
+ {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 */
- {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},
+ {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 */
- {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},
+ {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 */
- {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},
+ {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 */
- {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},
+ {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 */
- {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},
+ {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 */
- {0, SSL_TXT_FIPS, 0, 0, 0, 0, 0, 0, SSL_FIPS, 0, 0, 0},
+ {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,
@@ -360,18 +376,26 @@
}
}
-int ssl_get_handshake_digest(size_t idx, long *mask, const EVP_MD **md) {
+int ssl_get_handshake_digest(uint32_t *out_mask, const EVP_MD **out_md,
+ size_t idx) {
if (idx >= SSL_MAX_DIGEST) {
return 0;
}
- *mask = ssl_handshake_digests[idx].mask;
- *md = ssl_handshake_digests[idx].md_func();
+ *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) {
@@ -413,12 +437,11 @@
}
static void ssl_cipher_collect_ciphers(const SSL_PROTOCOL_METHOD *ssl_method,
- int num_of_ciphers,
+ size_t num_of_ciphers,
CIPHER_ORDER *co_list,
CIPHER_ORDER **head_p,
CIPHER_ORDER **tail_p) {
- int i, co_list_num;
- const SSL_CIPHER *c;
+ 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
@@ -427,9 +450,8 @@
/* 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) {
+ 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;
@@ -461,43 +483,31 @@
}
}
-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 */
-}
-
+/* 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(
- 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,
+ 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;
@@ -528,21 +538,23 @@
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) {
+ /* 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 && !(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;
- }
+ } 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. */
@@ -644,14 +656,15 @@
return 1;
}
-static int ssl_cipher_process_rulestr(const char *rule_str,
+static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method,
+ 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;
+ CIPHER_ORDER **tail_p) {
+ uint32_t 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;
+ int multi, rule, retval, ok, in_group = 0, has_group = 0;
+ size_t j, buf_len;
+ uint32_t cipher_id;
char ch;
retval = 1;
@@ -665,12 +678,6 @@
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;
}
@@ -687,7 +694,7 @@
!(ch >= '0' && ch <= '9')) {
OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr,
SSL_R_UNEXPECTED_OPERATOR_IN_GROUP);
- retval = found = in_group = 0;
+ retval = in_group = 0;
break;
} else {
rule = CIPHER_ADD;
@@ -707,7 +714,7 @@
} else if (ch == '[') {
if (in_group) {
OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_NESTED_GROUP);
- retval = found = in_group = 0;
+ retval = in_group = 0;
break;
}
in_group = 1;
@@ -723,7 +730,7 @@
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;
+ retval = in_group = 0;
break;
}
@@ -732,159 +739,82 @@
continue;
}
- alg_mkey = 0;
- alg_auth = 0;
- alg_enc = 0;
- alg_mac = 0;
- alg_ssl = 0;
- algo_strength = 0;
+ 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;
- buflen = 0;
+ buf_len = 0;
while (((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9')) ||
((ch >= 'a') && (ch <= 'z')) || (ch == '-') || (ch == '.')) {
ch = *(++l);
- buflen++;
+ buf_len++;
}
- if (buflen == 0) {
+ 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 = found = in_group = 0;
+ retval = 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;
}
+
+ /* 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 (buflen == 8 && !strncmp(buf, "STRENGTH", 8)) {
+ 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,
@@ -900,14 +830,10 @@
while (*l != '\0' && !ITEM_SEP(*l)) {
l++;
}
- } else if (found) {
+ } 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);
- } else {
- while (*l != '\0' && !ITEM_SEP(*l)) {
- l++;
- }
}
}
@@ -921,20 +847,20 @@
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;
+ 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;
- 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) {
+ if (rule_str == NULL || out_cipher_list == NULL) {
return NULL;
}
@@ -956,84 +882,64 @@
/* 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,
+ 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_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);
+ 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, 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,
+ 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, 0, 0, SSL_CHACHA20POLY1305, 0, 0, 0, CIPHER_ADD,
+ 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, 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, ~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, 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,
+ 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);
- 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);
+ 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_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);
+ 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, 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);
+ 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_DEFAULT_CIPHER_LIST, &head, &tail,
- ca_list);
+ ok = ssl_cipher_process_rulestr(ssl_method, SSL_DEFAULT_CIPHER_LIST, &head,
+ &tail);
rule_p += 7;
if (*rule_p == ':') {
rule_p++;
@@ -1041,11 +947,9 @@
}
if (ok && strlen(rule_p) > 0) {
- ok = ssl_cipher_process_rulestr(rule_p, &head, &tail, ca_list);
+ ok = ssl_cipher_process_rulestr(ssl_method, rule_p, &head, &tail);
}
- OPENSSL_free((void *)ca_list); /* Not needed anymore */
-
if (!ok) {
goto err;
}
@@ -1091,21 +995,20 @@
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);
+ if (*out_cipher_list != NULL) {
+ ssl_cipher_preference_list_free(*out_cipher_list);
}
- *cipher_list = pref_list;
+ *out_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;
+ 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(*cipher_list_by_id, ssl_cipher_ptr_id_cmp);
+ (void) sk_SSL_CIPHER_set_cmp_func(*out_cipher_list_by_id,
+ ssl_cipher_ptr_id_cmp);
- sk_SSL_CIPHER_sort(*cipher_list_by_id);
+ sk_SSL_CIPHER_sort(*out_cipher_list_by_id);
} else {
sk_SSL_CIPHER_free(tmp_cipher_list);
tmp_cipher_list = NULL;
@@ -1114,32 +1017,177 @@
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(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);
}
- if (pref_list) {
- OPENSSL_free(pref_list);
- }
+ 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;
- unsigned long alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl;
+ 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;
@@ -1161,11 +1209,11 @@
kx = "RSA";
break;
- case SSL_kEDH:
+ case SSL_kDHE:
kx = "DH";
break;
- case SSL_kEECDH:
+ case SSL_kECDHE:
kx = "ECDH";
break;
@@ -1182,10 +1230,6 @@
au = "RSA";
break;
- case SSL_aNULL:
- au = "None";
- break;
-
case SSL_aECDSA:
au = "ECDSA";
break;
@@ -1262,8 +1306,9 @@
if (buf == NULL) {
len = 128;
buf = OPENSSL_malloc(len);
- if (buf == NULL)
- return "OPENSSL_malloc Error";
+ if (buf == NULL) {
+ return NULL;
+ }
} else if (len < 128) {
return "Buffer too small";
}
@@ -1272,109 +1317,18 @@
return buf;
}
-int SSL_CIPHER_is_AES(const SSL_CIPHER *c) {
- return (c->algorithm_enc & SSL_AES) != 0;
+const char *SSL_CIPHER_get_version(const SSL_CIPHER *cipher) {
+ return "TLSv1/SSLv3";
}
-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;
+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;
@@ -1385,16 +1339,9 @@
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. */
+ /* 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;
@@ -1404,15 +1351,9 @@
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) {
+ if (cipher->algorithm_mkey & SSL_kDHE || cipher->algorithm_mkey & SSL_kECDHE) {
return 1;
}
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 <openssl/err.h>
-
-#include <openssl/ssl.h>
-
-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 <stdio.h>
#include <assert.h>
+#include <stdio.h>
+#include <string.h>
#include <openssl/bytestring.h>
#include <openssl/dh.h>
-#include <openssl/engine.h>
+#include <openssl/err.h>
#include <openssl/lhash.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/rand.h>
#include <openssl/x509v3.h>
-#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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_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 @@
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 @@
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 @@
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 @@
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;
- }
+ X509_VERIFY_PARAM_free(s->param);
- if (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 @@
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 @@
}
}
- 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 @@
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 @@
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 @@
}
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,6 +945,12 @@
}
int SSL_renegotiate(SSL *s) {
+ 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;
+ }
+
if (s->renegotiate == 0) {
s->renegotiate = 1;
}
@@ -1013,236 +959,146 @@
return s->method->ssl_renegotiate(s);
}
-int SSL_renegotiate_abbreviated(SSL *s) {
- if (s->renegotiate == 0) {
- s->renegotiate = 1;
- }
-
- s->new_session = 0;
- return s->method->ssl_renegotiate(s);
-}
-
int SSL_renegotiate_pending(SSL *s) {
/* becomes true when negotiation is requested; false again once a handshake
* has finished */
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;
-
- case SSL_CTRL_CLEAR_OPTIONS:
- return s->options &= ~larg;
-
- case SSL_CTRL_MODE:
- return s->mode |= larg;
-
- case SSL_CTRL_CLEAR_MODE:
- return s->mode &= ~larg;
-
- case SSL_CTRL_GET_MAX_CERT_LIST:
- return s->max_cert_list;
-
- case SSL_CTRL_SET_MAX_CERT_LIST:
- l = s->max_cert_list;
- s->max_cert_list = larg;
- return l;
-
- 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;
-
- 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;
-
- case SSL_CTRL_GET_RI_SUPPORT:
- if (s->s3) {
- return s->s3->send_connection_binding;
- }
- return 0;
-
- case SSL_CTRL_CERT_FLAGS:
- return s->cert->cert_flags |= larg;
-
- case SSL_CTRL_CLEAR_CERT_FLAGS:
- return s->cert->cert_flags &= ~larg;
-
- 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;
- }
-
- /* Passing a NULL |parg| returns the size of a single
- * cipher suite value. */
- return 2;
-
- default:
- return s->method->ssl_ctrl(s, cmd, larg, parg);
- }
+uint32_t SSL_CTX_set_options(SSL_CTX *ctx, uint32_t options) {
+ ctx->options |= options;
+ return ctx->options;
}
-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;
+uint32_t SSL_set_options(SSL *ssl, uint32_t options) {
+ ssl->options |= options;
+ return ssl->options;
+}
- default:
- return s->method->ssl_callback_ctrl(s, cmd, fp);
+uint32_t SSL_CTX_clear_options(SSL_CTX *ctx, uint32_t options) {
+ ctx->options &= ~options;
+ return ctx->options;
+}
+
+uint32_t SSL_clear_options(SSL *ssl, uint32_t options) {
+ ssl->options &= ~options;
+ return ssl->options;
+}
+
+uint32_t SSL_CTX_get_options(const SSL_CTX *ctx) { return ctx->options; }
+
+uint32_t SSL_get_options(const SSL *ssl) { return ssl->options; }
+
+uint32_t SSL_CTX_set_mode(SSL_CTX *ctx, uint32_t mode) {
+ ctx->mode |= mode;
+ return ctx->mode;
+}
+
+uint32_t SSL_set_mode(SSL *ssl, uint32_t mode) {
+ ssl->mode |= mode;
+ return ssl->mode;
+}
+
+uint32_t SSL_CTX_clear_mode(SSL_CTX *ctx, uint32_t mode) {
+ ctx->mode &= ~mode;
+ return ctx->mode;
+}
+
+uint32_t SSL_clear_mode(SSL *ssl, uint32_t mode) {
+ ssl->mode &= ~mode;
+ return ssl->mode;
+}
+
+uint32_t SSL_CTX_get_mode(const SSL_CTX *ctx) { return ctx->mode; }
+
+uint32_t SSL_get_mode(const SSL *ssl) { return ssl->mode; }
+
+size_t SSL_CTX_get_max_cert_list(const SSL_CTX *ctx) {
+ return ctx->max_cert_list;
+}
+
+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;
+}
+
+size_t SSL_get_max_cert_list(const SSL *ssl) {
+ return ssl->max_cert_list;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+int SSL_get_secure_renegotiation_support(const SSL *ssl) {
+ return ssl->s3->send_connection_binding;
+}
+
+long SSL_ctrl(SSL *s, int cmd, long larg, void *parg) {
+ return s->method->ssl_ctrl(s, cmd, larg, parg);
}
LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx) { return ctx->sessions; }
-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;
-
- case SSL_CTRL_SESS_CACHE_FULL:
- return ctx->stats.sess_cache_full;
-
- case SSL_CTRL_OPTIONS:
- return ctx->options |= larg;
-
- case SSL_CTRL_CLEAR_OPTIONS:
- return ctx->options &= ~larg;
-
- case SSL_CTRL_MODE:
- return ctx->mode |= larg;
-
- case SSL_CTRL_CLEAR_MODE:
- return ctx->mode &= ~larg;
-
- 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;
-
- case SSL_CTRL_CERT_FLAGS:
- return ctx->cert->cert_flags |= larg;
-
- case SSL_CTRL_CLEAR_CERT_FLAGS:
- return ctx->cert->cert_flags &= ~larg;
-
- default:
- return ctx->method->ssl_ctx_ctrl(ctx, cmd, larg, parg);
- }
+size_t SSL_CTX_sess_number(const SSL_CTX *ctx) {
+ return lh_SSL_SESSION_num_items(ctx->sessions);
}
-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;
+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;
+}
- default:
- return ctx->method->ssl_ctx_callback_ctrl(ctx, cmd, fp);
- }
+unsigned long SSL_CTX_sess_get_cache_size(const SSL_CTX *ctx) {
+ return ctx->session_cache_size;
+}
+
+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;
+}
+
+int SSL_CTX_get_session_cache_mode(const SSL_CTX *ctx) {
+ return ctx->session_cache_mode;
+}
+
+long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) {
+ return ctx->method->ssl_ctx_ctrl(ctx, cmd, larg, parg);
}
int ssl_cipher_id_cmp(const void *in_a, const void *in_b) {
@@ -1275,7 +1131,7 @@
/* 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 @@
/* 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 @@
/* 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 @@
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_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 @@
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 @@
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 @@
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 @@
return sk;
err:
- if (sk != NULL) {
- sk_SSL_CIPHER_free(sk);
- }
+ sk_SSL_CIPHER_free(sk);
return NULL;
}
@@ -1691,17 +1538,9 @@
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 @@
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 @@
}
}
-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 @@
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 @@
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_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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
/* 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 @@
(((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 @@
}
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 @@
}
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 @@
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 @@
case SSL3_VERSION:
return "SSLv3";
+ case DTLS1_VERSION:
+ return "DTLSv1";
+
+ case DTLS1_2_VERSION:
+ return "DTLSv1.2";
+
default:
return "unknown";
}
@@ -2552,15 +2319,11 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
}
/* 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 (*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 @@
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 @@
*ssl_session_size = sizeof(SSL_SESSION);
}
-int ssl3_can_cutthrough(const SSL *s) {
- const SSL_CIPHER *c;
+int ssl3_can_false_start(const SSL *s) {
+ const SSL_CIPHER *const cipher = SSL_get_current_cipher(s);
- /* 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;
- }
-
- 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 @@
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 @@
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_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_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_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 <openssl/pem.h>
#include <openssl/x509.h>
-#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 @@
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 @@
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 @@
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 @@
}
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 @@
}
}
- 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 @@
RSA_free(rsa);
end:
- if (in != NULL) {
- BIO_free(in);
- }
+ BIO_free(in);
return ret;
}
@@ -275,11 +252,6 @@
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 @@
EVP_PKEY_free(pkey);
end:
- if (in != NULL) {
- BIO_free(in);
- }
+ BIO_free(in);
return ret;
}
@@ -349,10 +319,6 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
RSA_free(rsa);
end:
- if (in != NULL) {
- BIO_free(in);
- }
+ BIO_free(in);
return ret;
}
@@ -560,11 +510,6 @@
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 @@
EVP_PKEY_free(pkey);
end:
- if (in != NULL) {
- BIO_free(in);
- }
+ BIO_free(in);
return ret;
}
@@ -668,7 +611,7 @@
* certificates. */
X509 *ca;
int r;
- unsigned long err;
+ uint32_t err;
SSL_CTX_clear_chain_certs(ctx);
@@ -697,11 +640,7 @@
}
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 <stdio.h>
+#include <string.h>
-#include <openssl/engine.h>
#include <openssl/err.h>
#include <openssl/lhash.h>
#include <openssl/mem.h>
#include <openssl/rand.h>
-#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_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 @@
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 @@
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 @@
}
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 @@
* 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 @@
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 @@
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 @@
/* 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 @@
if (!remove_session_lock(ctx, ctx->session_cache_tail, 0)) {
break;
}
- ctx->stats.sess_cache_full++;
}
}
}
@@ -623,45 +605,32 @@
return ret;
}
-void SSL_SESSION_free(SSL_SESSION *ss) {
- int i;
+SSL_SESSION *SSL_SESSION_up_ref(SSL_SESSION *session) {
+ if (session) {
+ CRYPTO_add(&session->references, 1, CRYPTO_LOCK_SSL_SESSION);
+ }
+ return session;
+}
- if (ss == NULL) {
+void SSL_SESSION_free(SSL_SESSION *session) {
+ if (session == NULL ||
+ CRYPTO_add(&session->references, -1, CRYPTO_LOCK_SSL_SESSION) > 0) {
return;
}
- i = CRYPTO_add(&ss->references, -1, CRYPTO_LOCK_SSL_SESSION);
- if (i > 0) {
- return;
- }
+ CRYPTO_free_ex_data(&g_ex_data_class, session, &session->ex_data);
- CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->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 @@
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 @@
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 @@
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 <stdio.h>
-#include "ssl_locl.h"
+#include "internal.h"
const char *SSL_state_string_long(const SSL *s) {
const char *str;
@@ -382,14 +382,6 @@
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 @@
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 <stdio.h>
-#include <string.h>
-
-#include <openssl/base64.h>
-#include <openssl/bio.h>
-#include <openssl/err.h>
-#include <openssl/ssl.h>
-
-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 <stdio.h>
+#include <string.h>
+
+#include <string>
+#include <vector>
+
+#include <openssl/base64.h>
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+
+#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<uint8_t> *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<uint8_t> 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 <openssl/err.h>
#include <openssl/mem.h>
-#include "ssl_locl.h"
+#include "internal.h"
int SSL_SESSION_print_fp(FILE *fp, const SSL_SESSION *x) {
@@ -145,8 +145,9 @@
}
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 <stdio.h>
#include <assert.h>
+#include <stdio.h>
+#include <string.h>
#include <openssl/err.h>
#include <openssl/evp.h>
@@ -144,7 +145,7 @@
#include <openssl/obj.h>
#include <openssl/rand.h>
-#include "ssl_locl.h"
+#include "internal.h"
/* tls1_P_hash computes the TLS P_<hash> function as described in RFC 5246,
@@ -225,7 +226,7 @@
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 @@
/* 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 @@
}
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 @@
}
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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;
+ 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;
}
- val = OPENSSL_malloc(vallen);
- if (val == NULL) {
- goto err2;
- }
-
- 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;
+ }
+ uint8_t *seed = OPENSSL_malloc(seed_len);
+ if (seed == NULL) {
+ OPENSSL_PUT_ERROR(SSL, tls1_export_keying_material, ERR_R_MALLOC_FAILURE);
+ return 0;
}
- /* 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;
+ 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);
}
- /* 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);
- }
-
+ 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 <assert.h>
#include <stdio.h>
#include <stdlib.h>
-#include <assert.h>
+#include <string.h>
#include <openssl/bytestring.h>
+#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/rand.h>
-#include "ssl_locl.h"
+#include "internal.h"
static int tls_decrypt_ticket(SSL *s, const uint8_t *tick, int ticklen,
@@ -133,16 +135,12 @@
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 @@
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 @@
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 @@
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 @@
ret = 1;
done:
- if (extension_types)
- OPENSSL_free(extension_types);
+ OPENSSL_free(extension_types);
return ret;
}
@@ -367,7 +356,7 @@
};
static const uint16_t eccurves_default[] = {
- 23, /* X9_64_prime256v1 */
+ 23, /* X9_62_prime256v1 */
24, /* secp384r1 */
};
@@ -399,6 +388,9 @@
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_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);
- for (i = 0; i < preflen; i++) {
- for (j = 0; j < supplen; j++) {
+ 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 < 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 @@
}
}
- 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 @@
* 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 @@
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 @@
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 @@
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 @@
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 *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 @@
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 @@
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 @@
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 @@
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 @@
}
/* 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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
}
}
- /* 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 @@
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 @@
return 1;
}
- /* Length must be even */
- if (CBS_len(sigalgs) % 2 != 0) {
+ if (CBS_len(sigalgs) % 2 != 0 ||
+ !CBS_stow(sigalgs, &c->peer_sigalgs, &c->peer_sigalgslen) ||
+ !tls1_set_shared_sigalgs(s)) {
return 0;
}
- /* Should never happen */
- if (!c) {
- return 0;
- }
-
- if (!CBS_stow(sigalgs, &c->peer_sigalgs, &c->peer_sigalgslen)) {
- return 0;
- }
-
- tls1_set_shared_sigalgs(s);
return 1;
}
@@ -2583,7 +2560,10 @@
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 @@
}
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 <stdio.h>
#include <assert.h>
+#include <stdio.h>
+#include <string.h>
#include <openssl/bytestring.h>
-#include <openssl/obj.h>
#include <openssl/err.h>
-#include "ssl_locl.h"
+#include "internal.h"
/* Add the client's renegotiation binding */
@@ -170,8 +170,7 @@
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 @@
)
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 @@
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 @@
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 @@
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 @@
return 1;
}
-static int async_free(BIO *bio) {
+static int AsyncFree(BIO *bio) {
if (bio == NULL) {
return 0;
}
@@ -128,51 +128,51 @@
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 <openssl/bio.h>
+#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 <arpa/inet.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <signal.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include <unistd.h>
+#else
+#include <io.h>
+#pragma warning(push, 3)
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#pragma warning(pop)
+
+#pragma comment(lib, "Ws2_32.lib")
#endif
#include <string.h>
@@ -28,126 +38,198 @@
#include <openssl/bio.h>
#include <openssl/buf.h>
#include <openssl/bytestring.h>
+#include <openssl/err.h>
#include <openssl/ssl.h>
+#include <memory>
+#include <vector>
+
+#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<TestState> 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;
-
- const TestConfig *config = GetConfigPtr(ctx->ssl);
-
- if (config->expected_server_name.empty()) {
- return 1;
- }
-
- 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;
- }
-
- 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 (!CBS_mem_equal(&host_name,
- (const uint8_t*)config->expected_server_name.data(),
- config->expected_server_name.size())) {
- fprintf(stderr, "Server name mismatch.\n");
- }
-
- return 1;
-}
-
-static int skip_verify(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 bool InstallCertificate(SSL *ssl) {
const TestConfig *config = GetConfigPtr(ssl);
- if (config->advertise_npn.empty())
+ 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()) {
+ 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;
+ }
+
+ 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 (!CBS_mem_equal(&host_name,
+ (const uint8_t*)config->expected_server_name.data(),
+ config->expected_server_name.size())) {
+ fprintf(stderr, "Server name mismatch.\n");
+ }
+ }
+
+ if (config->fail_early_callback) {
+ return -1;
+ }
+
+ // 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 SkipVerify(int preverify_ok, X509_STORE_CTX *store_ctx) {
+ return 1;
+}
+
+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()) {
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 @@
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 @@
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 @@
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<const char*>(&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<const sockaddr*>(&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 @@
//
// 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);
+ ssl_ctx->current_time_cb = CurrentTimeCallback;
+
+ SSL_CTX_set_info_callback(ssl_ctx.get(), InfoCallback);
+
return ssl_ctx;
-
- err:
- if (dh != NULL) {
- DH_free(dh);
- }
- if (ssl_ctx != NULL) {
- SSL_CTX_free(ssl_ctx);
- }
- return NULL;
}
-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,
+// 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;
+}
+
+// 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;
+}
+
+// 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) {
- early_callback_called = 0;
-
- SSL *ssl = SSL_new(ssl_ctx);
- if (ssl == NULL) {
- BIO_print_errors_fp(stdout);
- return 1;
+ ScopedSSL ssl(SSL_new(ssl_ctx));
+ if (!ssl) {
+ return false;
}
- if (!SetConfigPtr(ssl, config)) {
- BIO_print_errors_fp(stdout);
- return 1;
+ if (!SetConfigPtr(ssl.get(), config) ||
+ !SetTestState(ssl.get(), std::unique_ptr<TestState>(new TestState))) {
+ return false;
}
- if (config->fallback_scsv) {
- if (!SSL_enable_fallback_scsv(ssl)) {
- 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->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->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.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;
+ }
}
- 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;
- }
- 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());
}
- } 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 (!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;
+ } 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;
}
- if (!early_callback_called) {
+ if (is_resume &&
+ (!!SSL_session_reused(ssl.get()) == config->expect_session_miss)) {
+ fprintf(stderr, "session was%s reused\n",
+ SSL_session_reused(ssl.get()) ? "" : " not");
+ return false;
+ }
+
+ bool expect_handshake_done = is_resume || !config->false_start;
+ if (expect_handshake_done != GetTestState(ssl.get())->handshake_done) {
+ fprintf(stderr, "handshake was%s completed\n",
+ GetTestState(ssl.get())->handshake_done ? "" : " not");
+ return false;
+ }
+
+ if (config->is_server && !GetTestState(ssl.get())->early_callback_called) {
fprintf(stderr, "early callback not called\n");
- return 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->expect_extended_master_secret) {
- if (!ssl->session->extended_master_secret) {
- fprintf(stderr, "No EMS for session when expected");
- 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->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->expect_extended_master_secret) {
+ if (!ssl->session->extended_master_secret) {
+ fprintf(stderr, "No EMS for session when expected");
+ 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_ocsp_response.empty()) {
+ const uint8_t *data;
+ size_t len;
+ SSL_get0_ocsp_response(ssl.get(), &data, &len);
+ if (config->expected_ocsp_response.size() != len ||
+ memcmp(config->expected_ocsp_response.data(), data, len) != 0) {
+ fprintf(stderr, "OCSP response mismatch\n");
+ return false;
+ }
+ }
+
+ if (!config->expected_signed_cert_timestamps.empty()) {
+ const uint8_t *data;
+ size_t len;
+ SSL_get0_signed_cert_timestamp_list(ssl.get(), &data, &len);
+ if (config->expected_signed_cert_timestamps.size() != len ||
+ memcmp(config->expected_signed_cert_timestamps.data(),
+ data, len) != 0) {
+ fprintf(stderr, "SCT list mismatch\n");
+ return false;
+ }
}
}
if (config->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<uint8_t> result(
+ static_cast<size_t>(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<const uint8_t*>(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 @@
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<const uint8_t *>("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 <openssl/base.h>
+#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 <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
-#include <unistd.h>
-#include <stdio.h>
#include <new>
@@ -127,4 +136,4 @@
} // 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 <assert.h>
-#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
#include <string.h>
#include <openssl/mem.h>
@@ -23,58 +24,135 @@
namespace {
-extern const BIO_METHOD packeted_bio_method;
+extern const BIO_METHOD g_packeted_bio_method;
-static int packeted_write(BIO *bio, const char *in, int inl) {
+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 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 length prefix.
- uint8_t len_bytes[4];
- int ret = BIO_read(bio->next_bio, &len_bytes, sizeof(len_bytes));
+ // 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;
}
- // BIOs for which a partial length comes back are not supported.
- assert(ret == 4);
+
+ 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<uint64_t>(buf[0]) << 56) |
+ (static_cast<uint64_t>(buf[1]) << 48) |
+ (static_cast<uint64_t>(buf[2]) << 40) |
+ (static_cast<uint64_t>(buf[3]) << 32) |
+ (static_cast<uint64_t>(buf[4]) << 24) |
+ (static_cast<uint64_t>(buf[5]) << 16) |
+ (static_cast<uint64_t>(buf[6]) << 8) |
+ static_cast<uint64_t>(buf[7]);
+ timeout /= 1000; // Convert nanoseconds to microseconds.
+ timeval *out_timeout = reinterpret_cast<timeval *>(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];
+ ret = ReadAll(bio->next_bio, len_bytes, sizeof(len_bytes));
+ if (ret <= 0) {
+ BIO_copy_next_retry(bio);
+ return ret;
+ }
uint32_t len = (len_bytes[0] << 24) | (len_bytes[1] << 16) |
(len_bytes[2] << 8) | len_bytes[3];
- 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 @@
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 @@
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 @@
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 <openssl/base.h>
#include <openssl/bio.h>
+#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 <winsock2.h>
+#pragma warning(pop)
+#else
+#include <sys/types.h>
+#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 @@
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 @@
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 @@
{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 @@
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 @@
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 rsaKA(version uint16) keyAgreement {
- return &rsaKeyAgreement{}
+ return &rsaKeyAgreement{version: version}
}
func ecdheECDSAKA(version uint16) keyAgreement {
@@ -391,5 +407,8 @@
// 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 @@
type CurveID uint16
const (
+ CurveP224 CurveID = 21
CurveP256 CurveID = 23
CurveP384 CurveID = 24
CurveP521 CurveID = 25
@@ -429,15 +430,32 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
// 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 @@
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 @@
}
}
-// 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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
}
}
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 @@
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 @@
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 @@
// 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 @@
} 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 @@
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 @@
}
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 @@
import (
"bytes"
- "crypto/cipher"
"errors"
"fmt"
"io"
+ "math/rand"
"net"
)
@@ -38,7 +38,6 @@
}
func (c *Conn) dtlsDoReadRecord(want recordType) (recordType, *block, error) {
-Again:
recordHeaderLen := dtlsRecordHeaderLen
if c.rawInput == nil {
@@ -82,13 +81,6 @@
}
}
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,7 +105,134 @@
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) {
+ if typ != recordTypeHandshake {
+ // Only handshake messages are fragmented.
+ return c.dtlsWriteRawRecord(typ, data)
+ }
+
+ maxLen := c.config.Bugs.MaxHandshakeRecordLength
+ if maxLen <= 0 {
+ maxLen = 1024
+ }
+
+ // 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:]
+
+ isFinished := header[0] == typeFinished
+
+ if c.config.Bugs.SendEmptyFragments {
+ fragment := c.makeFragment(header, data, 0, 0)
+ c.pendingFragments = append(c.pendingFragments, fragment)
+ }
+
+ firstRun := true
+ fragOffset := 0
+ for firstRun || fragOffset < len(data) {
+ firstRun = false
+ fragLen := len(data) - fragOffset
+ if fragLen > maxLen {
+ fragLen = maxLen
+ }
+
+ 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]++
+ }
+
+ // 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 fragLen > (maxLen+1)/2 {
+ // Overlap each fragment by half.
+ fragLen = (maxLen + 1) / 2
+ }
+ }
+ 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]]
+ }
+ 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:]
+ }
+
+ // TODO(davidben): A real DTLS implementation needs to
+ // retransmit handshake messages. For testing purposes, we don't
+ // actually care.
+ if _, err := c.dtlsWriteRawRecord(recordTypeHandshake, fragment); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (c *Conn) dtlsWriteRawRecord(typ recordType, data []byte) (n int, err error) {
recordHeaderLen := dtlsRecordHeaderLen
maxLen := c.config.Bugs.MaxHandshakeRecordLength
if maxLen <= 0 {
@@ -122,118 +241,60 @@
b := c.out.newBlock()
- 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:]
- }
+ explicitIVLen := 0
+ explicitIVIsSeq := false
- firstRun := true
- for firstRun || len(data) > 0 {
- 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
- }
-
- // 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]
- }
-
- // Send the fragment.
- explicitIVLen := 0
- explicitIVIsSeq := false
-
- 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 {
+ 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.
+ // 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(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
- }
- 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
- }
+ } 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:], 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
- }
- n += m
- data = data[m:]
}
+ 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)
- // Increment the handshake sequence number for the next
- // handshake message.
- if typ == recordTypeHandshake {
- c.sendHandshakeSeq++
- }
-
if typ == recordTypeChangeCipherSpec {
err = c.out.changeCipherSpec(c.config)
if err != nil {
@@ -250,9 +311,9 @@
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 @@
}
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 @@
import (
"bytes"
- "crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
@@ -22,13 +21,14 @@
)
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
hs.writeClientHash(certVerify.marshal())
c.writeRecord(recordTypeHandshake, certVerify.marshal())
}
+ c.dtlsFlushHandshake()
hs.finishedHash.discardHandshakeBuffer()
@@ -825,15 +859,19 @@
} 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 @@
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 @@
masterSecret []byte
certsFromClient [][]byte
cert *Certificate
+ finishedBytes []byte
}
// serverHandshake performs a TLS handshake as a server.
@@ -71,6 +72,15 @@
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 @@
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 @@
}
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
// 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 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 @@
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,52 +6,117 @@
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) {
- var length uint32
- if err := binary.Read(p.Conn, binary.BigEndian, &length); err != nil {
+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 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
- }
- if n != len(b) {
- return 0, errors.New("internal error: length mismatch!")
- }
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
+ }
+
+ 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)
+ }
+ }
+}
+
type replayAdaptor struct {
net.Conn
prevWrite []byte
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 @@
// 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 @@
"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 @@
// 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 @@
// 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 @@
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 @@
},
{
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 {
@@ -840,27 +1286,6 @@
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
-}
-
type moreMallocsError struct{}
func (moreMallocsError) Error() string {
@@ -869,16 +1294,45 @@
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 @@
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 @@
} 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 @@
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 @@
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 @@
} 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 @@
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 @@
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 @@
{"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 @@
{"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 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 @@
})
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 @@
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 @@
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 @@
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 @@
},
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 @@
})
testCases = append(testCases, testCase{
testType: clientTest,
- name: "ServerNameExtensionClient",
+ name: "ServerNameExtensionClientMismatch",
config: Config{
Bugs: ProtocolBugs{
ExpectServerName: "mismatch.com",
@@ -1988,7 +2548,7 @@
})
testCases = append(testCases, testCase{
testType: clientTest,
- name: "ServerNameExtensionClient",
+ name: "ServerNameExtensionClientMissing",
config: Config{
Bugs: ProtocolBugs{
ExpectServerName: "missing.com",
@@ -2201,27 +2761,40 @@
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 @@
}
}
}
+
+ 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 @@
})
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 @@
},
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 @@
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 @@
})
testCases = append(testCases, testCase{
protocol: dtls,
- name: "FastRadio-Padding",
+ name: "FastRadio-Padding-DTLS",
config: Config{
Bugs: ProtocolBugs{
RequireFastradioPadding: true,
@@ -2534,6 +3173,196 @@
},
},
})
+
+ // 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 @@
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++
+
+ 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")
+ }
}
- fmt.Printf("\x1b[%dD\x1b[K", lineLen)
-
- 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 @@
addCBCPaddingTests()
addCBCSplittingTests()
addClientAuthTests()
+ addDDoSCallbackTests()
addVersionNegotiationTests()
addMinimumVersionTests()
addD5BugTests()
@@ -2611,6 +3461,8 @@
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 @@
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 @@
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 <openssl/ssl.h>
+
+#include "../../crypto/test/scoped_types.h"
+
+
+using ScopedSSL = ScopedOpenSSLType<SSL, SSL_free>;
+using ScopedSSL_CTX = ScopedOpenSSLType<SSL_CTX, SSL_CTX_free>;
+using ScopedSSL_SESSION = ScopedOpenSSLType<SSL_SESSION, SSL_SESSION_free>;
+
+
+#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 @@
{ "-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 @@
{ "-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<std::string> kStringFlags[] = {
@@ -91,6 +99,9 @@
{ "-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<std::string> kBase64Flags[] = {
@@ -102,43 +113,15 @@
};
const Flag<int> 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);