summaryrefslogtreecommitdiffstats
path: root/src/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'src/ssl')
-rw-r--r--src/ssl/CMakeLists.txt11
-rw-r--r--src/ssl/custom_extensions.c257
-rw-r--r--src/ssl/d1_both.c112
-rw-r--r--src/ssl/d1_clnt.c33
-rw-r--r--src/ssl/d1_lib.c25
-rw-r--r--src/ssl/d1_meth.c4
-rw-r--r--src/ssl/d1_pkt.c475
-rw-r--r--src/ssl/d1_srtp.c245
-rw-r--r--src/ssl/d1_srvr.c24
-rw-r--r--src/ssl/dtls_record.c308
-rw-r--r--src/ssl/internal.h534
-rw-r--r--src/ssl/s3_both.c146
-rw-r--r--src/ssl/s3_clnt.c811
-rw-r--r--src/ssl/s3_enc.c180
-rw-r--r--src/ssl/s3_lib.c346
-rw-r--r--src/ssl/s3_meth.c4
-rw-r--r--src/ssl/s3_pkt.c579
-rw-r--r--src/ssl/s3_srvr.c645
-rw-r--r--src/ssl/ssl_aead_ctx.c29
-rw-r--r--src/ssl/ssl_algs.c66
-rw-r--r--src/ssl/ssl_asn1.c393
-rw-r--r--src/ssl/ssl_buffer.c318
-rw-r--r--src/ssl/ssl_cert.c742
-rw-r--r--src/ssl/ssl_cipher.c239
-rw-r--r--src/ssl/ssl_file.c623
-rw-r--r--src/ssl/ssl_lib.c1992
-rw-r--r--src/ssl/ssl_rsa.c470
-rw-r--r--src/ssl/ssl_session.c (renamed from src/ssl/ssl_sess.c)660
-rw-r--r--src/ssl/ssl_stat.c114
-rw-r--r--src/ssl/ssl_test.cc276
-rw-r--r--src/ssl/ssl_txt.c8
-rw-r--r--src/ssl/t1_enc.c293
-rw-r--r--src/ssl/t1_lib.c3135
-rw-r--r--src/ssl/t1_reneg.c246
-rw-r--r--src/ssl/test/bssl_shim.cc731
-rw-r--r--src/ssl/test/runner/cipher_suites.go13
-rw-r--r--src/ssl/test/runner/common.go104
-rw-r--r--src/ssl/test/runner/conn.go117
-rw-r--r--src/ssl/test/runner/dtls.go15
-rw-r--r--src/ssl/test/runner/handshake_client.go42
-rw-r--r--src/ssl/test/runner/handshake_messages.go236
-rw-r--r--src/ssl/test/runner/handshake_server.go32
-rw-r--r--src/ssl/test/runner/runner.go2916
-rw-r--r--src/ssl/test/test_config.cc25
-rw-r--r--src/ssl/test/test_config.h22
-rw-r--r--src/ssl/tls_record.c338
46 files changed, 10093 insertions, 8841 deletions
diff --git a/src/ssl/CMakeLists.txt b/src/ssl/CMakeLists.txt
index cf5a29d..2785dcf 100644
--- a/src/ssl/CMakeLists.txt
+++ b/src/ssl/CMakeLists.txt
@@ -1,10 +1,11 @@
-include_directories(. .. ../include)
+include_directories(../include)
add_subdirectory(pqueue)
add_library(
ssl
+ custom_extensions.c
d1_both.c
d1_clnt.c
d1_lib.c
@@ -12,6 +13,7 @@ add_library(
d1_pkt.c
d1_srtp.c
d1_srvr.c
+ dtls_record.c
s3_both.c
s3_clnt.c
s3_enc.c
@@ -20,18 +22,19 @@ add_library(
s3_pkt.c
s3_srvr.c
ssl_aead_ctx.c
- ssl_algs.c
ssl_asn1.c
+ ssl_buffer.c
ssl_cert.c
ssl_cipher.c
+ ssl_file.c
ssl_lib.c
ssl_rsa.c
- ssl_sess.c
+ ssl_session.c
ssl_stat.c
ssl_txt.c
t1_enc.c
t1_lib.c
- t1_reneg.c
+ tls_record.c
$<TARGET_OBJECTS:pqueue>
)
diff --git a/src/ssl/custom_extensions.c b/src/ssl/custom_extensions.c
new file mode 100644
index 0000000..c94543d
--- /dev/null
+++ b/src/ssl/custom_extensions.c
@@ -0,0 +1,257 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/stack.h>
+
+#include "internal.h"
+
+
+void SSL_CUSTOM_EXTENSION_free(SSL_CUSTOM_EXTENSION *custom_extension) {
+ OPENSSL_free(custom_extension);
+}
+
+static const SSL_CUSTOM_EXTENSION *custom_ext_find(
+ STACK_OF(SSL_CUSTOM_EXTENSION) *stack,
+ unsigned *out_index, uint16_t value) {
+ size_t i;
+ for (i = 0; i < sk_SSL_CUSTOM_EXTENSION_num(stack); i++) {
+ const SSL_CUSTOM_EXTENSION *ext = sk_SSL_CUSTOM_EXTENSION_value(stack, i);
+ if (ext->value == value) {
+ if (out_index != NULL) {
+ *out_index = i;
+ }
+ return ext;
+ }
+ }
+
+ return NULL;
+}
+
+/* default_add_callback is used as the |add_callback| when the user doesn't
+ * provide one. For servers, it does nothing while, for clients, it causes an
+ * empty extension to be included. */
+static int default_add_callback(SSL *ssl, unsigned extension_value,
+ const uint8_t **out, size_t *out_len,
+ int *out_alert_value, void *add_arg) {
+ if (ssl->server) {
+ return 0;
+ }
+ *out_len = 0;
+ return 1;
+}
+
+static int custom_ext_add_hello(SSL *ssl, CBB *extensions) {
+ STACK_OF(SSL_CUSTOM_EXTENSION) *stack = ssl->ctx->client_custom_extensions;
+ if (ssl->server) {
+ stack = ssl->ctx->server_custom_extensions;
+ }
+
+ if (stack == NULL) {
+ return 1;
+ }
+
+ size_t i;
+ for (i = 0; i < sk_SSL_CUSTOM_EXTENSION_num(stack); i++) {
+ const SSL_CUSTOM_EXTENSION *ext = sk_SSL_CUSTOM_EXTENSION_value(stack, i);
+
+ if (ssl->server &&
+ !(ssl->s3->tmp.custom_extensions.received & (1u << i))) {
+ /* Servers cannot echo extensions that the client didn't send. */
+ continue;
+ }
+
+ const uint8_t *contents;
+ size_t contents_len;
+ int alert = SSL_AD_DECODE_ERROR;
+ CBB contents_cbb;
+
+ switch (ext->add_callback(ssl, ext->value, &contents, &contents_len, &alert,
+ ext->add_arg)) {
+ case 1:
+ if (!CBB_add_u16(extensions, ext->value) ||
+ !CBB_add_u16_length_prefixed(extensions, &contents_cbb) ||
+ !CBB_add_bytes(&contents_cbb, contents, contents_len) ||
+ !CBB_flush(extensions)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ ERR_add_error_dataf("extension: %u", (unsigned) ext->value);
+ if (ext->free_callback && 0 < contents_len) {
+ ext->free_callback(ssl, ext->value, contents, ext->add_arg);
+ }
+ return 0;
+ }
+
+ if (ext->free_callback && 0 < contents_len) {
+ ext->free_callback(ssl, ext->value, contents, ext->add_arg);
+ }
+
+ if (!ssl->server) {
+ assert((ssl->s3->tmp.custom_extensions.sent & (1u << i)) == 0);
+ ssl->s3->tmp.custom_extensions.sent |= (1u << i);
+ }
+ break;
+
+ case 0:
+ break;
+
+ default:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR);
+ ERR_add_error_dataf("extension: %u", (unsigned) ext->value);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int custom_ext_add_clienthello(SSL *ssl, CBB *extensions) {
+ return custom_ext_add_hello(ssl, extensions);
+}
+
+int custom_ext_parse_serverhello(SSL *ssl, int *out_alert, uint16_t value,
+ const CBS *extension) {
+ unsigned index;
+ const SSL_CUSTOM_EXTENSION *ext =
+ custom_ext_find(ssl->ctx->client_custom_extensions, &index, value);
+
+ if (/* Unknown extensions are not allowed in a ServerHello. */
+ ext == NULL ||
+ /* Also, if we didn't send the extension, that's also unacceptable. */
+ !(ssl->s3->tmp.custom_extensions.sent & (1u << index))) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ ERR_add_error_dataf("extension: %u", (unsigned)value);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ if (ext->parse_callback != NULL &&
+ !ext->parse_callback(ssl, value, CBS_data(extension), CBS_len(extension),
+ out_alert, ext->parse_arg)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR);
+ ERR_add_error_dataf("extension: %u", (unsigned)ext->value);
+ return 0;
+ }
+
+ return 1;
+}
+
+int custom_ext_parse_clienthello(SSL *ssl, int *out_alert, uint16_t value,
+ const CBS *extension) {
+ unsigned index;
+ const SSL_CUSTOM_EXTENSION *ext =
+ custom_ext_find(ssl->ctx->server_custom_extensions, &index, value);
+
+ if (ext == NULL) {
+ return 1;
+ }
+
+ assert((ssl->s3->tmp.custom_extensions.received & (1u << index)) == 0);
+ ssl->s3->tmp.custom_extensions.received |= (1u << index);
+
+ if (ext->parse_callback &&
+ !ext->parse_callback(ssl, value, CBS_data(extension), CBS_len(extension),
+ out_alert, ext->parse_arg)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR);
+ ERR_add_error_dataf("extension: %u", (unsigned)ext->value);
+ return 0;
+ }
+
+ return 1;
+}
+
+int custom_ext_add_serverhello(SSL *ssl, CBB *extensions) {
+ return custom_ext_add_hello(ssl, extensions);
+}
+
+/* MAX_NUM_CUSTOM_EXTENSIONS is the maximum number of custom extensions that
+ * can be set on an |SSL_CTX|. It's determined by the size of the bitset used
+ * to track when an extension has been sent. */
+#define MAX_NUM_CUSTOM_EXTENSIONS \
+ (sizeof(((struct ssl3_state_st *)NULL)->tmp.custom_extensions.sent) * 8)
+
+static int custom_ext_append(STACK_OF(SSL_CUSTOM_EXTENSION) **stack,
+ unsigned extension_value,
+ SSL_custom_ext_add_cb add_cb,
+ SSL_custom_ext_free_cb free_cb, void *add_arg,
+ SSL_custom_ext_parse_cb parse_cb,
+ void *parse_arg) {
+ if (add_cb == NULL ||
+ 0xffff < extension_value ||
+ SSL_extension_supported(extension_value) ||
+ /* Specifying a free callback without an add callback is nonsensical
+ * and an error. */
+ (*stack != NULL &&
+ (MAX_NUM_CUSTOM_EXTENSIONS <= sk_SSL_CUSTOM_EXTENSION_num(*stack) ||
+ custom_ext_find(*stack, NULL, extension_value) != NULL))) {
+ return 0;
+ }
+
+ SSL_CUSTOM_EXTENSION *ext = OPENSSL_malloc(sizeof(SSL_CUSTOM_EXTENSION));
+ if (ext == NULL) {
+ return 0;
+ }
+ ext->add_callback = add_cb;
+ ext->add_arg = add_arg;
+ ext->free_callback = free_cb;
+ ext->parse_callback = parse_cb;
+ ext->parse_arg = parse_arg;
+ ext->value = extension_value;
+
+ if (*stack == NULL) {
+ *stack = sk_SSL_CUSTOM_EXTENSION_new_null();
+ if (*stack == NULL) {
+ SSL_CUSTOM_EXTENSION_free(ext);
+ return 0;
+ }
+ }
+
+ if (!sk_SSL_CUSTOM_EXTENSION_push(*stack, ext)) {
+ SSL_CUSTOM_EXTENSION_free(ext);
+ if (sk_SSL_CUSTOM_EXTENSION_num(*stack) == 0) {
+ sk_SSL_CUSTOM_EXTENSION_free(*stack);
+ *stack = NULL;
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+int SSL_CTX_add_client_custom_ext(SSL_CTX *ctx, unsigned extension_value,
+ SSL_custom_ext_add_cb add_cb,
+ SSL_custom_ext_free_cb free_cb, void *add_arg,
+ SSL_custom_ext_parse_cb parse_cb,
+ void *parse_arg) {
+ return custom_ext_append(&ctx->client_custom_extensions, extension_value,
+ add_cb ? add_cb : default_add_callback, free_cb,
+ add_arg, parse_cb, parse_arg);
+}
+
+int SSL_CTX_add_server_custom_ext(SSL_CTX *ctx, unsigned extension_value,
+ SSL_custom_ext_add_cb add_cb,
+ SSL_custom_ext_free_cb free_cb, void *add_arg,
+ SSL_custom_ext_parse_cb parse_cb,
+ void *parse_arg) {
+ return custom_ext_append(&ctx->server_custom_extensions, extension_value,
+ add_cb ? add_cb : default_add_callback, free_cb,
+ add_arg, parse_cb, parse_arg);
+}
diff --git a/src/ssl/d1_both.c b/src/ssl/d1_both.c
index ac35a66..1acb3ce 100644
--- a/src/ssl/d1_both.c
+++ b/src/ssl/d1_both.c
@@ -111,6 +111,8 @@
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
+#include <openssl/ssl.h>
+
#include <assert.h>
#include <limits.h>
#include <stdio.h>
@@ -147,52 +149,44 @@ static void dtls1_fix_message_header(SSL *s, unsigned long frag_off,
unsigned long frag_len);
static unsigned char *dtls1_write_message_header(SSL *s, unsigned char *p);
-static hm_fragment *dtls1_hm_fragment_new(unsigned long frag_len,
- int reassembly) {
- hm_fragment *frag = NULL;
- uint8_t *buf = NULL;
- uint8_t *bitmask = NULL;
-
- frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment));
+static hm_fragment *dtls1_hm_fragment_new(size_t frag_len, int reassembly) {
+ hm_fragment *frag = OPENSSL_malloc(sizeof(hm_fragment));
if (frag == NULL) {
- OPENSSL_PUT_ERROR(SSL, dtls1_hm_fragment_new, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return NULL;
}
+ memset(frag, 0, sizeof(hm_fragment));
- if (frag_len) {
- buf = (uint8_t *)OPENSSL_malloc(frag_len);
- if (buf == NULL) {
- OPENSSL_PUT_ERROR(SSL, dtls1_hm_fragment_new, ERR_R_MALLOC_FAILURE);
- OPENSSL_free(frag);
- return NULL;
+ /* If the handshake message is empty, |frag->fragment| and |frag->reassembly|
+ * are NULL. */
+ if (frag_len > 0) {
+ frag->fragment = OPENSSL_malloc(frag_len);
+ if (frag->fragment == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
}
- }
-
- /* zero length fragment gets zero frag->fragment */
- frag->fragment = buf;
- /* Initialize reassembly bitmask if necessary */
- if (reassembly && frag_len > 0) {
- if (frag_len + 7 < frag_len) {
- OPENSSL_PUT_ERROR(SSL, dtls1_hm_fragment_new, ERR_R_OVERFLOW);
- return NULL;
- }
- size_t bitmask_len = (frag_len + 7) / 8;
- bitmask = (uint8_t *)OPENSSL_malloc(bitmask_len);
- if (bitmask == NULL) {
- OPENSSL_PUT_ERROR(SSL, dtls1_hm_fragment_new, ERR_R_MALLOC_FAILURE);
- if (buf != NULL) {
- OPENSSL_free(buf);
+ if (reassembly) {
+ /* Initialize reassembly bitmask. */
+ if (frag_len + 7 < frag_len) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ goto err;
}
- OPENSSL_free(frag);
- return NULL;
+ size_t bitmask_len = (frag_len + 7) / 8;
+ frag->reassembly = OPENSSL_malloc(bitmask_len);
+ if (frag->reassembly == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ memset(frag->reassembly, 0, bitmask_len);
}
- memset(bitmask, 0, bitmask_len);
}
- frag->reassembly = bitmask;
-
return frag;
+
+err:
+ dtls1_hm_fragment_free(frag);
+ return NULL;
}
void dtls1_hm_fragment_free(hm_fragment *frag) {
@@ -326,7 +320,7 @@ int dtls1_do_write(SSL *s, int type, enum dtls1_use_epoch_t use_epoch) {
if (curr_mtu <= DTLS1_HM_HEADER_LENGTH) {
/* To make forward progress, the MTU must, at minimum, fit the handshake
* header and one byte of handshake body. */
- OPENSSL_PUT_ERROR(SSL, dtls1_do_write, SSL_R_MTU_TOO_SMALL);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MTU_TOO_SMALL);
return -1;
}
@@ -344,7 +338,7 @@ int dtls1_do_write(SSL *s, int type, enum dtls1_use_epoch_t use_epoch) {
assert(type == SSL3_RT_CHANGE_CIPHER_SPEC);
/* ChangeCipherSpec cannot be fragmented. */
if (s->init_num > curr_mtu) {
- OPENSSL_PUT_ERROR(SSL, dtls1_do_write, SSL_R_MTU_TOO_SMALL);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MTU_TOO_SMALL);
return -1;
}
len = s->init_num;
@@ -450,8 +444,7 @@ static hm_fragment *dtls1_get_buffered_message(
frag->msg_header.msg_len != msg_hdr->msg_len) {
/* The new fragment must be compatible with the previous fragments from
* this message. */
- OPENSSL_PUT_ERROR(SSL, dtls1_get_buffered_message,
- SSL_R_FRAGMENT_MISMATCH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_FRAGMENT_MISMATCH);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return NULL;
}
@@ -473,11 +466,7 @@ static size_t dtls1_max_handshake_message_len(const SSL *s) {
/* dtls1_process_fragment reads a handshake fragment and processes it. It
* returns one if a fragment was successfully processed and 0 or -1 on error. */
static int dtls1_process_fragment(SSL *s) {
- /* Read handshake message header.
- *
- * 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. */
+ /* Read handshake message header. */
uint8_t header[DTLS1_HM_HEADER_LENGTH];
int ret = dtls1_read_bytes(s, SSL3_RT_HANDSHAKE, header,
DTLS1_HM_HEADER_LENGTH, 0);
@@ -485,7 +474,7 @@ static int dtls1_process_fragment(SSL *s) {
return ret;
}
if (ret != DTLS1_HM_HEADER_LENGTH) {
- OPENSSL_PUT_ERROR(SSL, dtls1_process_fragment, SSL_R_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
return -1;
}
@@ -494,14 +483,16 @@ static int dtls1_process_fragment(SSL *s) {
struct hm_header_st msg_hdr;
dtls1_get_message_header(header, &msg_hdr);
+ /* TODO(davidben): dtls1_read_bytes is the wrong abstraction for DTLS. There
+ * should be no need to reach into |s->s3->rrec.length|. */
const size_t frag_off = msg_hdr.frag_off;
const size_t frag_len = msg_hdr.frag_len;
const size_t msg_len = msg_hdr.msg_len;
if (frag_off > msg_len || frag_off + frag_len < frag_off ||
frag_off + frag_len > msg_len ||
- msg_len > dtls1_max_handshake_message_len(s)) {
- OPENSSL_PUT_ERROR(SSL, dtls1_process_fragment,
- SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ msg_len > dtls1_max_handshake_message_len(s) ||
+ frag_len > s->s3->rrec.length) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return -1;
}
@@ -535,8 +526,8 @@ static int dtls1_process_fragment(SSL *s) {
ret = dtls1_read_bytes(s, SSL3_RT_HANDSHAKE, frag->fragment + frag_off,
frag_len, 0);
if (ret != frag_len) {
- OPENSSL_PUT_ERROR(SSL, dtls1_process_fragment, SSL_R_UNEXPECTED_MESSAGE);
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return -1;
}
dtls1_hm_fragment_mark(frag, frag_off, frag_off + frag_len);
@@ -563,7 +554,7 @@ long dtls1_get_message(SSL *s, int st1, int stn, int msg_type, long max,
s->s3->tmp.reuse_message = 0;
if (msg_type >= 0 && s->s3->tmp.message_type != msg_type) {
al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, dtls1_get_message, SSL_R_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
goto f_err;
}
*ok = 1;
@@ -589,22 +580,19 @@ long dtls1_get_message(SSL *s, int st1, int stn, int msg_type, long max,
assert(frag->reassembly == NULL);
if (frag->msg_header.msg_len > (size_t)max) {
- OPENSSL_PUT_ERROR(SSL, dtls1_get_message, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
goto err;
}
+ /* Reconstruct the assembled message. */
+ size_t len;
CBB cbb;
+ CBB_zero(&cbb);
if (!BUF_MEM_grow(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_init_fixed(&cbb, (uint8_t *)s->init_buf->data, s->init_buf->max) ||
+ !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 */) ||
@@ -612,7 +600,7 @@ long dtls1_get_message(SSL *s, int st1, int stn, int msg_type, long max,
!CBB_add_bytes(&cbb, frag->fragment, frag->msg_header.msg_len) ||
!CBB_finish(&cbb, NULL, &len)) {
CBB_cleanup(&cbb);
- OPENSSL_PUT_ERROR(SSL, dtls1_get_message, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
assert(len == (size_t)frag->msg_header.msg_len + DTLS1_HM_HEADER_LENGTH);
@@ -628,7 +616,7 @@ long dtls1_get_message(SSL *s, int st1, int stn, int msg_type, long max,
if (msg_type >= 0 && s->s3->tmp.message_type != msg_type) {
al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, dtls1_get_message, SSL_R_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
goto f_err;
}
if (hash_message == ssl_hash_message && !ssl3_hash_current_message(s)) {
diff --git a/src/ssl/d1_clnt.c b/src/ssl/d1_clnt.c
index 92fb8f6..73a3f8a 100644
--- a/src/ssl/d1_clnt.c
+++ b/src/ssl/d1_clnt.c
@@ -112,6 +112,8 @@
* [including the GNU Public Licence.]
*/
+#include <openssl/ssl.h>
+
#include <assert.h>
#include <stdio.h>
#include <string.h>
@@ -128,6 +130,7 @@
#include "internal.h"
+
static int dtls1_get_hello_verify(SSL *s);
int dtls1_connect(SSL *s) {
@@ -188,9 +191,8 @@ int dtls1_connect(SSL *s) {
case SSL3_ST_CW_CLNT_HELLO_B:
s->shutdown = 0;
- /* every DTLS ClientHello resets Finished MAC */
- if (!ssl3_init_finished_mac(s)) {
- OPENSSL_PUT_ERROR(SSL, dtls1_connect, ERR_R_INTERNAL_ERROR);
+ if (!ssl3_init_handshake_buffer(s)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
ret = -1;
goto end;
}
@@ -261,7 +263,7 @@ int dtls1_connect(SSL *s) {
if (s->s3->tmp.certificate_status_expected) {
s->state = SSL3_ST_CR_CERT_STATUS_A;
} else {
- s->state = SSL3_ST_CR_KEY_EXCH_A;
+ s->state = SSL3_ST_VERIFY_SERVER_CERT;
}
} else {
skip = 1;
@@ -270,6 +272,16 @@ int dtls1_connect(SSL *s) {
s->init_num = 0;
break;
+ case SSL3_ST_VERIFY_SERVER_CERT:
+ ret = ssl3_verify_server_cert(s);
+ if (ret <= 0) {
+ goto end;
+ }
+
+ s->state = SSL3_ST_CR_KEY_EXCH_A;
+ s->init_num = 0;
+ break;
+
case SSL3_ST_CR_KEY_EXCH_A:
case SSL3_ST_CR_KEY_EXCH_B:
ret = ssl3_get_server_key_exchange(s);
@@ -278,13 +290,6 @@ int dtls1_connect(SSL *s) {
}
s->state = SSL3_ST_CR_CERT_REQ_A;
s->init_num = 0;
-
- /* at this point we check that we have the
- * required stuff from the server */
- if (!ssl3_check_cert_and_algorithm(s)) {
- ret = -1;
- goto end;
- }
break;
case SSL3_ST_CR_CERT_REQ_A:
@@ -426,7 +431,7 @@ int dtls1_connect(SSL *s) {
if (ret <= 0) {
goto end;
}
- s->state = SSL3_ST_CR_KEY_EXCH_A;
+ s->state = SSL3_ST_VERIFY_SERVER_CERT;
s->init_num = 0;
break;
@@ -483,7 +488,7 @@ int dtls1_connect(SSL *s) {
goto end;
default:
- OPENSSL_PUT_ERROR(SSL, dtls1_connect, SSL_R_UNKNOWN_STATE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE);
ret = -1;
goto end;
}
@@ -538,7 +543,7 @@ static int dtls1_get_hello_verify(SSL *s) {
!CBS_get_u8_length_prefixed(&hello_verify_request, &cookie) ||
CBS_len(&hello_verify_request) != 0) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, dtls1_get_hello_verify, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
diff --git a/src/ssl/d1_lib.c b/src/ssl/d1_lib.c
index ef7a9c9..cb95585 100644
--- a/src/ssl/d1_lib.c
+++ b/src/ssl/d1_lib.c
@@ -54,12 +54,18 @@
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com). */
-#include <openssl/base.h>
+#include <openssl/ssl.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+
#if defined(OPENSSL_WINDOWS)
#include <sys/timeb.h>
#else
@@ -67,11 +73,6 @@
#include <sys/time.h>
#endif
-#include <openssl/err.h>
-#include <openssl/mem.h>
-#include <openssl/obj.h>
-
-#include "internal.h"
/* DTLS1_MTU_TIMEOUTS is the maximum number of timeouts to expire
* before starting to decrease the MTU. */
@@ -152,8 +153,9 @@ void dtls1_free(SSL *s) {
}
int dtls1_supports_cipher(const SSL_CIPHER *cipher) {
- /* DTLS does not support stream ciphers. */
- return cipher->algorithm_enc != SSL_RC4;
+ /* DTLS does not support stream ciphers. The NULL cipher is rejected because
+ * it's not needed. */
+ return cipher->algorithm_enc != SSL_RC4 && cipher->algorithm_enc != SSL_eNULL;
}
void dtls1_start_timer(SSL *s) {
@@ -262,7 +264,7 @@ int dtls1_check_timeout_num(SSL *s) {
if (s->d1->num_timeouts > DTLS1_MAX_TIMEOUTS) {
/* fail the connection, enough alerts have been sent */
- OPENSSL_PUT_ERROR(SSL, dtls1_check_timeout_num, SSL_R_READ_TIMEOUT_EXPIRED);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_READ_TIMEOUT_EXPIRED);
return -1;
}
@@ -328,8 +330,9 @@ int dtls1_set_handshake_header(SSL *s, int htype, unsigned long len) {
s2n(msg_hdr->seq, p);
l2n3(0, p);
l2n3(msg_hdr->msg_len, p);
- return ssl3_finish_mac(s, serialised_header, sizeof(serialised_header)) &&
- ssl3_finish_mac(s, message + DTLS1_HM_HEADER_LENGTH, len);
+ return ssl3_update_handshake_hash(s, serialised_header,
+ sizeof(serialised_header)) &&
+ ssl3_update_handshake_hash(s, message + DTLS1_HM_HEADER_LENGTH, len);
}
int dtls1_handshake_write(SSL *s) {
diff --git a/src/ssl/d1_meth.c b/src/ssl/d1_meth.c
index d90f75b..d54a037 100644
--- a/src/ssl/d1_meth.c
+++ b/src/ssl/d1_meth.c
@@ -55,6 +55,8 @@
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com). */
+#include <openssl/ssl.h>
+
#include "internal.h"
@@ -69,8 +71,6 @@ static const SSL_PROTOCOL_METHOD DTLS_protocol_method = {
dtls1_read_close_notify,
dtls1_write_app_data,
dtls1_dispatch_alert,
- ssl3_ctrl,
- ssl3_ctx_ctrl,
dtls1_supports_cipher,
DTLS1_HM_HEADER_LENGTH,
dtls1_set_handshake_header,
diff --git a/src/ssl/d1_pkt.c b/src/ssl/d1_pkt.c
index 553499f..e2d505c 100644
--- a/src/ssl/d1_pkt.c
+++ b/src/ssl/d1_pkt.c
@@ -109,6 +109,8 @@
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
+#include <openssl/ssl.h>
+
#include <assert.h>
#include <stdio.h>
#include <string.h>
@@ -122,270 +124,66 @@
#include "internal.h"
-/* mod 128 saturating subtract of two 64-bit values in big-endian order */
-static int satsub64be(const uint8_t *v1, const uint8_t *v2) {
- int ret, sat, brw, i;
-
- if (sizeof(long) == 8) {
- do {
- const union {
- long one;
- char little;
- } is_endian = {1};
- long l;
-
- if (is_endian.little) {
- break;
- }
- /* not reached on little-endians */
- /* following test is redundant, because input is
- * always aligned, but I take no chances... */
- if (((size_t)v1 | (size_t)v2) & 0x7) {
- break;
- }
-
- l = *((long *)v1);
- l -= *((long *)v2);
- if (l > 128) {
- return 128;
- } else if (l < -128) {
- return -128;
- } else {
- return (int)l;
- }
- } while (0);
- }
-
- ret = (int)v1[7] - (int)v2[7];
- sat = 0;
- brw = ret >> 8; /* brw is either 0 or -1 */
- if (ret & 0x80) {
- for (i = 6; i >= 0; i--) {
- brw += (int)v1[i] - (int)v2[i];
- sat |= ~brw;
- brw >>= 8;
- }
- } else {
- for (i = 6; i >= 0; i--) {
- brw += (int)v1[i] - (int)v2[i];
- sat |= brw;
- brw >>= 8;
- }
- }
- brw <<= 8; /* brw is either 0 or -256 */
-
- if (sat & 0xff) {
- return brw | 0x80;
- } else {
- return brw + (ret & 0xFF);
- }
-}
-
-static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap);
-static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap);
-static int dtls1_process_record(SSL *s);
static int do_dtls1_write(SSL *s, int type, const uint8_t *buf,
unsigned int len, enum dtls1_use_epoch_t use_epoch);
-static int dtls1_process_record(SSL *s) {
- int al;
- SSL3_RECORD *rr = &s->s3->rrec;
-
- /* check is not needed I believe */
- if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
- al = SSL_AD_RECORD_OVERFLOW;
- OPENSSL_PUT_ERROR(SSL, dtls1_process_record,
- SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
- goto f_err;
- }
-
- /* |rr->data| points to |rr->length| bytes of ciphertext in |s->packet|. */
- rr->data = &s->packet[DTLS1_RT_HEADER_LENGTH];
-
- uint8_t seq[8];
- seq[0] = rr->epoch >> 8;
- seq[1] = rr->epoch & 0xff;
- memcpy(&seq[2], &rr->seq_num[2], 6);
-
- /* Decrypt the packet in-place. Note it is important that |SSL_AEAD_CTX_open|
- * not write beyond |rr->length|. There may be another record in the packet.
- *
- * TODO(davidben): This assumes |s->version| is the same as the record-layer
- * version which isn't always true, but it only differs with the NULL cipher
- * which ignores the parameter. */
- size_t plaintext_len;
- if (!SSL_AEAD_CTX_open(s->aead_read_ctx, rr->data, &plaintext_len, rr->length,
- rr->type, s->version, seq, rr->data, rr->length)) {
- /* Bad packets are silently dropped in DTLS. Clear the error queue of any
- * errors decryption may have added. */
- ERR_clear_error();
- rr->length = 0;
- s->packet_length = 0;
- goto err;
- }
-
- if (plaintext_len > SSL3_RT_MAX_PLAIN_LENGTH) {
- al = SSL_AD_RECORD_OVERFLOW;
- OPENSSL_PUT_ERROR(SSL, dtls1_process_record, SSL_R_DATA_LENGTH_TOO_LONG);
- goto f_err;
- }
- assert(plaintext_len < (1u << 16));
- rr->length = plaintext_len;
-
- rr->off = 0;
- /* So at this point the following is true
- * ssl->s3->rrec.type is the type of record
- * ssl->s3->rrec.length == number of bytes in record
- * ssl->s3->rrec.off == offset to first valid byte
- * ssl->s3->rrec.data == the first byte of the record body. */
-
- /* we have pulled in a full packet so zero things */
- s->packet_length = 0;
- return 1;
-
-f_err:
- ssl3_send_alert(s, SSL3_AL_FATAL, al);
-
-err:
- return 0;
-}
-
-/* Call this to get a new input record.
- * It will return <= 0 if more data is needed, normally due to an error
- * or non-blocking IO.
- * When it finishes, one packet has been decoded and can be found in
- * ssl->s3->rrec.type - is the type of record
- * ssl->s3->rrec.data, - data
- * ssl->s3->rrec.length, - number of bytes
- *
- * used only by dtls1_read_bytes */
-int dtls1_get_record(SSL *s) {
- uint8_t ssl_major, ssl_minor;
- int n;
- SSL3_RECORD *rr;
- uint8_t *p = NULL;
- uint16_t version;
-
- rr = &(s->s3->rrec);
-
- /* get something from the wire */
+/* dtls1_get_record reads a new input record. On success, it places it in
+ * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if
+ * more data is needed. */
+static int dtls1_get_record(SSL *ssl) {
again:
- /* check if we have the header */
- if ((s->rstate != SSL_ST_READ_BODY) ||
- (s->packet_length < DTLS1_RT_HEADER_LENGTH)) {
- n = ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH, 0);
- /* read timeout is handled by dtls1_read_bytes */
- if (n <= 0) {
- return n; /* error or non-blocking */
- }
-
- /* this packet contained a partial record, dump it */
- if (s->packet_length != DTLS1_RT_HEADER_LENGTH) {
- s->packet_length = 0;
- goto again;
+ /* Read a new packet if there is no unconsumed one. */
+ if (ssl_read_buffer_len(ssl) == 0) {
+ int ret = ssl_read_buffer_extend_to(ssl, 0 /* unused */);
+ if (ret <= 0) {
+ return ret;
}
+ }
+ assert(ssl_read_buffer_len(ssl) > 0);
- s->rstate = SSL_ST_READ_BODY;
+ /* Ensure the packet is large enough to decrypt in-place. */
+ if (ssl_read_buffer_len(ssl) < ssl_record_prefix_len(ssl)) {
+ ssl_read_buffer_clear(ssl);
+ goto again;
+ }
- p = s->packet;
+ uint8_t *out = ssl_read_buffer(ssl) + ssl_record_prefix_len(ssl);
+ size_t max_out = ssl_read_buffer_len(ssl) - ssl_record_prefix_len(ssl);
+ uint8_t type, alert;
+ size_t len, consumed;
+ switch (dtls_open_record(ssl, &type, out, &len, &consumed, &alert, max_out,
+ ssl_read_buffer(ssl), ssl_read_buffer_len(ssl))) {
+ case ssl_open_record_success:
+ ssl_read_buffer_consume(ssl, consumed);
- if (s->msg_callback) {
- s->msg_callback(0, 0, SSL3_RT_HEADER, p, DTLS1_RT_HEADER_LENGTH, s,
- s->msg_callback_arg);
- }
-
- /* Pull apart the header into the DTLS1_RECORD */
- rr->type = *(p++);
- ssl_major = *(p++);
- ssl_minor = *(p++);
- version = (((uint16_t)ssl_major) << 8) | ssl_minor;
-
- /* sequence number is 64 bits, with top 2 bytes = epoch */
- n2s(p, rr->epoch);
-
- memcpy(&(s->s3->read_sequence[2]), p, 6);
- p += 6;
-
- n2s(p, rr->length);
-
- /* Lets check version */
- if (s->s3->have_version) {
- if (version != s->version) {
- /* The record's version doesn't match, so silently drop it.
- *
- * TODO(davidben): This doesn't work. The DTLS record layer is not
- * packet-based, so the remainder of the packet isn't dropped and we
- * get a framing error. It's also unclear what it means to silently
- * drop a record in a packet containing two records. */
- rr->length = 0;
- s->packet_length = 0;
- goto again;
+ if (len > 0xffff) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return -1;
}
- }
- if ((version & 0xff00) != (s->version & 0xff00)) {
- /* wrong version, silently discard record */
- rr->length = 0;
- s->packet_length = 0;
- goto again;
- }
+ SSL3_RECORD *rr = &ssl->s3->rrec;
+ rr->type = type;
+ rr->length = (uint16_t)len;
+ rr->off = 0;
+ rr->data = out;
+ return 1;
- if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
- /* record too long, silently discard it */
- rr->length = 0;
- s->packet_length = 0;
- goto again;
- }
-
- /* now s->rstate == SSL_ST_READ_BODY */
- }
-
- /* s->rstate == SSL_ST_READ_BODY, get and decode the data */
-
- if (rr->length > s->packet_length - DTLS1_RT_HEADER_LENGTH) {
- /* now s->packet_length == DTLS1_RT_HEADER_LENGTH */
- n = ssl3_read_n(s, rr->length, 1);
- /* This packet contained a partial record, dump it. */
- if (n != rr->length) {
- rr->length = 0;
- s->packet_length = 0;
+ case ssl_open_record_discard:
+ ssl_read_buffer_consume(ssl, consumed);
goto again;
- }
-
- /* now n == rr->length,
- * and s->packet_length == DTLS1_RT_HEADER_LENGTH + rr->length */
- }
- s->rstate = SSL_ST_READ_HEADER; /* set state for later operations */
-
- if (rr->epoch != s->d1->r_epoch) {
- /* This record is from the wrong epoch. If it is the next epoch, it could be
- * buffered. For simplicity, drop it and expect retransmit to handle it
- * later; DTLS is supposed to handle packet loss. */
- rr->length = 0;
- s->packet_length = 0;
- goto again;
- }
-
- /* Check whether this is a repeat, or aged record. */
- if (!dtls1_record_replay_check(s, &s->d1->bitmap)) {
- rr->length = 0;
- s->packet_length = 0; /* dump this record */
- goto again; /* get another record */
- }
- /* just read a 0 length packet */
- if (rr->length == 0) {
- goto again;
- }
+ case ssl_open_record_error:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return -1;
- if (!dtls1_process_record(s)) {
- rr->length = 0;
- s->packet_length = 0; /* dump this record */
- goto again; /* get another record */
+ case ssl_open_record_partial:
+ /* Impossible in DTLS. */
+ break;
}
- dtls1_record_bitmap_update(s, &s->d1->bitmap); /* Mark receipt of record. */
- return 1;
+ assert(0);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
}
int dtls1_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek) {
@@ -393,7 +191,11 @@ int dtls1_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek) {
}
void dtls1_read_close_notify(SSL *ssl) {
- dtls1_read_bytes(ssl, 0, NULL, 0, 0);
+ /* Bidirectional shutdown doesn't make sense for an unordered transport. DTLS
+ * alerts also aren't delivered reliably, so we may even time out because the
+ * peer never received our close_notify. Report to the caller that the channel
+ * has fully shut down. */
+ ssl->shutdown |= SSL_RECEIVED_SHUTDOWN;
}
/* Return up to 'len' payload bytes received in 'type' records.
@@ -401,7 +203,6 @@ void dtls1_read_close_notify(SSL *ssl) {
*
* - SSL3_RT_HANDSHAKE (when ssl3_get_message calls us)
* - SSL3_RT_APPLICATION_DATA (when ssl3_read calls us)
- * - 0 (during a shutdown, no data has to be returned)
*
* If we don't have stored data to work from, read a SSL/TLS record first
* (possibly multiple records if we still don't have anything to return).
@@ -429,11 +230,9 @@ int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek) {
SSL3_RECORD *rr;
void (*cb)(const SSL *ssl, int type2, int val) = NULL;
- /* XXX: check what the second '&& type' is about */
- if ((type && (type != SSL3_RT_APPLICATION_DATA) &&
- (type != SSL3_RT_HANDSHAKE) && type) ||
- (peek && (type != SSL3_RT_APPLICATION_DATA))) {
- OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, ERR_R_INTERNAL_ERROR);
+ if ((type != SSL3_RT_APPLICATION_DATA && type != SSL3_RT_HANDSHAKE) ||
+ (peek && type != SSL3_RT_APPLICATION_DATA)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
}
@@ -444,7 +243,7 @@ int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek) {
return i;
}
if (i == 0) {
- OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
return -1;
}
}
@@ -464,7 +263,7 @@ start:
}
/* get new packet if necessary */
- if (rr->length == 0 || s->rstate == SSL_ST_READ_BODY) {
+ if (rr->length == 0) {
ret = dtls1_get_record(s);
if (ret <= 0) {
ret = dtls1_read_failed(s, ret);
@@ -507,10 +306,15 @@ start:
/* TODO(davidben): Is this check redundant with the handshake_func
* check? */
al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_APP_DATA_IN_HANDSHAKE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_APP_DATA_IN_HANDSHAKE);
goto f_err;
}
+ /* Discard empty records. */
+ if (rr->length == 0) {
+ goto start;
+ }
+
if (len <= 0) {
return len;
}
@@ -526,8 +330,9 @@ start:
rr->length -= n;
rr->off += n;
if (rr->length == 0) {
- s->rstate = SSL_ST_READ_HEADER;
rr->off = 0;
+ /* The record has been consumed, so we may now clear the buffer. */
+ ssl_read_buffer_discard(s);
}
}
@@ -542,7 +347,7 @@ start:
/* Alerts may not be fragmented. */
if (rr->length < 2) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_BAD_ALERT);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT);
goto f_err;
}
@@ -576,8 +381,7 @@ start:
s->rwstate = SSL_NOTHING;
s->s3->fatal_alert = alert_descr;
- OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes,
- SSL_AD_REASON_OFFSET + alert_descr);
+ OPENSSL_PUT_ERROR(SSL, SSL_AD_REASON_OFFSET + alert_descr);
BIO_snprintf(tmp, sizeof tmp, "%d", alert_descr);
ERR_add_error_data(2, "SSL alert number ", tmp);
s->shutdown |= SSL_RECEIVED_SHUTDOWN;
@@ -585,26 +389,19 @@ start:
return 0;
} else {
al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_UNKNOWN_ALERT_TYPE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_ALERT_TYPE);
goto f_err;
}
goto start;
}
- if (s->shutdown & SSL_SENT_SHUTDOWN) {
- /* but we have not received a shutdown */
- s->rwstate = SSL_NOTHING;
- rr->length = 0;
- return 0;
- }
-
if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) {
/* 'Change Cipher Spec' is just a single byte, so we know exactly what the
* record payload has to look like */
if (rr->length != 1 || rr->off != 0 || rr->data[0] != SSL3_MT_CCS) {
al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_BAD_CHANGE_CIPHER_SPEC);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC);
goto f_err;
}
@@ -641,7 +438,7 @@ start:
if (rr->type == SSL3_RT_HANDSHAKE && !s->in_handshake) {
if (rr->length < DTLS1_HM_HEADER_LENGTH) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_BAD_HANDSHAKE_RECORD);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HANDSHAKE_RECORD);
goto f_err;
}
struct hm_header_st msg_hdr;
@@ -669,7 +466,7 @@ start:
assert(rr->type != SSL3_RT_CHANGE_CIPHER_SPEC && rr->type != SSL3_RT_ALERT);
al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_UNEXPECTED_RECORD);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
@@ -686,13 +483,13 @@ int dtls1_write_app_data(SSL *s, const void *buf_, int len) {
return i;
}
if (i == 0) {
- OPENSSL_PUT_ERROR(SSL, dtls1_write_app_data, SSL_R_SSL_HANDSHAKE_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
return -1;
}
}
if (len > SSL3_RT_MAX_PLAIN_LENGTH) {
- OPENSSL_PUT_ERROR(SSL, dtls1_write_app_data, SSL_R_DTLS_MESSAGE_TOO_BIG);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DTLS_MESSAGE_TOO_BIG);
return -1;
}
@@ -713,73 +510,11 @@ int dtls1_write_bytes(SSL *s, int type, const void *buf, int len,
return i;
}
-/* dtls1_seal_record seals a new record of type |type| and plaintext |in| and
- * writes it to |out|. At most |max_out| bytes will be written. It returns one
- * on success and zero on error. On success, it updates the write sequence
- * number. */
-static int dtls1_seal_record(SSL *s, uint8_t *out, size_t *out_len,
- size_t max_out, uint8_t type, const uint8_t *in,
- size_t in_len, enum dtls1_use_epoch_t use_epoch) {
- if (max_out < DTLS1_RT_HEADER_LENGTH) {
- OPENSSL_PUT_ERROR(SSL, dtls1_seal_record, SSL_R_BUFFER_TOO_SMALL);
- return 0;
- }
-
- /* Determine the parameters for the current epoch. */
- uint16_t epoch = s->d1->w_epoch;
- SSL_AEAD_CTX *aead = s->aead_write_ctx;
- uint8_t *seq = s->s3->write_sequence;
- if (use_epoch == dtls1_use_previous_epoch) {
- /* DTLS renegotiation is unsupported, so only epochs 0 (NULL cipher) and 1
- * (negotiated cipher) exist. */
- assert(s->d1->w_epoch == 1);
- epoch = s->d1->w_epoch - 1;
- aead = NULL;
- seq = s->d1->last_write_sequence;
- }
-
- out[0] = type;
-
- uint16_t wire_version = s->s3->have_version ? s->version : DTLS1_VERSION;
- out[1] = wire_version >> 8;
- out[2] = wire_version & 0xff;
-
- out[3] = epoch >> 8;
- out[4] = epoch & 0xff;
- memcpy(&out[5], &seq[2], 6);
-
- size_t ciphertext_len;
- if (!SSL_AEAD_CTX_seal(aead, out + DTLS1_RT_HEADER_LENGTH, &ciphertext_len,
- max_out - DTLS1_RT_HEADER_LENGTH, type, wire_version,
- &out[3] /* seq */, in, in_len) ||
- !ssl3_record_sequence_update(&seq[2], 6)) {
- return 0;
- }
-
- if (ciphertext_len >= 1 << 16) {
- OPENSSL_PUT_ERROR(SSL, dtls1_seal_record, ERR_R_OVERFLOW);
- return 0;
- }
- out[11] = ciphertext_len >> 8;
- out[12] = ciphertext_len & 0xff;
-
- *out_len = DTLS1_RT_HEADER_LENGTH + ciphertext_len;
-
- if (s->msg_callback) {
- s->msg_callback(1 /* write */, 0, SSL3_RT_HEADER, out,
- DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
- }
-
- return 1;
-}
-
static int do_dtls1_write(SSL *s, int type, const uint8_t *buf,
unsigned int len, enum dtls1_use_epoch_t use_epoch) {
- SSL3_BUFFER *wb = &s->s3->wbuf;
-
/* ssl3_write_pending drops the write if |BIO_write| fails in DTLS, so there
* is never pending data. */
- assert(s->s3->wbuf.left == 0);
+ assert(!ssl_write_buffer_is_pending(s));
/* If we have an alert to send, lets send it */
if (s->s3->alert_dispatch) {
@@ -790,7 +525,8 @@ static int do_dtls1_write(SSL *s, int type, const uint8_t *buf,
/* if it went, fall through and send more stuff */
}
- if (wb->buf == NULL && !ssl3_setup_write_buffer(s)) {
+ if (len > SSL3_RT_MAX_PLAIN_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
}
@@ -798,21 +534,15 @@ static int do_dtls1_write(SSL *s, int type, const uint8_t *buf,
return 0;
}
- /* Align the output so the ciphertext is aligned to |SSL3_ALIGN_PAYLOAD|. */
- uintptr_t align = (uintptr_t)wb->buf + DTLS1_RT_HEADER_LENGTH;
- align = (0 - align) & (SSL3_ALIGN_PAYLOAD - 1);
- uint8_t *out = wb->buf + align;
- wb->offset = align;
- size_t max_out = wb->len - wb->offset;
-
+ size_t max_out = len + ssl_max_seal_overhead(s);
+ uint8_t *out;
size_t ciphertext_len;
- if (!dtls1_seal_record(s, out, &ciphertext_len, max_out, type, buf, len,
- use_epoch)) {
+ if (!ssl_write_buffer_init(s, &out, max_out) ||
+ !dtls_seal_record(s, out, &ciphertext_len, max_out, type, buf, len,
+ use_epoch)) {
return -1;
}
-
- /* now let's set up wb */
- wb->left = ciphertext_len;
+ ssl_write_buffer_set_len(s, ciphertext_len);
/* memorize arguments so that ssl3_write_pending can detect bad write retries
* later */
@@ -825,49 +555,6 @@ static int do_dtls1_write(SSL *s, int type, const uint8_t *buf,
return ssl3_write_pending(s, type, buf, len);
}
-static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap) {
- int cmp;
- unsigned int shift;
- const uint8_t *seq = s->s3->read_sequence;
-
- cmp = satsub64be(seq, bitmap->max_seq_num);
- if (cmp > 0) {
- memcpy(s->s3->rrec.seq_num, seq, 8);
- return 1; /* this record in new */
- }
- shift = -cmp;
- if (shift >= sizeof(bitmap->map) * 8) {
- return 0; /* stale, outside the window */
- } else if (bitmap->map & (((uint64_t)1) << shift)) {
- return 0; /* record previously received */
- }
-
- memcpy(s->s3->rrec.seq_num, seq, 8);
- return 1;
-}
-
-static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap) {
- int cmp;
- unsigned int shift;
- const uint8_t *seq = s->s3->read_sequence;
-
- cmp = satsub64be(seq, bitmap->max_seq_num);
- if (cmp > 0) {
- shift = cmp;
- if (shift < sizeof(bitmap->map) * 8) {
- bitmap->map <<= shift, bitmap->map |= 1UL;
- } else {
- bitmap->map = 1UL;
- }
- memcpy(bitmap->max_seq_num, seq, 8);
- } else {
- shift = -cmp;
- if (shift < sizeof(bitmap->map) * 8) {
- bitmap->map |= ((uint64_t)1) << shift;
- }
- }
-}
-
int dtls1_dispatch_alert(SSL *s) {
int i, j;
void (*cb)(const SSL *ssl, int type, int val) = NULL;
diff --git a/src/ssl/d1_srtp.c b/src/ssl/d1_srtp.c
index 5928fc8..2fcc1ea 100644
--- a/src/ssl/d1_srtp.c
+++ b/src/ssl/d1_srtp.c
@@ -114,6 +114,8 @@
Copyright (C) 2011, RTFM, Inc.
*/
+#include <openssl/ssl.h>
+
#include <stdio.h>
#include <string.h>
@@ -122,15 +124,14 @@
#include <openssl/obj.h>
#include "internal.h"
-#include <openssl/srtp.h>
-static const SRTP_PROTECTION_PROFILE srtp_known_profiles[] = {
+const SRTP_PROTECTION_PROFILE kSRTPProfiles[] = {
{
- "SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80,
+ "SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80,
},
{
- "SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32,
+ "SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32,
},
{0},
};
@@ -140,7 +141,7 @@ static int find_profile_by_name(const char *profile_name,
size_t len) {
const SRTP_PROTECTION_PROFILE *p;
- p = srtp_known_profiles;
+ p = kSRTPProfiles;
while (p->name) {
if (len == strlen(p->name) && !strncmp(p->name, profile_name, len)) {
*pptr = p;
@@ -153,22 +154,6 @@ static int find_profile_by_name(const char *profile_name,
return 0;
}
-static int find_profile_by_num(unsigned profile_num,
- const SRTP_PROTECTION_PROFILE **pptr) {
- const SRTP_PROTECTION_PROFILE *p;
-
- p = srtp_known_profiles;
- while (p->name) {
- if (p->id == profile_num) {
- *pptr = p;
- return 1;
- }
- p++;
- }
-
- return 0;
-}
-
static int ssl_ctx_make_profiles(const char *profiles_string,
STACK_OF(SRTP_PROTECTION_PROFILE) **out) {
STACK_OF(SRTP_PROTECTION_PROFILE) *profiles;
@@ -178,8 +163,7 @@ static int ssl_ctx_make_profiles(const char *profiles_string,
profiles = sk_SRTP_PROTECTION_PROFILE_new_null();
if (profiles == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl_ctx_make_profiles,
- SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES);
return 0;
}
@@ -190,8 +174,7 @@ static int ssl_ctx_make_profiles(const char *profiles_string,
if (find_profile_by_name(ptr, &p, col ? col - ptr : strlen(ptr))) {
sk_SRTP_PROTECTION_PROFILE_push(profiles, p);
} else {
- OPENSSL_PUT_ERROR(SSL, ssl_ctx_make_profiles,
- SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE);
return 0;
}
@@ -209,28 +192,28 @@ int SSL_CTX_set_srtp_profiles(SSL_CTX *ctx, const char *profiles) {
return ssl_ctx_make_profiles(profiles, &ctx->srtp_profiles);
}
-int SSL_set_srtp_profiles(SSL *s, const char *profiles) {
- return ssl_ctx_make_profiles(profiles, &s->srtp_profiles);
+int SSL_set_srtp_profiles(SSL *ssl, const char *profiles) {
+ return ssl_ctx_make_profiles(profiles, &ssl->srtp_profiles);
}
-STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(SSL *s) {
- if (s == NULL) {
+STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(SSL *ssl) {
+ if (ssl == NULL) {
return NULL;
}
- if (s->srtp_profiles != NULL) {
- return s->srtp_profiles;
+ if (ssl->srtp_profiles != NULL) {
+ return ssl->srtp_profiles;
}
- if (s->ctx != NULL && s->ctx->srtp_profiles != NULL) {
- return s->ctx->srtp_profiles;
+ if (ssl->ctx != NULL && ssl->ctx->srtp_profiles != NULL) {
+ return ssl->ctx->srtp_profiles;
}
return NULL;
}
-const SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s) {
- return s->srtp_profile;
+const SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *ssl) {
+ return ssl->srtp_profile;
}
int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx, const char *profiles) {
@@ -238,195 +221,7 @@ int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx, const char *profiles) {
return !SSL_CTX_set_srtp_profiles(ctx, profiles);
}
-int SSL_set_tlsext_use_srtp(SSL *s, const char *profiles) {
+int SSL_set_tlsext_use_srtp(SSL *ssl, const char *profiles) {
/* This API inverts its return value. */
- return !SSL_set_srtp_profiles(s, profiles);
-}
-
-/* Note: this function returns 0 length if there are no profiles specified */
-int ssl_add_clienthello_use_srtp_ext(SSL *s, uint8_t *p, int *len, int maxlen) {
- int ct = 0;
- int i;
- STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = 0;
- const SRTP_PROTECTION_PROFILE *prof;
-
- clnt = SSL_get_srtp_profiles(s);
- ct = sk_SRTP_PROTECTION_PROFILE_num(clnt); /* -1 if clnt == 0 */
-
- if (p) {
- if (ct == 0) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_use_srtp_ext,
- SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST);
- return 0;
- }
-
- if (2 + ct * 2 + 1 > maxlen) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_use_srtp_ext,
- SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG);
- return 0;
- }
-
- /* Add the length */
- s2n(ct * 2, p);
- for (i = 0; i < ct; i++) {
- prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i);
- s2n(prof->id, p);
- }
-
- /* Add an empty use_mki value */
- *p++ = 0;
- }
-
- *len = 2 + ct * 2 + 1;
-
- return 1;
-}
-
-int ssl_parse_clienthello_use_srtp_ext(SSL *s, CBS *cbs, int *out_alert) {
- CBS profile_ids, srtp_mki;
- const SRTP_PROTECTION_PROFILE *cprof, *sprof;
- STACK_OF(SRTP_PROTECTION_PROFILE) *client_profiles = 0, *server_profiles;
- size_t i, j;
- int ret = 0;
-
- if (!CBS_get_u16_length_prefixed(cbs, &profile_ids) ||
- CBS_len(&profile_ids) < 2 ||
- !CBS_get_u8_length_prefixed(cbs, &srtp_mki) ||
- CBS_len(cbs) != 0) {
- OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_use_srtp_ext,
- SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
- *out_alert = SSL_AD_DECODE_ERROR;
- goto done;
- }
-
- client_profiles = sk_SRTP_PROTECTION_PROFILE_new_null();
- if (client_profiles == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_use_srtp_ext,
- ERR_R_MALLOC_FAILURE);
- *out_alert = SSL_AD_INTERNAL_ERROR;
- goto done;
- }
-
- while (CBS_len(&profile_ids) > 0) {
- uint16_t profile_id;
-
- if (!CBS_get_u16(&profile_ids, &profile_id)) {
- *out_alert = SSL_AD_DECODE_ERROR;
- goto done;
- }
-
- if (find_profile_by_num(profile_id, &cprof)) {
- sk_SRTP_PROTECTION_PROFILE_push(client_profiles, cprof);
- }
- }
-
- /* Discard the MKI value for now. */
-
- server_profiles = SSL_get_srtp_profiles(s);
-
- /* Pick the server's most preferred profile. */
- for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(server_profiles); i++) {
- sprof = sk_SRTP_PROTECTION_PROFILE_value(server_profiles, i);
-
- for (j = 0; j < sk_SRTP_PROTECTION_PROFILE_num(client_profiles); j++) {
- cprof = sk_SRTP_PROTECTION_PROFILE_value(client_profiles, j);
-
- if (cprof->id == sprof->id) {
- s->srtp_profile = sprof;
- ret = 1;
- goto done;
- }
- }
- }
-
- ret = 1;
-
-done:
- if (client_profiles) {
- sk_SRTP_PROTECTION_PROFILE_free(client_profiles);
- }
-
- return ret;
-}
-
-int ssl_add_serverhello_use_srtp_ext(SSL *s, unsigned char *p, int *len,
- int maxlen) {
- if (p) {
- if (maxlen < 5) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_use_srtp_ext,
- SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG);
- return 0;
- }
-
- if (s->srtp_profile == 0) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_use_srtp_ext,
- SSL_R_USE_SRTP_NOT_NEGOTIATED);
- return 0;
- }
-
- s2n(2, p);
- s2n(s->srtp_profile->id, p);
- *p++ = 0;
- }
-
- *len = 5;
-
- return 1;
-}
-
-int ssl_parse_serverhello_use_srtp_ext(SSL *s, CBS *cbs, int *out_alert) {
- CBS profile_ids, srtp_mki;
- uint16_t profile_id;
- size_t i;
-
- STACK_OF(SRTP_PROTECTION_PROFILE) *client_profiles;
- const SRTP_PROTECTION_PROFILE *prof;
-
- /* The extension consists of a u16-prefixed profile ID list containing a
- * single uint16_t profile ID, then followed by a u8-prefixed srtp_mki field.
- *
- * See https://tools.ietf.org/html/rfc5764#section-4.1.1 */
- if (!CBS_get_u16_length_prefixed(cbs, &profile_ids) ||
- !CBS_get_u16(&profile_ids, &profile_id) || CBS_len(&profile_ids) != 0 ||
- !CBS_get_u8_length_prefixed(cbs, &srtp_mki) || CBS_len(cbs) != 0) {
- OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_use_srtp_ext,
- SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
-
- if (CBS_len(&srtp_mki) != 0) {
- /* Must be no MKI, since we never offer one. */
- OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_use_srtp_ext,
- SSL_R_BAD_SRTP_MKI_VALUE);
- *out_alert = SSL_AD_ILLEGAL_PARAMETER;
- return 0;
- }
-
- client_profiles = SSL_get_srtp_profiles(s);
-
- /* Throw an error if the server gave us an unsolicited extension */
- if (client_profiles == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_use_srtp_ext,
- SSL_R_NO_SRTP_PROFILES);
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
-
- /* Check to see if the server gave us something we support
- (and presumably offered). */
- for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(client_profiles); i++) {
- prof = sk_SRTP_PROTECTION_PROFILE_value(client_profiles, i);
-
- if (prof->id == profile_id) {
- s->srtp_profile = prof;
- *out_alert = 0;
- return 1;
- }
- }
-
- OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_use_srtp_ext,
- SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
- *out_alert = SSL_AD_ILLEGAL_PARAMETER;
- return 0;
+ return !SSL_set_srtp_profiles(ssl, profiles);
}
diff --git a/src/ssl/d1_srvr.c b/src/ssl/d1_srvr.c
index e49a3f0..89c26aa 100644
--- a/src/ssl/d1_srvr.c
+++ b/src/ssl/d1_srvr.c
@@ -112,6 +112,8 @@
* [including the GNU Public Licence.]
*/
+#include <openssl/ssl.h>
+
#include <assert.h>
#include <stdio.h>
@@ -150,11 +152,6 @@ int dtls1_accept(SSL *s) {
s->in_handshake++;
- if (s->cert == NULL) {
- OPENSSL_PUT_ERROR(SSL, dtls1_accept, SSL_R_NO_CERTIFICATE_SET);
- return -1;
- }
-
for (;;) {
state = s->state;
@@ -181,8 +178,8 @@ int dtls1_accept(SSL *s) {
goto end;
}
- if (!ssl3_init_finished_mac(s)) {
- OPENSSL_PUT_ERROR(SSL, dtls1_accept, ERR_R_INTERNAL_ERROR);
+ if (!ssl3_init_handshake_buffer(s)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
ret = -1;
goto end;
}
@@ -244,8 +241,19 @@ int dtls1_accept(SSL *s) {
s->init_num = 0;
break;
+ case SSL3_ST_SW_CERT_STATUS_A:
+ case SSL3_ST_SW_CERT_STATUS_B:
+ ret = ssl3_send_certificate_status(s);
+ if (ret <= 0) {
+ goto end;
+ }
+ s->state = SSL3_ST_SW_KEY_EXCH_A;
+ s->init_num = 0;
+ break;
+
case SSL3_ST_SW_KEY_EXCH_A:
case SSL3_ST_SW_KEY_EXCH_B:
+ case SSL3_ST_SW_KEY_EXCH_C:
alg_a = s->s3->tmp.new_cipher->algorithm_auth;
/* Send a ServerKeyExchange message if:
@@ -439,7 +447,7 @@ int dtls1_accept(SSL *s) {
goto end;
default:
- OPENSSL_PUT_ERROR(SSL, dtls1_accept, SSL_R_UNKNOWN_STATE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE);
ret = -1;
goto end;
}
diff --git a/src/ssl/dtls_record.c b/src/ssl/dtls_record.c
new file mode 100644
index 0000000..940494a
--- /dev/null
+++ b/src/ssl/dtls_record.c
@@ -0,0 +1,308 @@
+/* DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. */
+/* ====================================================================
+ * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+
+#include "internal.h"
+
+
+/* to_u64_be treats |in| as a 8-byte big-endian integer and returns the value as
+ * a |uint64_t|. */
+static uint64_t to_u64_be(const uint8_t in[8]) {
+ uint64_t ret = 0;
+ unsigned i;
+ for (i = 0; i < 8; i++) {
+ ret <<= 8;
+ ret |= in[i];
+ }
+ return ret;
+}
+
+/* dtls1_bitmap_should_discard returns one if |seq_num| has been seen in |bitmap|
+ * or is stale. Otherwise it returns zero. */
+static int dtls1_bitmap_should_discard(DTLS1_BITMAP *bitmap,
+ const uint8_t seq_num[8]) {
+ const unsigned kWindowSize = sizeof(bitmap->map) * 8;
+
+ uint64_t seq_num_u = to_u64_be(seq_num);
+ if (seq_num_u > bitmap->max_seq_num) {
+ return 0;
+ }
+ uint64_t idx = bitmap->max_seq_num - seq_num_u;
+ return idx >= kWindowSize || (bitmap->map & (((uint64_t)1) << idx));
+}
+
+/* dtls1_bitmap_record updates |bitmap| to record receipt of sequence number
+ * |seq_num|. It slides the window forward if needed. It is an error to call
+ * this function on a stale sequence number. */
+static void dtls1_bitmap_record(DTLS1_BITMAP *bitmap,
+ const uint8_t seq_num[8]) {
+ const unsigned kWindowSize = sizeof(bitmap->map) * 8;
+
+ uint64_t seq_num_u = to_u64_be(seq_num);
+ /* Shift the window if necessary. */
+ if (seq_num_u > bitmap->max_seq_num) {
+ uint64_t shift = seq_num_u - bitmap->max_seq_num;
+ if (shift >= kWindowSize) {
+ bitmap->map = 0;
+ } else {
+ bitmap->map <<= shift;
+ }
+ bitmap->max_seq_num = seq_num_u;
+ }
+
+ uint64_t idx = bitmap->max_seq_num - seq_num_u;
+ if (idx < kWindowSize) {
+ bitmap->map |= ((uint64_t)1) << idx;
+ }
+}
+
+enum ssl_open_record_t dtls_open_record(
+ SSL *ssl, uint8_t *out_type, uint8_t *out, size_t *out_len,
+ size_t *out_consumed, uint8_t *out_alert, size_t max_out, const uint8_t *in,
+ size_t in_len) {
+ CBS cbs;
+ CBS_init(&cbs, in, in_len);
+
+ /* Decode the record. */
+ uint8_t type;
+ uint16_t version;
+ uint8_t sequence[8];
+ CBS body;
+ if (!CBS_get_u8(&cbs, &type) ||
+ !CBS_get_u16(&cbs, &version) ||
+ !CBS_copy_bytes(&cbs, sequence, 8) ||
+ !CBS_get_u16_length_prefixed(&cbs, &body) ||
+ (ssl->s3->have_version && version != ssl->version) ||
+ (version >> 8) != DTLS1_VERSION_MAJOR ||
+ CBS_len(&body) > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
+ /* The record header was incomplete or malformed. Drop the entire packet. */
+ *out_consumed = in_len;
+ return ssl_open_record_discard;
+ }
+
+ if (ssl->msg_callback != NULL) {
+ ssl->msg_callback(0 /* read */, 0, SSL3_RT_HEADER, in,
+ DTLS1_RT_HEADER_LENGTH, ssl, ssl->msg_callback_arg);
+ }
+
+ uint16_t epoch = (((uint16_t)sequence[0]) << 8) | sequence[1];
+ if (epoch != ssl->d1->r_epoch ||
+ dtls1_bitmap_should_discard(&ssl->d1->bitmap, sequence)) {
+ /* Drop this record. It's from the wrong epoch or is a replay. Note that if
+ * |epoch| is the next epoch, the record could be buffered for later. For
+ * simplicity, drop it and expect retransmit to handle it later; DTLS must
+ * handle packet loss anyway. */
+ *out_consumed = in_len - CBS_len(&cbs);
+ return ssl_open_record_discard;
+ }
+
+ /* Decrypt the body. */
+ size_t plaintext_len;
+ if (!SSL_AEAD_CTX_open(ssl->aead_read_ctx, out, &plaintext_len, max_out,
+ type, version, sequence, CBS_data(&body),
+ CBS_len(&body))) {
+ /* Bad packets are silently dropped in DTLS. See section 4.2.1 of RFC 6347.
+ * Clear the error queue of any errors decryption may have added. Drop the
+ * entire packet as it must not have come from the peer.
+ *
+ * TODO(davidben): This doesn't distinguish malloc failures from encryption
+ * failures. */
+ ERR_clear_error();
+ *out_consumed = in_len - CBS_len(&cbs);
+ return ssl_open_record_discard;
+ }
+
+ /* Check the plaintext length. */
+ if (plaintext_len > SSL3_RT_MAX_PLAIN_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
+ *out_alert = SSL_AD_RECORD_OVERFLOW;
+ return ssl_open_record_error;
+ }
+
+ dtls1_bitmap_record(&ssl->d1->bitmap, sequence);
+
+ /* TODO(davidben): Limit the number of empty records as in TLS? This is only
+ * useful if we also limit discarded packets. */
+
+ *out_type = type;
+ *out_len = plaintext_len;
+ *out_consumed = in_len - CBS_len(&cbs);
+ return ssl_open_record_success;
+}
+
+int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+ uint8_t type, const uint8_t *in, size_t in_len,
+ enum dtls1_use_epoch_t use_epoch) {
+ /* Determine the parameters for the current epoch. */
+ uint16_t epoch = ssl->d1->w_epoch;
+ SSL_AEAD_CTX *aead = ssl->aead_write_ctx;
+ uint8_t *seq = ssl->s3->write_sequence;
+ if (use_epoch == dtls1_use_previous_epoch) {
+ /* DTLS renegotiation is unsupported, so only epochs 0 (NULL cipher) and 1
+ * (negotiated cipher) exist. */
+ assert(ssl->d1->w_epoch == 1);
+ epoch = ssl->d1->w_epoch - 1;
+ aead = NULL;
+ seq = ssl->d1->last_write_sequence;
+ }
+
+ if (max_out < DTLS1_RT_HEADER_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ /* Check the record header does not alias any part of the input.
+ * |SSL_AEAD_CTX_seal| will internally enforce other aliasing requirements. */
+ if (in < out + DTLS1_RT_HEADER_LENGTH && out < in + in_len) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
+ return 0;
+ }
+
+ out[0] = type;
+
+ uint16_t wire_version = ssl->s3->have_version ? ssl->version : DTLS1_VERSION;
+ out[1] = wire_version >> 8;
+ out[2] = wire_version & 0xff;
+
+ out[3] = epoch >> 8;
+ out[4] = epoch & 0xff;
+ memcpy(&out[5], &seq[2], 6);
+
+ size_t ciphertext_len;
+ if (!SSL_AEAD_CTX_seal(aead, out + DTLS1_RT_HEADER_LENGTH, &ciphertext_len,
+ max_out - DTLS1_RT_HEADER_LENGTH, type, wire_version,
+ &out[3] /* seq */, in, in_len) ||
+ !ssl3_record_sequence_update(&seq[2], 6)) {
+ return 0;
+ }
+
+ if (ciphertext_len >= 1 << 16) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return 0;
+ }
+ out[11] = ciphertext_len >> 8;
+ out[12] = ciphertext_len & 0xff;
+
+ *out_len = DTLS1_RT_HEADER_LENGTH + ciphertext_len;
+
+ if (ssl->msg_callback) {
+ ssl->msg_callback(1 /* write */, 0, SSL3_RT_HEADER, out,
+ DTLS1_RT_HEADER_LENGTH, ssl, ssl->msg_callback_arg);
+ }
+
+ return 1;
+}
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index 4d70431..6fb8dbe 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -182,6 +182,7 @@
#define SSL_AES128GCM 0x00000010L
#define SSL_AES256GCM 0x00000020L
#define SSL_CHACHA20POLY1305 0x00000040L
+#define SSL_eNULL 0x00000080L
#define SSL_AES (SSL_AES128 | SSL_AES256 | SSL_AES128GCM | SSL_AES256GCM)
@@ -202,25 +203,15 @@
#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)
+/* Bits for |algorithm_prf| (handshake digest). */
+#define SSL_HANDSHAKE_MAC_DEFAULT 0x1
+#define SSL_HANDSHAKE_MAC_SHA256 0x2
+#define SSL_HANDSHAKE_MAC_SHA384 0x4
/* SSL_MAX_DIGEST is the number of digest types which exist. When adding a new
* one, update the table in ssl_cipher.c. */
#define SSL_MAX_DIGEST 4
-/* SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD is a flag in
- * SSL_CIPHER.algorithm2 which indicates that the variable part of the nonce is
- * included as a prefix of the record. (AES-GCM, for example, does with with an
- * 8-byte variable nonce.) */
-#define SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD (1<<22)
-
/* Bits for |algo_strength|, cipher strength information. */
#define SSL_MEDIUM 0x00000001L
#define SSL_HIGH 0x00000002L
@@ -236,11 +227,11 @@ int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead,
size_t *out_fixed_iv_len,
const SSL_CIPHER *cipher, uint16_t version);
-/* ssl_get_handshake_digest 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_get_handshake_digest returns the |EVP_MD| corresponding to
+ * |algorithm_prf|. It returns SHA-1 for |SSL_HANDSHAKE_DEFAULT|. The caller is
+ * responsible for maintaining the additional MD5 digest and switching to
+ * SHA-256 in TLS 1.2. */
+const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf);
/* ssl_create_cipher_list evaluates |rule_str| according to the ciphers in
* |ssl_method|. It sets |*out_cipher_list| to a newly-allocated
@@ -254,18 +245,12 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method,
STACK_OF(SSL_CIPHER) **out_cipher_list_by_id,
const char *rule_str);
-/* SSL_PKEY_* denote certificate types. */
-#define SSL_PKEY_RSA_ENC 0
-#define SSL_PKEY_RSA_SIGN 1
-#define SSL_PKEY_ECC 2
-#define SSL_PKEY_NUM 3
-
/* ssl_cipher_get_value returns the cipher suite id of |cipher|. */
uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher);
-/* ssl_cipher_get_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_get_key_type returns the |EVP_PKEY_*| value corresponding to the
+ * server key used in |cipher| or |EVP_PKEY_NONE| if there is none. */
+int ssl_cipher_get_key_type(const SSL_CIPHER *cipher);
/* ssl_cipher_has_server_public_key returns 1 if |cipher| involves a server
* public key in the key exchange, sent in a server Certificate message.
@@ -275,11 +260,16 @@ 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. */
+ * Unlike |ssl_cipher_has_server_public_key|, this function may return zero
+ * while still allowing |cipher| an optional ServerKeyExchange. This is the
+ * case for plain PSK ciphers. */
int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher);
+/* ssl_cipher_get_record_split_len, for TLS 1.0 CBC mode ciphers, returns the
+ * length of an encrypted 1-byte record, for use in record-splitting. Otherwise
+ * it returns zero. */
+size_t ssl_cipher_get_record_split_len(const SSL_CIPHER *cipher);
+
/* Encryption layer. */
@@ -350,6 +340,238 @@ int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
size_t in_len);
+/* DTLS replay bitmap. */
+
+/* DTLS1_BITMAP maintains a sliding window of 64 sequence numbers to detect
+ * replayed packets. It should be initialized by zeroing every field. */
+typedef struct dtls1_bitmap_st {
+ /* map is a bit mask of the last 64 sequence numbers. Bit
+ * |1<<i| corresponds to |max_seq_num - i|. */
+ uint64_t map;
+ /* max_seq_num is the largest sequence number seen so far as a 64-bit
+ * integer. */
+ uint64_t max_seq_num;
+} DTLS1_BITMAP;
+
+
+/* Record layer. */
+
+/* ssl_record_prefix_len returns the length of the prefix before the ciphertext
+ * of a record for |ssl|.
+ *
+ * TODO(davidben): Expose this as part of public API once the high-level
+ * buffer-free APIs are available. */
+size_t ssl_record_prefix_len(const SSL *ssl);
+
+enum ssl_open_record_t {
+ ssl_open_record_success,
+ ssl_open_record_discard,
+ ssl_open_record_partial,
+ ssl_open_record_error,
+};
+
+/* tls_open_record decrypts a record from |in|.
+ *
+ * On success, it returns |ssl_open_record_success|. It sets |*out_type| to the
+ * record type, |*out_len| to the plaintext length, and writes the record body
+ * to |out|. It sets |*out_consumed| to the number of bytes of |in| consumed.
+ * Note that |*out_len| may be zero.
+ *
+ * If a record was successfully processed but should be discarded, it returns
+ * |ssl_open_record_discard| and sets |*out_consumed| to the number of bytes
+ * consumed.
+ *
+ * If the input did not contain a complete record, it returns
+ * |ssl_open_record_partial|. It sets |*out_consumed| to the total number of
+ * bytes necessary. It is guaranteed that a successful call to |tls_open_record|
+ * will consume at least that many bytes.
+ *
+ * On failure, it returns |ssl_open_record_error| and sets |*out_alert| to an
+ * alert to emit.
+ *
+ * If |in| and |out| alias, |out| must be <= |in| + |ssl_record_prefix_len|. */
+enum ssl_open_record_t tls_open_record(
+ SSL *ssl, uint8_t *out_type, uint8_t *out, size_t *out_len,
+ size_t *out_consumed, uint8_t *out_alert, size_t max_out, const uint8_t *in,
+ size_t in_len);
+
+/* dtls_open_record implements |tls_open_record| for DTLS. It never returns
+ * |ssl_open_record_partial| but otherwise behaves analogously. */
+enum ssl_open_record_t dtls_open_record(
+ SSL *ssl, uint8_t *out_type, uint8_t *out, size_t *out_len,
+ size_t *out_consumed, uint8_t *out_alert, size_t max_out, const uint8_t *in,
+ size_t in_len);
+
+/* ssl_seal_prefix_len returns the length of the prefix before the ciphertext
+ * when sealing a record with |ssl|. Note that this value may differ from
+ * |ssl_record_prefix_len| when TLS 1.0 CBC record-splitting is enabled. Sealing
+ * a small record may also result in a smaller output than this value.
+ *
+ * TODO(davidben): Expose this as part of public API once the high-level
+ * buffer-free APIs are available. */
+size_t ssl_seal_prefix_len(const SSL *ssl);
+
+/* ssl_max_seal_overhead returns the maximum overhead of sealing a record with
+ * |ssl|. This includes |ssl_seal_prefix_len|.
+ *
+ * TODO(davidben): Expose this as part of public API once the high-level
+ * buffer-free APIs are available. */
+size_t ssl_max_seal_overhead(const SSL *ssl);
+
+/* tls_seal_record seals a new record of type |type| and body |in| and writes it
+ * to |out|. At most |max_out| bytes will be written. It returns one on success
+ * and zero on error. If enabled, |tls_seal_record| implements TLS 1.0 CBC 1/n-1
+ * record splitting and may write two records concatenated.
+ *
+ * For a large record, the ciphertext will begin |ssl_seal_prefix_len| bytes
+ * into out. Aligning |out| appropriately may improve performance. It writes at
+ * most |in_len| + |ssl_max_seal_overhead| bytes to |out|.
+ *
+ * If |in| and |out| alias, |out| + |ssl_seal_prefix_len| must be <= |in|. */
+int tls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+ uint8_t type, const uint8_t *in, size_t in_len);
+
+enum dtls1_use_epoch_t {
+ dtls1_use_previous_epoch,
+ dtls1_use_current_epoch,
+};
+
+/* dtls_seal_record implements |tls_seal_record| for DTLS. |use_epoch| selects
+ * which epoch's cipher state to use. */
+int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+ uint8_t type, const uint8_t *in, size_t in_len,
+ enum dtls1_use_epoch_t use_epoch);
+
+
+/* Private key operations. */
+
+/* ssl_has_private_key returns one if |ssl| has a private key
+ * configured and zero otherwise. */
+int ssl_has_private_key(SSL *ssl);
+
+/* ssl_private_key_* call the corresponding function on the
+ * |SSL_PRIVATE_KEY_METHOD| for |ssl|, if configured. Otherwise, they implement
+ * the operation with |EVP_PKEY|. */
+
+int ssl_private_key_type(SSL *ssl);
+
+size_t ssl_private_key_max_signature_len(SSL *ssl);
+
+enum ssl_private_key_result_t ssl_private_key_sign(
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, const EVP_MD *md,
+ const uint8_t *in, size_t in_len);
+
+enum ssl_private_key_result_t ssl_private_key_sign_complete(
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out);
+
+
+/* Custom extensions */
+
+/* ssl_custom_extension (a.k.a. SSL_CUSTOM_EXTENSION) is a structure that
+ * contains information about custom-extension callbacks. */
+struct ssl_custom_extension {
+ SSL_custom_ext_add_cb add_callback;
+ void *add_arg;
+ SSL_custom_ext_free_cb free_callback;
+ SSL_custom_ext_parse_cb parse_callback;
+ void *parse_arg;
+ uint16_t value;
+};
+
+void SSL_CUSTOM_EXTENSION_free(SSL_CUSTOM_EXTENSION *custom_extension);
+
+int custom_ext_add_clienthello(SSL *ssl, CBB *extensions);
+int custom_ext_parse_serverhello(SSL *ssl, int *out_alert, uint16_t value,
+ const CBS *extension);
+int custom_ext_parse_clienthello(SSL *ssl, int *out_alert, uint16_t value,
+ const CBS *extension);
+int custom_ext_add_serverhello(SSL *ssl, CBB *extensions);
+
+
+/* Handshake hash.
+ *
+ * The TLS handshake maintains a transcript of all handshake messages. At
+ * various points in the protocol, this is either a handshake buffer, a rolling
+ * hash (selected by cipher suite) or both. */
+
+/* ssl3_init_handshake_buffer initializes the handshake buffer and resets the
+ * handshake hash. It returns one success and zero on failure. */
+int ssl3_init_handshake_buffer(SSL *ssl);
+
+/* ssl3_init_handshake_hash initializes the handshake hash based on the pending
+ * cipher and the contents of the handshake buffer. Subsequent calls to
+ * |ssl3_update_handshake_hash| will update the rolling hash. It returns one on
+ * success and zero on failure. It is an error to call this function after the
+ * handshake buffer is released. */
+int ssl3_init_handshake_hash(SSL *ssl);
+
+/* ssl3_free_handshake_buffer releases the handshake buffer. Subsequent calls
+ * to |ssl3_update_handshake_hash| will not update the handshake buffer. */
+void ssl3_free_handshake_buffer(SSL *ssl);
+
+/* ssl3_free_handshake_hash releases the handshake hash. */
+void ssl3_free_handshake_hash(SSL *s);
+
+/* ssl3_update_handshake_hash adds |in| to the handshake buffer and handshake
+ * hash, whichever is enabled. It returns one on success and zero on failure. */
+int ssl3_update_handshake_hash(SSL *ssl, const uint8_t *in, size_t in_len);
+
+
+/* Transport buffers. */
+
+/* ssl_read_buffer returns a pointer to contents of the read buffer. */
+uint8_t *ssl_read_buffer(SSL *ssl);
+
+/* ssl_read_buffer_len returns the length of the read buffer. */
+size_t ssl_read_buffer_len(const SSL *ssl);
+
+/* ssl_read_buffer_extend_to extends the read buffer to the desired length. For
+ * TLS, it reads to the end of the buffer until the buffer is |len| bytes
+ * long. For DTLS, it reads a new packet and ignores |len|. It returns one on
+ * success, zero on EOF, and a negative number on error.
+ *
+ * It is an error to call |ssl_read_buffer_extend_to| in DTLS when the buffer is
+ * non-empty. */
+int ssl_read_buffer_extend_to(SSL *ssl, size_t len);
+
+/* ssl_read_buffer_consume consumes |len| bytes from the read buffer. It
+ * advances the data pointer and decrements the length. The memory consumed will
+ * remain valid until the next call to |ssl_read_buffer_extend| or it is
+ * discarded with |ssl_read_buffer_discard|. */
+void ssl_read_buffer_consume(SSL *ssl, size_t len);
+
+/* ssl_read_buffer_discard discards the consumed bytes from the read buffer. If
+ * the buffer is now empty, it releases memory used by it. */
+void ssl_read_buffer_discard(SSL *ssl);
+
+/* ssl_read_buffer_clear releases all memory associated with the read buffer and
+ * zero-initializes it. */
+void ssl_read_buffer_clear(SSL *ssl);
+
+/* ssl_write_buffer_is_pending returns one if the write buffer has pending data
+ * and zero if is empty. */
+int ssl_write_buffer_is_pending(const SSL *ssl);
+
+/* ssl_write_buffer_init initializes the write buffer. On success, it sets
+ * |*out_ptr| to the start of the write buffer with space for up to |max_len|
+ * bytes. It returns one on success and zero on failure. Call
+ * |ssl_write_buffer_set_len| to complete initialization. */
+int ssl_write_buffer_init(SSL *ssl, uint8_t **out_ptr, size_t max_len);
+
+/* ssl_write_buffer_set_len is called after |ssl_write_buffer_init| to complete
+ * initialization after |len| bytes are written to the buffer. */
+void ssl_write_buffer_set_len(SSL *ssl, size_t len);
+
+/* ssl_write_buffer_flush flushes the write buffer to the transport. It returns
+ * one on success and <= 0 on error. For DTLS, whether or not the write
+ * succeeds, the write buffer will be cleared. */
+int ssl_write_buffer_flush(SSL *ssl);
+
+/* ssl_write_buffer_clear releases all memory associated with the write buffer
+ * and zero-initializes it. */
+void ssl_write_buffer_clear(SSL *ssl);
+
+
/* Underdocumented functions.
*
* Functions below here haven't been touched up and may be underdocumented. */
@@ -483,8 +705,6 @@ int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
* SSL_aRSA <- RSA_ENC | RSA_SIGN
* SSL_aDSS <- DSA_SIGN */
-#define PENDING_SESSION -10000
-
/* From RFC4492, used in encoding the curve type in ECParameters */
#define EXPLICIT_PRIME_CURVE_TYPE 1
#define EXPLICIT_CHAR2_CURVE_TYPE 2
@@ -495,18 +715,21 @@ enum ssl_hash_message_t {
ssl_hash_message,
};
-typedef struct cert_pkey_st {
+/* Structure containing decoded values of signature algorithms extension */
+typedef struct tls_sigalgs_st {
+ uint8_t rsign;
+ uint8_t rhash;
+} TLS_SIGALGS;
+
+typedef struct cert_st {
X509 *x509;
EVP_PKEY *privatekey;
/* Chain for this certificate */
STACK_OF(X509) *chain;
-} CERT_PKEY;
-typedef struct cert_st {
- /* Current active set */
- CERT_PKEY *key; /* ALWAYS points to an element of the pkeys array
- * Probably it would make more sense to store
- * an index, not a pointer. */
+ /* key_method, if non-NULL, is a set of callbacks to call for private key
+ * operations. */
+ const SSL_PRIVATE_KEY_METHOD *key_method;
/* For clients the following masks are of *disabled* key and auth algorithms
* based on the current session.
@@ -531,39 +754,18 @@ typedef struct cert_st {
* keys. If NULL, a curve is selected automatically. See
* |SSL_CTX_set_tmp_ecdh_callback|. */
EC_KEY *(*ecdh_tmp_cb)(SSL *ssl, int is_export, int keysize);
- CERT_PKEY pkeys[SSL_PKEY_NUM];
-
- /* Server-only: client_certificate_types is list of certificate types to
- * include in the CertificateRequest message.
- */
- uint8_t *client_certificate_types;
- size_t num_client_certificate_types;
-
- /* signature algorithms peer reports: e.g. supported signature
- * algorithms extension for server or as part of a certificate
- * request for client. */
- uint8_t *peer_sigalgs;
- /* Size of above array */
+
+ /* peer_sigalgs are the algorithm/hash pairs that the peer supports. These
+ * are taken from the contents of signature algorithms extension for a server
+ * or from the CertificateRequest for a client. */
+ TLS_SIGALGS *peer_sigalgs;
+ /* peer_sigalgslen is the number of entries in |peer_sigalgs|. */
size_t peer_sigalgslen;
- /* suppported signature algorithms.
- * When set on a client this is sent in the client hello as the
- * supported signature algorithms extension. For servers
- * it represents the signature algorithms we are willing to use. */
- uint8_t *conf_sigalgs;
- /* Size of above array */
- size_t conf_sigalgslen;
- /* Client authentication signature algorithms, if not set then
- * uses conf_sigalgs. On servers these will be the signature
- * algorithms sent to the client in a cerificate request for TLS 1.2.
- * On a client this represents the signature algortithms we are
- * willing to use for client authentication. */
- uint8_t *client_sigalgs;
- /* Size of above array */
- size_t client_sigalgslen;
- /* Signature algorithms shared by client and server: cached
- * because these are used most often. */
- TLS_SIGALGS *shared_sigalgs;
- size_t shared_sigalgslen;
+
+ /* digest_nids, if non-NULL, is the set of digests supported by |privatekey|
+ * in decreasing order of preference. */
+ int *digest_nids;
+ size_t num_digest_nids;
/* Certificate setup callback: if set is called whenever a
* certificate may be required (client or server). the callback
@@ -573,39 +775,8 @@ typedef struct cert_st {
* supported signature algorithms or curves. */
int (*cert_cb)(SSL *ssl, void *arg);
void *cert_cb_arg;
-
- /* Optional X509_STORE for chain building or certificate validation
- * If NULL the parent SSL_CTX store is used instead. */
- X509_STORE *chain_store;
- X509_STORE *verify_store;
} CERT;
-typedef struct sess_cert_st {
- /* cert_chain is the certificate chain sent by the peer. NOTE: for a client,
- * this does includes the server's leaf certificate, but, for a server, this
- * does NOT include the client's leaf. */
- STACK_OF(X509) *cert_chain;
-
- /* peer_cert, on a client, is the leaf certificate of the peer. */
- X509 *peer_cert;
-
- DH *peer_dh_tmp;
- EC_KEY *peer_ecdh_tmp;
-} SESS_CERT;
-
-/* Structure containing decoded values of signature algorithms extension */
-struct tls_sigalgs_st {
- /* NID of hash algorithm */
- int hash_nid;
- /* NID of signature algorithm */
- int sign_nid;
- /* Combined hash and signature NID */
- int signandhash_nid;
- /* Raw values used in extension */
- uint8_t rsign;
- uint8_t rhash;
-};
-
/* SSL_METHOD is a compatibility structure to support the legacy version-locked
* methods. */
struct ssl_method_st {
@@ -632,8 +803,6 @@ struct ssl_protocol_method_st {
void (*ssl_read_close_notify)(SSL *s);
int (*ssl_write_app_data)(SSL *s, const void *buf_, int len);
int (*ssl_dispatch_alert)(SSL *s);
- long (*ssl_ctrl)(SSL *s, int cmd, long larg, void *parg);
- long (*ssl_ctx_ctrl)(SSL_CTX *ctx, int cmd, long larg, void *parg);
/* supports_cipher returns one if |cipher| is supported by this protocol and
* zero otherwise. */
int (*supports_cipher)(const SSL_CIPHER *cipher);
@@ -696,15 +865,6 @@ struct ssl3_enc_method {
#define DTLS1_AL_HEADER_LENGTH 2
-typedef struct dtls1_bitmap_st {
- /* map is a bit mask of the last 64 sequence numbers. Bit
- * |1<<i| corresponds to |max_seq_num - i|. */
- uint64_t map;
- /* max_seq_num is the largest sequence number seen so far. It
- * is a 64-bit value in big-endian encoding. */
- uint8_t max_seq_num[8];
-} DTLS1_BITMAP;
-
/* TODO(davidben): This structure is used for both incoming messages and
* outgoing messages. |is_ccs| and |epoch| are only used in the latter and
* should be moved elsewhere. */
@@ -789,6 +949,7 @@ extern const SSL3_ENC_METHOD TLSv1_enc_data;
extern const SSL3_ENC_METHOD TLSv1_1_enc_data;
extern const SSL3_ENC_METHOD TLSv1_2_enc_data;
extern const SSL3_ENC_METHOD SSLv3_enc_data;
+extern const SRTP_PROTECTION_PROFILE kSRTPProfiles[];
void ssl_clear_cipher_ctx(SSL *s);
int ssl_clear_bad_session(SSL *s);
@@ -796,11 +957,24 @@ CERT *ssl_cert_new(void);
CERT *ssl_cert_dup(CERT *cert);
void ssl_cert_clear_certs(CERT *c);
void ssl_cert_free(CERT *c);
-SESS_CERT *ssl_sess_cert_new(void);
-SESS_CERT *ssl_sess_cert_dup(const SESS_CERT *sess_cert);
-void ssl_sess_cert_free(SESS_CERT *sess_cert);
int ssl_get_new_session(SSL *s, int session);
-int ssl_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx);
+
+enum ssl_session_result_t {
+ ssl_session_success,
+ ssl_session_error,
+ ssl_session_retry,
+};
+
+/* ssl_get_prev_session looks up the previous session based on |ctx|. On
+ * success, it sets |*out_session| to the session or NULL if none was found. It
+ * sets |*out_send_ticket| to whether a ticket should be sent at the end of the
+ * handshake. If the session could not be looked up synchronously, it returns
+ * |ssl_session_retry| and should be called again. Otherwise, it returns
+ * |ssl_session_error|. */
+enum ssl_session_result_t ssl_get_prev_session(
+ SSL *ssl, SSL_SESSION **out_session, int *out_send_ticket,
+ const struct ssl_early_callback_ctx *ctx);
+
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(
@@ -811,21 +985,16 @@ struct ssl_cipher_preference_list_st *ssl_cipher_preference_list_from_ciphers(
STACK_OF(SSL_CIPHER) *ciphers);
struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *s);
-int ssl_cert_set0_chain(CERT *c, STACK_OF(X509) *chain);
-int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain);
-int ssl_cert_add0_chain_cert(CERT *c, X509 *x);
-int ssl_cert_add1_chain_cert(CERT *c, X509 *x);
-int ssl_cert_select_current(CERT *c, X509 *x);
-void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg), void *arg);
-
-int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk);
-int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l);
-int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags);
-int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref);
-CERT_PKEY *ssl_get_server_send_pkey(const SSL *s);
-EVP_PKEY *ssl_get_sign_pkey(SSL *s, const SSL_CIPHER *c);
+int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain);
+int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain);
+int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509);
+int ssl_cert_add1_chain_cert(CERT *cert, X509 *x509);
+void ssl_cert_set_cert_cb(CERT *cert,
+ int (*cb)(SSL *ssl, void *arg), void *arg);
+
+int ssl_verify_cert_chain(SSL *ssl, STACK_OF(X509) *cert_chain);
+int ssl_add_cert_chain(SSL *s, unsigned long *l);
void ssl_update_cache(SSL *s, int mode);
-int ssl_cert_type(EVP_PKEY *pkey);
/* ssl_get_compatible_server_ciphers determines the key exchange and
* authentication cipher suite masks compatible with the server configuration
@@ -841,10 +1010,9 @@ int ssl_verify_alarm_type(long type);
* |len|. It returns one on success and zero on failure. */
int ssl_fill_hello_random(uint8_t *out, size_t len, int is_server);
-int ssl3_init_finished_mac(SSL *s);
int ssl3_send_server_certificate(SSL *s);
int ssl3_send_new_session_ticket(SSL *s);
-int ssl3_send_cert_status(SSL *s);
+int ssl3_send_certificate_status(SSL *s);
int ssl3_get_finished(SSL *s, int state_a, int state_b);
int ssl3_send_change_cipher_spec(SSL *s, int state_a, int state_b);
int ssl3_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret,
@@ -865,11 +1033,11 @@ int ssl3_hash_current_message(SSL *s);
/* ssl3_cert_verify_hash writes the CertificateVerify hash into the bytes
* pointed to by |out| and writes the number of bytes to |*out_len|. |out| must
* have room for EVP_MAX_MD_SIZE bytes. For TLS 1.2 and up, |*out_md| is used
- * for the hash function, otherwise the hash function depends on the type of
- * |pkey| and is written to |*out_md|. It returns one on success and zero on
+ * for the hash function, otherwise the hash function depends on |pkey_type|
+ * and is written to |*out_md|. It returns one on success and zero on
* failure. */
int ssl3_cert_verify_hash(SSL *s, uint8_t *out, size_t *out_len,
- const EVP_MD **out_md, EVP_PKEY *pkey);
+ const EVP_MD **out_md, int pkey_type);
int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen);
int ssl3_supports_cipher(const SSL_CIPHER *cipher);
@@ -882,29 +1050,15 @@ int ssl3_write_app_data(SSL *ssl, const void *buf, int len);
int ssl3_write_bytes(SSL *s, int type, const void *buf, int len);
int ssl3_final_finish_mac(SSL *s, const char *sender, int slen, uint8_t *p);
int ssl3_cert_verify_mac(SSL *s, int md_nid, uint8_t *p);
-int ssl3_finish_mac(SSL *s, const uint8_t *buf, int len);
-void ssl3_free_digest_list(SSL *s);
-int ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk);
+int ssl3_output_cert_chain(SSL *s);
const SSL_CIPHER *ssl3_choose_cipher(
SSL *ssl, STACK_OF(SSL_CIPHER) *clnt,
struct ssl_cipher_preference_list_st *srvr);
-int ssl3_setup_read_buffer(SSL *s);
-int ssl3_setup_write_buffer(SSL *s);
-int ssl3_release_read_buffer(SSL *s);
-int ssl3_release_write_buffer(SSL *s);
-
-enum should_free_handshake_buffer_t {
- free_handshake_buffer,
- dont_free_handshake_buffer,
-};
-int ssl3_digest_cached_records(SSL *s, enum should_free_handshake_buffer_t);
int ssl3_new(SSL *s);
void ssl3_free(SSL *s);
int ssl3_accept(SSL *s);
int ssl3_connect(SSL *s);
-long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg);
-long ssl3_ctx_ctrl(SSL_CTX *s, int cmd, long larg, void *parg);
/* ssl3_record_sequence_update increments the sequence number in |seq|. It
* returns one on success and zero on wraparound. */
@@ -915,13 +1069,7 @@ int ssl3_do_change_cipher_spec(SSL *ssl);
int ssl3_set_handshake_header(SSL *s, int htype, unsigned long len);
int ssl3_handshake_write(SSL *s);
-enum dtls1_use_epoch_t {
- dtls1_use_previous_epoch,
- dtls1_use_current_epoch,
-};
-
int dtls1_do_write(SSL *s, int type, enum dtls1_use_epoch_t use_epoch);
-int ssl3_read_n(SSL *s, int n, int extend);
int dtls1_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek);
void dtls1_read_close_notify(SSL *ssl);
int dtls1_read_bytes(SSL *s, int type, uint8_t *buf, int len, int peek);
@@ -968,11 +1116,9 @@ int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey);
int ssl3_send_client_key_exchange(SSL *s);
int ssl3_get_server_key_exchange(SSL *s);
int ssl3_get_server_certificate(SSL *s);
-int ssl3_check_cert_and_algorithm(SSL *s);
int ssl3_send_next_proto(SSL *s);
int ssl3_send_channel_id(SSL *s);
-
-int dtls1_client_hello(SSL *s);
+int ssl3_verify_server_cert(SSL *s);
/* some server-only functions */
int ssl3_get_initial_bytes(SSL *s);
@@ -995,7 +1141,6 @@ void dtls1_free(SSL *s);
long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max,
enum ssl_hash_message_t hash_message, int *ok);
-int dtls1_get_record(SSL *s);
int dtls1_dispatch_alert(SSL *s);
int ssl_init_wbio_buffer(SSL *s, int push);
@@ -1025,12 +1170,15 @@ int tls1_export_keying_material(SSL *s, uint8_t *out, size_t out_len,
int tls1_alert_code(int code);
int ssl3_alert_code(int code);
-int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s);
-
char ssl_early_callback_init(struct ssl_early_callback_ctx *ctx);
int tls1_ec_curve_id2nid(uint16_t curve_id);
int tls1_ec_nid2curve_id(uint16_t *out_curve_id, int nid);
+/* tls1_ec_curve_id2name returns a human-readable name for the
+ * curve specified by the TLS curve id in |curve_id|. If the
+ * curve is unknown, it returns NULL. */
+const char* tls1_ec_curve_id2name(uint16_t curve_id);
+
/* tls1_check_curve parses ECParameters out of |cbs|, modifying it. It
* checks the curve is one of our preferences and writes the
* NamedCurve value to |*out_curve_id|. It returns one on success and
@@ -1060,27 +1208,38 @@ int tls1_check_ec_tmp_key(SSL *s);
int tls1_shared_list(SSL *s, const uint8_t *l1, size_t l1len, const uint8_t *l2,
size_t l2len, int nmatch);
-uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit,
- size_t header_len);
-uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit);
+uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *const buf,
+ uint8_t *const limit, size_t header_len);
+uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *const buf,
+ uint8_t *const limit);
int ssl_parse_clienthello_tlsext(SSL *s, CBS *cbs);
int ssl_parse_serverhello_tlsext(SSL *s, CBS *cbs);
-int ssl_prepare_clienthello_tlsext(SSL *s);
-int ssl_prepare_serverhello_tlsext(SSL *s);
#define tlsext_tick_md EVP_sha256
-int tls1_process_ticket(SSL *s, const struct ssl_early_callback_ctx *ctx,
- SSL_SESSION **ret);
-int tls12_get_sigandhash(uint8_t *p, const EVP_PKEY *pk, const EVP_MD *md);
-int tls12_get_sigid(const EVP_PKEY *pk);
+/* tls_process_ticket processes the session ticket extension. On success, it
+ * sets |*out_session| to the decrypted session or NULL if the ticket was
+ * rejected. It sets |*out_send_ticket| to whether a new ticket should be sent
+ * at the end of the handshake. It returns one on success and zero on fatal
+ * error. */
+int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session,
+ int *out_send_ticket, const uint8_t *ticket,
+ size_t ticket_len, const uint8_t *session_id,
+ size_t session_id_len);
+
+/* tls12_get_sigandhash assembles the SignatureAndHashAlgorithm corresponding to
+ * |ssl|'s private key and |md|. The two-byte value is written to |p|. It
+ * returns one on success and zero on failure. */
+int tls12_get_sigandhash(SSL *ssl, uint8_t *p, const EVP_MD *md);
+int tls12_get_sigid(int pkey_type);
const EVP_MD *tls12_get_hash(uint8_t hash_alg);
-int tls1_channel_id_hash(EVP_MD_CTX *ctx, SSL *s);
-int tls1_record_handshake_hashes_for_channel_id(SSL *s);
+/* tls1_channel_id_hash computes the hash to be signed by Channel ID and writes
+ * it to |out|, which must contain at least |EVP_MAX_MD_SIZE| bytes. It returns
+ * one on success and zero on failure. */
+int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len);
-int tls1_set_sigalgs_list(CERT *c, const char *str, int client);
-int tls1_set_sigalgs(CERT *c, const int *salg, size_t salglen, int client);
+int tls1_record_handshake_hashes_for_channel_id(SSL *s);
/* ssl_ctx_log_rsa_client_key_exchange logs |premaster| to |ctx|, if logging is
* enabled. It returns one on success and zero on failure. The entry is
@@ -1134,27 +1293,16 @@ int ssl3_is_version_enabled(SSL *s, uint16_t version);
* the wire version except at API boundaries. */
uint16_t ssl3_version_from_wire(SSL *s, uint16_t wire_version);
-int ssl_add_serverhello_renegotiate_ext(SSL *s, uint8_t *p, int *len,
- int maxlen);
-int ssl_parse_serverhello_renegotiate_ext(SSL *s, CBS *cbs, int *out_alert);
-int ssl_add_clienthello_renegotiate_ext(SSL *s, uint8_t *p, int *len,
- int maxlen);
-int ssl_parse_clienthello_renegotiate_ext(SSL *s, CBS *cbs, int *out_alert);
-uint32_t ssl_get_algorithm2(SSL *s);
-int tls1_process_sigalgs(SSL *s, const CBS *sigalgs);
+uint32_t ssl_get_algorithm_prf(SSL *s);
+int tls1_parse_peer_sigalgs(SSL *s, const CBS *sigalgs);
-/* tls1_choose_signing_digest returns a digest for use with |pkey| based on the
- * peer's preferences recorded for |s| and the digests supported by |pkey|. */
-const EVP_MD *tls1_choose_signing_digest(SSL *s, EVP_PKEY *pkey);
+/* tls1_choose_signing_digest returns a digest for use with |ssl|'s private key
+ * based on the peer's preferences the digests supported. */
+const EVP_MD *tls1_choose_signing_digest(SSL *ssl);
size_t tls12_get_psigalgs(SSL *s, const uint8_t **psigs);
int tls12_check_peer_sigalg(const EVP_MD **out_md, int *out_alert, SSL *s,
CBS *cbs, EVP_PKEY *pkey);
void ssl_set_client_disabled(SSL *s);
-int ssl_add_clienthello_use_srtp_ext(SSL *s, uint8_t *p, int *len, int maxlen);
-int ssl_parse_clienthello_use_srtp_ext(SSL *s, CBS *cbs, int *out_alert);
-int ssl_add_serverhello_use_srtp_ext(SSL *s, uint8_t *p, int *len, int maxlen);
-int ssl_parse_serverhello_use_srtp_ext(SSL *s, CBS *cbs, int *out_alert);
-
#endif /* OPENSSL_HEADER_SSL_INTERNAL_H */
diff --git a/src/ssl/s3_both.c b/src/ssl/s3_both.c
index 06338b7..31e36c7 100644
--- a/src/ssl/s3_both.c
+++ b/src/ssl/s3_both.c
@@ -110,6 +110,8 @@
* ECC cipher suite support in OpenSSL originally developed by
* SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. */
+#include <openssl/ssl.h>
+
#include <assert.h>
#include <limits.h>
#include <stdio.h>
@@ -242,7 +244,7 @@ int ssl3_get_finished(SSL *s, int a, int b) {
* TODO(davidben): Is this check now redundant with SSL3_FLAGS_EXPECT_CCS? */
if (!s->s3->change_cipher_spec) {
al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_finished, SSL_R_GOT_A_FIN_BEFORE_A_CCS);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_GOT_A_FIN_BEFORE_A_CCS);
goto f_err;
}
s->s3->change_cipher_spec = 0;
@@ -252,13 +254,13 @@ int ssl3_get_finished(SSL *s, int a, int b) {
if (finished_len != message_len) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_finished, SSL_R_BAD_DIGEST_LENGTH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_DIGEST_LENGTH);
goto f_err;
}
if (CRYPTO_memcmp(p, s->s3->tmp.peer_finish_md, finished_len) != 0) {
al = SSL_AD_DECRYPT_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_finished, SSL_R_DIGEST_CHECK_FAILED);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED);
goto f_err;
}
@@ -301,17 +303,11 @@ int ssl3_send_change_cipher_spec(SSL *s, int a, int b) {
return ssl3_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);
}
-int ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk) {
+int ssl3_output_cert_chain(SSL *s) {
uint8_t *p;
unsigned long l = 3 + SSL_HM_HEADER_LENGTH(s);
- 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)) {
+ if (!ssl_add_cert_chain(s, &l)) {
return 0;
}
@@ -340,7 +336,7 @@ long ssl3_get_message(SSL *s, int header_state, int body_state, int msg_type,
s->s3->tmp.reuse_message = 0;
if (msg_type >= 0 && s->s3->tmp.message_type != msg_type) {
al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_message, SSL_R_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
goto f_err;
}
*ok = 1;
@@ -386,7 +382,7 @@ long ssl3_get_message(SSL *s, int header_state, int body_state, int msg_type,
if (msg_type >= 0 && *p != msg_type) {
al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_message, SSL_R_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
goto f_err;
}
s->s3->tmp.message_type = *(p++);
@@ -394,12 +390,12 @@ long ssl3_get_message(SSL *s, int header_state, int body_state, int msg_type,
n2l3(p, l);
if (l > (unsigned long)max) {
al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_message, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
goto f_err;
}
if (l && !BUF_MEM_grow_clean(s->init_buf, l + 4)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_message, ERR_R_BUF_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
goto err;
}
s->s3->tmp.message_size = l;
@@ -447,8 +443,8 @@ int ssl3_hash_current_message(SSL *s) {
/* The handshake header (different size between DTLS and TLS) is included in
* the hash. */
size_t header_len = s->init_msg - (uint8_t *)s->init_buf->data;
- return ssl3_finish_mac(s, (uint8_t *)s->init_buf->data,
- s->init_num + header_len);
+ return ssl3_update_handshake_hash(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
@@ -457,30 +453,25 @@ OPENSSL_COMPILE_ASSERT(EVP_MAX_MD_SIZE > MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH,
combined_tls_hash_fits_in_max);
int ssl3_cert_verify_hash(SSL *s, uint8_t *out, size_t *out_len,
- const EVP_MD **out_md, EVP_PKEY *pkey) {
+ const EVP_MD **out_md, int pkey_type) {
/* For TLS v1.2 send signature algorithm and signature using
* agreed digest and cached handshake records. Otherwise, use
* SHA1 or MD5 + SHA1 depending on key type. */
if (SSL_USE_SIGALGS(s)) {
- const uint8_t *hdata;
- size_t hdatalen;
EVP_MD_CTX mctx;
unsigned len;
- if (!BIO_mem_contents(s->s3->handshake_buffer, &hdata, &hdatalen)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_cert_verify_hash, ERR_R_INTERNAL_ERROR);
- return 0;
- }
EVP_MD_CTX_init(&mctx);
if (!EVP_DigestInit_ex(&mctx, *out_md, NULL) ||
- !EVP_DigestUpdate(&mctx, hdata, hdatalen) ||
+ !EVP_DigestUpdate(&mctx, s->s3->handshake_buffer->data,
+ s->s3->handshake_buffer->length) ||
!EVP_DigestFinal(&mctx, out, &len)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_cert_verify_hash, ERR_R_EVP_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_EVP_LIB);
EVP_MD_CTX_cleanup(&mctx);
return 0;
}
*out_len = len;
- } else if (pkey->type == EVP_PKEY_RSA) {
+ } else if (pkey_type == EVP_PKEY_RSA) {
if (s->enc_method->cert_verify_mac(s, NID_md5, out) == 0 ||
s->enc_method->cert_verify_mac(s, NID_sha1, out + MD5_DIGEST_LENGTH) ==
0) {
@@ -488,31 +479,20 @@ int ssl3_cert_verify_hash(SSL *s, uint8_t *out, size_t *out_len,
}
*out_len = MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH;
*out_md = EVP_md5_sha1();
- } else if (pkey->type == EVP_PKEY_EC) {
+ } else if (pkey_type == EVP_PKEY_EC) {
if (s->enc_method->cert_verify_mac(s, NID_sha1, out) == 0) {
return 0;
}
*out_len = SHA_DIGEST_LENGTH;
*out_md = EVP_sha1();
} else {
- OPENSSL_PUT_ERROR(SSL, ssl3_cert_verify_hash, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
return 1;
}
-int ssl_cert_type(EVP_PKEY *pkey) {
- switch (pkey->type) {
- case EVP_PKEY_RSA:
- return SSL_PKEY_RSA_ENC;
- case EVP_PKEY_EC:
- return SSL_PKEY_ECC;
- default:
- return -1;
- }
-}
-
int ssl_verify_alarm_type(long type) {
int al;
@@ -581,92 +561,6 @@ int ssl_verify_alarm_type(long type) {
return al;
}
-int ssl3_setup_read_buffer(SSL *s) {
- uint8_t *p;
- size_t len, align = 0, headerlen;
-
- if (SSL_IS_DTLS(s)) {
- headerlen = DTLS1_RT_HEADER_LENGTH;
- } else {
- headerlen = SSL3_RT_HEADER_LENGTH;
- }
-
-#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD != 0
- align = (-SSL3_RT_HEADER_LENGTH) & (SSL3_ALIGN_PAYLOAD - 1);
-#endif
-
- if (s->s3->rbuf.buf == NULL) {
- len = SSL3_RT_MAX_ENCRYPTED_LENGTH + headerlen + align;
- if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) {
- s->s3->init_extra = 1;
- len += SSL3_RT_MAX_EXTRA;
- }
- p = OPENSSL_malloc(len);
- if (p == NULL) {
- goto err;
- }
- s->s3->rbuf.buf = p;
- s->s3->rbuf.len = len;
- }
-
- s->packet = &s->s3->rbuf.buf[0];
- return 1;
-
-err:
- OPENSSL_PUT_ERROR(SSL, ssl3_setup_read_buffer, ERR_R_MALLOC_FAILURE);
- return 0;
-}
-
-int ssl3_setup_write_buffer(SSL *s) {
- uint8_t *p;
- size_t len, align = 0, headerlen;
-
- if (SSL_IS_DTLS(s)) {
- headerlen = DTLS1_RT_HEADER_LENGTH + 1;
- } else {
- headerlen = SSL3_RT_HEADER_LENGTH;
- }
-
-#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD != 0
- align = (-SSL3_RT_HEADER_LENGTH) & (SSL3_ALIGN_PAYLOAD - 1);
-#endif
-
- if (s->s3->wbuf.buf == NULL) {
- len = s->max_send_fragment + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD +
- headerlen + align;
- /* Account for 1/n-1 record splitting. */
- if (s->mode & SSL_MODE_CBC_RECORD_SPLITTING) {
- len += headerlen + align + 1 + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD;
- }
-
- p = OPENSSL_malloc(len);
- if (p == NULL) {
- goto err;
- }
- s->s3->wbuf.buf = p;
- s->s3->wbuf.len = len;
- }
-
- return 1;
-
-err:
- OPENSSL_PUT_ERROR(SSL, ssl3_setup_write_buffer, ERR_R_MALLOC_FAILURE);
- return 0;
-}
-
-int ssl3_release_write_buffer(SSL *s) {
- OPENSSL_free(s->s3->wbuf.buf);
- s->s3->wbuf.buf = NULL;
- return 1;
-}
-
-int ssl3_release_read_buffer(SSL *s) {
- OPENSSL_free(s->s3->rbuf.buf);
- s->s3->rbuf.buf = NULL;
- s->packet = NULL;
- return 1;
-}
-
int ssl_fill_hello_random(uint8_t *out, size_t len, int is_server) {
if (is_server) {
const uint32_t current_time = time(NULL);
diff --git a/src/ssl/s3_clnt.c b/src/ssl/s3_clnt.c
index d334e1d..559db72 100644
--- a/src/ssl/s3_clnt.c
+++ b/src/ssl/s3_clnt.c
@@ -148,21 +148,26 @@
* OTHERWISE.
*/
+#include <openssl/ssl.h>
+
#include <assert.h>
#include <stdio.h>
#include <string.h>
+#include <openssl/bn.h>
#include <openssl/buf.h>
#include <openssl/bytestring.h>
-#include <openssl/rand.h>
-#include <openssl/obj.h>
+#include <openssl/dh.h>
+#include <openssl/ec_key.h>
+#include <openssl/ecdsa.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/mem.h>
+#include <openssl/obj.h>
+#include <openssl/rand.h>
#include <openssl/x509.h>
+#include <openssl/x509v3.h>
#include "internal.h"
#include "../crypto/dh/internal.h"
@@ -217,8 +222,8 @@ int ssl3_connect(SSL *s) {
/* don't push the buffering BIO quite yet */
- if (!ssl3_init_finished_mac(s)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_connect, ERR_R_INTERNAL_ERROR);
+ if (!ssl3_init_handshake_buffer(s)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
ret = -1;
goto end;
}
@@ -273,7 +278,7 @@ int ssl3_connect(SSL *s) {
if (s->s3->tmp.certificate_status_expected) {
s->state = SSL3_ST_CR_CERT_STATUS_A;
} else {
- s->state = SSL3_ST_CR_KEY_EXCH_A;
+ s->state = SSL3_ST_VERIFY_SERVER_CERT;
}
} else {
skip = 1;
@@ -282,6 +287,16 @@ int ssl3_connect(SSL *s) {
s->init_num = 0;
break;
+ case SSL3_ST_VERIFY_SERVER_CERT:
+ ret = ssl3_verify_server_cert(s);
+ if (ret <= 0) {
+ goto end;
+ }
+
+ s->state = SSL3_ST_CR_KEY_EXCH_A;
+ s->init_num = 0;
+ break;
+
case SSL3_ST_CR_KEY_EXCH_A:
case SSL3_ST_CR_KEY_EXCH_B:
ret = ssl3_get_server_key_exchange(s);
@@ -290,13 +305,6 @@ int ssl3_connect(SSL *s) {
}
s->state = SSL3_ST_CR_CERT_REQ_A;
s->init_num = 0;
-
- /* at this point we check that we have the
- * required stuff from the server */
- if (!ssl3_check_cert_and_algorithm(s)) {
- ret = -1;
- goto end;
- }
break;
case SSL3_ST_CR_CERT_REQ_A:
@@ -356,6 +364,7 @@ int ssl3_connect(SSL *s) {
case SSL3_ST_CW_CERT_VRFY_A:
case SSL3_ST_CW_CERT_VRFY_B:
+ case SSL3_ST_CW_CERT_VRFY_C:
ret = ssl3_send_cert_verify(s);
if (ret <= 0) {
goto end;
@@ -433,11 +442,9 @@ int ssl3_connect(SSL *s) {
* record the handshake hashes at this point in the session so that
* any resumption of this session with ChannelID can sign those
* hashes. */
- if (s->s3->tlsext_channel_id_new) {
- ret = tls1_record_handshake_hashes_for_channel_id(s);
- if (ret <= 0) {
- goto end;
- }
+ ret = tls1_record_handshake_hashes_for_channel_id(s);
+ if (ret <= 0) {
+ goto end;
}
if ((SSL_get_mode(s) & SSL_MODE_ENABLE_FALSE_START) &&
ssl3_can_false_start(s) &&
@@ -473,7 +480,7 @@ int ssl3_connect(SSL *s) {
if (ret <= 0) {
goto end;
}
- s->state = SSL3_ST_CR_KEY_EXCH_A;
+ s->state = SSL3_ST_VERIFY_SERVER_CERT;
s->init_num = 0;
break;
@@ -536,11 +543,16 @@ int ssl3_connect(SSL *s) {
/* Remove write buffering now. */
ssl_free_wbio_buffer(s);
+ const int is_initial_handshake = !s->s3->initial_handshake_complete;
+
s->init_num = 0;
s->s3->tmp.in_false_start = 0;
s->s3->initial_handshake_complete = 1;
- ssl_update_cache(s, SSL_SESS_CACHE_CLIENT);
+ if (is_initial_handshake) {
+ /* Renegotiations do not participate in session resumption. */
+ ssl_update_cache(s, SSL_SESS_CACHE_CLIENT);
+ }
ret = 1;
/* s->server=0; */
@@ -552,7 +564,7 @@ int ssl3_connect(SSL *s) {
goto end;
default:
- OPENSSL_PUT_ERROR(SSL, ssl3_connect, SSL_R_UNKNOWN_STATE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE);
ret = -1;
goto end;
}
@@ -588,7 +600,7 @@ int ssl3_send_client_hello(SSL *s) {
uint16_t max_version = ssl3_get_max_client_version(s);
/* Disabling all versions is silly: return an error. */
if (max_version == 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello, SSL_R_WRONG_SSL_VERSION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SSL_VERSION);
goto err;
}
s->version = max_version;
@@ -661,7 +673,7 @@ int ssl3_send_client_hello(SSL *s) {
*(p++) = i;
if (i != 0) {
if (i > (int)sizeof(s->session->session_id)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;
}
memcpy(p, s->session->session_id, i);
@@ -671,7 +683,7 @@ int ssl3_send_client_hello(SSL *s) {
/* cookie stuff for DTLS */
if (SSL_IS_DTLS(s)) {
if (s->d1->cookie_len > sizeof(s->d1->cookie)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;
}
*(p++) = s->d1->cookie_len;
@@ -682,8 +694,7 @@ int ssl3_send_client_hello(SSL *s) {
/* Ciphers supported */
i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &p[2]);
if (i == 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello,
- SSL_R_NO_CIPHERS_AVAILABLE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHERS_AVAILABLE);
goto err;
}
s2n(i, p);
@@ -694,15 +705,10 @@ int ssl3_send_client_hello(SSL *s) {
*(p++) = 0; /* Add the NULL method */
/* TLS extensions*/
- if (ssl_prepare_clienthello_tlsext(s) <= 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello, SSL_R_CLIENTHELLO_TLSEXT);
- goto err;
- }
-
p = ssl_add_clienthello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH,
p - buf);
if (p == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;
}
@@ -746,8 +752,7 @@ int ssl3_get_server_hello(SSL *s) {
* parameters. Note: this error code comes after the original one.
*
* See https://crbug.com/446505. */
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello,
- SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO);
}
return n;
}
@@ -761,14 +766,14 @@ int ssl3_get_server_hello(SSL *s) {
!CBS_get_u16(&server_hello, &cipher_suite) ||
!CBS_get_u8(&server_hello, &compression_method)) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
assert(s->s3->have_version == s->s3->initial_handshake_complete);
if (!s->s3->have_version) {
if (!ssl3_is_version_enabled(s, server_version)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_UNSUPPORTED_PROTOCOL);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL);
s->version = server_version;
/* Mark the version as fixed so the record-layer version is not clamped
* to TLS 1.0. */
@@ -783,7 +788,7 @@ int ssl3_get_server_hello(SSL *s) {
* fixed. Begin enforcing the record-layer version. */
s->s3->have_version = 1;
} else if (server_version != s->version) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_WRONG_SSL_VERSION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SSL_VERSION);
al = SSL_AD_PROTOCOL_VERSION;
goto f_err;
}
@@ -799,7 +804,7 @@ int ssl3_get_server_hello(SSL *s) {
memcmp(s->session->sid_ctx, s->sid_ctx, s->sid_ctx_length)) {
/* actually a client application bug */
al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello,
+ OPENSSL_PUT_ERROR(SSL,
SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
goto f_err;
}
@@ -820,8 +825,7 @@ int ssl3_get_server_hello(SSL *s) {
if (c == NULL) {
/* unknown cipher */
al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello,
- SSL_R_UNKNOWN_CIPHER_RETURNED);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_RETURNED);
goto f_err;
}
/* ct->mask_ssl was computed from client capabilities. Now
@@ -837,7 +841,7 @@ int ssl3_get_server_hello(SSL *s) {
(c->algorithm_mkey & ct->mask_k) ||
(c->algorithm_auth & ct->mask_a)) {
al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_WRONG_CIPHER_RETURNED);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
goto f_err;
}
@@ -845,45 +849,46 @@ int ssl3_get_server_hello(SSL *s) {
if (!sk_SSL_CIPHER_find(sk, NULL, c)) {
/* we did not say we would use this cipher */
al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_WRONG_CIPHER_RETURNED);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
goto f_err;
}
if (s->hit) {
if (s->session->cipher != c) {
al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello,
- SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
+ OPENSSL_PUT_ERROR(SSL, 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);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_VERSION_NOT_RETURNED);
goto f_err;
}
}
s->s3->tmp.new_cipher = c;
+ /* Now that the cipher is known, initialize the handshake hash. */
+ if (!ssl3_init_handshake_hash(s)) {
+ goto f_err;
+ }
+
/* If doing a full handshake with TLS 1.2, the server may request a client
* certificate which requires hashing the handshake transcript under a
- * different hash. Otherwise, release the handshake buffer. */
- if ((!SSL_USE_SIGALGS(s) || s->hit) &&
- !ssl3_digest_cached_records(s, free_handshake_buffer)) {
- goto f_err;
+ * different hash. Otherwise, the handshake buffer may be released. */
+ if (!SSL_USE_SIGALGS(s) || s->hit) {
+ ssl3_free_handshake_buffer(s);
}
/* Only the NULL compression algorithm is supported. */
if (compression_method != 0) {
al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello,
- SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
goto f_err;
}
/* TLS extensions */
if (!ssl_parse_serverhello_tlsext(s, &server_hello)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_PARSE_TLSEXT);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
goto err;
}
@@ -891,7 +896,7 @@ int ssl3_get_server_hello(SSL *s) {
if (CBS_len(&server_hello) != 0) {
/* wrong packet length */
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_BAD_PACKET_LENGTH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH);
goto f_err;
}
@@ -899,11 +904,9 @@ int ssl3_get_server_hello(SSL *s) {
s->s3->tmp.extended_master_secret != s->session->extended_master_secret) {
al = SSL_AD_HANDSHAKE_FAILURE;
if (s->session->extended_master_secret) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello,
- SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION);
} else {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello,
- SSL_R_RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION);
}
goto f_err;
}
@@ -916,12 +919,49 @@ err:
return -1;
}
+/* ssl3_check_certificate_for_cipher returns one if |leaf| is a suitable server
+ * certificate type for |cipher|. Otherwise, it returns zero and pushes an error
+ * on the error queue. */
+static int ssl3_check_certificate_for_cipher(X509 *leaf,
+ const SSL_CIPHER *cipher) {
+ int ret = 0;
+ EVP_PKEY *pkey = X509_get_pubkey(leaf);
+ if (pkey == NULL) {
+ goto err;
+ }
+
+ /* Check the certificate's type matches the cipher. */
+ int expected_type = ssl_cipher_get_key_type(cipher);
+ assert(expected_type != EVP_PKEY_NONE);
+ if (pkey->type != expected_type) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CERTIFICATE_TYPE);
+ goto err;
+ }
+
+ /* TODO(davidben): This behavior is preserved from upstream. Should key usages
+ * be checked in other cases as well? */
+ if (cipher->algorithm_auth & SSL_aECDSA) {
+ /* This call populates the ex_flags field correctly */
+ X509_check_purpose(leaf, -1, 0);
+ if ((leaf->ex_flags & EXFLAG_KUSAGE) &&
+ !(leaf->ex_kusage & X509v3_KU_DIGITAL_SIGNATURE)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ECC_CERT_NOT_FOR_SIGNING);
+ goto err;
+ }
+ }
+
+ ret = 1;
+
+err:
+ EVP_PKEY_free(pkey);
+ return ret;
+}
+
int ssl3_get_server_certificate(SSL *s) {
- int al, i, ok, ret = -1;
+ int al, ok, ret = -1;
unsigned long n;
X509 *x = NULL;
STACK_OF(X509) *sk = NULL;
- SESS_CERT *sc;
EVP_PKEY *pkey = NULL;
CBS cbs, certificate_list;
const uint8_t *data;
@@ -938,14 +978,15 @@ int ssl3_get_server_certificate(SSL *s) {
sk = sk_X509_new_null();
if (sk == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!CBS_get_u24_length_prefixed(&cbs, &certificate_list) ||
+ CBS_len(&certificate_list) == 0 ||
CBS_len(&cbs) != 0) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, SSL_R_LENGTH_MISMATCH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
@@ -953,90 +994,45 @@ int ssl3_get_server_certificate(SSL *s) {
CBS certificate;
if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate)) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate,
- SSL_R_CERT_LENGTH_MISMATCH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
goto f_err;
}
data = CBS_data(&certificate);
x = d2i_X509(NULL, &data, CBS_len(&certificate));
if (x == NULL) {
al = SSL_AD_BAD_CERTIFICATE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, ERR_R_ASN1_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB);
goto f_err;
}
if (data != CBS_data(&certificate) + CBS_len(&certificate)) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate,
- SSL_R_CERT_LENGTH_MISMATCH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
goto f_err;
}
if (!sk_X509_push(sk, x)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
x = NULL;
}
- i = ssl_verify_cert_chain(s, sk);
- if (s->verify_mode != SSL_VERIFY_NONE && i <= 0) {
- al = ssl_verify_alarm_type(s->verify_result);
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate,
- SSL_R_CERTIFICATE_VERIFY_FAILED);
+ X509 *leaf = sk_X509_value(sk, 0);
+ if (!ssl3_check_certificate_for_cipher(leaf, s->s3->tmp.new_cipher)) {
+ al = SSL_AD_ILLEGAL_PARAMETER;
goto f_err;
}
- ERR_clear_error(); /* but we keep s->verify_result */
-
- sc = ssl_sess_cert_new();
- if (sc == NULL) {
- goto err;
- }
- ssl_sess_cert_free(s->session->sess_cert);
- s->session->sess_cert = sc;
-
- sc->cert_chain = sk;
- /* Inconsistency alert: cert_chain does include the peer's certificate, which
- * we don't include in s3_srvr.c */
- x = sk_X509_value(sk, 0);
+ /* NOTE: Unlike the server half, the client's copy of |cert_chain| includes
+ * the leaf. */
+ sk_X509_pop_free(s->session->cert_chain, X509_free);
+ s->session->cert_chain = sk;
sk = NULL;
- /* VRS 19990621: possible memory leak; sk=null ==> !sk_pop_free() @end*/
-
- pkey = X509_get_pubkey(x);
-
- if (pkey == NULL || EVP_PKEY_missing_parameters(pkey)) {
- x = NULL;
- al = SSL3_AL_FATAL;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate,
- SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS);
- goto f_err;
- }
-
- i = ssl_cert_type(pkey);
- if (i < 0) {
- x = NULL;
- al = SSL3_AL_FATAL;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate,
- SSL_R_UNKNOWN_CERTIFICATE_TYPE);
- goto f_err;
- }
-
- int exp_idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
- if (exp_idx >= 0 && i != exp_idx) {
- x = NULL;
- al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate,
- SSL_R_WRONG_CERTIFICATE_TYPE);
- goto f_err;
- }
- X509_free(sc->peer_cert);
- sc->peer_cert = X509_up_ref(x);
X509_free(s->session->peer);
- s->session->peer = X509_up_ref(x);
+ s->session->peer = X509_up_ref(leaf);
s->session->verify_result = s->verify_result;
- x = NULL;
ret = 1;
if (0) {
@@ -1075,25 +1071,14 @@ int ssl3_get_server_key_exchange(SSL *s) {
if (s->s3->tmp.message_type != SSL3_MT_SERVER_KEY_EXCHANGE) {
if (ssl_cipher_requires_server_key_exchange(s->s3->tmp.new_cipher)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange,
- SSL_R_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
return -1;
}
- /* In plain PSK ciphersuite, ServerKeyExchange can be
- omitted if no identity hint is sent. Set session->sess_cert anyway to
- avoid problems later.*/
+ /* In plain PSK ciphersuite, ServerKeyExchange may be omitted to send no
+ * identity hint. */
if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aPSK) {
- /* PSK ciphersuites that also send a Certificate would have already
- * initialized |sess_cert|. */
- if (s->session->sess_cert == NULL) {
- s->session->sess_cert = ssl_sess_cert_new();
- if (s->session->sess_cert == NULL) {
- return -1;
- }
- }
-
/* TODO(davidben): This should be reset in one place with the rest of the
* handshake state. */
OPENSSL_free(s->s3->tmp.peer_psk_identity_hint);
@@ -1107,18 +1092,6 @@ int ssl3_get_server_key_exchange(SSL *s) {
CBS_init(&server_key_exchange, s->init_msg, n);
server_key_exchange_orig = server_key_exchange;
- if (s->session->sess_cert != NULL) {
- DH_free(s->session->sess_cert->peer_dh_tmp);
- s->session->sess_cert->peer_dh_tmp = NULL;
- EC_KEY_free(s->session->sess_cert->peer_ecdh_tmp);
- s->session->sess_cert->peer_ecdh_tmp = NULL;
- } else {
- s->session->sess_cert = ssl_sess_cert_new();
- if (s->session->sess_cert == NULL) {
- return -1;
- }
- }
-
alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
alg_a = s->s3->tmp.new_cipher->algorithm_auth;
EVP_MD_CTX_init(&md_ctx);
@@ -1130,7 +1103,7 @@ int ssl3_get_server_key_exchange(SSL *s) {
if (!CBS_get_u16_length_prefixed(&server_key_exchange,
&psk_identity_hint)) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
@@ -1144,16 +1117,14 @@ int ssl3_get_server_key_exchange(SSL *s) {
if (CBS_len(&psk_identity_hint) > PSK_MAX_IDENTITY_LEN ||
CBS_contains_zero_byte(&psk_identity_hint)) {
al = SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange,
- SSL_R_DATA_LENGTH_TOO_LONG);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
goto f_err;
}
/* Save the identity hint as a C string. */
if (!CBS_strdup(&psk_identity_hint, &s->s3->tmp.peer_psk_identity_hint)) {
al = SSL_AD_INTERNAL_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto f_err;
}
}
@@ -1168,13 +1139,13 @@ int ssl3_get_server_key_exchange(SSL *s) {
!CBS_get_u16_length_prefixed(&server_key_exchange, &dh_Ys) ||
CBS_len(&dh_Ys) == 0) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
dh = DH_new();
if (dh == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, ERR_R_DH_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB);
goto err;
}
@@ -1182,22 +1153,17 @@ int ssl3_get_server_key_exchange(SSL *s) {
(dh->g = BN_bin2bn(CBS_data(&dh_g), CBS_len(&dh_g), NULL)) == NULL ||
(dh->pub_key = BN_bin2bn(CBS_data(&dh_Ys), CBS_len(&dh_Ys), NULL)) ==
NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, ERR_R_BN_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BN_LIB);
goto err;
}
- if (DH_num_bits(dh) < 1024) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange,
- SSL_R_BAD_DH_P_LENGTH);
+ s->session->key_exchange_info = DH_num_bits(dh);
+ if (s->session->key_exchange_info < 1024) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_DH_P_LENGTH);
goto err;
}
-
- if (alg_a & SSL_aRSA) {
- pkey = X509_get_pubkey(s->session->sess_cert->peer_cert);
- }
- /* else anonymous DH, so no certificate or pkey. */
-
- s->session->sess_cert->peer_dh_tmp = dh;
+ DH_free(s->s3->tmp.peer_dh_tmp);
+ s->s3->tmp.peer_dh_tmp = dh;
dh = NULL;
} else if (alg_k & SSL_kECDHE) {
uint16_t curve_id;
@@ -1210,22 +1176,21 @@ int ssl3_get_server_key_exchange(SSL *s) {
* invalid curve. */
if (!tls1_check_curve(s, &server_key_exchange, &curve_id)) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_WRONG_CURVE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
goto f_err;
}
curve_nid = tls1_ec_curve_id2nid(curve_id);
if (curve_nid == 0) {
al = SSL_AD_INTERNAL_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange,
- SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
goto f_err;
}
ecdh = EC_KEY_new_by_curve_name(curve_nid);
+ s->session->key_exchange_info = curve_id;
if (ecdh == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange,
- ERR_R_EC_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_EC_LIB);
goto err;
}
@@ -1234,35 +1199,25 @@ int ssl3_get_server_key_exchange(SSL *s) {
/* Next, get the encoded ECPoint */
if (!CBS_get_u8_length_prefixed(&server_key_exchange, &point)) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
if (((srvr_ecpoint = EC_POINT_new(group)) == NULL) ||
((bn_ctx = BN_CTX_new()) == NULL)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!EC_POINT_oct2point(group, srvr_ecpoint, CBS_data(&point),
CBS_len(&point), bn_ctx)) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_BAD_ECPOINT);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
goto f_err;
}
-
- /* The ECC/TLS specification does not mention the use of DSA to sign
- * ECParameters in the server key exchange message. We do support RSA and
- * ECDSA. */
- if (alg_a & (SSL_aRSA|SSL_aECDSA)) {
- pkey = X509_get_pubkey(s->session->sess_cert->peer_cert);
- } else {
- /* Otherwise this is ECDHE_PSK, so no public key. */
- assert(alg_a == SSL_aPSK);
- }
EC_KEY_set_public_key(ecdh, srvr_ecpoint);
- s->session->sess_cert->peer_ecdh_tmp = ecdh;
+ EC_KEY_free(s->s3->tmp.peer_ecdh_tmp);
+ s->s3->tmp.peer_ecdh_tmp = ecdh;
ecdh = NULL;
BN_CTX_free(bn_ctx);
bn_ctx = NULL;
@@ -1270,8 +1225,7 @@ int ssl3_get_server_key_exchange(SSL *s) {
srvr_ecpoint = NULL;
} else if (!(alg_k & SSL_kPSK)) {
al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange,
- SSL_R_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
goto f_err;
}
@@ -1281,9 +1235,12 @@ int ssl3_get_server_key_exchange(SSL *s) {
CBS_init(&parameter, CBS_data(&server_key_exchange_orig),
CBS_len(&server_key_exchange_orig) - CBS_len(&server_key_exchange));
- /* if it was signed, check the signature */
- if (pkey != NULL) {
- CBS signature;
+ /* ServerKeyExchange should be signed by the server's public key. */
+ if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) {
+ pkey = X509_get_pubkey(s->session->peer);
+ if (pkey == NULL) {
+ goto err;
+ }
if (SSL_USE_SIGALGS(s)) {
if (!tls12_check_peer_sigalg(&md, &al, s, &server_key_exchange, pkey)) {
@@ -1296,10 +1253,11 @@ int ssl3_get_server_key_exchange(SSL *s) {
}
/* The last field in |server_key_exchange| is the signature. */
+ CBS signature;
if (!CBS_get_u16_length_prefixed(&server_key_exchange, &signature) ||
CBS_len(&server_key_exchange) != 0) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
@@ -1314,24 +1272,16 @@ int ssl3_get_server_key_exchange(SSL *s) {
CBS_len(&signature))) {
/* bad signature */
al = SSL_AD_DECRYPT_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_BAD_SIGNATURE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE);
goto f_err;
}
} else {
- if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) {
- /* Might be wrong key type, check it */
- if (ssl3_check_cert_and_algorithm(s)) {
- /* Otherwise this shouldn't happen */
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange,
- ERR_R_INTERNAL_ERROR);
- }
- goto err;
- }
- /* still data left over */
+ /* PSK ciphers are the only supported certificate-less ciphers. */
+ assert(alg_a == SSL_aPSK);
+
if (CBS_len(&server_key_exchange) > 0) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange,
- SSL_R_EXTRA_DATA_IN_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_EXTRA_DATA_IN_MESSAGE);
goto f_err;
}
}
@@ -1378,19 +1328,15 @@ int ssl3_get_certificate_request(SSL *s) {
if (s->s3->tmp.message_type == SSL3_MT_SERVER_DONE) {
s->s3->tmp.reuse_message = 1;
- /* If we get here we don't need any cached handshake records as we wont be
- * doing client auth. */
- if (s->s3->handshake_buffer &&
- !ssl3_digest_cached_records(s, free_handshake_buffer)) {
- goto err;
- }
+ /* If we get here we don't need the handshake buffer as we won't be doing
+ * client auth. */
+ ssl3_free_handshake_buffer(s);
return 1;
}
if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE_REQUEST) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
- OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request,
- SSL_R_WRONG_MESSAGE_TYPE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_MESSAGE_TYPE);
goto err;
}
@@ -1398,14 +1344,14 @@ int ssl3_get_certificate_request(SSL *s) {
ca_sk = sk_X509_NAME_new(ca_dn_cmp);
if (ca_sk == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
/* get the certificate types */
if (!CBS_get_u8_length_prefixed(&cbs, &certificate_types)) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto err;
}
@@ -1417,16 +1363,10 @@ int ssl3_get_certificate_request(SSL *s) {
if (SSL_USE_SIGALGS(s)) {
CBS supported_signature_algorithms;
- if (!CBS_get_u16_length_prefixed(&cbs, &supported_signature_algorithms)) {
+ if (!CBS_get_u16_length_prefixed(&cbs, &supported_signature_algorithms) ||
+ !tls1_parse_peer_sigalgs(s, &supported_signature_algorithms)) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, SSL_R_DECODE_ERROR);
- goto err;
- }
-
- if (!tls1_process_sigalgs(s, &supported_signature_algorithms)) {
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request,
- SSL_R_SIGNATURE_ALGORITHMS_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto err;
}
}
@@ -1434,7 +1374,7 @@ int ssl3_get_certificate_request(SSL *s) {
/* get the CA RDNs */
if (!CBS_get_u16_length_prefixed(&cbs, &certificate_authorities)) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, SSL_R_LENGTH_MISMATCH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_LENGTH_MISMATCH);
goto err;
}
@@ -1443,8 +1383,7 @@ int ssl3_get_certificate_request(SSL *s) {
if (!CBS_get_u16_length_prefixed(&certificate_authorities,
&distinguished_name)) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request,
- SSL_R_CA_DN_TOO_LONG);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CA_DN_TOO_LONG);
goto err;
}
@@ -1453,26 +1392,24 @@ int ssl3_get_certificate_request(SSL *s) {
xn = d2i_X509_NAME(NULL, &data, CBS_len(&distinguished_name));
if (xn == NULL) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, ERR_R_ASN1_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB);
goto err;
}
if (!CBS_skip(&distinguished_name, data - CBS_data(&distinguished_name))) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;
}
if (CBS_len(&distinguished_name) != 0) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request,
- SSL_R_CA_DN_LENGTH_MISMATCH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CA_DN_LENGTH_MISMATCH);
goto err;
}
if (!sk_X509_NAME_push(ca_sk, xn)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}
@@ -1516,18 +1453,9 @@ int ssl3_get_new_session_ticket(SSL *s) {
OPENSSL_free(bytes);
if (new_session == NULL) {
/* This should never happen. */
- OPENSSL_PUT_ERROR(SSL, ssl3_get_new_session_ticket, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;
}
- if (s->session->sess_cert != NULL) {
- /* |sess_cert| is not serialized and must be duplicated explicitly. */
- assert(new_session->sess_cert == NULL);
- new_session->sess_cert = ssl_sess_cert_dup(s->session->sess_cert);
- if (new_session->sess_cert == NULL) {
- SSL_SESSION_free(new_session);
- goto err;
- }
- }
SSL_SESSION_free(s->session);
s->session = new_session;
@@ -1540,13 +1468,13 @@ int ssl3_get_new_session_ticket(SSL *s) {
!CBS_get_u16_length_prefixed(&new_session_ticket, &ticket) ||
CBS_len(&new_session_ticket) != 0) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_new_session_ticket, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
if (!CBS_stow(&ticket, &s->session->tlsext_tick,
&s->session->tlsext_ticklen)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_new_session_ticket, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -1594,14 +1522,14 @@ int ssl3_get_cert_status(SSL *s) {
CBS_len(&ocsp_response) == 0 ||
CBS_len(&certificate_status) != 0) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_status, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
if (!CBS_stow(&ocsp_response, &s->session->ocsp_response,
&s->session->ocsp_response_length)) {
al = SSL_AD_INTERNAL_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_status, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto f_err;
}
return 1;
@@ -1627,7 +1555,7 @@ int ssl3_get_server_done(SSL *s) {
if (n > 0) {
/* should contain no data */
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- OPENSSL_PUT_ERROR(SSL, ssl3_get_server_done, SSL_R_LENGTH_MISMATCH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_LENGTH_MISMATCH);
return -1;
}
@@ -1665,8 +1593,7 @@ int ssl3_send_client_key_exchange(SSL *s) {
size_t identity_len;
if (s->psk_client_callback == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- SSL_R_PSK_NO_CLIENT_CB);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_NO_CLIENT_CB);
goto err;
}
@@ -1675,28 +1602,24 @@ int ssl3_send_client_key_exchange(SSL *s) {
s->psk_client_callback(s, s->s3->tmp.peer_psk_identity_hint, identity,
sizeof(identity), psk, sizeof(psk));
if (psk_len > PSK_MAX_PSK_LEN) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;
} else if (psk_len == 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- SSL_R_PSK_IDENTITY_NOT_FOUND);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
goto err;
}
identity_len = OPENSSL_strnlen(identity, sizeof(identity));
if (identity_len > PSK_MAX_IDENTITY_LEN) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;
}
OPENSSL_free(s->session->psk_identity);
s->session->psk_identity = BUF_strdup(identity);
if (s->session->psk_identity == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -1715,28 +1638,20 @@ int ssl3_send_client_key_exchange(SSL *s) {
pms_len = SSL_MAX_MASTER_KEY_LENGTH;
pms = OPENSSL_malloc(pms_len);
if (pms == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
- if (s->session->sess_cert == NULL) {
- /* We should always have a server certificate with SSL_kRSA. */
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- pkey = X509_get_pubkey(s->session->sess_cert->peer_cert);
+ pkey = X509_get_pubkey(s->session->peer);
if (pkey == NULL ||
pkey->type != EVP_PKEY_RSA ||
pkey->pkey.rsa == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
EVP_PKEY_free(pkey);
goto err;
}
+ s->session->key_exchange_info = EVP_PKEY_bits(pkey);
rsa = pkey->pkey.rsa;
EVP_PKEY_free(pkey);
@@ -1756,8 +1671,7 @@ int ssl3_send_client_key_exchange(SSL *s) {
}
if (!RSA_encrypt(rsa, &enc_pms_len, p, RSA_size(rsa), pms, pms_len,
RSA_PKCS1_PADDING)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- SSL_R_BAD_RSA_ENCRYPT);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_RSA_ENCRYPT);
goto err;
}
n += enc_pms_len;
@@ -1774,32 +1688,23 @@ int ssl3_send_client_key_exchange(SSL *s) {
}
} else if (alg_k & SSL_kDHE) {
DH *dh_srvr, *dh_clnt;
- SESS_CERT *scert = s->session->sess_cert;
int dh_len;
size_t pub_len;
- if (scert == NULL) {
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- SSL_R_UNEXPECTED_MESSAGE);
- goto err;
- }
-
- if (scert->peer_dh_tmp == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- ERR_R_INTERNAL_ERROR);
+ if (s->s3->tmp.peer_dh_tmp == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;
}
- dh_srvr = scert->peer_dh_tmp;
+ dh_srvr = s->s3->tmp.peer_dh_tmp;
/* generate a new random key */
dh_clnt = DHparams_dup(dh_srvr);
if (dh_clnt == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_DH_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB);
goto err;
}
if (!DH_generate_key(dh_clnt)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_DH_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB);
DH_free(dh_clnt);
goto err;
}
@@ -1807,15 +1712,14 @@ int ssl3_send_client_key_exchange(SSL *s) {
pms_len = DH_size(dh_clnt);
pms = OPENSSL_malloc(pms_len);
if (pms == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
DH_free(dh_clnt);
goto err;
}
dh_len = DH_compute_key(pms, dh_srvr->pub_key, dh_clnt);
if (dh_len <= 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_DH_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB);
DH_free(dh_clnt);
goto err;
}
@@ -1833,64 +1737,53 @@ int ssl3_send_client_key_exchange(SSL *s) {
EC_KEY *tkey;
int field_size = 0, ecdh_len;
- if (s->session->sess_cert == NULL) {
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- SSL_R_UNEXPECTED_MESSAGE);
+ if (s->s3->tmp.peer_ecdh_tmp == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;
}
- if (s->session->sess_cert->peer_ecdh_tmp == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- tkey = s->session->sess_cert->peer_ecdh_tmp;
+ tkey = s->s3->tmp.peer_ecdh_tmp;
srvr_group = EC_KEY_get0_group(tkey);
srvr_ecpoint = EC_KEY_get0_public_key(tkey);
if (srvr_group == NULL || srvr_ecpoint == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;
}
clnt_ecdh = EC_KEY_new();
if (clnt_ecdh == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!EC_KEY_set_group(clnt_ecdh, srvr_group)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_EC_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_EC_LIB);
goto err;
}
/* Generate a new ECDH key pair */
if (!EC_KEY_generate_key(clnt_ecdh)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ECDH_LIB);
goto err;
}
field_size = EC_GROUP_get_degree(srvr_group);
if (field_size <= 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ECDH_LIB);
goto err;
}
pms_len = (field_size + 7) / 8;
pms = OPENSSL_malloc(pms_len);
if (pms == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
ecdh_len = ECDH_compute_key(pms, pms_len, srvr_ecpoint, clnt_ecdh, NULL);
if (ecdh_len <= 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ECDH_LIB);
goto err;
}
pms_len = ecdh_len;
@@ -1904,8 +1797,7 @@ int ssl3_send_client_key_exchange(SSL *s) {
(uint8_t *)OPENSSL_malloc(encoded_pt_len * sizeof(uint8_t));
bn_ctx = BN_CTX_new();
if (encodedPoint == NULL || bn_ctx == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -1938,15 +1830,13 @@ int ssl3_send_client_key_exchange(SSL *s) {
pms_len = psk_len;
pms = OPENSSL_malloc(pms_len);
if (pms == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
memset(pms, 0, pms_len);
} else {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;
}
@@ -1957,19 +1847,15 @@ int ssl3_send_client_key_exchange(SSL *s) {
uint8_t *new_pms;
size_t new_pms_len;
- if (!CBB_init(&cbb, 2 + psk_len + 2 + pms_len)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
- if (!CBB_add_u16_length_prefixed(&cbb, &child) ||
+ CBB_zero(&cbb);
+ if (!CBB_init(&cbb, 2 + psk_len + 2 + pms_len) ||
+ !CBB_add_u16_length_prefixed(&cbb, &child) ||
!CBB_add_bytes(&child, pms, pms_len) ||
!CBB_add_u16_length_prefixed(&cbb, &child) ||
!CBB_add_bytes(&child, psk, psk_len) ||
!CBB_finish(&cbb, &new_pms, &new_pms_len)) {
CBB_cleanup(&cbb);
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange,
- ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
OPENSSL_cleanse(pms, pms_len);
@@ -2011,87 +1897,87 @@ err:
}
int ssl3_send_cert_verify(SSL *s) {
- uint8_t *buf, *p;
- const EVP_MD *md = NULL;
- uint8_t digest[EVP_MAX_MD_SIZE];
- size_t digest_length;
- EVP_PKEY *pkey;
- EVP_PKEY_CTX *pctx = NULL;
- size_t signature_length = 0;
- unsigned long n = 0;
-
- buf = (uint8_t *)s->init_buf->data;
-
- if (s->state == SSL3_ST_CW_CERT_VRFY_A) {
- p = ssl_handshake_start(s);
- pkey = s->cert->key->privatekey;
-
- /* Write out the digest type if needbe. */
- if (SSL_USE_SIGALGS(s)) {
- md = tls1_choose_signing_digest(s, pkey);
- if (!tls12_get_sigandhash(p, pkey, md)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, ERR_R_INTERNAL_ERROR);
- goto err;
+ if (s->state == SSL3_ST_CW_CERT_VRFY_A ||
+ s->state == SSL3_ST_CW_CERT_VRFY_B) {
+ enum ssl_private_key_result_t sign_result;
+ uint8_t *p = ssl_handshake_start(s);
+ size_t signature_length = 0;
+ unsigned long n = 0;
+ assert(ssl_has_private_key(s));
+
+ if (s->state == SSL3_ST_CW_CERT_VRFY_A) {
+ uint8_t *buf = (uint8_t *)s->init_buf->data;
+ const EVP_MD *md = NULL;
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ size_t digest_length;
+
+ /* Write out the digest type if need be. */
+ if (SSL_USE_SIGALGS(s)) {
+ md = tls1_choose_signing_digest(s);
+ if (!tls12_get_sigandhash(s, p, md)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ p += 2;
+ n += 2;
}
- p += 2;
- n += 2;
- }
- /* Compute the digest. */
- if (!ssl3_cert_verify_hash(s, digest, &digest_length, &md, pkey)) {
- goto err;
- }
+ /* Compute the digest. */
+ const int pkey_type = ssl_private_key_type(s);
+ if (!ssl3_cert_verify_hash(s, digest, &digest_length, &md, pkey_type)) {
+ return -1;
+ }
- /* The handshake buffer is no longer necessary. */
- if (s->s3->handshake_buffer &&
- !ssl3_digest_cached_records(s, free_handshake_buffer)) {
- goto err;
- }
+ /* The handshake buffer is no longer necessary. */
+ ssl3_free_handshake_buffer(s);
- /* Sign the digest. */
- pctx = EVP_PKEY_CTX_new(pkey, NULL);
- if (pctx == NULL) {
- goto err;
- }
+ /* Sign the digest. */
+ signature_length = ssl_private_key_max_signature_len(s);
+ if (p + 2 + signature_length > buf + SSL3_RT_MAX_PLAIN_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
+ return -1;
+ }
- /* Initialize the EVP_PKEY_CTX and determine the size of the signature. */
- if (!EVP_PKEY_sign_init(pctx) || !EVP_PKEY_CTX_set_signature_md(pctx, md) ||
- !EVP_PKEY_sign(pctx, NULL, &signature_length, digest, digest_length)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, ERR_R_EVP_LIB);
- goto err;
+ s->rwstate = SSL_PRIVATE_KEY_OPERATION;
+ sign_result = ssl_private_key_sign(s, &p[2], &signature_length,
+ signature_length, md, digest,
+ digest_length);
+ } else {
+ if (SSL_USE_SIGALGS(s)) {
+ /* The digest has already been selected and written. */
+ p += 2;
+ n += 2;
+ }
+ signature_length = ssl_private_key_max_signature_len(s);
+ s->rwstate = SSL_PRIVATE_KEY_OPERATION;
+ sign_result = ssl_private_key_sign_complete(s, &p[2], &signature_length,
+ signature_length);
}
- if (p + 2 + signature_length > buf + SSL3_RT_MAX_PLAIN_LENGTH) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, SSL_R_DATA_LENGTH_TOO_LONG);
- goto err;
+ if (sign_result == ssl_private_key_retry) {
+ s->state = SSL3_ST_CW_CERT_VRFY_B;
+ return -1;
}
-
- if (!EVP_PKEY_sign(pctx, &p[2], &signature_length, digest, digest_length)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, ERR_R_EVP_LIB);
- goto err;
+ s->rwstate = SSL_NOTHING;
+ if (sign_result != ssl_private_key_success) {
+ return -1;
}
s2n(signature_length, p);
n += signature_length + 2;
-
if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n)) {
- goto err;
+ return -1;
}
- s->state = SSL3_ST_CW_CERT_VRFY_B;
+ s->state = SSL3_ST_CW_CERT_VRFY_C;
}
- EVP_PKEY_CTX_free(pctx);
return ssl_do_write(s);
-
-err:
- EVP_PKEY_CTX_free(pctx);
- return -1;
}
/* ssl3_has_client_certificate returns true if a client certificate is
* configured. */
-static int ssl3_has_client_certificate(SSL *s) {
- return s->cert && s->cert->key->x509 && s->cert->key->privatekey;
+static int ssl3_has_client_certificate(SSL *ssl) {
+ return ssl->cert && ssl->cert->x509 && ssl_has_private_key(ssl);
}
int ssl3_send_client_certificate(SSL *s) {
@@ -2139,8 +2025,7 @@ int ssl3_send_client_certificate(SSL *s) {
}
} else if (i == 1) {
i = 0;
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_certificate,
- SSL_R_BAD_DATA_RETURNED_BY_CALLBACK);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK);
}
X509_free(x509);
@@ -2157,11 +2042,7 @@ int ssl3_send_client_certificate(SSL *s) {
s->s3->tmp.cert_req = 2;
/* There is no client certificate, so the handshake buffer may be
* released. */
- if (s->s3->handshake_buffer &&
- !ssl3_digest_cached_records(s, free_handshake_buffer)) {
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return -1;
- }
+ ssl3_free_handshake_buffer(s);
}
}
@@ -2170,80 +2051,23 @@ int ssl3_send_client_certificate(SSL *s) {
}
if (s->state == SSL3_ST_CW_CERT_C) {
- CERT_PKEY *cert_pkey = (s->s3->tmp.cert_req == 2) ? NULL : s->cert->key;
- if (!ssl3_output_cert_chain(s, cert_pkey)) {
+ if (s->s3->tmp.cert_req == 2) {
+ /* Send an empty Certificate message. */
+ uint8_t *p = ssl_handshake_start(s);
+ l2n3(0, p);
+ if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE, 3)) {
+ return -1;
+ }
+ } else if (!ssl3_output_cert_chain(s)) {
return -1;
}
+ s->state = SSL3_ST_CW_CERT_D;
}
/* SSL3_ST_CW_CERT_D */
return ssl_do_write(s);
}
-#define has_bits(i, m) (((i) & (m)) == (m))
-
-int ssl3_check_cert_and_algorithm(SSL *s) {
- long alg_k, alg_a;
- SESS_CERT *sc;
- DH *dh;
-
- /* we don't have a certificate */
- if (!ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) {
- return 1;
- }
-
- alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
- alg_a = s->s3->tmp.new_cipher->algorithm_auth;
-
- sc = s->session->sess_cert;
- if (sc == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_check_cert_and_algorithm, ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- dh = s->session->sess_cert->peer_dh_tmp;
-
- int cert_type = X509_certificate_type(sc->peer_cert, NULL);
- if (cert_type & EVP_PK_EC) {
- if (ssl_check_srvr_ecc_cert_and_alg(sc->peer_cert, s) == 0) {
- /* check failed */
- OPENSSL_PUT_ERROR(SSL, ssl3_check_cert_and_algorithm, SSL_R_BAD_ECC_CERT);
- goto f_err;
- } else {
- return 1;
- }
- } else if (alg_a & SSL_aECDSA) {
- OPENSSL_PUT_ERROR(SSL, ssl3_check_cert_and_algorithm,
- SSL_R_MISSING_ECDSA_SIGNING_CERT);
- goto f_err;
- }
-
- /* Check that we have a certificate if we require one */
- if ((alg_a & SSL_aRSA) && !has_bits(cert_type, EVP_PK_RSA | EVP_PKT_SIGN)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_check_cert_and_algorithm,
- SSL_R_MISSING_RSA_SIGNING_CERT);
- goto f_err;
- }
-
- if ((alg_k & SSL_kRSA) && !has_bits(cert_type, EVP_PK_RSA | EVP_PKT_ENC)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_check_cert_and_algorithm,
- SSL_R_MISSING_RSA_ENCRYPTING_CERT);
- goto f_err;
- }
-
- if ((alg_k & SSL_kDHE) && dh == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_check_cert_and_algorithm, SSL_R_MISSING_DH_KEY);
- goto f_err;
- }
-
- return 1;
-
-f_err:
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
-err:
- return 0;
-}
-
int ssl3_send_next_proto(SSL *s) {
unsigned int len, padding_len;
uint8_t *d, *p;
@@ -2273,7 +2097,6 @@ int ssl3_send_channel_id(SSL *s) {
uint8_t *d;
int ret = -1, public_key_len;
EVP_MD_CTX md_ctx;
- size_t sig_len;
ECDSA_SIG *sig = NULL;
uint8_t *public_key = NULL, *derp, *der_sig = NULL;
@@ -2295,72 +2118,48 @@ int ssl3_send_channel_id(SSL *s) {
}
s->rwstate = SSL_NOTHING;
- d = ssl_handshake_start(s);
- if (s->s3->tlsext_channel_id_new) {
- s2n(TLSEXT_TYPE_channel_id_new, d);
- } else {
- s2n(TLSEXT_TYPE_channel_id, d);
+ if (EVP_PKEY_id(s->tlsext_channel_id_private) != EVP_PKEY_EC) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
}
+ EC_KEY *ec_key = s->tlsext_channel_id_private->pkey.ec;
+
+ d = ssl_handshake_start(s);
+ s2n(TLSEXT_TYPE_channel_id, d);
s2n(TLSEXT_CHANNEL_ID_SIZE, d);
EVP_MD_CTX_init(&md_ctx);
- public_key_len = i2d_PublicKey(s->tlsext_channel_id_private, NULL);
+ public_key_len = i2o_ECPublicKey(ec_key, NULL);
if (public_key_len <= 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id,
- SSL_R_CANNOT_SERIALIZE_PUBLIC_KEY);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CANNOT_SERIALIZE_PUBLIC_KEY);
goto err;
}
- /* i2d_PublicKey will produce an ANSI X9.62 public key which, for a
+ /* i2o_ECPublicKey will produce an ANSI X9.62 public key which, for a
* P-256 key, is 0x04 (meaning uncompressed) followed by the x and y
* field elements as 32-byte, big-endian numbers. */
if (public_key_len != 65) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, SSL_R_CHANNEL_ID_NOT_P256);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256);
goto err;
}
public_key = OPENSSL_malloc(public_key_len);
if (!public_key) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
derp = public_key;
- i2d_PublicKey(s->tlsext_channel_id_private, &derp);
+ i2o_ECPublicKey(ec_key, &derp);
- if (EVP_DigestSignInit(&md_ctx, NULL, EVP_sha256(), NULL,
- s->tlsext_channel_id_private) != 1) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id,
- SSL_R_EVP_DIGESTSIGNINIT_FAILED);
- goto err;
- }
-
- if (!tls1_channel_id_hash(&md_ctx, s)) {
- goto err;
- }
-
- if (!EVP_DigestSignFinal(&md_ctx, NULL, &sig_len)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id,
- SSL_R_EVP_DIGESTSIGNFINAL_FAILED);
- goto err;
- }
-
- der_sig = OPENSSL_malloc(sig_len);
- if (!der_sig) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (!EVP_DigestSignFinal(&md_ctx, der_sig, &sig_len)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id,
- SSL_R_EVP_DIGESTSIGNFINAL_FAILED);
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ size_t digest_len;
+ if (!tls1_channel_id_hash(s, digest, &digest_len)) {
goto err;
}
- derp = der_sig;
- sig = d2i_ECDSA_SIG(NULL, (const uint8_t **)&derp, sig_len);
+ sig = ECDSA_do_sign(digest, digest_len, ec_key);
if (sig == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, SSL_R_D2I_ECDSA_SIG);
goto err;
}
@@ -2369,7 +2168,7 @@ int ssl3_send_channel_id(SSL *s) {
d += 64;
if (!BN_bn2bin_padded(d, 32, sig->r) ||
!BN_bn2bin_padded(d + 32, 32, sig->s)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;
}
@@ -2397,3 +2196,17 @@ int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey) {
}
return i;
}
+
+int ssl3_verify_server_cert(SSL *s) {
+ int ret = ssl_verify_cert_chain(s, s->session->cert_chain);
+ if (s->verify_mode != SSL_VERIFY_NONE && ret <= 0) {
+ int al = ssl_verify_alarm_type(s->verify_result);
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED);
+ } else {
+ ret = 1;
+ ERR_clear_error(); /* but we keep s->verify_result */
+ }
+
+ return ret;
+}
diff --git a/src/ssl/s3_enc.c b/src/ssl/s3_enc.c
index fbe68da..f1924c0 100644
--- a/src/ssl/s3_enc.c
+++ b/src/ssl/s3_enc.c
@@ -4,21 +4,21 @@
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
- *g
+ *
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *g
+ *
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
- *g
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,10 +33,10 @@
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) fromg
+ * 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *g
+ *
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -48,7 +48,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *g
+ *
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
@@ -62,7 +62,7 @@
* are met:
*
* 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.g
+ * notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
@@ -133,6 +133,8 @@
* OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
* OTHERWISE. */
+#include <openssl/ssl.h>
+
#include <assert.h>
#include <stdio.h>
#include <string.h>
@@ -180,7 +182,7 @@ int ssl3_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret,
k++;
if (k > sizeof(buf)) {
/* bug: 'buf' is too small for this ciphersuite */
- OPENSSL_PUT_ERROR(SSL, ssl3_prf, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
@@ -189,7 +191,7 @@ int ssl3_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret,
}
c++;
if (!EVP_DigestInit_ex(&sha1, EVP_sha1(), NULL)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_prf, ERR_LIB_EVP);
+ OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
return 0;
}
EVP_DigestUpdate(&sha1, buf, k);
@@ -204,7 +206,7 @@ int ssl3_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret,
EVP_DigestFinal_ex(&sha1, smd, NULL);
if (!EVP_DigestInit_ex(&md5, EVP_md5(), NULL)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_prf, ERR_LIB_EVP);
+ OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
return 0;
}
EVP_DigestUpdate(&md5, secret, secret_len);
@@ -235,96 +237,75 @@ void ssl3_cleanup_key_block(SSL *s) {
s->s3->tmp.key_block_length = 0;
}
-int ssl3_init_finished_mac(SSL *s) {
- BIO_free(s->s3->handshake_buffer);
- ssl3_free_digest_list(s);
- s->s3->handshake_buffer = BIO_new(BIO_s_mem());
- if (s->s3->handshake_buffer == NULL) {
- return 0;
- }
- BIO_set_close(s->s3->handshake_buffer, BIO_CLOSE);
-
- return 1;
+int ssl3_init_handshake_buffer(SSL *ssl) {
+ ssl3_free_handshake_buffer(ssl);
+ ssl3_free_handshake_hash(ssl);
+ ssl->s3->handshake_buffer = BUF_MEM_new();
+ return ssl->s3->handshake_buffer != NULL;
}
-void ssl3_free_digest_list(SSL *s) {
- int i;
- if (!s->s3->handshake_dgst) {
- return;
- }
- for (i = 0; i < SSL_MAX_DIGEST; i++) {
- if (s->s3->handshake_dgst[i]) {
- EVP_MD_CTX_destroy(s->s3->handshake_dgst[i]);
- }
+/* init_digest_with_data calls |EVP_DigestInit_ex| on |ctx| with |md| and then
+ * writes the data in |buf| to it. */
+static int init_digest_with_data(EVP_MD_CTX *ctx, const EVP_MD *md,
+ const BUF_MEM *buf) {
+ if (!EVP_DigestInit_ex(ctx, md, NULL)) {
+ return 0;
}
- OPENSSL_free(s->s3->handshake_dgst);
- s->s3->handshake_dgst = NULL;
+ EVP_DigestUpdate(ctx, buf->data, buf->length);
+ return 1;
}
-int ssl3_finish_mac(SSL *s, const uint8_t *buf, int len) {
- int i;
+int ssl3_init_handshake_hash(SSL *ssl) {
+ ssl3_free_handshake_hash(ssl);
- if (s->s3->handshake_buffer) {
- return BIO_write(s->s3->handshake_buffer, (void *)buf, len) >= 0;
+ uint32_t algorithm_prf = ssl_get_algorithm_prf(ssl);
+ if (!init_digest_with_data(&ssl->s3->handshake_hash,
+ ssl_get_handshake_digest(algorithm_prf),
+ ssl->s3->handshake_buffer)) {
+ return 0;
}
- for (i = 0; i < SSL_MAX_DIGEST; i++) {
- if (s->s3->handshake_dgst[i] != NULL) {
- EVP_DigestUpdate(s->s3->handshake_dgst[i], buf, len);
- }
+ if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT &&
+ !init_digest_with_data(&ssl->s3->handshake_md5, EVP_md5(),
+ ssl->s3->handshake_buffer)) {
+ return 0;
}
+
return 1;
}
-int ssl3_digest_cached_records(
- SSL *s, enum should_free_handshake_buffer_t should_free_handshake_buffer) {
- int i;
- uint32_t mask;
- const EVP_MD *md;
- const uint8_t *hdata;
- size_t hdatalen;
-
- /* Allocate handshake_dgst array */
- ssl3_free_digest_list(s);
- s->s3->handshake_dgst = OPENSSL_malloc(SSL_MAX_DIGEST * sizeof(EVP_MD_CTX *));
- if (s->s3->handshake_dgst == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_digest_cached_records, ERR_R_MALLOC_FAILURE);
- return 0;
- }
+void ssl3_free_handshake_hash(SSL *ssl) {
+ EVP_MD_CTX_cleanup(&ssl->s3->handshake_hash);
+ EVP_MD_CTX_cleanup(&ssl->s3->handshake_md5);
+}
- memset(s->s3->handshake_dgst, 0, SSL_MAX_DIGEST * sizeof(EVP_MD_CTX *));
- if (!BIO_mem_contents(s->s3->handshake_buffer, &hdata, &hdatalen)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_digest_cached_records,
- SSL_R_BAD_HANDSHAKE_LENGTH);
- return 0;
- }
+void ssl3_free_handshake_buffer(SSL *ssl) {
+ BUF_MEM_free(ssl->s3->handshake_buffer);
+ ssl->s3->handshake_buffer = NULL;
+}
- /* Loop through bits of algorithm2 field and create MD_CTX-es */
- for (i = 0; ssl_get_handshake_digest(&mask, &md, i); i++) {
- if ((mask & ssl_get_algorithm2(s)) && md) {
- s->s3->handshake_dgst[i] = EVP_MD_CTX_create();
- if (s->s3->handshake_dgst[i] == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_digest_cached_records, ERR_LIB_EVP);
- return 0;
- }
- if (!EVP_DigestInit_ex(s->s3->handshake_dgst[i], md, NULL)) {
- EVP_MD_CTX_destroy(s->s3->handshake_dgst[i]);
- s->s3->handshake_dgst[i] = NULL;
- OPENSSL_PUT_ERROR(SSL, ssl3_digest_cached_records, ERR_LIB_EVP);
- return 0;
- }
- EVP_DigestUpdate(s->s3->handshake_dgst[i], hdata, hdatalen);
- } else {
- s->s3->handshake_dgst[i] = NULL;
+int ssl3_update_handshake_hash(SSL *ssl, const uint8_t *in, size_t in_len) {
+ /* Depending on the state of the handshake, either the handshake buffer may be
+ * active, the rolling hash, or both. */
+
+ if (ssl->s3->handshake_buffer != NULL) {
+ size_t new_len = ssl->s3->handshake_buffer->length + in_len;
+ if (new_len < in_len) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return 0;
+ }
+ if (!BUF_MEM_grow(ssl->s3->handshake_buffer, new_len)) {
+ return 0;
}
+ memcpy(ssl->s3->handshake_buffer->data + new_len - in_len, in, in_len);
}
- if (should_free_handshake_buffer == free_handshake_buffer) {
- /* Free handshake_buffer BIO */
- BIO_free(s->s3->handshake_buffer);
- s->s3->handshake_buffer = NULL;
+ if (EVP_MD_CTX_md(&ssl->s3->handshake_hash) != NULL) {
+ EVP_DigestUpdate(&ssl->s3->handshake_hash, in, in_len);
+ }
+ if (EVP_MD_CTX_md(&ssl->s3->handshake_md5) != NULL) {
+ EVP_DigestUpdate(&ssl->s3->handshake_md5, in, in_len);
}
-
return 1;
}
@@ -356,31 +337,22 @@ static int ssl3_handshake_mac(SSL *s, int md_nid, const char *sender, int len,
int npad, n;
unsigned int i;
uint8_t md_buf[EVP_MAX_MD_SIZE];
- EVP_MD_CTX ctx, *d = NULL;
-
- if (s->s3->handshake_buffer &&
- !ssl3_digest_cached_records(s, free_handshake_buffer)) {
- return 0;
- }
-
- /* Search for digest of specified type in the handshake_dgst array. */
- for (i = 0; i < SSL_MAX_DIGEST; i++) {
- if (s->s3->handshake_dgst[i] &&
- EVP_MD_CTX_type(s->s3->handshake_dgst[i]) == md_nid) {
- d = s->s3->handshake_dgst[i];
- break;
- }
- }
-
- if (!d) {
- OPENSSL_PUT_ERROR(SSL, ssl3_handshake_mac, SSL_R_NO_REQUIRED_DIGEST);
+ EVP_MD_CTX ctx;
+ const EVP_MD_CTX *ctx_template;
+
+ if (md_nid == NID_md5) {
+ ctx_template = &s->s3->handshake_md5;
+ } else if (md_nid == EVP_MD_CTX_type(&s->s3->handshake_hash)) {
+ ctx_template = &s->s3->handshake_hash;
+ } else {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_REQUIRED_DIGEST);
return 0;
}
EVP_MD_CTX_init(&ctx);
- if (!EVP_MD_CTX_copy_ex(&ctx, d)) {
+ if (!EVP_MD_CTX_copy_ex(&ctx, ctx_template)) {
EVP_MD_CTX_cleanup(&ctx);
- OPENSSL_PUT_ERROR(SSL, ssl3_handshake_mac, ERR_LIB_EVP);
+ OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
return 0;
}
@@ -399,7 +371,7 @@ static int ssl3_handshake_mac(SSL *s, int md_nid, const char *sender, int len,
if (!EVP_DigestInit_ex(&ctx, EVP_MD_CTX_md(&ctx), NULL)) {
EVP_MD_CTX_cleanup(&ctx);
- OPENSSL_PUT_ERROR(SSL, ssl3_handshake_mac, ERR_LIB_EVP);
+ OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
return 0;
}
EVP_DigestUpdate(&ctx, s->session->master_key, s->session->master_key_length);
@@ -420,7 +392,7 @@ int ssl3_record_sequence_update(uint8_t *seq, size_t seq_len) {
return 1;
}
}
- OPENSSL_PUT_ERROR(SSL, ssl3_record_sequence_update, ERR_R_OVERFLOW);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
return 0;
}
diff --git a/src/ssl/s3_lib.c b/src/ssl/s3_lib.c
index 1c28a73..617ea6e 100644
--- a/src/ssl/s3_lib.c
+++ b/src/ssl/s3_lib.c
@@ -146,12 +146,15 @@
* OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
* OTHERWISE. */
+#include <openssl/ssl.h>
+
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <openssl/buf.h>
#include <openssl/dh.h>
+#include <openssl/digest.h>
#include <openssl/err.h>
#include <openssl/md5.h>
#include <openssl/mem.h>
@@ -186,7 +189,8 @@ int ssl3_set_handshake_header(SSL *s, int htype, unsigned long len) {
s->init_off = 0;
/* Add the message to the handshake hash. */
- return ssl3_finish_mac(s, (uint8_t *)s->init_buf->data, s->init_num);
+ return ssl3_update_handshake_hash(s, (uint8_t *)s->init_buf->data,
+ s->init_num);
}
int ssl3_handshake_write(SSL *s) { return ssl3_do_write(s, SSL3_RT_HANDSHAKE); }
@@ -199,7 +203,9 @@ int ssl3_new(SSL *s) {
goto err;
}
memset(s3, 0, sizeof *s3);
- memset(s3->rrec.seq_num, 0, sizeof(s3->rrec.seq_num));
+
+ EVP_MD_CTX_init(&s3->handshake_hash);
+ EVP_MD_CTX_init(&s3->handshake_md5);
s->s3 = s3;
@@ -219,20 +225,20 @@ void ssl3_free(SSL *s) {
return;
}
- BUF_MEM_free(s->s3->sniff_buffer);
ssl3_cleanup_key_block(s);
- ssl3_release_read_buffer(s);
- ssl3_release_write_buffer(s);
+ ssl_read_buffer_clear(s);
+ ssl_write_buffer_clear(s);
DH_free(s->s3->tmp.dh);
EC_KEY_free(s->s3->tmp.ecdh);
sk_X509_NAME_pop_free(s->s3->tmp.ca_names, X509_NAME_free);
OPENSSL_free(s->s3->tmp.certificate_types);
- OPENSSL_free(s->s3->tmp.peer_ecpointformatlist);
OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist);
OPENSSL_free(s->s3->tmp.peer_psk_identity_hint);
- BIO_free(s->s3->handshake_buffer);
- ssl3_free_digest_list(s);
+ DH_free(s->s3->tmp.peer_dh_tmp);
+ EC_KEY_free(s->s3->tmp.peer_ecdh_tmp);
+ ssl3_free_handshake_buffer(s);
+ ssl3_free_handshake_hash(s);
OPENSSL_free(s->s3->alpn_selected);
OPENSSL_cleanse(s->s3, sizeof *s->s3);
@@ -240,8 +246,6 @@ void ssl3_free(SSL *s) {
s->s3 = NULL;
}
-static int ssl3_set_req_cert_type(CERT *c, const uint8_t *p, size_t len);
-
int SSL_session_reused(const SSL *ssl) {
return ssl->hit;
}
@@ -274,7 +278,7 @@ int SSL_CTX_set_tmp_dh(SSL_CTX *ctx, const DH *dh) {
DH_free(ctx->cert->dh_tmp);
ctx->cert->dh_tmp = DHparams_dup(dh);
if (ctx->cert->dh_tmp == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_set_tmp_dh, ERR_R_DH_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB);
return 0;
}
return 1;
@@ -284,7 +288,7 @@ int SSL_set_tmp_dh(SSL *ssl, const DH *dh) {
DH_free(ssl->cert->dh_tmp);
ssl->cert->dh_tmp = DHparams_dup(dh);
if (ssl->cert->dh_tmp == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_set_tmp_dh, ERR_R_DH_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB);
return 0;
}
return 1;
@@ -292,7 +296,7 @@ int SSL_set_tmp_dh(SSL *ssl, const DH *dh) {
int SSL_CTX_set_tmp_ecdh(SSL_CTX *ctx, const EC_KEY *ec_key) {
if (ec_key == NULL || EC_KEY_get0_group(ec_key) == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_set_tmp_ecdh, ERR_R_PASSED_NULL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
ctx->cert->ecdh_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key));
@@ -301,7 +305,7 @@ int SSL_CTX_set_tmp_ecdh(SSL_CTX *ctx, const EC_KEY *ec_key) {
int SSL_set_tmp_ecdh(SSL *ssl, const EC_KEY *ec_key) {
if (ec_key == NULL || EC_KEY_get0_group(ec_key) == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_set_tmp_ecdh, ERR_R_PASSED_NULL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
ssl->cert->ecdh_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key));
@@ -322,8 +326,7 @@ 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);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256);
return 0;
}
EVP_PKEY_free(ctx->tlsext_channel_id_private);
@@ -335,7 +338,7 @@ int SSL_set1_tls_channel_id(SSL *ssl, EVP_PKEY *private_key) {
ssl->tlsext_channel_id_enabled = 1;
if (EVP_PKEY_id(private_key) != EVP_PKEY_EC ||
EVP_PKEY_bits(private_key) != 256) {
- OPENSSL_PUT_ERROR(SSL, SSL_set1_tls_channel_id, SSL_R_CHANNEL_ID_NOT_P256);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256);
return 0;
}
EVP_PKEY_free(ssl->tlsext_channel_id_private);
@@ -359,238 +362,36 @@ int SSL_set_tlsext_host_name(SSL *ssl, const char *name) {
return 1;
}
if (strlen(name) > TLSEXT_MAXLEN_host_name) {
- OPENSSL_PUT_ERROR(SSL, SSL_set_tlsext_host_name,
- SSL_R_SSL3_EXT_INVALID_SERVERNAME);
+ OPENSSL_PUT_ERROR(SSL, 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);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return 0;
}
return 1;
}
-long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) {
- int ret = 0;
-
- switch (cmd) {
- case SSL_CTRL_CHAIN:
- if (larg) {
- return ssl_cert_set1_chain(s->cert, (STACK_OF(X509) *)parg);
- } else {
- return ssl_cert_set0_chain(s->cert, (STACK_OF(X509) *)parg);
- }
-
- case SSL_CTRL_CHAIN_CERT:
- if (larg) {
- return ssl_cert_add1_chain_cert(s->cert, (X509 *)parg);
- } else {
- return ssl_cert_add0_chain_cert(s->cert, (X509 *)parg);
- }
-
- case SSL_CTRL_GET_CHAIN_CERTS:
- *(STACK_OF(X509) **)parg = s->cert->key->chain;
- ret = 1;
- break;
-
- case SSL_CTRL_SELECT_CURRENT_CERT:
- return ssl_cert_select_current(s->cert, (X509 *)parg);
-
- case SSL_CTRL_GET_CURVES: {
- const uint16_t *clist = s->s3->tmp.peer_ellipticcurvelist;
- size_t clistlen = s->s3->tmp.peer_ellipticcurvelist_length;
- if (parg) {
- size_t i;
- int *cptr = parg;
- int nid;
- for (i = 0; i < clistlen; i++) {
- nid = tls1_ec_curve_id2nid(clist[i]);
- if (nid != NID_undef) {
- cptr[i] = nid;
- } else {
- cptr[i] = TLSEXT_nid_unknown | clist[i];
- }
- }
- }
- return (int)clistlen;
- }
-
- case SSL_CTRL_SET_CURVES:
- return tls1_set_curves(&s->tlsext_ellipticcurvelist,
- &s->tlsext_ellipticcurvelist_length, parg, larg);
-
- case SSL_CTRL_SET_SIGALGS:
- return tls1_set_sigalgs(s->cert, parg, larg, 0);
-
- case SSL_CTRL_SET_CLIENT_SIGALGS:
- return tls1_set_sigalgs(s->cert, parg, larg, 1);
-
- case SSL_CTRL_GET_CLIENT_CERT_TYPES: {
- const uint8_t **pctype = parg;
- if (s->server || !s->s3->tmp.cert_req) {
- return 0;
- }
- if (pctype) {
- *pctype = s->s3->tmp.certificate_types;
- }
- return (int)s->s3->tmp.num_certificate_types;
- }
-
- case SSL_CTRL_SET_CLIENT_CERT_TYPES:
- if (!s->server) {
- return 0;
- }
- return ssl3_set_req_cert_type(s->cert, parg, larg);
-
- case SSL_CTRL_BUILD_CERT_CHAIN:
- return ssl_build_cert_chain(s->cert, s->ctx->cert_store, larg);
-
- case SSL_CTRL_SET_VERIFY_CERT_STORE:
- return ssl_cert_set_cert_store(s->cert, parg, 0, larg);
-
- case SSL_CTRL_SET_CHAIN_CERT_STORE:
- return ssl_cert_set_cert_store(s->cert, parg, 1, larg);
-
- case SSL_CTRL_GET_SERVER_TMP_KEY:
- if (s->server || !s->session || !s->session->sess_cert) {
- return 0;
- } else {
- SESS_CERT *sc;
- EVP_PKEY *ptmp;
- int rv = 0;
- sc = s->session->sess_cert;
- if (!sc->peer_dh_tmp && !sc->peer_ecdh_tmp) {
- return 0;
- }
- ptmp = EVP_PKEY_new();
- if (!ptmp) {
- return 0;
- }
- if (sc->peer_dh_tmp) {
- rv = EVP_PKEY_set1_DH(ptmp, sc->peer_dh_tmp);
- } else if (sc->peer_ecdh_tmp) {
- rv = EVP_PKEY_set1_EC_KEY(ptmp, sc->peer_ecdh_tmp);
- }
- if (rv) {
- *(EVP_PKEY **)parg = ptmp;
- return 1;
- }
- EVP_PKEY_free(ptmp);
- return 0;
- }
-
- case SSL_CTRL_GET_EC_POINT_FORMATS: {
- const uint8_t **pformat = parg;
- if (!s->s3->tmp.peer_ecpointformatlist) {
- return 0;
- }
- *pformat = s->s3->tmp.peer_ecpointformatlist;
- return (int)s->s3->tmp.peer_ecpointformatlist_length;
- }
-
- default:
- break;
+size_t SSL_get0_certificate_types(SSL *ssl, const uint8_t **out_types) {
+ if (ssl->server || !ssl->s3->tmp.cert_req) {
+ *out_types = NULL;
+ return 0;
}
-
- return ret;
+ *out_types = ssl->s3->tmp.certificate_types;
+ return ssl->s3->tmp.num_certificate_types;
}
-long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) {
- switch (cmd) {
- case SSL_CTRL_SET_TLSEXT_TICKET_KEYS:
- case SSL_CTRL_GET_TLSEXT_TICKET_KEYS: {
- uint8_t *keys = parg;
- if (!keys) {
- return 48;
- }
- if (larg != 48) {
- OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, SSL_R_INVALID_TICKET_KEYS_LENGTH);
- return 0;
- }
- if (cmd == SSL_CTRL_SET_TLSEXT_TICKET_KEYS) {
- memcpy(ctx->tlsext_tick_key_name, keys, 16);
- memcpy(ctx->tlsext_tick_hmac_key, keys + 16, 16);
- memcpy(ctx->tlsext_tick_aes_key, keys + 32, 16);
- } else {
- memcpy(keys, ctx->tlsext_tick_key_name, 16);
- memcpy(keys + 16, ctx->tlsext_tick_hmac_key, 16);
- memcpy(keys + 32, ctx->tlsext_tick_aes_key, 16);
- }
- return 1;
- }
-
- case SSL_CTRL_SET_CURVES:
- return tls1_set_curves(&ctx->tlsext_ellipticcurvelist,
- &ctx->tlsext_ellipticcurvelist_length, parg, larg);
-
- case SSL_CTRL_SET_SIGALGS:
- return tls1_set_sigalgs(ctx->cert, parg, larg, 0);
-
- case SSL_CTRL_SET_CLIENT_SIGALGS:
- return tls1_set_sigalgs(ctx->cert, parg, larg, 1);
-
- case SSL_CTRL_SET_CLIENT_CERT_TYPES:
- return ssl3_set_req_cert_type(ctx->cert, parg, larg);
-
- case SSL_CTRL_BUILD_CERT_CHAIN:
- return ssl_build_cert_chain(ctx->cert, ctx->cert_store, larg);
-
- case SSL_CTRL_SET_VERIFY_CERT_STORE:
- return ssl_cert_set_cert_store(ctx->cert, parg, 0, larg);
-
- case SSL_CTRL_SET_CHAIN_CERT_STORE:
- return ssl_cert_set_cert_store(ctx->cert, parg, 1, larg);
-
- case SSL_CTRL_EXTRA_CHAIN_CERT:
- if (ctx->extra_certs == NULL) {
- ctx->extra_certs = sk_X509_new_null();
- if (ctx->extra_certs == NULL) {
- return 0;
- }
- }
- sk_X509_push(ctx->extra_certs, (X509 *)parg);
- break;
-
- case SSL_CTRL_GET_EXTRA_CHAIN_CERTS:
- if (ctx->extra_certs == NULL && larg == 0) {
- *(STACK_OF(X509) **)parg = ctx->cert->key->chain;
- } else {
- *(STACK_OF(X509) **)parg = ctx->extra_certs;
- }
- break;
-
- case SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS:
- sk_X509_pop_free(ctx->extra_certs, X509_free);
- ctx->extra_certs = NULL;
- break;
-
- case SSL_CTRL_CHAIN:
- if (larg) {
- return ssl_cert_set1_chain(ctx->cert, (STACK_OF(X509) *)parg);
- } else {
- return ssl_cert_set0_chain(ctx->cert, (STACK_OF(X509) *)parg);
- }
-
- case SSL_CTRL_CHAIN_CERT:
- if (larg) {
- return ssl_cert_add1_chain_cert(ctx->cert, (X509 *)parg);
- } else {
- return ssl_cert_add0_chain_cert(ctx->cert, (X509 *)parg);
- }
-
- case SSL_CTRL_GET_CHAIN_CERTS:
- *(STACK_OF(X509) **)parg = ctx->cert->key->chain;
- break;
-
- case SSL_CTRL_SELECT_CURRENT_CERT:
- return ssl_cert_select_current(ctx->cert, (X509 *)parg);
-
- default:
- return 0;
- }
+int SSL_CTX_set1_curves(SSL_CTX *ctx, const int *curves, size_t curves_len) {
+ return tls1_set_curves(&ctx->tlsext_ellipticcurvelist,
+ &ctx->tlsext_ellipticcurvelist_length, curves,
+ curves_len);
+}
- return 1;
+int SSL_set1_curves(SSL *ssl, const int *curves, size_t curves_len) {
+ return tls1_set_curves(&ssl->tlsext_ellipticcurvelist,
+ &ssl->tlsext_ellipticcurvelist_length, curves,
+ curves_len);
}
int SSL_CTX_set_tlsext_servername_callback(
@@ -604,6 +405,36 @@ int SSL_CTX_set_tlsext_servername_arg(SSL_CTX *ctx, void *arg) {
return 1;
}
+int SSL_CTX_get_tlsext_ticket_keys(SSL_CTX *ctx, void *out, size_t len) {
+ if (out == NULL) {
+ return 48;
+ }
+ if (len != 48) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH);
+ return 0;
+ }
+ uint8_t *out_bytes = out;
+ memcpy(out_bytes, ctx->tlsext_tick_key_name, 16);
+ memcpy(out_bytes + 16, ctx->tlsext_tick_hmac_key, 16);
+ memcpy(out_bytes + 32, ctx->tlsext_tick_aes_key, 16);
+ return 1;
+}
+
+int SSL_CTX_set_tlsext_ticket_keys(SSL_CTX *ctx, const void *in, size_t len) {
+ if (in == NULL) {
+ return 48;
+ }
+ if (len != 48) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH);
+ return 0;
+ }
+ const uint8_t *in_bytes = in;
+ memcpy(ctx->tlsext_tick_key_name, in_bytes, 16);
+ memcpy(ctx->tlsext_tick_hmac_key, in_bytes + 16, 16);
+ memcpy(ctx->tlsext_tick_aes_key, in_bytes + 32, 16);
+ return 1;
+}
+
int SSL_CTX_set_tlsext_ticket_key_cb(
SSL_CTX *ctx, int (*callback)(SSL *ssl, uint8_t *key_name, uint8_t *iv,
EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx,
@@ -622,6 +453,11 @@ struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *s) {
return s->ctx->cipher_list_tls11;
}
+ if (s->version >= TLS1_VERSION && s->ctx != NULL &&
+ s->ctx->cipher_list_tls10 != NULL) {
+ return s->ctx->cipher_list_tls10;
+ }
+
if (s->ctx != NULL && s->ctx->cipher_list != NULL) {
return s->ctx->cipher_list;
}
@@ -708,13 +544,6 @@ int ssl3_get_req_cert_type(SSL *s, uint8_t *p) {
int have_rsa_sign = 0;
int have_ecdsa_sign = 0;
- /* If we have custom certificate types set, use them */
- if (s->cert->client_certificate_types) {
- memcpy(p, s->cert->client_certificate_types,
- s->cert->num_client_certificate_types);
- return s->cert->num_client_certificate_types;
- }
-
/* get configured sigalgs */
siglen = tls12_get_psigalgs(s, &sig);
for (i = 0; i < siglen; i += 2, sig += 2) {
@@ -742,36 +571,13 @@ int ssl3_get_req_cert_type(SSL *s, uint8_t *p) {
return ret;
}
-static int ssl3_set_req_cert_type(CERT *c, const uint8_t *p, size_t len) {
- OPENSSL_free(c->client_certificate_types);
- c->client_certificate_types = NULL;
- c->num_client_certificate_types = 0;
-
- if (!p || !len) {
- return 1;
- }
-
- if (len > 0xff) {
- return 0;
- }
-
- c->client_certificate_types = BUF_memdup(p, len);
- if (!c->client_certificate_types) {
- return 0;
- }
-
- c->num_client_certificate_types = len;
- return 1;
-}
-
/* If we are using default SHA1+MD5 algorithms switch to new SHA256 PRF and
* handshake macs if required. */
-uint32_t ssl_get_algorithm2(SSL *s) {
- static const uint32_t kMask = SSL_HANDSHAKE_MAC_DEFAULT;
- uint32_t alg2 = s->s3->tmp.new_cipher->algorithm2;
+uint32_t ssl_get_algorithm_prf(SSL *s) {
+ uint32_t algorithm_prf = s->s3->tmp.new_cipher->algorithm_prf;
if (s->enc_method->enc_flags & SSL_ENC_FLAG_SHA256_PRF &&
- (alg2 & kMask) == kMask) {
+ algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT) {
return SSL_HANDSHAKE_MAC_SHA256;
}
- return alg2;
+ return algorithm_prf;
}
diff --git a/src/ssl/s3_meth.c b/src/ssl/s3_meth.c
index 66bbb29..01c1101 100644
--- a/src/ssl/s3_meth.c
+++ b/src/ssl/s3_meth.c
@@ -54,6 +54,8 @@
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
+#include <openssl/ssl.h>
+
#include "internal.h"
@@ -68,8 +70,6 @@ static const SSL_PROTOCOL_METHOD TLS_protocol_method = {
ssl3_read_close_notify,
ssl3_write_app_data,
ssl3_dispatch_alert,
- ssl3_ctrl,
- ssl3_ctx_ctrl,
ssl3_supports_cipher,
SSL3_HM_HEADER_LENGTH,
ssl3_set_handshake_header,
diff --git a/src/ssl/s3_pkt.c b/src/ssl/s3_pkt.c
index 4a9ae83..3c2435d 100644
--- a/src/ssl/s3_pkt.c
+++ b/src/ssl/s3_pkt.c
@@ -106,6 +106,8 @@
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com). */
+#include <openssl/ssl.h>
+
#include <assert.h>
#include <limits.h>
#include <stdio.h>
@@ -120,282 +122,65 @@
#include "internal.h"
-static int do_ssl3_write(SSL *s, int type, const uint8_t *buf, unsigned int len,
- char fragment);
-static int ssl3_get_record(SSL *s);
+static int do_ssl3_write(SSL *s, int type, const uint8_t *buf, unsigned len);
-int ssl3_read_n(SSL *s, int n, int extend) {
- /* If |extend| is 0, obtain new n-byte packet;
- * if |extend| is 1, increase packet by another n bytes.
- *
- * The packet will be in the sub-array of |s->s3->rbuf.buf| specified by
- * |s->packet| and |s->packet_length|. (If DTLS and |extend| is 0, additional
- * bytes will be read into |rbuf|, up to the size of the buffer.)
- *
- * TODO(davidben): |dtls1_get_record| and |ssl3_get_record| have very
- * different needs. Separate the two record layers. In DTLS, |BIO_read| is
- * called at most once, and only when |extend| is 0. In TLS, the buffer never
- * contains more than one record. */
- int i, len, left;
- uintptr_t align = 0;
- uint8_t *pkt;
- SSL3_BUFFER *rb;
-
- if (n <= 0) {
- return n;
- }
+/* kMaxWarningAlerts is the number of consecutive warning alerts that will be
+ * processed. */
+static const uint8_t kMaxWarningAlerts = 4;
- rb = &s->s3->rbuf;
- if (rb->buf == NULL && !ssl3_setup_read_buffer(s)) {
- return -1;
- }
-
- left = rb->left;
-
- align = (uintptr_t)rb->buf + SSL3_RT_HEADER_LENGTH;
- align = (0 - align) & (SSL3_ALIGN_PAYLOAD - 1);
-
- if (!extend) {
- /* start with empty packet ... */
- if (left == 0) {
- rb->offset = align;
- } else if (align != 0 && left >= SSL3_RT_HEADER_LENGTH) {
- /* check if next packet length is large enough to justify payload
- * alignment... */
- pkt = rb->buf + rb->offset;
- if (pkt[0] == SSL3_RT_APPLICATION_DATA && (pkt[3] << 8 | pkt[4]) >= 128) {
- /* Note that even if packet is corrupted and its length field is
- * insane, we can only be led to wrong decision about whether memmove
- * will occur or not. Header values has no effect on memmove arguments
- * and therefore no buffer overrun can be triggered. */
- memmove(rb->buf + align, pkt, left);
- rb->offset = align;
+/* ssl3_get_record reads a new input record. On success, it places it in
+ * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if
+ * more data is needed. */
+static int ssl3_get_record(SSL *ssl) {
+ int ret;
+again:
+ /* Ensure the buffer is large enough to decrypt in-place. */
+ ret = ssl_read_buffer_extend_to(ssl, ssl_record_prefix_len(ssl));
+ if (ret <= 0) {
+ return ret;
+ }
+ assert(ssl_read_buffer_len(ssl) >= ssl_record_prefix_len(ssl));
+
+ uint8_t *out = ssl_read_buffer(ssl) + ssl_record_prefix_len(ssl);
+ size_t max_out = ssl_read_buffer_len(ssl) - ssl_record_prefix_len(ssl);
+ uint8_t type, alert;
+ size_t len, consumed;
+ switch (tls_open_record(ssl, &type, out, &len, &consumed, &alert, max_out,
+ ssl_read_buffer(ssl), ssl_read_buffer_len(ssl))) {
+ case ssl_open_record_success:
+ ssl_read_buffer_consume(ssl, consumed);
+
+ if (len > 0xffff) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return -1;
}
- }
- s->packet = rb->buf + rb->offset;
- s->packet_length = 0;
- /* ... now we can act as if 'extend' was set */
- }
-
- /* In DTLS, if there is leftover data from the previous packet or |extend| is
- * true, clamp to the previous read. DTLS records may not span packet
- * boundaries. */
- if (SSL_IS_DTLS(s) && n > left && (left > 0 || extend)) {
- n = left;
- }
- /* if there is enough in the buffer from a previous read, take some */
- if (left >= n) {
- s->packet_length += n;
- rb->left = left - n;
- rb->offset += n;
- return n;
- }
-
- /* else we need to read more data */
-
- len = s->packet_length;
- pkt = rb->buf + align;
- /* Move any available bytes to front of buffer: |len| bytes already pointed
- * to by |packet|, |left| extra ones at the end. */
- if (s->packet != pkt) {
- /* len > 0 */
- memmove(pkt, s->packet, len + left);
- s->packet = pkt;
- rb->offset = len + align;
- }
-
- if (n > (int)(rb->len - rb->offset)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_read_n, ERR_R_INTERNAL_ERROR);
- return -1;
- }
-
- int max = n;
- if (SSL_IS_DTLS(s) && !extend) {
- max = rb->len - rb->offset;
- }
-
- while (left < n) {
- /* Now we have len+left bytes at the front of s->s3->rbuf.buf and need to
- * read in more until we have len+n (up to len+max if possible). */
- ERR_clear_system_error();
- if (s->rbio != NULL) {
- s->rwstate = SSL_READING;
- i = BIO_read(s->rbio, pkt + len + left, max - left);
- } else {
- OPENSSL_PUT_ERROR(SSL, ssl3_read_n, SSL_R_READ_BIO_NOT_SET);
- i = -1;
- }
-
- if (i <= 0) {
- rb->left = left;
- if (len + left == 0) {
- ssl3_release_read_buffer(s);
+ SSL3_RECORD *rr = &ssl->s3->rrec;
+ rr->type = type;
+ rr->length = (uint16_t)len;
+ rr->off = 0;
+ rr->data = out;
+ return 1;
+
+ case ssl_open_record_partial:
+ ret = ssl_read_buffer_extend_to(ssl, consumed);
+ if (ret <= 0) {
+ return ret;
}
- return i;
- }
- left += i;
- /* reads should *never* span multiple packets for DTLS because the
- * underlying transport protocol is message oriented as opposed to byte
- * oriented as in the TLS case. */
- if (SSL_IS_DTLS(s) && n > left) {
- n = left; /* makes the while condition false */
- }
- }
+ goto again;
- /* done reading, now the book-keeping */
- rb->offset += n;
- rb->left = left - n;
- s->packet_length += n;
- s->rwstate = SSL_NOTHING;
+ case ssl_open_record_discard:
+ ssl_read_buffer_consume(ssl, consumed);
+ goto again;
- return n;
-}
-
-/* MAX_EMPTY_RECORDS defines the number of consecutive, empty records that will
- * be processed per call to ssl3_get_record. Without this limit an attacker
- * could send empty records at a faster rate than we can process and cause
- * ssl3_get_record to loop forever. */
-#define MAX_EMPTY_RECORDS 32
-
-/* Call this to get a new input record. It will return <= 0 if more data is
- * needed, normally due to an error or non-blocking IO. When it finishes, one
- * packet has been decoded and can be found in
- * ssl->s3->rrec.type - is the type of record
- * ssl->s3->rrec.data - data
- * ssl->s3->rrec.length - number of bytes */
-/* used only by ssl3_read_bytes */
-static int ssl3_get_record(SSL *s) {
- uint8_t ssl_major, ssl_minor;
- int al, n, i, ret = -1;
- SSL3_RECORD *rr = &s->s3->rrec;
- uint8_t *p;
- uint16_t version;
- size_t extra;
- unsigned empty_record_count = 0;
-
-again:
- /* check if we have the header */
- if (s->rstate != SSL_ST_READ_BODY ||
- s->packet_length < SSL3_RT_HEADER_LENGTH) {
- n = ssl3_read_n(s, SSL3_RT_HEADER_LENGTH, 0);
- if (n <= 0) {
- return n; /* error or non-blocking */
- }
- s->rstate = SSL_ST_READ_BODY;
-
- /* Some bytes were read, so the read buffer must be existant and
- * |s->s3->init_extra| is defined. */
- assert(s->s3->rbuf.buf != NULL);
- extra = s->s3->init_extra ? SSL3_RT_MAX_EXTRA : 0;
-
- p = s->packet;
- if (s->msg_callback) {
- s->msg_callback(0, 0, SSL3_RT_HEADER, p, 5, s, s->msg_callback_arg);
- }
-
- /* Pull apart the header into the SSL3_RECORD */
- rr->type = *(p++);
- ssl_major = *(p++);
- ssl_minor = *(p++);
- version = (((uint16_t)ssl_major) << 8) | ssl_minor;
- n2s(p, rr->length);
-
- if (s->s3->have_version && version != s->version) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_WRONG_VERSION_NUMBER);
- al = SSL_AD_PROTOCOL_VERSION;
- goto f_err;
- }
-
- if ((version >> 8) != SSL3_VERSION_MAJOR) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_WRONG_VERSION_NUMBER);
- goto err;
- }
-
- if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH + extra) {
- al = SSL_AD_RECORD_OVERFLOW;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
- goto f_err;
- }
-
- /* now s->rstate == SSL_ST_READ_BODY */
- } else {
- /* |packet_length| is non-zero and |s->rstate| is |SSL_ST_READ_BODY|. The
- * read buffer must be existant and |s->s3->init_extra| is defined. */
- assert(s->s3->rbuf.buf != NULL);
- extra = s->s3->init_extra ? SSL3_RT_MAX_EXTRA : 0;
- }
-
- /* s->rstate == SSL_ST_READ_BODY, get and decode the data */
-
- if (rr->length > s->packet_length - SSL3_RT_HEADER_LENGTH) {
- /* now s->packet_length == SSL3_RT_HEADER_LENGTH */
- i = rr->length;
- n = ssl3_read_n(s, i, 1);
- if (n <= 0) {
- /* Error or non-blocking IO. Now |n| == |rr->length|, and
- * |s->packet_length| == |SSL3_RT_HEADER_LENGTH| + |rr->length|. */
- return n;
- }
- }
-
- s->rstate = SSL_ST_READ_HEADER; /* set state for later operations */
-
- /* |rr->data| points to |rr->length| bytes of ciphertext in |s->packet|. */
- rr->data = &s->packet[SSL3_RT_HEADER_LENGTH];
-
- /* Decrypt the packet in-place.
- *
- * TODO(davidben): This assumes |s->version| is the same as the record-layer
- * version which isn't always true, but it only differs with the NULL cipher
- * which ignores the parameter. */
- size_t plaintext_len;
- if (!SSL_AEAD_CTX_open(s->aead_read_ctx, rr->data, &plaintext_len, rr->length,
- rr->type, s->version, s->s3->read_sequence, rr->data,
- rr->length)) {
- al = SSL_AD_BAD_RECORD_MAC;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_record,
- SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
- goto f_err;
- }
- if (!ssl3_record_sequence_update(s->s3->read_sequence, 8)) {
- goto err;
- }
- if (plaintext_len > SSL3_RT_MAX_PLAIN_LENGTH + extra) {
- al = SSL_AD_RECORD_OVERFLOW;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_DATA_LENGTH_TOO_LONG);
- goto f_err;
- }
- assert(plaintext_len <= (1u << 16));
- rr->length = plaintext_len;
-
- rr->off = 0;
- /* So at this point the following is true:
- * ssl->s3->rrec.type is the type of record;
- * ssl->s3->rrec.length is the number of bytes in the record;
- * ssl->s3->rrec.off is the offset to first valid byte;
- * ssl->s3->rrec.data the first byte of the record body. */
-
- /* we have pulled in a full packet so zero things */
- s->packet_length = 0;
-
- /* just read a 0 length packet */
- if (rr->length == 0) {
- empty_record_count++;
- if (empty_record_count > MAX_EMPTY_RECORDS) {
- al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_TOO_MANY_EMPTY_FRAGMENTS);
- goto f_err;
- }
- goto again;
+ case ssl_open_record_error:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return -1;
}
- return 1;
-
-f_err:
- ssl3_send_alert(s, SSL3_AL_FATAL, al);
-err:
- return ret;
+ assert(0);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
}
int ssl3_write_app_data(SSL *ssl, const void *buf, int len) {
@@ -420,7 +205,7 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) {
return i;
}
if (i == 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_write_bytes, SSL_R_SSL_HANDSHAKE_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
return -1;
}
}
@@ -433,33 +218,22 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) {
* beyond the end of the users buffer ... so we trap and report the error in
* a way the user will notice. */
if (len < 0 || (size_t)len < tot) {
- OPENSSL_PUT_ERROR(SSL, ssl3_write_bytes, SSL_R_BAD_LENGTH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_LENGTH);
return -1;
}
- int record_split_done = 0;
n = (len - tot);
for (;;) {
/* max contains the maximum number of bytes that we can put into a
* record. */
unsigned max = s->max_send_fragment;
- /* fragment is true if do_ssl3_write should send the first byte in its own
- * record in order to randomise a CBC IV. */
- int fragment = 0;
- if (!record_split_done && s->s3->need_record_splitting &&
- type == SSL3_RT_APPLICATION_DATA) {
- /* Only the the first record per write call needs to be split. The
- * remaining plaintext was determined before the IV was randomized. */
- fragment = 1;
- record_split_done = 1;
- }
if (n > max) {
nw = max;
} else {
nw = n;
}
- i = do_ssl3_write(s, type, &buf[tot], nw, fragment);
+ i = do_ssl3_write(s, type, &buf[tot], nw);
if (i <= 0) {
s->s3->wnum = tot;
return i;
@@ -475,65 +249,10 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) {
}
}
-/* ssl3_seal_record seals a new record of type |type| and plaintext |in| and
- * writes it to |out|. At most |max_out| bytes will be written. It returns one
- * on success and zero on error. On success, it updates the write sequence
- * number. */
-static int ssl3_seal_record(SSL *s, uint8_t *out, size_t *out_len,
- size_t max_out, uint8_t type, const uint8_t *in,
- size_t in_len) {
- if (max_out < SSL3_RT_HEADER_LENGTH) {
- OPENSSL_PUT_ERROR(SSL, ssl3_seal_record, SSL_R_BUFFER_TOO_SMALL);
- return 0;
- }
-
- out[0] = type;
-
- /* Some servers hang if initial ClientHello is larger than 256 bytes and
- * record version number > TLS 1.0. */
- uint16_t wire_version = s->version;
- if (!s->s3->have_version && s->version > SSL3_VERSION) {
- wire_version = TLS1_VERSION;
- }
- out[1] = wire_version >> 8;
- out[2] = wire_version & 0xff;
-
- size_t ciphertext_len;
- if (!SSL_AEAD_CTX_seal(s->aead_write_ctx, out + SSL3_RT_HEADER_LENGTH,
- &ciphertext_len, max_out - SSL3_RT_HEADER_LENGTH,
- type, wire_version, s->s3->write_sequence, in,
- in_len) ||
- !ssl3_record_sequence_update(s->s3->write_sequence, 8)) {
- return 0;
- }
-
- if (ciphertext_len >= 1 << 16) {
- OPENSSL_PUT_ERROR(SSL, ssl3_seal_record, ERR_R_OVERFLOW);
- return 0;
- }
- out[3] = ciphertext_len >> 8;
- out[4] = ciphertext_len & 0xff;
-
- *out_len = SSL3_RT_HEADER_LENGTH + ciphertext_len;
-
- if (s->msg_callback) {
- s->msg_callback(1 /* write */, 0, SSL3_RT_HEADER, out, SSL3_RT_HEADER_LENGTH,
- s, s->msg_callback_arg);
- }
-
- return 1;
-}
-
-/* do_ssl3_write writes an SSL record of the given type. If |fragment| is 1
- * then it splits the record into a one byte record and a record with the rest
- * of the data in order to randomise a CBC IV. */
-static int do_ssl3_write(SSL *s, int type, const uint8_t *buf, unsigned int len,
- char fragment) {
- SSL3_BUFFER *wb = &s->s3->wbuf;
-
- /* first check if there is a SSL3_BUFFER still being written out. This will
- * happen with non blocking IO */
- if (wb->left != 0) {
+/* do_ssl3_write writes an SSL record of the given type. */
+static int do_ssl3_write(SSL *s, int type, const uint8_t *buf, unsigned len) {
+ /* If there is still data from the previous record, flush it. */
+ if (ssl_write_buffer_is_pending(s)) {
return ssl3_write_pending(s, type, buf, len);
}
@@ -546,113 +265,53 @@ static int do_ssl3_write(SSL *s, int type, const uint8_t *buf, unsigned int len,
/* if it went, fall through and send more stuff */
}
- if (wb->buf == NULL && !ssl3_setup_write_buffer(s)) {
+ if (len > SSL3_RT_MAX_PLAIN_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
}
if (len == 0) {
return 0;
}
- if (len == 1) {
- /* No sense in fragmenting a one-byte record. */
- fragment = 0;
- }
- /* Align the output so the ciphertext is aligned to |SSL3_ALIGN_PAYLOAD|. */
- uintptr_t align;
- if (fragment) {
- /* Only CBC-mode ciphers require fragmenting. CBC-mode ciphertext is a
- * multiple of the block size which we may assume is aligned. Thus we only
- * need to account for a second copy of the record header. */
- align = (uintptr_t)wb->buf + 2 * SSL3_RT_HEADER_LENGTH;
- } else {
- align = (uintptr_t)wb->buf + SSL3_RT_HEADER_LENGTH;
- }
- align = (0 - align) & (SSL3_ALIGN_PAYLOAD - 1);
- uint8_t *out = wb->buf + align;
- wb->offset = align;
- size_t max_out = wb->len - wb->offset;
-
- const uint8_t *orig_buf = buf;
- unsigned int orig_len = len;
- size_t fragment_len = 0;
- if (fragment) {
- /* Write the first byte in its own record as a countermeasure against
- * known-IV weaknesses in CBC ciphersuites. (See
- * http://www.openssl.org/~bodo/tls-cbc.txt.) */
- if (!ssl3_seal_record(s, out, &fragment_len, max_out, type, buf, 1)) {
- return -1;
- }
- out += fragment_len;
- max_out -= fragment_len;
- buf++;
- len--;
+ size_t max_out = len + ssl_max_seal_overhead(s);
+ if (max_out < len) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return -1;
}
-
- assert((((uintptr_t)out + SSL3_RT_HEADER_LENGTH) & (SSL3_ALIGN_PAYLOAD - 1))
- == 0);
+ uint8_t *out;
size_t ciphertext_len;
- if (!ssl3_seal_record(s, out, &ciphertext_len, max_out, type, buf, len)) {
+ if (!ssl_write_buffer_init(s, &out, max_out) ||
+ !tls_seal_record(s, out, &ciphertext_len, max_out, type, buf, len)) {
return -1;
}
- ciphertext_len += fragment_len;
-
- /* now let's set up wb */
- wb->left = ciphertext_len;
+ ssl_write_buffer_set_len(s, ciphertext_len);
/* memorize arguments so that ssl3_write_pending can detect bad write retries
* later */
- s->s3->wpend_tot = orig_len;
- s->s3->wpend_buf = orig_buf;
+ s->s3->wpend_tot = len;
+ s->s3->wpend_buf = buf;
s->s3->wpend_type = type;
- s->s3->wpend_ret = orig_len;
+ s->s3->wpend_ret = len;
/* we now just need to write the buffer */
- return ssl3_write_pending(s, type, orig_buf, orig_len);
+ return ssl3_write_pending(s, type, buf, len);
}
-/* if s->s3->wbuf.left != 0, we need to call this */
int ssl3_write_pending(SSL *s, int type, const uint8_t *buf, unsigned int len) {
- int i;
- SSL3_BUFFER *wb = &(s->s3->wbuf);
-
if (s->s3->wpend_tot > (int)len ||
(s->s3->wpend_buf != buf &&
!(s->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)) ||
s->s3->wpend_type != type) {
- OPENSSL_PUT_ERROR(SSL, ssl3_write_pending, SSL_R_BAD_WRITE_RETRY);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_WRITE_RETRY);
return -1;
}
- for (;;) {
- ERR_clear_system_error();
- if (s->wbio != NULL) {
- s->rwstate = SSL_WRITING;
- i = BIO_write(s->wbio, (char *)&(wb->buf[wb->offset]),
- (unsigned int)wb->left);
- } else {
- OPENSSL_PUT_ERROR(SSL, ssl3_write_pending, SSL_R_BIO_NOT_SET);
- i = -1;
- }
- if (i == wb->left) {
- wb->left = 0;
- wb->offset += i;
- ssl3_release_write_buffer(s);
- s->rwstate = SSL_NOTHING;
- return s->s3->wpend_ret;
- } else if (i <= 0) {
- if (SSL_IS_DTLS(s)) {
- /* For DTLS, just drop it. That's kind of the whole point in
- * using a datagram service */
- wb->left = 0;
- }
- return i;
- }
- /* TODO(davidben): This codepath is used in DTLS, but the write
- * payload may not split across packets. */
- wb->offset += i;
- wb->left -= i;
+ int ret = ssl_write_buffer_flush(s);
+ if (ret <= 0) {
+ return ret;
}
+ return s->s3->wpend_ret;
}
/* ssl3_expect_change_cipher_spec informs the record layer that a
@@ -662,8 +321,7 @@ int ssl3_write_pending(SSL *s, int type, const uint8_t *buf, unsigned int len) {
* function returns zero. Otherwise, the function returns one. */
int ssl3_expect_change_cipher_spec(SSL *s) {
if (s->s3->handshake_fragment_len > 0 || s->s3->tmp.reuse_message) {
- OPENSSL_PUT_ERROR(SSL, ssl3_expect_change_cipher_spec,
- SSL_R_UNPROCESSED_HANDSHAKE_DATA);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNPROCESSED_HANDSHAKE_DATA);
return 0;
}
@@ -714,7 +372,7 @@ int ssl3_read_bytes(SSL *s, int type, uint8_t *buf, int len, int peek) {
if ((type && type != SSL3_RT_APPLICATION_DATA && type != SSL3_RT_HANDSHAKE) ||
(peek && type != SSL3_RT_APPLICATION_DATA)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
}
@@ -753,7 +411,7 @@ int ssl3_read_bytes(SSL *s, int type, uint8_t *buf, int len, int peek) {
return i;
}
if (i == 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
return -1;
}
}
@@ -768,7 +426,7 @@ start:
rr = &s->s3->rrec;
/* get new packet if necessary */
- if (rr->length == 0 || s->rstate == SSL_ST_READ_BODY) {
+ if (rr->length == 0) {
ret = ssl3_get_record(s);
if (ret <= 0) {
return ret;
@@ -782,8 +440,7 @@ start:
if (s->s3->change_cipher_spec && rr->type != SSL3_RT_HANDSHAKE &&
rr->type != SSL3_RT_ALERT) {
al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes,
- SSL_R_DATA_BETWEEN_CCS_AND_FINISHED);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED);
goto f_err;
}
@@ -791,7 +448,7 @@ start:
* Handshake record. */
if (rr->type == SSL3_RT_HANDSHAKE && (s->s3->flags & SSL3_FLAGS_EXPECT_CCS)) {
al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_HANDSHAKE_RECORD_BEFORE_CCS);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_HANDSHAKE_RECORD_BEFORE_CCS);
goto f_err;
}
@@ -803,7 +460,9 @@ start:
return 0;
}
- if (type == rr->type) {
+ if (type != 0 && type == rr->type) {
+ s->s3->warning_alert_count = 0;
+
/* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */
/* make sure that we are not getting application data when we are doing a
* handshake for the first time */
@@ -812,10 +471,15 @@ start:
/* TODO(davidben): Is this check redundant with the handshake_func
* check? */
al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_APP_DATA_IN_HANDSHAKE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_APP_DATA_IN_HANDSHAKE);
goto f_err;
}
+ /* Discard empty records. */
+ if (rr->length == 0) {
+ goto start;
+ }
+
if (len <= 0) {
return len;
}
@@ -831,11 +495,9 @@ start:
rr->length -= n;
rr->off += n;
if (rr->length == 0) {
- s->rstate = SSL_ST_READ_HEADER;
rr->off = 0;
- if (s->s3->rbuf.left == 0) {
- ssl3_release_read_buffer(s);
- }
+ /* The record has been consumed, so we may now clear the buffer. */
+ ssl_read_buffer_discard(s);
}
}
@@ -849,7 +511,7 @@ start:
* are fatal. Renegotiations as a server are never supported. */
if (!s->accept_peer_renegotiations || s->server) {
al = SSL_AD_NO_RENEGOTIATION;
- OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_NO_RENEGOTIATION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION);
goto f_err;
}
@@ -872,7 +534,7 @@ start:
s->s3->handshake_fragment[2] != 0 ||
s->s3->handshake_fragment[3] != 0) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_BAD_HELLO_REQUEST);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HELLO_REQUEST);
goto f_err;
}
s->s3->handshake_fragment_len = 0;
@@ -886,7 +548,7 @@ start:
/* This cannot happen. If a handshake is in progress, |type| must be
* |SSL3_RT_HANDSHAKE|. */
assert(0);
- OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;
}
@@ -894,9 +556,9 @@ start:
* protocol, namely in HTTPS, just before reading the HTTP response. Require
* the record-layer be idle and avoid complexities of sending a handshake
* record while an application_data record is being written. */
- if (s->s3->wbuf.left != 0 || s->s3->rbuf.left != 0) {
+ if (ssl_write_buffer_is_pending(s)) {
al = SSL_AD_NO_RENEGOTIATION;
- OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_NO_RENEGOTIATION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION);
goto f_err;
}
@@ -907,7 +569,7 @@ start:
return i;
}
if (i == 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
return -1;
}
@@ -921,7 +583,7 @@ start:
/* 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);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT);
goto f_err;
}
@@ -960,7 +622,14 @@ start:
* peer refused it where we carry on. */
else if (alert_descr == SSL_AD_NO_RENEGOTIATION) {
al = SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_NO_RENEGOTIATION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION);
+ goto f_err;
+ }
+
+ s->s3->warning_alert_count++;
+ if (s->s3->warning_alert_count > kMaxWarningAlerts) {
+ al = SSL_AD_UNEXPECTED_MESSAGE;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_WARNING_ALERTS);
goto f_err;
}
} else if (alert_level == SSL3_AL_FATAL) {
@@ -968,8 +637,7 @@ start:
s->rwstate = SSL_NOTHING;
s->s3->fatal_alert = alert_descr;
- OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes,
- SSL_AD_REASON_OFFSET + alert_descr);
+ OPENSSL_PUT_ERROR(SSL, SSL_AD_REASON_OFFSET + alert_descr);
BIO_snprintf(tmp, sizeof(tmp), "%d", alert_descr);
ERR_add_error_data(2, "SSL alert number ", tmp);
s->shutdown |= SSL_RECEIVED_SHUTDOWN;
@@ -977,7 +645,7 @@ start:
return 0;
} else {
al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_UNKNOWN_ALERT_TYPE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_ALERT_TYPE);
goto f_err;
}
@@ -985,10 +653,9 @@ start:
}
if (s->shutdown & SSL_SENT_SHUTDOWN) {
- /* but we have not received a shutdown */
- s->rwstate = SSL_NOTHING;
+ /* close_notify has been sent, so discard all records other than alerts. */
rr->length = 0;
- return 0;
+ goto start;
}
if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) {
@@ -996,20 +663,20 @@ start:
* record payload has to look like */
if (rr->length != 1 || rr->off != 0 || rr->data[0] != SSL3_MT_CCS) {
al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_BAD_CHANGE_CIPHER_SPEC);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC);
goto f_err;
}
/* Check we have a cipher to change to */
if (s->s3->tmp.new_cipher == NULL) {
al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_CCS_RECEIVED_EARLY);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CCS_RECEIVED_EARLY);
goto f_err;
}
if (!(s->s3->flags & SSL3_FLAGS_EXPECT_CCS)) {
al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_CCS_RECEIVED_EARLY);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CCS_RECEIVED_EARLY);
goto f_err;
}
@@ -1035,7 +702,7 @@ start:
rr->type != SSL3_RT_HANDSHAKE);
al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_UNEXPECTED_RECORD);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
@@ -1055,8 +722,7 @@ int ssl3_do_change_cipher_spec(SSL *s) {
if (s->s3->tmp.key_block == NULL) {
if (s->session == NULL || s->session->master_key_length == 0) {
/* might happen if dtls1_read_bytes() calls this */
- OPENSSL_PUT_ERROR(SSL, ssl3_do_change_cipher_spec,
- SSL_R_CCS_RECEIVED_EARLY);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CCS_RECEIVED_EARLY);
return 0;
}
@@ -1092,8 +758,9 @@ int ssl3_send_alert(SSL *s, int level, int desc) {
s->s3->alert_dispatch = 1;
s->s3->send_alert[0] = level;
s->s3->send_alert[1] = desc;
- if (s->s3->wbuf.left == 0) {
- /* data is still being written out. */
+ if (!ssl_write_buffer_is_pending(s)) {
+ /* Nothing is being written out, so the alert may be dispatched
+ * immediately. */
return s->method->ssl_dispatch_alert(s);
}
@@ -1107,7 +774,7 @@ int ssl3_dispatch_alert(SSL *s) {
void (*cb)(const SSL *ssl, int type, int val) = NULL;
s->s3->alert_dispatch = 0;
- i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], 2, 0);
+ i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], 2);
if (i <= 0) {
s->s3->alert_dispatch = 1;
} else {
diff --git a/src/ssl/s3_srvr.c b/src/ssl/s3_srvr.c
index a72e17e..b428043 100644
--- a/src/ssl/s3_srvr.c
+++ b/src/ssl/s3_srvr.c
@@ -146,6 +146,8 @@
* OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
* OTHERWISE. */
+#include <openssl/ssl.h>
+
#include <assert.h>
#include <stdio.h>
#include <string.h>
@@ -172,10 +174,6 @@
#include "../crypto/dh/internal.h"
-/* INITIAL_SNIFF_BUFFER_SIZE is the number of bytes read in the initial sniff
- * buffer. */
-#define INITIAL_SNIFF_BUFFER_SIZE 8
-
int ssl3_accept(SSL *s) {
BUF_MEM *buf = NULL;
uint32_t alg_a;
@@ -199,7 +197,7 @@ int ssl3_accept(SSL *s) {
s->in_handshake++;
if (s->cert == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_accept, SSL_R_NO_CERTIFICATE_SET);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET);
return -1;
}
@@ -230,8 +228,8 @@ int ssl3_accept(SSL *s) {
goto end;
}
- if (!ssl3_init_finished_mac(s)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_accept, ERR_R_INTERNAL_ERROR);
+ if (!ssl3_init_handshake_buffer(s)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
ret = -1;
goto end;
}
@@ -310,8 +308,19 @@ int ssl3_accept(SSL *s) {
s->init_num = 0;
break;
+ case SSL3_ST_SW_CERT_STATUS_A:
+ case SSL3_ST_SW_CERT_STATUS_B:
+ ret = ssl3_send_certificate_status(s);
+ if (ret <= 0) {
+ goto end;
+ }
+ s->state = SSL3_ST_SW_KEY_EXCH_A;
+ s->init_num = 0;
+ break;
+
case SSL3_ST_SW_KEY_EXCH_A:
case SSL3_ST_SW_KEY_EXCH_B:
+ case SSL3_ST_SW_KEY_EXCH_C:
alg_a = s->s3->tmp.new_cipher->algorithm_auth;
/* Send a ServerKeyExchange message if:
@@ -473,7 +482,7 @@ int ssl3_accept(SSL *s) {
/* If this is a full handshake with ChannelID then record the hashshake
* hashes in |s->session| in case we need them to verify a ChannelID
* signature on a resumption of this session in the future. */
- if (!s->hit && s->s3->tlsext_channel_id_new) {
+ if (!s->hit) {
ret = tls1_record_handshake_hashes_for_channel_id(s);
if (ret <= 0) {
goto end;
@@ -550,6 +559,8 @@ int ssl3_accept(SSL *s) {
if (s->ctx->retain_only_sha256_of_client_certs) {
X509_free(s->session->peer);
s->session->peer = NULL;
+ sk_X509_pop_free(s->session->cert_chain, X509_free);
+ s->session->cert_chain = NULL;
}
s->s3->initial_handshake_complete = 1;
@@ -564,7 +575,7 @@ int ssl3_accept(SSL *s) {
goto end;
default:
- OPENSSL_PUT_ERROR(SSL, ssl3_accept, SSL_R_UNKNOWN_STATE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE);
ret = -1;
goto end;
}
@@ -587,42 +598,16 @@ end:
return ret;
}
-static int ssl3_read_sniff_buffer(SSL *s, size_t n) {
- if (s->s3->sniff_buffer == NULL) {
- s->s3->sniff_buffer = BUF_MEM_new();
- }
- if (s->s3->sniff_buffer == NULL || !BUF_MEM_grow(s->s3->sniff_buffer, n)) {
- return -1;
- }
-
- while (s->s3->sniff_buffer_len < n) {
- int ret;
-
- s->rwstate = SSL_READING;
- ret = BIO_read(s->rbio, s->s3->sniff_buffer->data + s->s3->sniff_buffer_len,
- n - s->s3->sniff_buffer_len);
- if (ret <= 0) {
- return ret;
- }
- s->rwstate = SSL_NOTHING;
- s->s3->sniff_buffer_len += ret;
- }
-
- return 1;
-}
-
int ssl3_get_initial_bytes(SSL *s) {
- int ret;
- const uint8_t *p;
-
- /* Read the first 8 bytes. To recognize a ClientHello or V2ClientHello only
- * needs the first 6 bytes, but 8 is needed to recognize CONNECT below. */
- ret = ssl3_read_sniff_buffer(s, INITIAL_SNIFF_BUFFER_SIZE);
+ /* Read the first 5 bytes, the size of the TLS record header. This is
+ * sufficient to detect a V2ClientHello and ensures that we never read beyond
+ * the first record. */
+ int ret = ssl_read_buffer_extend_to(s, SSL3_RT_HEADER_LENGTH);
if (ret <= 0) {
return ret;
}
- assert(s->s3->sniff_buffer_len >= INITIAL_SNIFF_BUFFER_SIZE);
- p = (const uint8_t *)s->s3->sniff_buffer->data;
+ assert(ssl_read_buffer_len(s) == SSL3_RT_HEADER_LENGTH);
+ const uint8_t *p = ssl_read_buffer(s);
/* Some dedicated error codes for protocol mixups should the application wish
* to interpret them differently. (These do not overlap with ClientHello or
@@ -631,46 +616,25 @@ int ssl3_get_initial_bytes(SSL *s) {
strncmp("POST ", (const char *)p, 5) == 0 ||
strncmp("HEAD ", (const char *)p, 5) == 0 ||
strncmp("PUT ", (const char *)p, 4) == 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_initial_bytes, SSL_R_HTTP_REQUEST);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_HTTP_REQUEST);
return -1;
}
- if (strncmp("CONNECT ", (const char *)p, 8) == 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_initial_bytes, SSL_R_HTTPS_PROXY_REQUEST);
+ if (strncmp("CONNE", (const char *)p, 5) == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_HTTPS_PROXY_REQUEST);
return -1;
}
- /* Determine if this is a ClientHello or V2ClientHello. */
+ /* Determine if this is a V2ClientHello. */
if ((p[0] & 0x80) && p[2] == SSL2_MT_CLIENT_HELLO &&
p[3] >= SSL3_VERSION_MAJOR) {
/* This is a V2ClientHello. */
s->state = SSL3_ST_SR_V2_CLIENT_HELLO;
return 1;
}
- if (p[0] == SSL3_RT_HANDSHAKE && p[1] >= SSL3_VERSION_MAJOR &&
- p[5] == SSL3_MT_CLIENT_HELLO) {
- /* This is a ClientHello. Initialize the record layer with the already
- * consumed data and continue the handshake. */
- if (!ssl3_setup_read_buffer(s)) {
- return -1;
- }
- assert(s->rstate == SSL_ST_READ_HEADER);
- /* There cannot have already been data in the record layer. */
- assert(s->s3->rbuf.left == 0);
- memcpy(s->s3->rbuf.buf, p, s->s3->sniff_buffer_len);
- s->s3->rbuf.offset = 0;
- s->s3->rbuf.left = s->s3->sniff_buffer_len;
- s->packet_length = 0;
-
- BUF_MEM_free(s->s3->sniff_buffer);
- s->s3->sniff_buffer = NULL;
- s->s3->sniff_buffer_len = 0;
-
- s->state = SSL3_ST_SR_CLNT_HELLO_A;
- return 1;
- }
- OPENSSL_PUT_ERROR(SSL, ssl3_get_initial_bytes, SSL_R_UNKNOWN_PROTOCOL);
- return -1;
+ /* Fall through to the standard logic. */
+ s->state = SSL3_ST_SR_CLNT_HELLO_A;
+ return 1;
}
int ssl3_get_v2_client_hello(SSL *s) {
@@ -683,36 +647,34 @@ int ssl3_get_v2_client_hello(SSL *s) {
CBB client_hello, hello_body, cipher_suites;
uint8_t random[SSL3_RANDOM_SIZE];
- /* Read the remainder of the V2ClientHello. We have previously read 8 bytes
- * in ssl3_get_initial_bytes. */
- assert(s->s3->sniff_buffer_len >= INITIAL_SNIFF_BUFFER_SIZE);
- p = (const uint8_t *)s->s3->sniff_buffer->data;
+ /* Determine the length of the V2ClientHello. */
+ assert(ssl_read_buffer_len(s) >= SSL3_RT_HEADER_LENGTH);
+ p = ssl_read_buffer(s);
msg_length = ((p[0] & 0x7f) << 8) | p[1];
if (msg_length > (1024 * 4)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_v2_client_hello, SSL_R_RECORD_TOO_LARGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_TOO_LARGE);
return -1;
}
- if (msg_length < INITIAL_SNIFF_BUFFER_SIZE - 2) {
- /* Reject lengths that are too short early. We have already read 8 bytes,
- * so we should not attempt to process an (invalid) V2ClientHello which
- * would be shorter than that. */
- OPENSSL_PUT_ERROR(SSL, ssl3_get_v2_client_hello,
- SSL_R_RECORD_LENGTH_MISMATCH);
+ if (msg_length < SSL3_RT_HEADER_LENGTH - 2) {
+ /* Reject lengths that are too short early. We have already read
+ * |SSL3_RT_HEADER_LENGTH| bytes, so we should not attempt to process an
+ * (invalid) V2ClientHello which would be shorter than that. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_LENGTH_MISMATCH);
return -1;
}
- ret = ssl3_read_sniff_buffer(s, msg_length + 2);
+ /* Read the remainder of the V2ClientHello. */
+ ret = ssl_read_buffer_extend_to(s, 2 + msg_length);
if (ret <= 0) {
return ret;
}
- assert(s->s3->sniff_buffer_len == msg_length + 2);
- CBS_init(&v2_client_hello, (const uint8_t *)s->s3->sniff_buffer->data + 2,
- msg_length);
+ assert(ssl_read_buffer_len(s) == msg_length + 2);
+ CBS_init(&v2_client_hello, ssl_read_buffer(s) + 2, msg_length);
- /* The V2ClientHello without the length is incorporated into the Finished
+ /* The V2ClientHello without the length is incorporated into the handshake
* hash. */
- if (!ssl3_finish_mac(s, CBS_data(&v2_client_hello),
- CBS_len(&v2_client_hello))) {
+ if (!ssl3_update_handshake_hash(s, CBS_data(&v2_client_hello),
+ CBS_len(&v2_client_hello))) {
return -1;
}
if (s->msg_callback) {
@@ -729,7 +691,7 @@ int ssl3_get_v2_client_hello(SSL *s) {
!CBS_get_bytes(&v2_client_hello, &session_id, session_id_length) ||
!CBS_get_bytes(&v2_client_hello, &challenge, challenge_length) ||
CBS_len(&v2_client_hello) != 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_v2_client_hello, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
return -1;
}
@@ -747,12 +709,10 @@ int ssl3_get_v2_client_hello(SSL *s) {
rand_len);
/* Write out an equivalent SSLv3 ClientHello. */
+ CBB_zero(&client_hello);
if (!CBB_init_fixed(&client_hello, (uint8_t *)s->init_buf->data,
- s->init_buf->max)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_v2_client_hello, ERR_R_MALLOC_FAILURE);
- return -1;
- }
- if (!CBB_add_u8(&client_hello, SSL3_MT_CLIENT_HELLO) ||
+ s->init_buf->max) ||
+ !CBB_add_u8(&client_hello, SSL3_MT_CLIENT_HELLO) ||
!CBB_add_u24_length_prefixed(&client_hello, &hello_body) ||
!CBB_add_u16(&hello_body, version) ||
!CBB_add_bytes(&hello_body, random, SSL3_RANDOM_SIZE) ||
@@ -760,7 +720,7 @@ int ssl3_get_v2_client_hello(SSL *s) {
!CBB_add_u8(&hello_body, 0) ||
!CBB_add_u16_length_prefixed(&hello_body, &cipher_suites)) {
CBB_cleanup(&client_hello);
- OPENSSL_PUT_ERROR(SSL, ssl3_get_v2_client_hello, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return -1;
}
@@ -769,7 +729,7 @@ int ssl3_get_v2_client_hello(SSL *s) {
uint32_t cipher_spec;
if (!CBS_get_u24(&cipher_specs, &cipher_spec)) {
CBB_cleanup(&client_hello);
- OPENSSL_PUT_ERROR(SSL, ssl3_get_v2_client_hello, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
return -1;
}
@@ -779,7 +739,7 @@ int ssl3_get_v2_client_hello(SSL *s) {
}
if (!CBB_add_u16(&cipher_suites, cipher_spec)) {
CBB_cleanup(&client_hello);
- OPENSSL_PUT_ERROR(SSL, ssl3_get_v2_client_hello, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
}
}
@@ -788,7 +748,7 @@ int ssl3_get_v2_client_hello(SSL *s) {
if (!CBB_add_u8(&hello_body, 1) || !CBB_add_u8(&hello_body, 0) ||
!CBB_finish(&client_hello, NULL, &len)) {
CBB_cleanup(&client_hello);
- OPENSSL_PUT_ERROR(SSL, ssl3_get_v2_client_hello, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
}
@@ -798,10 +758,9 @@ int ssl3_get_v2_client_hello(SSL *s) {
/* The handshake message header is 4 bytes. */
s->s3->tmp.message_size = len - 4;
- /* Drop the sniff buffer. */
- BUF_MEM_free(s->s3->sniff_buffer);
- s->s3->sniff_buffer = NULL;
- s->s3->sniff_buffer_len = 0;
+ /* Consume and discard the V2ClientHello. */
+ ssl_read_buffer_consume(s, 2 + msg_length);
+ ssl_read_buffer_discard(s);
return 1;
}
@@ -815,6 +774,7 @@ int ssl3_get_client_hello(SSL *s) {
CBS client_hello;
uint16_t client_version;
CBS client_random, session_id, cipher_suites, compression_methods;
+ SSL_SESSION *session = NULL;
/* We do this so that we will respond with our native type. If we are TLSv1
* and we get SSLv3, we will respond with TLSv1, This down switching should
@@ -847,8 +807,7 @@ int ssl3_get_client_hello(SSL *s) {
early_ctx.client_hello_len = n;
if (!ssl_early_callback_init(&early_ctx)) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello,
- SSL_R_CLIENTHELLO_PARSE_FAILED);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
goto f_err;
}
@@ -863,8 +822,7 @@ int ssl3_get_client_hello(SSL *s) {
case -1:
/* Connection rejected. */
al = SSL_AD_ACCESS_DENIED;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello,
- SSL_R_CONNECTION_REJECTED);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
goto f_err;
default:
@@ -875,7 +833,7 @@ int ssl3_get_client_hello(SSL *s) {
break;
default:
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_UNKNOWN_STATE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE);
return -1;
}
@@ -885,7 +843,7 @@ int ssl3_get_client_hello(SSL *s) {
!CBS_get_u8_length_prefixed(&client_hello, &session_id) ||
CBS_len(&session_id) > SSL_MAX_SSL_SESSION_ID_LENGTH) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
@@ -902,7 +860,7 @@ int ssl3_get_client_hello(SSL *s) {
if (!CBS_get_u8_length_prefixed(&client_hello, &cookie) ||
CBS_len(&cookie) > DTLS1_COOKIE_LENGTH) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
}
@@ -916,7 +874,7 @@ int ssl3_get_client_hello(SSL *s) {
/* Select version to use */
uint16_t version = ssl3_get_mutual_version(s, client_version);
if (version == 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_UNSUPPORTED_PROTOCOL);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL);
s->version = s->client_version;
al = SSL_AD_PROTOCOL_VERSION;
goto f_err;
@@ -929,19 +887,23 @@ int ssl3_get_client_hello(SSL *s) {
s->s3->have_version = 1;
} else if (SSL_IS_DTLS(s) ? (s->client_version > s->version)
: (s->client_version < s->version)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_WRONG_VERSION_NUMBER);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_NUMBER);
al = SSL_AD_PROTOCOL_VERSION;
goto f_err;
}
s->hit = 0;
- int session_ret = ssl_get_prev_session(s, &early_ctx);
- if (session_ret == PENDING_SESSION) {
- s->rwstate = SSL_PENDING_SESSION;
- goto err;
- } else if (session_ret == -1) {
- goto err;
+ int send_new_ticket = 0;
+ switch (ssl_get_prev_session(s, &session, &send_new_ticket, &early_ctx)) {
+ case ssl_session_success:
+ break;
+ case ssl_session_error:
+ goto err;
+ case ssl_session_retry:
+ s->rwstate = SSL_PENDING_SESSION;
+ goto err;
}
+ s->tlsext_ticket_expected = send_new_ticket;
/* The EMS state is needed when making the resumption decision, but
* extensions are not normally parsed until later. This detects the EMS
@@ -956,34 +918,40 @@ int ssl3_get_client_hello(SSL *s) {
&ems_data, &ems_len) &&
ems_len == 0;
- if (session_ret == 1) {
- if (s->session->extended_master_secret &&
+ if (session != NULL) {
+ if (session->extended_master_secret &&
!have_extended_master_secret) {
/* A ClientHello without EMS that attempts to resume a session with EMS
* is fatal to the connection. */
al = SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello,
- SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION);
goto f_err;
}
s->hit =
/* Only resume if the session's version matches the negotiated version:
* most clients do not accept a mismatch. */
- s->version == s->session->ssl_version &&
+ s->version == session->ssl_version &&
/* If the client offers the EMS extension, but the previous session
* didn't use it, then negotiate a new session. */
- have_extended_master_secret == s->session->extended_master_secret;
+ have_extended_master_secret == session->extended_master_secret;
}
- if (!s->hit && !ssl_get_new_session(s, 1)) {
+ if (s->hit) {
+ /* Use the new session. */
+ SSL_SESSION_free(s->session);
+ s->session = session;
+ session = NULL;
+
+ s->verify_result = s->session->verify_result;
+ } else if (!ssl_get_new_session(s, 1)) {
goto err;
}
if (s->ctx->dos_protection_cb != NULL && s->ctx->dos_protection_cb(&early_ctx) == 0) {
/* Connection rejected for DOS reasons. */
al = SSL_AD_ACCESS_DENIED;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_CONNECTION_REJECTED);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
goto f_err;
}
@@ -993,7 +961,7 @@ int ssl3_get_client_hello(SSL *s) {
!CBS_get_u8_length_prefixed(&client_hello, &compression_methods) ||
CBS_len(&compression_methods) == 0) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
@@ -1020,8 +988,7 @@ int ssl3_get_client_hello(SSL *s) {
/* we need to have the cipher in the cipher list if we are asked to reuse
* it */
al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello,
- SSL_R_REQUIRED_CIPHER_MISSING);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_REQUIRED_CIPHER_MISSING);
goto f_err;
}
}
@@ -1030,15 +997,14 @@ int ssl3_get_client_hello(SSL *s) {
if (memchr(CBS_data(&compression_methods), 0,
CBS_len(&compression_methods)) == NULL) {
al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello,
- SSL_R_NO_COMPRESSION_SPECIFIED);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_COMPRESSION_SPECIFIED);
goto f_err;
}
/* TLS extensions. */
if (s->version >= SSL3_VERSION &&
!ssl_parse_clienthello_tlsext(s, &client_hello)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_PARSE_TLSEXT);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
goto err;
}
@@ -1046,13 +1012,13 @@ int ssl3_get_client_hello(SSL *s) {
if (CBS_len(&client_hello) != 0) {
/* wrong packet length */
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_BAD_PACKET_LENGTH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH);
goto f_err;
}
if (have_extended_master_secret != s->s3->tmp.extended_master_secret) {
al = SSL_AD_INTERNAL_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_EMS_STATE_INCONSISTENT);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_EMS_STATE_INCONSISTENT);
goto f_err;
}
@@ -1060,7 +1026,7 @@ int ssl3_get_client_hello(SSL *s) {
if (!s->hit) {
if (ciphers == NULL) {
al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_NO_CIPHERS_PASSED);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHERS_PASSED);
goto f_err;
}
@@ -1069,7 +1035,7 @@ int ssl3_get_client_hello(SSL *s) {
int rv = s->cert->cert_cb(s, s->cert->cert_cb_arg);
if (rv == 0) {
al = SSL_AD_INTERNAL_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_CERT_CB_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
goto f_err;
}
if (rv < 0) {
@@ -1082,7 +1048,7 @@ int ssl3_get_client_hello(SSL *s) {
if (c == NULL) {
al = SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_NO_SHARED_CIPHER);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER);
goto f_err;
}
s->s3->tmp.new_cipher = c;
@@ -1104,11 +1070,15 @@ int ssl3_get_client_hello(SSL *s) {
s->s3->tmp.cert_request = 0;
}
+ /* Now that the cipher is known, initialize the handshake hash. */
+ if (!ssl3_init_handshake_hash(s)) {
+ goto f_err;
+ }
+
/* In TLS 1.2, client authentication requires hashing the handshake transcript
* under a different hash. Otherwise, release the handshake buffer. */
- if ((!SSL_USE_SIGALGS(s) || !s->s3->tmp.cert_request) &&
- !ssl3_digest_cached_records(s, free_handshake_buffer)) {
- goto f_err;
+ if (!SSL_USE_SIGALGS(s) || !s->s3->tmp.cert_request) {
+ ssl3_free_handshake_buffer(s);
}
/* we now have the following setup;
@@ -1132,6 +1102,7 @@ int ssl3_get_client_hello(SSL *s) {
err:
sk_SSL_CIPHER_free(ciphers);
+ SSL_SESSION_free(session);
return ret;
}
@@ -1152,8 +1123,7 @@ int ssl3_send_server_hello(SSL *s) {
/* If this is a resumption and the original handshake didn't support
* ChannelID then we didn't record the original handshake hashes in the
* session and so cannot resume with ChannelIDs. */
- if (s->hit && s->s3->tlsext_channel_id_new &&
- s->session->original_handshake_hash_len == 0) {
+ if (s->hit && s->session->original_handshake_hash_len == 0) {
s->s3->tlsext_channel_id_valid = 0;
}
@@ -1167,7 +1137,7 @@ int ssl3_send_server_hello(SSL *s) {
/* Random stuff */
if (!ssl_fill_hello_random(s->s3->server_random, SSL3_RANDOM_SIZE,
1 /* server */)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_hello, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
}
memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
@@ -1191,7 +1161,7 @@ int ssl3_send_server_hello(SSL *s) {
sl = s->session->session_id_length;
if (sl > (int)sizeof(s->session->session_id)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_hello, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
}
*(p++) = sl;
@@ -1203,13 +1173,10 @@ int ssl3_send_server_hello(SSL *s) {
/* put the compression method */
*(p++) = 0;
- if (ssl_prepare_serverhello_tlsext(s) <= 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_hello, SSL_R_SERVERHELLO_TLSEXT);
- return -1;
- }
+
p = ssl_add_serverhello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH);
if (p == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_hello, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
}
@@ -1225,6 +1192,32 @@ int ssl3_send_server_hello(SSL *s) {
return ssl_do_write(s);
}
+int ssl3_send_certificate_status(SSL *ssl) {
+ if (ssl->state == SSL3_ST_SW_CERT_STATUS_A) {
+ CBB out, ocsp_response;
+ size_t length;
+
+ CBB_zero(&out);
+ if (!CBB_init_fixed(&out, ssl_handshake_start(ssl),
+ ssl->init_buf->max - SSL_HM_HEADER_LENGTH(ssl)) ||
+ !CBB_add_u8(&out, TLSEXT_STATUSTYPE_ocsp) ||
+ !CBB_add_u24_length_prefixed(&out, &ocsp_response) ||
+ !CBB_add_bytes(&ocsp_response, ssl->ctx->ocsp_response,
+ ssl->ctx->ocsp_response_length) ||
+ !CBB_finish(&out, NULL, &length) ||
+ !ssl_set_handshake_header(ssl, SSL3_MT_CERTIFICATE_STATUS, length)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ CBB_cleanup(&out);
+ return -1;
+ }
+
+ ssl->state = SSL3_ST_SW_CERT_STATUS_B;
+ }
+
+ /* SSL3_ST_SW_CERT_STATUS_B */
+ return ssl_do_write(ssl);
+}
+
int ssl3_send_server_done(SSL *s) {
if (s->state == SSL3_ST_SW_SRVR_DONE_A) {
if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_DONE, 0)) {
@@ -1246,7 +1239,8 @@ int ssl3_send_server_key_exchange(SSL *s) {
BN_CTX *bn_ctx = NULL;
const char *psk_identity_hint = NULL;
size_t psk_identity_hint_len = 0;
- EVP_PKEY *pkey;
+ size_t sig_len;
+ size_t max_sig_len;
uint8_t *p, *d;
int al, i;
uint32_t alg_k;
@@ -1254,11 +1248,26 @@ int ssl3_send_server_key_exchange(SSL *s) {
int n;
CERT *cert;
BIGNUM *r[4];
- int nr[4], kn;
+ int nr[4];
BUF_MEM *buf;
EVP_MD_CTX md_ctx;
+ if (s->state == SSL3_ST_SW_KEY_EXCH_C) {
+ return ssl_do_write(s);
+ }
+
+ if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) {
+ if (!ssl_has_private_key(s)) {
+ al = SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ max_sig_len = ssl_private_key_max_signature_len(s);
+ } else {
+ max_sig_len = 0;
+ }
+
EVP_MD_CTX_init(&md_ctx);
+ enum ssl_private_key_result_t sign_result;
if (s->state == SSL3_ST_SW_KEY_EXCH_A) {
alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
alg_a = s->s3->tmp.new_cipher->algorithm_auth;
@@ -1286,25 +1295,23 @@ int ssl3_send_server_key_exchange(SSL *s) {
}
if (dhp == NULL) {
al = SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange,
- SSL_R_MISSING_TMP_DH_KEY);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_TMP_DH_KEY);
goto f_err;
}
if (s->s3->tmp.dh != NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange,
- ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, 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);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB);
goto err;
}
s->s3->tmp.dh = dh;
if (!DH_generate_key(dh)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_DH_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB);
goto err;
}
@@ -1328,14 +1335,12 @@ int ssl3_send_server_key_exchange(SSL *s) {
}
if (nid == NID_undef) {
al = SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange,
- SSL_R_MISSING_TMP_ECDH_KEY);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_TMP_ECDH_KEY);
goto f_err;
}
if (s->s3->tmp.ecdh != NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange,
- ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;
}
ecdh = EC_KEY_new_by_curve_name(nid);
@@ -1345,15 +1350,14 @@ int ssl3_send_server_key_exchange(SSL *s) {
s->s3->tmp.ecdh = ecdh;
if (!EC_KEY_generate_key(ecdh)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_ECDH_LIB);
+ OPENSSL_PUT_ERROR(SSL, 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);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
goto err;
}
@@ -1366,8 +1370,7 @@ int ssl3_send_server_key_exchange(SSL *s) {
encodedPoint = (uint8_t *)OPENSSL_malloc(encodedlen * sizeof(uint8_t));
bn_ctx = BN_CTX_new();
if (encodedPoint == NULL || bn_ctx == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -1376,7 +1379,7 @@ int ssl3_send_server_key_exchange(SSL *s) {
encodedPoint, encodedlen, bn_ctx);
if (encodedlen == 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_ECDH_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ECDH_LIB);
goto err;
}
@@ -1396,8 +1399,7 @@ int ssl3_send_server_key_exchange(SSL *s) {
r[3] = NULL;
} else if (!(alg_k & SSL_kPSK)) {
al = SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange,
- SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
goto f_err;
}
@@ -1406,20 +1408,8 @@ int ssl3_send_server_key_exchange(SSL *s) {
n += 2 + nr[i];
}
- if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) {
- pkey = ssl_get_sign_pkey(s, s->s3->tmp.new_cipher);
- if (pkey == NULL) {
- al = SSL_AD_DECODE_ERROR;
- goto f_err;
- }
- kn = EVP_PKEY_size(pkey);
- } else {
- pkey = NULL;
- kn = 0;
- }
-
- if (!BUF_MEM_grow_clean(buf, n + SSL_HM_HEADER_LENGTH(s) + kn)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_LIB_BUF);
+ if (!BUF_MEM_grow_clean(buf, n + SSL_HM_HEADER_LENGTH(s) + max_sig_len)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_LIB_BUF);
goto err;
}
d = p = ssl_handshake_start(s);
@@ -1458,54 +1448,81 @@ int ssl3_send_server_key_exchange(SSL *s) {
encodedPoint = NULL;
}
- /* not anonymous */
- if (pkey != NULL) {
- /* n is the length of the params, they start at &(d[4]) and p points to
+ if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) {
+ /* n is the length of the params, they start at d and p points to
* the space at the end. */
const EVP_MD *md;
- size_t sig_len = EVP_PKEY_size(pkey);
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ unsigned int digest_length;
+
+ const int pkey_type = ssl_private_key_type(s);
/* Determine signature algorithm. */
if (SSL_USE_SIGALGS(s)) {
- md = tls1_choose_signing_digest(s, pkey);
- if (!tls12_get_sigandhash(p, pkey, md)) {
+ md = tls1_choose_signing_digest(s);
+ if (!tls12_get_sigandhash(s, p, md)) {
/* Should never happen */
al = SSL_AD_INTERNAL_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange,
- ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto f_err;
}
p += 2;
- } else if (pkey->type == EVP_PKEY_RSA) {
+ } else if (pkey_type == EVP_PKEY_RSA) {
md = EVP_md5_sha1();
} else {
md = EVP_sha1();
}
- if (!EVP_DigestSignInit(&md_ctx, NULL, md, NULL, pkey) ||
- !EVP_DigestSignUpdate(&md_ctx, s->s3->client_random,
- SSL3_RANDOM_SIZE) ||
- !EVP_DigestSignUpdate(&md_ctx, s->s3->server_random,
- SSL3_RANDOM_SIZE) ||
- !EVP_DigestSignUpdate(&md_ctx, d, n) ||
- !EVP_DigestSignFinal(&md_ctx, &p[2], &sig_len)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_LIB_EVP);
+ if (!EVP_DigestInit_ex(&md_ctx, md, NULL) ||
+ !EVP_DigestUpdate(&md_ctx, s->s3->client_random, SSL3_RANDOM_SIZE) ||
+ !EVP_DigestUpdate(&md_ctx, s->s3->server_random, SSL3_RANDOM_SIZE) ||
+ !EVP_DigestUpdate(&md_ctx, d, n) ||
+ !EVP_DigestFinal_ex(&md_ctx, digest, &digest_length)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
goto err;
}
- s2n(sig_len, p);
- n += sig_len + 2;
- if (SSL_USE_SIGALGS(s)) {
- n += 2;
- }
+ sign_result = ssl_private_key_sign(s, &p[2], &sig_len, max_sig_len,
+ EVP_MD_CTX_md(&md_ctx), digest,
+ digest_length);
+ } else {
+ /* This key exchange doesn't involve a signature. */
+ sign_result = ssl_private_key_success;
+ sig_len = 0;
}
+ } else {
+ assert(s->state == SSL3_ST_SW_KEY_EXCH_B);
+ /* Restore |p|. */
+ p = ssl_handshake_start(s) + s->init_num - SSL_HM_HEADER_LENGTH(s);
+ sign_result = ssl_private_key_sign_complete(s, &p[2], &sig_len,
+ max_sig_len);
+ }
- if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE, n)) {
+ switch (sign_result) {
+ case ssl_private_key_success:
+ s->rwstate = SSL_NOTHING;
+ break;
+ case ssl_private_key_failure:
+ s->rwstate = SSL_NOTHING;
+ goto err;
+ case ssl_private_key_retry:
+ s->rwstate = SSL_PRIVATE_KEY_OPERATION;
+ /* Stash away |p|. */
+ s->init_num = p - ssl_handshake_start(s) + SSL_HM_HEADER_LENGTH(s);
+ s->state = SSL3_ST_SW_KEY_EXCH_B;
goto err;
- }
}
- s->state = SSL3_ST_SW_KEY_EXCH_B;
+ if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) {
+ s2n(sig_len, p);
+ p += sig_len;
+ }
+ if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE,
+ p - ssl_handshake_start(s))) {
+ goto err;
+ }
+ s->state = SSL3_ST_SW_KEY_EXCH_C;
+
EVP_MD_CTX_cleanup(&md_ctx);
return ssl_do_write(s);
@@ -1558,7 +1575,7 @@ int ssl3_send_certificate_request(SSL *s) {
name = sk_X509_NAME_value(sk, i);
j = i2d_X509_NAME(name, NULL);
if (!BUF_MEM_grow_clean(buf, SSL_HM_HEADER_LENGTH(s) + n + j + 2)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_certificate_request, ERR_R_BUF_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
goto err;
}
p = ssl_handshake_start(s) + n;
@@ -1629,30 +1646,27 @@ int ssl3_get_client_key_exchange(SSL *s) {
* then this is the only field in the message. */
if (!CBS_get_u16_length_prefixed(&client_key_exchange, &psk_identity) ||
((alg_k & SSL_kPSK) && CBS_len(&client_key_exchange) != 0)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
al = SSL_AD_DECODE_ERROR;
goto f_err;
}
if (s->psk_server_callback == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- SSL_R_PSK_NO_SERVER_CB);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_NO_SERVER_CB);
al = SSL_AD_INTERNAL_ERROR;
goto f_err;
}
if (CBS_len(&psk_identity) > PSK_MAX_IDENTITY_LEN ||
CBS_contains_zero_byte(&psk_identity)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- SSL_R_DATA_LENGTH_TOO_LONG);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
al = SSL_AD_ILLEGAL_PARAMETER;
goto f_err;
}
if (!CBS_strdup(&psk_identity, &s->session->psk_identity)) {
al = SSL_AD_INTERNAL_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto f_err;
}
@@ -1660,14 +1674,12 @@ int ssl3_get_client_key_exchange(SSL *s) {
psk_len =
s->psk_server_callback(s, s->session->psk_identity, psk, sizeof(psk));
if (psk_len > PSK_MAX_PSK_LEN) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
al = SSL_AD_INTERNAL_ERROR;
goto f_err;
} else if (psk_len == 0) {
/* PSK related to the given identity not found */
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- SSL_R_PSK_IDENTITY_NOT_FOUND);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND);
al = SSL_AD_UNKNOWN_PSK_IDENTITY;
goto f_err;
}
@@ -1681,11 +1693,10 @@ int ssl3_get_client_key_exchange(SSL *s) {
uint8_t good;
size_t rsa_size, decrypt_len, premaster_index, j;
- pkey = s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey;
+ pkey = s->cert->privatekey;
if (pkey == NULL || pkey->type != EVP_PKEY_RSA || pkey->pkey.rsa == NULL) {
al = SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- SSL_R_MISSING_RSA_CERTIFICATE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_RSA_CERTIFICATE);
goto f_err;
}
rsa = pkey->pkey.rsa;
@@ -1698,8 +1709,7 @@ int ssl3_get_client_key_exchange(SSL *s) {
CBS_len(&client_key_exchange) != 0) {
if (!(s->options & SSL_OP_TLS_D5_BUG)) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG);
goto f_err;
} else {
encrypted_premaster_secret = copy;
@@ -1716,8 +1726,7 @@ int ssl3_get_client_key_exchange(SSL *s) {
rsa_size = RSA_size(rsa);
if (rsa_size < SSL_MAX_MASTER_KEY_LENGTH) {
al = SSL_AD_DECRYPT_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- SSL_R_DECRYPTION_FAILED);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED);
goto f_err;
}
@@ -1733,8 +1742,7 @@ int ssl3_get_client_key_exchange(SSL *s) {
/* Allocate a buffer large enough for an RSA decryption. */
decrypt_buf = OPENSSL_malloc(rsa_size);
if (decrypt_buf == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -1748,8 +1756,7 @@ int ssl3_get_client_key_exchange(SSL *s) {
if (decrypt_len != rsa_size) {
/* This should never happen, but do a check so we do not read
* uninitialized memory. */
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;
}
@@ -1772,8 +1779,7 @@ int ssl3_get_client_key_exchange(SSL *s) {
BUF_memdup(decrypt_buf + (rsa_size - SSL_MAX_MASTER_KEY_LENGTH),
SSL_MAX_MASTER_KEY_LENGTH);
if (premaster_secret == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
OPENSSL_free(decrypt_buf);
@@ -1804,38 +1810,35 @@ int ssl3_get_client_key_exchange(SSL *s) {
if (!CBS_get_u16_length_prefixed(&client_key_exchange, &dh_Yc) ||
CBS_len(&dh_Yc) == 0 || CBS_len(&client_key_exchange) != 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
al = SSL_R_DECODE_ERROR;
goto f_err;
}
if (s->s3->tmp.dh == NULL) {
al = SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- SSL_R_MISSING_TMP_DH_KEY);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_TMP_DH_KEY);
goto f_err;
}
dh_srvr = s->s3->tmp.dh;
pub = BN_bin2bn(CBS_data(&dh_Yc), CBS_len(&dh_Yc), NULL);
if (pub == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_BN_LIB);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BN_LIB);
goto err;
}
/* Allocate a buffer for the premaster secret. */
premaster_secret = OPENSSL_malloc(DH_size(dh_srvr));
if (premaster_secret == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
BN_clear_free(pub);
goto err;
}
dh_len = DH_compute_key(premaster_secret, pub, dh_srvr);
if (dh_len <= 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_DH_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB);
BN_clear_free(pub);
goto err;
}
@@ -1856,8 +1859,7 @@ int ssl3_get_client_key_exchange(SSL *s) {
/* initialize structures for server's ECDH key pair */
srvr_ecdh = EC_KEY_new();
if (srvr_ecdh == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -1870,15 +1872,14 @@ int ssl3_get_client_key_exchange(SSL *s) {
if (!EC_KEY_set_group(srvr_ecdh, group) ||
!EC_KEY_set_private_key(srvr_ecdh, priv_key)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_EC_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_EC_LIB);
goto err;
}
/* Let's get client's public key */
clnt_ecpoint = EC_POINT_new(group);
if (clnt_ecpoint == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -1887,35 +1888,33 @@ int ssl3_get_client_key_exchange(SSL *s) {
if (!CBS_get_u8_length_prefixed(&client_key_exchange, &ecdh_Yc) ||
CBS_len(&client_key_exchange) != 0) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
bn_ctx = BN_CTX_new();
if (bn_ctx == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!EC_POINT_oct2point(group, clnt_ecpoint, CBS_data(&ecdh_Yc),
CBS_len(&ecdh_Yc), bn_ctx)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_EC_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_EC_LIB);
goto err;
}
/* Allocate a buffer for both the secret and the PSK. */
field_size = EC_GROUP_get_degree(group);
if (field_size <= 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_ECDH_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ECDH_LIB);
goto err;
}
ecdh_len = (field_size + 7) / 8;
premaster_secret = OPENSSL_malloc(ecdh_len);
if (premaster_secret == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -1923,7 +1922,7 @@ int ssl3_get_client_key_exchange(SSL *s) {
ecdh_len = ECDH_compute_key(premaster_secret, ecdh_len, clnt_ecpoint,
srvr_ecdh, NULL);
if (ecdh_len <= 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_ECDH_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ECDH_LIB);
goto err;
}
@@ -1945,15 +1944,13 @@ int ssl3_get_client_key_exchange(SSL *s) {
premaster_secret_len = psk_len;
premaster_secret = OPENSSL_malloc(premaster_secret_len);
if (premaster_secret == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
memset(premaster_secret, 0, premaster_secret_len);
} else {
al = SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- SSL_R_UNKNOWN_CIPHER_TYPE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_TYPE);
goto f_err;
}
@@ -1964,18 +1961,14 @@ int ssl3_get_client_key_exchange(SSL *s) {
uint8_t *new_data;
size_t new_len;
- if (!CBB_init(&new_premaster, 2 + psk_len + 2 + premaster_secret_len)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
- if (!CBB_add_u16_length_prefixed(&new_premaster, &child) ||
+ CBB_zero(&new_premaster);
+ if (!CBB_init(&new_premaster, 2 + psk_len + 2 + premaster_secret_len) ||
+ !CBB_add_u16_length_prefixed(&new_premaster, &child) ||
!CBB_add_bytes(&child, premaster_secret, premaster_secret_len) ||
!CBB_add_u16_length_prefixed(&new_premaster, &child) ||
!CBB_add_bytes(&child, psk, psk_len) ||
!CBB_finish(&new_premaster, &new_data, &new_len)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
- ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
CBB_cleanup(&new_premaster);
goto err;
}
@@ -2031,10 +2024,7 @@ int ssl3_get_cert_verify(SSL *s) {
* CertificateVerify is required if and only if there's a client certificate.
* */
if (peer == NULL) {
- if (s->s3->handshake_buffer &&
- !ssl3_digest_cached_records(s, free_handshake_buffer)) {
- return -1;
- }
+ ssl3_free_handshake_buffer(s);
return 1;
}
@@ -2055,8 +2045,7 @@ int ssl3_get_cert_verify(SSL *s) {
if (!(X509_certificate_type(peer, pkey) & EVP_PKT_SIGN) ||
(pkey->type != EVP_PKEY_RSA && pkey->type != EVP_PKEY_EC)) {
al = SSL_AD_UNSUPPORTED_CERTIFICATE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify,
- SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);
goto f_err;
}
@@ -2069,16 +2058,13 @@ int ssl3_get_cert_verify(SSL *s) {
}
/* Compute the digest. */
- if (!ssl3_cert_verify_hash(s, digest, &digest_length, &md, pkey)) {
+ if (!ssl3_cert_verify_hash(s, digest, &digest_length, &md, pkey->type)) {
goto err;
}
/* The handshake buffer is no longer necessary, and we may hash the current
* message.*/
- if (s->s3->handshake_buffer &&
- !ssl3_digest_cached_records(s, free_handshake_buffer)) {
- goto err;
- }
+ ssl3_free_handshake_buffer(s);
if (!ssl3_hash_current_message(s)) {
goto err;
}
@@ -2087,7 +2073,7 @@ int ssl3_get_cert_verify(SSL *s) {
if (!CBS_get_u16_length_prefixed(&certificate_verify, &signature) ||
CBS_len(&certificate_verify) != 0) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
@@ -2100,7 +2086,7 @@ int ssl3_get_cert_verify(SSL *s) {
!EVP_PKEY_verify(pctx, CBS_data(&signature), CBS_len(&signature), digest,
digest_length)) {
al = SSL_AD_DECRYPT_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_SIGNATURE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE);
goto f_err;
}
@@ -2137,15 +2123,14 @@ int ssl3_get_client_certificate(SSL *s) {
if (s->s3->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE) {
if ((s->verify_mode & SSL_VERIFY_PEER) &&
(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate,
- SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
al = SSL_AD_HANDSHAKE_FAILURE;
goto f_err;
}
/* If tls asked for a client cert, the client must return a 0 list */
if (s->version > SSL3_VERSION && s->s3->tmp.cert_request) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate,
+ OPENSSL_PUT_ERROR(SSL,
SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST);
al = SSL_AD_UNEXPECTED_MESSAGE;
goto f_err;
@@ -2157,8 +2142,7 @@ int ssl3_get_client_certificate(SSL *s) {
if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE) {
al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate,
- SSL_R_WRONG_MESSAGE_TYPE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_MESSAGE_TYPE);
goto f_err;
}
@@ -2166,14 +2150,14 @@ int ssl3_get_client_certificate(SSL *s) {
sk = sk_X509_new_null();
if (sk == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!CBS_get_u24_length_prefixed(&certificate_msg, &certificate_list) ||
CBS_len(&certificate_msg) != 0) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
@@ -2183,7 +2167,7 @@ int ssl3_get_client_certificate(SSL *s) {
if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate)) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
@@ -2201,50 +2185,42 @@ int ssl3_get_client_certificate(SSL *s) {
x = d2i_X509(NULL, &data, CBS_len(&certificate));
if (x == NULL) {
al = SSL_AD_BAD_CERTIFICATE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, ERR_R_ASN1_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB);
goto f_err;
}
if (data != CBS_data(&certificate) + CBS_len(&certificate)) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate,
- SSL_R_CERT_LENGTH_MISMATCH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
goto f_err;
}
if (!sk_X509_push(sk, x)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
x = NULL;
}
if (sk_X509_num(sk) <= 0) {
+ /* No client certificate so the handshake buffer may be discarded. */
+ ssl3_free_handshake_buffer(s);
+
/* TLS does not mind 0 certs returned */
if (s->version == SSL3_VERSION) {
al = SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate,
- SSL_R_NO_CERTIFICATES_RETURNED);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATES_RETURNED);
goto f_err;
- }
- /* Fail for TLS only if we required a certificate */
- else if ((s->verify_mode & SSL_VERIFY_PEER) &&
+ } else if ((s->verify_mode & SSL_VERIFY_PEER) &&
(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate,
- SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+ /* Fail for TLS only if we required a certificate */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
al = SSL_AD_HANDSHAKE_FAILURE;
goto f_err;
}
- /* No client certificate so digest cached records */
- if (s->s3->handshake_buffer &&
- !ssl3_digest_cached_records(s, free_handshake_buffer)) {
- al = SSL_AD_INTERNAL_ERROR;
- goto f_err;
- }
} else {
i = ssl_verify_cert_chain(s, sk);
if (i <= 0) {
al = ssl_verify_alarm_type(s->verify_result);
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate,
- SSL_R_CERTIFICATE_VERIFY_FAILED);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED);
goto f_err;
}
}
@@ -2253,17 +2229,8 @@ int ssl3_get_client_certificate(SSL *s) {
s->session->peer = sk_X509_shift(sk);
s->session->verify_result = s->verify_result;
- /* With the current implementation, sess_cert will always be NULL when we
- * arrive here. */
- if (s->session->sess_cert == NULL) {
- s->session->sess_cert = ssl_sess_cert_new();
- if (s->session->sess_cert == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- }
- sk_X509_pop_free(s->session->sess_cert->cert_chain, X509_free);
- s->session->sess_cert->cert_chain = sk;
+ sk_X509_pop_free(s->session->cert_chain, X509_free);
+ s->session->cert_chain = sk;
/* Inconsistency alert: cert_chain does *not* include the peer's own
* certificate, while we do include it in s3_clnt.c */
@@ -2283,17 +2250,8 @@ err:
}
int ssl3_send_server_certificate(SSL *s) {
- CERT_PKEY *cpk;
-
if (s->state == SSL3_ST_SW_CERT_A) {
- cpk = ssl_get_server_send_pkey(s);
- if (cpk == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_certificate,
- ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- if (!ssl3_output_cert_chain(s, cpk)) {
+ if (!ssl3_output_cert_chain(s)) {
return 0;
}
s->state = SSL3_ST_SW_CERT_B;
@@ -2444,8 +2402,7 @@ int ssl3_get_next_proto(SSL *s) {
/* Clients cannot send a NextProtocol message if we didn't see the extension
* in their ClientHello */
if (!s->s3->next_proto_neg_seen) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_next_proto,
- SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION);
return -1;
}
@@ -2465,8 +2422,7 @@ int ssl3_get_next_proto(SSL *s) {
* TODO(davidben): Is this check now redundant with
* SSL3_FLAGS_EXPECT_CCS? */
if (!s->s3->change_cipher_spec) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_next_proto,
- SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS);
return -1;
}
@@ -2492,11 +2448,10 @@ int ssl3_get_next_proto(SSL *s) {
int ssl3_get_channel_id(SSL *s) {
int ret = -1, ok;
long n;
- EVP_MD_CTX md_ctx;
- uint8_t channel_id_hash[SHA256_DIGEST_LENGTH];
- unsigned int channel_id_hash_len;
+ uint8_t channel_id_hash[EVP_MAX_MD_SIZE];
+ size_t channel_id_hash_len;
const uint8_t *p;
- uint16_t extension_type, expected_extension_type;
+ uint16_t extension_type;
EC_GROUP *p256 = NULL;
EC_KEY *key = NULL;
EC_POINT *point = NULL;
@@ -2515,15 +2470,9 @@ int ssl3_get_channel_id(SSL *s) {
/* Before incorporating the EncryptedExtensions message to the handshake
* hash, compute the hash that should have been signed. */
- channel_id_hash_len = sizeof(channel_id_hash);
- EVP_MD_CTX_init(&md_ctx);
- if (!EVP_DigestInit_ex(&md_ctx, EVP_sha256(), NULL) ||
- !tls1_channel_id_hash(&md_ctx, s) ||
- !EVP_DigestFinal(&md_ctx, channel_id_hash, &channel_id_hash_len)) {
- EVP_MD_CTX_cleanup(&md_ctx);
+ if (!tls1_channel_id_hash(s, channel_id_hash, &channel_id_hash_len)) {
return -1;
}
- EVP_MD_CTX_cleanup(&md_ctx);
assert(channel_id_hash_len == SHA256_DIGEST_LENGTH);
if (!ssl3_hash_current_message(s)) {
@@ -2536,8 +2485,7 @@ int ssl3_get_channel_id(SSL *s) {
*
* TODO(davidben): Is this check now redundant with SSL3_FLAGS_EXPECT_CCS? */
if (!s->s3->change_cipher_spec) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_channel_id,
- SSL_R_GOT_CHANNEL_ID_BEFORE_A_CCS);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_GOT_CHANNEL_ID_BEFORE_A_CCS);
return -1;
}
@@ -2554,23 +2502,19 @@ int ssl3_get_channel_id(SSL *s) {
* uint8 y[32];
* uint8 r[32];
* uint8 s[32]; */
- expected_extension_type = TLSEXT_TYPE_channel_id;
- if (s->s3->tlsext_channel_id_new) {
- expected_extension_type = TLSEXT_TYPE_channel_id_new;
- }
if (!CBS_get_u16(&encrypted_extensions, &extension_type) ||
!CBS_get_u16_length_prefixed(&encrypted_extensions, &extension) ||
CBS_len(&encrypted_extensions) != 0 ||
- extension_type != expected_extension_type ||
+ extension_type != TLSEXT_TYPE_channel_id ||
CBS_len(&extension) != TLSEXT_CHANNEL_ID_SIZE) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_channel_id, SSL_R_INVALID_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_MESSAGE);
return -1;
}
p256 = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
if (!p256) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_channel_id, SSL_R_NO_P256_SUPPORT);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_P256_SUPPORT);
return -1;
}
@@ -2604,8 +2548,7 @@ int ssl3_get_channel_id(SSL *s) {
/* We stored the handshake hash in |tlsext_channel_id| the first time that we
* were called. */
if (!ECDSA_do_verify(channel_id_hash, channel_id_hash_len, &sig, key)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_channel_id,
- SSL_R_CHANNEL_ID_SIGNATURE_INVALID);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_SIGNATURE_INVALID);
s->s3->tlsext_channel_id_valid = 0;
goto err;
}
diff --git a/src/ssl/ssl_aead_ctx.c b/src/ssl/ssl_aead_ctx.c
index c2fba1d..f9001c7 100644
--- a/src/ssl/ssl_aead_ctx.c
+++ b/src/ssl/ssl_aead_ctx.c
@@ -12,6 +12,8 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#include <openssl/ssl.h>
+
#include <assert.h>
#include <string.h>
@@ -34,7 +36,7 @@ SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction,
const EVP_AEAD *aead;
size_t discard;
if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard, cipher, version)) {
- OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_new, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
@@ -43,7 +45,7 @@ SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction,
/* This is a "stateful" AEAD (for compatibility with pre-AEAD cipher
* suites). */
if (mac_key_len + enc_key_len + fixed_iv_len > sizeof(merged_key)) {
- OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_new, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
memcpy(merged_key, mac_key, mac_key_len);
@@ -56,7 +58,7 @@ SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction,
SSL_AEAD_CTX *aead_ctx = (SSL_AEAD_CTX *)OPENSSL_malloc(sizeof(SSL_AEAD_CTX));
if (aead_ctx == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_new, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return NULL;
}
memset(aead_ctx, 0, sizeof(SSL_AEAD_CTX));
@@ -76,16 +78,17 @@ SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction,
if (fixed_iv_len > sizeof(aead_ctx->fixed_nonce) ||
fixed_iv_len > aead_ctx->variable_nonce_len) {
SSL_AEAD_CTX_free(aead_ctx);
- OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_new, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
aead_ctx->variable_nonce_len -= fixed_iv_len;
memcpy(aead_ctx->fixed_nonce, fixed_iv, fixed_iv_len);
aead_ctx->fixed_nonce_len = fixed_iv_len;
- aead_ctx->variable_nonce_included_in_record =
- (cipher->algorithm2 &
- SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD) != 0;
+ /* AES-GCM uses an explicit nonce. */
+ if (cipher->algorithm_enc & (SSL_AES128GCM | SSL_AES256GCM)) {
+ aead_ctx->variable_nonce_included_in_record = 1;
+ }
} else {
aead_ctx->variable_nonce_included_in_record = 1;
aead_ctx->random_variable_nonce = 1;
@@ -146,7 +149,7 @@ int SSL_AEAD_CTX_open(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len,
if (aead == NULL) {
/* Handle the initial NULL cipher. */
if (in_len > max_out) {
- OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_open, SSL_R_BUFFER_TOO_SMALL);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
return 0;
}
memmove(out, in, in_len);
@@ -161,7 +164,7 @@ int SSL_AEAD_CTX_open(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len,
size_t overhead = SSL_AEAD_CTX_max_overhead(aead);
if (in_len < overhead) {
/* Publicly invalid. */
- OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_open, SSL_R_BAD_PACKET_LENGTH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH);
return 0;
}
plaintext_len = in_len - overhead;
@@ -178,7 +181,7 @@ int SSL_AEAD_CTX_open(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len,
if (aead->variable_nonce_included_in_record) {
if (in_len < aead->variable_nonce_len) {
/* Publicly invalid. */
- OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_open, SSL_R_BAD_PACKET_LENGTH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH);
return 0;
}
memcpy(nonce + nonce_len, in, aead->variable_nonce_len);
@@ -201,7 +204,7 @@ int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len,
if (aead == NULL) {
/* Handle the initial NULL cipher. */
if (in_len > max_out) {
- OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_seal, SSL_R_BUFFER_TOO_SMALL);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
return 0;
}
memmove(out, in, in_len);
@@ -235,11 +238,11 @@ int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len,
size_t extra_len = 0;
if (aead->variable_nonce_included_in_record) {
if (max_out < aead->variable_nonce_len) {
- OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_seal, SSL_R_BUFFER_TOO_SMALL);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
return 0;
}
if (out < in + in_len && in < out + aead->variable_nonce_len) {
- OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_seal, SSL_R_OUTPUT_ALIASES_INPUT);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
return 0;
}
memcpy(out, nonce + aead->fixed_nonce_len, aead->variable_nonce_len);
diff --git a/src/ssl/ssl_algs.c b/src/ssl/ssl_algs.c
deleted file mode 100644
index fda39a5..0000000
--- a/src/ssl/ssl_algs.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.] */
-
-#include "internal.h"
-
-#include <openssl/crypto.h>
-
-int SSL_library_init(void) {
- CRYPTO_library_init();
- return 1;
-}
-
-void SSL_load_error_strings(void) {}
diff --git a/src/ssl/ssl_asn1.c b/src/ssl/ssl_asn1.c
index 76052df..0d4760d 100644
--- a/src/ssl/ssl_asn1.c
+++ b/src/ssl/ssl_asn1.c
@@ -80,6 +80,8 @@
* OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
* OTHERWISE. */
+#include <openssl/ssl.h>
+
#include <limits.h>
#include <string.h>
@@ -114,8 +116,10 @@
* signedCertTimestampList [15] OCTET STRING OPTIONAL,
* -- contents of SCT extension
* ocspResponse [16] OCTET STRING OPTIONAL,
- * -- stapled OCSP response from the server
+ * -- stapled OCSP response from the server
* extendedMasterSecret [17] BOOLEAN OPTIONAL,
+ * keyExchangeInfo [18] INTEGER OPTIONAL,
+ * certChain [19] SEQUENCE OF Certificate OPTIONAL,
* }
*
* Note: historically this serialization has included other optional
@@ -154,8 +158,28 @@ static const int kOCSPResponseTag =
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 16;
static const int kExtendedMasterSecretTag =
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 17;
+static const int kKeyExchangeInfoTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 18;
+static const int kCertChainTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 19;
+
+static int add_X509(CBB *cbb, X509 *x509) {
+ int len = i2d_X509(x509, NULL);
+ if (len < 0) {
+ return 0;
+ }
+ uint8_t *buf;
+ if (!CBB_add_space(cbb, &buf, len)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ if (buf != NULL && i2d_X509(x509, &buf) < 0) {
+ return 0;
+ }
+ return 1;
+}
-static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
+static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data,
size_t *out_len, int for_ticket) {
CBB cbb, session, child, child2;
@@ -163,11 +187,9 @@ static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
return 0;
}
- if (!CBB_init(&cbb, 0)) {
- return 0;
- }
-
- if (!CBB_add_asn1(&cbb, &session, CBS_ASN1_SEQUENCE) ||
+ CBB_zero(&cbb);
+ if (!CBB_init(&cbb, 0) ||
+ !CBB_add_asn1(&cbb, &session, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1_uint64(&session, SSL_SESSION_ASN1_VERSION) ||
!CBB_add_asn1_uint64(&session, in->ssl_version) ||
!CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
@@ -178,14 +200,14 @@ static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
for_ticket ? 0 : in->session_id_length) ||
!CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
!CBB_add_bytes(&child, in->master_key, in->master_key_length)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, 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, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}
@@ -193,7 +215,7 @@ static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
if (in->timeout != 0) {
if (!CBB_add_asn1(&session, &child, kTimeoutTag) ||
!CBB_add_asn1_uint64(&child, in->timeout)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}
@@ -201,17 +223,11 @@ static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
/* The peer certificate is only serialized if the SHA-256 isn't
* serialized instead. */
if (in->peer && !in->peer_sha256_valid) {
- uint8_t *buf;
- int len = i2d_X509(in->peer, NULL);
- if (len < 0) {
- goto err;
- }
- if (!CBB_add_asn1(&session, &child, kPeerTag) ||
- !CBB_add_space(&child, &buf, len)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE);
+ if (!CBB_add_asn1(&session, &child, kPeerTag)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
- if (buf != NULL && i2d_X509(in->peer, &buf) < 0) {
+ if (!add_X509(&child, in->peer)) {
goto err;
}
}
@@ -221,14 +237,14 @@ static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
if (!CBB_add_asn1(&session, &child, kSessionIDContextTag) ||
!CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
!CBB_add_bytes(&child2, in->sid_ctx, in->sid_ctx_length)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, 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, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}
@@ -238,7 +254,7 @@ static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
!CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
!CBB_add_bytes(&child2, (const uint8_t *)in->tlsext_hostname,
strlen(in->tlsext_hostname))) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}
@@ -248,7 +264,7 @@ static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
!CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
!CBB_add_bytes(&child2, (const uint8_t *)in->psk_identity,
strlen(in->psk_identity))) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}
@@ -256,7 +272,7 @@ static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
if (in->tlsext_tick_lifetime_hint > 0) {
if (!CBB_add_asn1(&session, &child, kTicketLifetimeHintTag) ||
!CBB_add_asn1_uint64(&child, in->tlsext_tick_lifetime_hint)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}
@@ -265,7 +281,7 @@ static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
if (!CBB_add_asn1(&session, &child, kTicketTag) ||
!CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
!CBB_add_bytes(&child2, in->tlsext_tick, in->tlsext_ticklen)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}
@@ -274,7 +290,7 @@ static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
if (!CBB_add_asn1(&session, &child, kPeerSHA256Tag) ||
!CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
!CBB_add_bytes(&child2, in->peer_sha256, sizeof(in->peer_sha256))) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}
@@ -284,7 +300,7 @@ static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
!CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
!CBB_add_bytes(&child2, in->original_handshake_hash,
in->original_handshake_hash_len)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}
@@ -294,7 +310,7 @@ static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
!CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
!CBB_add_bytes(&child2, in->tlsext_signed_cert_timestamp_list,
in->tlsext_signed_cert_timestamp_list_length)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}
@@ -303,7 +319,7 @@ static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
if (!CBB_add_asn1(&session, &child, kOCSPResponseTag) ||
!CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
!CBB_add_bytes(&child2, in->ocsp_response, in->ocsp_response_length)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}
@@ -312,13 +328,35 @@ static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
if (!CBB_add_asn1(&session, &child, kExtendedMasterSecretTag) ||
!CBB_add_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
!CBB_add_u8(&child2, 0xff)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}
+ if (in->key_exchange_info > 0 &&
+ (!CBB_add_asn1(&session, &child, kKeyExchangeInfoTag) ||
+ !CBB_add_asn1_uint64(&child, in->key_exchange_info))) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* The certificate chain is only serialized if the leaf's SHA-256 isn't
+ * serialized instead. */
+ if (in->cert_chain != NULL && !in->peer_sha256_valid) {
+ if (!CBB_add_asn1(&session, &child, kCertChainTag)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ size_t i;
+ for (i = 0; i < sk_X509_num(in->cert_chain); i++) {
+ if (!add_X509(&child, sk_X509_value(in->cert_chain, i))) {
+ goto err;
+ }
+ }
+ }
+
if (!CBB_finish(&cbb, out_data, out_len)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_to_bytes_full, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
return 1;
@@ -328,11 +366,12 @@ static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
return 0;
}
-int SSL_SESSION_to_bytes(SSL_SESSION *in, uint8_t **out_data, size_t *out_len) {
+int SSL_SESSION_to_bytes(const SSL_SESSION *in, uint8_t **out_data,
+ size_t *out_len) {
return SSL_SESSION_to_bytes_full(in, out_data, out_len, 0);
}
-int SSL_SESSION_to_bytes_for_ticket(SSL_SESSION *in, uint8_t **out_data,
+int SSL_SESSION_to_bytes_for_ticket(const SSL_SESSION *in, uint8_t **out_data,
size_t *out_len) {
return SSL_SESSION_to_bytes_full(in, out_data, out_len, 1);
}
@@ -347,7 +386,7 @@ int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp) {
if (len > INT_MAX) {
OPENSSL_free(out);
- OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_OVERFLOW);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
return -1;
}
@@ -370,17 +409,16 @@ static int SSL_SESSION_parse_string(CBS *cbs, char **out, unsigned tag) {
CBS value;
int present;
if (!CBS_get_optional_asn1_octet_string(cbs, &value, &present, tag)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse_string, SSL_R_INVALID_SSL_SESSION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
return 0;
}
if (present) {
if (CBS_contains_zero_byte(&value)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse_string,
- SSL_R_INVALID_SSL_SESSION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
return 0;
}
if (!CBS_strdup(&value, out)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse_string, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return 0;
}
} else {
@@ -397,170 +435,168 @@ static int SSL_SESSION_parse_string(CBS *cbs, char **out, unsigned tag) {
* |*out_ptr| to NULL. It returns one on success, whether or not the
* element was found, and zero on decode error. */
static int SSL_SESSION_parse_octet_string(CBS *cbs, uint8_t **out_ptr,
- size_t *out_len, unsigned tag) {
+ size_t *out_len, unsigned tag) {
CBS value;
if (!CBS_get_optional_asn1_octet_string(cbs, &value, NULL, tag)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse_octet_string,
- SSL_R_INVALID_SSL_SESSION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
return 0;
}
if (!CBS_stow(&value, out_ptr, out_len)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse_octet_string,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return 0;
}
return 1;
}
-static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) {
- SSL_SESSION *ret = NULL;
- CBS session, cipher, session_id, master_key;
- CBS peer, sid_ctx, peer_sha256, original_handshake_hash;
- int has_peer, has_peer_sha256, extended_master_secret;
- uint64_t version, ssl_version;
- uint64_t session_time, timeout, verify_result, ticket_lifetime_hint;
-
- ret = SSL_SESSION_new();
- if (ret == NULL) {
- goto err;
+/* SSL_SESSION_parse_bounded_octet_string parses an optional ASN.1 OCTET STRING
+ * explicitly tagged with |tag| of size at most |max_out|. */
+static int SSL_SESSION_parse_bounded_octet_string(
+ CBS *cbs, uint8_t *out, unsigned *out_len, unsigned max_out, unsigned tag) {
+ CBS value;
+ if (!CBS_get_optional_asn1_octet_string(cbs, &value, NULL, tag) ||
+ CBS_len(&value) > max_out) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ return 0;
}
+ memcpy(out, CBS_data(&value), CBS_len(&value));
+ *out_len = (unsigned)CBS_len(&value);
+ return 1;
+}
- if (!CBS_get_asn1(cbs, &session, CBS_ASN1_SEQUENCE) ||
- !CBS_get_asn1_uint64(&session, &version) ||
- !CBS_get_asn1_uint64(&session, &ssl_version) ||
- !CBS_get_asn1(&session, &cipher, CBS_ASN1_OCTETSTRING) ||
- !CBS_get_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING) ||
- !CBS_get_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING) ||
- !CBS_get_optional_asn1_uint64(&session, &session_time, kTimeTag,
- time(NULL)) ||
- !CBS_get_optional_asn1_uint64(&session, &timeout, kTimeoutTag, 3) ||
- !CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag) ||
- !CBS_get_optional_asn1_octet_string(&session, &sid_ctx, NULL,
- kSessionIDContextTag) ||
- !CBS_get_optional_asn1_uint64(&session, &verify_result, kVerifyResultTag,
- X509_V_OK)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION);
- goto err;
- }
- if (!SSL_SESSION_parse_string(&session, &ret->tlsext_hostname,
- kHostNameTag) ||
- !SSL_SESSION_parse_string(&session, &ret->psk_identity,
- kPSKIdentityTag)) {
- goto err;
- }
- if (!CBS_get_optional_asn1_uint64(&session, &ticket_lifetime_hint,
- kTicketLifetimeHintTag, 0)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION);
- goto err;
- }
- if (!SSL_SESSION_parse_octet_string(&session, &ret->tlsext_tick,
- &ret->tlsext_ticklen, kTicketTag)) {
- goto err;
+static int SSL_SESSION_parse_long(CBS *cbs, long *out, unsigned tag,
+ long default_value) {
+ uint64_t value;
+ if (!CBS_get_optional_asn1_uint64(cbs, &value, tag,
+ (uint64_t)default_value) ||
+ value > LONG_MAX) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ return 0;
}
- if (!CBS_get_optional_asn1_octet_string(&session, &peer_sha256,
- &has_peer_sha256, kPeerSHA256Tag) ||
- !CBS_get_optional_asn1_octet_string(&session, &original_handshake_hash,
- NULL, kOriginalHandshakeHashTag)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION);
- goto err;
+ *out = (long)value;
+ return 1;
+}
+
+static int SSL_SESSION_parse_u32(CBS *cbs, uint32_t *out, unsigned tag,
+ uint32_t default_value) {
+ uint64_t value;
+ if (!CBS_get_optional_asn1_uint64(cbs, &value, tag,
+ (uint64_t)default_value) ||
+ value > 0xffffffff) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ return 0;
}
- if (!SSL_SESSION_parse_octet_string(
- &session, &ret->tlsext_signed_cert_timestamp_list,
- &ret->tlsext_signed_cert_timestamp_list_length,
- kSignedCertTimestampListTag) ||
- !SSL_SESSION_parse_octet_string(
- &session, &ret->ocsp_response, &ret->ocsp_response_length,
- kOCSPResponseTag)) {
- goto err;
+ *out = (uint32_t)value;
+ return 1;
+}
+
+static X509 *parse_x509(CBS *cbs) {
+ const uint8_t *ptr = CBS_data(cbs);
+ X509 *ret = d2i_X509(NULL, &ptr, CBS_len(cbs));
+ if (ret == NULL) {
+ return NULL;
}
- if (!CBS_get_optional_asn1_bool(&session, &extended_master_secret,
- kExtendedMasterSecretTag,
- 0 /* default to false */) ||
- CBS_len(&session) != 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION);
+ CBS_skip(cbs, ptr - CBS_data(cbs));
+ return ret;
+}
+
+static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) {
+ SSL_SESSION *ret = SSL_SESSION_new();
+ if (ret == NULL) {
goto err;
}
- ret->extended_master_secret = extended_master_secret;
- if (version != SSL_SESSION_ASN1_VERSION) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION);
+ CBS session;
+ uint64_t version, ssl_version;
+ if (!CBS_get_asn1(cbs, &session, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1_uint64(&session, &version) ||
+ version != SSL_SESSION_ASN1_VERSION ||
+ !CBS_get_asn1_uint64(&session, &ssl_version)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}
-
/* Only support SSLv3/TLS and DTLS. */
if ((ssl_version >> 8) != SSL3_VERSION_MAJOR &&
(ssl_version >> 8) != (DTLS1_VERSION >> 8)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_UNKNOWN_SSL_VERSION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_SSL_VERSION);
goto err;
}
ret->ssl_version = ssl_version;
+ CBS cipher;
uint16_t cipher_value;
- if (!CBS_get_u16(&cipher, &cipher_value) || CBS_len(&cipher) != 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_CIPHER_CODE_WRONG_LENGTH);
+ if (!CBS_get_asn1(&session, &cipher, CBS_ASN1_OCTETSTRING) ||
+ !CBS_get_u16(&cipher, &cipher_value) ||
+ CBS_len(&cipher) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}
ret->cipher = SSL_get_cipher_by_value(cipher_value);
if (ret->cipher == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_UNSUPPORTED_CIPHER);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_CIPHER);
goto err;
}
- if (CBS_len(&session_id) > SSL3_MAX_SSL_SESSION_ID_LENGTH) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION);
+ CBS session_id, master_key;
+ if (!CBS_get_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING) ||
+ CBS_len(&session_id) > SSL3_MAX_SSL_SESSION_ID_LENGTH ||
+ !CBS_get_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING) ||
+ CBS_len(&master_key) > SSL_MAX_MASTER_KEY_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}
memcpy(ret->session_id, CBS_data(&session_id), CBS_len(&session_id));
ret->session_id_length = CBS_len(&session_id);
-
- if (CBS_len(&master_key) > SSL_MAX_MASTER_KEY_LENGTH) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION);
- goto err;
- }
memcpy(ret->master_key, CBS_data(&master_key), CBS_len(&master_key));
ret->master_key_length = CBS_len(&master_key);
- if (session_time > LONG_MAX ||
- timeout > LONG_MAX) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION);
+ if (!SSL_SESSION_parse_long(&session, &ret->time, kTimeTag, time(NULL)) ||
+ !SSL_SESSION_parse_long(&session, &ret->timeout, kTimeoutTag, 3)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}
- ret->time = session_time;
- ret->timeout = timeout;
+ CBS peer;
+ int has_peer;
+ if (!CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
X509_free(ret->peer);
ret->peer = NULL;
if (has_peer) {
- const uint8_t *ptr;
- ptr = CBS_data(&peer);
- ret->peer = d2i_X509(NULL, &ptr, CBS_len(&peer));
+ ret->peer = parse_x509(&peer);
if (ret->peer == NULL) {
goto err;
}
- if (ptr != CBS_data(&peer) + CBS_len(&peer)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION);
+ if (CBS_len(&peer) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}
}
- if (CBS_len(&sid_ctx) > sizeof(ret->sid_ctx)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION);
- goto err;
- }
- memcpy(ret->sid_ctx, CBS_data(&sid_ctx), CBS_len(&sid_ctx));
- ret->sid_ctx_length = CBS_len(&sid_ctx);
-
- if (verify_result > LONG_MAX ||
- ticket_lifetime_hint > 0xffffffff) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION);
+ if (!SSL_SESSION_parse_bounded_octet_string(
+ &session, ret->sid_ctx, &ret->sid_ctx_length, sizeof(ret->sid_ctx),
+ kSessionIDContextTag) ||
+ !SSL_SESSION_parse_long(&session, &ret->verify_result, kVerifyResultTag,
+ X509_V_OK) ||
+ !SSL_SESSION_parse_string(&session, &ret->tlsext_hostname,
+ kHostNameTag) ||
+ !SSL_SESSION_parse_string(&session, &ret->psk_identity,
+ kPSKIdentityTag) ||
+ !SSL_SESSION_parse_u32(&session, &ret->tlsext_tick_lifetime_hint,
+ kTicketLifetimeHintTag, 0) ||
+ !SSL_SESSION_parse_octet_string(&session, &ret->tlsext_tick,
+ &ret->tlsext_ticklen, kTicketTag)) {
goto err;
}
- ret->verify_result = verify_result;
- ret->tlsext_tick_lifetime_hint = ticket_lifetime_hint;
- if (has_peer_sha256) {
- if (CBS_len(&peer_sha256) != sizeof(ret->peer_sha256)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION);
+ if (CBS_peek_asn1_tag(&session, kPeerSHA256Tag)) {
+ CBS child, peer_sha256;
+ if (!CBS_get_asn1(&session, &child, kPeerSHA256Tag) ||
+ !CBS_get_asn1(&child, &peer_sha256, CBS_ASN1_OCTETSTRING) ||
+ CBS_len(&peer_sha256) != sizeof(ret->peer_sha256) ||
+ CBS_len(&child) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}
memcpy(ret->peer_sha256, CBS_data(&peer_sha256), sizeof(ret->peer_sha256));
@@ -569,14 +605,67 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) {
ret->peer_sha256_valid = 0;
}
- if (CBS_len(&original_handshake_hash) >
- sizeof(ret->original_handshake_hash)) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_parse, SSL_R_INVALID_SSL_SESSION);
+ if (!SSL_SESSION_parse_bounded_octet_string(
+ &session, ret->original_handshake_hash,
+ &ret->original_handshake_hash_len,
+ sizeof(ret->original_handshake_hash), kOriginalHandshakeHashTag) ||
+ !SSL_SESSION_parse_octet_string(
+ &session, &ret->tlsext_signed_cert_timestamp_list,
+ &ret->tlsext_signed_cert_timestamp_list_length,
+ kSignedCertTimestampListTag) ||
+ !SSL_SESSION_parse_octet_string(
+ &session, &ret->ocsp_response, &ret->ocsp_response_length,
+ kOCSPResponseTag)) {
+ goto err;
+ }
+
+ int extended_master_secret;
+ if (!CBS_get_optional_asn1_bool(&session, &extended_master_secret,
+ kExtendedMasterSecretTag,
+ 0 /* default to false */)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ ret->extended_master_secret = !!extended_master_secret;
+
+ if (!SSL_SESSION_parse_u32(&session, &ret->key_exchange_info,
+ kKeyExchangeInfoTag, 0)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+
+ CBS cert_chain;
+ int has_cert_chain;
+ if (!CBS_get_optional_asn1(&session, &cert_chain, &has_cert_chain,
+ kCertChainTag)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ sk_X509_pop_free(ret->cert_chain, X509_free);
+ ret->cert_chain = NULL;
+ if (has_cert_chain) {
+ ret->cert_chain = sk_X509_new_null();
+ if (ret->cert_chain == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ while (CBS_len(&cert_chain) > 0) {
+ X509 *x509 = parse_x509(&cert_chain);
+ if (x509 == NULL) {
+ goto err;
+ }
+ if (!sk_X509_push(ret->cert_chain, x509)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ X509_free(x509);
+ goto err;
+ }
+ }
+ }
+
+ if (CBS_len(&session) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}
- memcpy(ret->original_handshake_hash, CBS_data(&original_handshake_hash),
- CBS_len(&original_handshake_hash));
- ret->original_handshake_hash_len = CBS_len(&original_handshake_hash);
return ret;
@@ -593,7 +682,7 @@ SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len) {
return NULL;
}
if (CBS_len(&cbs) != 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_from_bytes, SSL_R_INVALID_SSL_SESSION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
SSL_SESSION_free(ret);
return NULL;
}
@@ -602,7 +691,7 @@ SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len) {
SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) {
if (length < 0) {
- OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return NULL;
}
diff --git a/src/ssl/ssl_buffer.c b/src/ssl/ssl_buffer.c
new file mode 100644
index 0000000..63dcd80
--- /dev/null
+++ b/src/ssl/ssl_buffer.c
@@ -0,0 +1,318 @@
+/* Copyright (c) 2015, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/type_check.h>
+
+#include "internal.h"
+
+
+OPENSSL_COMPILE_ASSERT(0xffff <= INT_MAX, uint16_fits_in_int);
+
+OPENSSL_COMPILE_ASSERT((SSL3_ALIGN_PAYLOAD & (SSL3_ALIGN_PAYLOAD - 1)) == 0,
+ align_to_a_power_of_two);
+
+/* setup_buffer initializes |buf| with capacity |cap|, aligned such that data
+ * written after |header_len| is aligned to a |SSL3_ALIGN_PAYLOAD|-byte
+ * boundary. It returns one on success and zero on error. */
+static int setup_buffer(SSL3_BUFFER *buf, size_t header_len, size_t cap) {
+ if (buf->buf != NULL || cap > 0xffff) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ /* Add up to |SSL3_ALIGN_PAYLOAD| - 1 bytes of slack for alignment. */
+ buf->buf = OPENSSL_malloc(cap + SSL3_ALIGN_PAYLOAD - 1);
+ if (buf->buf == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ /* Arrange the buffer such that the record body is aligned. */
+ buf->offset = (0 - header_len - (uintptr_t)buf->buf) &
+ (SSL3_ALIGN_PAYLOAD - 1);
+ buf->len = 0;
+ buf->cap = cap;
+ return 1;
+}
+
+static void consume_buffer(SSL3_BUFFER *buf, size_t len) {
+ if (len > buf->len) {
+ abort();
+ }
+ buf->offset += (uint16_t)len;
+ buf->len -= (uint16_t)len;
+ buf->cap -= (uint16_t)len;
+}
+
+static void clear_buffer(SSL3_BUFFER *buf) {
+ OPENSSL_free(buf->buf);
+ memset(buf, 0, sizeof(SSL3_BUFFER));
+}
+
+OPENSSL_COMPILE_ASSERT(DTLS1_RT_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH +
+ SSL3_RT_MAX_EXTRA <= 0xffff,
+ maximum_read_buffer_too_large);
+
+/* setup_read_buffer initializes the read buffer if not already initialized. It
+ * returns one on success and zero on failure. */
+static int setup_read_buffer(SSL *ssl) {
+ SSL3_BUFFER *buf = &ssl->s3->read_buffer;
+
+ if (buf->buf != NULL) {
+ return 1;
+ }
+
+ size_t header_len = ssl_record_prefix_len(ssl);
+ size_t cap = SSL3_RT_MAX_ENCRYPTED_LENGTH;
+ if (SSL_IS_DTLS(ssl)) {
+ cap += DTLS1_RT_HEADER_LENGTH;
+ } else {
+ cap += SSL3_RT_HEADER_LENGTH;
+ }
+ if (ssl->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) {
+ cap += SSL3_RT_MAX_EXTRA;
+ }
+
+ return setup_buffer(buf, header_len, cap);
+}
+
+uint8_t *ssl_read_buffer(SSL *ssl) {
+ return ssl->s3->read_buffer.buf + ssl->s3->read_buffer.offset;
+}
+
+size_t ssl_read_buffer_len(const SSL *ssl) {
+ return ssl->s3->read_buffer.len;
+}
+
+static int dtls_read_buffer_next_packet(SSL *ssl) {
+ SSL3_BUFFER *buf = &ssl->s3->read_buffer;
+
+ if (buf->len > 0) {
+ /* It is an error to call |dtls_read_buffer_extend| when the read buffer is
+ * not empty. */
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ /* Read a single packet from |ssl->rbio|. |buf->cap| must fit in an int. */
+ ssl->rwstate = SSL_READING;
+ int ret = BIO_read(ssl->rbio, buf->buf + buf->offset, (int)buf->cap);
+ if (ret <= 0) {
+ return ret;
+ }
+ ssl->rwstate = SSL_NOTHING;
+ /* |BIO_read| was bound by |buf->cap|, so this cannot overflow. */
+ buf->len = (uint16_t)ret;
+ return 1;
+}
+
+static int tls_read_buffer_extend_to(SSL *ssl, size_t len) {
+ SSL3_BUFFER *buf = &ssl->s3->read_buffer;
+
+ if (len > buf->cap) {
+ /* This may occur if |SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER| was toggled after
+ * |setup_read_buffer| was called. Stay within bounds, but do not attempt to
+ * recover. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
+ return -1;
+ }
+
+ /* Read until the target length is reached. */
+ while (buf->len < len) {
+ /* The amount of data to read is bounded by |buf->cap|, which must fit in an
+ * int. */
+ ssl->rwstate = SSL_READING;
+ int ret = BIO_read(ssl->rbio, buf->buf + buf->offset + buf->len,
+ (int)(len - buf->len));
+ if (ret <= 0) {
+ return ret;
+ }
+ ssl->rwstate = SSL_NOTHING;
+ /* |BIO_read| was bound by |buf->cap - buf->len|, so this cannot
+ * overflow. */
+ buf->len += (uint16_t)ret;
+ }
+
+ return 1;
+}
+
+int ssl_read_buffer_extend_to(SSL *ssl, size_t len) {
+ /* |ssl_read_buffer_extend_to| implicitly discards any consumed data. */
+ ssl_read_buffer_discard(ssl);
+
+ if (!setup_read_buffer(ssl)) {
+ return -1;
+ }
+
+ if (ssl->rbio == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BIO_NOT_SET);
+ return -1;
+ }
+
+ ERR_clear_system_error();
+
+ int ret;
+ if (SSL_IS_DTLS(ssl)) {
+ /* |len| is ignored for a datagram transport. */
+ ret = dtls_read_buffer_next_packet(ssl);
+ } else {
+ ret = tls_read_buffer_extend_to(ssl, len);
+ }
+
+ if (ret <= 0) {
+ /* If the buffer was empty originally and remained empty after attempting to
+ * extend it, release the buffer until the next attempt. */
+ ssl_read_buffer_discard(ssl);
+ }
+ return ret;
+}
+
+void ssl_read_buffer_consume(SSL *ssl, size_t len) {
+ SSL3_BUFFER *buf = &ssl->s3->read_buffer;
+
+ consume_buffer(buf, len);
+ if (!SSL_IS_DTLS(ssl)) {
+ /* The TLS stack never reads beyond the current record, so there will never
+ * be unconsumed data. If read-ahead is ever reimplemented,
+ * |ssl_read_buffer_discard| will require a |memcpy| to shift the excess
+ * back to the front of the buffer, to ensure there is enough space for the
+ * next record. */
+ assert(buf->len == 0);
+ }
+}
+
+void ssl_read_buffer_discard(SSL *ssl) {
+ if (ssl->s3->read_buffer.len == 0) {
+ ssl_read_buffer_clear(ssl);
+ }
+}
+
+void ssl_read_buffer_clear(SSL *ssl) {
+ clear_buffer(&ssl->s3->read_buffer);
+}
+
+
+int ssl_write_buffer_is_pending(const SSL *ssl) {
+ return ssl->s3->write_buffer.len > 0;
+}
+
+OPENSSL_COMPILE_ASSERT(SSL3_RT_HEADER_LENGTH * 2 +
+ SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD * 2 +
+ SSL3_RT_MAX_PLAIN_LENGTH <= 0xffff,
+ maximum_tls_write_buffer_too_large);
+
+OPENSSL_COMPILE_ASSERT(DTLS1_RT_HEADER_LENGTH +
+ SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD +
+ SSL3_RT_MAX_PLAIN_LENGTH <= 0xffff,
+ maximum_dtls_write_buffer_too_large);
+
+int ssl_write_buffer_init(SSL *ssl, uint8_t **out_ptr, size_t max_len) {
+ SSL3_BUFFER *buf = &ssl->s3->write_buffer;
+
+ if (buf->buf != NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ size_t header_len = ssl_seal_prefix_len(ssl);
+
+ /* TODO(davidben): This matches the original behavior in keeping the malloc
+ * size consistent. Does this matter? |cap| could just be |max_len|. */
+ size_t cap = SSL3_RT_MAX_PLAIN_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD;
+ if (SSL_IS_DTLS(ssl)) {
+ cap += DTLS1_RT_HEADER_LENGTH;
+ } else {
+ cap += SSL3_RT_HEADER_LENGTH;
+ if (ssl->mode & SSL_MODE_CBC_RECORD_SPLITTING) {
+ cap += SSL3_RT_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD;
+ }
+ }
+
+ if (max_len > cap) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+
+ if (!setup_buffer(buf, header_len, cap)) {
+ return 0;
+ }
+ *out_ptr = buf->buf + buf->offset;
+ return 1;
+}
+
+void ssl_write_buffer_set_len(SSL *ssl, size_t len) {
+ SSL3_BUFFER *buf = &ssl->s3->write_buffer;
+
+ if (len > buf->cap) {
+ abort();
+ }
+ buf->len = len;
+}
+
+static int tls_write_buffer_flush(SSL *ssl) {
+ SSL3_BUFFER *buf = &ssl->s3->write_buffer;
+
+ while (buf->len > 0) {
+ ssl->rwstate = SSL_WRITING;
+ int ret = BIO_write(ssl->wbio, buf->buf + buf->offset, buf->len);
+ if (ret <= 0) {
+ return ret;
+ }
+ ssl->rwstate = SSL_NOTHING;
+ consume_buffer(buf, (size_t)ret);
+ }
+ ssl_write_buffer_clear(ssl);
+ return 1;
+}
+
+static int dtls_write_buffer_flush(SSL *ssl) {
+ SSL3_BUFFER *buf = &ssl->s3->write_buffer;
+ if (buf->len == 0) {
+ return 1;
+ }
+
+ int ret = BIO_write(ssl->wbio, buf->buf + buf->offset, buf->len);
+ /* Drop the write buffer whether or not the write succeeded synchronously.
+ * TODO(davidben): How does this interact with the retry flag? */
+ ssl_write_buffer_clear(ssl);
+ return (ret <= 0) ? ret : 1;
+}
+
+int ssl_write_buffer_flush(SSL *ssl) {
+ if (ssl->wbio == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BIO_NOT_SET);
+ return -1;
+ }
+ ERR_clear_system_error();
+
+ if (SSL_IS_DTLS(ssl)) {
+ return dtls_write_buffer_flush(ssl);
+ } else {
+ return tls_write_buffer_flush(ssl);
+ }
+}
+
+void ssl_write_buffer_clear(SSL *ssl) {
+ clear_buffer(&ssl->s3->write_buffer);
+}
diff --git a/src/ssl/ssl_cert.c b/src/ssl/ssl_cert.c
index 85aa079..4094b27 100644
--- a/src/ssl/ssl_cert.c
+++ b/src/ssl/ssl_cert.c
@@ -112,84 +112,64 @@
* 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 <openssl/ssl.h>
+
#include <string.h>
-#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/buf.h>
#include <openssl/ec_key.h>
#include <openssl/dh.h>
#include <openssl/err.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
-#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include "../crypto/dh/internal.h"
-#include "../crypto/directory.h"
#include "../crypto/internal.h"
#include "internal.h"
-static CRYPTO_once_t g_x509_store_ex_data_index_once;
-static int g_x509_store_ex_data_index;
-
-static void ssl_x509_store_ex_data_index_init(void) {
- g_x509_store_ex_data_index = X509_STORE_CTX_get_ex_new_index(
- 0, "SSL for verify callback", NULL, NULL, NULL);
-}
-
int SSL_get_ex_data_X509_STORE_CTX_idx(void) {
- CRYPTO_once(&g_x509_store_ex_data_index_once,
- ssl_x509_store_ex_data_index_init);
- return g_x509_store_ex_data_index;
+ /* The ex_data index to go from |X509_STORE_CTX| to |SSL| always uses the
+ * reserved app_data slot. Before ex_data was introduced, app_data was used.
+ * Avoid breaking any software which assumes |X509_STORE_CTX_get_app_data|
+ * works. */
+ return 0;
}
CERT *ssl_cert_new(void) {
- CERT *ret;
-
- ret = (CERT *)OPENSSL_malloc(sizeof(CERT));
+ CERT *ret = (CERT *)OPENSSL_malloc(sizeof(CERT));
if (ret == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl_cert_new, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return NULL;
}
memset(ret, 0, sizeof(CERT));
- ret->key = &ret->pkeys[SSL_PKEY_RSA_ENC];
return ret;
}
CERT *ssl_cert_dup(CERT *cert) {
- CERT *ret;
- int i;
-
- ret = (CERT *)OPENSSL_malloc(sizeof(CERT));
+ CERT *ret = (CERT *)OPENSSL_malloc(sizeof(CERT));
if (ret == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return NULL;
}
memset(ret, 0, sizeof(CERT));
- ret->key = &ret->pkeys[cert->key - &cert->pkeys[0]];
- /* or ret->key = ret->pkeys + (cert->key - cert->pkeys), if you find that
- * more readable */
-
ret->mask_k = cert->mask_k;
ret->mask_a = cert->mask_a;
if (cert->dh_tmp != NULL) {
ret->dh_tmp = DHparams_dup(cert->dh_tmp);
if (ret->dh_tmp == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_DH_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB);
goto err;
}
if (cert->dh_tmp->priv_key) {
BIGNUM *b = BN_dup(cert->dh_tmp->priv_key);
if (!b) {
- OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_BN_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BN_LIB);
goto err;
}
ret->dh_tmp->priv_key = b;
@@ -197,7 +177,7 @@ CERT *ssl_cert_dup(CERT *cert) {
if (cert->dh_tmp->pub_key) {
BIGNUM *b = BN_dup(cert->dh_tmp->pub_key);
if (!b) {
- OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_BN_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BN_LIB);
goto err;
}
ret->dh_tmp->pub_key = b;
@@ -208,67 +188,25 @@ CERT *ssl_cert_dup(CERT *cert) {
ret->ecdh_nid = cert->ecdh_nid;
ret->ecdh_tmp_cb = cert->ecdh_tmp_cb;
- for (i = 0; i < SSL_PKEY_NUM; i++) {
- CERT_PKEY *cpk = cert->pkeys + i;
- CERT_PKEY *rpk = ret->pkeys + i;
- if (cpk->x509 != NULL) {
- rpk->x509 = X509_up_ref(cpk->x509);
- }
-
- if (cpk->privatekey != NULL) {
- rpk->privatekey = EVP_PKEY_up_ref(cpk->privatekey);
- }
-
- if (cpk->chain) {
- rpk->chain = X509_chain_up_ref(cpk->chain);
- if (!rpk->chain) {
- OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- }
+ if (cert->x509 != NULL) {
+ ret->x509 = X509_up_ref(cert->x509);
}
- /* Copy over signature algorithm configuration. */
- if (cert->conf_sigalgs) {
- ret->conf_sigalgs = BUF_memdup(cert->conf_sigalgs, cert->conf_sigalgslen);
- if (!ret->conf_sigalgs) {
- goto err;
- }
- ret->conf_sigalgslen = cert->conf_sigalgslen;
+ if (cert->privatekey != NULL) {
+ ret->privatekey = EVP_PKEY_up_ref(cert->privatekey);
}
- if (cert->client_sigalgs) {
- ret->client_sigalgs = BUF_memdup(cert->client_sigalgs,
- cert->client_sigalgslen);
- if (!ret->client_sigalgs) {
+ if (cert->chain) {
+ ret->chain = X509_chain_up_ref(cert->chain);
+ if (!ret->chain) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
- ret->client_sigalgslen = cert->client_sigalgslen;
- }
-
- /* Copy any custom client certificate types */
- if (cert->client_certificate_types) {
- ret->client_certificate_types = BUF_memdup(
- cert->client_certificate_types, cert->num_client_certificate_types);
- if (!ret->client_certificate_types) {
- goto err;
- }
- ret->num_client_certificate_types = cert->num_client_certificate_types;
}
ret->cert_cb = cert->cert_cb;
ret->cert_cb_arg = cert->cert_cb_arg;
- if (cert->verify_store) {
- CRYPTO_refcount_inc(&cert->verify_store->references);
- ret->verify_store = cert->verify_store;
- }
-
- if (cert->chain_store) {
- CRYPTO_refcount_inc(&cert->chain_store->references);
- ret->chain_store = cert->chain_store;
- }
-
return ret;
err:
@@ -277,27 +215,18 @@ err:
}
/* Free up and clear all certificates and chains */
-void ssl_cert_clear_certs(CERT *c) {
- int i;
- if (c == NULL) {
+void ssl_cert_clear_certs(CERT *cert) {
+ if (cert == NULL) {
return;
}
- for (i = 0; i < SSL_PKEY_NUM; i++) {
- CERT_PKEY *cpk = c->pkeys + i;
- if (cpk->x509) {
- X509_free(cpk->x509);
- cpk->x509 = NULL;
- }
- if (cpk->privatekey) {
- EVP_PKEY_free(cpk->privatekey);
- cpk->privatekey = NULL;
- }
- if (cpk->chain) {
- sk_X509_pop_free(cpk->chain, X509_free);
- cpk->chain = NULL;
- }
- }
+ X509_free(cert->x509);
+ cert->x509 = NULL;
+ EVP_PKEY_free(cert->privatekey);
+ cert->privatekey = NULL;
+ sk_X509_pop_free(cert->chain, X509_free);
+ cert->chain = NULL;
+ cert->key_method = NULL;
}
void ssl_cert_free(CERT *c) {
@@ -309,38 +238,29 @@ void ssl_cert_free(CERT *c) {
ssl_cert_clear_certs(c);
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->digest_nids);
OPENSSL_free(c);
}
-int ssl_cert_set0_chain(CERT *c, STACK_OF(X509) *chain) {
- CERT_PKEY *cpk = c->key;
- if (!cpk) {
- return 0;
- }
- sk_X509_pop_free(cpk->chain, X509_free);
- cpk->chain = chain;
+int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain) {
+ sk_X509_pop_free(cert->chain, X509_free);
+ cert->chain = chain;
return 1;
}
-int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain) {
+int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain) {
STACK_OF(X509) *dchain;
- if (!chain) {
- return ssl_cert_set0_chain(c, NULL);
+ if (chain == NULL) {
+ return ssl_cert_set0_chain(cert, NULL);
}
dchain = X509_chain_up_ref(chain);
- if (!dchain) {
+ if (dchain == NULL) {
return 0;
}
- if (!ssl_cert_set0_chain(c, dchain)) {
+ if (!ssl_cert_set0_chain(cert, dchain)) {
sk_X509_pop_free(dchain, X509_free);
return 0;
}
@@ -348,158 +268,71 @@ int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain) {
return 1;
}
-int ssl_cert_add0_chain_cert(CERT *c, X509 *x) {
- CERT_PKEY *cpk = c->key;
- if (!cpk) {
- return 0;
+int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509) {
+ if (cert->chain == NULL) {
+ cert->chain = sk_X509_new_null();
}
-
- if (!cpk->chain) {
- cpk->chain = sk_X509_new_null();
- }
- if (!cpk->chain || !sk_X509_push(cpk->chain, x)) {
+ if (cert->chain == NULL || !sk_X509_push(cert->chain, x509)) {
return 0;
}
return 1;
}
-int ssl_cert_add1_chain_cert(CERT *c, X509 *x) {
- if (!ssl_cert_add0_chain_cert(c, x)) {
+int ssl_cert_add1_chain_cert(CERT *cert, X509 *x509) {
+ if (!ssl_cert_add0_chain_cert(cert, x509)) {
return 0;
}
- X509_up_ref(x);
+ X509_up_ref(x509);
return 1;
}
-int ssl_cert_select_current(CERT *c, X509 *x) {
- int i;
- if (x == NULL) {
- return 0;
- }
-
- for (i = 0; i < SSL_PKEY_NUM; i++) {
- if (c->pkeys[i].x509 == x) {
- c->key = &c->pkeys[i];
- return 1;
- }
- }
-
- for (i = 0; i < SSL_PKEY_NUM; i++) {
- if (c->pkeys[i].x509 && !X509_cmp(c->pkeys[i].x509, x)) {
- c->key = &c->pkeys[i];
- return 1;
- }
- }
-
- return 0;
-}
-
void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg), void *arg) {
c->cert_cb = cb;
c->cert_cb_arg = arg;
}
-SESS_CERT *ssl_sess_cert_new(void) {
- SESS_CERT *ret;
-
- ret = OPENSSL_malloc(sizeof *ret);
- if (ret == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl_sess_cert_new, ERR_R_MALLOC_FAILURE);
- return NULL;
- }
-
- memset(ret, 0, sizeof *ret);
-
- return ret;
-}
-
-SESS_CERT *ssl_sess_cert_dup(const SESS_CERT *sess_cert) {
- SESS_CERT *ret = ssl_sess_cert_new();
- if (ret == NULL) {
- return NULL;
- }
-
- if (sess_cert->cert_chain != NULL) {
- ret->cert_chain = X509_chain_up_ref(sess_cert->cert_chain);
- if (ret->cert_chain == NULL) {
- ssl_sess_cert_free(ret);
- return NULL;
- }
- }
- if (sess_cert->peer_cert != NULL) {
- ret->peer_cert = X509_up_ref(sess_cert->peer_cert);
- }
- if (sess_cert->peer_dh_tmp != NULL) {
- ret->peer_dh_tmp = sess_cert->peer_dh_tmp;
- DH_up_ref(ret->peer_dh_tmp);
- }
- if (sess_cert->peer_ecdh_tmp != NULL) {
- ret->peer_ecdh_tmp = sess_cert->peer_ecdh_tmp;
- EC_KEY_up_ref(ret->peer_ecdh_tmp);
- }
- return ret;
-}
-
-void ssl_sess_cert_free(SESS_CERT *sess_cert) {
- if (sess_cert == NULL) {
- return;
+int ssl_verify_cert_chain(SSL *ssl, STACK_OF(X509) *cert_chain) {
+ if (cert_chain == NULL || sk_X509_num(cert_chain) == 0) {
+ return 0;
}
- sk_X509_pop_free(sess_cert->cert_chain, X509_free);
- X509_free(sess_cert->peer_cert);
- DH_free(sess_cert->peer_dh_tmp);
- EC_KEY_free(sess_cert->peer_ecdh_tmp);
-
- OPENSSL_free(sess_cert);
-}
-
-int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk) {
- X509 *x;
- int i;
- X509_STORE *verify_store;
+ X509 *leaf = sk_X509_value(cert_chain, 0);
+ int ret = 0;
X509_STORE_CTX ctx;
-
- if (s->cert->verify_store) {
- verify_store = s->cert->verify_store;
- } else {
- verify_store = s->ctx->cert_store;
- }
-
- if (sk == NULL || sk_X509_num(sk) == 0) {
+ if (!X509_STORE_CTX_init(&ctx, ssl->ctx->cert_store, leaf, cert_chain)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
return 0;
}
-
- x = sk_X509_value(sk, 0);
- if (!X509_STORE_CTX_init(&ctx, verify_store, x, sk)) {
- OPENSSL_PUT_ERROR(SSL, ssl_verify_cert_chain, ERR_R_X509_LIB);
- return 0;
+ if (!X509_STORE_CTX_set_ex_data(&ctx, SSL_get_ex_data_X509_STORE_CTX_idx(),
+ ssl)) {
+ goto err;
}
- X509_STORE_CTX_set_ex_data(&ctx, SSL_get_ex_data_X509_STORE_CTX_idx(), s);
/* We need to inherit the verify parameters. These can be determined by the
* context: if its a server it will verify SSL client certificates or vice
* versa. */
- X509_STORE_CTX_set_default(&ctx, s->server ? "ssl_client" : "ssl_server");
+ X509_STORE_CTX_set_default(&ctx, ssl->server ? "ssl_client" : "ssl_server");
/* Anything non-default in "param" should overwrite anything in the ctx. */
- X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), s->param);
+ X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), ssl->param);
- if (s->verify_callback) {
- X509_STORE_CTX_set_verify_cb(&ctx, s->verify_callback);
+ if (ssl->verify_callback) {
+ X509_STORE_CTX_set_verify_cb(&ctx, ssl->verify_callback);
}
- if (s->ctx->app_verify_callback != NULL) {
- i = s->ctx->app_verify_callback(&ctx, s->ctx->app_verify_arg);
+ if (ssl->ctx->app_verify_callback != NULL) {
+ ret = ssl->ctx->app_verify_callback(&ctx, ssl->ctx->app_verify_arg);
} else {
- i = X509_verify_cert(&ctx);
+ ret = X509_verify_cert(&ctx);
}
- s->verify_result = ctx.error;
- X509_STORE_CTX_cleanup(&ctx);
+ ssl->verify_result = ctx.error;
- return i;
+err:
+ X509_STORE_CTX_cleanup(&ctx);
+ return ret;
}
static void set_client_CA_list(STACK_OF(X509_NAME) **ca_list,
@@ -508,15 +341,17 @@ static void set_client_CA_list(STACK_OF(X509_NAME) **ca_list,
*ca_list = name_list;
}
-STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk) {
- size_t i;
- STACK_OF(X509_NAME) *ret;
- X509_NAME *name;
+STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *list) {
+ STACK_OF(X509_NAME) *ret = sk_X509_NAME_new_null();
+ if (ret == NULL) {
+ return NULL;
+ }
- ret = sk_X509_NAME_new_null();
- for (i = 0; i < sk_X509_NAME_num(sk); i++) {
- name = X509_NAME_dup(sk_X509_NAME_value(sk, i));
+ size_t i;
+ for (i = 0; i < sk_X509_NAME_num(list); i++) {
+ X509_NAME *name = X509_NAME_dup(sk_X509_NAME_value(list, i));
if (name == NULL || !sk_X509_NAME_push(ret, name)) {
+ X509_NAME_free(name);
sk_X509_NAME_pop_free(ret, X509_NAME_free);
return NULL;
}
@@ -525,38 +360,38 @@ STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk) {
return ret;
}
-void SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) *name_list) {
- set_client_CA_list(&(s->client_CA), name_list);
+void SSL_set_client_CA_list(SSL *ssl, STACK_OF(X509_NAME) *name_list) {
+ set_client_CA_list(&ssl->client_CA, name_list);
}
void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list) {
- set_client_CA_list(&(ctx->client_CA), name_list);
+ set_client_CA_list(&ctx->client_CA, name_list);
}
STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx) {
return ctx->client_CA;
}
-STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s) {
- if (s->server) {
- if (s->client_CA != NULL) {
- return s->client_CA;
- } else {
- return s->ctx->client_CA;
- }
- } else {
- if ((s->version >> 8) == SSL3_VERSION_MAJOR && s->s3 != NULL) {
- return s->s3->tmp.ca_names;
- } else {
- return NULL;
- }
+STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl) {
+ /* For historical reasons, this function is used both to query configuration
+ * state on a server as well as handshake state on a client. However, whether
+ * |ssl| is a client or server is not known until explicitly configured with
+ * |SSL_set_connect_state|. If |handshake_func| is NULL, |ssl| is in an
+ * indeterminate mode and |ssl->server| is unset. */
+ if (ssl->handshake_func != NULL && !ssl->server) {
+ return ssl->s3->tmp.ca_names;
+ }
+
+ if (ssl->client_CA != NULL) {
+ return ssl->client_CA;
}
+ return ssl->ctx->client_CA;
}
-static int add_client_CA(STACK_OF(X509_NAME) **sk, X509 *x) {
+static int add_client_CA(STACK_OF(X509_NAME) **sk, X509 *x509) {
X509_NAME *name;
- if (x == NULL) {
+ if (x509 == NULL) {
return 0;
}
if (*sk == NULL) {
@@ -566,7 +401,7 @@ static int add_client_CA(STACK_OF(X509_NAME) **sk, X509 *x) {
}
}
- name = X509_NAME_dup(X509_get_subject_name(x));
+ name = X509_NAME_dup(X509_get_subject_name(x509));
if (name == NULL) {
return 0;
}
@@ -579,195 +414,12 @@ static int add_client_CA(STACK_OF(X509_NAME) **sk, X509 *x) {
return 1;
}
-int SSL_add_client_CA(SSL *ssl, X509 *x) {
- return add_client_CA(&(ssl->client_CA), x);
-}
-
-int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) {
- return add_client_CA(&(ctx->client_CA), x);
+int SSL_add_client_CA(SSL *ssl, X509 *x509) {
+ return add_client_CA(&ssl->client_CA, x509);
}
-static int xname_cmp(const X509_NAME **a, const X509_NAME **b) {
- return X509_NAME_cmp(*a, *b);
-}
-
-/* Load CA certs from a file into a STACK. Note that it is somewhat misnamed;
- * it doesn't really have anything to do with clients (except that a common use
- * for a stack of CAs is to send it to the client). Actually, it doesn't have
- * much to do with CAs, either, since it will load any old cert.
- *
- * \param file the file containing one or more certs.
- * \return a ::STACK containing the certs. */
-STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) {
- BIO *in;
- X509 *x = NULL;
- X509_NAME *xn = NULL;
- STACK_OF(X509_NAME) *ret = NULL, *sk;
-
- sk = sk_X509_NAME_new(xname_cmp);
- in = BIO_new(BIO_s_file());
-
- if (sk == NULL || in == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_load_client_CA_file, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (!BIO_read_filename(in, file)) {
- goto err;
- }
-
- for (;;) {
- if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL) {
- break;
- }
- if (ret == NULL) {
- ret = sk_X509_NAME_new_null();
- if (ret == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_load_client_CA_file, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- }
- xn = X509_get_subject_name(x);
- if (xn == NULL) {
- goto err;
- }
-
- /* check for duplicates */
- xn = X509_NAME_dup(xn);
- if (xn == NULL) {
- goto err;
- }
- if (sk_X509_NAME_find(sk, NULL, xn)) {
- X509_NAME_free(xn);
- } else {
- sk_X509_NAME_push(sk, xn);
- sk_X509_NAME_push(ret, xn);
- }
- }
-
- if (0) {
- err:
- sk_X509_NAME_pop_free(ret, X509_NAME_free);
- ret = NULL;
- }
-
- sk_X509_NAME_free(sk);
- BIO_free(in);
- X509_free(x);
- if (ret != NULL) {
- ERR_clear_error();
- }
- return ret;
-}
-
-/* Add a file of certs to a stack.
- *
- * \param stack the stack to add to.
- * \param file the file to add from. All certs in this file that are not
- * already in the stack will be added.
- * \return 1 for success, 0 for failure. Note that in the case of failure some
- * certs may have been added to \c stack. */
-int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
- const char *file) {
- BIO *in;
- X509 *x = NULL;
- X509_NAME *xn = NULL;
- int ret = 1;
- int (*oldcmp)(const X509_NAME **a, const X509_NAME **b);
-
- oldcmp = sk_X509_NAME_set_cmp_func(stack, xname_cmp);
- in = BIO_new(BIO_s_file());
-
- if (in == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_add_file_cert_subjects_to_stack,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (!BIO_read_filename(in, file)) {
- goto err;
- }
-
- for (;;) {
- if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL) {
- break;
- }
- xn = X509_get_subject_name(x);
- if (xn == NULL) {
- goto err;
- }
- xn = X509_NAME_dup(xn);
- if (xn == NULL) {
- goto err;
- }
- if (sk_X509_NAME_find(stack, NULL, xn)) {
- X509_NAME_free(xn);
- } else {
- sk_X509_NAME_push(stack, xn);
- }
- }
-
- ERR_clear_error();
-
- if (0) {
- err:
- ret = 0;
- }
-
- BIO_free(in);
- X509_free(x);
-
- (void) sk_X509_NAME_set_cmp_func(stack, oldcmp);
-
- return ret;
-}
-
-/* Add a directory of certs to a stack.
- *
- * \param stack the stack to append to.
- * \param dir the directory to append from. All files in this directory will be
- * examined as potential certs. Any that are acceptable to
- * SSL_add_dir_cert_subjects_to_stack() that are not already in the stack will
- * be included.
- * \return 1 for success, 0 for failure. Note that in the case of failure some
- * certs may have been added to \c stack. */
-int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
- const char *dir) {
- OPENSSL_DIR_CTX *d = NULL;
- const char *filename;
- int ret = 0;
-
- /* Note that a side effect is that the CAs will be sorted by name */
- while ((filename = OPENSSL_DIR_read(&d, dir))) {
- char buf[1024];
- int r;
-
- if (strlen(dir) + strlen(filename) + 2 > sizeof(buf)) {
- OPENSSL_PUT_ERROR(SSL, SSL_add_dir_cert_subjects_to_stack,
- SSL_R_PATH_TOO_LONG);
- goto err;
- }
-
- r = BIO_snprintf(buf, sizeof buf, "%s/%s", dir, filename);
- if (r <= 0 || r >= (int)sizeof(buf) ||
- !SSL_add_file_cert_subjects_to_stack(stack, buf)) {
- goto err;
- }
- }
-
- if (errno) {
- OPENSSL_PUT_ERROR(SSL, SSL_add_dir_cert_subjects_to_stack, ERR_R_SYS_LIB);
- ERR_add_error_data(3, "OPENSSL_DIR_read(&ctx, '", dir, "')");
- goto err;
- }
-
- ret = 1;
-
-err:
- if (d) {
- OPENSSL_DIR_end(&d);
- }
- return ret;
+int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x509) {
+ return add_client_CA(&ctx->client_CA, x509);
}
/* Add a certificate to a BUF_MEM structure */
@@ -777,7 +429,7 @@ static int ssl_add_cert_to_buf(BUF_MEM *buf, unsigned long *l, X509 *x) {
n = i2d_X509(x, NULL);
if (!BUF_MEM_grow_clean(buf, (int)(n + (*l) + 3))) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_cert_to_buf, ERR_R_BUF_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
return 0;
}
p = (uint8_t *)&(buf->data[*l]);
@@ -789,34 +441,21 @@ static int ssl_add_cert_to_buf(BUF_MEM *buf, unsigned long *l, X509 *x) {
}
/* Add certificate chain to internal SSL BUF_MEM structure. */
-int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l) {
- BUF_MEM *buf = s->init_buf;
+int ssl_add_cert_chain(SSL *ssl, unsigned long *l) {
+ CERT *cert = ssl->cert;
+ BUF_MEM *buf = ssl->init_buf;
int no_chain = 0;
size_t i;
- X509 *x = cpk->x509;
- STACK_OF(X509) *extra_certs;
- X509_STORE *chain_store;
+ X509 *x = cert->x509;
+ STACK_OF(X509) *chain = cert->chain;
if (x == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_cert_chain, SSL_R_NO_CERTIFICATE_SET);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET);
return 0;
}
- if (s->cert->chain_store) {
- chain_store = s->cert->chain_store;
- } else {
- chain_store = s->ctx->cert_store;
- }
-
- /* If we have a certificate specific chain use it, else use parent ctx. */
- if (cpk && cpk->chain) {
- extra_certs = cpk->chain;
- } else {
- extra_certs = s->ctx->extra_certs;
- }
-
- if ((s->mode & SSL_MODE_NO_AUTO_CHAIN) || extra_certs) {
+ if ((ssl->mode & SSL_MODE_NO_AUTO_CHAIN) || chain != NULL) {
no_chain = 1;
}
@@ -825,8 +464,8 @@ int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l) {
return 0;
}
- for (i = 0; i < sk_X509_num(extra_certs); i++) {
- x = sk_X509_value(extra_certs, i);
+ for (i = 0; i < sk_X509_num(chain); i++) {
+ x = sk_X509_value(chain, i);
if (!ssl_add_cert_to_buf(buf, l, x)) {
return 0;
}
@@ -834,8 +473,8 @@ int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l) {
} 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);
+ if (!X509_STORE_CTX_init(&xs_ctx, ssl->ctx->cert_store, x, NULL)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
return 0;
}
X509_verify_cert(&xs_ctx);
@@ -855,132 +494,65 @@ int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l) {
return 1;
}
-/* Build a certificate chain for current certificate */
-int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags) {
- CERT_PKEY *cpk = c->key;
- X509_STORE_CTX xs_ctx;
- STACK_OF(X509) *chain = NULL, *untrusted = NULL;
- X509 *x;
- int i, rv = 0;
- uint32_t error;
-
- if (!cpk->x509) {
- OPENSSL_PUT_ERROR(SSL, ssl_build_cert_chain, SSL_R_NO_CERTIFICATE_SET);
- goto err;
- }
-
- /* Rearranging and check the chain: add everything to a store */
- if (flags & SSL_BUILD_CHAIN_FLAG_CHECK) {
- size_t j;
- chain_store = X509_STORE_new();
- if (!chain_store) {
- goto err;
- }
-
- for (j = 0; j < sk_X509_num(cpk->chain); j++) {
- x = sk_X509_value(cpk->chain, j);
- if (!X509_STORE_add_cert(chain_store, x)) {
- error = ERR_peek_last_error();
- if (ERR_GET_LIB(error) != ERR_LIB_X509 ||
- ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE) {
- goto err;
- }
- ERR_clear_error();
- }
- }
+int SSL_CTX_set0_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) {
+ return ssl_cert_set0_chain(ctx->cert, chain);
+}
- /* Add EE cert too: it might be self signed */
- if (!X509_STORE_add_cert(chain_store, cpk->x509)) {
- error = ERR_peek_last_error();
- if (ERR_GET_LIB(error) != ERR_LIB_X509 ||
- ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE) {
- goto err;
- }
- ERR_clear_error();
- }
- } else {
- if (c->chain_store) {
- chain_store = c->chain_store;
- }
+int SSL_CTX_set1_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) {
+ return ssl_cert_set1_chain(ctx->cert, chain);
+}
- if (flags & SSL_BUILD_CHAIN_FLAG_UNTRUSTED) {
- untrusted = cpk->chain;
- }
- }
+int SSL_set0_chain(SSL *ssl, STACK_OF(X509) *chain) {
+ return ssl_cert_set0_chain(ssl->cert, chain);
+}
- if (!X509_STORE_CTX_init(&xs_ctx, chain_store, cpk->x509, untrusted)) {
- OPENSSL_PUT_ERROR(SSL, ssl_build_cert_chain, ERR_R_X509_LIB);
- goto err;
- }
+int SSL_set1_chain(SSL *ssl, STACK_OF(X509) *chain) {
+ return ssl_cert_set1_chain(ssl->cert, chain);
+}
- i = X509_verify_cert(&xs_ctx);
- if (i <= 0 && flags & SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR) {
- if (flags & SSL_BUILD_CHAIN_FLAG_CLEAR_ERROR) {
- ERR_clear_error();
- }
- i = 1;
- rv = 2;
- }
+int SSL_CTX_add0_chain_cert(SSL_CTX *ctx, X509 *x509) {
+ return ssl_cert_add0_chain_cert(ctx->cert, x509);
+}
- if (i > 0) {
- chain = X509_STORE_CTX_get1_chain(&xs_ctx);
- }
- if (i <= 0) {
- OPENSSL_PUT_ERROR(SSL, ssl_build_cert_chain,
- SSL_R_CERTIFICATE_VERIFY_FAILED);
- i = X509_STORE_CTX_get_error(&xs_ctx);
- ERR_add_error_data(2, "Verify error:", X509_verify_cert_error_string(i));
+int SSL_CTX_add1_chain_cert(SSL_CTX *ctx, X509 *x509) {
+ return ssl_cert_add1_chain_cert(ctx->cert, x509);
+}
- X509_STORE_CTX_cleanup(&xs_ctx);
- goto err;
- }
+int SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *x509) {
+ return SSL_CTX_add0_chain_cert(ctx, x509);
+}
- X509_STORE_CTX_cleanup(&xs_ctx);
- if (cpk->chain) {
- sk_X509_pop_free(cpk->chain, X509_free);
- }
+int SSL_add0_chain_cert(SSL *ssl, X509 *x509) {
+ return ssl_cert_add0_chain_cert(ssl->cert, x509);
+}
- /* Remove EE certificate from chain */
- x = sk_X509_shift(chain);
- X509_free(x);
- if (flags & SSL_BUILD_CHAIN_FLAG_NO_ROOT) {
- if (sk_X509_num(chain) > 0) {
- /* See if last cert is self signed */
- x = sk_X509_value(chain, sk_X509_num(chain) - 1);
- X509_check_purpose(x, -1, 0);
- if (x->ex_flags & EXFLAG_SS) {
- x = sk_X509_pop(chain);
- X509_free(x);
- }
- }
- }
+int SSL_add1_chain_cert(SSL *ssl, X509 *x509) {
+ return ssl_cert_add1_chain_cert(ssl->cert, x509);
+}
- cpk->chain = chain;
- if (rv == 0) {
- rv = 1;
- }
+int SSL_CTX_clear_chain_certs(SSL_CTX *ctx) {
+ return SSL_CTX_set0_chain(ctx, NULL);
+}
-err:
- if (flags & SSL_BUILD_CHAIN_FLAG_CHECK) {
- X509_STORE_free(chain_store);
- }
+int SSL_CTX_clear_extra_chain_certs(SSL_CTX *ctx) {
+ return SSL_CTX_clear_chain_certs(ctx);
+}
- return rv;
+int SSL_clear_chain_certs(SSL *ssl) {
+ return SSL_set0_chain(ssl, NULL);
}
-int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref) {
- X509_STORE **pstore;
- if (chain) {
- pstore = &c->chain_store;
- } else {
- pstore = &c->verify_store;
- }
+int SSL_CTX_get0_chain_certs(const SSL_CTX *ctx, STACK_OF(X509) **out_chain) {
+ *out_chain = ctx->cert->chain;
+ return 1;
+}
- X509_STORE_free(*pstore);
- *pstore = store;
+int SSL_CTX_get_extra_chain_certs(const SSL_CTX *ctx,
+ STACK_OF(X509) **out_chain) {
+ return SSL_CTX_get0_chain_certs(ctx, out_chain);
+}
- if (ref && store) {
- CRYPTO_refcount_inc(&store->references);
- }
+int SSL_get0_chain_certs(const SSL *ssl, STACK_OF(X509) **out_chain) {
+ *out_chain = ssl->cert->chain;
return 1;
}
diff --git a/src/ssl/ssl_cipher.c b/src/ssl/ssl_cipher.c
index 8d03c9e..b23d775 100644
--- a/src/ssl/ssl_cipher.c
+++ b/src/ssl/ssl_cipher.c
@@ -138,6 +138,8 @@
* OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
* OTHERWISE. */
+#include <openssl/ssl.h>
+
#include <assert.h>
#include <stdio.h>
#include <string.h>
@@ -155,6 +157,12 @@
/* kCiphers is an array of all supported ciphers, sorted by id. */
const SSL_CIPHER kCiphers[] = {
/* The RSA ciphers */
+ /* Cipher 02 */
+ {
+ SSL3_TXT_RSA_NULL_SHA, SSL3_CK_RSA_NULL_SHA, SSL_kRSA, SSL_aRSA,
+ SSL_eNULL, SSL_SHA1, SSL_SSLV3, SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT, 0, 0,
+ },
+
/* Cipher 04 */
{
SSL3_TXT_RSA_RC4_128_MD5, SSL3_CK_RSA_RC4_128_MD5, SSL_kRSA, SSL_aRSA,
@@ -270,8 +278,7 @@ const SSL_CIPHER kCiphers[] = {
TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256,
TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, SSL_kRSA, SSL_aRSA, SSL_AES128GCM,
SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS,
- SSL_HANDSHAKE_MAC_SHA256 |
- SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
+ SSL_HANDSHAKE_MAC_SHA256,
128, 128,
},
@@ -280,8 +287,7 @@ const SSL_CIPHER kCiphers[] = {
TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384,
TLS1_CK_RSA_WITH_AES_256_GCM_SHA384, SSL_kRSA, SSL_aRSA, SSL_AES256GCM,
SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS,
- SSL_HANDSHAKE_MAC_SHA384 |
- SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
+ SSL_HANDSHAKE_MAC_SHA384,
256, 256,
},
@@ -290,8 +296,7 @@ const SSL_CIPHER kCiphers[] = {
TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256,
TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256, SSL_kDHE, SSL_aRSA, SSL_AES128GCM,
SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS,
- SSL_HANDSHAKE_MAC_SHA256 |
- SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
+ SSL_HANDSHAKE_MAC_SHA256,
128, 128,
},
@@ -300,8 +305,7 @@ const SSL_CIPHER kCiphers[] = {
TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384,
TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384, SSL_kDHE, SSL_aRSA, SSL_AES256GCM,
SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS,
- SSL_HANDSHAKE_MAC_SHA384 |
- SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
+ SSL_HANDSHAKE_MAC_SHA384,
256, 256,
},
@@ -395,8 +399,7 @@ const SSL_CIPHER kCiphers[] = {
TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, SSL_kECDHE, SSL_aECDSA,
SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS,
- SSL_HANDSHAKE_MAC_SHA256 |
- SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
+ SSL_HANDSHAKE_MAC_SHA256,
128, 128,
},
@@ -405,8 +408,7 @@ const SSL_CIPHER kCiphers[] = {
TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, SSL_kECDHE, SSL_aECDSA,
SSL_AES256GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS,
- SSL_HANDSHAKE_MAC_SHA384 |
- SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
+ SSL_HANDSHAKE_MAC_SHA384,
256, 256,
},
@@ -415,8 +417,7 @@ const SSL_CIPHER kCiphers[] = {
TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, SSL_kECDHE, SSL_aRSA,
SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS,
- SSL_HANDSHAKE_MAC_SHA256 |
- SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
+ SSL_HANDSHAKE_MAC_SHA256,
128, 128,
},
@@ -425,8 +426,7 @@ const SSL_CIPHER kCiphers[] = {
TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, SSL_kECDHE, SSL_aRSA,
SSL_AES256GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS,
- SSL_HANDSHAKE_MAC_SHA384 |
- SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
+ SSL_HANDSHAKE_MAC_SHA384,
256, 256,
},
@@ -448,15 +448,15 @@ const SSL_CIPHER kCiphers[] = {
SSL_HANDSHAKE_MAC_DEFAULT, 256, 256,
},
+#if !defined(BORINGSSL_ANDROID_SYSTEM)
/* ChaCha20-Poly1305 cipher suites. */
-#if !defined(ANDROID)
{
TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305,
TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, SSL_kECDHE, SSL_aRSA,
SSL_CHACHA20POLY1305, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH,
SSL_HANDSHAKE_MAC_SHA256,
- 256, 0,
+ 256, 256,
},
{
@@ -464,33 +464,13 @@ const SSL_CIPHER kCiphers[] = {
TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, SSL_kECDHE, SSL_aECDSA,
SSL_CHACHA20POLY1305, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH,
SSL_HANDSHAKE_MAC_SHA256,
- 256, 0,
- },
-
- {
- TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305,
- TLS1_CK_DHE_RSA_CHACHA20_POLY1305, SSL_kDHE, SSL_aRSA,
- SSL_CHACHA20POLY1305, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH,
- SSL_HANDSHAKE_MAC_SHA256,
- 256, 0,
+ 256, 256,
},
#endif
};
static const size_t kCiphersLen = sizeof(kCiphers) / sizeof(kCiphers[0]);
-struct handshake_digest {
- uint32_t mask;
- const EVP_MD *(*md_func)(void);
-};
-
-static const struct handshake_digest ssl_handshake_digests[SSL_MAX_DIGEST] = {
- {SSL_HANDSHAKE_MAC_MD5, EVP_md5},
- {SSL_HANDSHAKE_MAC_SHA, EVP_sha1},
- {SSL_HANDSHAKE_MAC_SHA256, EVP_sha256},
- {SSL_HANDSHAKE_MAC_SHA384, EVP_sha384},
-};
-
#define CIPHER_ADD 1
#define CIPHER_KILL 2
#define CIPHER_DEL 3
@@ -521,7 +501,8 @@ typedef struct cipher_alias_st {
} CIPHER_ALIAS;
static const CIPHER_ALIAS kCipherAliases[] = {
- {SSL_TXT_ALL, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u},
+ /* "ALL" doesn't include eNULL (must be specifically enabled) */
+ {SSL_TXT_ALL, ~0u, ~0u, ~SSL_eNULL, ~0u, ~0u, ~0u},
/* The "COMPLEMENTOFDEFAULT" rule is omitted. It matches nothing. */
@@ -542,7 +523,7 @@ static const CIPHER_ALIAS kCipherAliases[] = {
{SSL_TXT_kPSK, SSL_kPSK, ~0u, ~0u, ~0u, ~0u, ~0u},
/* server authentication aliases */
- {SSL_TXT_aRSA, ~0u, SSL_aRSA, ~0u, ~0u, ~0u, ~0u},
+ {SSL_TXT_aRSA, ~0u, SSL_aRSA, ~SSL_eNULL, ~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},
@@ -552,7 +533,7 @@ static const CIPHER_ALIAS kCipherAliases[] = {
{SSL_TXT_EDH, SSL_kDHE, ~0u, ~0u, ~0u, ~0u, ~0u},
{SSL_TXT_ECDHE, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u},
{SSL_TXT_EECDH, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u},
- {SSL_TXT_RSA, SSL_kRSA, SSL_aRSA, ~0u, ~0u, ~0u, ~0u},
+ {SSL_TXT_RSA, SSL_kRSA, SSL_aRSA, ~SSL_eNULL, ~0u, ~0u, ~0u},
{SSL_TXT_PSK, SSL_kPSK, SSL_aPSK, ~0u, ~0u, ~0u, ~0u},
/* symmetric encryption aliases */
@@ -566,21 +547,21 @@ static const CIPHER_ALIAS kCipherAliases[] = {
/* MAC aliases */
{SSL_TXT_MD5, ~0u, ~0u, ~0u, SSL_MD5, ~0u, ~0u},
- {SSL_TXT_SHA1, ~0u, ~0u, ~0u, SSL_SHA1, ~0u, ~0u},
- {SSL_TXT_SHA, ~0u, ~0u, ~0u, SSL_SHA1, ~0u, ~0u},
+ {SSL_TXT_SHA1, ~0u, ~0u, ~SSL_eNULL, SSL_SHA1, ~0u, ~0u},
+ {SSL_TXT_SHA, ~0u, ~0u, ~SSL_eNULL, SSL_SHA1, ~0u, ~0u},
{SSL_TXT_SHA256, ~0u, ~0u, ~0u, SSL_SHA256, ~0u, ~0u},
{SSL_TXT_SHA384, ~0u, ~0u, ~0u, SSL_SHA384, ~0u, ~0u},
/* protocol version aliases */
- {SSL_TXT_SSLV3, ~0u, ~0u, ~0u, ~0u, SSL_SSLV3, ~0u},
- {SSL_TXT_TLSV1, ~0u, ~0u, ~0u, ~0u, SSL_TLSV1, ~0u},
- {SSL_TXT_TLSV1_2, ~0u, ~0u, ~0u, ~0u, SSL_TLSV1_2, ~0u},
+ {SSL_TXT_SSLV3, ~0u, ~0u, ~SSL_eNULL, ~0u, SSL_SSLV3, ~0u},
+ {SSL_TXT_TLSV1, ~0u, ~0u, ~SSL_eNULL, ~0u, SSL_TLSV1, ~0u},
+ {SSL_TXT_TLSV1_2, ~0u, ~0u, ~SSL_eNULL, ~0u, SSL_TLSV1_2, ~0u},
/* strength classes */
{SSL_TXT_MEDIUM, ~0u, ~0u, ~0u, ~0u, ~0u, SSL_MEDIUM},
{SSL_TXT_HIGH, ~0u, ~0u, ~0u, ~0u, ~0u, SSL_HIGH},
/* FIPS 140-2 approved ciphersuite */
- {SSL_TXT_FIPS, ~0u, ~0u, ~0u, ~0u, ~0u, SSL_FIPS},
+ {SSL_TXT_FIPS, ~0u, ~0u, ~SSL_eNULL, ~0u, ~0u, SSL_FIPS},
};
static const size_t kCipherAliasesLen =
@@ -630,7 +611,7 @@ int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead,
*out_fixed_iv_len = 4;
return 1;
-#if !defined(ANDROID)
+#if !defined(BORINGSSL_ANDROID_SYSTEM)
case SSL_CHACHA20POLY1305:
*out_aead = EVP_aead_chacha20_poly1305();
*out_fixed_iv_len = 0;
@@ -725,19 +706,36 @@ int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead,
return 0;
}
+ case SSL_eNULL:
+ switch (cipher->algorithm_mac) {
+ case SSL_SHA1:
+ if (version == SSL3_VERSION) {
+ *out_aead = EVP_aead_null_sha1_ssl3();
+ } else {
+ *out_aead = EVP_aead_null_sha1_tls();
+ }
+ *out_mac_secret_len = SHA_DIGEST_LENGTH;
+ return 1;
+ default:
+ return 0;
+ }
+
default:
return 0;
}
}
-int ssl_get_handshake_digest(uint32_t *out_mask, const EVP_MD **out_md,
- size_t idx) {
- if (idx >= SSL_MAX_DIGEST) {
- return 0;
+const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf) {
+ switch (algorithm_prf) {
+ case SSL_HANDSHAKE_MAC_DEFAULT:
+ return EVP_sha1();
+ case SSL_HANDSHAKE_MAC_SHA256:
+ return EVP_sha256();
+ case SSL_HANDSHAKE_MAC_SHA384:
+ return EVP_sha384();
+ default:
+ return NULL;
}
- *out_mask = ssl_handshake_digests[idx].mask;
- *out_md = ssl_handshake_digests[idx].md_func();
- return 1;
}
#define ITEM_SEP(a) \
@@ -979,7 +977,7 @@ static int ssl_cipher_strength_sort(CIPHER_ORDER **head_p,
number_uses = OPENSSL_malloc((max_strength_bits + 1) * sizeof(int));
if (!number_uses) {
- OPENSSL_PUT_ERROR(SSL, ssl_cipher_strength_sort, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return 0;
}
memset(number_uses, 0, (max_strength_bits + 1) * sizeof(int));
@@ -1041,8 +1039,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method,
continue;
} else if (!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') &&
!(ch >= '0' && ch <= '9')) {
- OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr,
- SSL_R_UNEXPECTED_OPERATOR_IN_GROUP);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_OPERATOR_IN_GROUP);
retval = in_group = 0;
break;
} else {
@@ -1062,7 +1059,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method,
l++;
} else if (ch == '[') {
if (in_group) {
- OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_NESTED_GROUP);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NESTED_GROUP);
retval = in_group = 0;
break;
}
@@ -1077,8 +1074,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method,
/* If preference groups are enabled, the only legal operator is +.
* Otherwise the in_group bits will get mixed up. */
if (has_group && rule != CIPHER_ADD) {
- OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr,
- SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS);
retval = in_group = 0;
break;
}
@@ -1110,8 +1106,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method,
if (buf_len == 0) {
/* We hit something we cannot deal with, it is no command or separator
* nor alphanumeric, so we call this an error. */
- OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr,
- SSL_R_INVALID_COMMAND);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND);
retval = in_group = 0;
l++;
break;
@@ -1165,8 +1160,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method,
if (buf_len == 8 && !strncmp(buf, "STRENGTH", 8)) {
ok = ssl_cipher_strength_sort(head_p, tail_p);
} else {
- OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr,
- SSL_R_INVALID_COMMAND);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND);
}
if (ok == 0) {
@@ -1186,7 +1180,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method,
}
if (in_group) {
- OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_INVALID_COMMAND);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND);
retval = 0;
}
@@ -1216,7 +1210,7 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method,
* allocation. */
co_list = (CIPHER_ORDER *)OPENSSL_malloc(sizeof(CIPHER_ORDER) * kCiphersLen);
if (co_list == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl_create_cipher_list, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return NULL;
}
@@ -1391,13 +1385,27 @@ int SSL_CIPHER_has_MD5_HMAC(const SSL_CIPHER *cipher) {
}
int SSL_CIPHER_is_AESGCM(const SSL_CIPHER *cipher) {
- return (cipher->algorithm_mac & (SSL_AES128GCM | SSL_AES256GCM)) != 0;
+ return (cipher->algorithm_enc & (SSL_AES128GCM | SSL_AES256GCM)) != 0;
}
int SSL_CIPHER_is_CHACHA20POLY1305(const SSL_CIPHER *cipher) {
return (cipher->algorithm_enc & SSL_CHACHA20POLY1305) != 0;
}
+int SSL_CIPHER_is_NULL(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_enc & SSL_eNULL) != 0;
+}
+
+int SSL_CIPHER_is_RC4(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_enc & SSL_RC4) != 0;
+}
+
+int SSL_CIPHER_is_block_cipher(const SSL_CIPHER *cipher) {
+ /* Neither stream cipher nor AEAD. */
+ return (cipher->algorithm_enc & (SSL_RC4 | SSL_eNULL)) == 0 &&
+ cipher->algorithm_mac != SSL_AEAD;
+}
+
/* return the actual cipher being used */
const char *SSL_CIPHER_get_name(const SSL_CIPHER *cipher) {
if (cipher != NULL) {
@@ -1472,27 +1480,24 @@ static const char *ssl_cipher_get_enc_name(const SSL_CIPHER *cipher) {
}
static const char *ssl_cipher_get_prf_name(const SSL_CIPHER *cipher) {
- if ((cipher->algorithm2 & SSL_HANDSHAKE_MAC_DEFAULT) ==
- SSL_HANDSHAKE_MAC_DEFAULT) {
- /* Before TLS 1.2, the PRF component is the hash used in the HMAC, which is
- * only ever MD5 or SHA-1. */
- switch (cipher->algorithm_mac) {
- case SSL_MD5:
- return "MD5";
- case SSL_SHA1:
- return "SHA";
- default:
- assert(0);
- return "UNKNOWN";
- }
- } else if (cipher->algorithm2 & SSL_HANDSHAKE_MAC_SHA256) {
- return "SHA256";
- } else if (cipher->algorithm2 & SSL_HANDSHAKE_MAC_SHA384) {
- return "SHA384";
- } else {
- assert(0);
- return "UNKNOWN";
+ switch (cipher->algorithm_prf) {
+ case SSL_HANDSHAKE_MAC_DEFAULT:
+ /* Before TLS 1.2, the PRF component is the hash used in the HMAC, which is
+ * only ever MD5 or SHA-1. */
+ switch (cipher->algorithm_mac) {
+ case SSL_MD5:
+ return "MD5";
+ case SSL_SHA1:
+ return "SHA";
+ }
+ break;
+ case SSL_HANDSHAKE_MAC_SHA256:
+ return "SHA256";
+ case SSL_HANDSHAKE_MAC_SHA384:
+ return "SHA384";
}
+ assert(0);
+ return "UNKNOWN";
}
char *SSL_CIPHER_get_rfc_name(const SSL_CIPHER *cipher) {
@@ -1625,6 +1630,10 @@ const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf,
enc = "ChaCha20-Poly1305";
break;
+ case SSL_eNULL:
+ enc="None";
+ break;
+
default:
enc = "unknown";
break;
@@ -1674,29 +1683,28 @@ const char *SSL_CIPHER_get_version(const SSL_CIPHER *cipher) {
return "TLSv1/SSLv3";
}
-void *SSL_COMP_get_compression_methods(void) { return NULL; }
+COMP_METHOD *SSL_COMP_get_compression_methods(void) { return NULL; }
-int SSL_COMP_add_compression_method(int id, void *cm) { return 1; }
+int SSL_COMP_add_compression_method(int id, COMP_METHOD *cm) { return 1; }
-const char *SSL_COMP_get_name(const void *comp) { return NULL; }
+const char *SSL_COMP_get_name(const COMP_METHOD *comp) { return NULL; }
-int ssl_cipher_get_cert_index(const SSL_CIPHER *cipher) {
+int ssl_cipher_get_key_type(const SSL_CIPHER *cipher) {
uint32_t alg_a = cipher->algorithm_auth;
if (alg_a & SSL_aECDSA) {
- return SSL_PKEY_ECC;
+ return EVP_PKEY_EC;
} else if (alg_a & SSL_aRSA) {
- return SSL_PKEY_RSA_ENC;
+ return EVP_PKEY_RSA;
}
- return -1;
+ return EVP_PKEY_NONE;
}
int ssl_cipher_has_server_public_key(const SSL_CIPHER *cipher) {
- /* PSK-authenticated ciphers do not use a public key, except for
- * RSA_PSK. */
- if ((cipher->algorithm_auth & SSL_aPSK) &&
- !(cipher->algorithm_mkey & SSL_kRSA)) {
+ /* PSK-authenticated ciphers do not use a certificate. (RSA_PSK is not
+ * supported.) */
+ if (cipher->algorithm_auth & SSL_aPSK) {
return 0;
}
@@ -1713,3 +1721,34 @@ int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher) {
/* It is optional in all others. */
return 0;
}
+
+size_t ssl_cipher_get_record_split_len(const SSL_CIPHER *cipher) {
+ size_t block_size;
+ switch (cipher->algorithm_enc) {
+ case SSL_3DES:
+ block_size = 8;
+ break;
+ case SSL_AES128:
+ case SSL_AES256:
+ block_size = 16;
+ break;
+ default:
+ return 0;
+ }
+
+ size_t mac_len;
+ switch (cipher->algorithm_mac) {
+ case SSL_MD5:
+ mac_len = MD5_DIGEST_LENGTH;
+ break;
+ case SSL_SHA1:
+ mac_len = SHA_DIGEST_LENGTH;
+ break;
+ default:
+ return 0;
+ }
+
+ size_t ret = 1 + mac_len;
+ ret += block_size - (ret % block_size);
+ return ret;
+}
diff --git a/src/ssl/ssl_file.c b/src/ssl/ssl_file.c
new file mode 100644
index 0000000..88ad5b7
--- /dev/null
+++ b/src/ssl/ssl_file.c
@@ -0,0 +1,623 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <openssl/ssl.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/pem.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+
+#include "../crypto/directory.h"
+#include "internal.h"
+
+
+static int xname_cmp(const X509_NAME **a, const X509_NAME **b) {
+ return X509_NAME_cmp(*a, *b);
+}
+
+/* TODO(davidben): Is there any reason this doesn't call
+ * |SSL_add_file_cert_subjects_to_stack|? */
+STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) {
+ BIO *in;
+ X509 *x = NULL;
+ X509_NAME *xn = NULL;
+ STACK_OF(X509_NAME) *ret = NULL, *sk;
+
+ sk = sk_X509_NAME_new(xname_cmp);
+ in = BIO_new(BIO_s_file());
+
+ if (sk == NULL || in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!BIO_read_filename(in, file)) {
+ goto err;
+ }
+
+ for (;;) {
+ if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL) {
+ break;
+ }
+ if (ret == NULL) {
+ ret = sk_X509_NAME_new_null();
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+ xn = X509_get_subject_name(x);
+ if (xn == NULL) {
+ goto err;
+ }
+
+ /* check for duplicates */
+ xn = X509_NAME_dup(xn);
+ if (xn == NULL) {
+ goto err;
+ }
+ if (sk_X509_NAME_find(sk, NULL, xn)) {
+ X509_NAME_free(xn);
+ } else {
+ sk_X509_NAME_push(sk, xn);
+ sk_X509_NAME_push(ret, xn);
+ }
+ }
+
+ if (0) {
+ err:
+ sk_X509_NAME_pop_free(ret, X509_NAME_free);
+ ret = NULL;
+ }
+
+ sk_X509_NAME_free(sk);
+ BIO_free(in);
+ X509_free(x);
+ if (ret != NULL) {
+ ERR_clear_error();
+ }
+ return ret;
+}
+
+int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+ const char *file) {
+ BIO *in;
+ X509 *x = NULL;
+ X509_NAME *xn = NULL;
+ int ret = 1;
+ int (*oldcmp)(const X509_NAME **a, const X509_NAME **b);
+
+ oldcmp = sk_X509_NAME_set_cmp_func(stack, xname_cmp);
+ in = BIO_new(BIO_s_file());
+
+ if (in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!BIO_read_filename(in, file)) {
+ goto err;
+ }
+
+ for (;;) {
+ if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL) {
+ break;
+ }
+ xn = X509_get_subject_name(x);
+ if (xn == NULL) {
+ goto err;
+ }
+ xn = X509_NAME_dup(xn);
+ if (xn == NULL) {
+ goto err;
+ }
+ if (sk_X509_NAME_find(stack, NULL, xn)) {
+ X509_NAME_free(xn);
+ } else {
+ sk_X509_NAME_push(stack, xn);
+ }
+ }
+
+ ERR_clear_error();
+
+ if (0) {
+ err:
+ ret = 0;
+ }
+
+ BIO_free(in);
+ X509_free(x);
+
+ (void) sk_X509_NAME_set_cmp_func(stack, oldcmp);
+
+ return ret;
+}
+
+/* Add a directory of certs to a stack.
+ *
+ * \param stack the stack to append to.
+ * \param dir the directory to append from. All files in this directory will be
+ * examined as potential certs. Any that are acceptable to
+ * SSL_add_dir_cert_subjects_to_stack() that are not already in the stack will
+ * be included.
+ * \return 1 for success, 0 for failure. Note that in the case of failure some
+ * certs may have been added to \c stack. */
+int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+ const char *dir) {
+ OPENSSL_DIR_CTX *d = NULL;
+ const char *filename;
+ int ret = 0;
+
+ /* Note that a side effect is that the CAs will be sorted by name */
+ while ((filename = OPENSSL_DIR_read(&d, dir))) {
+ char buf[1024];
+ int r;
+
+ if (strlen(dir) + strlen(filename) + 2 > sizeof(buf)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PATH_TOO_LONG);
+ goto err;
+ }
+
+ r = BIO_snprintf(buf, sizeof buf, "%s/%s", dir, filename);
+ if (r <= 0 || r >= (int)sizeof(buf) ||
+ !SSL_add_file_cert_subjects_to_stack(stack, buf)) {
+ goto err;
+ }
+ }
+
+ if (errno) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
+ ERR_add_error_data(3, "OPENSSL_DIR_read(&ctx, '", dir, "')");
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ if (d) {
+ OPENSSL_DIR_end(&d);
+ }
+ return ret;
+}
+
+int SSL_use_certificate_file(SSL *ssl, const char *file, int type) {
+ int reason_code;
+ BIO *in;
+ int ret = 0;
+ X509 *x = NULL;
+
+ in = BIO_new(BIO_s_file());
+ if (in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ goto end;
+ }
+
+ if (BIO_read_filename(in, file) <= 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
+ goto end;
+ }
+
+ if (type == SSL_FILETYPE_ASN1) {
+ reason_code = ERR_R_ASN1_LIB;
+ x = d2i_X509_bio(in, NULL);
+ } else if (type == SSL_FILETYPE_PEM) {
+ reason_code = ERR_R_PEM_LIB;
+ x = PEM_read_bio_X509(in, NULL, ssl->ctx->default_passwd_callback,
+ ssl->ctx->default_passwd_callback_userdata);
+ } else {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
+ goto end;
+ }
+
+ if (x == NULL) {
+ OPENSSL_PUT_ERROR(SSL, reason_code);
+ goto end;
+ }
+
+ ret = SSL_use_certificate(ssl, x);
+
+end:
+ X509_free(x);
+ BIO_free(in);
+
+ return ret;
+}
+
+int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type) {
+ int reason_code, ret = 0;
+ BIO *in;
+ RSA *rsa = NULL;
+
+ in = BIO_new(BIO_s_file());
+ if (in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ goto end;
+ }
+
+ if (BIO_read_filename(in, file) <= 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
+ goto end;
+ }
+
+ if (type == SSL_FILETYPE_ASN1) {
+ reason_code = ERR_R_ASN1_LIB;
+ rsa = d2i_RSAPrivateKey_bio(in, NULL);
+ } else if (type == SSL_FILETYPE_PEM) {
+ reason_code = ERR_R_PEM_LIB;
+ rsa =
+ PEM_read_bio_RSAPrivateKey(in, NULL, ssl->ctx->default_passwd_callback,
+ ssl->ctx->default_passwd_callback_userdata);
+ } else {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
+ goto end;
+ }
+
+ if (rsa == NULL) {
+ OPENSSL_PUT_ERROR(SSL, reason_code);
+ goto end;
+ }
+ ret = SSL_use_RSAPrivateKey(ssl, rsa);
+ RSA_free(rsa);
+
+end:
+ BIO_free(in);
+ return ret;
+}
+
+int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type) {
+ int reason_code, ret = 0;
+ BIO *in;
+ EVP_PKEY *pkey = NULL;
+
+ in = BIO_new(BIO_s_file());
+ if (in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ goto end;
+ }
+
+ if (BIO_read_filename(in, file) <= 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
+ goto end;
+ }
+
+ if (type == SSL_FILETYPE_PEM) {
+ reason_code = ERR_R_PEM_LIB;
+ pkey = PEM_read_bio_PrivateKey(in, NULL, ssl->ctx->default_passwd_callback,
+ ssl->ctx->default_passwd_callback_userdata);
+ } else if (type == SSL_FILETYPE_ASN1) {
+ reason_code = ERR_R_ASN1_LIB;
+ pkey = d2i_PrivateKey_bio(in, NULL);
+ } else {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
+ goto end;
+ }
+
+ if (pkey == NULL) {
+ OPENSSL_PUT_ERROR(SSL, reason_code);
+ goto end;
+ }
+ ret = SSL_use_PrivateKey(ssl, pkey);
+ EVP_PKEY_free(pkey);
+
+end:
+ BIO_free(in);
+ return ret;
+}
+
+int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) {
+ int reason_code;
+ BIO *in;
+ int ret = 0;
+ X509 *x = NULL;
+
+ in = BIO_new(BIO_s_file());
+ if (in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ goto end;
+ }
+
+ if (BIO_read_filename(in, file) <= 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
+ goto end;
+ }
+
+ if (type == SSL_FILETYPE_ASN1) {
+ reason_code = ERR_R_ASN1_LIB;
+ x = d2i_X509_bio(in, NULL);
+ } else if (type == SSL_FILETYPE_PEM) {
+ reason_code = ERR_R_PEM_LIB;
+ x = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback,
+ ctx->default_passwd_callback_userdata);
+ } else {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
+ goto end;
+ }
+
+ if (x == NULL) {
+ OPENSSL_PUT_ERROR(SSL, reason_code);
+ goto end;
+ }
+
+ ret = SSL_CTX_use_certificate(ctx, x);
+
+end:
+ X509_free(x);
+ BIO_free(in);
+ return ret;
+}
+
+int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type) {
+ int reason_code, ret = 0;
+ BIO *in;
+ RSA *rsa = NULL;
+
+ in = BIO_new(BIO_s_file());
+ if (in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ goto end;
+ }
+
+ if (BIO_read_filename(in, file) <= 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
+ goto end;
+ }
+
+ if (type == SSL_FILETYPE_ASN1) {
+ reason_code = ERR_R_ASN1_LIB;
+ rsa = d2i_RSAPrivateKey_bio(in, NULL);
+ } else if (type == SSL_FILETYPE_PEM) {
+ reason_code = ERR_R_PEM_LIB;
+ rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ctx->default_passwd_callback,
+ ctx->default_passwd_callback_userdata);
+ } else {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
+ goto end;
+ }
+
+ if (rsa == NULL) {
+ OPENSSL_PUT_ERROR(SSL, reason_code);
+ goto end;
+ }
+ ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa);
+ RSA_free(rsa);
+
+end:
+ BIO_free(in);
+ return ret;
+}
+
+int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) {
+ int reason_code, ret = 0;
+ BIO *in;
+ EVP_PKEY *pkey = NULL;
+
+ in = BIO_new(BIO_s_file());
+ if (in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ goto end;
+ }
+
+ if (BIO_read_filename(in, file) <= 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
+ goto end;
+ }
+
+ if (type == SSL_FILETYPE_PEM) {
+ reason_code = ERR_R_PEM_LIB;
+ pkey = PEM_read_bio_PrivateKey(in, NULL, ctx->default_passwd_callback,
+ ctx->default_passwd_callback_userdata);
+ } else if (type == SSL_FILETYPE_ASN1) {
+ reason_code = ERR_R_ASN1_LIB;
+ pkey = d2i_PrivateKey_bio(in, NULL);
+ } else {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
+ goto end;
+ }
+
+ if (pkey == NULL) {
+ OPENSSL_PUT_ERROR(SSL, reason_code);
+ goto end;
+ }
+ ret = SSL_CTX_use_PrivateKey(ctx, pkey);
+ EVP_PKEY_free(pkey);
+
+end:
+ BIO_free(in);
+ return ret;
+}
+
+/* Read a file that contains our certificate in "PEM" format, possibly followed
+ * by a sequence of CA certificates that should be sent to the peer in the
+ * Certificate message. */
+int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) {
+ BIO *in;
+ int ret = 0;
+ X509 *x = NULL;
+
+ ERR_clear_error(); /* clear error stack for SSL_CTX_use_certificate() */
+
+ in = BIO_new(BIO_s_file());
+ if (in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ goto end;
+ }
+
+ if (BIO_read_filename(in, file) <= 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
+ goto end;
+ }
+
+ x = PEM_read_bio_X509_AUX(in, NULL, ctx->default_passwd_callback,
+ ctx->default_passwd_callback_userdata);
+ if (x == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PEM_LIB);
+ goto end;
+ }
+
+ ret = SSL_CTX_use_certificate(ctx, x);
+
+ if (ERR_peek_error() != 0) {
+ ret = 0; /* Key/certificate mismatch doesn't imply ret==0 ... */
+ }
+
+ if (ret) {
+ /* If we could set up our certificate, now proceed to the CA
+ * certificates. */
+ X509 *ca;
+ int r;
+ uint32_t err;
+
+ SSL_CTX_clear_chain_certs(ctx);
+
+ while ((ca = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback,
+ ctx->default_passwd_callback_userdata)) !=
+ NULL) {
+ r = SSL_CTX_add0_chain_cert(ctx, ca);
+ if (!r) {
+ X509_free(ca);
+ ret = 0;
+ goto end;
+ }
+ /* Note that we must not free r if it was successfully added to the chain
+ * (while we must free the main certificate, since its reference count is
+ * increased by SSL_CTX_use_certificate). */
+ }
+
+ /* When the while loop ends, it's usually just EOF. */
+ err = ERR_peek_last_error();
+ if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
+ ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
+ ERR_clear_error();
+ } else {
+ ret = 0; /* some real error */
+ }
+ }
+
+end:
+ X509_free(x);
+ BIO_free(in);
+ return ret;
+}
+
+void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb) {
+ ctx->default_passwd_callback = cb;
+}
+
+void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *data) {
+ ctx->default_passwd_callback_userdata = data;
+}
+
+IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION)
diff --git a/src/ssl/ssl_lib.c b/src/ssl/ssl_lib.c
index 9e1e308..74bd633 100644
--- a/src/ssl/ssl_lib.c
+++ b/src/ssl/ssl_lib.c
@@ -138,11 +138,14 @@
* OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
* OTHERWISE. */
+#include <openssl/ssl.h>
+
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <openssl/bytestring.h>
+#include <openssl/crypto.h>
#include <openssl/dh.h>
#include <openssl/err.h>
#include <openssl/lhash.h>
@@ -155,6 +158,10 @@
#include "../crypto/internal.h"
+/* |SSL_R_UNKNOWN_PROTOCOL| is no longer emitted, but continue to define it
+ * to avoid downstream churn. */
+OPENSSL_DECLARE_ERROR_REASON(SSL, UNKNOWN_PROTOCOL)
+
/* Some error codes are special. Ensure the make_errors.go script never
* regresses this. */
OPENSSL_COMPILE_ASSERT(SSL_R_TLSV1_ALERT_NO_RENEGOTIATION ==
@@ -164,91 +171,192 @@ OPENSSL_COMPILE_ASSERT(SSL_R_TLSV1_ALERT_NO_RENEGOTIATION ==
/* kMaxHandshakeSize is the maximum size, in bytes, of a handshake message. */
static const size_t kMaxHandshakeSize = (1u << 24) - 1;
-static CRYPTO_EX_DATA_CLASS g_ex_data_class_ssl = CRYPTO_EX_DATA_CLASS_INIT;
-static CRYPTO_EX_DATA_CLASS g_ex_data_class_ssl_ctx = CRYPTO_EX_DATA_CLASS_INIT;
+static CRYPTO_EX_DATA_CLASS g_ex_data_class_ssl =
+ CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA;
+static CRYPTO_EX_DATA_CLASS g_ex_data_class_ssl_ctx =
+ CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA;
-int SSL_clear(SSL *ssl) {
- if (ssl->method == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_clear, SSL_R_NO_METHOD_SPECIFIED);
- return 0;
+int SSL_library_init(void) {
+ CRYPTO_library_init();
+ return 1;
+}
+
+static uint32_t ssl_session_hash(const SSL_SESSION *a) {
+ uint32_t hash =
+ ((uint32_t)a->session_id[0]) ||
+ ((uint32_t)a->session_id[1] << 8) ||
+ ((uint32_t)a->session_id[2] << 16) ||
+ ((uint32_t)a->session_id[3] << 24);
+
+ return hash;
+}
+
+/* NB: If this function (or indeed the hash function which uses a sort of
+ * coarser function than this one) is changed, ensure
+ * SSL_CTX_has_matching_session_id() is checked accordingly. It relies on being
+ * able to construct an SSL_SESSION that will collide with any existing session
+ * with a matching session ID. */
+static int ssl_session_cmp(const SSL_SESSION *a, const SSL_SESSION *b) {
+ if (a->ssl_version != b->ssl_version) {
+ return 1;
}
- if (ssl_clear_bad_session(ssl)) {
- SSL_SESSION_free(ssl->session);
- ssl->session = NULL;
+ if (a->session_id_length != b->session_id_length) {
+ return 1;
}
- ssl->hit = 0;
- ssl->shutdown = 0;
+ return memcmp(a->session_id, b->session_id, a->session_id_length);
+}
- /* SSL_clear may be called before or after the |ssl| is initialized in either
- * accept or connect state. In the latter case, SSL_clear should preserve the
- * half and reset |ssl->state| accordingly. */
- if (ssl->handshake_func != NULL) {
- if (ssl->server) {
- SSL_set_accept_state(ssl);
- } else {
- SSL_set_connect_state(ssl);
- }
- } else {
- assert(ssl->state == 0);
+SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) {
+ SSL_CTX *ret = NULL;
+
+ if (method == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NULL_SSL_METHOD_PASSED);
+ return NULL;
}
- /* TODO(davidben): Some state on |ssl| is reset both in |SSL_new| and
- * |SSL_clear| because it is per-connection state rather than configuration
- * state. Per-connection state should be on |ssl->s3| and |ssl->d1| so it is
- * naturally reset at the right points between |SSL_new|, |SSL_clear|, and
- * |ssl3_new|. */
+ if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS);
+ goto err;
+ }
- ssl->rwstate = SSL_NOTHING;
- ssl->rstate = SSL_ST_READ_HEADER;
+ ret = (SSL_CTX *)OPENSSL_malloc(sizeof(SSL_CTX));
+ if (ret == NULL) {
+ goto err;
+ }
- BUF_MEM_free(ssl->init_buf);
- ssl->init_buf = NULL;
+ memset(ret, 0, sizeof(SSL_CTX));
- ssl->packet = NULL;
- ssl->packet_length = 0;
+ ret->method = method->method;
- ssl_clear_cipher_ctx(ssl);
+ CRYPTO_MUTEX_init(&ret->lock);
- OPENSSL_free(ssl->next_proto_negotiated);
- ssl->next_proto_negotiated = NULL;
- ssl->next_proto_negotiated_len = 0;
+ ret->session_cache_mode = SSL_SESS_CACHE_SERVER;
+ ret->session_cache_size = SSL_SESSION_CACHE_MAX_SIZE_DEFAULT;
- /* The ssl->d1->mtu is simultaneously configuration (preserved across
- * clear) and connection-specific state (gets reset).
- *
- * TODO(davidben): Avoid this. */
- unsigned mtu = 0;
- if (ssl->d1 != NULL) {
- mtu = ssl->d1->mtu;
+ /* We take the system default */
+ ret->session_timeout = SSL_DEFAULT_SESSION_TIMEOUT;
+
+ ret->references = 1;
+
+ ret->max_cert_list = SSL_MAX_CERT_LIST_DEFAULT;
+ ret->verify_mode = SSL_VERIFY_NONE;
+ ret->cert = ssl_cert_new();
+ if (ret->cert == NULL) {
+ goto err;
}
- ssl->method->ssl_free(ssl);
- if (!ssl->method->ssl_new(ssl)) {
- return 0;
+ ret->sessions = lh_SSL_SESSION_new(ssl_session_hash, ssl_session_cmp);
+ if (ret->sessions == NULL) {
+ goto err;
+ }
+ ret->cert_store = X509_STORE_new();
+ if (ret->cert_store == NULL) {
+ goto err;
}
- ssl->enc_method = ssl3_get_enc_method(ssl->version);
- assert(ssl->enc_method != NULL);
- if (SSL_IS_DTLS(ssl) && (SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) {
- ssl->d1->mtu = mtu;
+ ssl_create_cipher_list(ret->method, &ret->cipher_list,
+ &ret->cipher_list_by_id, SSL_DEFAULT_CIPHER_LIST);
+ if (ret->cipher_list == NULL ||
+ sk_SSL_CIPHER_num(ret->cipher_list->ciphers) <= 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_LIBRARY_HAS_NO_CIPHERS);
+ goto err2;
}
- ssl->client_version = ssl->version;
+ ret->param = X509_VERIFY_PARAM_new();
+ if (!ret->param) {
+ goto err;
+ }
- return 1;
+ ret->client_CA = sk_X509_NAME_new_null();
+ if (ret->client_CA == NULL) {
+ goto err;
+ }
+
+ CRYPTO_new_ex_data(&g_ex_data_class_ssl_ctx, ret, &ret->ex_data);
+
+ ret->max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
+
+ /* Setup RFC4507 ticket keys */
+ if (!RAND_bytes(ret->tlsext_tick_key_name, 16) ||
+ !RAND_bytes(ret->tlsext_tick_hmac_key, 16) ||
+ !RAND_bytes(ret->tlsext_tick_aes_key, 16)) {
+ ret->options |= SSL_OP_NO_TICKET;
+ }
+
+ /* Default is to connect to non-RI servers. When RI is more widely deployed
+ * might change this. */
+ ret->options |= SSL_OP_LEGACY_SERVER_CONNECT;
+
+ /* Lock the SSL_CTX to the specified version, for compatibility with legacy
+ * uses of SSL_METHOD. */
+ if (method->version != 0) {
+ SSL_CTX_set_max_version(ret, method->version);
+ SSL_CTX_set_min_version(ret, method->version);
+ }
+
+ return ret;
+
+err:
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+err2:
+ SSL_CTX_free(ret);
+ return NULL;
+}
+
+void SSL_CTX_free(SSL_CTX *ctx) {
+ if (ctx == NULL ||
+ !CRYPTO_refcount_dec_and_test_zero(&ctx->references)) {
+ return;
+ }
+
+ X509_VERIFY_PARAM_free(ctx->param);
+
+ /* Free internal session cache. However: the remove_cb() may reference the
+ * ex_data of SSL_CTX, thus the ex_data store can only be removed after the
+ * sessions were flushed. As the ex_data handling routines might also touch
+ * the session cache, the most secure solution seems to be: empty (flush) the
+ * cache, then free ex_data, then finally free the cache. (See ticket
+ * [openssl.org #212].) */
+ SSL_CTX_flush_sessions(ctx, 0);
+
+ CRYPTO_free_ex_data(&g_ex_data_class_ssl_ctx, ctx, &ctx->ex_data);
+
+ CRYPTO_MUTEX_cleanup(&ctx->lock);
+ lh_SSL_SESSION_free(ctx->sessions);
+ X509_STORE_free(ctx->cert_store);
+ ssl_cipher_preference_list_free(ctx->cipher_list);
+ sk_SSL_CIPHER_free(ctx->cipher_list_by_id);
+ ssl_cipher_preference_list_free(ctx->cipher_list_tls10);
+ ssl_cipher_preference_list_free(ctx->cipher_list_tls11);
+ ssl_cert_free(ctx->cert);
+ sk_SSL_CUSTOM_EXTENSION_pop_free(ctx->client_custom_extensions,
+ SSL_CUSTOM_EXTENSION_free);
+ sk_SSL_CUSTOM_EXTENSION_pop_free(ctx->server_custom_extensions,
+ SSL_CUSTOM_EXTENSION_free);
+ sk_X509_NAME_pop_free(ctx->client_CA, X509_NAME_free);
+ sk_SRTP_PROTECTION_PROFILE_free(ctx->srtp_profiles);
+ OPENSSL_free(ctx->psk_identity_hint);
+ OPENSSL_free(ctx->tlsext_ellipticcurvelist);
+ OPENSSL_free(ctx->alpn_client_proto_list);
+ OPENSSL_free(ctx->ocsp_response);
+ OPENSSL_free(ctx->signed_cert_timestamp_list);
+ EVP_PKEY_free(ctx->tlsext_channel_id_private);
+ BIO_free(ctx->keylog_bio);
+
+ OPENSSL_free(ctx);
}
SSL *SSL_new(SSL_CTX *ctx) {
SSL *s;
if (ctx == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_new, SSL_R_NULL_SSL_CTX);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NULL_SSL_CTX);
return NULL;
}
if (ctx->method == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_new, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION);
return NULL;
}
@@ -289,17 +397,8 @@ SSL *SSL_new(SSL_CTX *ctx) {
CRYPTO_refcount_inc(&ctx->references);
s->ctx = ctx;
- s->tlsext_ticket_expected = 0;
CRYPTO_refcount_inc(&ctx->references);
s->initial_ctx = ctx;
- if (ctx->tlsext_ecpointformatlist) {
- s->tlsext_ecpointformatlist = BUF_memdup(
- ctx->tlsext_ecpointformatlist, ctx->tlsext_ecpointformatlist_length);
- if (!s->tlsext_ecpointformatlist) {
- goto err;
- }
- s->tlsext_ecpointformatlist_length = ctx->tlsext_ecpointformatlist_length;
- }
if (ctx->tlsext_ellipticcurvelist) {
s->tlsext_ellipticcurvelist =
@@ -310,7 +409,6 @@ SSL *SSL_new(SSL_CTX *ctx) {
}
s->tlsext_ellipticcurvelist_length = ctx->tlsext_ellipticcurvelist_length;
}
- s->next_proto_negotiated = NULL;
if (s->ctx->alpn_client_proto_list) {
s->alpn_client_proto_list = BUF_memdup(s->ctx->alpn_client_proto_list,
@@ -331,7 +429,6 @@ SSL *SSL_new(SSL_CTX *ctx) {
assert(s->enc_method != NULL);
s->rwstate = SSL_NOTHING;
- s->rstate = SSL_ST_READ_HEADER;
CRYPTO_new_ex_data(&g_ex_data_class_ssl, s, &s->ex_data);
@@ -358,16 +455,474 @@ SSL *SSL_new(SSL_CTX *ctx) {
err:
SSL_free(s);
- OPENSSL_PUT_ERROR(SSL, SSL_new, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return NULL;
}
+void SSL_free(SSL *ssl) {
+ if (ssl == NULL) {
+ return;
+ }
+
+ X509_VERIFY_PARAM_free(ssl->param);
+
+ CRYPTO_free_ex_data(&g_ex_data_class_ssl, ssl, &ssl->ex_data);
+
+ if (ssl->bbio != NULL) {
+ /* If the buffering BIO is in place, pop it off */
+ if (ssl->bbio == ssl->wbio) {
+ ssl->wbio = BIO_pop(ssl->wbio);
+ }
+ BIO_free(ssl->bbio);
+ ssl->bbio = NULL;
+ }
+
+ int free_wbio = ssl->wbio != ssl->rbio;
+ BIO_free_all(ssl->rbio);
+ if (free_wbio) {
+ BIO_free_all(ssl->wbio);
+ }
+
+ BUF_MEM_free(ssl->init_buf);
+
+ /* add extra stuff */
+ ssl_cipher_preference_list_free(ssl->cipher_list);
+ sk_SSL_CIPHER_free(ssl->cipher_list_by_id);
+
+ ssl_clear_bad_session(ssl);
+ SSL_SESSION_free(ssl->session);
+
+ ssl_clear_cipher_ctx(ssl);
+
+ ssl_cert_free(ssl->cert);
+
+ OPENSSL_free(ssl->tlsext_hostname);
+ SSL_CTX_free(ssl->initial_ctx);
+ OPENSSL_free(ssl->tlsext_ellipticcurvelist);
+ OPENSSL_free(ssl->alpn_client_proto_list);
+ EVP_PKEY_free(ssl->tlsext_channel_id_private);
+ OPENSSL_free(ssl->psk_identity_hint);
+ sk_X509_NAME_pop_free(ssl->client_CA, X509_NAME_free);
+ OPENSSL_free(ssl->next_proto_negotiated);
+ sk_SRTP_PROTECTION_PROFILE_free(ssl->srtp_profiles);
+
+ if (ssl->method != NULL) {
+ ssl->method->ssl_free(ssl);
+ }
+ SSL_CTX_free(ssl->ctx);
+
+ OPENSSL_free(ssl);
+}
+
+void SSL_set_connect_state(SSL *ssl) {
+ ssl->server = 0;
+ ssl->shutdown = 0;
+ ssl->state = SSL_ST_CONNECT;
+ ssl->handshake_func = ssl->method->ssl_connect;
+ /* clear the current cipher */
+ ssl_clear_cipher_ctx(ssl);
+}
+
+void SSL_set_accept_state(SSL *ssl) {
+ ssl->server = 1;
+ ssl->shutdown = 0;
+ ssl->state = SSL_ST_ACCEPT;
+ ssl->handshake_func = ssl->method->ssl_accept;
+ /* clear the current cipher */
+ ssl_clear_cipher_ctx(ssl);
+}
+
+void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio) {
+ /* If the output buffering BIO is still in place, remove it. */
+ if (ssl->bbio != NULL) {
+ if (ssl->wbio == ssl->bbio) {
+ ssl->wbio = ssl->wbio->next_bio;
+ ssl->bbio->next_bio = NULL;
+ }
+ }
+
+ if (ssl->rbio != rbio) {
+ BIO_free_all(ssl->rbio);
+ }
+ if (ssl->wbio != wbio && ssl->rbio != ssl->wbio) {
+ BIO_free_all(ssl->wbio);
+ }
+ ssl->rbio = rbio;
+ ssl->wbio = wbio;
+}
+
+BIO *SSL_get_rbio(const SSL *ssl) { return ssl->rbio; }
+
+BIO *SSL_get_wbio(const SSL *ssl) { return ssl->wbio; }
+
+int SSL_do_handshake(SSL *ssl) {
+ if (ssl->handshake_func == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_TYPE_NOT_SET);
+ return -1;
+ }
+
+ if (!SSL_in_init(ssl)) {
+ return 1;
+ }
+
+ return ssl->handshake_func(ssl);
+}
+
+int SSL_connect(SSL *ssl) {
+ if (ssl->handshake_func == 0) {
+ /* Not properly initialized yet */
+ SSL_set_connect_state(ssl);
+ }
+
+ if (ssl->handshake_func != ssl->method->ssl_connect) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ return ssl->handshake_func(ssl);
+}
+
+int SSL_accept(SSL *ssl) {
+ if (ssl->handshake_func == 0) {
+ /* Not properly initialized yet */
+ SSL_set_accept_state(ssl);
+ }
+
+ if (ssl->handshake_func != ssl->method->ssl_accept) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ return ssl->handshake_func(ssl);
+}
+
+int SSL_read(SSL *ssl, void *buf, int num) {
+ if (ssl->handshake_func == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
+ return -1;
+ }
+
+ if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) {
+ ssl->rwstate = SSL_NOTHING;
+ return 0;
+ }
+
+ ERR_clear_system_error();
+ return ssl->method->ssl_read_app_data(ssl, buf, num, 0);
+}
+
+int SSL_peek(SSL *ssl, void *buf, int num) {
+ if (ssl->handshake_func == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
+ return -1;
+ }
+
+ if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) {
+ return 0;
+ }
+
+ ERR_clear_system_error();
+ return ssl->method->ssl_read_app_data(ssl, buf, num, 1);
+}
+
+int SSL_write(SSL *ssl, const void *buf, int num) {
+ if (ssl->handshake_func == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
+ return -1;
+ }
+
+ if (ssl->shutdown & SSL_SENT_SHUTDOWN) {
+ ssl->rwstate = SSL_NOTHING;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
+ return -1;
+ }
+
+ ERR_clear_system_error();
+ return ssl->method->ssl_write_app_data(ssl, buf, num);
+}
+
+int SSL_shutdown(SSL *ssl) {
+ /* Note that this function behaves differently from what one might expect.
+ * Return values are 0 for no success (yet), 1 for success; but calling it
+ * once is usually not enough, even if blocking I/O is used (see
+ * ssl3_shutdown). */
+
+ if (ssl->handshake_func == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
+ return -1;
+ }
+
+ if (SSL_in_init(ssl)) {
+ return 1;
+ }
+
+ /* Do nothing if configured not to send a close_notify. */
+ if (ssl->quiet_shutdown) {
+ ssl->shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN;
+ return 1;
+ }
+
+ if (!(ssl->shutdown & SSL_SENT_SHUTDOWN)) {
+ ssl->shutdown |= SSL_SENT_SHUTDOWN;
+ ssl3_send_alert(ssl, SSL3_AL_WARNING, SSL_AD_CLOSE_NOTIFY);
+
+ /* our shutdown alert has been sent now, and if it still needs to be
+ * written, ssl->s3->alert_dispatch will be true */
+ if (ssl->s3->alert_dispatch) {
+ return -1; /* return WANT_WRITE */
+ }
+ } else if (ssl->s3->alert_dispatch) {
+ /* resend it if not sent */
+ int ret = ssl->method->ssl_dispatch_alert(ssl);
+ if (ret == -1) {
+ /* we only get to return -1 here the 2nd/Nth invocation, we must have
+ * already signalled return 0 upon a previous invoation, return
+ * WANT_WRITE */
+ return ret;
+ }
+ } else if (!(ssl->shutdown & SSL_RECEIVED_SHUTDOWN)) {
+ /* If we are waiting for a close from our peer, we are closed */
+ ssl->method->ssl_read_close_notify(ssl);
+ if (!(ssl->shutdown & SSL_RECEIVED_SHUTDOWN)) {
+ return -1; /* return WANT_READ */
+ }
+ }
+
+ if (ssl->shutdown == (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN) &&
+ !ssl->s3->alert_dispatch) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int SSL_get_error(const SSL *ssl, int ret_code) {
+ int reason;
+ uint32_t err;
+ BIO *bio;
+
+ if (ret_code > 0) {
+ return SSL_ERROR_NONE;
+ }
+
+ /* Make things return SSL_ERROR_SYSCALL when doing SSL_do_handshake etc,
+ * where we do encode the error */
+ err = ERR_peek_error();
+ if (err != 0) {
+ if (ERR_GET_LIB(err) == ERR_LIB_SYS) {
+ return SSL_ERROR_SYSCALL;
+ }
+ return SSL_ERROR_SSL;
+ }
+
+ if (ret_code == 0) {
+ if ((ssl->shutdown & SSL_RECEIVED_SHUTDOWN) &&
+ (ssl->s3->warn_alert == SSL_AD_CLOSE_NOTIFY)) {
+ /* The socket was cleanly shut down with a close_notify. */
+ return SSL_ERROR_ZERO_RETURN;
+ }
+ /* An EOF was observed which violates the protocol, and the underlying
+ * transport does not participate in the error queue. Bubble up to the
+ * caller. */
+ return SSL_ERROR_SYSCALL;
+ }
+
+ if (SSL_want_session(ssl)) {
+ return SSL_ERROR_PENDING_SESSION;
+ }
+
+ if (SSL_want_certificate(ssl)) {
+ return SSL_ERROR_PENDING_CERTIFICATE;
+ }
+
+ if (SSL_want_read(ssl)) {
+ bio = SSL_get_rbio(ssl);
+ if (BIO_should_read(bio)) {
+ return SSL_ERROR_WANT_READ;
+ }
+
+ if (BIO_should_write(bio)) {
+ /* This one doesn't make too much sense ... We never try to write to the
+ * rbio, and an application program where rbio and wbio are separate
+ * couldn't even know what it should wait for. However if we ever set
+ * s->rwstate incorrectly (so that we have SSL_want_read(s) instead of
+ * SSL_want_write(s)) and rbio and wbio *are* the same, this test works
+ * around that bug; so it might be safer to keep it. */
+ return SSL_ERROR_WANT_WRITE;
+ }
+
+ if (BIO_should_io_special(bio)) {
+ reason = BIO_get_retry_reason(bio);
+ if (reason == BIO_RR_CONNECT) {
+ return SSL_ERROR_WANT_CONNECT;
+ }
+
+ if (reason == BIO_RR_ACCEPT) {
+ return SSL_ERROR_WANT_ACCEPT;
+ }
+
+ return SSL_ERROR_SYSCALL; /* unknown */
+ }
+ }
+
+ if (SSL_want_write(ssl)) {
+ bio = SSL_get_wbio(ssl);
+ if (BIO_should_write(bio)) {
+ return SSL_ERROR_WANT_WRITE;
+ }
+
+ if (BIO_should_read(bio)) {
+ /* See above (SSL_want_read(ssl) with BIO_should_write(bio)) */
+ return SSL_ERROR_WANT_READ;
+ }
+
+ if (BIO_should_io_special(bio)) {
+ reason = BIO_get_retry_reason(bio);
+ if (reason == BIO_RR_CONNECT) {
+ return SSL_ERROR_WANT_CONNECT;
+ }
+
+ if (reason == BIO_RR_ACCEPT) {
+ return SSL_ERROR_WANT_ACCEPT;
+ }
+
+ return SSL_ERROR_SYSCALL;
+ }
+ }
+
+ if (SSL_want_x509_lookup(ssl)) {
+ return SSL_ERROR_WANT_X509_LOOKUP;
+ }
+
+ if (SSL_want_channel_id_lookup(ssl)) {
+ return SSL_ERROR_WANT_CHANNEL_ID_LOOKUP;
+ }
+
+ if (SSL_want_private_key_operation(ssl)) {
+ return SSL_ERROR_WANT_PRIVATE_KEY_OPERATION;
+ }
+
+ return SSL_ERROR_SYSCALL;
+}
+
+void SSL_CTX_set_min_version(SSL_CTX *ctx, uint16_t version) {
+ ctx->min_version = version;
+}
+
+void SSL_CTX_set_max_version(SSL_CTX *ctx, uint16_t version) {
+ ctx->max_version = version;
+}
+
+void SSL_set_min_version(SSL *ssl, uint16_t version) {
+ ssl->min_version = version;
+}
+
+void SSL_set_max_version(SSL *ssl, uint16_t version) {
+ ssl->max_version = version;
+}
+
+uint32_t SSL_CTX_set_options(SSL_CTX *ctx, uint32_t options) {
+ ctx->options |= options;
+ return ctx->options;
+}
+
+uint32_t SSL_CTX_clear_options(SSL_CTX *ctx, uint32_t options) {
+ ctx->options &= ~options;
+ return ctx->options;
+}
+
+uint32_t SSL_CTX_get_options(const SSL_CTX *ctx) { return ctx->options; }
+
+uint32_t SSL_set_options(SSL *ssl, uint32_t options) {
+ ssl->options |= options;
+ return ssl->options;
+}
+
+uint32_t SSL_clear_options(SSL *ssl, uint32_t options) {
+ ssl->options &= ~options;
+ return ssl->options;
+}
+
+uint32_t SSL_get_options(const SSL *ssl) { return ssl->options; }
+
+uint32_t SSL_CTX_set_mode(SSL_CTX *ctx, uint32_t mode) {
+ ctx->mode |= mode;
+ return ctx->mode;
+}
+
+uint32_t SSL_CTX_clear_mode(SSL_CTX *ctx, uint32_t mode) {
+ ctx->mode &= ~mode;
+ return ctx->mode;
+}
+
+uint32_t SSL_CTX_get_mode(const SSL_CTX *ctx) { return ctx->mode; }
+
+uint32_t SSL_set_mode(SSL *ssl, uint32_t mode) {
+ ssl->mode |= mode;
+ return ssl->mode;
+}
+
+uint32_t SSL_clear_mode(SSL *ssl, uint32_t mode) {
+ ssl->mode &= ~mode;
+ return ssl->mode;
+}
+
+uint32_t SSL_get_mode(const SSL *ssl) { return ssl->mode; }
+
+X509 *SSL_get_peer_certificate(const SSL *ssl) {
+ if (ssl == NULL || ssl->session == NULL || ssl->session->peer == NULL) {
+ return NULL;
+ }
+ return X509_up_ref(ssl->session->peer);
+}
+
+STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *ssl) {
+ if (ssl == NULL || ssl->session == NULL) {
+ return NULL;
+ }
+ return ssl->session->cert_chain;
+}
+
+int SSL_get_tls_unique(const SSL *ssl, uint8_t *out, size_t *out_len,
+ size_t max_out) {
+ /* The tls-unique value is the first Finished message in the handshake, which
+ * is the client's in a full handshake and the server's for a resumption. See
+ * https://tools.ietf.org/html/rfc5929#section-3.1. */
+ const uint8_t *finished = ssl->s3->previous_client_finished;
+ size_t finished_len = ssl->s3->previous_client_finished_len;
+ if (ssl->hit) {
+ /* tls-unique is broken for resumed sessions unless EMS is used. */
+ if (!ssl->session->extended_master_secret) {
+ goto err;
+ }
+ finished = ssl->s3->previous_server_finished;
+ finished_len = ssl->s3->previous_server_finished_len;
+ }
+
+ if (!ssl->s3->initial_handshake_complete ||
+ ssl->version < TLS1_VERSION) {
+ goto err;
+ }
+
+ *out_len = finished_len;
+ if (finished_len > max_out) {
+ *out_len = max_out;
+ }
+
+ memcpy(out, finished, *out_len);
+ return 1;
+
+err:
+ *out_len = 0;
+ memset(out, 0, max_out);
+ return 0;
+}
+
int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const uint8_t *sid_ctx,
- unsigned int sid_ctx_len) {
- if (sid_ctx_len > sizeof ctx->sid_ctx) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_set_session_id_context,
- SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
+ unsigned sid_ctx_len) {
+ if (sid_ctx_len > sizeof(ctx->sid_ctx)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
return 0;
}
ctx->sid_ctx_length = sid_ctx_len;
@@ -377,10 +932,9 @@ int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const uint8_t *sid_ctx,
}
int SSL_set_session_id_context(SSL *ssl, const uint8_t *sid_ctx,
- unsigned int sid_ctx_len) {
+ unsigned sid_ctx_len) {
if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) {
- OPENSSL_PUT_ERROR(SSL, SSL_set_session_id_context,
- SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
return 0;
}
ssl->sid_ctx_length = sid_ctx_len;
@@ -400,7 +954,7 @@ int SSL_set_generate_session_id(SSL *ssl, GEN_SESSION_CB cb) {
}
int SSL_has_matching_session_id(const SSL *ssl, const uint8_t *id,
- unsigned int id_len) {
+ unsigned id_len) {
/* A quick examination of SSL_SESSION_hash and SSL_SESSION_cmp shows how we
* can "construct" a session to give us the desired check - ie. to find if
* there's a session in the hash table that would conflict with any new
@@ -422,28 +976,28 @@ int SSL_has_matching_session_id(const SSL *ssl, const uint8_t *id,
return p != NULL;
}
-int SSL_CTX_set_purpose(SSL_CTX *s, int purpose) {
- return X509_VERIFY_PARAM_set_purpose(s->param, purpose);
+int SSL_CTX_set_purpose(SSL_CTX *ctx, int purpose) {
+ return X509_VERIFY_PARAM_set_purpose(ctx->param, purpose);
}
-int SSL_set_purpose(SSL *s, int purpose) {
- return X509_VERIFY_PARAM_set_purpose(s->param, purpose);
+int SSL_set_purpose(SSL *ssl, int purpose) {
+ return X509_VERIFY_PARAM_set_purpose(ssl->param, purpose);
}
-int SSL_CTX_set_trust(SSL_CTX *s, int trust) {
- return X509_VERIFY_PARAM_set_trust(s->param, trust);
+int SSL_CTX_set_trust(SSL_CTX *ctx, int trust) {
+ return X509_VERIFY_PARAM_set_trust(ctx->param, trust);
}
-int SSL_set_trust(SSL *s, int trust) {
- return X509_VERIFY_PARAM_set_trust(s->param, trust);
+int SSL_set_trust(SSL *ssl, int trust) {
+ return X509_VERIFY_PARAM_set_trust(ssl->param, trust);
}
-int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm) {
- return X509_VERIFY_PARAM_set1(ctx->param, vpm);
+int SSL_CTX_set1_param(SSL_CTX *ctx, const X509_VERIFY_PARAM *param) {
+ return X509_VERIFY_PARAM_set1(ctx->param, param);
}
-int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm) {
- return X509_VERIFY_PARAM_set1(ssl->param, vpm);
+int SSL_set1_param(SSL *ssl, const X509_VERIFY_PARAM *param) {
+ return X509_VERIFY_PARAM_set1(ssl->param, param);
}
void ssl_cipher_preference_list_free(
@@ -515,86 +1069,7 @@ X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx) { return ctx->param; }
X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl) { return ssl->param; }
-void SSL_certs_clear(SSL *s) { ssl_cert_clear_certs(s->cert); }
-
-void SSL_free(SSL *ssl) {
- if (ssl == NULL) {
- return;
- }
-
- X509_VERIFY_PARAM_free(ssl->param);
-
- CRYPTO_free_ex_data(&g_ex_data_class_ssl, ssl, &ssl->ex_data);
-
- if (ssl->bbio != NULL) {
- /* If the buffering BIO is in place, pop it off */
- if (ssl->bbio == ssl->wbio) {
- ssl->wbio = BIO_pop(ssl->wbio);
- }
- BIO_free(ssl->bbio);
- ssl->bbio = NULL;
- }
-
- int free_wbio = ssl->wbio != ssl->rbio;
- BIO_free_all(ssl->rbio);
- if (free_wbio) {
- BIO_free_all(ssl->wbio);
- }
-
- BUF_MEM_free(ssl->init_buf);
-
- /* add extra stuff */
- ssl_cipher_preference_list_free(ssl->cipher_list);
- sk_SSL_CIPHER_free(ssl->cipher_list_by_id);
-
- ssl_clear_bad_session(ssl);
- SSL_SESSION_free(ssl->session);
-
- ssl_clear_cipher_ctx(ssl);
-
- ssl_cert_free(ssl->cert);
-
- OPENSSL_free(ssl->tlsext_hostname);
- SSL_CTX_free(ssl->initial_ctx);
- OPENSSL_free(ssl->tlsext_ecpointformatlist);
- OPENSSL_free(ssl->tlsext_ellipticcurvelist);
- OPENSSL_free(ssl->alpn_client_proto_list);
- EVP_PKEY_free(ssl->tlsext_channel_id_private);
- OPENSSL_free(ssl->psk_identity_hint);
- sk_X509_NAME_pop_free(ssl->client_CA, X509_NAME_free);
- OPENSSL_free(ssl->next_proto_negotiated);
- sk_SRTP_PROTECTION_PROFILE_free(ssl->srtp_profiles);
-
- if (ssl->method != NULL) {
- ssl->method->ssl_free(ssl);
- }
- SSL_CTX_free(ssl->ctx);
-
- OPENSSL_free(ssl);
-}
-
-void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio) {
- /* If the output buffering BIO is still in place, remove it. */
- if (s->bbio != NULL) {
- if (s->wbio == s->bbio) {
- s->wbio = s->wbio->next_bio;
- s->bbio->next_bio = NULL;
- }
- }
-
- if (s->rbio != rbio) {
- BIO_free_all(s->rbio);
- }
- if (s->wbio != wbio && s->rbio != s->wbio) {
- BIO_free_all(s->wbio);
- }
- s->rbio = rbio;
- s->wbio = wbio;
-}
-
-BIO *SSL_get_rbio(const SSL *s) { return s->rbio; }
-
-BIO *SSL_get_wbio(const SSL *s) { return s->wbio; }
+void SSL_certs_clear(SSL *ssl) { ssl_cert_clear_certs(ssl->cert); }
int SSL_get_fd(const SSL *s) { return SSL_get_rfd(s); }
@@ -630,7 +1105,7 @@ int SSL_set_fd(SSL *s, int fd) {
bio = BIO_new(BIO_s_fd());
if (bio == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_set_fd, ERR_R_BUF_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
goto err;
}
BIO_set_fd(bio, fd, BIO_NOCLOSE);
@@ -650,7 +1125,7 @@ int SSL_set_wfd(SSL *s, int fd) {
bio = BIO_new(BIO_s_fd());
if (bio == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_set_wfd, ERR_R_BUF_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
goto err;
}
BIO_set_fd(bio, fd, BIO_NOCLOSE);
@@ -674,7 +1149,7 @@ int SSL_set_rfd(SSL *s, int fd) {
bio = BIO_new(BIO_s_fd());
if (bio == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_set_rfd, ERR_R_BUF_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
goto err;
}
BIO_set_fd(bio, fd, BIO_NOCLOSE);
@@ -718,14 +1193,18 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count) {
return ret;
}
-int SSL_get_verify_mode(const SSL *s) { return s->verify_mode; }
+int SSL_get_verify_mode(const SSL *ssl) { return ssl->verify_mode; }
+
+int SSL_get_verify_depth(const SSL *ssl) {
+ return X509_VERIFY_PARAM_get_depth(ssl->param);
+}
-int SSL_get_verify_depth(const SSL *s) {
- return X509_VERIFY_PARAM_get_depth(s->param);
+int SSL_get_extms_support(const SSL *ssl) {
+ return ssl->s3->tmp.extended_master_secret == 1;
}
-int (*SSL_get_verify_callback(const SSL *s))(int, X509_STORE_CTX *) {
- return s->verify_callback;
+int (*SSL_get_verify_callback(const SSL *ssl))(int, X509_STORE_CTX *) {
+ return ssl->verify_callback;
}
int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) { return ctx->verify_mode; }
@@ -734,20 +1213,21 @@ int SSL_CTX_get_verify_depth(const SSL_CTX *ctx) {
return X509_VERIFY_PARAM_get_depth(ctx->param);
}
-int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))(int, X509_STORE_CTX *) {
+int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))(
+ int ok, X509_STORE_CTX *store_ctx) {
return ctx->default_verify_callback;
}
-void SSL_set_verify(SSL *s, int mode,
- int (*callback)(int ok, X509_STORE_CTX *ctx)) {
- s->verify_mode = mode;
+void SSL_set_verify(SSL *ssl, int mode,
+ int (*callback)(int ok, X509_STORE_CTX *store_ctx)) {
+ ssl->verify_mode = mode;
if (callback != NULL) {
- s->verify_callback = callback;
+ ssl->verify_callback = callback;
}
}
-void SSL_set_verify_depth(SSL *s, int depth) {
- X509_VERIFY_PARAM_set_depth(s->param, depth);
+void SSL_set_verify_depth(SSL *ssl, int depth) {
+ X509_VERIFY_PARAM_set_depth(ssl->param, depth);
}
int SSL_CTX_get_read_ahead(const SSL_CTX *ctx) { return 0; }
@@ -759,226 +1239,47 @@ void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes) { }
void SSL_set_read_ahead(SSL *s, int yes) { }
int SSL_pending(const SSL *s) {
- if (s->rstate == SSL_ST_READ_BODY) {
- return 0;
- }
-
return (s->s3->rrec.type == SSL3_RT_APPLICATION_DATA) ? s->s3->rrec.length
: 0;
}
-X509 *SSL_get_peer_certificate(const SSL *s) {
- X509 *r;
-
- if (s == NULL || s->session == NULL) {
- r = NULL;
- } else {
- r = s->session->peer;
- }
-
- if (r == NULL) {
- return NULL;
- }
-
- return X509_up_ref(r);
-}
-
-STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s) {
- STACK_OF(X509) *r;
-
- if (s == NULL || s->session == NULL || s->session->sess_cert == NULL) {
- r = NULL;
- } else {
- r = s->session->sess_cert->cert_chain;
- }
-
- /* If we are a client, cert_chain includes the peer's own certificate; if we
- * are a server, it does not. */
- return r;
-}
-
/* Fix this so it checks all the valid key/cert options */
int SSL_CTX_check_private_key(const SSL_CTX *ctx) {
- if (ctx == NULL || ctx->cert == NULL || ctx->cert->key->x509 == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_check_private_key,
- SSL_R_NO_CERTIFICATE_ASSIGNED);
+ if (ctx->cert->x509 == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED);
return 0;
}
- if (ctx->cert->key->privatekey == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_check_private_key,
- SSL_R_NO_PRIVATE_KEY_ASSIGNED);
+ if (ctx->cert->privatekey == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED);
return 0;
}
- return X509_check_private_key(ctx->cert->key->x509,
- ctx->cert->key->privatekey);
+ return X509_check_private_key(ctx->cert->x509, ctx->cert->privatekey);
}
/* Fix this function so that it takes an optional type parameter */
int SSL_check_private_key(const SSL *ssl) {
- if (ssl == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_check_private_key, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
-
- if (ssl->cert == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_check_private_key,
- SSL_R_NO_CERTIFICATE_ASSIGNED);
- return 0;
- }
-
- if (ssl->cert->key->x509 == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_check_private_key,
- SSL_R_NO_CERTIFICATE_ASSIGNED);
+ if (ssl->cert->x509 == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED);
return 0;
}
- if (ssl->cert->key->privatekey == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_check_private_key,
- SSL_R_NO_PRIVATE_KEY_ASSIGNED);
+ if (ssl->cert->privatekey == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED);
return 0;
}
- return X509_check_private_key(ssl->cert->key->x509,
- ssl->cert->key->privatekey);
-}
-
-int SSL_accept(SSL *s) {
- if (s->handshake_func == 0) {
- /* Not properly initialized yet */
- SSL_set_accept_state(s);
- }
-
- if (s->handshake_func != s->method->ssl_accept) {
- OPENSSL_PUT_ERROR(SSL, SSL_accept, ERR_R_INTERNAL_ERROR);
- return -1;
- }
-
- return s->handshake_func(s);
-}
-
-int SSL_connect(SSL *s) {
- if (s->handshake_func == 0) {
- /* Not properly initialized yet */
- SSL_set_connect_state(s);
- }
-
- if (s->handshake_func != s->method->ssl_connect) {
- OPENSSL_PUT_ERROR(SSL, SSL_connect, ERR_R_INTERNAL_ERROR);
- return -1;
- }
-
- return s->handshake_func(s);
+ return X509_check_private_key(ssl->cert->x509, ssl->cert->privatekey);
}
-long SSL_get_default_timeout(const SSL *s) {
+long SSL_get_default_timeout(const SSL *ssl) {
return SSL_DEFAULT_SESSION_TIMEOUT;
}
-int SSL_read(SSL *s, void *buf, int num) {
- if (s->handshake_func == 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_read, SSL_R_UNINITIALIZED);
- return -1;
- }
-
- if (s->shutdown & SSL_RECEIVED_SHUTDOWN) {
- s->rwstate = SSL_NOTHING;
- return 0;
- }
-
- ERR_clear_system_error();
- return s->method->ssl_read_app_data(s, buf, num, 0);
-}
-
-int SSL_peek(SSL *s, void *buf, int num) {
- if (s->handshake_func == 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_peek, SSL_R_UNINITIALIZED);
- return -1;
- }
-
- if (s->shutdown & SSL_RECEIVED_SHUTDOWN) {
- return 0;
- }
-
- ERR_clear_system_error();
- return s->method->ssl_read_app_data(s, buf, num, 1);
-}
-
-int SSL_write(SSL *s, const void *buf, int num) {
- if (s->handshake_func == 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_write, SSL_R_UNINITIALIZED);
- return -1;
- }
-
- if (s->shutdown & SSL_SENT_SHUTDOWN) {
- s->rwstate = SSL_NOTHING;
- OPENSSL_PUT_ERROR(SSL, SSL_write, SSL_R_PROTOCOL_IS_SHUTDOWN);
- return -1;
- }
-
- ERR_clear_system_error();
- return s->method->ssl_write_app_data(s, buf, num);
-}
-
-int SSL_shutdown(SSL *s) {
- /* Note that this function behaves differently from what one might expect.
- * Return values are 0 for no success (yet), 1 for success; but calling it
- * once is usually not enough, even if blocking I/O is used (see
- * ssl3_shutdown). */
-
- if (s->handshake_func == 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_shutdown, SSL_R_UNINITIALIZED);
- return -1;
- }
-
- if (SSL_in_init(s)) {
- return 1;
- }
-
- /* Do nothing if configured not to send a close_notify. */
- if (s->quiet_shutdown) {
- s->shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN;
- return 1;
- }
-
- if (!(s->shutdown & SSL_SENT_SHUTDOWN)) {
- s->shutdown |= SSL_SENT_SHUTDOWN;
- ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_CLOSE_NOTIFY);
-
- /* our shutdown alert has been sent now, and if it still needs to be
- * written, s->s3->alert_dispatch will be true */
- if (s->s3->alert_dispatch) {
- return -1; /* return WANT_WRITE */
- }
- } else if (s->s3->alert_dispatch) {
- /* resend it if not sent */
- int ret = s->method->ssl_dispatch_alert(s);
- if (ret == -1) {
- /* we only get to return -1 here the 2nd/Nth invocation, we must have
- * already signalled return 0 upon a previous invoation, return
- * WANT_WRITE */
- return ret;
- }
- } else if (!(s->shutdown & SSL_RECEIVED_SHUTDOWN)) {
- /* If we are waiting for a close from our peer, we are closed */
- s->method->ssl_read_close_notify(s);
- if (!(s->shutdown & SSL_RECEIVED_SHUTDOWN)) {
- return -1; /* return WANT_READ */
- }
- }
-
- if (s->shutdown == (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN) &&
- !s->s3->alert_dispatch) {
- return 1;
- } else {
- return 0;
- }
-}
-
int SSL_renegotiate(SSL *ssl) {
/* Caller-initiated renegotiation is not supported. */
- OPENSSL_PUT_ERROR(SSL, SSL_renegotiate, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
@@ -986,54 +1287,6 @@ int SSL_renegotiate_pending(SSL *ssl) {
return SSL_in_init(ssl) && ssl->s3->initial_handshake_complete;
}
-uint32_t SSL_CTX_set_options(SSL_CTX *ctx, uint32_t options) {
- ctx->options |= options;
- return ctx->options;
-}
-
-uint32_t SSL_set_options(SSL *ssl, uint32_t options) {
- ssl->options |= options;
- return ssl->options;
-}
-
-uint32_t SSL_CTX_clear_options(SSL_CTX *ctx, uint32_t options) {
- ctx->options &= ~options;
- return ctx->options;
-}
-
-uint32_t SSL_clear_options(SSL *ssl, uint32_t options) {
- ssl->options &= ~options;
- return ssl->options;
-}
-
-uint32_t SSL_CTX_get_options(const SSL_CTX *ctx) { return ctx->options; }
-
-uint32_t SSL_get_options(const SSL *ssl) { return ssl->options; }
-
-uint32_t SSL_CTX_set_mode(SSL_CTX *ctx, uint32_t mode) {
- ctx->mode |= mode;
- return ctx->mode;
-}
-
-uint32_t SSL_set_mode(SSL *ssl, uint32_t mode) {
- ssl->mode |= mode;
- return ssl->mode;
-}
-
-uint32_t SSL_CTX_clear_mode(SSL_CTX *ctx, uint32_t mode) {
- ctx->mode &= ~mode;
- return ctx->mode;
-}
-
-uint32_t SSL_clear_mode(SSL *ssl, uint32_t mode) {
- ssl->mode &= ~mode;
- return ssl->mode;
-}
-
-uint32_t SSL_CTX_get_mode(const SSL_CTX *ctx) { return ctx->mode; }
-
-uint32_t SSL_get_mode(const SSL *ssl) { return ssl->mode; }
-
size_t SSL_CTX_get_max_cert_list(const SSL_CTX *ctx) {
return ctx->max_cert_list;
}
@@ -1088,10 +1341,6 @@ int SSL_get_secure_renegotiation_support(const SSL *ssl) {
return ssl->s3->send_connection_binding;
}
-long SSL_ctrl(SSL *s, int cmd, long larg, void *parg) {
- return s->method->ssl_ctrl(s, cmd, larg, parg);
-}
-
LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx) { return ctx->sessions; }
size_t SSL_CTX_sess_number(const SSL_CTX *ctx) {
@@ -1118,10 +1367,6 @@ int SSL_CTX_get_session_cache_mode(const SSL_CTX *ctx) {
return ctx->session_cache_mode;
}
-long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) {
- return ctx->method->ssl_ctx_ctrl(ctx, cmd, larg, parg);
-}
-
/* return a STACK of the ciphers available for the SSL and in order of
* preference */
STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s) {
@@ -1138,6 +1383,11 @@ STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s) {
return s->ctx->cipher_list_tls11->ciphers;
}
+ if (s->version >= TLS1_VERSION && s->ctx != NULL &&
+ s->ctx->cipher_list_tls10 != NULL) {
+ return s->ctx->cipher_list_tls10->ciphers;
+ }
+
if (s->ctx != NULL && s->ctx->cipher_list != NULL) {
return s->ctx->cipher_list->ciphers;
}
@@ -1199,7 +1449,21 @@ int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) {
if (sk == NULL) {
return 0;
} else if (sk_SSL_CIPHER_num(sk) == 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_set_cipher_list, SSL_R_NO_CIPHER_MATCH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH);
+ return 0;
+ }
+
+ return 1;
+}
+
+int SSL_CTX_set_cipher_list_tls10(SSL_CTX *ctx, const char *str) {
+ STACK_OF(SSL_CIPHER) *sk;
+
+ sk = ssl_create_cipher_list(ctx->method, &ctx->cipher_list_tls10, NULL, str);
+ if (sk == NULL) {
+ return 0;
+ } else if (sk_SSL_CIPHER_num(sk) == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH);
return 0;
}
@@ -1213,8 +1477,7 @@ int SSL_CTX_set_cipher_list_tls11(SSL_CTX *ctx, const char *str) {
if (sk == NULL) {
return 0;
} else if (sk_SSL_CIPHER_num(sk) == 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_set_cipher_list_tls11,
- SSL_R_NO_CIPHER_MATCH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH);
return 0;
}
@@ -1232,7 +1495,7 @@ int SSL_set_cipher_list(SSL *s, const char *str) {
if (sk == NULL) {
return 0;
} else if (sk_SSL_CIPHER_num(sk) == 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_set_cipher_list, SSL_R_NO_CIPHER_MATCH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH);
return 0;
}
@@ -1268,9 +1531,13 @@ int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, uint8_t *p) {
return 0;
}
- /* Add SCSVs. */
- if (!s->s3->initial_handshake_complete) {
+ /* For SSLv3, the SCSV is added. Otherwise the renegotiation extension is
+ * added. */
+ if (s->client_version == SSL3_VERSION &&
+ !s->s3->initial_handshake_complete) {
s2n(SSL3_CK_SCSV & 0xffff, p);
+ /* The renegotiation extension is required to be at index zero. */
+ s->s3->tmp.extensions.sent |= (1u << 0);
}
if (s->mode & SSL_MODE_SEND_FALLBACK_SCSV) {
@@ -1290,14 +1557,13 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) {
}
if (CBS_len(&cipher_suites) % 2 != 0) {
- OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list,
- SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
return NULL;
}
sk = sk_SSL_CIPHER_new_null();
if (sk == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -1305,7 +1571,7 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) {
uint16_t cipher_suite;
if (!CBS_get_u16(&cipher_suites, &cipher_suite)) {
- OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;
}
@@ -1313,8 +1579,7 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) {
if (s->s3 && cipher_suite == (SSL3_CK_SCSV & 0xffff)) {
/* SCSV is fatal if renegotiating. */
if (s->s3->initial_handshake_complete) {
- OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list,
- SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
goto err;
}
@@ -1327,8 +1592,7 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) {
uint16_t max_version = ssl3_get_max_server_version(s);
if (SSL_IS_DTLS(s) ? (uint16_t)s->version > max_version
: (uint16_t)s->version < max_version) {
- OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list,
- SSL_R_INAPPROPRIATE_FALLBACK);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INAPPROPRIATE_FALLBACK);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_INAPPROPRIATE_FALLBACK);
goto err;
}
@@ -1337,7 +1601,7 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) {
c = SSL_get_cipher_by_value(cipher_suite);
if (c != NULL && !sk_SSL_CIPHER_push(sk, c)) {
- OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}
@@ -1415,39 +1679,37 @@ void SSL_get0_ocsp_response(const SSL *ssl, const uint8_t **out,
*out_len = session->ocsp_response_length;
}
-/* SSL_select_next_proto implements the standard protocol selection. It is
- * expected that this function is called from the callback set by
- * SSL_CTX_set_next_proto_select_cb.
- *
- * The protocol data is assumed to be a vector of 8-bit, length prefixed byte
- * strings. The length byte itself is not included in the length. A byte
- * string of length 0 is invalid. No byte string may be truncated.
- *
- * The current, but experimental algorithm for selecting the protocol is:
- *
- * 1) If the server doesn't support NPN then this is indicated to the
- * callback. In this case, the client application has to abort the connection
- * or have a default application level protocol.
- *
- * 2) If the server supports NPN, but advertises an empty list then the
- * client selects the first protcol in its list, but indicates via the
- * API that this fallback case was enacted.
- *
- * 3) Otherwise, the client finds the first protocol in the server's list
- * that it supports and selects this protocol. This is because it's
- * assumed that the server has better information about which protocol
- * a client should use.
- *
- * 4) If the client doesn't support any of the server's advertised
- * protocols, then this is treated the same as case 2.
- *
- * It returns either
- * OPENSSL_NPN_NEGOTIATED if a common protocol was found, or
- * OPENSSL_NPN_NO_OVERLAP if the fallback case was reached.
- */
-int SSL_select_next_proto(uint8_t **out, uint8_t *outlen, const uint8_t *server,
- unsigned int server_len, const uint8_t *client,
- unsigned int client_len) {
+int SSL_CTX_set_signed_cert_timestamp_list(SSL_CTX *ctx, const uint8_t *list,
+ size_t list_len) {
+ OPENSSL_free(ctx->signed_cert_timestamp_list);
+ ctx->signed_cert_timestamp_list_length = 0;
+
+ ctx->signed_cert_timestamp_list = BUF_memdup(list, list_len);
+ if (ctx->signed_cert_timestamp_list == NULL) {
+ return 0;
+ }
+ ctx->signed_cert_timestamp_list_length = list_len;
+
+ return 1;
+}
+
+int SSL_CTX_set_ocsp_response(SSL_CTX *ctx, const uint8_t *response,
+ size_t response_len) {
+ OPENSSL_free(ctx->ocsp_response);
+ ctx->ocsp_response_length = 0;
+
+ ctx->ocsp_response = BUF_memdup(response, response_len);
+ if (ctx->ocsp_response == NULL) {
+ return 0;
+ }
+ ctx->ocsp_response_length = response_len;
+
+ return 1;
+}
+
+int SSL_select_next_proto(uint8_t **out, uint8_t *out_len,
+ const uint8_t *server, unsigned server_len,
+ const uint8_t *client, unsigned client_len) {
unsigned int i, j;
const uint8_t *result;
int status = OPENSSL_NPN_UNSUPPORTED;
@@ -1475,57 +1737,31 @@ int SSL_select_next_proto(uint8_t **out, uint8_t *outlen, const uint8_t *server,
found:
*out = (uint8_t *)result + 1;
- *outlen = result[0];
+ *out_len = result[0];
return status;
}
-/* SSL_get0_next_proto_negotiated sets *data and *len to point to the client's
- * requested protocol for this connection and returns 0. If the client didn't
- * request any protocol, then *data is set to NULL.
- *
- * Note that the client can request any protocol it chooses. The value returned
- * from this function need not be a member of the list of supported protocols
- * provided by the callback. */
-void SSL_get0_next_proto_negotiated(const SSL *s, const uint8_t **data,
- unsigned *len) {
- *data = s->next_proto_negotiated;
- if (!*data) {
- *len = 0;
+void SSL_get0_next_proto_negotiated(const SSL *ssl, const uint8_t **out_data,
+ unsigned *out_len) {
+ *out_data = ssl->next_proto_negotiated;
+ if (*out_data == NULL) {
+ *out_len = 0;
} else {
- *len = s->next_proto_negotiated_len;
+ *out_len = ssl->next_proto_negotiated_len;
}
}
-/* SSL_CTX_set_next_protos_advertised_cb sets a callback that is called when a
- * TLS server needs a list of supported protocols for Next Protocol
- * Negotiation. The returned list must be in wire format. The list is returned
- * by setting |out| to point to it and |outlen| to its length. This memory will
- * not be modified, but one should assume that the SSL* keeps a reference to
- * it.
- *
- * The callback should return SSL_TLSEXT_ERR_OK if it wishes to advertise.
- * Otherwise, no such extension will be included in the ServerHello. */
void SSL_CTX_set_next_protos_advertised_cb(
SSL_CTX *ctx,
- int (*cb)(SSL *ssl, const uint8_t **out, unsigned int *outlen, void *arg),
+ int (*cb)(SSL *ssl, const uint8_t **out, unsigned *out_len, void *arg),
void *arg) {
ctx->next_protos_advertised_cb = cb;
ctx->next_protos_advertised_cb_arg = arg;
}
-/* SSL_CTX_set_next_proto_select_cb sets a callback that is called when a
- * client needs to select a protocol from the server's provided list. |out|
- * must be set to point to the selected protocol (which may be within |in|).
- * The length of the protocol name must be written into |outlen|. The server's
- * advertised protocols are provided in |in| and |inlen|. The callback can
- * assume that |in| is syntactically valid.
- *
- * The client must select a protocol. It is fatal to the connection if this
- * callback returns a value other than SSL_TLSEXT_ERR_OK.
- */
void SSL_CTX_set_next_proto_select_cb(
- SSL_CTX *ctx, int (*cb)(SSL *s, uint8_t **out, uint8_t *outlen,
- const uint8_t *in, unsigned int inlen, void *arg),
+ SSL_CTX *ctx, int (*cb)(SSL *ssl, uint8_t **out, uint8_t *out_len,
+ const uint8_t *in, unsigned in_len, void *arg),
void *arg) {
ctx->next_proto_select_cb = cb;
ctx->next_proto_select_cb_arg = arg;
@@ -1554,32 +1790,25 @@ int SSL_set_alpn_protos(SSL *ssl, const uint8_t *protos, unsigned protos_len) {
return 0;
}
-/* SSL_CTX_set_alpn_select_cb sets a callback function on |ctx| that is called
- * during ClientHello processing in order to select an ALPN protocol from the
- * client's list of offered protocols. */
void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx,
int (*cb)(SSL *ssl, const uint8_t **out,
- uint8_t *outlen, const uint8_t *in,
- unsigned int inlen, void *arg),
+ uint8_t *out_len, const uint8_t *in,
+ unsigned in_len, void *arg),
void *arg) {
ctx->alpn_select_cb = cb;
ctx->alpn_select_cb_arg = arg;
}
-/* SSL_get0_alpn_selected gets the selected ALPN protocol (if any) from |ssl|.
- * On return it sets |*data| to point to |*len| bytes of protocol name (not
- * including the leading length-prefix byte). If the server didn't respond with
- * a negotiated protocol then |*len| will be zero. */
-void SSL_get0_alpn_selected(const SSL *ssl, const uint8_t **data,
- unsigned *len) {
- *data = NULL;
+void SSL_get0_alpn_selected(const SSL *ssl, const uint8_t **out_data,
+ unsigned *out_len) {
+ *out_data = NULL;
if (ssl->s3) {
- *data = ssl->s3->alpn_selected;
+ *out_data = ssl->s3->alpn_selected;
}
- if (*data == NULL) {
- *len = 0;
+ if (*out_data == NULL) {
+ *out_len = 0;
} else {
- *len = ssl->s3->alpn_selected_len;
+ *out_len = ssl->s3->alpn_selected_len;
}
}
@@ -1595,210 +1824,9 @@ int SSL_export_keying_material(SSL *s, uint8_t *out, size_t out_len,
s, out, out_len, label, label_len, context, context_len, use_context);
}
-static uint32_t ssl_session_hash(const SSL_SESSION *a) {
- uint32_t hash =
- ((uint32_t)a->session_id[0]) ||
- ((uint32_t)a->session_id[1] << 8) ||
- ((uint32_t)a->session_id[2] << 16) ||
- ((uint32_t)a->session_id[3] << 24);
-
- return hash;
-}
-
-/* NB: If this function (or indeed the hash function which uses a sort of
- * coarser function than this one) is changed, ensure
- * SSL_CTX_has_matching_session_id() is checked accordingly. It relies on being
- * able to construct an SSL_SESSION that will collide with any existing session
- * with a matching session ID. */
-static int ssl_session_cmp(const SSL_SESSION *a, const SSL_SESSION *b) {
- if (a->ssl_version != b->ssl_version) {
- return 1;
- }
-
- if (a->session_id_length != b->session_id_length) {
- return 1;
- }
-
- return memcmp(a->session_id, b->session_id, a->session_id_length);
-}
-
-SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) {
- SSL_CTX *ret = NULL;
-
- if (method == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_new, SSL_R_NULL_SSL_METHOD_PASSED);
- return NULL;
- }
-
- if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_new, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS);
- goto err;
- }
-
- ret = (SSL_CTX *)OPENSSL_malloc(sizeof(SSL_CTX));
- if (ret == NULL) {
- goto err;
- }
-
- memset(ret, 0, sizeof(SSL_CTX));
-
- ret->method = method->method;
-
- CRYPTO_MUTEX_init(&ret->lock);
-
- ret->cert_store = NULL;
- ret->session_cache_mode = SSL_SESS_CACHE_SERVER;
- ret->session_cache_size = SSL_SESSION_CACHE_MAX_SIZE_DEFAULT;
- ret->session_cache_head = NULL;
- ret->session_cache_tail = NULL;
-
- /* We take the system default */
- ret->session_timeout = SSL_DEFAULT_SESSION_TIMEOUT;
-
- ret->new_session_cb = 0;
- ret->remove_session_cb = 0;
- ret->get_session_cb = 0;
- ret->generate_session_id = 0;
-
- ret->references = 1;
- ret->quiet_shutdown = 0;
-
- ret->info_callback = NULL;
-
- ret->app_verify_callback = 0;
- ret->app_verify_arg = NULL;
-
- ret->max_cert_list = SSL_MAX_CERT_LIST_DEFAULT;
- ret->msg_callback = 0;
- ret->msg_callback_arg = NULL;
- ret->verify_mode = SSL_VERIFY_NONE;
- ret->sid_ctx_length = 0;
- ret->default_verify_callback = NULL;
- ret->cert = ssl_cert_new();
- if (ret->cert == NULL) {
- goto err;
- }
-
- ret->default_passwd_callback = 0;
- ret->default_passwd_callback_userdata = NULL;
- ret->client_cert_cb = 0;
-
- ret->sessions = lh_SSL_SESSION_new(ssl_session_hash, ssl_session_cmp);
- if (ret->sessions == NULL) {
- goto err;
- }
- ret->cert_store = X509_STORE_new();
- if (ret->cert_store == NULL) {
- goto err;
- }
-
- ssl_create_cipher_list(ret->method, &ret->cipher_list,
- &ret->cipher_list_by_id, SSL_DEFAULT_CIPHER_LIST);
- if (ret->cipher_list == NULL ||
- sk_SSL_CIPHER_num(ret->cipher_list->ciphers) <= 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_new, SSL_R_LIBRARY_HAS_NO_CIPHERS);
- goto err2;
- }
-
- ret->param = X509_VERIFY_PARAM_new();
- if (!ret->param) {
- goto err;
- }
-
- ret->client_CA = sk_X509_NAME_new_null();
- if (ret->client_CA == NULL) {
- goto err;
- }
-
- CRYPTO_new_ex_data(&g_ex_data_class_ssl_ctx, ret, &ret->ex_data);
-
- ret->extra_certs = NULL;
-
- ret->max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
-
- ret->tlsext_servername_callback = 0;
- ret->tlsext_servername_arg = NULL;
- /* Setup RFC4507 ticket keys */
- if (!RAND_bytes(ret->tlsext_tick_key_name, 16) ||
- !RAND_bytes(ret->tlsext_tick_hmac_key, 16) ||
- !RAND_bytes(ret->tlsext_tick_aes_key, 16)) {
- ret->options |= SSL_OP_NO_TICKET;
- }
-
- ret->next_protos_advertised_cb = 0;
- ret->next_proto_select_cb = 0;
- ret->psk_identity_hint = NULL;
- ret->psk_client_callback = NULL;
- ret->psk_server_callback = NULL;
-
- /* Default is to connect to non-RI servers. When RI is more widely deployed
- * might change this. */
- ret->options |= SSL_OP_LEGACY_SERVER_CONNECT;
-
- /* Lock the SSL_CTX to the specified version, for compatibility with legacy
- * uses of SSL_METHOD. */
- if (method->version != 0) {
- SSL_CTX_set_max_version(ret, method->version);
- SSL_CTX_set_min_version(ret, method->version);
- }
-
- return ret;
-
-err:
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_new, ERR_R_MALLOC_FAILURE);
-err2:
- SSL_CTX_free(ret);
- return NULL;
-}
-
-void SSL_CTX_free(SSL_CTX *ctx) {
- if (ctx == NULL ||
- !CRYPTO_refcount_dec_and_test_zero(&ctx->references)) {
- return;
- }
-
- X509_VERIFY_PARAM_free(ctx->param);
-
- /* Free internal session cache. However: the remove_cb() may reference the
- * ex_data of SSL_CTX, thus the ex_data store can only be removed after the
- * sessions were flushed. As the ex_data handling routines might also touch
- * the session cache, the most secure solution seems to be: empty (flush) the
- * cache, then free ex_data, then finally free the cache. (See ticket
- * [openssl.org #212].) */
- SSL_CTX_flush_sessions(ctx, 0);
-
- CRYPTO_free_ex_data(&g_ex_data_class_ssl_ctx, ctx, &ctx->ex_data);
-
- CRYPTO_MUTEX_cleanup(&ctx->lock);
- lh_SSL_SESSION_free(ctx->sessions);
- X509_STORE_free(ctx->cert_store);
- ssl_cipher_preference_list_free(ctx->cipher_list);
- sk_SSL_CIPHER_free(ctx->cipher_list_by_id);
- ssl_cipher_preference_list_free(ctx->cipher_list_tls11);
- ssl_cert_free(ctx->cert);
- sk_X509_NAME_pop_free(ctx->client_CA, X509_NAME_free);
- sk_X509_pop_free(ctx->extra_certs, X509_free);
- sk_SRTP_PROTECTION_PROFILE_free(ctx->srtp_profiles);
- OPENSSL_free(ctx->psk_identity_hint);
- OPENSSL_free(ctx->tlsext_ecpointformatlist);
- OPENSSL_free(ctx->tlsext_ellipticcurvelist);
- OPENSSL_free(ctx->alpn_client_proto_list);
- EVP_PKEY_free(ctx->tlsext_channel_id_private);
- BIO_free(ctx->keylog_bio);
-
- OPENSSL_free(ctx);
-}
-
-void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb) {
- ctx->default_passwd_callback = cb;
-}
-
-void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u) {
- ctx->default_passwd_callback_userdata = u;
-}
-
void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx,
- int (*cb)(X509_STORE_CTX *, void *),
+ int (*cb)(X509_STORE_CTX *store_ctx,
+ void *arg),
void *arg) {
ctx->app_verify_callback = cb;
ctx->app_verify_arg = arg;
@@ -1814,57 +1842,48 @@ void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) {
X509_VERIFY_PARAM_set_depth(ctx->param, depth);
}
-void SSL_CTX_set_cert_cb(SSL_CTX *c, int (*cb)(SSL *ssl, void *arg),
+void SSL_CTX_set_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, void *arg),
void *arg) {
- ssl_cert_set_cert_cb(c->cert, cb, arg);
+ ssl_cert_set_cert_cb(ctx->cert, cb, arg);
}
-void SSL_set_cert_cb(SSL *s, int (*cb)(SSL *ssl, void *arg), void *arg) {
- ssl_cert_set_cert_cb(s->cert, cb, arg);
-}
-
-static int ssl_has_key(SSL *s, size_t idx) {
- CERT_PKEY *cpk = &s->cert->pkeys[idx];
- return cpk->x509 && cpk->privatekey;
+void SSL_set_cert_cb(SSL *ssl, int (*cb)(SSL *ssl, void *arg), void *arg) {
+ ssl_cert_set_cert_cb(ssl->cert, cb, arg);
}
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;
+ int have_rsa_cert = 0, dh_tmp;
uint32_t mask_k, mask_a;
- int have_ecc_cert, ecdsa_ok;
+ int have_ecc_cert = 0, ecdsa_ok;
X509 *x;
- if (c == NULL) {
- /* TODO(davidben): Is this codepath possible? */
- *out_mask_k = 0;
- *out_mask_a = 0;
- return;
- }
-
dh_tmp = (c->dh_tmp != NULL || c->dh_tmp_cb != NULL);
- rsa_enc = ssl_has_key(s, SSL_PKEY_RSA_ENC);
- rsa_sign = ssl_has_key(s, SSL_PKEY_RSA_SIGN);
- have_ecc_cert = ssl_has_key(s, SSL_PKEY_ECC);
+ if (s->cert->x509 != NULL && ssl_has_private_key(s)) {
+ if (ssl_private_key_type(s) == EVP_PKEY_RSA) {
+ have_rsa_cert = 1;
+ } else if (ssl_private_key_type(s) == EVP_PKEY_EC) {
+ have_ecc_cert = 1;
+ }
+ }
+
mask_k = 0;
mask_a = 0;
- if (rsa_enc) {
- mask_k |= SSL_kRSA;
- }
if (dh_tmp) {
mask_k |= SSL_kDHE;
}
- if (rsa_enc || rsa_sign) {
+ if (have_rsa_cert) {
+ mask_k |= SSL_kRSA;
mask_a |= SSL_aRSA;
}
/* An ECC certificate may be usable for ECDSA cipher suites depending on the
* key usage extension and on the client's curve preferences. */
if (have_ecc_cert) {
- x = c->pkeys[SSL_PKEY_ECC].x509;
+ x = c->x509;
/* This call populates extension flags (ex_flags). */
X509_check_purpose(x, -1, 0);
ecdsa_ok = (x->ex_flags & EXFLAG_KUSAGE)
@@ -1894,81 +1913,6 @@ void ssl_get_compatible_server_ciphers(SSL *s, uint32_t *out_mask_k,
*out_mask_a = mask_a;
}
-/* This handy macro borrowed from crypto/x509v3/v3_purp.c */
-#define ku_reject(x, usage) \
- (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
-
-int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s) {
- const SSL_CIPHER *cs = s->s3->tmp.new_cipher;
- uint32_t alg_a = cs->algorithm_auth;
- int signature_nid = 0, md_nid = 0, pk_nid = 0;
-
- /* This call populates the ex_flags field correctly */
- X509_check_purpose(x, -1, 0);
- if (x->sig_alg && x->sig_alg->algorithm) {
- signature_nid = OBJ_obj2nid(x->sig_alg->algorithm);
- OBJ_find_sigid_algs(signature_nid, &md_nid, &pk_nid);
- }
- if (alg_a & SSL_aECDSA) {
- /* key usage, if present, must allow signing */
- if (ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE)) {
- OPENSSL_PUT_ERROR(SSL, ssl_check_srvr_ecc_cert_and_alg,
- SSL_R_ECC_CERT_NOT_FOR_SIGNING);
- return 0;
- }
- }
-
- return 1; /* all checks are ok */
-}
-
-static int ssl_get_server_cert_index(const SSL *s) {
- int idx;
- idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
- if (idx == SSL_PKEY_RSA_ENC && !s->cert->pkeys[SSL_PKEY_RSA_ENC].x509) {
- idx = SSL_PKEY_RSA_SIGN;
- }
- if (idx == -1) {
- OPENSSL_PUT_ERROR(SSL, ssl_get_server_cert_index, ERR_R_INTERNAL_ERROR);
- }
- return idx;
-}
-
-CERT_PKEY *ssl_get_server_send_pkey(const SSL *s) {
- int i = ssl_get_server_cert_index(s);
-
- /* This may or may not be an error. */
- if (i < 0) {
- return NULL;
- }
-
- /* May be NULL. */
- return &s->cert->pkeys[i];
-}
-
-EVP_PKEY *ssl_get_sign_pkey(SSL *s, const SSL_CIPHER *cipher) {
- uint32_t alg_a = cipher->algorithm_auth;
- CERT *c = s->cert;
- int idx = -1;
-
- if (alg_a & SSL_aRSA) {
- if (c->pkeys[SSL_PKEY_RSA_SIGN].privatekey != NULL) {
- idx = SSL_PKEY_RSA_SIGN;
- } else if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey != NULL) {
- idx = SSL_PKEY_RSA_ENC;
- }
- } else if ((alg_a & SSL_aECDSA) &&
- (c->pkeys[SSL_PKEY_ECC].privatekey != NULL)) {
- idx = SSL_PKEY_ECC;
- }
-
- if (idx == -1) {
- OPENSSL_PUT_ERROR(SSL, ssl_get_sign_pkey, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
-
- return c->pkeys[idx].privatekey;
-}
-
void ssl_update_cache(SSL *s, int mode) {
/* Never cache sessions with empty session IDs. */
if (s->session->session_id_length == 0) {
@@ -2014,143 +1958,6 @@ void ssl_update_cache(SSL *s, int mode) {
}
}
-int SSL_get_error(const SSL *s, int ret_code) {
- int reason;
- uint32_t err;
- BIO *bio;
-
- if (ret_code > 0) {
- return SSL_ERROR_NONE;
- }
-
- /* Make things return SSL_ERROR_SYSCALL when doing SSL_do_handshake etc,
- * where we do encode the error */
- err = ERR_peek_error();
- if (err != 0) {
- if (ERR_GET_LIB(err) == ERR_LIB_SYS) {
- return SSL_ERROR_SYSCALL;
- }
- return SSL_ERROR_SSL;
- }
-
- if (ret_code == 0) {
- if ((s->shutdown & SSL_RECEIVED_SHUTDOWN) &&
- (s->s3->warn_alert == SSL_AD_CLOSE_NOTIFY)) {
- /* The socket was cleanly shut down with a close_notify. */
- return SSL_ERROR_ZERO_RETURN;
- }
- /* An EOF was observed which violates the protocol, and the underlying
- * transport does not participate in the error queue. Bubble up to the
- * caller. */
- return SSL_ERROR_SYSCALL;
- }
-
- if (SSL_want_session(s)) {
- return SSL_ERROR_PENDING_SESSION;
- }
-
- if (SSL_want_certificate(s)) {
- return SSL_ERROR_PENDING_CERTIFICATE;
- }
-
- if (SSL_want_read(s)) {
- bio = SSL_get_rbio(s);
- if (BIO_should_read(bio)) {
- return SSL_ERROR_WANT_READ;
- }
-
- if (BIO_should_write(bio)) {
- /* This one doesn't make too much sense ... We never try to write to the
- * rbio, and an application program where rbio and wbio are separate
- * couldn't even know what it should wait for. However if we ever set
- * s->rwstate incorrectly (so that we have SSL_want_read(s) instead of
- * SSL_want_write(s)) and rbio and wbio *are* the same, this test works
- * around that bug; so it might be safer to keep it. */
- return SSL_ERROR_WANT_WRITE;
- }
-
- if (BIO_should_io_special(bio)) {
- reason = BIO_get_retry_reason(bio);
- if (reason == BIO_RR_CONNECT) {
- return SSL_ERROR_WANT_CONNECT;
- }
-
- if (reason == BIO_RR_ACCEPT) {
- return SSL_ERROR_WANT_ACCEPT;
- }
-
- return SSL_ERROR_SYSCALL; /* unknown */
- }
- }
-
- if (SSL_want_write(s)) {
- bio = SSL_get_wbio(s);
- if (BIO_should_write(bio)) {
- return SSL_ERROR_WANT_WRITE;
- }
-
- if (BIO_should_read(bio)) {
- /* See above (SSL_want_read(s) with BIO_should_write(bio)) */
- return SSL_ERROR_WANT_READ;
- }
-
- if (BIO_should_io_special(bio)) {
- reason = BIO_get_retry_reason(bio);
- if (reason == BIO_RR_CONNECT) {
- return SSL_ERROR_WANT_CONNECT;
- }
-
- if (reason == BIO_RR_ACCEPT) {
- return SSL_ERROR_WANT_ACCEPT;
- }
-
- return SSL_ERROR_SYSCALL;
- }
- }
-
- if (SSL_want_x509_lookup(s)) {
- return SSL_ERROR_WANT_X509_LOOKUP;
- }
-
- if (SSL_want_channel_id_lookup(s)) {
- return SSL_ERROR_WANT_CHANNEL_ID_LOOKUP;
- }
-
- return SSL_ERROR_SYSCALL;
-}
-
-int SSL_do_handshake(SSL *s) {
- int ret = 1;
-
- if (s->handshake_func == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_do_handshake, SSL_R_CONNECTION_TYPE_NOT_SET);
- return -1;
- }
-
- if (SSL_in_init(s)) {
- ret = s->handshake_func(s);
- }
- return ret;
-}
-
-void SSL_set_accept_state(SSL *ssl) {
- ssl->server = 1;
- ssl->shutdown = 0;
- ssl->state = SSL_ST_ACCEPT;
- ssl->handshake_func = ssl->method->ssl_accept;
- /* clear the current cipher */
- ssl_clear_cipher_ctx(ssl);
-}
-
-void SSL_set_connect_state(SSL *ssl) {
- ssl->server = 0;
- ssl->shutdown = 0;
- ssl->state = SSL_ST_CONNECT;
- ssl->handshake_func = ssl->method->ssl_connect;
- /* clear the current cipher */
- ssl_clear_cipher_ctx(ssl);
-}
-
static const char *ssl_get_version(int version) {
switch (version) {
case TLS1_2_VERSION:
@@ -2176,12 +1983,16 @@ static const char *ssl_get_version(int version) {
}
}
-const char *SSL_get_version(const SSL *s) {
- return ssl_get_version(s->version);
+const char *SSL_get_version(const SSL *ssl) {
+ return ssl_get_version(ssl->version);
+}
+
+const char *SSL_SESSION_get_version(const SSL_SESSION *session) {
+ return ssl_get_version(session->ssl_version);
}
-const char *SSL_SESSION_get_version(const SSL_SESSION *sess) {
- return ssl_get_version(sess->ssl_version);
+const char* SSL_get_curve_name(uint16_t curve_id) {
+ return tls1_ec_curve_id2name(curve_id);
}
void ssl_clear_cipher_ctx(SSL *s) {
@@ -2193,7 +2004,7 @@ void ssl_clear_cipher_ctx(SSL *s) {
X509 *SSL_get_certificate(const SSL *s) {
if (s->cert != NULL) {
- return s->cert->key->x509;
+ return s->cert->x509;
}
return NULL;
@@ -2201,7 +2012,7 @@ X509 *SSL_get_certificate(const SSL *s) {
EVP_PKEY *SSL_get_privatekey(const SSL *s) {
if (s->cert != NULL) {
- return s->cert->key->privatekey;
+ return s->cert->privatekey;
}
return NULL;
@@ -2209,7 +2020,7 @@ EVP_PKEY *SSL_get_privatekey(const SSL *s) {
X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) {
if (ctx->cert != NULL) {
- return ctx->cert->key->x509;
+ return ctx->cert->x509;
}
return NULL;
@@ -2217,22 +2028,22 @@ X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) {
EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx) {
if (ctx->cert != NULL) {
- return ctx->cert->key->privatekey;
+ return ctx->cert->privatekey;
}
return NULL;
}
-const SSL_CIPHER *SSL_get_current_cipher(const SSL *s) {
- if (s->aead_write_ctx == NULL) {
+const SSL_CIPHER *SSL_get_current_cipher(const SSL *ssl) {
+ if (ssl->aead_write_ctx == NULL) {
return NULL;
}
- return s->aead_write_ctx->cipher;
+ return ssl->aead_write_ctx->cipher;
}
-const void *SSL_get_current_compression(SSL *s) { return NULL; }
+const COMP_METHOD *SSL_get_current_compression(SSL *s) { return NULL; }
-const void *SSL_get_current_expansion(SSL *s) { return NULL; }
+const COMP_METHOD *SSL_get_current_expansion(SSL *s) { return NULL; }
int ssl_init_wbio_buffer(SSL *s, int push) {
BIO *bbio;
@@ -2252,7 +2063,7 @@ int ssl_init_wbio_buffer(SSL *s, int push) {
BIO_reset(bbio);
if (!BIO_set_read_buffer_size(bbio, 1)) {
- OPENSSL_PUT_ERROR(SSL, ssl_init_wbio_buffer, ERR_R_BUF_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
return 0;
}
@@ -2330,9 +2141,9 @@ int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx) {
return X509_STORE_set_default_paths(ctx->cert_store);
}
-int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
- const char *CApath) {
- return X509_STORE_load_locations(ctx->cert_store, CAfile, CApath);
+int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *ca_file,
+ const char *ca_dir) {
+ return X509_STORE_load_locations(ctx->cert_store, ca_file, ca_dir);
}
void SSL_set_info_callback(SSL *ssl,
@@ -2349,7 +2160,9 @@ int SSL_state(const SSL *ssl) { return ssl->state; }
void SSL_set_state(SSL *ssl, int state) { }
-void SSL_set_verify_result(SSL *ssl, long arg) { ssl->verify_result = arg; }
+void SSL_set_verify_result(SSL *ssl, long result) {
+ ssl->verify_result = result;
+}
long SSL_get_verify_result(const SSL *ssl) { return ssl->verify_result; }
@@ -2363,12 +2176,12 @@ int SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
return index;
}
-int SSL_set_ex_data(SSL *s, int idx, void *arg) {
- return CRYPTO_set_ex_data(&s->ex_data, idx, arg);
+int SSL_set_ex_data(SSL *ssl, int idx, void *arg) {
+ return CRYPTO_set_ex_data(&ssl->ex_data, idx, arg);
}
-void *SSL_get_ex_data(const SSL *s, int idx) {
- return CRYPTO_get_ex_data(&s->ex_data, idx);
+void *SSL_get_ex_data(const SSL *ssl, int idx) {
+ return CRYPTO_get_ex_data(&ssl->ex_data, idx);
}
int SSL_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
@@ -2382,12 +2195,12 @@ int SSL_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
return index;
}
-int SSL_CTX_set_ex_data(SSL_CTX *s, int idx, void *arg) {
- return CRYPTO_set_ex_data(&s->ex_data, idx, arg);
+int SSL_CTX_set_ex_data(SSL_CTX *ctx, int idx, void *arg) {
+ return CRYPTO_set_ex_data(&ctx->ex_data, idx, arg);
}
-void *SSL_CTX_get_ex_data(const SSL_CTX *s, int idx) {
- return CRYPTO_get_ex_data(&s->ex_data, idx);
+void *SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx) {
+ return CRYPTO_get_ex_data(&ctx->ex_data, idx);
}
X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) {
@@ -2435,8 +2248,7 @@ void SSL_set_tmp_ecdh_callback(SSL *ssl,
int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint) {
if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_psk_identity_hint,
- SSL_R_DATA_LENGTH_TOO_LONG);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
return 0;
}
@@ -2454,24 +2266,23 @@ int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint) {
return 1;
}
-int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint) {
- if (s == NULL) {
+int SSL_use_psk_identity_hint(SSL *ssl, const char *identity_hint) {
+ if (ssl == NULL) {
return 0;
}
if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN) {
- OPENSSL_PUT_ERROR(SSL, SSL_use_psk_identity_hint,
- SSL_R_DATA_LENGTH_TOO_LONG);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
return 0;
}
/* Clear currently configured hint, if any. */
- OPENSSL_free(s->psk_identity_hint);
- s->psk_identity_hint = NULL;
+ OPENSSL_free(ssl->psk_identity_hint);
+ ssl->psk_identity_hint = NULL;
if (identity_hint != NULL) {
- s->psk_identity_hint = BUF_strdup(identity_hint);
- if (s->psk_identity_hint == NULL) {
+ ssl->psk_identity_hint = BUF_strdup(identity_hint);
+ if (ssl->psk_identity_hint == NULL) {
return 0;
}
}
@@ -2479,63 +2290,47 @@ int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint) {
return 1;
}
-const char *SSL_get_psk_identity_hint(const SSL *s) {
- if (s == NULL) {
+const char *SSL_get_psk_identity_hint(const SSL *ssl) {
+ if (ssl == NULL) {
return NULL;
}
- return s->psk_identity_hint;
+ return ssl->psk_identity_hint;
}
-const char *SSL_get_psk_identity(const SSL *s) {
- if (s == NULL || s->session == NULL) {
+const char *SSL_get_psk_identity(const SSL *ssl) {
+ if (ssl == NULL || ssl->session == NULL) {
return NULL;
}
- return s->session->psk_identity;
+ return ssl->session->psk_identity;
}
void SSL_set_psk_client_callback(
- SSL *s, unsigned int (*cb)(SSL *ssl, const char *hint, char *identity,
- unsigned int max_identity_len, uint8_t *psk,
- unsigned int max_psk_len)) {
- s->psk_client_callback = cb;
+ SSL *ssl, unsigned (*cb)(SSL *ssl, const char *hint, char *identity,
+ unsigned max_identity_len, uint8_t *psk,
+ unsigned max_psk_len)) {
+ ssl->psk_client_callback = cb;
}
void SSL_CTX_set_psk_client_callback(
- SSL_CTX *ctx, unsigned int (*cb)(SSL *ssl, const char *hint, char *identity,
- unsigned int max_identity_len,
- uint8_t *psk, unsigned int max_psk_len)) {
+ SSL_CTX *ctx, unsigned (*cb)(SSL *ssl, const char *hint, char *identity,
+ unsigned max_identity_len, uint8_t *psk,
+ unsigned max_psk_len)) {
ctx->psk_client_callback = cb;
}
void SSL_set_psk_server_callback(
- SSL *s, unsigned int (*cb)(SSL *ssl, const char *identity, uint8_t *psk,
- unsigned int max_psk_len)) {
- s->psk_server_callback = cb;
+ SSL *ssl, unsigned (*cb)(SSL *ssl, const char *identity, uint8_t *psk,
+ unsigned max_psk_len)) {
+ ssl->psk_server_callback = cb;
}
void SSL_CTX_set_psk_server_callback(
- SSL_CTX *ctx, unsigned int (*cb)(SSL *ssl, const char *identity,
- uint8_t *psk, unsigned int max_psk_len)) {
+ SSL_CTX *ctx, unsigned (*cb)(SSL *ssl, const char *identity,
+ uint8_t *psk, unsigned max_psk_len)) {
ctx->psk_server_callback = cb;
}
-void SSL_CTX_set_min_version(SSL_CTX *ctx, uint16_t version) {
- ctx->min_version = version;
-}
-
-void SSL_CTX_set_max_version(SSL_CTX *ctx, uint16_t version) {
- ctx->max_version = version;
-}
-
-void SSL_set_min_version(SSL *ssl, uint16_t version) {
- ssl->min_version = version;
-}
-
-void SSL_set_max_version(SSL *ssl, uint16_t version) {
- ssl->max_version = version;
-}
-
void SSL_CTX_set_msg_callback(SSL_CTX *ctx,
void (*cb)(int write_p, int version,
int content_type, const void *buf,
@@ -2596,16 +2391,13 @@ int ssl_ctx_log_rsa_client_key_exchange(SSL_CTX *ctx,
}
if (encrypted_premaster_len < 8) {
- OPENSSL_PUT_ERROR(SSL, ssl_ctx_log_rsa_client_key_exchange,
- ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- if (!CBB_init(&cbb, 4 + 16 + 1 + premaster_len * 2 + 1)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
- if (!CBB_add_bytes(&cbb, (const uint8_t *)"RSA ", 4) ||
+ CBB_zero(&cbb);
+ if (!CBB_init(&cbb, 4 + 16 + 1 + premaster_len * 2 + 1) ||
+ !CBB_add_bytes(&cbb, (const uint8_t *)"RSA ", 4) ||
/* Only the first 8 bytes of the encrypted premaster secret are
* logged. */
!cbb_add_hex(&cbb, encrypted_premaster, 8) ||
@@ -2639,15 +2431,13 @@ int ssl_ctx_log_master_secret(SSL_CTX *ctx, const uint8_t *client_random,
}
if (client_random_len != 32) {
- OPENSSL_PUT_ERROR(SSL, ssl_ctx_log_master_secret, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
- if (!CBB_init(&cbb, 14 + 64 + 1 + master_len * 2 + 1)) {
- return 0;
- }
-
- if (!CBB_add_bytes(&cbb, (const uint8_t *)"CLIENT_RANDOM ", 14) ||
+ CBB_zero(&cbb);
+ if (!CBB_init(&cbb, 14 + 64 + 1 + master_len * 2 + 1) ||
+ !CBB_add_bytes(&cbb, (const uint8_t *)"CLIENT_RANDOM ", 14) ||
!cbb_add_hex(&cbb, client_random, 32) ||
!CBB_add_bytes(&cbb, (const uint8_t *)" ", 1) ||
!cbb_add_hex(&cbb, master, master_len) ||
@@ -2906,19 +2696,15 @@ uint16_t ssl3_version_from_wire(SSL *s, uint16_t wire_version) {
return version;
}
-int SSL_cache_hit(SSL *s) { return s->hit; }
+int SSL_cache_hit(SSL *ssl) { return SSL_session_reused(ssl); }
-int SSL_is_server(SSL *s) { return s->server; }
+int SSL_is_server(SSL *ssl) { return ssl->server; }
void SSL_CTX_set_dos_protection_cb(
SSL_CTX *ctx, int (*cb)(const struct ssl_early_callback_ctx *)) {
ctx->dos_protection_cb = cb;
}
-void SSL_enable_fastradio_padding(SSL *s, char on_off) {
- s->fastradio_padding = on_off;
-}
-
void SSL_set_reject_peer_renegotiations(SSL *s, int reject) {
s->accept_peer_renegotiations = !reject;
}
@@ -2933,43 +2719,73 @@ int SSL_get_rc4_state(const SSL *ssl, const RC4_KEY **read_key,
EVP_AEAD_CTX_get_rc4_state(&ssl->aead_write_ctx->ctx, write_key);
}
-int SSL_get_tls_unique(const SSL *ssl, uint8_t *out, size_t *out_len,
- size_t max_out) {
- /* The tls-unique value is the first Finished message in the handshake, which
- * is the client's in a full handshake and the server's for a resumption. See
- * https://tools.ietf.org/html/rfc5929#section-3.1. */
- const uint8_t *finished = ssl->s3->previous_client_finished;
- size_t finished_len = ssl->s3->previous_client_finished_len;
- if (ssl->hit) {
- /* tls-unique is broken for resumed sessions unless EMS is used. */
- if (!ssl->session->extended_master_secret) {
- goto err;
+int SSL_clear(SSL *ssl) {
+ if (ssl->method == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_METHOD_SPECIFIED);
+ return 0;
+ }
+
+ if (ssl_clear_bad_session(ssl)) {
+ SSL_SESSION_free(ssl->session);
+ ssl->session = NULL;
+ }
+
+ ssl->hit = 0;
+ ssl->shutdown = 0;
+
+ /* SSL_clear may be called before or after the |ssl| is initialized in either
+ * accept or connect state. In the latter case, SSL_clear should preserve the
+ * half and reset |ssl->state| accordingly. */
+ if (ssl->handshake_func != NULL) {
+ if (ssl->server) {
+ SSL_set_accept_state(ssl);
+ } else {
+ SSL_set_connect_state(ssl);
}
- finished = ssl->s3->previous_server_finished;
- finished_len = ssl->s3->previous_server_finished_len;
+ } else {
+ assert(ssl->state == 0);
}
- if (!ssl->s3->initial_handshake_complete ||
- ssl->version < TLS1_VERSION) {
- goto err;
+ /* TODO(davidben): Some state on |ssl| is reset both in |SSL_new| and
+ * |SSL_clear| because it is per-connection state rather than configuration
+ * state. Per-connection state should be on |ssl->s3| and |ssl->d1| so it is
+ * naturally reset at the right points between |SSL_new|, |SSL_clear|, and
+ * |ssl3_new|. */
+
+ ssl->rwstate = SSL_NOTHING;
+
+ BUF_MEM_free(ssl->init_buf);
+ ssl->init_buf = NULL;
+
+ ssl_clear_cipher_ctx(ssl);
+
+ OPENSSL_free(ssl->next_proto_negotiated);
+ ssl->next_proto_negotiated = NULL;
+ ssl->next_proto_negotiated_len = 0;
+
+ /* The ssl->d1->mtu is simultaneously configuration (preserved across
+ * clear) and connection-specific state (gets reset).
+ *
+ * TODO(davidben): Avoid this. */
+ unsigned mtu = 0;
+ if (ssl->d1 != NULL) {
+ mtu = ssl->d1->mtu;
}
- *out_len = finished_len;
- if (finished_len > max_out) {
- *out_len = max_out;
+ ssl->method->ssl_free(ssl);
+ if (!ssl->method->ssl_new(ssl)) {
+ return 0;
}
+ ssl->enc_method = ssl3_get_enc_method(ssl->version);
+ assert(ssl->enc_method != NULL);
- memcpy(out, finished, *out_len);
- return 1;
+ if (SSL_IS_DTLS(ssl) && (SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) {
+ ssl->d1->mtu = mtu;
+ }
-err:
- *out_len = 0;
- memset(out, 0, max_out);
- return 0;
-}
+ ssl->client_version = ssl->version;
-int SSL_initial_handshake_complete(const SSL *ssl) {
- return ssl->s3->initial_handshake_complete;
+ return 1;
}
int SSL_CTX_sess_connect(const SSL_CTX *ctx) { return 0; }
@@ -2983,3 +2799,5 @@ int SSL_CTX_sess_cb_hits(const SSL_CTX *ctx) { return 0; }
int SSL_CTX_sess_misses(const SSL_CTX *ctx) { return 0; }
int SSL_CTX_sess_timeouts(const SSL_CTX *ctx) { return 0; }
int SSL_CTX_sess_cache_full(const SSL_CTX *ctx) { return 0; }
+void ERR_load_SSL_strings(void) {}
+void SSL_load_error_strings(void) {}
diff --git a/src/ssl/ssl_rsa.c b/src/ssl/ssl_rsa.c
index 87f4c1c..ccd3858 100644
--- a/src/ssl/ssl_rsa.c
+++ b/src/ssl/ssl_rsa.c
@@ -54,79 +54,38 @@
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
-#include <stdio.h>
+#include <openssl/ssl.h>
-#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
-#include <openssl/pem.h>
#include <openssl/x509.h>
#include "internal.h"
+
static int ssl_set_cert(CERT *c, X509 *x509);
static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey);
+static int is_key_type_supported(int key_type) {
+ return key_type == EVP_PKEY_RSA || key_type == EVP_PKEY_EC;
+}
+
int SSL_use_certificate(SSL *ssl, X509 *x) {
if (x == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_use_certificate, ERR_R_PASSED_NULL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
return ssl_set_cert(ssl->cert, x);
}
-int SSL_use_certificate_file(SSL *ssl, const char *file, int type) {
- int reason_code;
- BIO *in;
- int ret = 0;
- X509 *x = NULL;
-
- in = BIO_new(BIO_s_file());
- if (in == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_use_certificate_file, ERR_R_BUF_LIB);
- goto end;
- }
-
- if (BIO_read_filename(in, file) <= 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_use_certificate_file, ERR_R_SYS_LIB);
- goto end;
- }
-
- if (type == SSL_FILETYPE_ASN1) {
- reason_code = ERR_R_ASN1_LIB;
- x = d2i_X509_bio(in, NULL);
- } else if (type == SSL_FILETYPE_PEM) {
- reason_code = ERR_R_PEM_LIB;
- x = PEM_read_bio_X509(in, NULL, ssl->ctx->default_passwd_callback,
- ssl->ctx->default_passwd_callback_userdata);
- } else {
- OPENSSL_PUT_ERROR(SSL, SSL_use_certificate_file, SSL_R_BAD_SSL_FILETYPE);
- goto end;
- }
-
- if (x == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_use_certificate_file, reason_code);
- goto end;
- }
-
- ret = SSL_use_certificate(ssl, x);
-
-end:
- X509_free(x);
- BIO_free(in);
-
- return ret;
-}
-
int SSL_use_certificate_ASN1(SSL *ssl, const uint8_t *d, int len) {
X509 *x;
int ret;
x = d2i_X509(NULL, &d, (long)len);
if (x == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_use_certificate_ASN1, ERR_R_ASN1_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB);
return 0;
}
@@ -140,13 +99,13 @@ int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) {
int ret;
if (rsa == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey, ERR_R_PASSED_NULL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
pkey = EVP_PKEY_new();
if (pkey == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey, ERR_R_EVP_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_EVP_LIB);
return 0;
}
@@ -160,86 +119,36 @@ int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) {
}
static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) {
- int i;
-
- i = ssl_cert_type(pkey);
- if (i < 0) {
- OPENSSL_PUT_ERROR(SSL, ssl_set_pkey, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+ if (!is_key_type_supported(pkey->type)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
return 0;
}
- if (c->pkeys[i].x509 != NULL) {
+ if (c->x509 != NULL) {
/* Sanity-check that the private key and the certificate match, unless the
* key is opaque (in case of, say, a smartcard). */
if (!EVP_PKEY_is_opaque(pkey) &&
- !X509_check_private_key(c->pkeys[i].x509, pkey)) {
- X509_free(c->pkeys[i].x509);
- c->pkeys[i].x509 = NULL;
+ !X509_check_private_key(c->x509, pkey)) {
+ X509_free(c->x509);
+ c->x509 = NULL;
return 0;
}
}
- EVP_PKEY_free(c->pkeys[i].privatekey);
- c->pkeys[i].privatekey = EVP_PKEY_up_ref(pkey);
- c->key = &(c->pkeys[i]);
+ EVP_PKEY_free(c->privatekey);
+ c->privatekey = EVP_PKEY_up_ref(pkey);
return 1;
}
-int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type) {
- int reason_code, ret = 0;
- BIO *in;
- RSA *rsa = NULL;
-
- in = BIO_new(BIO_s_file());
- if (in == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey_file, ERR_R_BUF_LIB);
- goto end;
- }
-
- if (BIO_read_filename(in, file) <= 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey_file, ERR_R_SYS_LIB);
- goto end;
- }
-
- if (type == SSL_FILETYPE_ASN1) {
- reason_code = ERR_R_ASN1_LIB;
- rsa = d2i_RSAPrivateKey_bio(in, NULL);
- } else if (type == SSL_FILETYPE_PEM) {
- reason_code = ERR_R_PEM_LIB;
- rsa =
- PEM_read_bio_RSAPrivateKey(in, NULL, ssl->ctx->default_passwd_callback,
- ssl->ctx->default_passwd_callback_userdata);
- } else {
- OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey_file, SSL_R_BAD_SSL_FILETYPE);
- goto end;
- }
-
- if (rsa == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey_file, reason_code);
- goto end;
- }
- ret = SSL_use_RSAPrivateKey(ssl, rsa);
- RSA_free(rsa);
-
-end:
- BIO_free(in);
- return ret;
-}
-
-int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, uint8_t *d, long len) {
- int ret;
- const uint8_t *p;
- RSA *rsa;
-
- p = d;
- rsa = d2i_RSAPrivateKey(NULL, &p, (long)len);
+int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, const uint8_t *der, size_t der_len) {
+ RSA *rsa = RSA_private_key_from_bytes(der, der_len);
if (rsa == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey_ASN1, ERR_R_ASN1_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB);
return 0;
}
- ret = SSL_use_RSAPrivateKey(ssl, rsa);
+ int ret = SSL_use_RSAPrivateKey(ssl, rsa);
RSA_free(rsa);
return ret;
}
@@ -248,7 +157,7 @@ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) {
int ret;
if (pkey == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey, ERR_R_PASSED_NULL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
@@ -256,46 +165,6 @@ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) {
return ret;
}
-int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type) {
- int reason_code, ret = 0;
- BIO *in;
- EVP_PKEY *pkey = NULL;
-
- in = BIO_new(BIO_s_file());
- if (in == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey_file, ERR_R_BUF_LIB);
- goto end;
- }
-
- if (BIO_read_filename(in, file) <= 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey_file, ERR_R_SYS_LIB);
- goto end;
- }
-
- if (type == SSL_FILETYPE_PEM) {
- reason_code = ERR_R_PEM_LIB;
- pkey = PEM_read_bio_PrivateKey(in, NULL, ssl->ctx->default_passwd_callback,
- ssl->ctx->default_passwd_callback_userdata);
- } else if (type == SSL_FILETYPE_ASN1) {
- reason_code = ERR_R_ASN1_LIB;
- pkey = d2i_PrivateKey_bio(in, NULL);
- } else {
- OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey_file, SSL_R_BAD_SSL_FILETYPE);
- goto end;
- }
-
- if (pkey == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey_file, reason_code);
- goto end;
- }
- ret = SSL_use_PrivateKey(ssl, pkey);
- EVP_PKEY_free(pkey);
-
-end:
- BIO_free(in);
- return ret;
-}
-
int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const uint8_t *d, long len) {
int ret;
const uint8_t *p;
@@ -304,7 +173,7 @@ int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const uint8_t *d, long len) {
p = d;
pkey = d2i_PrivateKey(type, NULL, &p, (long)len);
if (pkey == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey_ASN1, ERR_R_ASN1_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB);
return 0;
}
@@ -315,8 +184,7 @@ int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const uint8_t *d, long len) {
int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) {
if (x == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate,
- ERR_R_PASSED_NULL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
@@ -324,32 +192,28 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) {
}
static int ssl_set_cert(CERT *c, X509 *x) {
- EVP_PKEY *pkey;
- int i;
-
- pkey = X509_get_pubkey(x);
+ EVP_PKEY *pkey = X509_get_pubkey(x);
if (pkey == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl_set_cert, SSL_R_X509_LIB);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_X509_LIB);
return 0;
}
- i = ssl_cert_type(pkey);
- if (i < 0) {
- OPENSSL_PUT_ERROR(SSL, ssl_set_cert, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+ if (!is_key_type_supported(pkey->type)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
EVP_PKEY_free(pkey);
return 0;
}
- if (c->pkeys[i].privatekey != NULL) {
+ if (c->privatekey != NULL) {
/* Sanity-check that the private key and the certificate match, unless the
* key is opaque (in case of, say, a smartcard). */
- if (!EVP_PKEY_is_opaque(c->pkeys[i].privatekey) &&
- !X509_check_private_key(x, c->pkeys[i].privatekey)) {
+ if (!EVP_PKEY_is_opaque(c->privatekey) &&
+ !X509_check_private_key(x, c->privatekey)) {
/* don't fail for a cert/key mismatch, just free current private key
* (when switching to a different cert & key, first this function should
* be used, then ssl_set_pkey */
- EVP_PKEY_free(c->pkeys[i].privatekey);
- c->pkeys[i].privatekey = NULL;
+ EVP_PKEY_free(c->privatekey);
+ c->privatekey = NULL;
/* clear error queue */
ERR_clear_error();
}
@@ -357,63 +221,19 @@ static int ssl_set_cert(CERT *c, X509 *x) {
EVP_PKEY_free(pkey);
- X509_free(c->pkeys[i].x509);
- c->pkeys[i].x509 = X509_up_ref(x);
- c->key = &(c->pkeys[i]);
+ X509_free(c->x509);
+ c->x509 = X509_up_ref(x);
return 1;
}
-int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) {
- int reason_code;
- BIO *in;
- int ret = 0;
- X509 *x = NULL;
-
- in = BIO_new(BIO_s_file());
- if (in == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_file, ERR_R_BUF_LIB);
- goto end;
- }
-
- if (BIO_read_filename(in, file) <= 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_file, ERR_R_SYS_LIB);
- goto end;
- }
-
- if (type == SSL_FILETYPE_ASN1) {
- reason_code = ERR_R_ASN1_LIB;
- x = d2i_X509_bio(in, NULL);
- } else if (type == SSL_FILETYPE_PEM) {
- reason_code = ERR_R_PEM_LIB;
- x = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback,
- ctx->default_passwd_callback_userdata);
- } else {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_file,
- SSL_R_BAD_SSL_FILETYPE);
- goto end;
- }
-
- if (x == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_file, reason_code);
- goto end;
- }
-
- ret = SSL_CTX_use_certificate(ctx, x);
-
-end:
- X509_free(x);
- BIO_free(in);
- return ret;
-}
-
int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const uint8_t *d) {
X509 *x;
int ret;
x = d2i_X509(NULL, &d, (long)len);
if (x == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_ASN1, ERR_R_ASN1_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB);
return 0;
}
@@ -427,14 +247,13 @@ int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa) {
EVP_PKEY *pkey;
if (rsa == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey,
- ERR_R_PASSED_NULL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
pkey = EVP_PKEY_new();
if (pkey == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey, ERR_R_EVP_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_EVP_LIB);
return 0;
}
@@ -446,113 +265,28 @@ int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa) {
return ret;
}
-int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type) {
- int reason_code, ret = 0;
- BIO *in;
- RSA *rsa = NULL;
-
- in = BIO_new(BIO_s_file());
- if (in == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey_file, ERR_R_BUF_LIB);
- goto end;
- }
-
- if (BIO_read_filename(in, file) <= 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey_file, ERR_R_SYS_LIB);
- goto end;
- }
-
- if (type == SSL_FILETYPE_ASN1) {
- reason_code = ERR_R_ASN1_LIB;
- rsa = d2i_RSAPrivateKey_bio(in, NULL);
- } else if (type == SSL_FILETYPE_PEM) {
- reason_code = ERR_R_PEM_LIB;
- rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ctx->default_passwd_callback,
- ctx->default_passwd_callback_userdata);
- } else {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey_file,
- SSL_R_BAD_SSL_FILETYPE);
- goto end;
- }
-
- if (rsa == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey_file, reason_code);
- goto end;
- }
- ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa);
- RSA_free(rsa);
-
-end:
- BIO_free(in);
- return ret;
-}
-
-int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const uint8_t *d, long len) {
- int ret;
- const uint8_t *p;
- RSA *rsa;
-
- p = d;
- rsa = d2i_RSAPrivateKey(NULL, &p, (long)len);
+int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const uint8_t *der,
+ size_t der_len) {
+ RSA *rsa = RSA_private_key_from_bytes(der, der_len);
if (rsa == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey_ASN1, ERR_R_ASN1_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB);
return 0;
}
- ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa);
+ int ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa);
RSA_free(rsa);
return ret;
}
int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) {
if (pkey == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey, ERR_R_PASSED_NULL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
return ssl_set_pkey(ctx->cert, pkey);
}
-int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) {
- int reason_code, ret = 0;
- BIO *in;
- EVP_PKEY *pkey = NULL;
-
- in = BIO_new(BIO_s_file());
- if (in == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey_file, ERR_R_BUF_LIB);
- goto end;
- }
-
- if (BIO_read_filename(in, file) <= 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey_file, ERR_R_SYS_LIB);
- goto end;
- }
-
- if (type == SSL_FILETYPE_PEM) {
- reason_code = ERR_R_PEM_LIB;
- pkey = PEM_read_bio_PrivateKey(in, NULL, ctx->default_passwd_callback,
- ctx->default_passwd_callback_userdata);
- } else if (type == SSL_FILETYPE_ASN1) {
- reason_code = ERR_R_ASN1_LIB;
- pkey = d2i_PrivateKey_bio(in, NULL);
- } else {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey_file, SSL_R_BAD_SSL_FILETYPE);
- goto end;
- }
-
- if (pkey == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey_file, reason_code);
- goto end;
- }
- ret = SSL_CTX_use_PrivateKey(ctx, pkey);
- EVP_PKEY_free(pkey);
-
-end:
- BIO_free(in);
- return ret;
-}
-
int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, const uint8_t *d,
long len) {
int ret;
@@ -562,7 +296,7 @@ int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, const uint8_t *d,
p = d;
pkey = d2i_PrivateKey(type, NULL, &p, (long)len);
if (pkey == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey_ASN1, ERR_R_ASN1_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB);
return 0;
}
@@ -571,76 +305,74 @@ int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, const uint8_t *d,
return ret;
}
+void SSL_set_private_key_method(SSL *ssl,
+ const SSL_PRIVATE_KEY_METHOD *key_method) {
+ ssl->cert->key_method = key_method;
+}
-/* Read a file that contains our certificate in "PEM" format, possibly followed
- * by a sequence of CA certificates that should be sent to the peer in the
- * Certificate message. */
-int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) {
- BIO *in;
- int ret = 0;
- X509 *x = NULL;
-
- ERR_clear_error(); /* clear error stack for SSL_CTX_use_certificate() */
+int SSL_set_private_key_digest_prefs(SSL *ssl, const int *digest_nids,
+ size_t num_digests) {
+ OPENSSL_free(ssl->cert->digest_nids);
- in = BIO_new(BIO_s_file());
- if (in == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_chain_file, ERR_R_BUF_LIB);
- goto end;
+ ssl->cert->num_digest_nids = 0;
+ ssl->cert->digest_nids = BUF_memdup(digest_nids, num_digests*sizeof(int));
+ if (ssl->cert->digest_nids == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
}
- if (BIO_read_filename(in, file) <= 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_chain_file, ERR_R_SYS_LIB);
- goto end;
- }
+ ssl->cert->num_digest_nids = num_digests;
+ return 1;
+}
- x = PEM_read_bio_X509_AUX(in, NULL, ctx->default_passwd_callback,
- ctx->default_passwd_callback_userdata);
- if (x == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_chain_file, ERR_R_PEM_LIB);
- goto end;
+int ssl_has_private_key(SSL *ssl) {
+ return ssl->cert->privatekey != NULL || ssl->cert->key_method != NULL;
+}
+
+int ssl_private_key_type(SSL *ssl) {
+ if (ssl->cert->key_method != NULL) {
+ return ssl->cert->key_method->type(ssl);
}
+ return EVP_PKEY_id(ssl->cert->privatekey);
+}
- ret = SSL_CTX_use_certificate(ctx, x);
+size_t ssl_private_key_max_signature_len(SSL *ssl) {
+ if (ssl->cert->key_method != NULL) {
+ return ssl->cert->key_method->max_signature_len(ssl);
+ }
+ return EVP_PKEY_size(ssl->cert->privatekey);
+}
- if (ERR_peek_error() != 0) {
- ret = 0; /* Key/certificate mismatch doesn't imply ret==0 ... */
+enum ssl_private_key_result_t ssl_private_key_sign(
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, const EVP_MD *md,
+ const uint8_t *in, size_t in_len) {
+ if (ssl->cert->key_method != NULL) {
+ return ssl->cert->key_method->sign(ssl, out, out_len, max_out, md, in,
+ in_len);
}
- if (ret) {
- /* If we could set up our certificate, now proceed to the CA
- * certificates. */
- X509 *ca;
- int r;
- uint32_t err;
-
- SSL_CTX_clear_chain_certs(ctx);
-
- while ((ca = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback,
- ctx->default_passwd_callback_userdata)) !=
- NULL) {
- r = SSL_CTX_add0_chain_cert(ctx, ca);
- if (!r) {
- X509_free(ca);
- ret = 0;
- goto end;
- }
- /* Note that we must not free r if it was successfully added to the chain
- * (while we must free the main certificate, since its reference count is
- * increased by SSL_CTX_use_certificate). */
- }
+ enum ssl_private_key_result_t ret = ssl_private_key_failure;
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(ssl->cert->privatekey, NULL);
+ if (ctx == NULL) {
+ goto end;
+ }
- /* When the while loop ends, it's usually just EOF. */
- err = ERR_peek_last_error();
- if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
- ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
- ERR_clear_error();
- } else {
- ret = 0; /* some real error */
- }
+ size_t len = max_out;
+ if (!EVP_PKEY_sign_init(ctx) ||
+ !EVP_PKEY_CTX_set_signature_md(ctx, md) ||
+ !EVP_PKEY_sign(ctx, out, &len, in, in_len)) {
+ goto end;
}
+ *out_len = len;
+ ret = ssl_private_key_success;
end:
- X509_free(x);
- BIO_free(in);
+ EVP_PKEY_CTX_free(ctx);
return ret;
}
+
+enum ssl_private_key_result_t ssl_private_key_sign_complete(
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out) {
+ /* Only custom keys may be asynchronous. */
+ return ssl->cert->key_method->sign_complete(ssl, out, out_len, max_out);
+}
diff --git a/src/ssl/ssl_sess.c b/src/ssl/ssl_session.c
index 9ab4585..345aca2 100644
--- a/src/ssl/ssl_sess.c
+++ b/src/ssl/ssl_session.c
@@ -133,6 +133,9 @@
* OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
* OTHERWISE. */
+#include <openssl/ssl.h>
+
+#include <assert.h>
#include <stdio.h>
#include <string.h>
@@ -150,11 +153,111 @@
* 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 CRYPTO_EX_DATA_CLASS g_ex_data_class =
+ CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA;
+
+static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *session);
+static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *session);
+static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock);
+
+SSL_SESSION *SSL_SESSION_new(void) {
+ SSL_SESSION *session = (SSL_SESSION *)OPENSSL_malloc(sizeof(SSL_SESSION));
+ if (session == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ memset(session, 0, sizeof(SSL_SESSION));
+
+ session->verify_result = 1; /* avoid 0 (= X509_V_OK) just in case */
+ session->references = 1;
+ session->timeout = SSL_DEFAULT_SESSION_TIMEOUT;
+ session->time = (unsigned long)time(NULL);
+ CRYPTO_new_ex_data(&g_ex_data_class, session, &session->ex_data);
+ return session;
+}
+
+SSL_SESSION *SSL_SESSION_up_ref(SSL_SESSION *session) {
+ if (session != NULL) {
+ CRYPTO_refcount_inc(&session->references);
+ }
+ return session;
+}
+
+void SSL_SESSION_free(SSL_SESSION *session) {
+ if (session == NULL ||
+ !CRYPTO_refcount_dec_and_test_zero(&session->references)) {
+ return;
+ }
+
+ CRYPTO_free_ex_data(&g_ex_data_class, session, &session->ex_data);
+
+ OPENSSL_cleanse(session->master_key, sizeof(session->master_key));
+ OPENSSL_cleanse(session->session_id, sizeof(session->session_id));
+ X509_free(session->peer);
+ sk_X509_pop_free(session->cert_chain, X509_free);
+ OPENSSL_free(session->tlsext_hostname);
+ OPENSSL_free(session->tlsext_tick);
+ OPENSSL_free(session->tlsext_signed_cert_timestamp_list);
+ OPENSSL_free(session->ocsp_response);
+ OPENSSL_free(session->psk_identity);
+ OPENSSL_cleanse(session, sizeof(*session));
+ OPENSSL_free(session);
+}
+
+const uint8_t *SSL_SESSION_get_id(const SSL_SESSION *session,
+ unsigned *out_len) {
+ if (out_len != NULL) {
+ *out_len = session->session_id_length;
+ }
+ return session->session_id;
+}
+
+long SSL_SESSION_get_timeout(const SSL_SESSION *session) {
+ return session->timeout;
+}
+
+long SSL_SESSION_get_time(const SSL_SESSION *session) {
+ return session->time;
+}
+
+uint32_t SSL_SESSION_get_key_exchange_info(const SSL_SESSION *session) {
+ return session->key_exchange_info;
+}
+
+X509 *SSL_SESSION_get0_peer(const SSL_SESSION *session) {
+ return session->peer;
+}
+
+long SSL_SESSION_set_time(SSL_SESSION *session, long time) {
+ if (session == NULL) {
+ return 0;
+ }
+
+ session->time = time;
+ return time;
+}
+
+long SSL_SESSION_set_timeout(SSL_SESSION *session, long timeout) {
+ if (session == NULL) {
+ return 0;
+ }
-static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s);
-static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s);
-static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck);
+ session->timeout = timeout;
+ return 1;
+}
+
+int SSL_SESSION_set1_id_context(SSL_SESSION *session, const uint8_t *sid_ctx,
+ unsigned sid_ctx_len) {
+ if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
+ return 0;
+ }
+
+ session->sid_ctx_length = sid_ctx_len;
+ memcpy(session->sid_ctx, sid_ctx, sid_ctx_len);
+
+ return 1;
+}
SSL_SESSION *SSL_magic_pending_session_ptr(void) {
return (SSL_SESSION *)&g_pending_session_magic;
@@ -182,37 +285,12 @@ int SSL_SESSION_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
return index;
}
-int SSL_SESSION_set_ex_data(SSL_SESSION *s, int idx, void *arg) {
- return CRYPTO_set_ex_data(&s->ex_data, idx, arg);
-}
-
-void *SSL_SESSION_get_ex_data(const SSL_SESSION *s, int idx) {
- return CRYPTO_get_ex_data(&s->ex_data, idx);
+int SSL_SESSION_set_ex_data(SSL_SESSION *session, int idx, void *arg) {
+ return CRYPTO_set_ex_data(&session->ex_data, idx, arg);
}
-SSL_SESSION *SSL_SESSION_new(void) {
- SSL_SESSION *ss;
-
- ss = (SSL_SESSION *)OPENSSL_malloc(sizeof(SSL_SESSION));
- if (ss == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_new, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- memset(ss, 0, sizeof(SSL_SESSION));
-
- ss->verify_result = 1; /* avoid 0 (= X509_V_OK) just in case */
- ss->references = 1;
- ss->timeout = SSL_DEFAULT_SESSION_TIMEOUT;
- ss->time = (unsigned long)time(NULL);
- CRYPTO_new_ex_data(&g_ex_data_class, ss, &ss->ex_data);
- return ss;
-}
-
-const uint8_t *SSL_SESSION_get_id(const SSL_SESSION *s, unsigned int *len) {
- if (len) {
- *len = s->session_id_length;
- }
- return s->session_id;
+void *SSL_SESSION_get_ex_data(const SSL_SESSION *session, int idx) {
+ return CRYPTO_get_ex_data(&session->ex_data, idx);
}
/* Even with SSLv2, we have 16 bytes (128 bits) of session ID space.
@@ -225,9 +303,9 @@ const uint8_t *SSL_SESSION_get_id(const SSL_SESSION *s, unsigned int *len) {
* server. How you might store that many sessions is perhaps a more interesting
* question ... */
static int def_generate_session_id(const SSL *ssl, uint8_t *id,
- unsigned int *id_len) {
+ unsigned *id_len) {
static const unsigned kMaxAttempts = 10;
- unsigned int retry = 0;
+ unsigned retry = 0;
do {
if (!RAND_bytes(id, *id_len)) {
return 0;
@@ -257,8 +335,7 @@ int ssl_get_new_session(SSL *s, int session) {
GEN_SESSION_CB cb = def_generate_session_id;
if (s->mode & SSL_MODE_NO_SESSION_CREATION) {
- OPENSSL_PUT_ERROR(SSL, ssl_get_new_session,
- SSL_R_SESSION_MAY_NOT_BE_CREATED);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SESSION_MAY_NOT_BE_CREATED);
return 0;
}
@@ -282,8 +359,7 @@ int ssl_get_new_session(SSL *s, int session) {
ss->ssl_version = s->version;
ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
} else {
- OPENSSL_PUT_ERROR(SSL, ssl_get_new_session,
- SSL_R_UNSUPPORTED_SSL_VERSION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_SSL_VERSION);
SSL_SESSION_free(ss);
return 0;
}
@@ -305,8 +381,7 @@ int ssl_get_new_session(SSL *s, int session) {
tmp = ss->session_id_length;
if (!cb(s, ss->session_id, &tmp)) {
/* The callback failed */
- OPENSSL_PUT_ERROR(SSL, ssl_get_new_session,
- SSL_R_SSL_SESSION_ID_CALLBACK_FAILED);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CALLBACK_FAILED);
SSL_SESSION_free(ss);
return 0;
}
@@ -315,8 +390,7 @@ int ssl_get_new_session(SSL *s, int session) {
* higher than it was. */
if (!tmp || tmp > ss->session_id_length) {
/* The callback set an illegal length */
- OPENSSL_PUT_ERROR(SSL, ssl_get_new_session,
- SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH);
SSL_SESSION_free(ss);
return 0;
}
@@ -324,8 +398,7 @@ int ssl_get_new_session(SSL *s, int session) {
ss->session_id_length = tmp;
/* Finally, check for a conflict */
if (SSL_has_matching_session_id(s, ss->session_id, ss->session_id_length)) {
- OPENSSL_PUT_ERROR(SSL, ssl_get_new_session,
- SSL_R_SSL_SESSION_ID_CONFLICT);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONFLICT);
SSL_SESSION_free(ss);
return 0;
}
@@ -334,7 +407,7 @@ int ssl_get_new_session(SSL *s, int session) {
if (s->tlsext_hostname) {
ss->tlsext_hostname = BUF_strdup(s->tlsext_hostname);
if (ss->tlsext_hostname == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl_get_new_session, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
SSL_SESSION_free(ss);
return 0;
}
@@ -344,7 +417,7 @@ int ssl_get_new_session(SSL *s, int session) {
}
if (s->sid_ctx_length > sizeof(ss->sid_ctx)) {
- OPENSSL_PUT_ERROR(SSL, ssl_get_new_session, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
SSL_SESSION_free(ss);
return 0;
}
@@ -358,121 +431,110 @@ int ssl_get_new_session(SSL *s, int session) {
return 1;
}
-/* ssl_get_prev attempts to find an SSL_SESSION to be used to resume this
- * connection. It is only called by servers.
- *
- * ctx: contains the early callback context, which is the result of a
- * shallow parse of the ClientHello.
- *
- * Returns:
- * -1: error
- * 0: a session may have been found.
- *
- * Side effects:
- * - If a session is found then s->session is pointed at it (after freeing an
- * existing session if need be) and s->verify_result is set from the session.
- * - Both for new and resumed sessions, s->tlsext_ticket_expected is set to 1
- * if the server should issue a new session ticket (to 0 otherwise). */
-int ssl_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx) {
- /* This is used only by servers. */
- SSL_SESSION *ret = NULL;
- int fatal = 0;
- int try_session_cache = 1;
- int r;
-
- if (ctx->session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) {
- goto err;
- }
+/* ssl_lookup_session looks up |session_id| in the session cache and sets
+ * |*out_session| to an |SSL_SESSION| object if found. The caller takes
+ * ownership of the result. */
+static enum ssl_session_result_t ssl_lookup_session(
+ SSL *ssl, SSL_SESSION **out_session, const uint8_t *session_id,
+ size_t session_id_len) {
+ *out_session = NULL;
- if (ctx->session_id_len == 0) {
- try_session_cache = 0;
+ if (session_id_len == 0 || session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) {
+ return ssl_session_success;
}
- r = tls1_process_ticket(s, ctx, &ret); /* sets s->tlsext_ticket_expected */
- switch (r) {
- case -1: /* Error during processing */
- fatal = 1;
- goto err;
-
- case 0: /* No ticket found */
- case 1: /* Zero length ticket found */
- break; /* Ok to carry on processing session id. */
-
- case 2: /* Ticket found but not decrypted. */
- case 3: /* Ticket decrypted, *ret has been set. */
- try_session_cache = 0;
- break;
-
- default:
- abort();
- }
-
- if (try_session_cache && ret == NULL &&
- !(s->initial_ctx->session_cache_mode &
+ SSL_SESSION *session;
+ /* Try the internal cache, if it exists. */
+ if (!(ssl->initial_ctx->session_cache_mode &
SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) {
SSL_SESSION data;
- data.ssl_version = s->version;
- data.session_id_length = ctx->session_id_len;
- if (ctx->session_id_len == 0) {
- return 0;
+ data.ssl_version = ssl->version;
+ data.session_id_length = session_id_len;
+ memcpy(data.session_id, session_id, session_id_len);
+
+ CRYPTO_MUTEX_lock_read(&ssl->initial_ctx->lock);
+ session = lh_SSL_SESSION_retrieve(ssl->initial_ctx->sessions, &data);
+ if (session != NULL) {
+ SSL_SESSION_up_ref(session);
}
- memcpy(data.session_id, ctx->session_id, ctx->session_id_len);
+ CRYPTO_MUTEX_unlock(&ssl->initial_ctx->lock);
- CRYPTO_MUTEX_lock_read(&s->initial_ctx->lock);
- ret = lh_SSL_SESSION_retrieve(s->initial_ctx->sessions, &data);
- CRYPTO_MUTEX_unlock(&s->initial_ctx->lock);
-
- if (ret != NULL) {
- SSL_SESSION_up_ref(ret);
+ if (session != NULL) {
+ *out_session = session;
+ return ssl_session_success;
}
}
- if (try_session_cache && ret == NULL &&
- s->initial_ctx->get_session_cb != NULL) {
- int copy = 1;
-
- ret = s->initial_ctx->get_session_cb(s, (uint8_t *)ctx->session_id,
- ctx->session_id_len, &copy);
- if (ret != NULL) {
- if (ret == SSL_magic_pending_session_ptr()) {
- /* This is a magic value which indicates that the callback needs to
- * unwind the stack and figure out the session asynchronously. */
- return PENDING_SESSION;
- }
-
- /* Increment reference count now if the session callback asks us to do so
- * (note that if the session structures returned by the callback are
- * shared between threads, it must handle the reference count itself
- * [i.e. copy == 0], or things won't be thread-safe). */
- if (copy) {
- SSL_SESSION_up_ref(ret);
- }
+ /* Fall back to the external cache, if it exists. */
+ if (ssl->initial_ctx->get_session_cb == NULL) {
+ return ssl_session_success;
+ }
+ int copy = 1;
+ session = ssl->initial_ctx->get_session_cb(ssl, (uint8_t *)session_id,
+ session_id_len, &copy);
+ if (session == NULL) {
+ return ssl_session_success;
+ }
+ if (session == SSL_magic_pending_session_ptr()) {
+ return ssl_session_retry;
+ }
- /* Add the externally cached session to the internal cache as well if and
- * only if we are supposed to. */
- if (!(s->initial_ctx->session_cache_mode &
- SSL_SESS_CACHE_NO_INTERNAL_STORE)) {
- /* The following should not return 1, otherwise, things are very
- * strange */
- SSL_CTX_add_session(s->initial_ctx, ret);
- }
- }
+ /* Increment reference count now if the session callback asks us to do so
+ * (note that if the session structures returned by the callback are shared
+ * between threads, it must handle the reference count itself [i.e. copy ==
+ * 0], or things won't be thread-safe). */
+ if (copy) {
+ SSL_SESSION_up_ref(session);
}
- if (ret == NULL) {
- goto err;
+ /* Add the externally cached session to the internal cache if necessary. */
+ if (!(ssl->initial_ctx->session_cache_mode &
+ SSL_SESS_CACHE_NO_INTERNAL_STORE)) {
+ SSL_CTX_add_session(ssl->initial_ctx, session);
}
- /* Now ret is non-NULL and we own one of its reference counts. */
+ *out_session = session;
+ return ssl_session_success;
+}
- if (ret->sid_ctx_length != s->sid_ctx_length ||
- memcmp(ret->sid_ctx, s->sid_ctx, ret->sid_ctx_length)) {
- /* We have the session requested by the client, but we don't want to use it
- * in this context. */
- goto err; /* treat like cache miss */
+enum ssl_session_result_t ssl_get_prev_session(
+ SSL *ssl, SSL_SESSION **out_session, int *out_send_ticket,
+ const struct ssl_early_callback_ctx *ctx) {
+ /* This is used only by servers. */
+ assert(ssl->server);
+ SSL_SESSION *session = NULL;
+ int send_ticket = 0;
+
+ /* If tickets are disabled, always behave as if no tickets are present. */
+ const uint8_t *ticket = NULL;
+ size_t ticket_len = 0;
+ const int tickets_supported =
+ !(SSL_get_options(ssl) & SSL_OP_NO_TICKET) &&
+ (ssl->version > SSL3_VERSION || ctx->extensions != NULL) &&
+ SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_session_ticket,
+ &ticket, &ticket_len);
+ if (tickets_supported) {
+ if (!tls_process_ticket(ssl, &session, &send_ticket, ticket, ticket_len,
+ ctx->session_id, ctx->session_id_len)) {
+ return ssl_session_error;
+ }
+ } else {
+ /* The client does not support session tickets, so the session ID should be
+ * used instead. */
+ enum ssl_session_result_t lookup_ret = ssl_lookup_session(
+ ssl, &session, ctx->session_id, ctx->session_id_len);
+ if (lookup_ret != ssl_session_success) {
+ return lookup_ret;
+ }
}
- if ((s->verify_mode & SSL_VERIFY_PEER) && s->sid_ctx_length == 0) {
+ if (session == NULL ||
+ session->sid_ctx_length != ssl->sid_ctx_length ||
+ memcmp(session->sid_ctx, ssl->sid_ctx, ssl->sid_ctx_length) != 0) {
+ goto no_session;
+ }
+
+ if ((ssl->verify_mode & SSL_VERIFY_PEER) && ssl->sid_ctx_length == 0) {
/* We can't be sure if this session is being used out of context, which is
* especially important for SSL_VERIFY_PEER. The application should have
* used SSL[_CTX]_set_session_id_context.
@@ -481,83 +543,76 @@ int ssl_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx) {
* like a cache miss (otherwise it would be easy for applications to
* effectively disable the session cache by accident without anyone
* noticing). */
- OPENSSL_PUT_ERROR(SSL, ssl_get_prev_session,
- SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED);
- fatal = 1;
- goto err;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED);
+ goto fatal_error;
}
- if (ret->timeout < (long)(time(NULL) - ret->time)) {
- /* timeout */
- if (try_session_cache) {
- /* session was from the cache, so remove it */
- SSL_CTX_remove_session(s->initial_ctx, ret);
+ if (session->timeout < (long)(time(NULL) - session->time)) {
+ if (!tickets_supported) {
+ /* The session was from the cache, so remove it. */
+ SSL_CTX_remove_session(ssl->initial_ctx, session);
}
- goto err;
+ goto no_session;
}
- SSL_SESSION_free(s->session);
- s->session = ret;
- s->verify_result = s->session->verify_result;
- return 1;
+ *out_session = session;
+ *out_send_ticket = send_ticket;
+ return ssl_session_success;
-err:
- if (ret != NULL) {
- SSL_SESSION_free(ret);
- if (!try_session_cache) {
- /* The session was from a ticket, so we should
- * issue a ticket for the new session */
- s->tlsext_ticket_expected = 1;
- }
- }
- if (fatal) {
- return -1;
- }
- return 0;
+fatal_error:
+ SSL_SESSION_free(session);
+ return ssl_session_error;
+
+no_session:
+ *out_session = NULL;
+ *out_send_ticket = tickets_supported;
+ SSL_SESSION_free(session);
+ return ssl_session_success;
}
-int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) {
+int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *session) {
int ret = 0;
- SSL_SESSION *s;
+ SSL_SESSION *old_session;
- /* add just 1 reference count for the SSL_CTX's session cache even though it
+ /* Add just 1 reference count for the |SSL_CTX|'s session cache even though it
* has two ways of access: each session is in a doubly linked list and an
- * lhash */
- SSL_SESSION_up_ref(c);
- /* if session c is in already in cache, we take back the increment later */
+ * lhash. */
+ SSL_SESSION_up_ref(session);
+ /* If |session| is in already in cache, we take back the increment later. */
CRYPTO_MUTEX_lock_write(&ctx->lock);
- if (!lh_SSL_SESSION_insert(ctx->sessions, &s, c)) {
+ if (!lh_SSL_SESSION_insert(ctx->sessions, &old_session, session)) {
CRYPTO_MUTEX_unlock(&ctx->lock);
+ SSL_SESSION_free(session);
return 0;
}
- /* s != NULL iff we already had a session with the given PID. In this case, s
- * == c should hold (then we did not really modify ctx->sessions), or we're
- * in trouble. */
- if (s != NULL && s != c) {
+ /* |old_session| != NULL iff we already had a session with the given session
+ * ID. In this case, |old_session| == |session| should hold (then we did not
+ * really modify |ctx->sessions|), or we're in trouble. */
+ if (old_session != NULL && old_session != session) {
/* We *are* in trouble ... */
- SSL_SESSION_list_remove(ctx, s);
- SSL_SESSION_free(s);
+ SSL_SESSION_list_remove(ctx, old_session);
+ SSL_SESSION_free(old_session);
/* ... so pretend the other session did not exist in cache (we cannot
- * handle two SSL_SESSION structures with identical session ID in the same
+ * handle two |SSL_SESSION| structures with identical session ID in the same
* cache, which could happen e.g. when two threads concurrently obtain the
- * same session from an external cache) */
- s = NULL;
+ * same session from an external cache). */
+ old_session = NULL;
}
- /* Put at the head of the queue unless it is already in the cache */
- if (s == NULL) {
- SSL_SESSION_list_add(ctx, c);
+ /* Put at the head of the queue unless it is already in the cache. */
+ if (old_session == NULL) {
+ SSL_SESSION_list_add(ctx, session);
}
- if (s != NULL) {
- /* existing cache entry -- decrement previously incremented reference count
- * because it already takes into account the cache */
- SSL_SESSION_free(s); /* s == c */
+ if (old_session != NULL) {
+ /* Existing cache entry -- decrement previously incremented reference count
+ * because it already takes into account the cache. */
+ SSL_SESSION_free(old_session); /* |old_session| == |session| */
ret = 0;
} else {
- /* new cache entry -- remove old ones if cache has become too large */
+ /* New cache entry -- remove old ones if cache has become too large. */
ret = 1;
if (SSL_CTX_sess_get_cache_size(ctx) > 0) {
@@ -573,23 +628,23 @@ int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) {
return ret;
}
-int SSL_CTX_remove_session(SSL_CTX *ctx, SSL_SESSION *c) {
- return remove_session_lock(ctx, c, 1);
+int SSL_CTX_remove_session(SSL_CTX *ctx, SSL_SESSION *session) {
+ return remove_session_lock(ctx, session, 1);
}
-static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lock) {
- SSL_SESSION *r;
+static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock) {
int ret = 0;
- if (c != NULL && c->session_id_length != 0) {
+ if (session != NULL && session->session_id_length != 0) {
if (lock) {
CRYPTO_MUTEX_lock_write(&ctx->lock);
}
- r = lh_SSL_SESSION_retrieve(ctx->sessions, c);
- if (r == c) {
+ SSL_SESSION *found_session = lh_SSL_SESSION_retrieve(ctx->sessions,
+ session);
+ if (found_session == session) {
ret = 1;
- r = lh_SSL_SESSION_delete(ctx->sessions, c);
- SSL_SESSION_list_remove(ctx, c);
+ found_session = lh_SSL_SESSION_delete(ctx->sessions, session);
+ SSL_SESSION_list_remove(ctx, session);
}
if (lock) {
@@ -597,127 +652,48 @@ static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lock) {
}
if (ret) {
- r->not_resumable = 1;
+ found_session->not_resumable = 1;
if (ctx->remove_session_cb != NULL) {
- ctx->remove_session_cb(ctx, r);
+ ctx->remove_session_cb(ctx, found_session);
}
- SSL_SESSION_free(r);
+ SSL_SESSION_free(found_session);
}
}
return ret;
}
-SSL_SESSION *SSL_SESSION_up_ref(SSL_SESSION *session) {
- if (session) {
- CRYPTO_refcount_inc(&session->references);
- }
- return session;
-}
-
-void SSL_SESSION_free(SSL_SESSION *session) {
- if (session == NULL ||
- !CRYPTO_refcount_dec_and_test_zero(&session->references)) {
- return;
- }
-
- CRYPTO_free_ex_data(&g_ex_data_class, session, &session->ex_data);
-
- OPENSSL_cleanse(session->master_key, sizeof(session->master_key));
- OPENSSL_cleanse(session->session_id, sizeof(session->session_id));
- ssl_sess_cert_free(session->sess_cert);
- X509_free(session->peer);
- OPENSSL_free(session->tlsext_hostname);
- OPENSSL_free(session->tlsext_tick);
- OPENSSL_free(session->tlsext_signed_cert_timestamp_list);
- OPENSSL_free(session->ocsp_response);
- OPENSSL_free(session->psk_identity);
- OPENSSL_cleanse(session, sizeof(*session));
- OPENSSL_free(session);
-}
-
-int SSL_set_session(SSL *s, SSL_SESSION *session) {
- if (s->session == session) {
+int SSL_set_session(SSL *ssl, SSL_SESSION *session) {
+ if (ssl->session == session) {
return 1;
}
- SSL_SESSION_free(s->session);
- s->session = session;
+ SSL_SESSION_free(ssl->session);
+ ssl->session = session;
if (session != NULL) {
SSL_SESSION_up_ref(session);
- s->verify_result = session->verify_result;
+ ssl->verify_result = session->verify_result;
}
return 1;
}
-long SSL_SESSION_set_timeout(SSL_SESSION *s, long t) {
- if (s == NULL) {
+long SSL_CTX_set_timeout(SSL_CTX *ctx, long timeout) {
+ if (ctx == NULL) {
return 0;
}
- s->timeout = t;
- return 1;
+ long old_timeout = ctx->session_timeout;
+ ctx->session_timeout = timeout;
+ return old_timeout;
}
-long SSL_SESSION_get_timeout(const SSL_SESSION *s) {
- if (s == NULL) {
+long SSL_CTX_get_timeout(const SSL_CTX *ctx) {
+ if (ctx == NULL) {
return 0;
}
- return s->timeout;
-}
-
-long SSL_SESSION_get_time(const SSL_SESSION *s) {
- if (s == NULL) {
- return 0;
- }
-
- return s->time;
-}
-
-long SSL_SESSION_set_time(SSL_SESSION *s, long t) {
- if (s == NULL) {
- return 0;
- }
-
- s->time = t;
- return t;
-}
-
-X509 *SSL_SESSION_get0_peer(SSL_SESSION *s) { return s->peer; }
-
-int SSL_SESSION_set1_id_context(SSL_SESSION *s, const uint8_t *sid_ctx,
- unsigned int sid_ctx_len) {
- if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_set1_id_context,
- SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
- return 0;
- }
-
- s->sid_ctx_length = sid_ctx_len;
- memcpy(s->sid_ctx, sid_ctx, sid_ctx_len);
-
- return 1;
-}
-
-long SSL_CTX_set_timeout(SSL_CTX *s, long t) {
- long l;
- if (s == NULL) {
- return 0;
- }
-
- l = s->session_timeout;
- s->session_timeout = t;
- return l;
-}
-
-long SSL_CTX_get_timeout(const SSL_CTX *s) {
- if (s == NULL) {
- return 0;
- }
-
- return s->session_timeout;
+ return ctx->session_timeout;
}
typedef struct timeout_param_st {
@@ -726,25 +702,25 @@ typedef struct timeout_param_st {
LHASH_OF(SSL_SESSION) *cache;
} TIMEOUT_PARAM;
-static void timeout_doall_arg(SSL_SESSION *sess, void *void_param) {
+static void timeout_doall_arg(SSL_SESSION *session, void *void_param) {
TIMEOUT_PARAM *param = void_param;
if (param->time == 0 ||
- param->time > (sess->time + sess->timeout)) {
+ param->time > (session->time + session->timeout)) {
/* timeout */
/* The reason we don't call SSL_CTX_remove_session() is to
* save on locking overhead */
- (void) lh_SSL_SESSION_delete(param->cache, sess);
- SSL_SESSION_list_remove(param->ctx, sess);
- sess->not_resumable = 1;
+ (void) lh_SSL_SESSION_delete(param->cache, session);
+ SSL_SESSION_list_remove(param->ctx, session);
+ session->not_resumable = 1;
if (param->ctx->remove_session_cb != NULL) {
- param->ctx->remove_session_cb(param->ctx, sess);
+ param->ctx->remove_session_cb(param->ctx, session);
}
- SSL_SESSION_free(sess);
+ SSL_SESSION_free(session);
}
}
-void SSL_CTX_flush_sessions(SSL_CTX *ctx, long t) {
+void SSL_CTX_flush_sessions(SSL_CTX *ctx, long time) {
TIMEOUT_PARAM tp;
tp.ctx = ctx;
@@ -752,7 +728,7 @@ void SSL_CTX_flush_sessions(SSL_CTX *ctx, long t) {
if (tp.cache == NULL) {
return;
}
- tp.time = t;
+ tp.time = time;
CRYPTO_MUTEX_lock_write(&ctx->lock);
lh_SSL_SESSION_doall_arg(tp.cache, timeout_doall_arg, &tp);
CRYPTO_MUTEX_unlock(&ctx->lock);
@@ -769,80 +745,80 @@ int ssl_clear_bad_session(SSL *s) {
}
/* locked by SSL_CTX in the calling function */
-static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s) {
- if (s->next == NULL || s->prev == NULL) {
+static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *session) {
+ if (session->next == NULL || session->prev == NULL) {
return;
}
- if (s->next == (SSL_SESSION *)&ctx->session_cache_tail) {
+ if (session->next == (SSL_SESSION *)&ctx->session_cache_tail) {
/* last element in list */
- if (s->prev == (SSL_SESSION *)&ctx->session_cache_head) {
+ if (session->prev == (SSL_SESSION *)&ctx->session_cache_head) {
/* only one element in list */
ctx->session_cache_head = NULL;
ctx->session_cache_tail = NULL;
} else {
- ctx->session_cache_tail = s->prev;
- s->prev->next = (SSL_SESSION *)&(ctx->session_cache_tail);
+ ctx->session_cache_tail = session->prev;
+ session->prev->next = (SSL_SESSION *)&(ctx->session_cache_tail);
}
} else {
- if (s->prev == (SSL_SESSION *)&ctx->session_cache_head) {
+ if (session->prev == (SSL_SESSION *)&ctx->session_cache_head) {
/* first element in list */
- ctx->session_cache_head = s->next;
- s->next->prev = (SSL_SESSION *)&(ctx->session_cache_head);
+ ctx->session_cache_head = session->next;
+ session->next->prev = (SSL_SESSION *)&(ctx->session_cache_head);
} else { /* middle of list */
- s->next->prev = s->prev;
- s->prev->next = s->next;
+ session->next->prev = session->prev;
+ session->prev->next = session->next;
}
}
- s->prev = s->next = NULL;
+ session->prev = session->next = NULL;
}
-static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s) {
- if (s->next != NULL && s->prev != NULL) {
- SSL_SESSION_list_remove(ctx, s);
+static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *session) {
+ if (session->next != NULL && session->prev != NULL) {
+ SSL_SESSION_list_remove(ctx, session);
}
if (ctx->session_cache_head == NULL) {
- ctx->session_cache_head = s;
- ctx->session_cache_tail = s;
- s->prev = (SSL_SESSION *)&(ctx->session_cache_head);
- s->next = (SSL_SESSION *)&(ctx->session_cache_tail);
+ ctx->session_cache_head = session;
+ ctx->session_cache_tail = session;
+ session->prev = (SSL_SESSION *)&(ctx->session_cache_head);
+ session->next = (SSL_SESSION *)&(ctx->session_cache_tail);
} else {
- s->next = ctx->session_cache_head;
- s->next->prev = s;
- s->prev = (SSL_SESSION *)&(ctx->session_cache_head);
- ctx->session_cache_head = s;
+ session->next = ctx->session_cache_head;
+ session->next->prev = session;
+ session->prev = (SSL_SESSION *)&(ctx->session_cache_head);
+ ctx->session_cache_head = session;
}
}
void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx,
- int (*cb)(struct ssl_st *ssl, SSL_SESSION *sess)) {
+ int (*cb)(SSL *ssl, SSL_SESSION *session)) {
ctx->new_session_cb = cb;
}
-int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx))(SSL *ssl, SSL_SESSION *sess) {
+int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx))(SSL *ssl, SSL_SESSION *session) {
return ctx->new_session_cb;
}
-void SSL_CTX_sess_set_remove_cb(SSL_CTX *ctx,
- void (*cb)(SSL_CTX *ctx, SSL_SESSION *sess)) {
+void SSL_CTX_sess_set_remove_cb(
+ SSL_CTX *ctx, void (*cb)(SSL_CTX *ctx, SSL_SESSION *session)) {
ctx->remove_session_cb = cb;
}
void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx))(SSL_CTX *ctx,
- SSL_SESSION *sess) {
+ SSL_SESSION *session) {
return ctx->remove_session_cb;
}
void SSL_CTX_sess_set_get_cb(SSL_CTX *ctx,
- SSL_SESSION *(*cb)(struct ssl_st *ssl,
- uint8_t *data, int len,
- int *copy)) {
+ SSL_SESSION *(*cb)(SSL *ssl,
+ uint8_t *id, int id_len,
+ int *out_copy)) {
ctx->get_session_cb = cb;
}
-SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx))(SSL *ssl, uint8_t *data,
- int len, int *copy) {
+SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx))(
+ SSL *ssl, uint8_t *id, int id_len, int *out_copy) {
return ctx->get_session_cb;
}
@@ -874,5 +850,3 @@ void SSL_CTX_set_channel_id_cb(SSL_CTX *ctx,
void (*SSL_CTX_get_channel_id_cb(SSL_CTX *ctx))(SSL *ssl, EVP_PKEY **pkey) {
return ctx->channel_id_cb;
}
-
-IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION)
diff --git a/src/ssl/ssl_stat.c b/src/ssl/ssl_stat.c
index fa5541b..5ad1e47 100644
--- a/src/ssl/ssl_stat.c
+++ b/src/ssl/ssl_stat.c
@@ -82,9 +82,11 @@
* OTHERWISE.
*/
-#include <stdio.h>
+#include <openssl/ssl.h>
+
#include "internal.h"
+
const char *SSL_state_string_long(const SSL *s) {
const char *str;
@@ -334,37 +336,6 @@ const char *SSL_state_string_long(const SSL *s) {
str = "SSLv3 read certificate verify B";
break;
- /* SSLv2/v3 compatibility states */
- /* client */
- case SSL23_ST_CW_CLNT_HELLO_A:
- str = "SSLv2/v3 write client hello A";
- break;
-
- case SSL23_ST_CW_CLNT_HELLO_B:
- str = "SSLv2/v3 write client hello B";
- break;
-
- case SSL23_ST_CR_SRVR_HELLO_A:
- str = "SSLv2/v3 read server hello A";
- break;
-
- case SSL23_ST_CR_SRVR_HELLO_B:
- str = "SSLv2/v3 read server hello B";
- break;
-
- /* server */
- case SSL23_ST_SR_CLNT_HELLO:
- str = "SSLv2/v3 read client hello";
- break;
-
- case SSL23_ST_SR_V2_CLNT_HELLO:
- str = "SSLv2/v3 read v2 client hello";
- break;
-
- case SSL23_ST_SR_SWITCH_VERSION:
- str = "SSLv2/v3 switch version";
- break;
-
/* DTLS */
case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
str = "DTLS1 read hello verify request A";
@@ -382,30 +353,6 @@ const char *SSL_state_string_long(const SSL *s) {
return str;
}
-const char *SSL_rstate_string_long(const SSL *s) {
- const char *str;
-
- switch (s->rstate) {
- case SSL_ST_READ_HEADER:
- str = "read header";
- break;
-
- case SSL_ST_READ_BODY:
- str = "read body";
- break;
-
- case SSL_ST_READ_DONE:
- str = "read done";
- break;
-
- default:
- str = "unknown";
- break;
- }
-
- return str;
-}
-
const char *SSL_state_string(const SSL *s) {
const char *str;
@@ -635,37 +582,6 @@ const char *SSL_state_string(const SSL *s) {
str = "3RCV_B";
break;
- /* SSLv2/v3 compatibility states */
- /* client */
- case SSL23_ST_CW_CLNT_HELLO_A:
- str = "23WCHA";
- break;
-
- case SSL23_ST_CW_CLNT_HELLO_B:
- str = "23WCHB";
- break;
-
- case SSL23_ST_CR_SRVR_HELLO_A:
- str = "23RSHA";
- break;
-
- case SSL23_ST_CR_SRVR_HELLO_B:
- str = "23RSHA";
- break;
-
- /* server */
- case SSL23_ST_SR_CLNT_HELLO:
- str = "23RCH_";
- break;
-
- case SSL23_ST_SR_V2_CLNT_HELLO:
- str = "23R2CH";
- break;
-
- case SSL23_ST_SR_SWITCH_VERSION:
- str = "23RSW_";
- break;
-
/* DTLS */
case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
str = "DRCHVA";
@@ -968,27 +884,3 @@ const char *SSL_alert_desc_string_long(int value) {
return str;
}
-
-const char *SSL_rstate_string(const SSL *s) {
- const char *str;
-
- switch (s->rstate) {
- case SSL_ST_READ_HEADER:
- str = "RH";
- break;
-
- case SSL_ST_READ_BODY:
- str = "RB";
- break;
-
- case SSL_ST_READ_DONE:
- str = "RD";
- break;
-
- default:
- str = "unknown";
- break;
- }
-
- return str;
-}
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index 9f2ddb9..810d3fa 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -24,6 +24,8 @@
#include <openssl/ssl.h>
#include "test/scoped_types.h"
+#include "../crypto/test/test_util.h"
+
struct ExpectedCipher {
unsigned long id;
@@ -212,6 +214,21 @@ static const char *kBadRules[] = {
NULL,
};
+static const char *kMustNotIncludeNull[] = {
+ "ALL",
+ "DEFAULT",
+ "ALL:!eNULL",
+ "ALL:!NULL",
+ "FIPS",
+ "SHA",
+ "SHA1",
+ "RSA",
+ "SSLv3",
+ "TLSv1",
+ "TLSv1.2",
+ NULL
+};
+
static void PrintCipherPreferenceList(ssl_cipher_preference_list_st *list) {
bool in_group = false;
for (size_t i = 0; i < sk_SSL_CIPHER_num(list->ciphers); i++) {
@@ -265,6 +282,24 @@ static bool TestCipherRule(CipherTest *t) {
return true;
}
+static bool TestRuleDoesNotIncludeNull(const char *rule) {
+ ScopedSSL_CTX ctx(SSL_CTX_new(SSLv23_server_method()));
+ if (!ctx) {
+ return false;
+ }
+ if (!SSL_CTX_set_cipher_list(ctx.get(), rule)) {
+ fprintf(stderr, "Error: cipher rule '%s' failed\n", rule);
+ return false;
+ }
+ for (size_t i = 0; i < sk_SSL_CIPHER_num(ctx->cipher_list->ciphers); i++) {
+ if (SSL_CIPHER_is_NULL(sk_SSL_CIPHER_value(ctx->cipher_list->ciphers, i))) {
+ fprintf(stderr, "Error: cipher rule '%s' includes NULL\n",rule);
+ return false;
+ }
+ }
+ return true;
+}
+
static bool TestCipherRules() {
for (size_t i = 0; kCipherTests[i].rule != NULL; i++) {
if (!TestCipherRule(&kCipherTests[i])) {
@@ -284,6 +319,12 @@ static bool TestCipherRules() {
ERR_clear_error();
}
+ for (size_t i = 0; kMustNotIncludeNull[i] != NULL; i++) {
+ if (!TestRuleDoesNotIncludeNull(kMustNotIncludeNull[i])) {
+ return false;
+ }
+ }
+
return true;
}
@@ -335,6 +376,104 @@ static const char kCustomSession[] =
"q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG"
"BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBLADBAEF";
+// kBoringSSLSession is a serialized SSL_SESSION generated from bssl client.
+static const char kBoringSSLSession[] =
+ "MIIRwQIBAQICAwMEAsAvBCDdoGxGK26mR+8lM0uq6+k9xYuxPnwAjpcF9n0Yli9R"
+ "kQQwbyshfWhdi5XQ1++7n2L1qqrcVlmHBPpr6yknT/u4pUrpQB5FZ7vqvNn8MdHf"
+ "9rWgoQYCBFXgs7uiBAICHCCjggR6MIIEdjCCA16gAwIBAgIIf+yfD7Y6UicwDQYJ"
+ "KoZIhvcNAQELBQAwSTELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMx"
+ "JTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3JpdHkgRzIwHhcNMTUwODEy"
+ "MTQ1MzE1WhcNMTUxMTEwMDAwMDAwWjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwK"
+ "Q2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzETMBEGA1UECgwKR29v"
+ "Z2xlIEluYzEXMBUGA1UEAwwOd3d3Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEB"
+ "AQUAA4IBDwAwggEKAoIBAQC0MeG5YGQ0t+IeJeoneP/PrhEaieibeKYkbKVLNZpo"
+ "PLuBinvhkXZo3DC133NpCBpy6ZktBwamqyixAyuk/NU6OjgXqwwxfQ7di1AInLIU"
+ "792c7hFyNXSUCG7At8Ifi3YwBX9Ba6u/1d6rWTGZJrdCq3QU11RkKYyTq2KT5mce"
+ "Tv9iGKqSkSTlp8puy/9SZ/3DbU3U+BuqCFqeSlz7zjwFmk35acdCilpJlVDDN5C/"
+ "RCh8/UKc8PaL+cxlt531qoTENvYrflBno14YEZlCBZsPiFeUSILpKEj3Ccwhy0eL"
+ "EucWQ72YZU8mUzXBoXGn0zA0crFl5ci/2sTBBGZsylNBAgMBAAGjggFBMIIBPTAd"
+ "BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdv"
+ "b2dsZS5jb20waAYIKwYBBQUHAQEEXDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtp"
+ "Lmdvb2dsZS5jb20vR0lBRzIuY3J0MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50"
+ "czEuZ29vZ2xlLmNvbS9vY3NwMB0GA1UdDgQWBBS/bzHxcE73Q4j3slC4BLbMtLjG"
+ "GjAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEv"
+ "MBcGA1UdIAQQMA4wDAYKKwYBBAHWeQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRw"
+ "Oi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQAb"
+ "qdWPZEHk0X7iKPCTHL6S3w6q1eR67goxZGFSM1lk1hjwyu7XcLJuvALVV9uY3ovE"
+ "kQZSHwT+pyOPWQhsSjO+1GyjvCvK/CAwiUmBX+bQRGaqHsRcio7xSbdVcajQ3bXd"
+ "X+s0WdbOpn6MStKAiBVloPlSxEI8pxY6x/BBCnTIk/+DMB17uZlOjG3vbAnkDkP+"
+ "n0OTucD9sHV7EVj9XUxi51nOfNBCN/s7lpUjDS/NJ4k3iwOtbCPswiot8vLO779a"
+ "f07vR03r349Iz/KTzk95rlFtX0IU+KYNxFNsanIXZ+C9FYGRXkwhHcvFb4qMUB1y"
+ "TTlM80jBMOwyjZXmjRAhpAIEAKUDAgEUqQUCAwGJwKqBpwSBpOgebbmn9NRUtMWH"
+ "+eJpqA5JLMFSMCChOsvKey3toBaCNGU7HfAEiiXNuuAdCBoK262BjQc2YYfqFzqH"
+ "zuppopXCvhohx7j/tnCNZIMgLYt/O9SXK2RYI5z8FhCCHvB4CbD5G0LGl5EFP27s"
+ "Jb6S3aTTYPkQe8yZSlxevg6NDwmTogLO9F7UUkaYmVcMQhzssEE2ZRYNwSOU6KjE"
+ "0Yj+8fAiBtbQriIEIN2L8ZlpaVrdN5KFNdvcmOxJu81P8q53X55xQyGTnGWwsgMC"
+ "ARezggvvMIIEdjCCA16gAwIBAgIIf+yfD7Y6UicwDQYJKoZIhvcNAQELBQAwSTEL"
+ "MAkGA1UEBhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2ds"
+ "ZSBJbnRlcm5ldCBBdXRob3JpdHkgRzIwHhcNMTUwODEyMTQ1MzE1WhcNMTUxMTEw"
+ "MDAwMDAwWjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG"
+ "A1UEBwwNTW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UE"
+ "AwwOd3d3Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB"
+ "AQC0MeG5YGQ0t+IeJeoneP/PrhEaieibeKYkbKVLNZpoPLuBinvhkXZo3DC133Np"
+ "CBpy6ZktBwamqyixAyuk/NU6OjgXqwwxfQ7di1AInLIU792c7hFyNXSUCG7At8If"
+ "i3YwBX9Ba6u/1d6rWTGZJrdCq3QU11RkKYyTq2KT5mceTv9iGKqSkSTlp8puy/9S"
+ "Z/3DbU3U+BuqCFqeSlz7zjwFmk35acdCilpJlVDDN5C/RCh8/UKc8PaL+cxlt531"
+ "qoTENvYrflBno14YEZlCBZsPiFeUSILpKEj3Ccwhy0eLEucWQ72YZU8mUzXBoXGn"
+ "0zA0crFl5ci/2sTBBGZsylNBAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEF"
+ "BQcDAQYIKwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYB"
+ "BQUHAQEEXDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB"
+ "RzIuY3J0MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9v"
+ "Y3NwMB0GA1UdDgQWBBS/bzHxcE73Q4j3slC4BLbMtLjGGjAMBgNVHRMBAf8EAjAA"
+ "MB8GA1UdIwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYK"
+ "KwYBBAHWeQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5j"
+ "b20vR0lBRzIuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQAbqdWPZEHk0X7iKPCTHL6S"
+ "3w6q1eR67goxZGFSM1lk1hjwyu7XcLJuvALVV9uY3ovEkQZSHwT+pyOPWQhsSjO+"
+ "1GyjvCvK/CAwiUmBX+bQRGaqHsRcio7xSbdVcajQ3bXdX+s0WdbOpn6MStKAiBVl"
+ "oPlSxEI8pxY6x/BBCnTIk/+DMB17uZlOjG3vbAnkDkP+n0OTucD9sHV7EVj9XUxi"
+ "51nOfNBCN/s7lpUjDS/NJ4k3iwOtbCPswiot8vLO779af07vR03r349Iz/KTzk95"
+ "rlFtX0IU+KYNxFNsanIXZ+C9FYGRXkwhHcvFb4qMUB1yTTlM80jBMOwyjZXmjRAh"
+ "MIID8DCCAtigAwIBAgIDAjqDMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT"
+ "MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i"
+ "YWwgQ0EwHhcNMTMwNDA1MTUxNTU2WhcNMTYxMjMxMjM1OTU5WjBJMQswCQYDVQQG"
+ "EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy"
+ "bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB"
+ "AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP"
+ "VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv"
+ "h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE"
+ "ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ"
+ "EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC"
+ "DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB5zCB5DAfBgNVHSMEGDAWgBTAephojYn7"
+ "qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wDgYD"
+ "VR0PAQH/BAQDAgEGMC4GCCsGAQUFBwEBBCIwIDAeBggrBgEFBQcwAYYSaHR0cDov"
+ "L2cuc3ltY2QuY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwNQYDVR0fBC4wLDAqoCig"
+ "JoYkaHR0cDovL2cuc3ltY2IuY29tL2NybHMvZ3RnbG9iYWwuY3JsMBcGA1UdIAQQ"
+ "MA4wDAYKKwYBBAHWeQIFATANBgkqhkiG9w0BAQsFAAOCAQEAqvqpIM1qZ4PtXtR+"
+ "3h3Ef+AlBgDFJPupyC1tft6dgmUsgWM0Zj7pUsIItMsv91+ZOmqcUHqFBYx90SpI"
+ "hNMJbHzCzTWf84LuUt5oX+QAihcglvcpjZpNy6jehsgNb1aHA30DP9z6eX0hGfnI"
+ "Oi9RdozHQZJxjyXON/hKTAAj78Q1EK7gI4BzfE00LshukNYQHpmEcxpw8u1VDu4X"
+ "Bupn7jLrLN1nBz/2i8Jw3lsA5rsb0zYaImxssDVCbJAJPZPpZAkiDoUGn8JzIdPm"
+ "X4DkjYUiOnMDsWCOrmji9D6X52ASCWg23jrW4kOVWzeBkoEfu43XrVJkFleW2V40"
+ "fsg12DCCA30wggLmoAMCAQICAxK75jANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG"
+ "EwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUg"
+ "Q2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTAyMDUyMTA0MDAwMFoXDTE4MDgyMTA0"
+ "MDAwMFowQjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xGzAZ"
+ "BgNVBAMTEkdlb1RydXN0IEdsb2JhbCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP"
+ "ADCCAQoCggEBANrMGGMw/fQXIxpWflvfPGw45HG3eJHUvKHYTPioQ7YD6U0hBwiI"
+ "2lgvZjkpvQV4i5046AW3an5xpObEYKaw74DkiSgPniXW7YPzraaRx5jJQhg1FJ2t"
+ "mEaSLk/K8YdDwRaVVy1Q74ktgHpXrfLuX2vSAI25FPgUFTXZwEaje3LIkb/JVSvN"
+ "0Jc+nCZkzN/Ogxlxyk7m1NV7qRnNVd7I7NJeOFPlXE+MLf5QIzb8ZubLjqQ5GQC3"
+ "lQI5kQsO/jgu0R0FmvZNPm8PBx2vLB6PYDni+jZTEznUXiYr2z2oFL0y6xgDKFIE"
+ "ceWrMz3hOLsHNoRinHnqFjD0X8Ar6HFr5PkCAwEAAaOB8DCB7TAfBgNVHSMEGDAW"
+ "gBRI5mj5K9KylddH2CMgEE8zmJCf1DAdBgNVHQ4EFgQUwHqYaI2J+6sFZAwRfap9"
+ "ZbjKzE4wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMw"
+ "MTAvoC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9zZWN1cmVjYS5j"
+ "cmwwTgYDVR0gBEcwRTBDBgRVHSAAMDswOQYIKwYBBQUHAgEWLWh0dHBzOi8vd3d3"
+ "Lmdlb3RydXN0LmNvbS9yZXNvdXJjZXMvcmVwb3NpdG9yeTANBgkqhkiG9w0BAQUF"
+ "AAOBgQB24RJuTksWEoYwBrKBCM/wCMfHcX5m7sLt1Dsf//DwyE7WQziwuTB9GNBV"
+ "g6JqyzYRnOhIZqNtf7gT1Ef+i1pcc/yu2RsyGTirlzQUqpbS66McFAhJtrvlke+D"
+ "NusdVm/K2rxzY5Dkf3s+Iss9B+1fOHSc4wNQTqGvmO5h8oQ/Eg==";
+
// kBadSessionExtraField is a custom serialized SSL_SESSION generated by replacing
// the final (optional) element of |kCustomSession| with tag number 30.
static const char kBadSessionExtraField[] =
@@ -418,6 +557,8 @@ static bool TestSSL_SESSIONEncoding(const char *input_b64) {
if (encoded_len != input.size() ||
memcmp(bssl::vector_data(&input), encoded.get(), input.size()) != 0) {
fprintf(stderr, "SSL_SESSION_to_bytes did not round-trip\n");
+ hexdump(stderr, "Before: ", input.data(), input.size());
+ hexdump(stderr, "After: ", encoded_raw, encoded_len);
return false;
}
@@ -549,12 +690,141 @@ static bool TestCipherGetRFCName(void) {
return true;
}
-int main(void) {
+// CreateSessionWithTicket returns a sample |SSL_SESSION| with the ticket
+// replaced for one of length |ticket_len| or nullptr on failure.
+static ScopedSSL_SESSION CreateSessionWithTicket(size_t ticket_len) {
+ std::vector<uint8_t> der;
+ if (!DecodeBase64(&der, kOpenSSLSession)) {
+ return nullptr;
+ }
+ ScopedSSL_SESSION session(SSL_SESSION_from_bytes(bssl::vector_data(&der),
+ der.size()));
+ if (!session) {
+ return nullptr;
+ }
+
+ // Swap out the ticket for a garbage one.
+ OPENSSL_free(session->tlsext_tick);
+ session->tlsext_tick = reinterpret_cast<uint8_t*>(OPENSSL_malloc(ticket_len));
+ if (session->tlsext_tick == nullptr) {
+ return nullptr;
+ }
+ memset(session->tlsext_tick, 'a', ticket_len);
+ session->tlsext_ticklen = ticket_len;
+ return session;
+}
+
+// GetClientHelloLen creates a client SSL connection with a ticket of length
+// |ticket_len| and records the ClientHello. It returns the length of the
+// ClientHello, not including the record header, on success and zero on error.
+static size_t GetClientHelloLen(size_t ticket_len) {
+ ScopedSSL_CTX ctx(SSL_CTX_new(TLS_method()));
+ ScopedSSL_SESSION session = CreateSessionWithTicket(ticket_len);
+ if (!ctx || !session) {
+ return 0;
+ }
+ ScopedSSL ssl(SSL_new(ctx.get()));
+ ScopedBIO bio(BIO_new(BIO_s_mem()));
+ if (!ssl || !bio || !SSL_set_session(ssl.get(), session.get())) {
+ return 0;
+ }
+ // Do not configure a reading BIO, but record what's written to a memory BIO.
+ SSL_set_bio(ssl.get(), nullptr /* rbio */, BIO_up_ref(bio.get()));
+ int ret = SSL_connect(ssl.get());
+ if (ret > 0) {
+ // SSL_connect should fail without a BIO to write to.
+ return 0;
+ }
+ ERR_clear_error();
+
+ const uint8_t *unused;
+ size_t client_hello_len;
+ if (!BIO_mem_contents(bio.get(), &unused, &client_hello_len) ||
+ client_hello_len <= SSL3_RT_HEADER_LENGTH) {
+ return 0;
+ }
+ return client_hello_len - SSL3_RT_HEADER_LENGTH;
+}
+
+struct PaddingTest {
+ size_t input_len, padded_len;
+};
+
+static const PaddingTest kPaddingTests[] = {
+ // ClientHellos of length below 0x100 do not require padding.
+ {0xfe, 0xfe},
+ {0xff, 0xff},
+ // ClientHellos of length 0x100 through 0x1fb are padded up to 0x200.
+ {0x100, 0x200},
+ {0x123, 0x200},
+ {0x1fb, 0x200},
+ // ClientHellos of length 0x1fc through 0x1ff get padded beyond 0x200. The
+ // padding extension takes a minimum of four bytes plus one required content
+ // byte. (To work around yet more server bugs, we avoid empty final
+ // extensions.)
+ {0x1fc, 0x201},
+ {0x1fd, 0x202},
+ {0x1fe, 0x203},
+ {0x1ff, 0x204},
+ // Finally, larger ClientHellos need no padding.
+ {0x200, 0x200},
+ {0x201, 0x201},
+};
+
+static bool TestPaddingExtension() {
+ // Sample a baseline length.
+ size_t base_len = GetClientHelloLen(1);
+ if (base_len == 0) {
+ return false;
+ }
+
+ for (const PaddingTest &test : kPaddingTests) {
+ if (base_len > test.input_len) {
+ fprintf(stderr, "Baseline ClientHello too long.\n");
+ return false;
+ }
+
+ size_t padded_len = GetClientHelloLen(1 + test.input_len - base_len);
+ if (padded_len != test.padded_len) {
+ fprintf(stderr, "%u-byte ClientHello padded to %u bytes, not %u.\n",
+ static_cast<unsigned>(test.input_len),
+ static_cast<unsigned>(padded_len),
+ static_cast<unsigned>(test.padded_len));
+ return false;
+ }
+ }
+ return true;
+}
+
+// Test that |SSL_get_client_CA_list| echoes back the configured parameter even
+// before configuring as a server.
+static bool TestClientCAList() {
+ ScopedSSL_CTX ctx(SSL_CTX_new(TLS_method()));
+ if (!ctx) {
+ return false;
+ }
+ ScopedSSL ssl(SSL_new(ctx.get()));
+ if (!ssl) {
+ return false;
+ }
+
+ STACK_OF(X509_NAME) *stack = sk_X509_NAME_new_null();
+ if (stack == nullptr) {
+ return false;
+ }
+ // |SSL_set_client_CA_list| takes ownership.
+ SSL_set_client_CA_list(ssl.get(), stack);
+
+ return SSL_get_client_CA_list(ssl.get()) == stack;
+}
+
+int main() {
SSL_library_init();
if (!TestCipherRules() ||
!TestSSL_SESSIONEncoding(kOpenSSLSession) ||
!TestSSL_SESSIONEncoding(kCustomSession) ||
+ !TestSSL_SESSIONEncoding(kBoringSSLSession) ||
!TestBadSSL_SESSIONEncoding(kBadSessionExtraField) ||
!TestBadSSL_SESSIONEncoding(kBadSessionVersion) ||
!TestBadSSL_SESSIONEncoding(kBadSessionTrailingData) ||
@@ -566,7 +836,9 @@ int main(void) {
!TestDefaultVersion(0, &DTLS_method) ||
!TestDefaultVersion(DTLS1_VERSION, &DTLSv1_method) ||
!TestDefaultVersion(DTLS1_2_VERSION, &DTLSv1_2_method) ||
- !TestCipherGetRFCName()) {
+ !TestCipherGetRFCName() ||
+ !TestPaddingExtension() ||
+ !TestClientCAList()) {
ERR_print_errors_fp(stderr);
return 1;
}
diff --git a/src/ssl/ssl_txt.c b/src/ssl/ssl_txt.c
index 2275f16..3ba0887 100644
--- a/src/ssl/ssl_txt.c
+++ b/src/ssl/ssl_txt.c
@@ -80,12 +80,14 @@
* OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
* OTHERWISE. */
+#include <openssl/ssl.h>
+
#include <inttypes.h>
#include <stdio.h>
-#include <openssl/buf.h>
+#include <openssl/bio.h>
#include <openssl/err.h>
-#include <openssl/mem.h>
+#include <openssl/x509.h>
#include "internal.h"
@@ -96,7 +98,7 @@ int SSL_SESSION_print_fp(FILE *fp, const SSL_SESSION *x) {
b = BIO_new(BIO_s_file());
if (b == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_SESSION_print_fp, ERR_R_BUF_LIB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
return 0;
}
diff --git a/src/ssl/t1_enc.c b/src/ssl/t1_enc.c
index 6bd80c3..076f8bd 100644
--- a/src/ssl/t1_enc.c
+++ b/src/ssl/t1_enc.c
@@ -133,6 +133,8 @@
* OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
* OTHERWISE. */
+#include <openssl/ssl.h>
+
#include <assert.h>
#include <stdio.h>
#include <string.h>
@@ -149,7 +151,7 @@
/* tls1_P_hash computes the TLS P_<hash> function as described in RFC 5246,
- * section 5. It writes |out_len| bytes to |out|, using |md| as the hash and
+ * section 5. It XORs |out_len| bytes to |out|, using |md| as the hash and
* |secret| as the secret. |seed1| through |seed3| are concatenated to form the
* seed parameter. It returns one on success and zero on failure. */
static int tls1_P_hash(uint8_t *out, size_t out_len, const EVP_MD *md,
@@ -188,26 +190,32 @@ static int tls1_P_hash(uint8_t *out, size_t out_len, const EVP_MD *md,
goto err;
}
- if (out_len > chunk) {
- unsigned len;
- if (!HMAC_Final(&ctx, out, &len)) {
- goto err;
- }
- assert(len == chunk);
- out += len;
- out_len -= len;
- /* Calculate the next A1 value. */
- if (!HMAC_Final(&ctx_tmp, A1, &A1_len)) {
- goto err;
- }
- } else {
- /* Last chunk. */
- if (!HMAC_Final(&ctx, A1, &A1_len)) {
- goto err;
- }
- memcpy(out, A1, out_len);
+ unsigned len;
+ uint8_t hmac[EVP_MAX_MD_SIZE];
+ if (!HMAC_Final(&ctx, hmac, &len)) {
+ goto err;
+ }
+ assert(len == chunk);
+
+ /* XOR the result into |out|. */
+ if (len > out_len) {
+ len = out_len;
+ }
+ unsigned i;
+ for (i = 0; i < len; i++) {
+ out[i] ^= hmac[i];
+ }
+ out += len;
+ out_len -= len;
+
+ if (out_len == 0) {
break;
}
+
+ /* Calculate the next A1 value. */
+ if (!HMAC_Final(&ctx_tmp, A1, &A1_len)) {
+ goto err;
+ }
}
ret = 1;
@@ -224,62 +232,36 @@ int tls1_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret,
size_t secret_len, const char *label, size_t label_len,
const uint8_t *seed1, size_t seed1_len,
const uint8_t *seed2, size_t seed2_len) {
- size_t idx, len, count, i;
- const uint8_t *S1;
- uint32_t m;
- const EVP_MD *md;
- int ret = 0;
- uint8_t *tmp;
if (out_len == 0) {
return 1;
}
- /* Allocate a temporary buffer. */
- tmp = OPENSSL_malloc(out_len);
- if (tmp == NULL) {
- OPENSSL_PUT_ERROR(SSL, tls1_prf, ERR_R_MALLOC_FAILURE);
- return 0;
- }
+ memset(out, 0, out_len);
- /* Count number of digests and partition |secret| evenly. */
- count = 0;
- for (idx = 0; ssl_get_handshake_digest(&m, &md, idx); idx++) {
- if (m & ssl_get_algorithm2(s)) {
- count++;
+ uint32_t algorithm_prf = ssl_get_algorithm_prf(s);
+ if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT) {
+ /* If using the MD5/SHA1 PRF, |secret| is partitioned between SHA-1 and
+ * MD5, MD5 first. */
+ size_t secret_half = secret_len - (secret_len / 2);
+ if (!tls1_P_hash(out, out_len, EVP_md5(), secret, secret_half,
+ (const uint8_t *)label, label_len, seed1, seed1_len, seed2,
+ seed2_len)) {
+ return 0;
}
+
+ /* Note that, if |secret_len| is odd, the two halves share a byte. */
+ secret = secret + (secret_len - secret_half);
+ secret_len = secret_half;
}
- /* TODO(davidben): The only case where count isn't 1 is the old MD5/SHA-1
- * combination. The logic around multiple handshake digests can probably be
- * simplified. */
- assert(count == 1 || count == 2);
- len = secret_len / count;
- if (count == 1) {
- secret_len = 0;
- }
- S1 = secret;
- memset(out, 0, out_len);
- for (idx = 0; ssl_get_handshake_digest(&m, &md, idx); idx++) {
- if (m & ssl_get_algorithm2(s)) {
- /* If |count| is 2 and |secret_len| is odd, |secret| is partitioned into
- * two halves with an overlapping byte. */
- if (!tls1_P_hash(tmp, out_len, md, S1, len + (secret_len & 1),
- (const uint8_t *)label, label_len, seed1, seed1_len,
- seed2, seed2_len)) {
- goto err;
- }
- S1 += len;
- for (i = 0; i < out_len; i++) {
- out[i] ^= tmp[i];
- }
- }
+
+ if (!tls1_P_hash(out, out_len, ssl_get_handshake_digest(algorithm_prf),
+ secret, secret_len, (const uint8_t *)label, label_len,
+ seed1, seed1_len, seed2, seed2_len)) {
+ return 0;
}
- ret = 1;
-err:
- OPENSSL_cleanse(tmp, out_len);
- OPENSSL_free(tmp);
- return ret;
+ return 1;
}
static int tls1_generate_key_block(SSL *s, uint8_t *out, size_t out_len) {
@@ -317,7 +299,7 @@ int tls1_change_cipher_state(SSL *s, int which) {
iv_len = s->s3->tmp.new_fixed_iv_len;
if (aead == NULL) {
- OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
@@ -327,7 +309,7 @@ int tls1_change_cipher_state(SSL *s, int which) {
* suites) the key length reported by |EVP_AEAD_key_length| will
* include the MAC and IV key bytes. */
if (key_len < mac_secret_len + iv_len) {
- OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
key_len -= mac_secret_len + iv_len;
@@ -358,7 +340,7 @@ int tls1_change_cipher_state(SSL *s, int which) {
}
if (key_data - s->s3->tmp.key_block != s->s3->tmp.key_block_length) {
- OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
@@ -369,14 +351,26 @@ int tls1_change_cipher_state(SSL *s, int which) {
s->s3->tmp.new_cipher, key, key_len, mac_secret, mac_secret_len, iv,
iv_len);
return s->aead_read_ctx != NULL;
- } else {
- SSL_AEAD_CTX_free(s->aead_write_ctx);
- s->aead_write_ctx = SSL_AEAD_CTX_new(
- evp_aead_seal, ssl3_version_from_wire(s, s->version),
- s->s3->tmp.new_cipher, key, key_len, mac_secret, mac_secret_len, iv,
- iv_len);
- return s->aead_write_ctx != NULL;
}
+
+ SSL_AEAD_CTX_free(s->aead_write_ctx);
+ s->aead_write_ctx = SSL_AEAD_CTX_new(
+ evp_aead_seal, ssl3_version_from_wire(s, s->version),
+ s->s3->tmp.new_cipher, key, key_len, mac_secret, mac_secret_len, iv,
+ iv_len);
+ if (s->aead_write_ctx == NULL) {
+ return 0;
+ }
+
+ s->s3->need_record_splitting = 0;
+ if (!SSL_USE_EXPLICIT_IV(s) &&
+ (s->mode & SSL_MODE_CBC_RECORD_SPLITTING) != 0 &&
+ SSL_CIPHER_is_block_cipher(s->s3->tmp.new_cipher)) {
+ /* Enable 1/n-1 record-splitting to randomize the IV. See
+ * https://www.openssl.org/~bodo/tls-cbc.txt and the BEAST attack. */
+ s->s3->need_record_splitting = 1;
+ }
+ return 1;
}
int tls1_setup_key_block(SSL *s) {
@@ -406,14 +400,14 @@ int tls1_setup_key_block(SSL *s) {
* key length reported by |EVP_AEAD_key_length| will include the MAC key
* bytes and initial implicit IV. */
if (key_len < mac_secret_len + fixed_iv_len) {
- OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
key_len -= mac_secret_len + fixed_iv_len;
} else {
/* The nonce is split into a fixed portion and a variable portion. */
if (variable_iv_len < fixed_iv_len) {
- OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
variable_iv_len -= fixed_iv_len;
@@ -435,7 +429,7 @@ int tls1_setup_key_block(SSL *s) {
p = (uint8_t *)OPENSSL_malloc(key_block_len);
if (p == NULL) {
- OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -446,60 +440,61 @@ int tls1_setup_key_block(SSL *s) {
goto err;
}
- if (!SSL_USE_EXPLICIT_IV(s) &&
- (s->mode & SSL_MODE_CBC_RECORD_SPLITTING) != 0) {
- /* enable vulnerability countermeasure for CBC ciphers with known-IV
- * problem (http://www.openssl.org/~bodo/tls-cbc.txt). */
- s->s3->need_record_splitting = 1;
-
- if (s->session->cipher != NULL &&
- s->session->cipher->algorithm_enc == SSL_RC4) {
- s->s3->need_record_splitting = 0;
- }
- }
-
ret = 1;
err:
return ret;
cipher_unavailable_err:
- OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block,
- SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
return 0;
}
int tls1_cert_verify_mac(SSL *s, int md_nid, uint8_t *out) {
- unsigned int ret;
- EVP_MD_CTX ctx, *d = NULL;
- int i;
-
- if (s->s3->handshake_buffer &&
- !ssl3_digest_cached_records(s, free_handshake_buffer)) {
- return 0;
- }
-
- for (i = 0; i < SSL_MAX_DIGEST; i++) {
- if (s->s3->handshake_dgst[i] &&
- EVP_MD_CTX_type(s->s3->handshake_dgst[i]) == md_nid) {
- d = s->s3->handshake_dgst[i];
- break;
- }
- }
-
- if (!d) {
- OPENSSL_PUT_ERROR(SSL, tls1_cert_verify_mac, SSL_R_NO_REQUIRED_DIGEST);
+ const EVP_MD_CTX *ctx_template;
+ if (md_nid == NID_md5) {
+ ctx_template = &s->s3->handshake_md5;
+ } else if (md_nid == EVP_MD_CTX_type(&s->s3->handshake_hash)) {
+ ctx_template = &s->s3->handshake_hash;
+ } else {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_REQUIRED_DIGEST);
return 0;
}
+ EVP_MD_CTX ctx;
EVP_MD_CTX_init(&ctx);
- if (!EVP_MD_CTX_copy_ex(&ctx, d)) {
+ if (!EVP_MD_CTX_copy_ex(&ctx, ctx_template)) {
EVP_MD_CTX_cleanup(&ctx);
return 0;
}
+ unsigned ret;
EVP_DigestFinal_ex(&ctx, out, &ret);
EVP_MD_CTX_cleanup(&ctx);
+ return ret;
+}
+
+static int append_digest(const EVP_MD_CTX *ctx, uint8_t *out, size_t *out_len,
+ size_t max_out) {
+ int ret = 0;
+ EVP_MD_CTX ctx_copy;
+ EVP_MD_CTX_init(&ctx_copy);
+
+ if (EVP_MD_CTX_size(ctx) > max_out) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
+ goto err;
+ }
+ unsigned len;
+ if (!EVP_MD_CTX_copy_ex(&ctx_copy, ctx) ||
+ !EVP_DigestFinal_ex(&ctx_copy, out, &len)) {
+ goto err;
+ }
+ assert(len == EVP_MD_CTX_size(ctx));
+
+ *out_len = len;
+ ret = 1;
+err:
+ EVP_MD_CTX_cleanup(&ctx_copy);
return ret;
}
@@ -509,44 +504,19 @@ int tls1_cert_verify_mac(SSL *s, int md_nid, uint8_t *out) {
* underlying digests so can be called multiple times and prior to the final
* update etc. */
int tls1_handshake_digest(SSL *s, uint8_t *out, size_t out_len) {
- const EVP_MD *md;
- EVP_MD_CTX ctx;
- int err = 0, len = 0;
- size_t i;
- uint32_t mask;
-
- EVP_MD_CTX_init(&ctx);
-
- for (i = 0; ssl_get_handshake_digest(&mask, &md, i); i++) {
- size_t hash_size;
- unsigned int digest_len;
- EVP_MD_CTX *hdgst = s->s3->handshake_dgst[i];
-
- if ((mask & ssl_get_algorithm2(s)) == 0) {
- continue;
- }
-
- hash_size = EVP_MD_size(md);
- if (!hdgst ||
- hash_size > out_len ||
- !EVP_MD_CTX_copy_ex(&ctx, hdgst) ||
- !EVP_DigestFinal_ex(&ctx, out, &digest_len) ||
- digest_len != hash_size /* internal error */) {
- err = 1;
- break;
- }
-
- out += digest_len;
- out_len -= digest_len;
- len += digest_len;
+ size_t md5_len = 0;
+ if (EVP_MD_CTX_md(&s->s3->handshake_md5) != NULL &&
+ !append_digest(&s->s3->handshake_md5, out, &md5_len, out_len)) {
+ return -1;
}
- EVP_MD_CTX_cleanup(&ctx);
-
- if (err != 0) {
+ size_t len;
+ if (!append_digest(&s->s3->handshake_hash, out + md5_len, &len,
+ out_len - md5_len)) {
return -1;
}
- return len;
+
+ return (int)(md5_len + len);
}
int tls1_final_finish_mac(SSL *s, const char *str, int slen, uint8_t *out) {
@@ -555,14 +525,8 @@ int tls1_final_finish_mac(SSL *s, const char *str, int slen, uint8_t *out) {
int digests_len;
/* At this point, the handshake should have released the handshake buffer on
- * its own.
- * TODO(davidben): Apart from initialization, the handshake buffer should be
- * orthogonal to the handshake digest. https://crbug.com/492371 */
+ * its own. */
assert(s->s3->handshake_buffer == NULL);
- if (s->s3->handshake_buffer &&
- !ssl3_digest_cached_records(s, free_handshake_buffer)) {
- return 0;
- }
digests_len = tls1_handshake_digest(s, buf, sizeof(buf));
if (digests_len < 0) {
@@ -587,21 +551,7 @@ int tls1_generate_master_secret(SSL *s, uint8_t *out, const uint8_t *premaster,
size_t premaster_len) {
if (s->s3->tmp.extended_master_secret) {
uint8_t digests[2 * EVP_MAX_MD_SIZE];
- int digests_len;
-
- /* The master secret is based on the handshake hash just after sending the
- * ClientKeyExchange. However, we might have a client certificate to send,
- * in which case we might need different hashes for the verification and
- * thus still need the handshake buffer around. Keeping both a handshake
- * buffer *and* running hashes isn't yet supported so, when it comes to
- * calculating the Finished hash, we'll have to hash the handshake buffer
- * again. */
- if (s->s3->handshake_buffer &&
- !ssl3_digest_cached_records(s, dont_free_handshake_buffer)) {
- return 0;
- }
-
- digests_len = tls1_handshake_digest(s, digests, sizeof(digests));
+ int digests_len = tls1_handshake_digest(s, digests, sizeof(digests));
if (digests_len == -1) {
return 0;
}
@@ -630,22 +580,21 @@ int tls1_export_keying_material(SSL *s, uint8_t *out, size_t out_len,
const uint8_t *context, size_t context_len,
int use_context) {
if (!s->s3->have_version || s->version == SSL3_VERSION) {
- OPENSSL_PUT_ERROR(SSL, tls1_export_keying_material,
- ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
size_t seed_len = 2 * SSL3_RANDOM_SIZE;
if (use_context) {
if (context_len >= 1u << 16) {
- OPENSSL_PUT_ERROR(SSL, tls1_export_keying_material, ERR_R_OVERFLOW);
+ OPENSSL_PUT_ERROR(SSL, 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);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return 0;
}
diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c
index 213a647..f30e8eb 100644
--- a/src/ssl/t1_lib.c
+++ b/src/ssl/t1_lib.c
@@ -106,12 +106,16 @@
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com). */
+#include <openssl/ssl.h>
+
#include <assert.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/bytestring.h>
+#include <openssl/digest.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
@@ -122,9 +126,6 @@
#include "internal.h"
-static int tls_decrypt_ticket(SSL *s, const uint8_t *tick, int ticklen,
- const uint8_t *sess_id, int sesslen,
- SSL_SESSION **psess);
static int ssl_check_clienthello_tlsext(SSL *s);
static int ssl_check_serverhello_tlsext(SSL *s);
@@ -213,8 +214,7 @@ static int tls1_check_duplicate_extensions(const CBS *cbs) {
extension_types =
(uint16_t *)OPENSSL_malloc(sizeof(uint16_t) * num_extensions);
if (extension_types == NULL) {
- OPENSSL_PUT_ERROR(SSL, tls1_check_duplicate_extensions,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto done;
}
@@ -338,24 +338,21 @@ char SSL_early_callback_ctx_extension_get(
struct tls_curve {
uint16_t curve_id;
int nid;
+ const char curve_name[8];
};
/* ECC curves from RFC4492. */
static const struct tls_curve tls_curves[] = {
- {21, NID_secp224r1},
- {23, NID_X9_62_prime256v1},
- {24, NID_secp384r1},
- {25, NID_secp521r1},
-};
-
-static const uint8_t ecformats_default[] = {
- TLSEXT_ECPOINTFORMAT_uncompressed,
+ {21, NID_secp224r1, "P-224"},
+ {23, NID_X9_62_prime256v1, "P-256"},
+ {24, NID_secp384r1, "P-384"},
+ {25, NID_secp521r1, "P-521"},
};
static const uint16_t eccurves_default[] = {
23, /* X9_62_prime256v1 */
24, /* secp384r1 */
-#if defined(ANDROID)
+#if defined(BORINGSSL_ANDROID_SYSTEM)
25, /* secp521r1 */
#endif
};
@@ -381,6 +378,16 @@ int tls1_ec_nid2curve_id(uint16_t *out_curve_id, int nid) {
return 0;
}
+const char* tls1_ec_curve_id2name(uint16_t curve_id) {
+ size_t i;
+ for (i = 0; i < sizeof(tls_curves) / sizeof(tls_curves[0]); i++) {
+ if (curve_id == tls_curves[i].curve_id) {
+ return tls_curves[i].curve_name;
+ }
+ }
+ return NULL;
+}
+
/* tls1_get_curvelist sets |*out_curve_ids| and |*out_curve_ids_len| to the
* list of allowed curve IDs. If |get_peer_curves| is non-zero, return the
* peer's curve list. Otherwise, return the preferred list. */
@@ -535,28 +542,6 @@ static int tls1_curve_params_from_ec_key(uint16_t *out_curve_id,
return 1;
}
-/* tls1_check_point_format returns one if |comp_id| is consistent with the
- * peer's point format preferences. */
-static int tls1_check_point_format(SSL *s, uint8_t comp_id) {
- uint8_t *p = s->s3->tmp.peer_ecpointformatlist;
- size_t plen = s->s3->tmp.peer_ecpointformatlist_length;
- size_t i;
-
- /* If point formats extension present check it, otherwise everything is
- * supported (see RFC4492). */
- if (p == NULL) {
- return 1;
- }
-
- for (i = 0; i < plen; i++) {
- if (comp_id == p[i]) {
- return 1;
- }
- }
-
- return 0;
-}
-
/* tls1_check_curve_id returns one if |curve_id| is consistent with both our
* and the peer's curve preferences. Note: if called as the client, only our
* preferences are checked; the peer (the server) does not send preferences. */
@@ -593,18 +578,6 @@ static int tls1_check_curve_id(SSL *s, uint16_t curve_id) {
return 1;
}
-static void tls1_get_formatlist(SSL *s, const uint8_t **pformats,
- size_t *pformatslen) {
- /* If we have a custom point format list use it otherwise use default */
- if (s->tlsext_ecpointformatlist) {
- *pformats = s->tlsext_ecpointformatlist;
- *pformatslen = s->tlsext_ecpointformatlist_length;
- } else {
- *pformats = ecformats_default;
- *pformatslen = sizeof(ecformats_default);
- }
-}
-
int tls1_check_ec_cert(SSL *s, X509 *x) {
int ret = 0;
EVP_PKEY *pkey = X509_get_pubkey(x);
@@ -615,7 +588,7 @@ int tls1_check_ec_cert(SSL *s, X509 *x) {
pkey->type != EVP_PKEY_EC ||
!tls1_curve_params_from_ec_key(&curve_id, &comp_id, pkey->pkey.ec) ||
!tls1_check_curve_id(s, curve_id) ||
- !tls1_check_point_format(s, comp_id)) {
+ comp_id != TLSEXT_ECPOINTFORMAT_uncompressed) {
goto done;
}
@@ -663,17 +636,8 @@ static const uint8_t tls12_sigalgs[] = {
};
size_t tls12_get_psigalgs(SSL *s, const uint8_t **psigs) {
- /* If server use client authentication sigalgs if not NULL */
- if (s->server && s->cert->client_sigalgs) {
- *psigs = s->cert->client_sigalgs;
- return s->cert->client_sigalgslen;
- } else if (s->cert->conf_sigalgs) {
- *psigs = s->cert->conf_sigalgs;
- return s->cert->conf_sigalgslen;
- } else {
- *psigs = tls12_sigalgs;
- return sizeof(tls12_sigalgs);
- }
+ *psigs = tls12_sigalgs;
+ return sizeof(tls12_sigalgs);
}
/* tls12_check_peer_sigalg parses a SignatureAndHashAlgorithm out of |cbs|. It
@@ -684,26 +648,26 @@ int tls12_check_peer_sigalg(const EVP_MD **out_md, int *out_alert, SSL *s,
CBS *cbs, EVP_PKEY *pkey) {
const uint8_t *sent_sigs;
size_t sent_sigslen, i;
- int sigalg = tls12_get_sigid(pkey);
+ int sigalg = tls12_get_sigid(pkey->type);
uint8_t hash, signature;
/* Should never happen */
if (sigalg == -1) {
- OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
*out_alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
if (!CBS_get_u8(cbs, &hash) ||
!CBS_get_u8(cbs, &signature)) {
- OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
*out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
/* Check key type is consistent with signature */
if (sigalg != signature) {
- OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_WRONG_SIGNATURE_TYPE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
@@ -718,8 +682,8 @@ int tls12_check_peer_sigalg(const EVP_MD **out_md, int *out_alert, SSL *s,
}
if (s->server && (!tls1_check_curve_id(s, curve_id) ||
- !tls1_check_point_format(s, comp_id))) {
- OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_WRONG_CURVE);
+ comp_id != TLSEXT_ECPOINTFORMAT_uncompressed)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
@@ -735,14 +699,14 @@ int tls12_check_peer_sigalg(const EVP_MD **out_md, int *out_alert, SSL *s,
/* Allow fallback to SHA-1. */
if (i == sent_sigslen && hash != TLSEXT_hash_sha1) {
- OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_WRONG_SIGNATURE_TYPE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
*out_md = tls12_get_hash(hash);
if (*out_md == NULL) {
- OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_UNKNOWN_DIGEST);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_DIGEST);
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
@@ -799,1128 +763,1785 @@ void ssl_set_client_disabled(SSL *s) {
}
}
-/* header_len is the length of the ClientHello header written so far, used to
- * compute padding. It does not include the record header. Pass 0 if no padding
- * is to be done. */
-uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit,
- size_t header_len) {
- int extdatalen = 0;
- uint8_t *ret = buf;
- uint8_t *orig = buf;
- /* See if we support any ECC ciphersuites */
- int using_ecc = 0;
-
- if (s->version >= TLS1_VERSION || SSL_IS_DTLS(s)) {
- size_t i;
- uint32_t alg_k, alg_a;
- STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
-
- for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) {
- const SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
-
- alg_k = c->algorithm_mkey;
- alg_a = c->algorithm_auth;
- if ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)) {
- using_ecc = 1;
- break;
- }
- }
+/* tls_extension represents a TLS extension that is handled internally. The
+ * |init| function is called for each handshake, before any other functions of
+ * the extension. Then the add and parse callbacks are called as needed.
+ *
+ * The parse callbacks receive a |CBS| that contains the contents of the
+ * extension (i.e. not including the type and length bytes). If an extension is
+ * not received then the parse callbacks will be called with a NULL CBS so that
+ * they can do any processing needed to handle the absence of an extension.
+ *
+ * The add callbacks receive a |CBB| to which the extension can be appended but
+ * the function is responsible for appending the type and length bytes too.
+ *
+ * All callbacks return one for success and zero for error. If a parse function
+ * returns zero then a fatal alert with value |*out_alert| will be sent. If
+ * |*out_alert| isn't set, then a |decode_error| alert will be sent. */
+struct tls_extension {
+ uint16_t value;
+ void (*init)(SSL *ssl);
+
+ int (*add_clienthello)(SSL *ssl, CBB *out);
+ int (*parse_serverhello)(SSL *ssl, uint8_t *out_alert, CBS *contents);
+
+ int (*parse_clienthello)(SSL *ssl, uint8_t *out_alert, CBS *contents);
+ int (*add_serverhello)(SSL *ssl, CBB *out);
+};
+
+
+/* Server name indication (SNI).
+ *
+ * https://tools.ietf.org/html/rfc6066#section-3. */
+
+static void ext_sni_init(SSL *ssl) {
+ ssl->s3->tmp.should_ack_sni = 0;
+}
+
+static int ext_sni_add_clienthello(SSL *ssl, CBB *out) {
+ if (ssl->tlsext_hostname == NULL) {
+ return 1;
}
- /* don't add extensions for SSLv3 unless doing secure renegotiation */
- if (s->client_version == SSL3_VERSION && !s->s3->send_connection_binding) {
- return orig;
+ CBB contents, server_name_list, name;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_server_name) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &server_name_list) ||
+ !CBB_add_u8(&server_name_list, TLSEXT_NAMETYPE_host_name) ||
+ !CBB_add_u16_length_prefixed(&server_name_list, &name) ||
+ !CBB_add_bytes(&name, (const uint8_t *)ssl->tlsext_hostname,
+ strlen(ssl->tlsext_hostname)) ||
+ !CBB_flush(out)) {
+ return 0;
}
- ret += 2;
+ return 1;
+}
- if (ret >= limit) {
- return NULL; /* should never occur. */
+static int ext_sni_parse_serverhello(SSL *ssl, uint8_t *out_alert, CBS *contents) {
+ if (contents == NULL) {
+ return 1;
}
- if (s->tlsext_hostname != NULL) {
- /* Add TLS extension servername to the Client Hello message */
- unsigned long size_str;
- long lenmax;
+ if (CBS_len(contents) != 0) {
+ return 0;
+ }
- /* check for enough space.
- 4 for the servername type and entension length
- 2 for servernamelist length
- 1 for the hostname type
- 2 for hostname length
- + hostname length */
+ assert(ssl->tlsext_hostname != NULL);
- lenmax = limit - ret - 9;
- size_str = strlen(s->tlsext_hostname);
- if (lenmax < 0 || size_str > (unsigned long)lenmax) {
- return NULL;
+ if (!ssl->hit) {
+ assert(ssl->session->tlsext_hostname == NULL);
+ ssl->session->tlsext_hostname = BUF_strdup(ssl->tlsext_hostname);
+ if (!ssl->session->tlsext_hostname) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
}
+ }
- /* extension type and length */
- s2n(TLSEXT_TYPE_server_name, ret);
- s2n(size_str + 5, ret);
+ return 1;
+}
- /* length of servername list */
- s2n(size_str + 3, ret);
+static int ext_sni_parse_clienthello(SSL *ssl, uint8_t *out_alert, CBS *contents) {
+ if (contents == NULL) {
+ return 1;
+ }
- /* hostname type, length and hostname */
- *(ret++) = (uint8_t)TLSEXT_NAMETYPE_host_name;
- s2n(size_str, ret);
- memcpy(ret, s->tlsext_hostname, size_str);
- ret += size_str;
+ /* The servername extension is treated as follows:
+ *
+ * - Only the hostname type is supported with a maximum length of 255.
+ * - The servername is rejected if too long or if it contains zeros, in
+ * which case an fatal alert is generated.
+ * - The servername field is maintained together with the session cache.
+ * - When a session is resumed, the servername callback is invoked in order
+ * to allow the application to position itself to the right context.
+ * - The servername is acknowledged if it is new for a session or when
+ * it is identical to a previously used for the same session.
+ * Applications can control the behaviour. They can at any time
+ * set a 'desirable' servername for a new SSL object. This can be the
+ * case for example with HTTPS when a Host: header field is received and
+ * a renegotiation is requested. In this case, a possible servername
+ * presented in the new client hello is only acknowledged if it matches
+ * the value of the Host: field.
+ * - Applications must use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+ * if they provide for changing an explicit servername context for the
+ * session,
+ * i.e. when the session has been established with a servername extension.
+ */
+
+ CBS server_name_list;
+ char have_seen_host_name = 0;
+
+ if (!CBS_get_u16_length_prefixed(contents, &server_name_list) ||
+ CBS_len(&server_name_list) == 0 ||
+ CBS_len(contents) != 0) {
+ return 0;
}
- /* Add RI if renegotiating */
- if (s->s3->initial_handshake_complete) {
- int el;
+ /* Decode each ServerName in the extension. */
+ while (CBS_len(&server_name_list) > 0) {
+ uint8_t name_type;
+ CBS host_name;
- if (!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0)) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR);
- return NULL;
+ if (!CBS_get_u8(&server_name_list, &name_type) ||
+ !CBS_get_u16_length_prefixed(&server_name_list, &host_name)) {
+ return 0;
}
- if ((limit - ret - 4 - el) < 0) {
- return NULL;
+ /* Only host_name is supported. */
+ if (name_type != TLSEXT_NAMETYPE_host_name) {
+ continue;
}
- s2n(TLSEXT_TYPE_renegotiate, ret);
- s2n(el, ret);
-
- if (!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el)) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR);
- return NULL;
+ if (have_seen_host_name) {
+ /* The ServerNameList MUST NOT contain more than one name of the same
+ * name_type. */
+ return 0;
}
- ret += el;
- }
+ have_seen_host_name = 1;
- /* Add extended master secret. */
- if (s->version != SSL3_VERSION) {
- if (limit - ret - 4 < 0) {
- return NULL;
- }
- s2n(TLSEXT_TYPE_extended_master_secret, ret);
- s2n(0, ret);
- }
-
- if (!(SSL_get_options(s) & SSL_OP_NO_TICKET)) {
- int ticklen = 0;
- /* Renegotiation does not participate in session resumption. However, still
- * advertise the extension to avoid potentially breaking servers which carry
- * over the state from the previous handshake, such as OpenSSL servers
- * without upstream's 3c3f0259238594d77264a78944d409f2127642c4. */
- if (!s->s3->initial_handshake_complete && s->session != NULL &&
- s->session->tlsext_tick != NULL) {
- ticklen = s->session->tlsext_ticklen;
+ if (CBS_len(&host_name) == 0 ||
+ CBS_len(&host_name) > TLSEXT_MAXLEN_host_name ||
+ CBS_contains_zero_byte(&host_name)) {
+ *out_alert = SSL_AD_UNRECOGNIZED_NAME;
+ return 0;
}
- /* Check for enough room 2 for extension type, 2 for len rest for
- * ticket. */
- if ((long)(limit - ret - 4 - ticklen) < 0) {
- return NULL;
- }
- s2n(TLSEXT_TYPE_session_ticket, ret);
- s2n(ticklen, ret);
- if (ticklen) {
- memcpy(ret, s->session->tlsext_tick, ticklen);
- ret += ticklen;
+ if (!ssl->hit) {
+ assert(ssl->session->tlsext_hostname == NULL);
+ if (ssl->session->tlsext_hostname) {
+ /* This should be impossible. */
+ return 0;
+ }
+
+ /* Copy the hostname as a string. */
+ if (!CBS_strdup(&host_name, &ssl->session->tlsext_hostname)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+
+ ssl->s3->tmp.should_ack_sni = 1;
}
}
- if (ssl3_version_from_wire(s, s->client_version) >= TLS1_2_VERSION) {
- size_t salglen;
- const uint8_t *salg;
- salglen = tls12_get_psigalgs(s, &salg);
- if ((size_t)(limit - ret) < salglen + 6) {
- return NULL;
- }
- s2n(TLSEXT_TYPE_signature_algorithms, ret);
- s2n(salglen + 2, ret);
- s2n(salglen, ret);
- memcpy(ret, salg, salglen);
- ret += salglen;
- }
-
- if (s->ocsp_stapling_enabled) {
- /* The status_request extension is excessively extensible at every layer.
- * On the client, only support requesting OCSP responses with an empty
- * responder_id_list and no extensions. */
- if (limit - ret - 4 - 1 - 2 - 2 < 0) {
- return NULL;
- }
+ return 1;
+}
- s2n(TLSEXT_TYPE_status_request, ret);
- s2n(1 + 2 + 2, ret);
- /* status_type */
- *(ret++) = TLSEXT_STATUSTYPE_ocsp;
- /* responder_id_list - empty */
- s2n(0, ret);
- /* request_extensions - empty */
- s2n(0, ret);
- }
-
- if (s->ctx->next_proto_select_cb && !s->s3->initial_handshake_complete &&
- !SSL_IS_DTLS(s)) {
- /* The client advertises an emtpy extension to indicate its support for
- * Next Protocol Negotiation */
- if (limit - ret - 4 < 0) {
- return NULL;
- }
- s2n(TLSEXT_TYPE_next_proto_neg, ret);
- s2n(0, ret);
+static int ext_sni_add_serverhello(SSL *ssl, CBB *out) {
+ if (ssl->hit ||
+ !ssl->s3->tmp.should_ack_sni ||
+ ssl->session->tlsext_hostname == NULL) {
+ return 1;
}
- if (s->signed_cert_timestamps_enabled) {
- /* The client advertises an empty extension to indicate its support for
- * certificate timestamps. */
- if (limit - ret - 4 < 0) {
- return NULL;
- }
- s2n(TLSEXT_TYPE_certificate_timestamp, ret);
- s2n(0, ret);
+ if (!CBB_add_u16(out, TLSEXT_TYPE_server_name) ||
+ !CBB_add_u16(out, 0 /* length */)) {
+ return 0;
}
- if (s->alpn_client_proto_list && !s->s3->initial_handshake_complete) {
- if ((size_t)(limit - ret) < 6 + s->alpn_client_proto_list_len) {
- return NULL;
- }
- s2n(TLSEXT_TYPE_application_layer_protocol_negotiation, ret);
- s2n(2 + s->alpn_client_proto_list_len, ret);
- s2n(s->alpn_client_proto_list_len, ret);
- memcpy(ret, s->alpn_client_proto_list, s->alpn_client_proto_list_len);
- ret += s->alpn_client_proto_list_len;
+ return 1;
+}
+
+
+/* Renegotiation indication.
+ *
+ * https://tools.ietf.org/html/rfc5746 */
+
+static int ext_ri_add_clienthello(SSL *ssl, CBB *out) {
+ CBB contents, prev_finished;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_renegotiate) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u8_length_prefixed(&contents, &prev_finished) ||
+ !CBB_add_bytes(&prev_finished, ssl->s3->previous_client_finished,
+ ssl->s3->previous_client_finished_len) ||
+ !CBB_flush(out)) {
+ return 0;
}
- if (s->tlsext_channel_id_enabled && !SSL_IS_DTLS(s)) {
- /* The client advertises an emtpy extension to indicate its support for
- * Channel ID. */
- if (limit - ret - 4 < 0) {
- return NULL;
+ return 1;
+}
+
+static int ext_ri_parse_serverhello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ /* No renegotiation extension received.
+ *
+ * Strictly speaking if we want to avoid an attack we should *always* see
+ * RI even on initial ServerHello because the client doesn't see any
+ * renegotiation during an attack. However this would mean we could not
+ * connect to any server which doesn't support RI.
+ *
+ * A lack of the extension is allowed if SSL_OP_LEGACY_SERVER_CONNECT is
+ * defined. */
+ if (ssl->options & SSL_OP_LEGACY_SERVER_CONNECT) {
+ return 1;
}
- if (s->ctx->tlsext_channel_id_enabled_new) {
- s2n(TLSEXT_TYPE_channel_id_new, ret);
+
+ *out_alert = SSL_AD_HANDSHAKE_FAILURE;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+ return 0;
+ }
+
+ const size_t expected_len = ssl->s3->previous_client_finished_len +
+ ssl->s3->previous_server_finished_len;
+
+ /* Check for logic errors */
+ assert(!expected_len || ssl->s3->previous_client_finished_len);
+ assert(!expected_len || ssl->s3->previous_server_finished_len);
+
+ /* Parse out the extension contents. */
+ CBS renegotiated_connection;
+ if (!CBS_get_u8_length_prefixed(contents, &renegotiated_connection) ||
+ CBS_len(contents) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_ENCODING_ERR);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+
+ /* Check that the extension matches. */
+ if (CBS_len(&renegotiated_connection) != expected_len) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH);
+ *out_alert = SSL_AD_HANDSHAKE_FAILURE;
+ return 0;
+ }
+
+ const uint8_t *d = CBS_data(&renegotiated_connection);
+ if (CRYPTO_memcmp(d, ssl->s3->previous_client_finished,
+ ssl->s3->previous_client_finished_len)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH);
+ *out_alert = SSL_AD_HANDSHAKE_FAILURE;
+ return 0;
+ }
+ d += ssl->s3->previous_client_finished_len;
+
+ if (CRYPTO_memcmp(d, ssl->s3->previous_server_finished,
+ ssl->s3->previous_server_finished_len)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+ ssl->s3->send_connection_binding = 1;
+
+ return 1;
+}
+
+static int ext_ri_parse_clienthello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ /* Renegotiation isn't supported as a server so this function should never be
+ * called after the initial handshake. */
+ assert(!ssl->s3->initial_handshake_complete);
+
+ CBS fake_contents;
+ static const uint8_t kFakeExtension[] = {0};
+
+ if (contents == NULL) {
+ if (ssl->s3->send_connection_binding) {
+ /* The renegotiation SCSV was received so pretend that we received a
+ * renegotiation extension. */
+ CBS_init(&fake_contents, kFakeExtension, sizeof(kFakeExtension));
+ contents = &fake_contents;
+ /* We require that the renegotiation extension is at index zero of
+ * kExtensions. */
+ ssl->s3->tmp.extensions.received |= (1u << 0);
} else {
- s2n(TLSEXT_TYPE_channel_id, ret);
+ return 1;
}
- s2n(0, ret);
}
- if (SSL_get_srtp_profiles(s)) {
- int el;
+ CBS renegotiated_connection;
- ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0);
+ if (!CBS_get_u8_length_prefixed(contents, &renegotiated_connection) ||
+ CBS_len(contents) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_ENCODING_ERR);
+ return 0;
+ }
- if ((limit - ret - 4 - el) < 0) {
- return NULL;
- }
+ /* Check that the extension matches */
+ if (!CBS_mem_equal(&renegotiated_connection, ssl->s3->previous_client_finished,
+ ssl->s3->previous_client_finished_len)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH);
+ *out_alert = SSL_AD_HANDSHAKE_FAILURE;
+ return 0;
+ }
- s2n(TLSEXT_TYPE_use_srtp, ret);
- s2n(el, ret);
+ ssl->s3->send_connection_binding = 1;
- if (!ssl_add_clienthello_use_srtp_ext(s, ret, &el, el)) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
- ret += el;
+ return 1;
+}
+
+static int ext_ri_add_serverhello(SSL *ssl, CBB *out) {
+ CBB contents, prev_finished;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_renegotiate) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u8_length_prefixed(&contents, &prev_finished) ||
+ !CBB_add_bytes(&prev_finished, ssl->s3->previous_client_finished,
+ ssl->s3->previous_client_finished_len) ||
+ !CBB_add_bytes(&prev_finished, ssl->s3->previous_server_finished,
+ ssl->s3->previous_server_finished_len) ||
+ !CBB_flush(out)) {
+ return 0;
}
- if (using_ecc) {
- /* Add TLS extension ECPointFormats to the ClientHello message */
- long lenmax;
- const uint8_t *formats;
- const uint16_t *curves;
- size_t formats_len, curves_len, i;
+ return 1;
+}
- tls1_get_formatlist(s, &formats, &formats_len);
- lenmax = limit - ret - 5;
- if (lenmax < 0) {
- return NULL;
- }
- if (formats_len > (size_t)lenmax) {
- return NULL;
- }
- if (formats_len > 255) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
+/* Extended Master Secret.
+ *
+ * https://tools.ietf.org/html/draft-ietf-tls-session-hash-05 */
- s2n(TLSEXT_TYPE_ec_point_formats, ret);
- s2n(formats_len + 1, ret);
- *(ret++) = (uint8_t)formats_len;
- memcpy(ret, formats, formats_len);
- ret += formats_len;
+static void ext_ems_init(SSL *ssl) {
+ ssl->s3->tmp.extended_master_secret = 0;
+}
- /* Add TLS extension EllipticCurves to the ClientHello message */
- tls1_get_curvelist(s, 0, &curves, &curves_len);
+static int ext_ems_add_clienthello(SSL *ssl, CBB *out) {
+ if (ssl->version == SSL3_VERSION) {
+ return 1;
+ }
- lenmax = limit - ret - 6;
- if (lenmax < 0) {
- return NULL;
- }
- if (curves_len * 2 > (size_t)lenmax) {
- return NULL;
- }
- if (curves_len * 2 > 65532) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
+ if (!CBB_add_u16(out, TLSEXT_TYPE_extended_master_secret) ||
+ !CBB_add_u16(out, 0 /* length */)) {
+ return 0;
+ }
- s2n(TLSEXT_TYPE_elliptic_curves, ret);
- s2n((curves_len * 2) + 2, ret);
+ return 1;
+}
- s2n(curves_len * 2, ret);
- for (i = 0; i < curves_len; i++) {
- s2n(curves[i], ret);
- }
+static int ext_ems_parse_serverhello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
}
- if (header_len > 0) {
- size_t clienthello_minsize = 0;
- header_len += ret - orig;
- if (header_len > 0xff && header_len < 0x200) {
- /* Add padding to workaround bugs in F5 terminators. See
- * https://tools.ietf.org/html/draft-agl-tls-padding-03
- *
- * NB: because this code works out the length of all existing extensions
- * it MUST always appear last. */
- clienthello_minsize = 0x200;
- }
- if (s->fastradio_padding) {
- /* Pad the ClientHello record to 1024 bytes to fast forward the radio
- * into DCH (high data rate) state in 3G networks. Note that when
- * fastradio_padding is enabled, even if the header_len is less than 255
- * bytes, the padding will be applied regardless. This is slightly
- * different from the TLS padding extension suggested in
- * https://tools.ietf.org/html/draft-agl-tls-padding-03 */
- clienthello_minsize = 0x400;
- }
- if (header_len < clienthello_minsize) {
- size_t padding_len = clienthello_minsize - header_len;
- /* Extensions take at least four bytes to encode. Always include least
- * one byte of data if including the extension. WebSphere Application
- * Server 7.0 is intolerant to the last extension being zero-length. */
- if (padding_len >= 4 + 1) {
- padding_len -= 4;
- } else {
- padding_len = 1;
- }
+ if (ssl->version == SSL3_VERSION || CBS_len(contents) != 0) {
+ return 0;
+ }
- if (limit - ret - 4 - (long)padding_len < 0) {
- return NULL;
- }
+ ssl->s3->tmp.extended_master_secret = 1;
+ return 1;
+}
- s2n(TLSEXT_TYPE_padding, ret);
- s2n(padding_len, ret);
- memset(ret, 0, padding_len);
- ret += padding_len;
- }
+static int ext_ems_parse_clienthello(SSL *ssl, uint8_t *out_alert, CBS *contents) {
+ if (ssl->version == SSL3_VERSION || contents == NULL) {
+ return 1;
}
- extdatalen = ret - orig - 2;
- if (extdatalen == 0) {
- return orig;
+ if (CBS_len(contents) != 0) {
+ return 0;
}
- s2n(extdatalen, orig);
- return ret;
+ ssl->s3->tmp.extended_master_secret = 1;
+ return 1;
}
-uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit) {
- int extdatalen = 0;
- uint8_t *orig = buf;
- uint8_t *ret = buf;
- int next_proto_neg_seen;
- uint32_t alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
- uint32_t alg_a = s->s3->tmp.new_cipher->algorithm_auth;
- int using_ecc = (alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA);
- using_ecc = using_ecc && (s->s3->tmp.peer_ecpointformatlist != NULL);
+static int ext_ems_add_serverhello(SSL *ssl, CBB *out) {
+ if (!ssl->s3->tmp.extended_master_secret) {
+ return 1;
+ }
- /* don't add extensions for SSLv3, unless doing secure renegotiation */
- if (s->version == SSL3_VERSION && !s->s3->send_connection_binding) {
- return orig;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_extended_master_secret) ||
+ !CBB_add_u16(out, 0 /* length */)) {
+ return 0;
}
- ret += 2;
- if (ret >= limit) {
- return NULL; /* should never happen. */
+ return 1;
+}
+
+
+/* Session tickets.
+ *
+ * https://tools.ietf.org/html/rfc5077 */
+
+static int ext_ticket_add_clienthello(SSL *ssl, CBB *out) {
+ if (SSL_get_options(ssl) & SSL_OP_NO_TICKET) {
+ return 1;
}
- if (!s->hit && s->should_ack_sni && s->session->tlsext_hostname != NULL) {
- if ((long)(limit - ret - 4) < 0) {
- return NULL;
- }
+ const uint8_t *ticket_data = NULL;
+ int ticket_len = 0;
- s2n(TLSEXT_TYPE_server_name, ret);
- s2n(0, ret);
+ /* Renegotiation does not participate in session resumption. However, still
+ * advertise the extension to avoid potentially breaking servers which carry
+ * over the state from the previous handshake, such as OpenSSL servers
+ * without upstream's 3c3f0259238594d77264a78944d409f2127642c4. */
+ if (!ssl->s3->initial_handshake_complete &&
+ ssl->session != NULL &&
+ ssl->session->tlsext_tick != NULL) {
+ ticket_data = ssl->session->tlsext_tick;
+ ticket_len = ssl->session->tlsext_ticklen;
}
- if (s->s3->send_connection_binding) {
- int el;
+ CBB ticket;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_session_ticket) ||
+ !CBB_add_u16_length_prefixed(out, &ticket) ||
+ !CBB_add_bytes(&ticket, ticket_data, ticket_len) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
- if (!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0)) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
+ return 1;
+}
- if ((limit - ret - 4 - el) < 0) {
- return NULL;
- }
+static int ext_ticket_parse_serverhello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ ssl->tlsext_ticket_expected = 0;
- s2n(TLSEXT_TYPE_renegotiate, ret);
- s2n(el, ret);
+ if (contents == NULL) {
+ return 1;
+ }
- if (!ssl_add_serverhello_renegotiate_ext(s, ret, &el, el)) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
+ /* If |SSL_OP_NO_TICKET| is set then no extension will have been sent and
+ * this function should never be called, even if the server tries to send the
+ * extension. */
+ assert((SSL_get_options(ssl) & SSL_OP_NO_TICKET) == 0);
- ret += el;
+ if (CBS_len(contents) != 0) {
+ return 0;
}
- if (s->s3->tmp.extended_master_secret) {
- if ((long)(limit - ret - 4) < 0) {
- return NULL;
- }
+ ssl->tlsext_ticket_expected = 1;
+ return 1;
+}
+
+static int ext_ticket_parse_clienthello(SSL *ssl, uint8_t *out_alert, CBS *contents) {
+ /* This function isn't used because the ticket extension from the client is
+ * handled in ssl_sess.c. */
+ return 1;
+}
- s2n(TLSEXT_TYPE_extended_master_secret, ret);
- s2n(0, ret);
+static int ext_ticket_add_serverhello(SSL *ssl, CBB *out) {
+ if (!ssl->tlsext_ticket_expected) {
+ return 1;
}
- if (using_ecc) {
- const uint8_t *plist;
- size_t plistlen;
- /* Add TLS extension ECPointFormats to the ServerHello message */
- long lenmax;
+ /* If |SSL_OP_NO_TICKET| is set, |tlsext_ticket_expected| should never be
+ * true. */
+ assert((SSL_get_options(ssl) & SSL_OP_NO_TICKET) == 0);
- tls1_get_formatlist(s, &plist, &plistlen);
+ if (!CBB_add_u16(out, TLSEXT_TYPE_session_ticket) ||
+ !CBB_add_u16(out, 0 /* length */)) {
+ return 0;
+ }
- lenmax = limit - ret - 5;
- if (lenmax < 0) {
- return NULL;
- }
- if (plistlen > (size_t)lenmax) {
- return NULL;
- }
- if (plistlen > 255) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
+ return 1;
+}
- s2n(TLSEXT_TYPE_ec_point_formats, ret);
- s2n(plistlen + 1, ret);
- *(ret++) = (uint8_t)plistlen;
- memcpy(ret, plist, plistlen);
- ret += plistlen;
+
+/* Signature Algorithms.
+ *
+ * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
+
+static int ext_sigalgs_add_clienthello(SSL *ssl, CBB *out) {
+ if (ssl3_version_from_wire(ssl, ssl->client_version) < TLS1_2_VERSION) {
+ return 1;
}
- /* Currently the server should not respond with a SupportedCurves extension */
- if (s->tlsext_ticket_expected && !(SSL_get_options(s) & SSL_OP_NO_TICKET)) {
- if ((long)(limit - ret - 4) < 0) {
- return NULL;
- }
- s2n(TLSEXT_TYPE_session_ticket, ret);
- s2n(0, ret);
+ const uint8_t *sigalgs_data;
+ const size_t sigalgs_len = tls12_get_psigalgs(ssl, &sigalgs_data);
+
+ CBB contents, sigalgs;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_signature_algorithms) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &sigalgs) ||
+ !CBB_add_bytes(&sigalgs, sigalgs_data, sigalgs_len) ||
+ !CBB_flush(out)) {
+ return 0;
}
- if (s->s3->tmp.certificate_status_expected) {
- if ((long)(limit - ret - 4) < 0) {
- return NULL;
- }
- s2n(TLSEXT_TYPE_status_request, ret);
- s2n(0, ret);
+ return 1;
+}
+
+static int ext_sigalgs_parse_serverhello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents != NULL) {
+ /* Servers MUST NOT send this extension. */
+ *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER);
+ return 0;
}
- if (s->srtp_profile) {
- int el;
+ return 1;
+}
- ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0);
+static int ext_sigalgs_parse_clienthello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ OPENSSL_free(ssl->cert->peer_sigalgs);
+ ssl->cert->peer_sigalgs = NULL;
+ ssl->cert->peer_sigalgslen = 0;
- if ((limit - ret - 4 - el) < 0) {
- return NULL;
- }
+ if (contents == NULL) {
+ return 1;
+ }
- s2n(TLSEXT_TYPE_use_srtp, ret);
- s2n(el, ret);
+ CBS supported_signature_algorithms;
+ if (!CBS_get_u16_length_prefixed(contents, &supported_signature_algorithms) ||
+ CBS_len(contents) != 0 ||
+ CBS_len(&supported_signature_algorithms) == 0 ||
+ !tls1_parse_peer_sigalgs(ssl, &supported_signature_algorithms)) {
+ return 0;
+ }
- if (!ssl_add_serverhello_use_srtp_ext(s, ret, &el, el)) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
- ret += el;
+ return 1;
+}
+
+static int ext_sigalgs_add_serverhello(SSL *ssl, CBB *out) {
+ /* Servers MUST NOT send this extension. */
+ return 1;
+}
+
+
+/* OCSP Stapling.
+ *
+ * https://tools.ietf.org/html/rfc6066#section-8 */
+
+static void ext_ocsp_init(SSL *ssl) {
+ ssl->s3->tmp.certificate_status_expected = 0;
+}
+
+static int ext_ocsp_add_clienthello(SSL *ssl, CBB *out) {
+ if (!ssl->ocsp_stapling_enabled) {
+ return 1;
+ }
+
+ CBB contents;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_status_request) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u8(&contents, TLSEXT_STATUSTYPE_ocsp) ||
+ !CBB_add_u16(&contents, 0 /* empty responder ID list */) ||
+ !CBB_add_u16(&contents, 0 /* empty request extensions */) ||
+ !CBB_flush(out)) {
+ return 0;
}
- next_proto_neg_seen = s->s3->next_proto_neg_seen;
- s->s3->next_proto_neg_seen = 0;
- if (next_proto_neg_seen && s->ctx->next_protos_advertised_cb) {
- const uint8_t *npa;
- unsigned int npalen;
- int r;
+ return 1;
+}
- r = s->ctx->next_protos_advertised_cb(
- s, &npa, &npalen, s->ctx->next_protos_advertised_cb_arg);
- if (r == SSL_TLSEXT_ERR_OK) {
- if ((long)(limit - ret - 4 - npalen) < 0) {
- return NULL;
- }
- s2n(TLSEXT_TYPE_next_proto_neg, ret);
- s2n(npalen, ret);
- memcpy(ret, npa, npalen);
- ret += npalen;
- s->s3->next_proto_neg_seen = 1;
- }
+static int ext_ocsp_parse_serverhello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
}
- if (s->s3->alpn_selected) {
- const uint8_t *selected = s->s3->alpn_selected;
- size_t len = s->s3->alpn_selected_len;
+ if (CBS_len(contents) != 0) {
+ return 0;
+ }
- if ((long)(limit - ret - 4 - 2 - 1 - len) < 0) {
- return NULL;
- }
- s2n(TLSEXT_TYPE_application_layer_protocol_negotiation, ret);
- s2n(3 + len, ret);
- s2n(1 + len, ret);
- *ret++ = len;
- memcpy(ret, selected, len);
- ret += len;
- }
-
- /* If the client advertised support for Channel ID, and we have it
- * enabled, then we want to echo it back. */
- if (s->s3->tlsext_channel_id_valid) {
- if (limit - ret - 4 < 0) {
- return NULL;
- }
- if (s->s3->tlsext_channel_id_new) {
- s2n(TLSEXT_TYPE_channel_id_new, ret);
- } else {
- s2n(TLSEXT_TYPE_channel_id, ret);
- }
- s2n(0, ret);
+ ssl->s3->tmp.certificate_status_expected = 1;
+ return 1;
+}
+
+static int ext_ocsp_parse_clienthello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
}
- extdatalen = ret - orig - 2;
- if (extdatalen == 0) {
- return orig;
+ uint8_t status_type;
+ if (!CBS_get_u8(contents, &status_type)) {
+ return 0;
}
- s2n(extdatalen, orig);
- return ret;
+ /* We cannot decide whether OCSP stapling will occur yet because the correct
+ * SSL_CTX might not have been selected. */
+ ssl->s3->tmp.ocsp_stapling_requested = status_type == TLSEXT_STATUSTYPE_ocsp;
+
+ return 1;
+}
+
+static int ext_ocsp_add_serverhello(SSL *ssl, CBB *out) {
+ /* The extension shouldn't be sent when resuming sessions. */
+ if (ssl->hit ||
+ !ssl->s3->tmp.ocsp_stapling_requested ||
+ ssl->ctx->ocsp_response_length == 0) {
+ return 1;
+ }
+
+ ssl->s3->tmp.certificate_status_expected = 1;
+
+ return CBB_add_u16(out, TLSEXT_TYPE_status_request) &&
+ CBB_add_u16(out, 0 /* length */);
}
-/* tls1_alpn_handle_client_hello is called to process the ALPN extension in a
- * ClientHello.
- * cbs: the contents of the extension, not including the type and length.
- * out_alert: a pointer to the alert value to send in the event of a zero
- * return.
+
+/* Next protocol negotiation.
*
- * returns: 1 on success. */
-static int tls1_alpn_handle_client_hello(SSL *s, CBS *cbs, int *out_alert) {
- CBS protocol_name_list, protocol_name_list_copy;
- const uint8_t *selected;
+ * https://htmlpreview.github.io/?https://github.com/agl/technotes/blob/master/nextprotoneg.html */
+
+static void ext_npn_init(SSL *ssl) {
+ ssl->s3->next_proto_neg_seen = 0;
+}
+
+static int ext_npn_add_clienthello(SSL *ssl, CBB *out) {
+ if (ssl->s3->initial_handshake_complete ||
+ ssl->ctx->next_proto_select_cb == NULL ||
+ SSL_IS_DTLS(ssl)) {
+ return 1;
+ }
+
+ if (!CBB_add_u16(out, TLSEXT_TYPE_next_proto_neg) ||
+ !CBB_add_u16(out, 0 /* length */)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_npn_parse_serverhello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
+ }
+
+ /* If any of these are false then we should never have sent the NPN
+ * extension in the ClientHello and thus this function should never have been
+ * called. */
+ assert(!ssl->s3->initial_handshake_complete);
+ assert(!SSL_IS_DTLS(ssl));
+ assert(ssl->ctx->next_proto_select_cb != NULL);
+
+ if (ssl->s3->alpn_selected != NULL) {
+ /* NPN and ALPN may not be negotiated in the same connection. */
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_BOTH_NPN_AND_ALPN);
+ return 0;
+ }
+
+ const uint8_t *const orig_contents = CBS_data(contents);
+ const size_t orig_len = CBS_len(contents);
+
+ while (CBS_len(contents) != 0) {
+ CBS proto;
+ if (!CBS_get_u8_length_prefixed(contents, &proto) ||
+ CBS_len(&proto) == 0) {
+ return 0;
+ }
+ }
+
+ uint8_t *selected;
uint8_t selected_len;
- int r;
+ if (ssl->ctx->next_proto_select_cb(
+ ssl, &selected, &selected_len, orig_contents, orig_len,
+ ssl->ctx->next_proto_select_cb_arg) != SSL_TLSEXT_ERR_OK) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+
+ OPENSSL_free(ssl->next_proto_negotiated);
+ ssl->next_proto_negotiated = BUF_memdup(selected, selected_len);
+ if (ssl->next_proto_negotiated == NULL) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+
+ ssl->next_proto_negotiated_len = selected_len;
+ ssl->s3->next_proto_neg_seen = 1;
+
+ return 1;
+}
+
+static int ext_npn_parse_clienthello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents != NULL && CBS_len(contents) != 0) {
+ return 0;
+ }
+
+ if (contents == NULL ||
+ ssl->s3->initial_handshake_complete ||
+ /* If the ALPN extension is seen before NPN, ignore it. (If ALPN is seen
+ * afterwards, parsing the ALPN extension will clear
+ * |next_proto_neg_seen|. */
+ ssl->s3->alpn_selected != NULL ||
+ ssl->ctx->next_protos_advertised_cb == NULL ||
+ SSL_IS_DTLS(ssl)) {
+ return 1;
+ }
+
+ ssl->s3->next_proto_neg_seen = 1;
+ return 1;
+}
+
+static int ext_npn_add_serverhello(SSL *ssl, CBB *out) {
+ /* |next_proto_neg_seen| might have been cleared when an ALPN extension was
+ * parsed. */
+ if (!ssl->s3->next_proto_neg_seen) {
+ return 1;
+ }
+
+ const uint8_t *npa;
+ unsigned npa_len;
+
+ if (ssl->ctx->next_protos_advertised_cb(
+ ssl, &npa, &npa_len, ssl->ctx->next_protos_advertised_cb_arg) !=
+ SSL_TLSEXT_ERR_OK) {
+ ssl->s3->next_proto_neg_seen = 0;
+ return 1;
+ }
+
+ CBB contents;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_next_proto_neg) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_bytes(&contents, npa, npa_len) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* Signed certificate timestamps.
+ *
+ * https://tools.ietf.org/html/rfc6962#section-3.3.1 */
- if (s->ctx->alpn_select_cb == NULL) {
+static int ext_sct_add_clienthello(SSL *ssl, CBB *out) {
+ if (!ssl->signed_cert_timestamps_enabled) {
return 1;
}
- if (!CBS_get_u16_length_prefixed(cbs, &protocol_name_list) ||
- CBS_len(cbs) != 0 || CBS_len(&protocol_name_list) < 2) {
- goto parse_error;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_certificate_timestamp) ||
+ !CBB_add_u16(out, 0 /* length */)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_sct_parse_serverhello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
+ }
+
+ /* If this is false then we should never have sent the SCT extension in the
+ * ClientHello and thus this function should never have been called. */
+ assert(ssl->signed_cert_timestamps_enabled);
+
+ if (CBS_len(contents) == 0) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ /* Session resumption uses the original session information. */
+ if (!ssl->hit &&
+ !CBS_stow(contents, &ssl->session->tlsext_signed_cert_timestamp_list,
+ &ssl->session->tlsext_signed_cert_timestamp_list_length)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_sct_parse_clienthello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ return contents == NULL || CBS_len(contents) == 0;
+}
+
+static int ext_sct_add_serverhello(SSL *ssl, CBB *out) {
+ /* The extension shouldn't be sent when resuming sessions. */
+ if (ssl->hit ||
+ ssl->ctx->signed_cert_timestamp_list_length == 0) {
+ return 1;
+ }
+
+ CBB contents;
+ return CBB_add_u16(out, TLSEXT_TYPE_certificate_timestamp) &&
+ CBB_add_u16_length_prefixed(out, &contents) &&
+ CBB_add_bytes(&contents, ssl->ctx->signed_cert_timestamp_list,
+ ssl->ctx->signed_cert_timestamp_list_length) &&
+ CBB_flush(out);
+}
+
+
+/* Application-level Protocol Negotiation.
+ *
+ * https://tools.ietf.org/html/rfc7301 */
+
+static void ext_alpn_init(SSL *ssl) {
+ OPENSSL_free(ssl->s3->alpn_selected);
+ ssl->s3->alpn_selected = NULL;
+}
+
+static int ext_alpn_add_clienthello(SSL *ssl, CBB *out) {
+ if (ssl->alpn_client_proto_list == NULL ||
+ ssl->s3->initial_handshake_complete) {
+ return 1;
+ }
+
+ CBB contents, proto_list;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_application_layer_protocol_negotiation) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &proto_list) ||
+ !CBB_add_bytes(&proto_list, ssl->alpn_client_proto_list,
+ ssl->alpn_client_proto_list_len) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_alpn_parse_serverhello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
+ }
+
+ assert(!ssl->s3->initial_handshake_complete);
+ assert(ssl->alpn_client_proto_list != NULL);
+
+ if (ssl->s3->next_proto_neg_seen) {
+ /* NPN and ALPN may not be negotiated in the same connection. */
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_BOTH_NPN_AND_ALPN);
+ return 0;
+ }
+
+ /* The extension data consists of a ProtocolNameList which must have
+ * exactly one ProtocolName. Each of these is length-prefixed. */
+ CBS protocol_name_list, protocol_name;
+ if (!CBS_get_u16_length_prefixed(contents, &protocol_name_list) ||
+ CBS_len(contents) != 0 ||
+ !CBS_get_u8_length_prefixed(&protocol_name_list, &protocol_name) ||
+ /* Empty protocol names are forbidden. */
+ CBS_len(&protocol_name) == 0 ||
+ CBS_len(&protocol_name_list) != 0) {
+ return 0;
+ }
+
+ if (!CBS_stow(&protocol_name, &ssl->s3->alpn_selected,
+ &ssl->s3->alpn_selected_len)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_alpn_parse_clienthello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
+ }
+
+ if (ssl->ctx->alpn_select_cb == NULL ||
+ ssl->s3->initial_handshake_complete) {
+ return 1;
+ }
+
+ /* ALPN takes precedence over NPN. */
+ ssl->s3->next_proto_neg_seen = 0;
+
+ CBS protocol_name_list;
+ if (!CBS_get_u16_length_prefixed(contents, &protocol_name_list) ||
+ CBS_len(contents) != 0 ||
+ CBS_len(&protocol_name_list) < 2) {
+ return 0;
}
/* Validate the protocol list. */
- protocol_name_list_copy = protocol_name_list;
+ CBS protocol_name_list_copy = protocol_name_list;
while (CBS_len(&protocol_name_list_copy) > 0) {
CBS protocol_name;
- if (!CBS_get_u8_length_prefixed(&protocol_name_list_copy, &protocol_name)) {
- goto parse_error;
+ if (!CBS_get_u8_length_prefixed(&protocol_name_list_copy, &protocol_name) ||
+ /* Empty protocol names are forbidden. */
+ CBS_len(&protocol_name) == 0) {
+ return 0;
}
}
- r = s->ctx->alpn_select_cb(
- s, &selected, &selected_len, CBS_data(&protocol_name_list),
- CBS_len(&protocol_name_list), s->ctx->alpn_select_cb_arg);
- if (r == SSL_TLSEXT_ERR_OK) {
- OPENSSL_free(s->s3->alpn_selected);
- s->s3->alpn_selected = BUF_memdup(selected, selected_len);
- if (!s->s3->alpn_selected) {
+ const uint8_t *selected;
+ uint8_t selected_len;
+ if (ssl->ctx->alpn_select_cb(
+ ssl, &selected, &selected_len, CBS_data(&protocol_name_list),
+ CBS_len(&protocol_name_list),
+ ssl->ctx->alpn_select_cb_arg) == SSL_TLSEXT_ERR_OK) {
+ OPENSSL_free(ssl->s3->alpn_selected);
+ ssl->s3->alpn_selected = BUF_memdup(selected, selected_len);
+ if (ssl->s3->alpn_selected == NULL) {
*out_alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
- s->s3->alpn_selected_len = selected_len;
+ ssl->s3->alpn_selected_len = selected_len;
}
return 1;
+}
-parse_error:
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
+static int ext_alpn_add_serverhello(SSL *ssl, CBB *out) {
+ if (ssl->s3->alpn_selected == NULL) {
+ return 1;
+ }
+
+ CBB contents, proto_list, proto;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_application_layer_protocol_negotiation) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &proto_list) ||
+ !CBB_add_u8_length_prefixed(&proto_list, &proto) ||
+ !CBB_add_bytes(&proto, ssl->s3->alpn_selected, ssl->s3->alpn_selected_len) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
}
-static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) {
- int renegotiate_seen = 0;
- CBS extensions;
- s->should_ack_sni = 0;
- s->srtp_profile = NULL;
- s->s3->next_proto_neg_seen = 0;
- s->s3->tmp.certificate_status_expected = 0;
- s->s3->tmp.extended_master_secret = 0;
+/* Channel ID.
+ *
+ * https://tools.ietf.org/html/draft-balfanz-tls-channelid-01 */
+
+static void ext_channel_id_init(SSL *ssl) {
+ ssl->s3->tlsext_channel_id_valid = 0;
+}
+
+static int ext_channel_id_add_clienthello(SSL *ssl, CBB *out) {
+ if (!ssl->tlsext_channel_id_enabled ||
+ SSL_IS_DTLS(ssl)) {
+ return 1;
+ }
+
+ if (!CBB_add_u16(out, TLSEXT_TYPE_channel_id) ||
+ !CBB_add_u16(out, 0 /* length */)) {
+ return 0;
+ }
- OPENSSL_free(s->s3->alpn_selected);
- s->s3->alpn_selected = NULL;
+ return 1;
+}
- /* Clear any signature algorithms extension received */
- OPENSSL_free(s->cert->peer_sigalgs);
- s->cert->peer_sigalgs = NULL;
- s->cert->peer_sigalgslen = 0;
+static int ext_channel_id_parse_serverhello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
+ }
- /* Clear any shared signature algorithms */
- OPENSSL_free(s->cert->shared_sigalgs);
- s->cert->shared_sigalgs = NULL;
- s->cert->shared_sigalgslen = 0;
+ assert(!SSL_IS_DTLS(ssl));
+ assert(ssl->tlsext_channel_id_enabled);
- /* Clear ECC extensions */
- OPENSSL_free(s->s3->tmp.peer_ecpointformatlist);
- s->s3->tmp.peer_ecpointformatlist = NULL;
- s->s3->tmp.peer_ecpointformatlist_length = 0;
+ if (CBS_len(contents) != 0) {
+ return 0;
+ }
- OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist);
- s->s3->tmp.peer_ellipticcurvelist = NULL;
- s->s3->tmp.peer_ellipticcurvelist_length = 0;
+ ssl->s3->tlsext_channel_id_valid = 1;
+ return 1;
+}
- /* There may be no extensions. */
- if (CBS_len(cbs) == 0) {
- goto ri_check;
+static int ext_channel_id_parse_clienthello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL ||
+ !ssl->tlsext_channel_id_enabled ||
+ SSL_IS_DTLS(ssl)) {
+ return 1;
}
- /* Decode the extensions block and check it is valid. */
- if (!CBS_get_u16_length_prefixed(cbs, &extensions) ||
- !tls1_check_duplicate_extensions(&extensions)) {
- *out_alert = SSL_AD_DECODE_ERROR;
+ if (CBS_len(contents) != 0) {
return 0;
}
- while (CBS_len(&extensions) != 0) {
- uint16_t type;
- CBS extension;
+ ssl->s3->tlsext_channel_id_valid = 1;
+ return 1;
+}
- /* Decode the next extension. */
- if (!CBS_get_u16(&extensions, &type) ||
- !CBS_get_u16_length_prefixed(&extensions, &extension)) {
- *out_alert = SSL_AD_DECODE_ERROR;
+static int ext_channel_id_add_serverhello(SSL *ssl, CBB *out) {
+ if (!ssl->s3->tlsext_channel_id_valid) {
+ return 1;
+ }
+
+ if (!CBB_add_u16(out, TLSEXT_TYPE_channel_id) ||
+ !CBB_add_u16(out, 0 /* length */)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* Secure Real-time Transport Protocol (SRTP) extension.
+ *
+ * https://tools.ietf.org/html/rfc5764 */
+
+
+static void ext_srtp_init(SSL *ssl) {
+ ssl->srtp_profile = NULL;
+}
+
+static int ext_srtp_add_clienthello(SSL *ssl, CBB *out) {
+ STACK_OF(SRTP_PROTECTION_PROFILE) *profiles = SSL_get_srtp_profiles(ssl);
+ if (profiles == NULL) {
+ return 1;
+ }
+ const size_t num_profiles = sk_SRTP_PROTECTION_PROFILE_num(profiles);
+ if (num_profiles == 0) {
+ return 1;
+ }
+
+ CBB contents, profile_ids;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_srtp) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &profile_ids)) {
+ return 0;
+ }
+
+ size_t i;
+ for (i = 0; i < num_profiles; i++) {
+ if (!CBB_add_u16(&profile_ids,
+ sk_SRTP_PROTECTION_PROFILE_value(profiles, i)->id)) {
return 0;
}
+ }
- /* The servername extension is treated as follows:
-
- - Only the hostname type is supported with a maximum length of 255.
- - The servername is rejected if too long or if it contains zeros, in
- which case an fatal alert is generated.
- - The servername field is maintained together with the session cache.
- - When a session is resumed, the servername call back invoked in order
- to allow the application to position itself to the right context.
- - The servername is acknowledged if it is new for a session or when
- it is identical to a previously used for the same session.
- Applications can control the behaviour. They can at any time
- set a 'desirable' servername for a new SSL object. This can be the
- case for example with HTTPS when a Host: header field is received and
- a renegotiation is requested. In this case, a possible servername
- presented in the new client hello is only acknowledged if it matches
- the value of the Host: field.
- - Applications must use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
- if they provide for changing an explicit servername context for the
- session,
- i.e. when the session has been established with a servername extension.
- - On session reconnect, the servername extension may be absent. */
-
- if (type == TLSEXT_TYPE_server_name) {
- CBS server_name_list;
- char have_seen_host_name = 0;
-
- if (!CBS_get_u16_length_prefixed(&extension, &server_name_list) ||
- CBS_len(&server_name_list) < 1 || CBS_len(&extension) != 0) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
+ if (!CBB_add_u8(&contents, 0 /* empty use_mki value */) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
- /* Decode each ServerName in the extension. */
- while (CBS_len(&server_name_list) > 0) {
- uint8_t name_type;
- CBS host_name;
+ return 1;
+}
- /* Decode the NameType. */
- if (!CBS_get_u8(&server_name_list, &name_type)) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
+static int ext_srtp_parse_serverhello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
+ }
- /* Only host_name is supported. */
- if (name_type != TLSEXT_NAMETYPE_host_name) {
- continue;
- }
+ /* The extension consists of a u16-prefixed profile ID list containing a
+ * single uint16_t profile ID, then followed by a u8-prefixed srtp_mki field.
+ *
+ * See https://tools.ietf.org/html/rfc5764#section-4.1.1 */
+ CBS profile_ids, srtp_mki;
+ uint16_t profile_id;
+ if (!CBS_get_u16_length_prefixed(contents, &profile_ids) ||
+ !CBS_get_u16(&profile_ids, &profile_id) ||
+ CBS_len(&profile_ids) != 0 ||
+ !CBS_get_u8_length_prefixed(contents, &srtp_mki) ||
+ CBS_len(contents) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+ return 0;
+ }
- if (have_seen_host_name) {
- /* The ServerNameList MUST NOT contain more than one name of the same
- * name_type. */
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
+ if (CBS_len(&srtp_mki) != 0) {
+ /* Must be no MKI, since we never offer one. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_MKI_VALUE);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
- have_seen_host_name = 1;
+ STACK_OF(SRTP_PROTECTION_PROFILE) *profiles = SSL_get_srtp_profiles(ssl);
- if (!CBS_get_u16_length_prefixed(&server_name_list, &host_name) ||
- CBS_len(&host_name) < 1) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
+ /* Check to see if the server gave us something we support (and presumably
+ * offered). */
+ size_t i;
+ for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(profiles); i++) {
+ const SRTP_PROTECTION_PROFILE *profile =
+ sk_SRTP_PROTECTION_PROFILE_value(profiles, i);
- if (CBS_len(&host_name) > TLSEXT_MAXLEN_host_name ||
- CBS_contains_zero_byte(&host_name)) {
- *out_alert = SSL_AD_UNRECOGNIZED_NAME;
- return 0;
- }
+ if (profile->id == profile_id) {
+ ssl->srtp_profile = profile;
+ return 1;
+ }
+ }
- if (!s->hit) {
- assert(s->session->tlsext_hostname == NULL);
- if (s->session->tlsext_hostname) {
- /* This should be impossible. */
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
-
- /* Copy the hostname as a string. */
- if (!CBS_strdup(&host_name, &s->session->tlsext_hostname)) {
- *out_alert = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
-
- s->should_ack_sni = 1;
- }
- }
- } else if (type == TLSEXT_TYPE_ec_point_formats) {
- CBS ec_point_format_list;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+}
- if (!CBS_get_u8_length_prefixed(&extension, &ec_point_format_list) ||
- CBS_len(&extension) != 0) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
+static int ext_srtp_parse_clienthello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
+ }
- if (!CBS_stow(&ec_point_format_list, &s->s3->tmp.peer_ecpointformatlist,
- &s->s3->tmp.peer_ecpointformatlist_length)) {
- *out_alert = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
- } else if (type == TLSEXT_TYPE_elliptic_curves) {
- CBS elliptic_curve_list;
- size_t i, num_curves;
-
- if (!CBS_get_u16_length_prefixed(&extension, &elliptic_curve_list) ||
- CBS_len(&elliptic_curve_list) == 0 ||
- (CBS_len(&elliptic_curve_list) & 1) != 0 ||
- CBS_len(&extension) != 0) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
+ CBS profile_ids, srtp_mki;
+ if (!CBS_get_u16_length_prefixed(contents, &profile_ids) ||
+ CBS_len(&profile_ids) < 2 ||
+ !CBS_get_u8_length_prefixed(contents, &srtp_mki) ||
+ CBS_len(contents) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+ return 0;
+ }
+ /* Discard the MKI value for now. */
- OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist);
- s->s3->tmp.peer_ellipticcurvelist_length = 0;
+ const STACK_OF(SRTP_PROTECTION_PROFILE) *server_profiles =
+ SSL_get_srtp_profiles(ssl);
- s->s3->tmp.peer_ellipticcurvelist =
- (uint16_t *)OPENSSL_malloc(CBS_len(&elliptic_curve_list));
+ /* Pick the server's most preferred profile. */
+ size_t i;
+ for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(server_profiles); i++) {
+ const SRTP_PROTECTION_PROFILE *server_profile =
+ sk_SRTP_PROTECTION_PROFILE_value(server_profiles, i);
- if (s->s3->tmp.peer_ellipticcurvelist == NULL) {
- *out_alert = SSL_AD_INTERNAL_ERROR;
+ CBS profile_ids_tmp;
+ CBS_init(&profile_ids_tmp, CBS_data(&profile_ids), CBS_len(&profile_ids));
+
+ while (CBS_len(&profile_ids_tmp) > 0) {
+ uint16_t profile_id;
+ if (!CBS_get_u16(&profile_ids_tmp, &profile_id)) {
return 0;
}
- num_curves = CBS_len(&elliptic_curve_list) / 2;
- for (i = 0; i < num_curves; i++) {
- if (!CBS_get_u16(&elliptic_curve_list,
- &s->s3->tmp.peer_ellipticcurvelist[i])) {
- *out_alert = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
+ if (server_profile->id == profile_id) {
+ ssl->srtp_profile = server_profile;
+ return 1;
}
+ }
+ }
- if (CBS_len(&elliptic_curve_list) != 0) {
- *out_alert = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
+ return 1;
+}
- s->s3->tmp.peer_ellipticcurvelist_length = num_curves;
- } else if (type == TLSEXT_TYPE_renegotiate) {
- if (!ssl_parse_clienthello_renegotiate_ext(s, &extension, out_alert)) {
- return 0;
- }
- renegotiate_seen = 1;
- } else if (type == TLSEXT_TYPE_signature_algorithms) {
- CBS supported_signature_algorithms;
+static int ext_srtp_add_serverhello(SSL *ssl, CBB *out) {
+ if (ssl->srtp_profile == NULL) {
+ return 1;
+ }
- if (!CBS_get_u16_length_prefixed(&extension,
- &supported_signature_algorithms) ||
- CBS_len(&extension) != 0) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
+ CBB contents, profile_ids;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_srtp) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &profile_ids) ||
+ !CBB_add_u16(&profile_ids, ssl->srtp_profile->id) ||
+ !CBB_add_u8(&contents, 0 /* empty MKI */) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
- /* Ensure the signature algorithms are non-empty. It contains a list of
- * SignatureAndHashAlgorithms which are two bytes each. */
- if (CBS_len(&supported_signature_algorithms) == 0 ||
- (CBS_len(&supported_signature_algorithms) % 2) != 0) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
+ return 1;
+}
- if (!tls1_process_sigalgs(s, &supported_signature_algorithms)) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
- /* If sigalgs received and no shared algorithms fatal error. */
- if (s->cert->peer_sigalgs && !s->cert->shared_sigalgs) {
- OPENSSL_PUT_ERROR(SSL, ssl_scan_clienthello_tlsext,
- SSL_R_NO_SHARED_SIGATURE_ALGORITHMS);
- *out_alert = SSL_AD_ILLEGAL_PARAMETER;
- return 0;
- }
- } else if (type == TLSEXT_TYPE_next_proto_neg &&
- !s->s3->initial_handshake_complete &&
- s->s3->alpn_selected == NULL && !SSL_IS_DTLS(s)) {
- /* The extension must be empty. */
- if (CBS_len(&extension) != 0) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
- s->s3->next_proto_neg_seen = 1;
- } else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation &&
- s->ctx->alpn_select_cb && !s->s3->initial_handshake_complete) {
- if (!tls1_alpn_handle_client_hello(s, &extension, out_alert)) {
- return 0;
- }
- /* ALPN takes precedence over NPN. */
- s->s3->next_proto_neg_seen = 0;
- } else if (type == TLSEXT_TYPE_channel_id && s->tlsext_channel_id_enabled &&
- !SSL_IS_DTLS(s)) {
- /* The extension must be empty. */
- if (CBS_len(&extension) != 0) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
- s->s3->tlsext_channel_id_valid = 1;
- } else if (type == TLSEXT_TYPE_channel_id_new &&
- s->tlsext_channel_id_enabled && !SSL_IS_DTLS(s)) {
- /* The extension must be empty. */
- if (CBS_len(&extension) != 0) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
+/* EC point formats.
+ *
+ * https://tools.ietf.org/html/rfc4492#section-5.1.2 */
- s->s3->tlsext_channel_id_valid = 1;
- s->s3->tlsext_channel_id_new = 1;
- } else if (type == TLSEXT_TYPE_use_srtp) {
- if (!ssl_parse_clienthello_use_srtp_ext(s, &extension, out_alert)) {
- return 0;
- }
- } else if (type == TLSEXT_TYPE_extended_master_secret &&
- s->version != SSL3_VERSION) {
- if (CBS_len(&extension) != 0) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
+static int ssl_any_ec_cipher_suites_enabled(const SSL *ssl) {
+ if (ssl->version < TLS1_VERSION && !SSL_IS_DTLS(ssl)) {
+ return 0;
+ }
+
+ const STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(ssl);
+
+ size_t i;
+ for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) {
+ const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(cipher_stack, i);
- s->s3->tmp.extended_master_secret = 1;
+ const uint32_t alg_k = cipher->algorithm_mkey;
+ const uint32_t alg_a = cipher->algorithm_auth;
+ if ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)) {
+ return 1;
}
}
-ri_check:
- /* Need RI if renegotiating */
+ return 0;
+}
- if (!renegotiate_seen && s->s3->initial_handshake_complete &&
- !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
- *out_alert = SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, ssl_scan_clienthello_tlsext,
- SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+static int ext_ec_point_add_extension(SSL *ssl, CBB *out) {
+ CBB contents, formats;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_ec_point_formats) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u8_length_prefixed(&contents, &formats) ||
+ !CBB_add_u8(&formats, TLSEXT_ECPOINTFORMAT_uncompressed) ||
+ !CBB_flush(out)) {
return 0;
}
return 1;
}
-int ssl_parse_clienthello_tlsext(SSL *s, CBS *cbs) {
- int alert = -1;
- if (ssl_scan_clienthello_tlsext(s, cbs, &alert) <= 0) {
- ssl3_send_alert(s, SSL3_AL_FATAL, alert);
+static int ext_ec_point_add_clienthello(SSL *ssl, CBB *out) {
+ if (!ssl_any_ec_cipher_suites_enabled(ssl)) {
+ return 1;
+ }
+
+ return ext_ec_point_add_extension(ssl, out);
+}
+
+static int ext_ec_point_parse_serverhello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
+ }
+
+ CBS ec_point_format_list;
+ if (!CBS_get_u8_length_prefixed(contents, &ec_point_format_list) ||
+ CBS_len(contents) != 0) {
return 0;
}
- if (ssl_check_clienthello_tlsext(s) <= 0) {
- OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_tlsext,
- SSL_R_CLIENTHELLO_TLSEXT);
+ /* Per RFC 4492, section 5.1.2, implementations MUST support the uncompressed
+ * point format. */
+ if (memchr(CBS_data(&ec_point_format_list), TLSEXT_ECPOINTFORMAT_uncompressed,
+ CBS_len(&ec_point_format_list)) == NULL) {
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
return 1;
}
-/* ssl_next_proto_validate validates a Next Protocol Negotiation block. No
- * elements of zero length are allowed and the set of elements must exactly
- * fill the length of the block. */
-static char ssl_next_proto_validate(const CBS *cbs) {
- CBS copy = *cbs;
+static int ext_ec_point_parse_clienthello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ return ext_ec_point_parse_serverhello(ssl, out_alert, contents);
+}
+
+static int ext_ec_point_add_serverhello(SSL *ssl, CBB *out) {
+ const uint32_t alg_k = ssl->s3->tmp.new_cipher->algorithm_mkey;
+ const uint32_t alg_a = ssl->s3->tmp.new_cipher->algorithm_auth;
+ const int using_ecc = (alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA);
- while (CBS_len(&copy) != 0) {
- CBS proto;
- if (!CBS_get_u8_length_prefixed(&copy, &proto) || CBS_len(&proto) == 0) {
+ if (!using_ecc) {
+ return 1;
+ }
+
+ return ext_ec_point_add_extension(ssl, out);
+}
+
+
+/* EC supported curves.
+ *
+ * https://tools.ietf.org/html/rfc4492#section-5.1.2 */
+
+static void ext_ec_curves_init(SSL *ssl) {
+ OPENSSL_free(ssl->s3->tmp.peer_ellipticcurvelist);
+ ssl->s3->tmp.peer_ellipticcurvelist = NULL;
+ ssl->s3->tmp.peer_ellipticcurvelist_length = 0;
+}
+
+static int ext_ec_curves_add_clienthello(SSL *ssl, CBB *out) {
+ if (!ssl_any_ec_cipher_suites_enabled(ssl)) {
+ return 1;
+ }
+
+ CBB contents, curves_bytes;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_elliptic_curves) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &curves_bytes)) {
+ return 0;
+ }
+
+ const uint16_t *curves;
+ size_t curves_len;
+ tls1_get_curvelist(ssl, 0, &curves, &curves_len);
+
+ size_t i;
+ for (i = 0; i < curves_len; i++) {
+ if (!CBB_add_u16(&curves_bytes, curves[i])) {
return 0;
}
}
+ return CBB_flush(out);
+}
+
+static int ext_ec_curves_parse_serverhello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ /* This extension is not expected to be echoed by servers and is ignored. */
return 1;
}
-static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) {
- int tlsext_servername = 0;
- int renegotiate_seen = 0;
- CBS extensions;
+static int ext_ec_curves_parse_clienthello(SSL *ssl, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
+ }
- /* TODO(davidben): Move all of these to some per-handshake state that gets
- * systematically reset on a new handshake; perhaps allocate it fresh each
- * time so it's not even kept around post-handshake. */
- s->s3->next_proto_neg_seen = 0;
- s->tlsext_ticket_expected = 0;
- s->s3->tmp.certificate_status_expected = 0;
- s->s3->tmp.extended_master_secret = 0;
- s->srtp_profile = NULL;
+ CBS elliptic_curve_list;
+ if (!CBS_get_u16_length_prefixed(contents, &elliptic_curve_list) ||
+ CBS_len(&elliptic_curve_list) == 0 ||
+ (CBS_len(&elliptic_curve_list) & 1) != 0 ||
+ CBS_len(contents) != 0) {
+ return 0;
+ }
- OPENSSL_free(s->s3->alpn_selected);
- s->s3->alpn_selected = NULL;
+ ssl->s3->tmp.peer_ellipticcurvelist =
+ (uint16_t *)OPENSSL_malloc(CBS_len(&elliptic_curve_list));
- /* Clear ECC extensions */
- OPENSSL_free(s->s3->tmp.peer_ecpointformatlist);
- s->s3->tmp.peer_ecpointformatlist = NULL;
- s->s3->tmp.peer_ecpointformatlist_length = 0;
+ if (ssl->s3->tmp.peer_ellipticcurvelist == NULL) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
- /* There may be no extensions. */
- if (CBS_len(cbs) == 0) {
- goto ri_check;
+ const size_t num_curves = CBS_len(&elliptic_curve_list) / 2;
+ size_t i;
+ for (i = 0; i < num_curves; i++) {
+ if (!CBS_get_u16(&elliptic_curve_list,
+ &ssl->s3->tmp.peer_ellipticcurvelist[i])) {
+ goto err;
+ }
}
- /* Decode the extensions block and check it is valid. */
- if (!CBS_get_u16_length_prefixed(cbs, &extensions) ||
- !tls1_check_duplicate_extensions(&extensions)) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
+ assert(CBS_len(&elliptic_curve_list) == 0);
+ ssl->s3->tmp.peer_ellipticcurvelist_length = num_curves;
+
+ return 1;
+
+err:
+ OPENSSL_free(ssl->s3->tmp.peer_ellipticcurvelist);
+ ssl->s3->tmp.peer_ellipticcurvelist = NULL;
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+}
+
+static int ext_ec_curves_add_serverhello(SSL *ssl, CBB *out) {
+ /* Servers don't echo this extension. */
+ return 1;
+}
+
+
+/* kExtensions contains all the supported extensions. */
+static const struct tls_extension kExtensions[] = {
+ {
+ /* The renegotiation extension must always be at index zero because the
+ * |received| and |sent| bitsets need to be tweaked when the "extension" is
+ * sent as an SCSV. */
+ TLSEXT_TYPE_renegotiate,
+ NULL,
+ ext_ri_add_clienthello,
+ ext_ri_parse_serverhello,
+ ext_ri_parse_clienthello,
+ ext_ri_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_server_name,
+ ext_sni_init,
+ ext_sni_add_clienthello,
+ ext_sni_parse_serverhello,
+ ext_sni_parse_clienthello,
+ ext_sni_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_extended_master_secret,
+ ext_ems_init,
+ ext_ems_add_clienthello,
+ ext_ems_parse_serverhello,
+ ext_ems_parse_clienthello,
+ ext_ems_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_session_ticket,
+ NULL,
+ ext_ticket_add_clienthello,
+ ext_ticket_parse_serverhello,
+ ext_ticket_parse_clienthello,
+ ext_ticket_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_signature_algorithms,
+ NULL,
+ ext_sigalgs_add_clienthello,
+ ext_sigalgs_parse_serverhello,
+ ext_sigalgs_parse_clienthello,
+ ext_sigalgs_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_status_request,
+ ext_ocsp_init,
+ ext_ocsp_add_clienthello,
+ ext_ocsp_parse_serverhello,
+ ext_ocsp_parse_clienthello,
+ ext_ocsp_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_next_proto_neg,
+ ext_npn_init,
+ ext_npn_add_clienthello,
+ ext_npn_parse_serverhello,
+ ext_npn_parse_clienthello,
+ ext_npn_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_certificate_timestamp,
+ NULL,
+ ext_sct_add_clienthello,
+ ext_sct_parse_serverhello,
+ ext_sct_parse_clienthello,
+ ext_sct_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_application_layer_protocol_negotiation,
+ ext_alpn_init,
+ ext_alpn_add_clienthello,
+ ext_alpn_parse_serverhello,
+ ext_alpn_parse_clienthello,
+ ext_alpn_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_channel_id,
+ ext_channel_id_init,
+ ext_channel_id_add_clienthello,
+ ext_channel_id_parse_serverhello,
+ ext_channel_id_parse_clienthello,
+ ext_channel_id_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_srtp,
+ ext_srtp_init,
+ ext_srtp_add_clienthello,
+ ext_srtp_parse_serverhello,
+ ext_srtp_parse_clienthello,
+ ext_srtp_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_ec_point_formats,
+ NULL,
+ ext_ec_point_add_clienthello,
+ ext_ec_point_parse_serverhello,
+ ext_ec_point_parse_clienthello,
+ ext_ec_point_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_elliptic_curves,
+ ext_ec_curves_init,
+ ext_ec_curves_add_clienthello,
+ ext_ec_curves_parse_serverhello,
+ ext_ec_curves_parse_clienthello,
+ ext_ec_curves_add_serverhello,
+ },
+};
+
+#define kNumExtensions (sizeof(kExtensions) / sizeof(struct tls_extension))
+
+OPENSSL_COMPILE_ASSERT(kNumExtensions <=
+ sizeof(((SSL *)NULL)->s3->tmp.extensions.sent) * 8,
+ too_many_extensions_for_sent_bitset);
+OPENSSL_COMPILE_ASSERT(kNumExtensions <=
+ sizeof(((SSL *)NULL)->s3->tmp.extensions.received) *
+ 8,
+ too_many_extensions_for_received_bitset);
+
+static const struct tls_extension *tls_extension_find(uint32_t *out_index,
+ uint16_t value) {
+ unsigned i;
+ for (i = 0; i < kNumExtensions; i++) {
+ if (kExtensions[i].value == value) {
+ *out_index = i;
+ return &kExtensions[i];
+ }
}
- while (CBS_len(&extensions) != 0) {
- uint16_t type;
- CBS extension;
+ return NULL;
+}
- /* Decode the next extension. */
- if (!CBS_get_u16(&extensions, &type) ||
- !CBS_get_u16_length_prefixed(&extensions, &extension)) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
+int SSL_extension_supported(unsigned extension_value) {
+ uint32_t index;
+ return extension_value == TLSEXT_TYPE_padding ||
+ tls_extension_find(&index, extension_value) != NULL;
+}
+
+/* header_len is the length of the ClientHello header written so far, used to
+ * compute padding. It does not include the record header. Pass 0 if no padding
+ * is to be done. */
+uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *const buf,
+ uint8_t *const limit, size_t header_len) {
+ /* don't add extensions for SSLv3 unless doing secure renegotiation */
+ if (s->client_version == SSL3_VERSION && !s->s3->send_connection_binding) {
+ return buf;
+ }
+
+ CBB cbb, extensions;
+ CBB_zero(&cbb);
+ if (!CBB_init_fixed(&cbb, buf, limit - buf) ||
+ !CBB_add_u16_length_prefixed(&cbb, &extensions)) {
+ goto err;
+ }
+
+ s->s3->tmp.extensions.sent = 0;
+ s->s3->tmp.custom_extensions.sent = 0;
+
+ size_t i;
+ for (i = 0; i < kNumExtensions; i++) {
+ if (kExtensions[i].init != NULL) {
+ kExtensions[i].init(s);
}
+ }
- if (type == TLSEXT_TYPE_server_name) {
- /* The extension must be empty. */
- if (CBS_len(&extension) != 0) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
+ for (i = 0; i < kNumExtensions; i++) {
+ const size_t len_before = CBB_len(&extensions);
+ if (!kExtensions[i].add_clienthello(s, &extensions)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION);
+ ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
+ goto err;
+ }
+
+ if (CBB_len(&extensions) != len_before) {
+ s->s3->tmp.extensions.sent |= (1u << i);
+ }
+ }
+
+ if (!custom_ext_add_clienthello(s, &extensions)) {
+ goto err;
+ }
+
+ if (header_len > 0) {
+ header_len += CBB_len(&extensions);
+ if (header_len > 0xff && header_len < 0x200) {
+ /* Add padding to workaround bugs in F5 terminators. See
+ * https://tools.ietf.org/html/draft-agl-tls-padding-03
+ *
+ * NB: because this code works out the length of all existing extensions
+ * it MUST always appear last. */
+ size_t padding_len = 0x200 - header_len;
+ /* Extensions take at least four bytes to encode. Always include least
+ * one byte of data if including the extension. WebSphere Application
+ * Server 7.0 is intolerant to the last extension being zero-length. */
+ if (padding_len >= 4 + 1) {
+ padding_len -= 4;
+ } else {
+ padding_len = 1;
}
- /* We must have sent it in ClientHello. */
- if (s->tlsext_hostname == NULL) {
- *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
- return 0;
+ uint8_t *padding_bytes;
+ if (!CBB_add_u16(&extensions, TLSEXT_TYPE_padding) ||
+ !CBB_add_u16(&extensions, padding_len) ||
+ !CBB_add_space(&extensions, &padding_bytes, padding_len)) {
+ goto err;
}
- tlsext_servername = 1;
- } else if (type == TLSEXT_TYPE_ec_point_formats) {
- CBS ec_point_format_list;
+ memset(padding_bytes, 0, padding_len);
+ }
+ }
+
+ if (!CBB_flush(&cbb)) {
+ goto err;
+ }
+
+ uint8_t *ret = buf;
+ const size_t cbb_len = CBB_len(&cbb);
+ /* If only two bytes have been written then the extensions are actually empty
+ * and those two bytes are the zero length. In that case, we don't bother
+ * sending the extensions length. */
+ if (cbb_len > 2) {
+ ret += cbb_len;
+ }
+
+ CBB_cleanup(&cbb);
+ return ret;
+
+err:
+ CBB_cleanup(&cbb);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return NULL;
+}
+
+uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *const buf,
+ uint8_t *const limit) {
+ /* don't add extensions for SSLv3, unless doing secure renegotiation */
+ if (s->version == SSL3_VERSION && !s->s3->send_connection_binding) {
+ return buf;
+ }
+
+ CBB cbb, extensions;
+ CBB_zero(&cbb);
+ if (!CBB_init_fixed(&cbb, buf, limit - buf) ||
+ !CBB_add_u16_length_prefixed(&cbb, &extensions)) {
+ goto err;
+ }
+
+ unsigned i;
+ for (i = 0; i < kNumExtensions; i++) {
+ if (!(s->s3->tmp.extensions.received & (1u << i))) {
+ /* Don't send extensions that were not received. */
+ continue;
+ }
+
+ if (!kExtensions[i].add_serverhello(s, &extensions)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION);
+ ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
+ goto err;
+ }
+ }
+
+ if (!custom_ext_add_serverhello(s, &extensions)) {
+ goto err;
+ }
+
+ if (!CBB_flush(&cbb)) {
+ goto err;
+ }
+
+ uint8_t *ret = buf;
+ const size_t cbb_len = CBB_len(&cbb);
+ /* If only two bytes have been written then the extensions are actually empty
+ * and those two bytes are the zero length. In that case, we don't bother
+ * sending the extensions length. */
+ if (cbb_len > 2) {
+ ret += cbb_len;
+ }
+
+ CBB_cleanup(&cbb);
+ return ret;
+
+err:
+ CBB_cleanup(&cbb);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return NULL;
+}
+
+static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) {
+ size_t i;
+ for (i = 0; i < kNumExtensions; i++) {
+ if (kExtensions[i].init != NULL) {
+ kExtensions[i].init(s);
+ }
+ }
+
+ s->s3->tmp.extensions.received = 0;
+ s->s3->tmp.custom_extensions.received = 0;
+ /* The renegotiation extension must always be at index zero because the
+ * |received| and |sent| bitsets need to be tweaked when the "extension" is
+ * sent as an SCSV. */
+ assert(kExtensions[0].value == TLSEXT_TYPE_renegotiate);
- if (!CBS_get_u8_length_prefixed(&extension, &ec_point_format_list) ||
- CBS_len(&extension) != 0) {
+ /* There may be no extensions. */
+ if (CBS_len(cbs) != 0) {
+ /* Decode the extensions block and check it is valid. */
+ CBS extensions;
+ if (!CBS_get_u16_length_prefixed(cbs, &extensions) ||
+ !tls1_check_duplicate_extensions(&extensions)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ while (CBS_len(&extensions) != 0) {
+ uint16_t type;
+ CBS extension;
+
+ /* Decode the next extension. */
+ if (!CBS_get_u16(&extensions, &type) ||
+ !CBS_get_u16_length_prefixed(&extensions, &extension)) {
*out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
- if (!CBS_stow(&ec_point_format_list, &s->s3->tmp.peer_ecpointformatlist,
- &s->s3->tmp.peer_ecpointformatlist_length)) {
- *out_alert = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
- } else if (type == TLSEXT_TYPE_session_ticket) {
- if ((SSL_get_options(s) & SSL_OP_NO_TICKET) || CBS_len(&extension) > 0) {
- *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
- return 0;
+ unsigned ext_index;
+ const struct tls_extension *const ext =
+ tls_extension_find(&ext_index, type);
+
+ if (ext == NULL) {
+ if (!custom_ext_parse_clienthello(s, out_alert, type, &extension)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
+ return 0;
+ }
+ continue;
}
- s->tlsext_ticket_expected = 1;
- } else if (type == TLSEXT_TYPE_status_request) {
- /* The extension MUST be empty and may only sent if we've requested a
- * status request message. */
- if (CBS_len(&extension) != 0) {
- *out_alert = SSL_AD_DECODE_ERROR;
+ s->s3->tmp.extensions.received |= (1u << ext_index);
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!ext->parse_clienthello(s, &alert, &extension)) {
+ *out_alert = alert;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
+ ERR_add_error_dataf("extension: %u", (unsigned)type);
return 0;
}
+ }
+ }
- if (!s->ocsp_stapling_enabled) {
- *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
+ for (i = 0; i < kNumExtensions; i++) {
+ if (!(s->s3->tmp.extensions.received & (1u << i))) {
+ /* Extension wasn't observed so call the callback with a NULL
+ * parameter. */
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!kExtensions[i].parse_clienthello(s, &alert, NULL)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION);
+ ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
+ *out_alert = alert;
return 0;
}
+ }
+ }
- /* Set a flag to expect a CertificateStatus message */
- s->s3->tmp.certificate_status_expected = 1;
- } else if (type == TLSEXT_TYPE_next_proto_neg &&
- !s->s3->initial_handshake_complete && !SSL_IS_DTLS(s)) {
- uint8_t *selected;
- uint8_t selected_len;
+ return 1;
+}
- /* We must have requested it. */
- if (s->ctx->next_proto_select_cb == NULL) {
- *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
- return 0;
- }
+int ssl_parse_clienthello_tlsext(SSL *s, CBS *cbs) {
+ int alert = -1;
+ if (ssl_scan_clienthello_tlsext(s, cbs, &alert) <= 0) {
+ ssl3_send_alert(s, SSL3_AL_FATAL, alert);
+ return 0;
+ }
- /* The data must be valid. */
- if (!ssl_next_proto_validate(&extension)) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
+ if (ssl_check_clienthello_tlsext(s) <= 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_TLSEXT);
+ return 0;
+ }
- if (s->ctx->next_proto_select_cb(
- s, &selected, &selected_len, CBS_data(&extension),
- CBS_len(&extension),
- s->ctx->next_proto_select_cb_arg) != SSL_TLSEXT_ERR_OK) {
- *out_alert = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
+ return 1;
+}
- s->next_proto_negotiated = BUF_memdup(selected, selected_len);
- if (s->next_proto_negotiated == NULL) {
- *out_alert = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
+static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) {
+ uint32_t received = 0;
+ assert(kNumExtensions <= sizeof(received) * 8);
+
+ if (CBS_len(cbs) != 0) {
+ /* Decode the extensions block and check it is valid. */
+ CBS extensions;
+ if (!CBS_get_u16_length_prefixed(cbs, &extensions) ||
+ !tls1_check_duplicate_extensions(&extensions)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
- s->next_proto_negotiated_len = selected_len;
- s->s3->next_proto_neg_seen = 1;
- } else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation &&
- !s->s3->initial_handshake_complete) {
- CBS protocol_name_list, protocol_name;
- /* We must have requested it. */
- if (s->alpn_client_proto_list == NULL) {
- *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
- return 0;
- }
+ while (CBS_len(&extensions) != 0) {
+ uint16_t type;
+ CBS extension;
- /* The extension data consists of a ProtocolNameList which must have
- * exactly one ProtocolName. Each of these is length-prefixed. */
- if (!CBS_get_u16_length_prefixed(&extension, &protocol_name_list) ||
- CBS_len(&extension) != 0 ||
- !CBS_get_u8_length_prefixed(&protocol_name_list, &protocol_name) ||
- CBS_len(&protocol_name_list) != 0) {
+ /* Decode the next extension. */
+ if (!CBS_get_u16(&extensions, &type) ||
+ !CBS_get_u16_length_prefixed(&extensions, &extension)) {
*out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
- if (!CBS_stow(&protocol_name, &s->s3->alpn_selected,
- &s->s3->alpn_selected_len)) {
- *out_alert = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
- } else if (type == TLSEXT_TYPE_channel_id && !SSL_IS_DTLS(s)) {
- if (CBS_len(&extension) != 0) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
+ unsigned ext_index;
+ const struct tls_extension *const ext =
+ tls_extension_find(&ext_index, type);
- s->s3->tlsext_channel_id_valid = 1;
- } else if (type == TLSEXT_TYPE_channel_id_new && !SSL_IS_DTLS(s)) {
- if (CBS_len(&extension) != 0) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
+ if (ext == NULL) {
+ if (!custom_ext_parse_serverhello(s, out_alert, type, &extension)) {
+ return 0;
+ }
+ continue;
}
- s->s3->tlsext_channel_id_valid = 1;
- s->s3->tlsext_channel_id_new = 1;
- } else if (type == TLSEXT_TYPE_certificate_timestamp) {
- if (CBS_len(&extension) == 0) {
+ if (!(s->s3->tmp.extensions.sent & (1u << ext_index))) {
+ /* If the extension was never sent then it is illegal. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ ERR_add_error_dataf("extension :%u", (unsigned)type);
*out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
- /* Session resumption uses the original session information. */
- if (!s->hit &&
- !CBS_stow(&extension, &s->session->tlsext_signed_cert_timestamp_list,
- &s->session->tlsext_signed_cert_timestamp_list_length)) {
- *out_alert = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
- } else if (type == TLSEXT_TYPE_renegotiate) {
- if (!ssl_parse_serverhello_renegotiate_ext(s, &extension, out_alert)) {
- return 0;
- }
+ received |= (1u << ext_index);
- renegotiate_seen = 1;
- } else if (type == TLSEXT_TYPE_use_srtp) {
- if (!ssl_parse_serverhello_use_srtp_ext(s, &extension, out_alert)) {
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!ext->parse_serverhello(s, &alert, &extension)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
+ ERR_add_error_dataf("extension: %u", (unsigned)type);
+ *out_alert = alert;
return 0;
}
- } else if (type == TLSEXT_TYPE_extended_master_secret) {
- if (/* It is invalid for the server to select EMS and
- SSLv3. */
- s->version == SSL3_VERSION || CBS_len(&extension) != 0) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
-
- s->s3->tmp.extended_master_secret = 1;
}
}
- if (!s->hit && tlsext_servername == 1 && s->tlsext_hostname) {
- if (s->session->tlsext_hostname == NULL) {
- s->session->tlsext_hostname = BUF_strdup(s->tlsext_hostname);
- if (!s->session->tlsext_hostname) {
- *out_alert = SSL_AD_UNRECOGNIZED_NAME;
+ size_t i;
+ for (i = 0; i < kNumExtensions; i++) {
+ if (!(received & (1u << i))) {
+ /* Extension wasn't observed so call the callback with a NULL
+ * parameter. */
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!kExtensions[i].parse_serverhello(s, &alert, NULL)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION);
+ ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
+ *out_alert = alert;
return 0;
}
- } else {
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
}
}
-ri_check:
- /* Determine if we need to see RI. Strictly speaking if we want to avoid an
- * attack we should *always* see RI even on initial server hello because the
- * client doesn't see any renegotiation during an attack. However this would
- * mean we could not connect to any server which doesn't support RI so for
- * the immediate future tolerate RI absence on initial connect only. */
- if (!renegotiate_seen && !(s->options & SSL_OP_LEGACY_SERVER_CONNECT) &&
- !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
- *out_alert = SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, ssl_scan_serverhello_tlsext,
- SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
- return 0;
- }
-
return 1;
}
-int ssl_prepare_clienthello_tlsext(SSL *s) { return 1; }
-
-int ssl_prepare_serverhello_tlsext(SSL *s) { return 1; }
-
static int ssl_check_clienthello_tlsext(SSL *s) {
int ret = SSL_TLSEXT_ERR_NOACK;
int al = SSL_AD_UNRECOGNIZED_NAME;
@@ -1947,7 +2568,7 @@ static int ssl_check_clienthello_tlsext(SSL *s) {
return 1;
case SSL_TLSEXT_ERR_NOACK:
- s->should_ack_sni = 0;
+ s->s3->tmp.should_ack_sni = 0;
return 1;
default:
@@ -1956,22 +2577,9 @@ static int ssl_check_clienthello_tlsext(SSL *s) {
}
static int ssl_check_serverhello_tlsext(SSL *s) {
- int ret = SSL_TLSEXT_ERR_NOACK;
+ int ret = SSL_TLSEXT_ERR_OK;
int al = SSL_AD_UNRECOGNIZED_NAME;
- /* If we are client and using an elliptic curve cryptography cipher suite,
- * then if server returns an EC point formats lists extension it must contain
- * uncompressed. */
- uint32_t alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
- uint32_t alg_a = s->s3->tmp.new_cipher->algorithm_auth;
- if (((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)) &&
- !tls1_check_point_format(s, TLSEXT_ECPOINTFORMAT_uncompressed)) {
- OPENSSL_PUT_ERROR(SSL, ssl_check_serverhello_tlsext,
- SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
- return -1;
- }
- ret = SSL_TLSEXT_ERR_OK;
-
if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) {
ret = s->ctx->tlsext_servername_callback(s, &al,
s->ctx->tlsext_servername_arg);
@@ -2007,203 +2615,131 @@ int ssl_parse_serverhello_tlsext(SSL *s, CBS *cbs) {
}
if (ssl_check_serverhello_tlsext(s) <= 0) {
- OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_tlsext,
- SSL_R_SERVERHELLO_TLSEXT);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SERVERHELLO_TLSEXT);
return 0;
}
return 1;
}
-/* Since the server cache lookup is done early on in the processing of the
- * ClientHello, and other operations depend on the result, we need to handle
- * any TLS session ticket extension at the same time.
- *
- * ctx: contains the early callback context, which is the result of a
- * shallow parse of the ClientHello.
- * ret: (output) on return, if a ticket was decrypted, then this is set to
- * point to the resulting session.
- *
- * Returns:
- * -1: fatal error, either from parsing or decrypting the ticket.
- * 0: no ticket was found (or was ignored, based on settings).
- * 1: a zero length extension was found, indicating that the client supports
- * session tickets but doesn't currently have one to offer.
- * 2: a ticket was offered but couldn't be decrypted because of a non-fatal
- * error.
- * 3: a ticket was successfully decrypted and *ret was set.
- *
- * Side effects:
- * Sets s->tlsext_ticket_expected to 1 if the server will have to issue
- * a new session ticket to the client because the client indicated support
- * but the client either doesn't have a session ticket or we couldn't use
- * the one it gave us, or if s->ctx->tlsext_ticket_key_cb asked to renew
- * the client's ticket. Otherwise, s->tlsext_ticket_expected is set to 0.
- */
-int tls1_process_ticket(SSL *s, const struct ssl_early_callback_ctx *ctx,
- SSL_SESSION **ret) {
- *ret = NULL;
- s->tlsext_ticket_expected = 0;
- const uint8_t *data;
- size_t len;
- int r;
-
- /* If tickets disabled behave as if no ticket present to permit stateful
- * resumption. */
- if ((SSL_get_options(s) & SSL_OP_NO_TICKET) ||
- (s->version <= SSL3_VERSION && !ctx->extensions) ||
- !SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_session_ticket,
- &data, &len)) {
- return 0;
- }
-
- if (len == 0) {
- /* The client will accept a ticket but doesn't currently have one. */
- s->tlsext_ticket_expected = 1;
- return 1;
- }
-
- r = tls_decrypt_ticket(s, data, len, ctx->session_id, ctx->session_id_len,
- ret);
- switch (r) {
- case 2: /* ticket couldn't be decrypted */
- s->tlsext_ticket_expected = 1;
- return 2;
+int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session,
+ int *out_send_ticket, const uint8_t *ticket,
+ size_t ticket_len, const uint8_t *session_id,
+ size_t session_id_len) {
+ int ret = 1; /* Most errors are non-fatal. */
+ SSL_CTX *ssl_ctx = ssl->initial_ctx;
+ uint8_t *plaintext = NULL;
- case 3: /* ticket was decrypted */
- return r;
+ HMAC_CTX hmac_ctx;
+ HMAC_CTX_init(&hmac_ctx);
+ EVP_CIPHER_CTX cipher_ctx;
+ EVP_CIPHER_CTX_init(&cipher_ctx);
- case 4: /* ticket decrypted but need to renew */
- s->tlsext_ticket_expected = 1;
- return 3;
+ *out_send_ticket = 0;
+ *out_session = NULL;
- default: /* fatal error */
- return -1;
+ if (session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) {
+ goto done;
}
-}
-/* tls_decrypt_ticket attempts to decrypt a session ticket.
- *
- * etick: points to the body of the session ticket extension.
- * eticklen: the length of the session tickets extenion.
- * sess_id: points at the session ID.
- * sesslen: the length of the session ID.
- * psess: (output) on return, if a ticket was decrypted, then this is set to
- * point to the resulting session.
- *
- * Returns:
- * -1: fatal error, either from parsing or decrypting the ticket.
- * 2: the ticket couldn't be decrypted.
- * 3: a ticket was successfully decrypted and *psess was set.
- * 4: same as 3, but the ticket needs to be renewed. */
-static int tls_decrypt_ticket(SSL *s, const uint8_t *etick, int eticklen,
- const uint8_t *sess_id, int sesslen,
- SSL_SESSION **psess) {
- SSL_SESSION *sess;
- uint8_t *sdec;
- const uint8_t *p;
- int slen, mlen, renew_ticket = 0;
- uint8_t tick_hmac[EVP_MAX_MD_SIZE];
- HMAC_CTX hctx;
- EVP_CIPHER_CTX ctx;
- SSL_CTX *tctx = s->initial_ctx;
+ if (ticket_len == 0) {
+ /* The client will accept a ticket but doesn't currently have one. */
+ *out_send_ticket = 1;
+ goto done;
+ }
/* 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;
- }
-
- /* Initialize session ticket encryption and HMAC contexts */
- HMAC_CTX_init(&hctx);
- EVP_CIPHER_CTX_init(&ctx);
- if (tctx->tlsext_ticket_key_cb) {
- uint8_t *nctick = (uint8_t *)etick;
- int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16, &ctx, &hctx,
- 0 /* decrypt */);
- if (rv < 0) {
- return -1;
+ if (ticket_len < SSL_TICKET_KEY_NAME_LEN + EVP_MAX_IV_LENGTH) {
+ goto done;
+ }
+ const uint8_t *iv = ticket + SSL_TICKET_KEY_NAME_LEN;
+
+ if (ssl_ctx->tlsext_ticket_key_cb != NULL) {
+ int cb_ret = ssl_ctx->tlsext_ticket_key_cb(ssl, (uint8_t*)ticket /* name */,
+ (uint8_t*)iv, &cipher_ctx, &hmac_ctx,
+ 0 /* decrypt */);
+ if (cb_ret < 0) {
+ ret = 0;
+ goto done;
}
- if (rv == 0) {
- return 2;
+ if (cb_ret == 0) {
+ goto done;
}
- if (rv == 2) {
- renew_ticket = 1;
+ if (cb_ret == 2) {
+ *out_send_ticket = 1;
}
} else {
- /* Check key name matches */
- if (memcmp(etick, tctx->tlsext_tick_key_name, 16)) {
- return 2;
+ /* Check the key name matches. */
+ if (memcmp(ticket, ssl_ctx->tlsext_tick_key_name,
+ SSL_TICKET_KEY_NAME_LEN) != 0) {
+ goto done;
}
- if (!HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, tlsext_tick_md(),
+ if (!HMAC_Init_ex(&hmac_ctx, ssl_ctx->tlsext_tick_hmac_key,
+ sizeof(ssl_ctx->tlsext_tick_hmac_key), tlsext_tick_md(),
NULL) ||
- !EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
- tctx->tlsext_tick_aes_key, etick + 16)) {
- HMAC_CTX_cleanup(&hctx);
- EVP_CIPHER_CTX_cleanup(&ctx);
- return -1;
+ !EVP_DecryptInit_ex(&cipher_ctx, EVP_aes_128_cbc(), NULL,
+ ssl_ctx->tlsext_tick_aes_key, iv)) {
+ ret = 0;
+ goto done;
}
}
+ size_t iv_len = EVP_CIPHER_CTX_iv_length(&cipher_ctx);
- /* First, check the MAC. The MAC is at the end of the ticket. */
- mlen = HMAC_size(&hctx);
- if ((size_t) eticklen < 16 + EVP_CIPHER_CTX_iv_length(&ctx) + 1 + mlen) {
+ /* Check the MAC at the end of the ticket. */
+ uint8_t mac[EVP_MAX_MD_SIZE];
+ size_t mac_len = HMAC_size(&hmac_ctx);
+ if (ticket_len < SSL_TICKET_KEY_NAME_LEN + iv_len + 1 + mac_len) {
/* The ticket must be large enough for key name, IV, data, and MAC. */
- HMAC_CTX_cleanup(&hctx);
- EVP_CIPHER_CTX_cleanup(&ctx);
- return 2;
- }
- eticklen -= mlen;
- /* Check HMAC of encrypted ticket */
- HMAC_Update(&hctx, etick, eticklen);
- HMAC_Final(&hctx, tick_hmac, NULL);
- HMAC_CTX_cleanup(&hctx);
- if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen)) {
- EVP_CIPHER_CTX_cleanup(&ctx);
- return 2;
- }
-
- /* Attempt to decrypt session data */
- /* Move p after IV to start of encrypted ticket, update length */
- p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx);
- eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx);
- sdec = OPENSSL_malloc(eticklen);
- if (!sdec) {
- EVP_CIPHER_CTX_cleanup(&ctx);
- return -1;
+ goto done;
}
- EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen);
- if (EVP_DecryptFinal_ex(&ctx, sdec + slen, &mlen) <= 0) {
- EVP_CIPHER_CTX_cleanup(&ctx);
- OPENSSL_free(sdec);
- return 2;
- }
- slen += mlen;
- EVP_CIPHER_CTX_cleanup(&ctx);
- p = sdec;
-
- sess = SSL_SESSION_from_bytes(sdec, slen);
- OPENSSL_free(sdec);
- if (sess) {
- /* The session ID, if non-empty, is used by some clients to detect that the
- * ticket has been accepted. So we copy it to the session structure. If it
- * is empty set length to zero as required by standard. */
- if (sesslen) {
- memcpy(sess->session_id, sess_id, sesslen);
- }
- sess->session_id_length = sesslen;
- *psess = sess;
- if (renew_ticket) {
- return 4;
- }
- return 3;
+ HMAC_Update(&hmac_ctx, ticket, ticket_len - mac_len);
+ HMAC_Final(&hmac_ctx, mac, NULL);
+ if (CRYPTO_memcmp(mac, ticket + (ticket_len - mac_len), mac_len) != 0) {
+ goto done;
+ }
+
+ /* Decrypt the session data. */
+ const uint8_t *ciphertext = ticket + SSL_TICKET_KEY_NAME_LEN + iv_len;
+ size_t ciphertext_len = ticket_len - SSL_TICKET_KEY_NAME_LEN - iv_len -
+ mac_len;
+ plaintext = OPENSSL_malloc(ciphertext_len);
+ if (plaintext == NULL) {
+ ret = 0;
+ goto done;
+ }
+ if (ciphertext_len >= INT_MAX) {
+ goto done;
+ }
+ int len1, len2;
+ if (!EVP_DecryptUpdate(&cipher_ctx, plaintext, &len1, ciphertext,
+ (int)ciphertext_len) ||
+ !EVP_DecryptFinal_ex(&cipher_ctx, plaintext + len1, &len2)) {
+ ERR_clear_error(); /* Don't leave an error on the queue. */
+ goto done;
+ }
+
+ /* Decode the session. */
+ SSL_SESSION *session = SSL_SESSION_from_bytes(plaintext, len1 + len2);
+ if (session == NULL) {
+ ERR_clear_error(); /* Don't leave an error on the queue. */
+ goto done;
}
- ERR_clear_error();
- /* For session parse failure, indicate that we need to send a new ticket. */
- return 2;
+ /* Copy the client's session ID into the new session, to denote the ticket has
+ * been accepted. */
+ memcpy(session->session_id, session_id, session_id_len);
+ session->session_id_length = session_id_len;
+
+ *out_session = session;
+
+done:
+ OPENSSL_free(plaintext);
+ HMAC_CTX_cleanup(&hmac_ctx);
+ EVP_CIPHER_CTX_cleanup(&cipher_ctx);
+ return ret;
}
/* Tables to translate from NIDs to TLS v1.2 ids */
@@ -2233,18 +2769,12 @@ static int tls12_find_id(int nid, const tls12_lookup *table, size_t tlen) {
return -1;
}
-static int tls12_find_nid(int id, const tls12_lookup *table, size_t tlen) {
- size_t i;
- for (i = 0; i < tlen; i++) {
- if (table[i].id == id) {
- return table[i].nid;
- }
- }
-
- return NID_undef;
+int tls12_get_sigid(int pkey_type) {
+ return tls12_find_id(pkey_type, tls12_sig,
+ sizeof(tls12_sig) / sizeof(tls12_lookup));
}
-int tls12_get_sigandhash(uint8_t *p, const EVP_PKEY *pk, const EVP_MD *md) {
+int tls12_get_sigandhash(SSL *ssl, uint8_t *p, const EVP_MD *md) {
int sig_id, md_id;
if (!md) {
@@ -2257,7 +2787,7 @@ int tls12_get_sigandhash(uint8_t *p, const EVP_PKEY *pk, const EVP_MD *md) {
return 0;
}
- sig_id = tls12_get_sigid(pk);
+ sig_id = tls12_get_sigid(ssl_private_key_type(ssl));
if (sig_id == -1) {
return 0;
}
@@ -2267,11 +2797,6 @@ int tls12_get_sigandhash(uint8_t *p, const EVP_PKEY *pk, const EVP_MD *md) {
return 1;
}
-int tls12_get_sigid(const EVP_PKEY *pk) {
- return tls12_find_id(pk->type, tls12_sig,
- sizeof(tls12_sig) / sizeof(tls12_lookup));
-}
-
const EVP_MD *tls12_get_hash(uint8_t hash_alg) {
switch (hash_alg) {
case TLSEXT_hash_md5:
@@ -2312,256 +2837,129 @@ static int tls12_get_pkey_type(uint8_t sig_alg) {
}
}
-/* Convert TLS 1.2 signature algorithm extension values into NIDs */
-static void tls1_lookup_sigalg(int *phash_nid, int *psign_nid,
- int *psignhash_nid, const uint8_t *data) {
- int sign_nid = 0, hash_nid = 0;
- if (!phash_nid && !psign_nid && !psignhash_nid) {
- return;
- }
-
- if (phash_nid || psignhash_nid) {
- hash_nid = tls12_find_nid(data[0], tls12_md,
- sizeof(tls12_md) / sizeof(tls12_lookup));
- if (phash_nid) {
- *phash_nid = hash_nid;
- }
- }
-
- if (psign_nid || psignhash_nid) {
- sign_nid = tls12_find_nid(data[1], tls12_sig,
- sizeof(tls12_sig) / sizeof(tls12_lookup));
- if (psign_nid) {
- *psign_nid = sign_nid;
- }
- }
-
- if (psignhash_nid) {
- if (sign_nid && hash_nid) {
- OBJ_find_sigid_by_algs(psignhash_nid, hash_nid, sign_nid);
- } else {
- *psignhash_nid = NID_undef;
- }
- }
-}
-
-/* Given preference and allowed sigalgs set shared sigalgs */
-static int tls12_do_shared_sigalgs(TLS_SIGALGS *shsig, const uint8_t *pref,
- size_t preflen, const uint8_t *allow,
- size_t allowlen) {
- const uint8_t *ptmp, *atmp;
- size_t i, j, nmatch = 0;
-
- for (i = 0, ptmp = pref; i < preflen; i += 2, ptmp += 2) {
- /* Skip disabled hashes or signature algorithms */
- if (tls12_get_hash(ptmp[0]) == NULL ||
- tls12_get_pkey_type(ptmp[1]) == -1) {
- continue;
- }
-
- for (j = 0, atmp = allow; j < allowlen; j += 2, atmp += 2) {
- if (ptmp[0] == atmp[0] && ptmp[1] == atmp[1]) {
- nmatch++;
- if (shsig) {
- shsig->rhash = ptmp[0];
- shsig->rsign = ptmp[1];
- tls1_lookup_sigalg(&shsig->hash_nid, &shsig->sign_nid,
- &shsig->signandhash_nid, ptmp);
- shsig++;
- }
-
- break;
- }
- }
- }
-
- return nmatch;
-}
-
-/* Set shared signature algorithms for SSL structures */
-static int tls1_set_shared_sigalgs(SSL *s) {
- const uint8_t *pref, *allow, *conf;
- size_t preflen, allowlen, conflen;
- size_t nmatch;
- TLS_SIGALGS *salgs = NULL;
- CERT *c = s->cert;
+OPENSSL_COMPILE_ASSERT(sizeof(TLS_SIGALGS) == 2,
+ sizeof_tls_sigalgs_is_not_two);
- OPENSSL_free(c->shared_sigalgs);
- c->shared_sigalgs = NULL;
- c->shared_sigalgslen = 0;
-
- /* If client use client signature algorithms if not NULL */
- if (!s->server && c->client_sigalgs) {
- conf = c->client_sigalgs;
- conflen = c->client_sigalgslen;
- } else if (c->conf_sigalgs) {
- conf = c->conf_sigalgs;
- conflen = c->conf_sigalgslen;
- } else {
- conflen = tls12_get_psigalgs(s, &conf);
+int tls1_parse_peer_sigalgs(SSL *ssl, const CBS *in_sigalgs) {
+ /* Extension ignored for inappropriate versions */
+ if (!SSL_USE_SIGALGS(ssl)) {
+ return 1;
}
- if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) {
- pref = conf;
- preflen = conflen;
- allow = c->peer_sigalgs;
- allowlen = c->peer_sigalgslen;
- } else {
- allow = conf;
- allowlen = conflen;
- pref = c->peer_sigalgs;
- preflen = c->peer_sigalgslen;
- }
+ CERT *const cert = ssl->cert;
+ OPENSSL_free(cert->peer_sigalgs);
+ cert->peer_sigalgs = NULL;
+ cert->peer_sigalgslen = 0;
- nmatch = tls12_do_shared_sigalgs(NULL, pref, preflen, allow, allowlen);
- if (!nmatch) {
- return 1;
- }
+ size_t num_sigalgs = CBS_len(in_sigalgs);
- salgs = OPENSSL_malloc(nmatch * sizeof(TLS_SIGALGS));
- if (!salgs) {
+ if (num_sigalgs % 2 != 0) {
return 0;
}
+ num_sigalgs /= 2;
- nmatch = tls12_do_shared_sigalgs(salgs, pref, preflen, allow, allowlen);
- c->shared_sigalgs = salgs;
- c->shared_sigalgslen = nmatch;
- return 1;
-}
-
-/* Set preferred digest for each key type */
-int tls1_process_sigalgs(SSL *s, const CBS *sigalgs) {
- CERT *c = s->cert;
-
- /* Extension ignored for inappropriate versions */
- if (!SSL_USE_SIGALGS(s)) {
+ /* supported_signature_algorithms in the certificate request is
+ * allowed to be empty. */
+ if (num_sigalgs == 0) {
return 1;
}
- if (CBS_len(sigalgs) % 2 != 0 ||
- !CBS_stow(sigalgs, &c->peer_sigalgs, &c->peer_sigalgslen) ||
- !tls1_set_shared_sigalgs(s)) {
+ /* This multiplication doesn't overflow because sizeof(TLS_SIGALGS) is two
+ * (statically asserted above) and we just divided |num_sigalgs| by two. */
+ cert->peer_sigalgs = OPENSSL_malloc(num_sigalgs * sizeof(TLS_SIGALGS));
+ if (cert->peer_sigalgs == NULL) {
return 0;
}
+ cert->peer_sigalgslen = num_sigalgs;
- return 1;
-}
+ CBS sigalgs;
+ CBS_init(&sigalgs, CBS_data(in_sigalgs), CBS_len(in_sigalgs));
-const EVP_MD *tls1_choose_signing_digest(SSL *s, EVP_PKEY *pkey) {
- CERT *c = s->cert;
- int type = EVP_PKEY_id(pkey);
size_t i;
-
- /* Select the first shared digest supported by our key. */
- for (i = 0; i < c->shared_sigalgslen; i++) {
- const EVP_MD *md = tls12_get_hash(c->shared_sigalgs[i].rhash);
- if (md == NULL ||
- tls12_get_pkey_type(c->shared_sigalgs[i].rsign) != type ||
- !EVP_PKEY_supports_digest(pkey, md)) {
- continue;
- }
- return md;
- }
-
- /* If no suitable digest may be found, default to SHA-1. */
- return EVP_sha1();
-}
-
-int SSL_get_sigalgs(SSL *s, int idx, int *psign, int *phash, int *psignhash,
- uint8_t *rsig, uint8_t *rhash) {
- const uint8_t *psig = s->cert->peer_sigalgs;
-
- if (psig == NULL) {
- return 0;
- }
-
- if (idx >= 0) {
- idx <<= 1;
- if (idx >= (int)s->cert->peer_sigalgslen) {
+ for (i = 0; i < num_sigalgs; i++) {
+ TLS_SIGALGS *const sigalg = &cert->peer_sigalgs[i];
+ if (!CBS_get_u8(&sigalgs, &sigalg->rhash) ||
+ !CBS_get_u8(&sigalgs, &sigalg->rsign)) {
return 0;
}
- psig += idx;
- if (rhash) {
- *rhash = psig[0];
- }
- if (rsig) {
- *rsig = psig[1];
- }
- tls1_lookup_sigalg(phash, psign, psignhash, psig);
}
- return s->cert->peer_sigalgslen / 2;
+ return 1;
}
-int SSL_get_shared_sigalgs(SSL *s, int idx, int *psign, int *phash,
- int *psignhash, uint8_t *rsig, uint8_t *rhash) {
- TLS_SIGALGS *shsigalgs = s->cert->shared_sigalgs;
-
- if (!shsigalgs || idx >= (int)s->cert->shared_sigalgslen) {
- return 0;
- }
+const EVP_MD *tls1_choose_signing_digest(SSL *ssl) {
+ CERT *cert = ssl->cert;
+ int type = ssl_private_key_type(ssl);
+ size_t i, j;
+
+ static const int kDefaultDigestList[] = {NID_sha256, NID_sha384, NID_sha512,
+ NID_sha224, NID_sha1};
+
+ const int *digest_nids = kDefaultDigestList;
+ size_t num_digest_nids =
+ sizeof(kDefaultDigestList) / sizeof(kDefaultDigestList[0]);
+ if (cert->digest_nids != NULL) {
+ digest_nids = cert->digest_nids;
+ num_digest_nids = cert->num_digest_nids;
+ }
+
+ for (i = 0; i < num_digest_nids; i++) {
+ const int digest_nid = digest_nids[i];
+ for (j = 0; j < cert->peer_sigalgslen; j++) {
+ const EVP_MD *md = tls12_get_hash(cert->peer_sigalgs[j].rhash);
+ if (md == NULL ||
+ digest_nid != EVP_MD_type(md) ||
+ tls12_get_pkey_type(cert->peer_sigalgs[j].rsign) != type) {
+ continue;
+ }
- shsigalgs += idx;
- if (phash) {
- *phash = shsigalgs->hash_nid;
- }
- if (psign) {
- *psign = shsigalgs->sign_nid;
- }
- if (psignhash) {
- *psignhash = shsigalgs->signandhash_nid;
- }
- if (rsig) {
- *rsig = shsigalgs->rsign;
- }
- if (rhash) {
- *rhash = shsigalgs->rhash;
+ return md;
+ }
}
- return s->cert->shared_sigalgslen;
+ /* If no suitable digest may be found, default to SHA-1. */
+ return EVP_sha1();
}
-/* tls1_channel_id_hash calculates the signed data for a Channel ID on the
- * given SSL connection and writes it to |md|. */
-int tls1_channel_id_hash(EVP_MD_CTX *md, SSL *s) {
+int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len) {
+ int ret = 0;
EVP_MD_CTX ctx;
- uint8_t temp_digest[EVP_MAX_MD_SIZE];
- unsigned temp_digest_len;
- int i;
- static const char kClientIDMagic[] = "TLS Channel ID signature";
- if (s->s3->handshake_buffer &&
- !ssl3_digest_cached_records(s, free_handshake_buffer)) {
- return 0;
+ EVP_MD_CTX_init(&ctx);
+ if (!EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL)) {
+ goto err;
}
- EVP_DigestUpdate(md, kClientIDMagic, sizeof(kClientIDMagic));
+ static const char kClientIDMagic[] = "TLS Channel ID signature";
+ EVP_DigestUpdate(&ctx, kClientIDMagic, sizeof(kClientIDMagic));
- if (s->hit && s->s3->tlsext_channel_id_new) {
+ if (ssl->hit) {
static const char kResumptionMagic[] = "Resumption";
- EVP_DigestUpdate(md, kResumptionMagic, sizeof(kResumptionMagic));
- if (s->session->original_handshake_hash_len == 0) {
- return 0;
+ EVP_DigestUpdate(&ctx, kResumptionMagic, sizeof(kResumptionMagic));
+ if (ssl->session->original_handshake_hash_len == 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
}
- EVP_DigestUpdate(md, s->session->original_handshake_hash,
- s->session->original_handshake_hash_len);
+ EVP_DigestUpdate(&ctx, ssl->session->original_handshake_hash,
+ ssl->session->original_handshake_hash_len);
}
- EVP_MD_CTX_init(&ctx);
- for (i = 0; i < SSL_MAX_DIGEST; i++) {
- if (s->s3->handshake_dgst[i] == NULL) {
- continue;
- }
- if (!EVP_MD_CTX_copy_ex(&ctx, s->s3->handshake_dgst[i])) {
- EVP_MD_CTX_cleanup(&ctx);
- return 0;
- }
- EVP_DigestFinal_ex(&ctx, temp_digest, &temp_digest_len);
- EVP_DigestUpdate(md, temp_digest, temp_digest_len);
+ uint8_t handshake_hash[EVP_MAX_MD_SIZE];
+ int handshake_hash_len = tls1_handshake_digest(ssl, handshake_hash,
+ sizeof(handshake_hash));
+ if (handshake_hash_len < 0) {
+ goto err;
}
- EVP_MD_CTX_cleanup(&ctx);
+ EVP_DigestUpdate(&ctx, handshake_hash, (size_t)handshake_hash_len);
+ unsigned len_u;
+ EVP_DigestFinal_ex(&ctx, out, &len_u);
+ *out_len = len_u;
- return 1;
+ ret = 1;
+
+err:
+ EVP_MD_CTX_cleanup(&ctx);
+ return ret;
}
/* tls1_record_handshake_hashes_for_channel_id records the current handshake
@@ -2575,12 +2973,6 @@ int tls1_record_handshake_hashes_for_channel_id(SSL *s) {
return -1;
}
- /* It only makes sense to call this function if Channel IDs have been
- * negotiated. */
- if (!s->s3->tlsext_channel_id_new) {
- return -1;
- }
-
digest_len =
tls1_handshake_digest(s, s->session->original_handshake_hash,
sizeof(s->session->original_handshake_hash));
@@ -2592,48 +2984,3 @@ int tls1_record_handshake_hashes_for_channel_id(SSL *s) {
return 1;
}
-
-int tls1_set_sigalgs(CERT *c, const int *psig_nids, size_t salglen,
- int client) {
- uint8_t *sigalgs, *sptr;
- int rhash, rsign;
- size_t i;
-
- if (salglen & 1) {
- return 0;
- }
-
- sigalgs = OPENSSL_malloc(salglen);
- if (sigalgs == NULL) {
- return 0;
- }
-
- for (i = 0, sptr = sigalgs; i < salglen; i += 2) {
- rhash = tls12_find_id(*psig_nids++, tls12_md,
- sizeof(tls12_md) / sizeof(tls12_lookup));
- rsign = tls12_find_id(*psig_nids++, tls12_sig,
- sizeof(tls12_sig) / sizeof(tls12_lookup));
-
- if (rhash == -1 || rsign == -1) {
- goto err;
- }
- *sptr++ = rhash;
- *sptr++ = rsign;
- }
-
- if (client) {
- OPENSSL_free(c->client_sigalgs);
- c->client_sigalgs = sigalgs;
- c->client_sigalgslen = salglen;
- } else {
- OPENSSL_free(c->conf_sigalgs);
- c->conf_sigalgs = sigalgs;
- c->conf_sigalgslen = salglen;
- }
-
- return 1;
-
-err:
- OPENSSL_free(sigalgs);
- return 0;
-}
diff --git a/src/ssl/t1_reneg.c b/src/ssl/t1_reneg.c
deleted file mode 100644
index d0009c1..0000000
--- a/src/ssl/t1_reneg.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2009 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com). */
-
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <openssl/bytestring.h>
-#include <openssl/err.h>
-
-#include "internal.h"
-
-
-/* Add the client's renegotiation binding */
-int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, int *len,
- int maxlen) {
- if (p) {
- if (s->s3->previous_client_finished_len + 1 > maxlen) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_renegotiate_ext,
- SSL_R_RENEGOTIATE_EXT_TOO_LONG);
- return 0;
- }
-
- /* Length byte */
- *p = s->s3->previous_client_finished_len;
- p++;
-
- memcpy(p, s->s3->previous_client_finished,
- s->s3->previous_client_finished_len);
- }
-
- *len = s->s3->previous_client_finished_len + 1;
-
- return 1;
-}
-
-/* Parse the client's renegotiation binding and abort if it's not right */
-int ssl_parse_clienthello_renegotiate_ext(SSL *s, CBS *cbs, int *out_alert) {
- CBS renegotiated_connection;
-
- if (!CBS_get_u8_length_prefixed(cbs, &renegotiated_connection) ||
- CBS_len(cbs) != 0) {
- OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_renegotiate_ext,
- SSL_R_RENEGOTIATION_ENCODING_ERR);
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
-
- /* Check that the extension matches */
- if (!CBS_mem_equal(&renegotiated_connection, s->s3->previous_client_finished,
- s->s3->previous_client_finished_len)) {
- OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_renegotiate_ext,
- SSL_R_RENEGOTIATION_MISMATCH);
- *out_alert = SSL_AD_HANDSHAKE_FAILURE;
- return 0;
- }
-
- s->s3->send_connection_binding = 1;
-
- return 1;
-}
-
-/* Add the server's renegotiation binding */
-int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len,
- int maxlen) {
- if (p) {
- if (s->s3->previous_client_finished_len +
- s->s3->previous_server_finished_len + 1 > maxlen) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_renegotiate_ext,
- SSL_R_RENEGOTIATE_EXT_TOO_LONG);
- return 0;
- }
-
- /* Length byte */
- *p = s->s3->previous_client_finished_len +
- s->s3->previous_server_finished_len;
- p++;
-
- memcpy(p, s->s3->previous_client_finished,
- s->s3->previous_client_finished_len);
- p += s->s3->previous_client_finished_len;
-
- memcpy(p, s->s3->previous_server_finished,
- s->s3->previous_server_finished_len);
- }
-
- *len = s->s3->previous_client_finished_len +
- s->s3->previous_server_finished_len + 1;
-
- return 1;
-}
-
-/* Parse the server's renegotiation binding and abort if it's not right */
-int ssl_parse_serverhello_renegotiate_ext(SSL *s, CBS *cbs, int *out_alert) {
- int expected_len =
- s->s3->previous_client_finished_len + s->s3->previous_server_finished_len;
- CBS renegotiated_connection;
- const uint8_t *d;
-
- /* Check for logic errors */
- assert(!expected_len || s->s3->previous_client_finished_len);
- assert(!expected_len || s->s3->previous_server_finished_len);
-
- /* Parse out the extension contents. */
- if (!CBS_get_u8_length_prefixed(cbs, &renegotiated_connection) ||
- CBS_len(cbs) != 0) {
- OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_renegotiate_ext,
- SSL_R_RENEGOTIATION_ENCODING_ERR);
- *out_alert = SSL_AD_ILLEGAL_PARAMETER;
- return 0;
- }
-
- /* Check that the extension matches. */
- if (CBS_len(&renegotiated_connection) != expected_len) {
- OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_renegotiate_ext,
- SSL_R_RENEGOTIATION_MISMATCH);
- *out_alert = SSL_AD_HANDSHAKE_FAILURE;
- return 0;
- }
-
- d = CBS_data(&renegotiated_connection);
- if (memcmp(d, s->s3->previous_client_finished,
- s->s3->previous_client_finished_len)) {
- OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_renegotiate_ext,
- SSL_R_RENEGOTIATION_MISMATCH);
- *out_alert = SSL_AD_HANDSHAKE_FAILURE;
- return 0;
- }
- d += s->s3->previous_client_finished_len;
-
- if (memcmp(d, s->s3->previous_server_finished,
- s->s3->previous_server_finished_len)) {
- OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_renegotiate_ext,
- SSL_R_RENEGOTIATION_MISMATCH);
- *out_alert = SSL_AD_ILLEGAL_PARAMETER;
- return 0;
- }
- s->s3->send_connection_binding = 1;
-
- return 1;
-}
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index 3b95d7e..edae67b 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -38,10 +38,14 @@
#include <openssl/bio.h>
#include <openssl/buf.h>
#include <openssl/bytestring.h>
+#include <openssl/cipher.h>
#include <openssl/err.h>
+#include <openssl/hmac.h>
+#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <memory>
+#include <string>
#include <vector>
#include "../../crypto/test/scoped_types.h"
@@ -90,10 +94,17 @@ struct TestState {
ScopedSSL_SESSION pending_session;
bool early_callback_called = false;
bool handshake_done = false;
+ // private_key is the underlying private key used when testing custom keys.
+ ScopedEVP_PKEY private_key;
+ std::vector<uint8_t> signature;
+ // signature_retries is the number of times an asynchronous sign operation has
+ // been retried.
+ unsigned signature_retries = 0;
+ bool got_new_session = false;
};
static void TestStateExFree(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
- int index, long argl, void *argp) {
+ int index, long argl, void *argp) {
delete ((TestState *)ptr);
}
@@ -129,18 +140,137 @@ static ScopedEVP_PKEY LoadPrivateKey(const std::string &file) {
return pkey;
}
+static int AsyncPrivateKeyType(SSL *ssl) {
+ return EVP_PKEY_id(GetTestState(ssl)->private_key.get());
+}
+
+static size_t AsyncPrivateKeyMaxSignatureLen(SSL *ssl) {
+ return EVP_PKEY_size(GetTestState(ssl)->private_key.get());
+}
+
+static ssl_private_key_result_t AsyncPrivateKeySign(
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+ const EVP_MD *md, const uint8_t *in, size_t in_len) {
+ TestState *test_state = GetTestState(ssl);
+ if (!test_state->signature.empty()) {
+ fprintf(stderr, "AsyncPrivateKeySign called with operation pending.\n");
+ abort();
+ }
+
+ ScopedEVP_PKEY_CTX ctx(EVP_PKEY_CTX_new(test_state->private_key.get(),
+ nullptr));
+ if (!ctx) {
+ return ssl_private_key_failure;
+ }
+
+ // Write the signature into |test_state|.
+ size_t len = 0;
+ if (!EVP_PKEY_sign_init(ctx.get()) ||
+ !EVP_PKEY_CTX_set_signature_md(ctx.get(), md) ||
+ !EVP_PKEY_sign(ctx.get(), nullptr, &len, in, in_len)) {
+ return ssl_private_key_failure;
+ }
+ test_state->signature.resize(len);
+ if (!EVP_PKEY_sign(ctx.get(), bssl::vector_data(&test_state->signature), &len,
+ in, in_len)) {
+ return ssl_private_key_failure;
+ }
+ test_state->signature.resize(len);
+
+ // The signature will be released asynchronously in |AsyncPrivateKeySignComplete|.
+ return ssl_private_key_retry;
+}
+
+static ssl_private_key_result_t AsyncPrivateKeySignComplete(
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out) {
+ TestState *test_state = GetTestState(ssl);
+ if (test_state->signature.empty()) {
+ fprintf(stderr,
+ "AsyncPrivateKeySignComplete called without operation pending.\n");
+ abort();
+ }
+
+ if (test_state->signature_retries < 2) {
+ // Only return the signature on the second attempt, to test both incomplete
+ // |sign| and |sign_complete|.
+ return ssl_private_key_retry;
+ }
+
+ if (max_out < test_state->signature.size()) {
+ fprintf(stderr, "Output buffer too small.\n");
+ return ssl_private_key_failure;
+ }
+ memcpy(out, bssl::vector_data(&test_state->signature),
+ test_state->signature.size());
+ *out_len = test_state->signature.size();
+
+ test_state->signature.clear();
+ test_state->signature_retries = 0;
+ return ssl_private_key_success;
+}
+
+static const SSL_PRIVATE_KEY_METHOD g_async_private_key_method = {
+ AsyncPrivateKeyType,
+ AsyncPrivateKeyMaxSignatureLen,
+ AsyncPrivateKeySign,
+ AsyncPrivateKeySignComplete,
+};
+
+template<typename T>
+struct Free {
+ void operator()(T *buf) {
+ free(buf);
+ }
+};
+
static bool InstallCertificate(SSL *ssl) {
const TestConfig *config = GetConfigPtr(ssl);
- if (!config->key_file.empty() &&
- !SSL_use_PrivateKey_file(ssl, config->key_file.c_str(),
- SSL_FILETYPE_PEM)) {
- return false;
+ TestState *test_state = GetTestState(ssl);
+
+ if (!config->digest_prefs.empty()) {
+ std::unique_ptr<char, Free<char>> digest_prefs(
+ strdup(config->digest_prefs.c_str()));
+ std::vector<int> digest_list;
+
+ for (;;) {
+ char *token =
+ strtok(digest_list.empty() ? digest_prefs.get() : nullptr, ",");
+ if (token == nullptr) {
+ break;
+ }
+
+ digest_list.push_back(EVP_MD_type(EVP_get_digestbyname(token)));
+ }
+
+ if (!SSL_set_private_key_digest_prefs(ssl, digest_list.data(),
+ digest_list.size())) {
+ return false;
+ }
+ }
+
+ if (!config->key_file.empty()) {
+ if (config->use_async_private_key) {
+ test_state->private_key = LoadPrivateKey(config->key_file.c_str());
+ if (!test_state->private_key) {
+ return false;
+ }
+ SSL_set_private_key_method(ssl, &g_async_private_key_method);
+ } else if (!SSL_use_PrivateKey_file(ssl, config->key_file.c_str(),
+ SSL_FILETYPE_PEM)) {
+ return false;
+ }
}
if (!config->cert_file.empty() &&
!SSL_use_certificate_file(ssl, config->cert_file.c_str(),
SSL_FILETYPE_PEM)) {
return false;
}
+ if (!config->ocsp_response.empty() &&
+ !SSL_CTX_set_ocsp_response(ssl->ctx,
+ (const uint8_t *)config->ocsp_response.data(),
+ config->ocsp_response.size())) {
+ return false;
+ }
return true;
}
@@ -196,10 +326,29 @@ static int SelectCertificateCallback(const struct ssl_early_callback_ctx *ctx) {
return 1;
}
-static int SkipVerify(int preverify_ok, X509_STORE_CTX *store_ctx) {
+static int VerifySucceed(X509_STORE_CTX *store_ctx, void *arg) {
+ SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(store_ctx,
+ SSL_get_ex_data_X509_STORE_CTX_idx());
+ const TestConfig *config = GetConfigPtr(ssl);
+
+ if (!config->expected_ocsp_response.empty()) {
+ const uint8_t *data;
+ size_t len;
+ SSL_get0_ocsp_response(ssl, &data, &len);
+ if (len == 0) {
+ fprintf(stderr, "OCSP response not available in verify callback\n");
+ return 0;
+ }
+ }
+
return 1;
}
+static int VerifyFail(X509_STORE_CTX *store_ctx, void *arg) {
+ store_ctx->error = X509_V_ERR_APPLICATION_VERIFICATION;
+ return 0;
+}
+
static int NextProtosAdvertisedCallback(SSL *ssl, const uint8_t **out,
unsigned int *out_len, void *arg) {
const TestConfig *config = GetConfigPtr(ssl);
@@ -341,6 +490,94 @@ static void InfoCallback(const SSL *ssl, int type, int val) {
}
}
+static int NewSessionCallback(SSL *ssl, SSL_SESSION *session) {
+ GetTestState(ssl)->got_new_session = true;
+ // BoringSSL passes a reference to |session|.
+ SSL_SESSION_free(session);
+ return 1;
+}
+
+static int TicketKeyCallback(SSL *ssl, uint8_t *key_name, uint8_t *iv,
+ EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx,
+ int encrypt) {
+ // This is just test code, so use the all-zeros key.
+ static const uint8_t kZeros[16] = {0};
+
+ if (encrypt) {
+ memcpy(key_name, kZeros, sizeof(kZeros));
+ RAND_bytes(iv, 16);
+ } else if (memcmp(key_name, kZeros, 16) != 0) {
+ return 0;
+ }
+
+ if (!HMAC_Init_ex(hmac_ctx, kZeros, sizeof(kZeros), EVP_sha256(), NULL) ||
+ !EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, kZeros, iv, encrypt)) {
+ return -1;
+ }
+
+ if (!encrypt) {
+ return GetConfigPtr(ssl)->renew_ticket ? 2 : 1;
+ }
+ return 1;
+}
+
+// kCustomExtensionValue is the extension value that the custom extension
+// callbacks will add.
+static const uint16_t kCustomExtensionValue = 1234;
+static void *const kCustomExtensionAddArg =
+ reinterpret_cast<void *>(kCustomExtensionValue);
+static void *const kCustomExtensionParseArg =
+ reinterpret_cast<void *>(kCustomExtensionValue + 1);
+static const char kCustomExtensionContents[] = "custom extension";
+
+static int CustomExtensionAddCallback(SSL *ssl, unsigned extension_value,
+ const uint8_t **out, size_t *out_len,
+ int *out_alert_value, void *add_arg) {
+ if (extension_value != kCustomExtensionValue ||
+ add_arg != kCustomExtensionAddArg) {
+ abort();
+ }
+
+ if (GetConfigPtr(ssl)->custom_extension_skip) {
+ return 0;
+ }
+ if (GetConfigPtr(ssl)->custom_extension_fail_add) {
+ return -1;
+ }
+
+ *out = reinterpret_cast<const uint8_t*>(kCustomExtensionContents);
+ *out_len = sizeof(kCustomExtensionContents) - 1;
+
+ return 1;
+}
+
+static void CustomExtensionFreeCallback(SSL *ssl, unsigned extension_value,
+ const uint8_t *out, void *add_arg) {
+ if (extension_value != kCustomExtensionValue ||
+ add_arg != kCustomExtensionAddArg ||
+ out != reinterpret_cast<const uint8_t *>(kCustomExtensionContents)) {
+ abort();
+ }
+}
+
+static int CustomExtensionParseCallback(SSL *ssl, unsigned extension_value,
+ const uint8_t *contents,
+ size_t contents_len,
+ int *out_alert_value, void *parse_arg) {
+ if (extension_value != kCustomExtensionValue ||
+ parse_arg != kCustomExtensionParseArg) {
+ abort();
+ }
+
+ if (contents_len != sizeof(kCustomExtensionContents) - 1 ||
+ memcmp(contents, kCustomExtensionContents, contents_len) != 0) {
+ *out_alert_value = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ return 1;
+}
+
// Connect returns a new socket connected to localhost on |port| or -1 on
// error.
static int Connect(uint16_t port) {
@@ -406,7 +643,23 @@ static ScopedSSL_CTX SetupCtx(const TestConfig *config) {
return nullptr;
}
- if (!SSL_CTX_set_cipher_list(ssl_ctx.get(), "ALL")) {
+ std::string cipher_list = "ALL";
+ if (!config->cipher.empty()) {
+ cipher_list = config->cipher;
+ SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_CIPHER_SERVER_PREFERENCE);
+ }
+ if (!SSL_CTX_set_cipher_list(ssl_ctx.get(), cipher_list.c_str())) {
+ return nullptr;
+ }
+
+ if (!config->cipher_tls10.empty() &&
+ !SSL_CTX_set_cipher_list_tls10(ssl_ctx.get(),
+ config->cipher_tls10.c_str())) {
+ return nullptr;
+ }
+ if (!config->cipher_tls11.empty() &&
+ !SSL_CTX_set_cipher_list_tls11(ssl_ctx.get(),
+ config->cipher_tls11.c_str())) {
return nullptr;
}
@@ -438,12 +691,46 @@ static ScopedSSL_CTX SetupCtx(const TestConfig *config) {
SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), AlpnSelectCallback, NULL);
}
- ssl_ctx->tlsext_channel_id_enabled_new = 1;
+ SSL_CTX_enable_tls_channel_id(ssl_ctx.get());
SSL_CTX_set_channel_id_cb(ssl_ctx.get(), ChannelIdCallback);
ssl_ctx->current_time_cb = CurrentTimeCallback;
SSL_CTX_set_info_callback(ssl_ctx.get(), InfoCallback);
+ SSL_CTX_sess_set_new_cb(ssl_ctx.get(), NewSessionCallback);
+
+ if (config->use_ticket_callback) {
+ SSL_CTX_set_tlsext_ticket_key_cb(ssl_ctx.get(), TicketKeyCallback);
+ }
+
+ if (config->enable_client_custom_extension &&
+ !SSL_CTX_add_client_custom_ext(
+ ssl_ctx.get(), kCustomExtensionValue, CustomExtensionAddCallback,
+ CustomExtensionFreeCallback, kCustomExtensionAddArg,
+ CustomExtensionParseCallback, kCustomExtensionParseArg)) {
+ return nullptr;
+ }
+
+ if (config->enable_server_custom_extension &&
+ !SSL_CTX_add_server_custom_ext(
+ ssl_ctx.get(), kCustomExtensionValue, CustomExtensionAddCallback,
+ CustomExtensionFreeCallback, kCustomExtensionAddArg,
+ CustomExtensionParseCallback, kCustomExtensionParseArg)) {
+ return nullptr;
+ }
+
+ if (config->verify_fail) {
+ SSL_CTX_set_cert_verify_callback(ssl_ctx.get(), VerifyFail, NULL);
+ } else {
+ SSL_CTX_set_cert_verify_callback(ssl_ctx.get(), VerifySucceed, NULL);
+ }
+
+ if (!config->signed_cert_timestamps.empty() &&
+ !SSL_CTX_set_signed_cert_timestamp_list(
+ ssl_ctx.get(), (const uint8_t *)config->signed_cert_timestamps.data(),
+ config->signed_cert_timestamps.size())) {
+ return nullptr;
+ }
return ssl_ctx;
}
@@ -500,6 +787,9 @@ static bool RetryAsync(SSL *ssl, int ret) {
case SSL_ERROR_PENDING_CERTIFICATE:
// The handshake will resume without a second call to the early callback.
return InstallCertificate(ssl);
+ case SSL_ERROR_WANT_PRIVATE_KEY_OPERATION:
+ test_state->signature_retries++;
+ return true;
default:
return false;
}
@@ -531,6 +821,177 @@ static int WriteAll(SSL *ssl, const uint8_t *in, size_t in_len) {
return ret;
}
+// DoShutdown calls |SSL_shutdown|, resolving any asynchronous operations. It
+// returns the result of the final |SSL_shutdown| call.
+static int DoShutdown(SSL *ssl) {
+ const TestConfig *config = GetConfigPtr(ssl);
+ int ret;
+ do {
+ ret = SSL_shutdown(ssl);
+ } while (config->async && RetryAsync(ssl, ret));
+ return ret;
+}
+
+// CheckHandshakeProperties checks, immediately after |ssl| completes its
+// initial handshake (or False Starts), whether all the properties are
+// consistent with the test configuration and invariants.
+static bool CheckHandshakeProperties(SSL *ssl, bool is_resume) {
+ const TestConfig *config = GetConfigPtr(ssl);
+
+ if (SSL_get_current_cipher(ssl) == nullptr) {
+ fprintf(stderr, "null cipher after handshake\n");
+ return false;
+ }
+
+ if (is_resume &&
+ (!!SSL_session_reused(ssl) == config->expect_session_miss)) {
+ fprintf(stderr, "session was%s reused\n",
+ SSL_session_reused(ssl) ? "" : " not");
+ return false;
+ }
+
+ bool expect_handshake_done = is_resume || !config->false_start;
+ if (expect_handshake_done != GetTestState(ssl)->handshake_done) {
+ fprintf(stderr, "handshake was%s completed\n",
+ GetTestState(ssl)->handshake_done ? "" : " not");
+ return false;
+ }
+
+ if (expect_handshake_done && !config->is_server) {
+ bool expect_new_session =
+ !config->expect_no_session &&
+ (!SSL_session_reused(ssl) || config->expect_ticket_renewal);
+ if (expect_new_session != GetTestState(ssl)->got_new_session) {
+ fprintf(stderr,
+ "new session was%s established, but we expected the opposite\n",
+ GetTestState(ssl)->got_new_session ? "" : " not");
+ return false;
+ }
+ }
+
+ if (config->is_server && !GetTestState(ssl)->early_callback_called) {
+ fprintf(stderr, "early callback not called\n");
+ return false;
+ }
+
+ if (!config->expected_server_name.empty()) {
+ const char *server_name =
+ SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+ if (server_name != config->expected_server_name) {
+ fprintf(stderr, "servername mismatch (got %s; want %s)\n",
+ server_name, config->expected_server_name.c_str());
+ return false;
+ }
+ }
+
+ if (!config->expected_certificate_types.empty()) {
+ const uint8_t *certificate_types;
+ size_t certificate_types_len =
+ SSL_get0_certificate_types(ssl, &certificate_types);
+ if (certificate_types_len != config->expected_certificate_types.size() ||
+ memcmp(certificate_types,
+ config->expected_certificate_types.data(),
+ certificate_types_len) != 0) {
+ fprintf(stderr, "certificate types mismatch\n");
+ return false;
+ }
+ }
+
+ if (!config->expected_next_proto.empty()) {
+ const uint8_t *next_proto;
+ unsigned next_proto_len;
+ SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len);
+ if (next_proto_len != config->expected_next_proto.size() ||
+ memcmp(next_proto, config->expected_next_proto.data(),
+ next_proto_len) != 0) {
+ fprintf(stderr, "negotiated next proto mismatch\n");
+ return false;
+ }
+ }
+
+ if (!config->expected_alpn.empty()) {
+ const uint8_t *alpn_proto;
+ unsigned alpn_proto_len;
+ SSL_get0_alpn_selected(ssl, &alpn_proto, &alpn_proto_len);
+ if (alpn_proto_len != config->expected_alpn.size() ||
+ memcmp(alpn_proto, config->expected_alpn.data(),
+ alpn_proto_len) != 0) {
+ fprintf(stderr, "negotiated alpn proto mismatch\n");
+ return false;
+ }
+ }
+
+ if (!config->expected_channel_id.empty()) {
+ uint8_t channel_id[64];
+ if (!SSL_get_tls_channel_id(ssl, channel_id, sizeof(channel_id))) {
+ fprintf(stderr, "no channel id negotiated\n");
+ return false;
+ }
+ if (config->expected_channel_id.size() != 64 ||
+ memcmp(config->expected_channel_id.data(),
+ channel_id, 64) != 0) {
+ fprintf(stderr, "channel id mismatch\n");
+ return false;
+ }
+ }
+
+ if (config->expect_extended_master_secret) {
+ if (!ssl->session->extended_master_secret) {
+ fprintf(stderr, "No EMS for session when expected");
+ return false;
+ }
+ }
+
+ if (!config->expected_ocsp_response.empty()) {
+ const uint8_t *data;
+ size_t len;
+ SSL_get0_ocsp_response(ssl, &data, &len);
+ if (config->expected_ocsp_response.size() != len ||
+ memcmp(config->expected_ocsp_response.data(), data, len) != 0) {
+ fprintf(stderr, "OCSP response mismatch\n");
+ return false;
+ }
+ }
+
+ if (!config->expected_signed_cert_timestamps.empty()) {
+ const uint8_t *data;
+ size_t len;
+ SSL_get0_signed_cert_timestamp_list(ssl, &data, &len);
+ if (config->expected_signed_cert_timestamps.size() != len ||
+ memcmp(config->expected_signed_cert_timestamps.data(),
+ data, len) != 0) {
+ fprintf(stderr, "SCT list mismatch\n");
+ return false;
+ }
+ }
+
+ if (config->expect_verify_result) {
+ int expected_verify_result = config->verify_fail ?
+ X509_V_ERR_APPLICATION_VERIFICATION :
+ X509_V_OK;
+
+ if (SSL_get_verify_result(ssl) != expected_verify_result) {
+ fprintf(stderr, "Wrong certificate verification result\n");
+ return false;
+ }
+ }
+
+ if (!config->is_server) {
+ /* Clients should expect a peer certificate chain iff this was not a PSK
+ * cipher suite. */
+ if (config->psk.empty()) {
+ if (SSL_get_peer_cert_chain(ssl) == nullptr) {
+ fprintf(stderr, "Missing peer certificate chain!\n");
+ return false;
+ }
+ } else if (SSL_get_peer_cert_chain(ssl) != nullptr) {
+ fprintf(stderr, "Unexpected peer certificate chain!\n");
+ return false;
+ }
+ }
+ return true;
+}
+
// DoExchange runs a test SSL exchange against the peer. On success, it returns
// true and sets |*out_session| to the negotiated SSL session. If the test is a
// resumption attempt, |is_resume| is true and |session| is the session from the
@@ -562,7 +1023,10 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx,
}
if (config->require_any_client_certificate) {
SSL_set_verify(ssl.get(), SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
- SkipVerify);
+ NULL);
+ }
+ if (config->verify_peer) {
+ SSL_set_verify(ssl.get(), SSL_VERIFY_PEER, NULL);
}
if (config->false_start) {
SSL_set_mode(ssl.get(), SSL_MODE_ENABLE_FALSE_START);
@@ -588,8 +1052,8 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx,
if (config->tls_d5_bug) {
SSL_set_options(ssl.get(), SSL_OP_TLS_D5_BUG);
}
- if (config->allow_unsafe_legacy_renegotiation) {
- SSL_set_options(ssl.get(), SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
+ if (config->microsoft_big_sslv3_buffer) {
+ SSL_set_options(ssl.get(), SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);
}
if (config->no_legacy_server_connect) {
SSL_clear_options(ssl.get(), SSL_OP_LEGACY_SERVER_CONNECT);
@@ -637,7 +1101,6 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx,
!SSL_enable_signed_cert_timestamps(ssl.get())) {
return false;
}
- SSL_enable_fastradio_padding(ssl.get(), config->fastradio_padding);
if (config->min_version != 0) {
SSL_set_min_version(ssl.get(), (uint16_t)config->min_version);
}
@@ -651,14 +1114,13 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx,
if (config->install_ddos_callback) {
SSL_CTX_set_dos_protection_cb(ssl_ctx, DDoSCallback);
}
- if (!config->cipher.empty() &&
- !SSL_set_cipher_list(ssl.get(), config->cipher.c_str())) {
- return false;
- }
if (!config->reject_peer_renegotiations) {
/* Renegotiations are disabled by default. */
SSL_set_reject_peer_renegotiations(ssl.get(), 0);
}
+ if (!config->check_close_notify) {
+ SSL_set_quiet_shutdown(ssl.get(), 1);
+ }
int sock = Connect(config->port);
if (sock == -1) {
@@ -719,139 +1181,14 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx,
ret = SSL_connect(ssl.get());
}
} while (config->async && RetryAsync(ssl.get(), ret));
- if (ret != 1) {
- return false;
- }
-
- if (SSL_get_current_cipher(ssl.get()) == nullptr) {
- fprintf(stderr, "null cipher after handshake\n");
- return false;
- }
-
- if (is_resume &&
- (!!SSL_session_reused(ssl.get()) == config->expect_session_miss)) {
- fprintf(stderr, "session was%s reused\n",
- SSL_session_reused(ssl.get()) ? "" : " not");
- return false;
- }
-
- bool expect_handshake_done = is_resume || !config->false_start;
- if (expect_handshake_done != GetTestState(ssl.get())->handshake_done) {
- fprintf(stderr, "handshake was%s completed\n",
- GetTestState(ssl.get())->handshake_done ? "" : " not");
- return false;
- }
-
- if (config->is_server && !GetTestState(ssl.get())->early_callback_called) {
- fprintf(stderr, "early callback not called\n");
+ if (ret != 1 ||
+ !CheckHandshakeProperties(ssl.get(), is_resume)) {
return false;
}
- if (!config->expected_server_name.empty()) {
- const char *server_name =
- SSL_get_servername(ssl.get(), TLSEXT_NAMETYPE_host_name);
- if (server_name != config->expected_server_name) {
- fprintf(stderr, "servername mismatch (got %s; want %s)\n",
- server_name, config->expected_server_name.c_str());
- return false;
- }
- }
-
- if (!config->expected_certificate_types.empty()) {
- uint8_t *certificate_types;
- int num_certificate_types =
- SSL_get0_certificate_types(ssl.get(), &certificate_types);
- if (num_certificate_types !=
- (int)config->expected_certificate_types.size() ||
- memcmp(certificate_types,
- config->expected_certificate_types.data(),
- num_certificate_types) != 0) {
- fprintf(stderr, "certificate types mismatch\n");
- return false;
- }
- }
-
- if (!config->expected_next_proto.empty()) {
- const uint8_t *next_proto;
- unsigned next_proto_len;
- SSL_get0_next_proto_negotiated(ssl.get(), &next_proto, &next_proto_len);
- if (next_proto_len != config->expected_next_proto.size() ||
- memcmp(next_proto, config->expected_next_proto.data(),
- next_proto_len) != 0) {
- fprintf(stderr, "negotiated next proto mismatch\n");
- return false;
- }
- }
-
- if (!config->expected_alpn.empty()) {
- const uint8_t *alpn_proto;
- unsigned alpn_proto_len;
- SSL_get0_alpn_selected(ssl.get(), &alpn_proto, &alpn_proto_len);
- if (alpn_proto_len != config->expected_alpn.size() ||
- memcmp(alpn_proto, config->expected_alpn.data(),
- alpn_proto_len) != 0) {
- fprintf(stderr, "negotiated alpn proto mismatch\n");
- return false;
- }
- }
-
- if (!config->expected_channel_id.empty()) {
- uint8_t channel_id[64];
- if (!SSL_get_tls_channel_id(ssl.get(), channel_id, sizeof(channel_id))) {
- fprintf(stderr, "no channel id negotiated\n");
- return false;
- }
- if (config->expected_channel_id.size() != 64 ||
- memcmp(config->expected_channel_id.data(),
- channel_id, 64) != 0) {
- fprintf(stderr, "channel id mismatch\n");
- return false;
- }
- }
-
- if (config->expect_extended_master_secret) {
- if (!ssl->session->extended_master_secret) {
- fprintf(stderr, "No EMS for session when expected");
- return false;
- }
- }
-
- if (!config->expected_ocsp_response.empty()) {
- const uint8_t *data;
- size_t len;
- SSL_get0_ocsp_response(ssl.get(), &data, &len);
- if (config->expected_ocsp_response.size() != len ||
- memcmp(config->expected_ocsp_response.data(), data, len) != 0) {
- fprintf(stderr, "OCSP response mismatch\n");
- return false;
- }
- }
-
- if (!config->expected_signed_cert_timestamps.empty()) {
- const uint8_t *data;
- size_t len;
- SSL_get0_signed_cert_timestamp_list(ssl.get(), &data, &len);
- if (config->expected_signed_cert_timestamps.size() != len ||
- memcmp(config->expected_signed_cert_timestamps.data(),
- data, len) != 0) {
- fprintf(stderr, "SCT list mismatch\n");
- return false;
- }
- }
-
- if (!config->is_server) {
- /* Clients should expect a peer certificate chain iff this was not a PSK
- * cipher suite. */
- if (config->psk.empty()) {
- if (SSL_get_peer_cert_chain(ssl.get()) == nullptr) {
- fprintf(stderr, "Missing peer certificate chain!\n");
- return false;
- }
- } else if (SSL_get_peer_cert_chain(ssl.get()) != nullptr) {
- fprintf(stderr, "Unexpected peer certificate chain!\n");
- return false;
- }
- }
+ // Reset the state to assert later that the callback isn't called in
+ // renegotations.
+ GetTestState(ssl.get())->got_new_session = false;
}
if (config->export_keying_material > 0) {
@@ -897,18 +1234,19 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx,
}
// This mode writes a number of different record sizes in an attempt to
// trip up the CBC record splitting code.
- uint8_t buf[32769];
- memset(buf, 0x42, sizeof(buf));
+ static const size_t kBufLen = 32769;
+ std::unique_ptr<uint8_t[]> buf(new uint8_t[kBufLen]);
+ memset(buf.get(), 0x42, kBufLen);
static const size_t kRecordSizes[] = {
0, 1, 255, 256, 257, 16383, 16384, 16385, 32767, 32768, 32769};
for (size_t i = 0; i < sizeof(kRecordSizes) / sizeof(kRecordSizes[0]);
i++) {
const size_t len = kRecordSizes[i];
- if (len > sizeof(buf)) {
+ if (len > kBufLen) {
fprintf(stderr, "Bad kRecordSizes value.\n");
return false;
}
- if (WriteAll(ssl.get(), buf, len) < 0) {
+ if (WriteAll(ssl.get(), buf.get(), len) < 0) {
return false;
}
}
@@ -919,53 +1257,82 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx,
return false;
}
}
- for (;;) {
- uint8_t buf[512];
- int n = DoRead(ssl.get(), buf, sizeof(buf));
- int err = SSL_get_error(ssl.get(), n);
- if (err == SSL_ERROR_ZERO_RETURN ||
- (n == 0 && err == SSL_ERROR_SYSCALL)) {
- if (n != 0) {
- fprintf(stderr, "Invalid SSL_get_error output\n");
+ if (!config->shim_shuts_down) {
+ for (;;) {
+ static const size_t kBufLen = 16384;
+ std::unique_ptr<uint8_t[]> buf(new uint8_t[kBufLen]);
+
+ // Read only 512 bytes at a time in TLS to ensure records may be
+ // returned in multiple reads.
+ int n = DoRead(ssl.get(), buf.get(), config->is_dtls ? kBufLen : 512);
+ int err = SSL_get_error(ssl.get(), n);
+ if (err == SSL_ERROR_ZERO_RETURN ||
+ (n == 0 && err == SSL_ERROR_SYSCALL)) {
+ if (n != 0) {
+ fprintf(stderr, "Invalid SSL_get_error output\n");
+ return false;
+ }
+ // Stop on either clean or unclean shutdown.
+ break;
+ } else if (err != SSL_ERROR_NONE) {
+ if (n > 0) {
+ fprintf(stderr, "Invalid SSL_get_error output\n");
+ return false;
+ }
return false;
}
- // 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) {
+ // Successfully read data.
+ if (n <= 0) {
fprintf(stderr, "Invalid SSL_get_error output\n");
return false;
}
- return false;
- }
- // Successfully read data.
- if (n <= 0) {
- fprintf(stderr, "Invalid SSL_get_error output\n");
- return false;
- }
- // After a successful read, with or without False Start, the handshake
- // must be complete.
- if (!GetTestState(ssl.get())->handshake_done) {
- fprintf(stderr, "handshake was not completed after SSL_read\n");
- return false;
- }
+ // After a successful read, with or without False Start, the handshake
+ // must be complete.
+ if (!GetTestState(ssl.get())->handshake_done) {
+ fprintf(stderr, "handshake was not completed after SSL_read\n");
+ return false;
+ }
- for (int i = 0; i < n; i++) {
- buf[i] ^= 0xff;
- }
- if (WriteAll(ssl.get(), buf, n) < 0) {
- return false;
+ for (int i = 0; i < n; i++) {
+ buf[i] ^= 0xff;
+ }
+ if (WriteAll(ssl.get(), buf.get(), n) < 0) {
+ return false;
+ }
}
}
}
+ if (!config->is_server && !config->false_start &&
+ !config->implicit_handshake &&
+ GetTestState(ssl.get())->got_new_session) {
+ fprintf(stderr, "new session was established after the handshake\n");
+ return false;
+ }
+
if (out_session) {
out_session->reset(SSL_get1_session(ssl.get()));
}
- SSL_shutdown(ssl.get());
+ ret = DoShutdown(ssl.get());
+
+ if (config->shim_shuts_down && config->check_close_notify) {
+ // We initiate shutdown, so |SSL_shutdown| will return in two stages. First
+ // it returns zero when our close_notify is sent, then one when the peer's
+ // is received.
+ if (ret != 0) {
+ fprintf(stderr, "Unexpected SSL_shutdown result: %d != 0\n", ret);
+ return false;
+ }
+ ret = DoShutdown(ssl.get());
+ }
+
+ if (ret != 1) {
+ fprintf(stderr, "Unexpected SSL_shutdown result: %d != 1\n", ret);
+ return false;
+ }
+
return true;
}
diff --git a/src/ssl/test/runner/cipher_suites.go b/src/ssl/test/runner/cipher_suites.go
index 70c7262..ffc056d 100644
--- a/src/ssl/test/runner/cipher_suites.go
+++ b/src/ssl/test/runner/cipher_suites.go
@@ -102,7 +102,6 @@ var cipherSuites = []*cipherSuite{
{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, 32, 48, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, cipherAES, macSHA384, nil},
{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
- {TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 0, dheRSAKA, suiteTLS12, nil, nil, aeadCHACHA20POLY1305},
{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, dheRSAKA, suiteTLS12, nil, nil, aeadAESGCM},
{TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, dheRSAKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
{TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, dheRSAKA, suiteTLS12, cipherAES, macSHA256, nil},
@@ -120,12 +119,18 @@ var cipherSuites = []*cipherSuite{
{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
{TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, dheRSAKA, 0, cipher3DES, macSHA1, nil},
{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil},
- {TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdhePSKKA, suiteECDHE | suiteTLS12 | suitePSK, nil, nil, aeadAESGCM},
{TLS_PSK_WITH_RC4_128_SHA, 16, 20, 0, pskKA, suiteNoDTLS | suitePSK, cipherRC4, macSHA1, nil},
{TLS_PSK_WITH_AES_128_CBC_SHA, 16, 20, 16, pskKA, suitePSK, cipherAES, macSHA1, nil},
{TLS_PSK_WITH_AES_256_CBC_SHA, 32, 20, 16, pskKA, suitePSK, cipherAES, macSHA1, nil},
{TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdhePSKKA, suiteECDHE | suitePSK, cipherAES, macSHA1, nil},
{TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdhePSKKA, suiteECDHE | suitePSK, cipherAES, macSHA1, nil},
+ {TLS_RSA_WITH_NULL_SHA, 0, 20, 0, rsaKA, suiteNoDTLS, cipherNull, macSHA1, nil},
+}
+
+type nullCipher struct{}
+
+func cipherNull(key, iv []byte, isRead bool) interface{} {
+ return nullCipher{}
}
func cipherRC4(key, iv []byte, isRead bool) interface{} {
@@ -370,6 +375,7 @@ func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
// A list of the possible cipher suite ids. Taken from
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
const (
+ TLS_RSA_WITH_NULL_SHA uint16 = 0x0002
TLS_RSA_WITH_RC4_128_MD5 uint16 = 0x0004
TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a
@@ -406,13 +412,12 @@ const (
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030
TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA uint16 = 0xc035
TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA uint16 = 0xc036
+ renegotiationSCSV uint16 = 0x00ff
fallbackSCSV uint16 = 0x5600
)
// Additional cipher suite IDs, not IANA-assigned.
const (
- TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0xcafe
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcc13
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcc14
- TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcc15
)
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index edebba1..77be9f6 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -82,6 +82,7 @@ const (
extensionSignedCertificateTimestamp uint16 = 18
extensionExtendedMasterSecret uint16 = 23
extensionSessionTicket uint16 = 35
+ extensionCustom uint16 = 1234 // not IANA assigned
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
extensionRenegotiationInfo uint16 = 0xff01
extensionChannelID uint16 = 30032 // not IANA assigned
@@ -188,7 +189,9 @@ type ConnectionState struct {
VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates
ChannelID *ecdsa.PublicKey // the channel ID for this connection
SRTPProtectionProfile uint16 // the negotiated DTLS-SRTP protection profile
- TLSUnique []byte
+ TLSUnique []byte // the tls-unique channel binding
+ SCTList []byte // signed certificate timestamp list
+ ClientCertSignatureHash uint8 // TLS id of the hash used by the client to sign the handshake
}
// ClientAuthType declares the policy the server will follow for
@@ -214,6 +217,8 @@ type ClientSessionState struct {
handshakeHash []byte // Handshake hash for Channel ID purposes.
serverCertificates []*x509.Certificate // Certificate chain presented by the server
extendedMasterSecret bool // Whether an extended master secret was used to generate the session
+ sctList []byte
+ ocspResponse []byte
}
// ClientSessionCache is a cache of ClientSessionState objects that can be used
@@ -399,6 +404,10 @@ type ProtocolBugs struct {
// ServerKeyExchange message should be invalid.
InvalidSKXSignature bool
+ // InvalidCertVerifySignature specifies that the signature in a
+ // CertificateVerify message should be invalid.
+ InvalidCertVerifySignature bool
+
// InvalidSKXCurve causes the curve ID in the ServerKeyExchange message
// to be wrong.
InvalidSKXCurve bool
@@ -476,6 +485,10 @@ type ProtocolBugs struct {
// TLS_FALLBACK_SCSV in the ClientHello.
SendFallbackSCSV bool
+ // SendRenegotiationSCSV causes the client to include the renegotiation
+ // SCSV in the ClientHello.
+ SendRenegotiationSCSV bool
+
// MaxHandshakeRecordLength, if non-zero, is the maximum size of a
// handshake record. Handshake messages will be split into multiple
// records at the specified size, except that the client_version will
@@ -535,11 +548,14 @@ type ProtocolBugs struct {
// must specify in the server_name extension.
ExpectServerName string
- // SwapNPNAndALPN switches the relative order between NPN and
- // ALPN on the server. This is to test that server preference
- // of ALPN works regardless of their relative order.
+ // SwapNPNAndALPN switches the relative order between NPN and ALPN in
+ // both ClientHello and ServerHello.
SwapNPNAndALPN bool
+ // ALPNProtocol, if not nil, sets the ALPN protocol that a server will
+ // return.
+ ALPNProtocol *string
+
// AllowSessionVersionMismatch causes the server to resume sessions
// regardless of the version associated with the session.
AllowSessionVersionMismatch bool
@@ -572,11 +588,15 @@ type ProtocolBugs struct {
// didn't support the renegotiation info extension.
NoRenegotiationInfo bool
- // SequenceNumberIncrement, if non-zero, causes outgoing sequence
- // numbers in DTLS to increment by that value rather by 1. This is to
- // stress the replay bitmap window by simulating extreme packet loss and
- // retransmit at the record layer.
- SequenceNumberIncrement uint64
+ // RequireRenegotiationInfo, if true, causes the client to return an
+ // error if the server doesn't reply with the renegotiation extension.
+ RequireRenegotiationInfo bool
+
+ // SequenceNumberMapping, if non-nil, is the mapping function to apply
+ // to the sequence number of outgoing packets. For both TLS and DTLS,
+ // the two most-significant bytes in the resulting sequence number are
+ // ignored so that the DTLS epoch cannot be changed.
+ SequenceNumberMapping func(uint64) uint64
// RSAEphemeralKey, if true, causes the server to send a
// ServerKeyExchange message containing an ephemeral key (as in
@@ -609,10 +629,6 @@ type ProtocolBugs struct {
// across a renego.
RequireSameRenegoClientVersion bool
- // RequireFastradioPadding, if true, requires that ClientHello messages
- // be at least 1000 bytes long.
- RequireFastradioPadding bool
-
// ExpectInitialRecordVersion, if non-zero, is the expected
// version of the records before the version is determined.
ExpectInitialRecordVersion uint16
@@ -626,7 +642,11 @@ type ProtocolBugs struct {
// the server believes it has actually negotiated.
SendCipherSuite uint16
- // AppDataAfterChangeCipherSpec, if not null, causes application data to
+ // AppDataBeforeHandshake, if not nil, causes application data to be
+ // sent immediately before the first handshake message.
+ AppDataBeforeHandshake []byte
+
+ // AppDataAfterChangeCipherSpec, if not nil, causes application data to
// be sent immediately after ChangeCipherSpec.
AppDataAfterChangeCipherSpec []byte
@@ -668,17 +688,10 @@ type ProtocolBugs struct {
// 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
+ // SplitFragments, if non-zero, causes the handshake fragments in DTLS
+ // to be split across two records. The value of |SplitFragments| is the
+ // number of bytes in the first fragment.
+ SplitFragments int
// SendEmptyFragments, if true, causes handshakes to include empty
// fragments in DTLS.
@@ -705,10 +718,6 @@ type ProtocolBugs struct {
// preferences to be ignored.
IgnorePeerCurvePreferences bool
- // SendWarningAlerts, if non-zero, causes every record to be prefaced by
- // a warning alert.
- SendWarningAlerts alert
-
// BadFinished, if true, causes the Finished hash to be broken.
BadFinished bool
@@ -727,6 +736,43 @@ type ProtocolBugs struct {
// EnableAllCiphersInDTLS, if true, causes RC4 to be enabled in DTLS.
EnableAllCiphersInDTLS bool
+
+ // EmptyCertificateList, if true, causes the server to send an empty
+ // certificate list in the Certificate message.
+ EmptyCertificateList bool
+
+ // ExpectNewTicket, if true, causes the client to abort if it does not
+ // receive a new ticket.
+ ExpectNewTicket bool
+
+ // RequireClientHelloSize, if not zero, is the required length in bytes
+ // of the ClientHello /record/. This is checked by the server.
+ RequireClientHelloSize int
+
+ // CustomExtension, if not empty, contains the contents of an extension
+ // that will be added to client/server hellos.
+ CustomExtension string
+
+ // ExpectedCustomExtension, if not nil, contains the expected contents
+ // of a custom extension.
+ ExpectedCustomExtension *string
+
+ // NoCloseNotify, if true, causes the close_notify alert to be skipped
+ // on connection shutdown.
+ NoCloseNotify bool
+
+ // ExpectCloseNotify, if true, requires a close_notify from the peer on
+ // shutdown. Records from the peer received after close_notify is sent
+ // are not discard.
+ ExpectCloseNotify bool
+
+ // SendLargeRecords, if true, allows outgoing records to be sent
+ // arbitrarily large.
+ SendLargeRecords bool
+
+ // NegotiateALPNAndNPN, if true, causes the server to negotiate both
+ // ALPN and NPN in the same connetion.
+ NegotiateALPNAndNPN bool
}
func (c *Config) serverInit() {
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index adbc1c3..39bdfda 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -12,6 +12,7 @@ import (
"crypto/ecdsa"
"crypto/subtle"
"crypto/x509"
+ "encoding/binary"
"errors"
"fmt"
"io"
@@ -39,6 +40,7 @@ type Conn struct {
extendedMasterSecret bool // whether this session used an extended master secret
cipherSuite *cipherSuite
ocspResponse []byte // stapled OCSP response
+ sctList []byte // signed certificate timestamp list
peerCertificates []*x509.Certificate
// verifiedChains contains the certificate chains that we built, as
// opposed to the ones presented by the server.
@@ -48,6 +50,11 @@ type Conn struct {
// firstFinished contains the first Finished hash sent during the
// handshake. This is the "tls-unique" channel binding value.
firstFinished [12]byte
+ // clientCertSignatureHash contains the TLS hash id for the hash that
+ // was used by the client to sign the handshake with a client
+ // certificate. This is only set by a server and is zero if no client
+ // certificates were used.
+ clientCertSignatureHash uint8
clientRandom, serverRandom [32]byte
masterSecret [48]byte
@@ -87,6 +94,8 @@ func (c *Conn) init() {
c.out.isDTLS = c.isDTLS
c.in.config = c.config
c.out.config = c.config
+
+ c.out.updateOutSeq()
}
// Access to net.Conn methods.
@@ -134,6 +143,7 @@ type halfConn struct {
cipher interface{} // cipher algorithm
mac macFunction
seq [8]byte // 64-bit sequence number
+ outSeq [8]byte // Mapped sequence number
bfree *block // list of free blocks
nextCipher interface{} // next encryption state
@@ -189,10 +199,6 @@ func (hc *halfConn) incSeq(isOutgoing bool) {
if hc.isDTLS {
// Increment up to the epoch in DTLS.
limit = 2
-
- if isOutgoing && hc.config.Bugs.SequenceNumberIncrement != 0 {
- increment = hc.config.Bugs.SequenceNumberIncrement
- }
}
for i := 7; i >= limit; i-- {
increment += uint64(hc.seq[i])
@@ -206,6 +212,8 @@ func (hc *halfConn) incSeq(isOutgoing bool) {
if increment != 0 {
panic("TLS: sequence number wraparound")
}
+
+ hc.updateOutSeq()
}
// incNextSeq increments the starting sequence number for the next epoch.
@@ -241,6 +249,22 @@ func (hc *halfConn) incEpoch() {
hc.seq[i] = 0
}
}
+
+ hc.updateOutSeq()
+}
+
+func (hc *halfConn) updateOutSeq() {
+ if hc.config.Bugs.SequenceNumberMapping != nil {
+ seqU64 := binary.BigEndian.Uint64(hc.seq[:])
+ seqU64 = hc.config.Bugs.SequenceNumberMapping(seqU64)
+ binary.BigEndian.PutUint64(hc.outSeq[:], seqU64)
+
+ // The DTLS epoch cannot be changed.
+ copy(hc.outSeq[:2], hc.seq[:2])
+ return
+ }
+
+ copy(hc.outSeq[:], hc.seq[:])
}
func (hc *halfConn) recordHeaderLen() int {
@@ -397,6 +421,8 @@ func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert)
//
// However, our behavior matches OpenSSL, so we leak
// only as much as they do.
+ case nullCipher:
+ break
default:
panic("unknown cipher type")
}
@@ -460,7 +486,7 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
// mac
if hc.mac != nil {
- mac := hc.mac.MAC(hc.outDigestBuf, hc.seq[0:], b.data[:3], b.data[recordHeaderLen-2:recordHeaderLen], b.data[recordHeaderLen+explicitIVLen:])
+ mac := hc.mac.MAC(hc.outDigestBuf, hc.outSeq[0:], b.data[:3], b.data[recordHeaderLen-2:recordHeaderLen], b.data[recordHeaderLen+explicitIVLen:])
n := len(b.data)
b.resize(n + len(mac))
@@ -478,7 +504,7 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
case *tlsAead:
payloadLen := len(b.data) - recordHeaderLen - explicitIVLen
b.resize(len(b.data) + c.Overhead())
- nonce := hc.seq[:]
+ nonce := hc.outSeq[:]
if c.explicitNonce {
nonce = b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
}
@@ -486,7 +512,7 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
payload = payload[:payloadLen]
var additionalData [13]byte
- copy(additionalData[:], hc.seq[:])
+ copy(additionalData[:], hc.outSeq[:])
copy(additionalData[8:], b.data[:3])
additionalData[11] = byte(payloadLen >> 8)
additionalData[12] = byte(payloadLen)
@@ -502,6 +528,8 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
b.resize(recordHeaderLen + explicitIVLen + len(prefix) + len(finalBlock))
c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen:], prefix)
c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen+len(prefix):], finalBlock)
+ case nullCipher:
+ break
default:
panic("unknown cipher type")
}
@@ -630,10 +658,10 @@ func (c *Conn) doReadRecord(want recordType) (recordType, *block, error) {
if err := b.readFromUntil(c.conn, recordHeaderLen); err != nil {
// RFC suggests that EOF without an alertCloseNotify is
// an error, but popular web sites seem to do this,
- // so we can't make it an error.
- // if err == io.EOF {
- // err = io.ErrUnexpectedEOF
- // }
+ // so we can't make it an error, outside of tests.
+ if err == io.EOF && c.config.Bugs.ExpectCloseNotify {
+ err = io.ErrUnexpectedEOF
+ }
if e, ok := err.(net.Error); !ok || !e.Temporary() {
c.in.setErrorLocked(err)
}
@@ -722,6 +750,10 @@ func (c *Conn) readRecord(want recordType) error {
c.sendAlert(alertInternalError)
return c.in.setErrorLocked(errors.New("tls: application data record requested before handshake complete"))
}
+ case recordTypeAlert:
+ // Looking for a close_notify. Note: unlike a real
+ // implementation, this is not tolerant of additional records.
+ // See the documentation for ExpectCloseNotify.
}
Again:
@@ -784,7 +816,7 @@ Again:
// A client might need to process a HelloRequest from
// the server, thus receiving a handshake message when
// application data is expected is ok.
- if !c.isClient {
+ if !c.isClient || want != recordTypeApplicationData {
return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation))
}
}
@@ -799,13 +831,8 @@ Again:
// sendAlert sends a TLS alert message.
// c.out.Mutex <= L.
-func (c *Conn) sendAlertLocked(err alert) error {
- switch err {
- case alertNoRenegotiation, alertCloseNotify:
- c.tmp[0] = alertLevelWarning
- default:
- c.tmp[0] = alertLevelError
- }
+func (c *Conn) sendAlertLocked(level byte, err alert) error {
+ c.tmp[0] = level
c.tmp[1] = byte(err)
if c.config.Bugs.FragmentAlert {
c.writeRecord(recordTypeAlert, c.tmp[0:1])
@@ -813,8 +840,8 @@ func (c *Conn) sendAlertLocked(err alert) error {
} else {
c.writeRecord(recordTypeAlert, c.tmp[0:2])
}
- // closeNotify is a special case in that it isn't an error:
- if err != alertCloseNotify {
+ // Error alerts are fatal to the connection.
+ if level == alertLevelError {
return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
}
return nil
@@ -823,9 +850,17 @@ func (c *Conn) sendAlertLocked(err alert) error {
// sendAlert sends a TLS alert message.
// L < c.out.Mutex.
func (c *Conn) sendAlert(err alert) error {
+ level := byte(alertLevelError)
+ if err == alertNoRenegotiation || err == alertCloseNotify {
+ level = alertLevelWarning
+ }
+ return c.SendAlert(level, err)
+}
+
+func (c *Conn) SendAlert(level byte, err alert) error {
c.out.Lock()
defer c.out.Unlock()
- return c.sendAlertLocked(err)
+ return c.sendAlertLocked(level, err)
}
// writeV2Record writes a record for a V2ClientHello.
@@ -841,13 +876,6 @@ func (c *Conn) writeV2Record(data []byte) (n int, err error) {
// to the connection and updates the record layer state.
// c.out.Mutex <= L.
func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
- if typ != recordTypeAlert && c.config.Bugs.SendWarningAlerts != 0 {
- alert := make([]byte, 2)
- alert[0] = alertLevelWarning
- alert[1] = byte(c.config.Bugs.SendWarningAlerts)
- c.writeRecord(recordTypeAlert, alert)
- }
-
if c.isDTLS {
return c.dtlsWriteRecord(typ, data)
}
@@ -856,9 +884,9 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
b := c.out.newBlock()
first := true
isClientHello := typ == recordTypeHandshake && len(data) > 0 && data[0] == typeClientHello
- for len(data) > 0 {
+ for len(data) > 0 || first {
m := len(data)
- if m > maxPlaintext {
+ if m > maxPlaintext && !c.config.Bugs.SendLargeRecords {
m = maxPlaintext
}
if typ == recordTypeHandshake && c.config.Bugs.MaxHandshakeRecordLength > 0 && m > c.config.Bugs.MaxHandshakeRecordLength {
@@ -1038,6 +1066,9 @@ func (c *Conn) readHandshake() (interface{}, error) {
// sequence number expectations but otherwise ignores them.
func (c *Conn) skipPacket(packet []byte) error {
for len(packet) > 0 {
+ if len(packet) < 13 {
+ return errors.New("tls: bad packet")
+ }
// Dropped packets are completely ignored save to update
// expected sequence numbers for this and the next epoch. (We
// don't assert on the contents of the packets both for
@@ -1057,6 +1088,9 @@ func (c *Conn) skipPacket(packet []byte) error {
}
c.in.incNextSeq()
}
+ if len(packet) < 13+int(length) {
+ return errors.New("tls: bad packet")
+ }
packet = packet[13+length:]
}
return nil
@@ -1113,7 +1147,7 @@ func (c *Conn) Write(b []byte) (int, error) {
}
if c.config.Bugs.SendSpuriousAlert != 0 {
- c.sendAlertLocked(c.config.Bugs.SendSpuriousAlert)
+ c.sendAlertLocked(alertLevelError, c.config.Bugs.SendSpuriousAlert)
}
// SSL 3.0 and TLS 1.0 are susceptible to a chosen-plaintext
@@ -1240,10 +1274,22 @@ func (c *Conn) Close() error {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
- if c.handshakeComplete {
+ if c.handshakeComplete && !c.config.Bugs.NoCloseNotify {
alertErr = c.sendAlert(alertCloseNotify)
}
+ // Consume a close_notify from the peer if one hasn't been received
+ // already. This avoids the peer from failing |SSL_shutdown| due to a
+ // write failing.
+ if c.handshakeComplete && alertErr == nil && c.config.Bugs.ExpectCloseNotify {
+ for c.in.error() == nil {
+ c.readRecord(recordTypeAlert)
+ }
+ if c.in.error() != io.EOF {
+ alertErr = c.in.error()
+ }
+ }
+
if err := c.conn.Close(); err != nil {
return err
}
@@ -1273,6 +1319,9 @@ func (c *Conn) Handshake() error {
})
c.conn.Write([]byte{alertLevelError, byte(alertInternalError)})
}
+ if data := c.config.Bugs.AppDataBeforeHandshake; data != nil {
+ c.writeRecord(recordTypeApplicationData, data)
+ }
if c.isClient {
c.handshakeErr = c.clientHandshake()
} else {
@@ -1304,6 +1353,8 @@ func (c *Conn) ConnectionState() ConnectionState {
state.ChannelID = c.channelID
state.SRTPProtectionProfile = c.srtpProtectionProfile
state.TLSUnique = c.firstFinished[:]
+ state.SCTList = c.sctList
+ state.ClientCertSignatureHash = c.clientCertSignatureHash
}
return state
diff --git a/src/ssl/test/runner/dtls.go b/src/ssl/test/runner/dtls.go
index 50f7786..5c59dea 100644
--- a/src/ssl/test/runner/dtls.go
+++ b/src/ssl/test/runner/dtls.go
@@ -216,13 +216,10 @@ func (c *Conn) dtlsFlushHandshake() error {
// Pack handshake fragments into records.
var records [][]byte
for _, fragment := range fragments {
- if c.config.Bugs.SplitFragmentHeader {
- records = append(records, fragment[:2])
- records = append(records, fragment[2:])
- } else if c.config.Bugs.SplitFragmentBody {
- if len(fragment) > 12 {
- records = append(records, fragment[:13])
- records = append(records, fragment[13:])
+ if n := c.config.Bugs.SplitFragments; n > 0 {
+ if len(fragment) > n {
+ records = append(records, fragment[:n])
+ records = append(records, fragment[n:])
} else {
records = append(records, fragment)
}
@@ -301,13 +298,13 @@ func (c *Conn) dtlsSealRecord(typ recordType, data []byte) (b *block, err error)
b.data[1] = byte(vers >> 8)
b.data[2] = byte(vers)
// DTLS records include an explicit sequence number.
- copy(b.data[3:11], c.out.seq[0:])
+ copy(b.data[3:11], c.out.outSeq[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[:])
+ copy(explicitIV, c.out.outSeq[:])
} else {
if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil {
return
diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go
index a950313..a3ce686 100644
--- a/src/ssl/test/runner/handshake_client.go
+++ b/src/ssl/test/runner/handshake_client.go
@@ -45,7 +45,7 @@ func (c *Conn) clientHandshake() error {
nextProtosLength := 0
for _, proto := range c.config.NextProtos {
- if l := len(proto); l == 0 || l > 255 {
+ if l := len(proto); l > 255 {
return errors.New("tls: invalid NextProtos value")
} else {
nextProtosLength += 1 + l
@@ -61,6 +61,7 @@ func (c *Conn) clientHandshake() error {
compressionMethods: []uint8{compressionNone},
random: make([]byte, 32),
ocspStapling: true,
+ sctListSupported: true,
serverName: c.config.ServerName,
supportedCurves: c.config.curvePreferences(),
supportedPoints: []uint8{pointFormatUncompressed},
@@ -73,6 +74,7 @@ func (c *Conn) clientHandshake() error {
extendedMasterSecret: c.config.maxVersion() >= VersionTLS10,
srtpProtectionProfiles: c.config.SRTPProtectionProfiles,
srtpMasterKeyIdentifier: c.config.Bugs.SRTPMasterKeyIdentifer,
+ customExtension: c.config.Bugs.CustomExtension,
}
if c.config.Bugs.SendClientVersion != 0 {
@@ -123,6 +125,10 @@ NextCipherSuite:
}
}
+ if c.config.Bugs.SendRenegotiationSCSV {
+ hello.cipherSuites = append(hello.cipherSuites, renegotiationSCSV)
+ }
+
if c.config.Bugs.SendFallbackSCSV {
hello.cipherSuites = append(hello.cipherSuites, fallbackSCSV)
}
@@ -272,6 +278,10 @@ NextCipherSuite:
return fmt.Errorf("tls: server selected an unsupported cipher suite")
}
+ if c.config.Bugs.RequireRenegotiationInfo && serverHello.secureRenegotiation == nil {
+ return errors.New("tls: renegotiation extension missing")
+ }
+
if len(c.clientVerify) > 0 && !c.config.Bugs.NoRenegotiationInfo {
var expectedRenegInfo []byte
expectedRenegInfo = append(expectedRenegInfo, c.clientVerify...)
@@ -282,6 +292,12 @@ NextCipherSuite:
}
}
+ if expected := c.config.Bugs.ExpectedCustomExtension; expected != nil {
+ if serverHello.customExtension != *expected {
+ return fmt.Errorf("tls: bad custom extension contents %q", serverHello.customExtension)
+ }
+ }
+
hs := &clientHandshakeState{
c: c,
serverHello: serverHello,
@@ -356,6 +372,7 @@ NextCipherSuite:
copy(c.clientRandom[:], hs.hello.random)
copy(c.serverRandom[:], hs.serverHello.random)
copy(c.masterSecret[:], hs.masterSecret)
+
return nil
}
@@ -607,6 +624,9 @@ func (hs *clientHandshakeState) doFullHandshake() error {
c.sendAlert(alertInternalError)
return err
}
+ if c.config.Bugs.InvalidCertVerifySignature {
+ digest[0] ^= 0x80
+ }
switch key := c.config.Certificates[0].PrivateKey.(type) {
case *ecdsa.PrivateKey:
@@ -730,13 +750,28 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
return false, errors.New("tls: server resumed session on renegotiation")
}
+ if hs.serverHello.sctList != nil {
+ return false, errors.New("tls: server sent SCT extension on session resumption")
+ }
+
+ if hs.serverHello.ocspStapling {
+ return false, errors.New("tls: server sent OCSP extension on session resumption")
+ }
+
// Restore masterSecret and peerCerts from previous state
hs.masterSecret = hs.session.masterSecret
c.peerCertificates = hs.session.serverCertificates
c.extendedMasterSecret = hs.session.extendedMasterSecret
+ c.sctList = hs.session.sctList
+ c.ocspResponse = hs.session.ocspResponse
hs.finishedHash.discardHandshakeBuffer()
return true, nil
}
+
+ if hs.serverHello.sctList != nil {
+ c.sctList = hs.serverHello.sctList
+ }
+
return false, nil
}
@@ -783,9 +818,14 @@ func (hs *clientHandshakeState) readSessionTicket() error {
masterSecret: hs.masterSecret,
handshakeHash: hs.finishedHash.server.Sum(nil),
serverCertificates: c.peerCertificates,
+ sctList: c.sctList,
+ ocspResponse: c.ocspResponse,
}
if !hs.serverHello.ticketSupported {
+ if c.config.Bugs.ExpectNewTicket {
+ return errors.New("tls: expected new ticket")
+ }
if hs.session == nil && len(hs.serverHello.sessionId) > 0 {
session.sessionId = hs.serverHello.sessionId
hs.session = session
diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go
index ce214fd..da85e7a 100644
--- a/src/ssl/test/runner/handshake_messages.go
+++ b/src/ssl/test/runner/handshake_messages.go
@@ -32,6 +32,7 @@ type clientHelloMsg struct {
srtpProtectionProfiles []uint16
srtpMasterKeyIdentifier string
sctListSupported bool
+ customExtension string
}
func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -65,7 +66,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
m.extendedMasterSecret == m1.extendedMasterSecret &&
eqUint16s(m.srtpProtectionProfiles, m1.srtpProtectionProfiles) &&
m.srtpMasterKeyIdentifier == m1.srtpMasterKeyIdentifier &&
- m.sctListSupported == m1.sctListSupported
+ m.sctListSupported == m1.sctListSupported &&
+ m.customExtension == m1.customExtension
}
func (m *clientHelloMsg) marshal() []byte {
@@ -119,7 +121,7 @@ func (m *clientHelloMsg) marshal() []byte {
if len(m.alpnProtocols) > 0 {
extensionsLength += 2
for _, s := range m.alpnProtocols {
- if l := len(s); l == 0 || l > 255 {
+ if l := len(s); l > 255 {
panic("invalid ALPN protocol")
}
extensionsLength++
@@ -138,6 +140,10 @@ func (m *clientHelloMsg) marshal() []byte {
if m.sctListSupported {
numExtensions++
}
+ if l := len(m.customExtension); l > 0 {
+ extensionsLength += l
+ numExtensions++
+ }
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
@@ -376,6 +382,14 @@ func (m *clientHelloMsg) marshal() []byte {
z[1] = byte(extensionSignedCertificateTimestamp & 0xff)
z = z[4:]
}
+ if l := len(m.customExtension); l > 0 {
+ z[0] = byte(extensionCustom >> 8)
+ z[1] = byte(extensionCustom & 0xff)
+ z[2] = byte(l >> 8)
+ z[3] = byte(l & 0xff)
+ copy(z[4:], []byte(m.customExtension))
+ z = z[4+l:]
+ }
m.raw = x
@@ -443,6 +457,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.signatureAndHashes = nil
m.alpnProtocols = nil
m.extendedMasterSecret = false
+ m.customExtension = ""
if len(data) == 0 {
// ClientHello is optionally followed by extension data
@@ -604,6 +619,8 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
return false
}
m.sctListSupported = true
+ case extensionCustom:
+ m.customExtension = string(data[:length])
}
data = data[length:]
}
@@ -625,40 +642,15 @@ type serverHelloMsg struct {
ticketSupported bool
secureRenegotiation []byte
alpnProtocol string
+ alpnProtocolEmpty bool
duplicateExtension bool
channelIDRequested bool
extendedMasterSecret bool
srtpProtectionProfile uint16
srtpMasterKeyIdentifier string
sctList []byte
-}
-
-func (m *serverHelloMsg) equal(i interface{}) bool {
- m1, ok := i.(*serverHelloMsg)
- if !ok {
- return false
- }
-
- return bytes.Equal(m.raw, m1.raw) &&
- m.isDTLS == m1.isDTLS &&
- m.vers == m1.vers &&
- bytes.Equal(m.random, m1.random) &&
- bytes.Equal(m.sessionId, m1.sessionId) &&
- m.cipherSuite == m1.cipherSuite &&
- m.compressionMethod == m1.compressionMethod &&
- m.nextProtoNeg == m1.nextProtoNeg &&
- eqStrings(m.nextProtos, m1.nextProtos) &&
- m.ocspStapling == m1.ocspStapling &&
- m.ticketSupported == m1.ticketSupported &&
- bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
- (m.secureRenegotiation == nil) == (m1.secureRenegotiation == nil) &&
- m.alpnProtocol == m1.alpnProtocol &&
- m.duplicateExtension == m1.duplicateExtension &&
- m.channelIDRequested == m1.channelIDRequested &&
- m.extendedMasterSecret == m1.extendedMasterSecret &&
- m.srtpProtectionProfile == m1.srtpProtectionProfile &&
- m.srtpMasterKeyIdentifier == m1.srtpMasterKeyIdentifier &&
- bytes.Equal(m.sctList, m1.sctList)
+ customExtension string
+ npnLast bool
}
func (m *serverHelloMsg) marshal() []byte {
@@ -695,7 +687,7 @@ func (m *serverHelloMsg) marshal() []byte {
if m.channelIDRequested {
numExtensions++
}
- if alpnLen := len(m.alpnProtocol); alpnLen > 0 {
+ if alpnLen := len(m.alpnProtocol); alpnLen > 0 || m.alpnProtocolEmpty {
if alpnLen >= 256 {
panic("invalid ALPN protocol")
}
@@ -713,6 +705,10 @@ func (m *serverHelloMsg) marshal() []byte {
extensionsLength += len(m.sctList)
numExtensions++
}
+ if l := len(m.customExtension); l > 0 {
+ extensionsLength += l
+ numExtensions++
+ }
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
@@ -747,7 +743,7 @@ func (m *serverHelloMsg) marshal() []byte {
z[1] = 0xff
z = z[4:]
}
- if m.nextProtoNeg {
+ if m.nextProtoNeg && !m.npnLast {
z[0] = byte(extensionNextProtoNeg >> 8)
z[1] = byte(extensionNextProtoNeg & 0xff)
z[2] = byte(nextProtoLen >> 8)
@@ -784,7 +780,7 @@ func (m *serverHelloMsg) marshal() []byte {
copy(z, m.secureRenegotiation)
z = z[len(m.secureRenegotiation):]
}
- if alpnLen := len(m.alpnProtocol); alpnLen > 0 {
+ if alpnLen := len(m.alpnProtocol); alpnLen > 0 || m.alpnProtocolEmpty {
z[0] = byte(extensionALPN >> 8)
z[1] = byte(extensionALPN & 0xff)
l := 2 + 1 + alpnLen
@@ -838,6 +834,31 @@ func (m *serverHelloMsg) marshal() []byte {
copy(z[4:], m.sctList)
z = z[4+l:]
}
+ if l := len(m.customExtension); l > 0 {
+ z[0] = byte(extensionCustom >> 8)
+ z[1] = byte(extensionCustom & 0xff)
+ z[2] = byte(l >> 8)
+ z[3] = byte(l & 0xff)
+ copy(z[4:], []byte(m.customExtension))
+ z = z[4+l:]
+ }
+ if m.nextProtoNeg && m.npnLast {
+ z[0] = byte(extensionNextProtoNeg >> 8)
+ z[1] = byte(extensionNextProtoNeg & 0xff)
+ z[2] = byte(nextProtoLen >> 8)
+ z[3] = byte(nextProtoLen)
+ z = z[4:]
+
+ for _, v := range m.nextProtos {
+ l := len(v)
+ if l > 255 {
+ l = 255
+ }
+ z[0] = byte(l)
+ copy(z[1:], []byte(v[0:l]))
+ z = z[1+l:]
+ }
+ }
m.raw = x
@@ -869,7 +890,9 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
m.ocspStapling = false
m.ticketSupported = false
m.alpnProtocol = ""
+ m.alpnProtocolEmpty = false
m.extendedMasterSecret = false
+ m.customExtension = ""
if len(data) == 0 {
// ServerHello is optionally followed by extension data
@@ -940,6 +963,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
}
d = d[1:]
m.alpnProtocol = string(d)
+ m.alpnProtocolEmpty = len(d) == 0
case extensionChannelID:
if length > 0 {
return false
@@ -965,14 +989,9 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
}
m.srtpMasterKeyIdentifier = string(d[1:])
case extensionSignedCertificateTimestamp:
- if length < 2 {
- return false
- }
- l := int(data[0])<<8 | int(data[1])
- if l != len(data)-2 {
- return false
- }
- m.sctList = data[2:length]
+ m.sctList = data[:length]
+ case extensionCustom:
+ m.customExtension = string(data[:length])
}
data = data[length:]
}
@@ -985,16 +1004,6 @@ type certificateMsg struct {
certificates [][]byte
}
-func (m *certificateMsg) equal(i interface{}) bool {
- m1, ok := i.(*certificateMsg)
- if !ok {
- return false
- }
-
- return bytes.Equal(m.raw, m1.raw) &&
- eqByteSlices(m.certificates, m1.certificates)
-}
-
func (m *certificateMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
@@ -1072,16 +1081,6 @@ type serverKeyExchangeMsg struct {
key []byte
}
-func (m *serverKeyExchangeMsg) equal(i interface{}) bool {
- m1, ok := i.(*serverKeyExchangeMsg)
- if !ok {
- return false
- }
-
- return bytes.Equal(m.raw, m1.raw) &&
- bytes.Equal(m.key, m1.key)
-}
-
func (m *serverKeyExchangeMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -1113,17 +1112,6 @@ type certificateStatusMsg struct {
response []byte
}
-func (m *certificateStatusMsg) equal(i interface{}) bool {
- m1, ok := i.(*certificateStatusMsg)
- if !ok {
- return false
- }
-
- return bytes.Equal(m.raw, m1.raw) &&
- m.statusType == m1.statusType &&
- bytes.Equal(m.response, m1.response)
-}
-
func (m *certificateStatusMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -1175,11 +1163,6 @@ func (m *certificateStatusMsg) unmarshal(data []byte) bool {
type serverHelloDoneMsg struct{}
-func (m *serverHelloDoneMsg) equal(i interface{}) bool {
- _, ok := i.(*serverHelloDoneMsg)
- return ok
-}
-
func (m *serverHelloDoneMsg) marshal() []byte {
x := make([]byte, 4)
x[0] = typeServerHelloDone
@@ -1195,16 +1178,6 @@ type clientKeyExchangeMsg struct {
ciphertext []byte
}
-func (m *clientKeyExchangeMsg) equal(i interface{}) bool {
- m1, ok := i.(*clientKeyExchangeMsg)
- if !ok {
- return false
- }
-
- return bytes.Equal(m.raw, m1.raw) &&
- bytes.Equal(m.ciphertext, m1.ciphertext)
-}
-
func (m *clientKeyExchangeMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -1239,16 +1212,6 @@ type finishedMsg struct {
verifyData []byte
}
-func (m *finishedMsg) equal(i interface{}) bool {
- m1, ok := i.(*finishedMsg)
- if !ok {
- return false
- }
-
- return bytes.Equal(m.raw, m1.raw) &&
- bytes.Equal(m.verifyData, m1.verifyData)
-}
-
func (m *finishedMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
@@ -1276,16 +1239,6 @@ type nextProtoMsg struct {
proto string
}
-func (m *nextProtoMsg) equal(i interface{}) bool {
- m1, ok := i.(*nextProtoMsg)
- if !ok {
- return false
- }
-
- return bytes.Equal(m.raw, m1.raw) &&
- m.proto == m1.proto
-}
-
func (m *nextProtoMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -1353,18 +1306,6 @@ type certificateRequestMsg struct {
certificateAuthorities [][]byte
}
-func (m *certificateRequestMsg) equal(i interface{}) bool {
- m1, ok := i.(*certificateRequestMsg)
- if !ok {
- return false
- }
-
- return bytes.Equal(m.raw, m1.raw) &&
- bytes.Equal(m.certificateTypes, m1.certificateTypes) &&
- eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities) &&
- eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes)
-}
-
func (m *certificateRequestMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
@@ -1507,19 +1448,6 @@ type certificateVerifyMsg struct {
signature []byte
}
-func (m *certificateVerifyMsg) equal(i interface{}) bool {
- m1, ok := i.(*certificateVerifyMsg)
- if !ok {
- return false
- }
-
- return bytes.Equal(m.raw, m1.raw) &&
- m.hasSignatureAndHash == m1.hasSignatureAndHash &&
- m.signatureAndHash.hash == m1.signatureAndHash.hash &&
- m.signatureAndHash.signature == m1.signatureAndHash.signature &&
- bytes.Equal(m.signature, m1.signature)
-}
-
func (m *certificateVerifyMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
@@ -1589,16 +1517,6 @@ type newSessionTicketMsg struct {
ticket []byte
}
-func (m *newSessionTicketMsg) equal(i interface{}) bool {
- m1, ok := i.(*newSessionTicketMsg)
- if !ok {
- return false
- }
-
- return bytes.Equal(m.raw, m1.raw) &&
- bytes.Equal(m.ticket, m1.ticket)
-}
-
func (m *newSessionTicketMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
@@ -1651,19 +1569,6 @@ type v2ClientHelloMsg struct {
challenge []byte
}
-func (m *v2ClientHelloMsg) equal(i interface{}) bool {
- m1, ok := i.(*v2ClientHelloMsg)
- if !ok {
- return false
- }
-
- return bytes.Equal(m.raw, m1.raw) &&
- m.vers == m1.vers &&
- eqUint16s(m.cipherSuites, m1.cipherSuites) &&
- bytes.Equal(m.sessionId, m1.sessionId) &&
- bytes.Equal(m.challenge, m1.challenge)
-}
-
func (m *v2ClientHelloMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -1703,17 +1608,6 @@ type helloVerifyRequestMsg struct {
cookie []byte
}
-func (m *helloVerifyRequestMsg) equal(i interface{}) bool {
- m1, ok := i.(*helloVerifyRequestMsg)
- if !ok {
- return false
- }
-
- return bytes.Equal(m.raw, m1.raw) &&
- m.vers == m1.vers &&
- bytes.Equal(m.cookie, m1.cookie)
-}
-
func (m *helloVerifyRequestMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -1755,16 +1649,6 @@ type encryptedExtensionsMsg struct {
channelID []byte
}
-func (m *encryptedExtensionsMsg) equal(i interface{}) bool {
- m1, ok := i.(*encryptedExtensionsMsg)
- if !ok {
- return false
- }
-
- return bytes.Equal(m.raw, m1.raw) &&
- bytes.Equal(m.channelID, m1.channelID)
-}
-
func (m *encryptedExtensionsMsg) marshal() []byte {
if m.raw != nil {
return m.raw
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index 85cc0d2..068dff9 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -139,8 +139,8 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
c.sendAlert(alertUnexpectedMessage)
return false, unexpectedMessageError(hs.clientHello, msg)
}
- if config.Bugs.RequireFastradioPadding && len(hs.clientHello.raw) < 1000 {
- return false, errors.New("tls: ClientHello record size should be larger than 1000 bytes when padding enabled.")
+ if size := config.Bugs.RequireClientHelloSize; size != 0 && len(hs.clientHello.raw) != size {
+ return false, fmt.Errorf("tls: ClientHello record size is %d, but expected %d", len(hs.clientHello.raw), size)
}
if c.isDTLS && !config.Bugs.SkipHelloVerifyRequest {
@@ -210,8 +210,11 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
}
c.haveVers = true
- hs.hello = new(serverHelloMsg)
- hs.hello.isDTLS = c.isDTLS
+ hs.hello = &serverHelloMsg{
+ isDTLS: c.isDTLS,
+ customExtension: config.Bugs.CustomExtension,
+ npnLast: config.Bugs.SwapNPNAndALPN,
+ }
supportedCurve := false
preferredCurves := config.curvePreferences()
@@ -285,12 +288,18 @@ Curves:
}
if len(hs.clientHello.alpnProtocols) > 0 {
- if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback {
+ if proto := c.config.Bugs.ALPNProtocol; proto != nil {
+ hs.hello.alpnProtocol = *proto
+ hs.hello.alpnProtocolEmpty = len(*proto) == 0
+ c.clientProtocol = *proto
+ c.usedALPN = true
+ } else if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback {
hs.hello.alpnProtocol = selectedProto
c.clientProtocol = selectedProto
c.usedALPN = true
}
- } else {
+ }
+ if len(hs.clientHello.alpnProtocols) == 0 || c.config.Bugs.NegotiateALPNAndNPN {
// Although sending an empty NPN extension is reasonable, Firefox has
// had a bug around this. Best to send nothing at all if
// config.NextProtos is empty. See
@@ -335,6 +344,12 @@ Curves:
hs.hello.srtpProtectionProfile = c.config.Bugs.SendSRTPProtectionProfile
}
+ if expected := c.config.Bugs.ExpectedCustomExtension; expected != nil {
+ if hs.clientHello.customExtension != *expected {
+ return false, fmt.Errorf("tls: bad custom extension contents %q", hs.clientHello.customExtension)
+ }
+ }
+
_, hs.ecdsaOk = hs.cert.PrivateKey.(*ecdsa.PrivateKey)
// For test purposes, check that the peer never offers a session when
@@ -516,7 +531,9 @@ func (hs *serverHandshakeState) doFullHandshake() error {
if !isPSK {
certMsg := new(certificateMsg)
- certMsg.certificates = hs.cert.Certificate
+ if !config.Bugs.EmptyCertificateList {
+ certMsg.certificates = hs.cert.Certificate
+ }
if !config.Bugs.UnauthenticatedECDH {
certMsgBytes := certMsg.marshal()
if config.Bugs.WrongCertificateMessageType {
@@ -668,6 +685,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
if !isSupportedSignatureAndHash(signatureAndHash, config.signatureAndHashesForServer()) {
return errors.New("tls: unsupported hash function for client certificate")
}
+ c.clientCertSignatureHash = signatureAndHash.hash
} else {
// Before TLS 1.2 the signature algorithm was implicit
// from the key type, and only one hash per signature
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index 94c1d32..269a955 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -32,6 +32,10 @@ var (
mallocTestDebug = flag.Bool("malloc-test-debug", false, "If true, ask bssl_shim to abort rather than fail a malloc. This can be used with a specific value for --malloc-test to identity the malloc failing that is causing problems.")
jsonOutput = flag.String("json-output", "", "The file to output JSON results to.")
pipe = flag.Bool("pipe", false, "If true, print status output suitable for piping into another program.")
+ testToRun = flag.String("test", "", "The name of a test to run, or empty to run all tests")
+ numWorkers = flag.Int("num-workers", runtime.NumCPU(), "The number of workers to run in parallel.")
+ shimPath = flag.String("shim-path", "../../../build/ssl/test/bssl_shim", "The location of the shim binary.")
+ resourceDir = flag.String("resource-dir", ".", "The directory in which to find certificate and key files.")
)
const (
@@ -54,21 +58,21 @@ var testSCTList = []byte{5, 6, 7, 8}
func initCertificates() {
var err error
- rsaCertificate, err = LoadX509KeyPair(rsaCertificateFile, rsaKeyFile)
+ rsaCertificate, err = LoadX509KeyPair(path.Join(*resourceDir, rsaCertificateFile), path.Join(*resourceDir, rsaKeyFile))
if err != nil {
panic(err)
}
rsaCertificate.OCSPStaple = testOCSPResponse
rsaCertificate.SignedCertificateTimestampList = testSCTList
- ecdsaCertificate, err = LoadX509KeyPair(ecdsaCertificateFile, ecdsaKeyFile)
+ ecdsaCertificate, err = LoadX509KeyPair(path.Join(*resourceDir, ecdsaCertificateFile), path.Join(*resourceDir, ecdsaKeyFile))
if err != nil {
panic(err)
}
ecdsaCertificate.OCSPStaple = testOCSPResponse
ecdsaCertificate.SignedCertificateTimestampList = testSCTList
- channelIDPEMBlock, err := ioutil.ReadFile(channelIDKeyFile)
+ channelIDPEMBlock, err := ioutil.ReadFile(path.Join(*resourceDir, channelIDKeyFile))
if err != nil {
panic(err)
}
@@ -151,9 +155,21 @@ type testCase struct {
// expectedSRTPProtectionProfile is the DTLS-SRTP profile that
// should be negotiated. If zero, none should be negotiated.
expectedSRTPProtectionProfile uint16
+ // expectedOCSPResponse, if not nil, is the expected OCSP response to be received.
+ expectedOCSPResponse []uint8
+ // expectedSCTList, if not nil, is the expected SCT list to be received.
+ expectedSCTList []uint8
+ // expectedClientCertSignatureHash, if not zero, is the TLS id of the
+ // hash function that the client should have used when signing the
+ // handshake with a client certificate.
+ expectedClientCertSignatureHash uint8
// messageLen is the length, in bytes, of the test message that will be
// sent.
messageLen int
+ // messageCount is the number of test messages that will be sent.
+ messageCount int
+ // digestPrefs is the list of digest preferences from the client.
+ digestPrefs string
// certFile is the path to the certificate to use for the server.
certFile string
// keyFile is the path to the private key to use for the server.
@@ -174,12 +190,19 @@ type testCase struct {
// newSessionsOnResume, if true, will cause resumeConfig to
// use a different session resumption context.
newSessionsOnResume bool
+ // noSessionCache, if true, will cause the server to run without a
+ // session cache.
+ noSessionCache bool
// sendPrefix sends a prefix on the socket before actually performing a
// handshake.
sendPrefix string
// shimWritesFirst controls whether the shim sends an initial "hello"
// message before doing a roundtrip with the runner.
shimWritesFirst bool
+ // shimShutsDown, if true, runs a test where the shim shuts down the
+ // connection immediately after the handshake rather than echoing
+ // messages from the runner.
+ shimShutsDown bool
// renegotiate indicates the the connection should be renegotiated
// during the exchange.
renegotiate bool
@@ -204,941 +227,20 @@ type testCase struct {
// testTLSUnique, if true, causes the shim to send the tls-unique value
// which will be compared against the expected value.
testTLSUnique bool
+ // sendEmptyRecords is the number of consecutive empty records to send
+ // before and after the test message.
+ sendEmptyRecords int
+ // sendWarningAlerts is the number of consecutive warning alerts to send
+ // before and after the test message.
+ sendWarningAlerts int
+ // expectMessageDropped, if true, means the test message is expected to
+ // be dropped by the client rather than echoed back.
+ expectMessageDropped bool
}
-var testCases = []testCase{
- {
- name: "BadRSASignature",
- config: Config{
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- Bugs: ProtocolBugs{
- InvalidSKXSignature: true,
- },
- },
- shouldFail: true,
- expectedError: ":BAD_SIGNATURE:",
- },
- {
- name: "BadECDSASignature",
- config: Config{
- CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
- Bugs: ProtocolBugs{
- InvalidSKXSignature: true,
- },
- Certificates: []Certificate{getECDSACertificate()},
- },
- shouldFail: true,
- expectedError: ":BAD_SIGNATURE:",
- },
- {
- name: "BadECDSACurve",
- config: Config{
- CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
- Bugs: ProtocolBugs{
- InvalidSKXCurve: true,
- },
- Certificates: []Certificate{getECDSACertificate()},
- },
- shouldFail: true,
- expectedError: ":WRONG_CURVE:",
- },
- {
- testType: serverTest,
- name: "BadRSAVersion",
- config: Config{
- CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
- Bugs: ProtocolBugs{
- RsaClientKeyExchangeVersion: VersionTLS11,
- },
- },
- shouldFail: true,
- expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
- },
- {
- name: "NoFallbackSCSV",
- config: Config{
- Bugs: ProtocolBugs{
- FailIfNotFallbackSCSV: true,
- },
- },
- shouldFail: true,
- expectedLocalError: "no fallback SCSV found",
- },
- {
- name: "SendFallbackSCSV",
- config: Config{
- Bugs: ProtocolBugs{
- FailIfNotFallbackSCSV: true,
- },
- },
- flags: []string{"-fallback-scsv"},
- },
- {
- name: "ClientCertificateTypes",
- config: Config{
- ClientAuth: RequestClientCert,
- ClientCertificateTypes: []byte{
- CertTypeDSSSign,
- CertTypeRSASign,
- CertTypeECDSASign,
- },
- },
- flags: []string{
- "-expect-certificate-types",
- base64.StdEncoding.EncodeToString([]byte{
- CertTypeDSSSign,
- CertTypeRSASign,
- CertTypeECDSASign,
- }),
- },
- },
- {
- name: "NoClientCertificate",
- config: Config{
- ClientAuth: RequireAnyClientCert,
- },
- shouldFail: true,
- expectedLocalError: "client didn't provide a certificate",
- },
- {
- name: "UnauthenticatedECDH",
- config: Config{
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- Bugs: ProtocolBugs{
- UnauthenticatedECDH: true,
- },
- },
- shouldFail: true,
- expectedError: ":UNEXPECTED_MESSAGE:",
- },
- {
- name: "SkipCertificateStatus",
- config: Config{
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- Bugs: ProtocolBugs{
- SkipCertificateStatus: true,
- },
- },
- flags: []string{
- "-enable-ocsp-stapling",
- },
- },
- {
- name: "SkipServerKeyExchange",
- config: Config{
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- Bugs: ProtocolBugs{
- SkipServerKeyExchange: true,
- },
- },
- shouldFail: true,
- expectedError: ":UNEXPECTED_MESSAGE:",
- },
- {
- name: "SkipChangeCipherSpec-Client",
- config: Config{
- Bugs: ProtocolBugs{
- SkipChangeCipherSpec: true,
- },
- },
- shouldFail: true,
- expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
- },
- {
- testType: serverTest,
- name: "SkipChangeCipherSpec-Server",
- config: Config{
- Bugs: ProtocolBugs{
- SkipChangeCipherSpec: true,
- },
- },
- shouldFail: true,
- expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
- },
- {
- testType: serverTest,
- name: "SkipChangeCipherSpec-Server-NPN",
- config: Config{
- NextProtos: []string{"bar"},
- Bugs: ProtocolBugs{
- SkipChangeCipherSpec: true,
- },
- },
- flags: []string{
- "-advertise-npn", "\x03foo\x03bar\x03baz",
- },
- shouldFail: true,
- expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
- },
- {
- name: "FragmentAcrossChangeCipherSpec-Client",
- config: Config{
- Bugs: ProtocolBugs{
- FragmentAcrossChangeCipherSpec: true,
- },
- },
- shouldFail: true,
- expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
- },
- {
- testType: serverTest,
- name: "FragmentAcrossChangeCipherSpec-Server",
- config: Config{
- Bugs: ProtocolBugs{
- FragmentAcrossChangeCipherSpec: true,
- },
- },
- shouldFail: true,
- expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
- },
- {
- testType: serverTest,
- name: "FragmentAcrossChangeCipherSpec-Server-NPN",
- config: Config{
- NextProtos: []string{"bar"},
- Bugs: ProtocolBugs{
- FragmentAcrossChangeCipherSpec: true,
- },
- },
- flags: []string{
- "-advertise-npn", "\x03foo\x03bar\x03baz",
- },
- shouldFail: true,
- expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
- },
- {
- testType: serverTest,
- name: "Alert",
- config: Config{
- Bugs: ProtocolBugs{
- SendSpuriousAlert: alertRecordOverflow,
- },
- },
- shouldFail: true,
- expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:",
- },
- {
- protocol: dtls,
- testType: serverTest,
- name: "Alert-DTLS",
- config: Config{
- Bugs: ProtocolBugs{
- SendSpuriousAlert: alertRecordOverflow,
- },
- },
- shouldFail: true,
- expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:",
- },
- {
- testType: serverTest,
- name: "FragmentAlert",
- config: Config{
- Bugs: ProtocolBugs{
- FragmentAlert: true,
- SendSpuriousAlert: alertRecordOverflow,
- },
- },
- shouldFail: true,
- expectedError: ":BAD_ALERT:",
- },
- {
- protocol: dtls,
- testType: serverTest,
- name: "FragmentAlert-DTLS",
- config: Config{
- Bugs: ProtocolBugs{
- FragmentAlert: true,
- SendSpuriousAlert: alertRecordOverflow,
- },
- },
- shouldFail: true,
- expectedError: ":BAD_ALERT:",
- },
- {
- testType: serverTest,
- name: "EarlyChangeCipherSpec-server-1",
- config: Config{
- Bugs: ProtocolBugs{
- EarlyChangeCipherSpec: 1,
- },
- },
- shouldFail: true,
- expectedError: ":CCS_RECEIVED_EARLY:",
- },
- {
- testType: serverTest,
- name: "EarlyChangeCipherSpec-server-2",
- config: Config{
- Bugs: ProtocolBugs{
- EarlyChangeCipherSpec: 2,
- },
- },
- shouldFail: true,
- expectedError: ":CCS_RECEIVED_EARLY:",
- },
- {
- name: "SkipNewSessionTicket",
- config: Config{
- Bugs: ProtocolBugs{
- SkipNewSessionTicket: true,
- },
- },
- shouldFail: true,
- expectedError: ":CCS_RECEIVED_EARLY:",
- },
- {
- testType: serverTest,
- name: "FallbackSCSV",
- config: Config{
- MaxVersion: VersionTLS11,
- Bugs: ProtocolBugs{
- SendFallbackSCSV: true,
- },
- },
- shouldFail: true,
- expectedError: ":INAPPROPRIATE_FALLBACK:",
- },
- {
- testType: serverTest,
- name: "FallbackSCSV-VersionMatch",
- config: Config{
- Bugs: ProtocolBugs{
- SendFallbackSCSV: true,
- },
- },
- },
- {
- testType: serverTest,
- name: "FragmentedClientVersion",
- config: Config{
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: 1,
- FragmentClientVersion: true,
- },
- },
- expectedVersion: VersionTLS12,
- },
- {
- testType: serverTest,
- name: "MinorVersionTolerance",
- config: Config{
- Bugs: ProtocolBugs{
- SendClientVersion: 0x03ff,
- },
- },
- expectedVersion: VersionTLS12,
- },
- {
- testType: serverTest,
- name: "MajorVersionTolerance",
- config: Config{
- Bugs: ProtocolBugs{
- SendClientVersion: 0x0400,
- },
- },
- expectedVersion: VersionTLS12,
- },
- {
- testType: serverTest,
- name: "VersionTooLow",
- config: Config{
- Bugs: ProtocolBugs{
- SendClientVersion: 0x0200,
- },
- },
- shouldFail: true,
- expectedError: ":UNSUPPORTED_PROTOCOL:",
- },
- {
- testType: serverTest,
- name: "HttpGET",
- sendPrefix: "GET / HTTP/1.0\n",
- shouldFail: true,
- expectedError: ":HTTP_REQUEST:",
- },
- {
- testType: serverTest,
- name: "HttpPOST",
- sendPrefix: "POST / HTTP/1.0\n",
- shouldFail: true,
- expectedError: ":HTTP_REQUEST:",
- },
- {
- testType: serverTest,
- name: "HttpHEAD",
- sendPrefix: "HEAD / HTTP/1.0\n",
- shouldFail: true,
- expectedError: ":HTTP_REQUEST:",
- },
- {
- testType: serverTest,
- name: "HttpPUT",
- sendPrefix: "PUT / HTTP/1.0\n",
- shouldFail: true,
- expectedError: ":HTTP_REQUEST:",
- },
- {
- testType: serverTest,
- name: "HttpCONNECT",
- sendPrefix: "CONNECT www.google.com:443 HTTP/1.0\n",
- shouldFail: true,
- expectedError: ":HTTPS_PROXY_REQUEST:",
- },
- {
- testType: serverTest,
- name: "Garbage",
- sendPrefix: "blah",
- shouldFail: true,
- expectedError: ":UNKNOWN_PROTOCOL:",
- },
- {
- name: "SkipCipherVersionCheck",
- config: Config{
- CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
- MaxVersion: VersionTLS11,
- Bugs: ProtocolBugs{
- SkipCipherVersionCheck: true,
- },
- },
- shouldFail: true,
- expectedError: ":WRONG_CIPHER_RETURNED:",
- },
- {
- name: "RSAEphemeralKey",
- config: Config{
- CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
- Bugs: ProtocolBugs{
- RSAEphemeralKey: true,
- },
- },
- shouldFail: true,
- expectedError: ":UNEXPECTED_MESSAGE:",
- },
- {
- name: "DisableEverything",
- flags: []string{"-no-tls12", "-no-tls11", "-no-tls1", "-no-ssl3"},
- shouldFail: true,
- expectedError: ":WRONG_SSL_VERSION:",
- },
- {
- protocol: dtls,
- name: "DisableEverything-DTLS",
- flags: []string{"-no-tls12", "-no-tls1"},
- shouldFail: true,
- expectedError: ":WRONG_SSL_VERSION:",
- },
- {
- name: "NoSharedCipher",
- config: Config{
- CipherSuites: []uint16{},
- },
- shouldFail: true,
- expectedError: ":HANDSHAKE_FAILURE_ON_CLIENT_HELLO:",
- },
- {
- protocol: dtls,
- testType: serverTest,
- name: "MTU",
- config: Config{
- Bugs: ProtocolBugs{
- MaxPacketLength: 256,
- },
- },
- flags: []string{"-mtu", "256"},
- },
- {
- protocol: dtls,
- testType: serverTest,
- name: "MTUExceeded",
- config: Config{
- Bugs: ProtocolBugs{
- MaxPacketLength: 255,
- },
- },
- flags: []string{"-mtu", "256"},
- shouldFail: true,
- expectedLocalError: "dtls: exceeded maximum packet length",
- },
- {
- name: "CertMismatchRSA",
- config: Config{
- CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
- Certificates: []Certificate{getECDSACertificate()},
- Bugs: ProtocolBugs{
- SendCipherSuite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
- },
- },
- shouldFail: true,
- expectedError: ":WRONG_CERTIFICATE_TYPE:",
- },
- {
- name: "CertMismatchECDSA",
- config: Config{
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- Certificates: []Certificate{getRSACertificate()},
- Bugs: ProtocolBugs{
- SendCipherSuite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
- },
- },
- shouldFail: true,
- expectedError: ":WRONG_CERTIFICATE_TYPE:",
- },
- {
- name: "TLSFatalBadPackets",
- damageFirstWrite: true,
- shouldFail: true,
- expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
- },
- {
- protocol: dtls,
- name: "DTLSIgnoreBadPackets",
- damageFirstWrite: true,
- },
- {
- protocol: dtls,
- name: "DTLSIgnoreBadPackets-Async",
- damageFirstWrite: true,
- flags: []string{"-async"},
- },
- {
- name: "AppDataAfterChangeCipherSpec",
- config: Config{
- Bugs: ProtocolBugs{
- AppDataAfterChangeCipherSpec: []byte("TEST MESSAGE"),
- },
- },
- shouldFail: true,
- expectedError: ":DATA_BETWEEN_CCS_AND_FINISHED:",
- },
- {
- protocol: dtls,
- name: "AppDataAfterChangeCipherSpec-DTLS",
- config: Config{
- Bugs: ProtocolBugs{
- AppDataAfterChangeCipherSpec: []byte("TEST MESSAGE"),
- },
- },
- // BoringSSL's DTLS implementation will drop the out-of-order
- // application data.
- },
- {
- name: "AlertAfterChangeCipherSpec",
- config: Config{
- Bugs: ProtocolBugs{
- AlertAfterChangeCipherSpec: alertRecordOverflow,
- },
- },
- shouldFail: true,
- expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:",
- },
- {
- protocol: dtls,
- name: "AlertAfterChangeCipherSpec-DTLS",
- config: Config{
- Bugs: ProtocolBugs{
- AlertAfterChangeCipherSpec: alertRecordOverflow,
- },
- },
- shouldFail: true,
- expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:",
- },
- {
- protocol: dtls,
- name: "ReorderHandshakeFragments-Small-DTLS",
- config: Config{
- Bugs: ProtocolBugs{
- ReorderHandshakeFragments: true,
- // Small enough that every handshake message is
- // fragmented.
- MaxHandshakeRecordLength: 2,
- },
- },
- },
- {
- protocol: dtls,
- name: "ReorderHandshakeFragments-Large-DTLS",
- config: Config{
- Bugs: ProtocolBugs{
- ReorderHandshakeFragments: true,
- // Large enough that no handshake message is
- // fragmented.
- MaxHandshakeRecordLength: 2048,
- },
- },
- },
- {
- protocol: dtls,
- name: "MixCompleteMessageWithFragments-DTLS",
- config: Config{
- Bugs: ProtocolBugs{
- ReorderHandshakeFragments: true,
- MixCompleteMessageWithFragments: true,
- MaxHandshakeRecordLength: 2,
- },
- },
- },
- {
- name: "SendInvalidRecordType",
- config: Config{
- Bugs: ProtocolBugs{
- SendInvalidRecordType: true,
- },
- },
- shouldFail: true,
- expectedError: ":UNEXPECTED_RECORD:",
- },
- {
- protocol: dtls,
- name: "SendInvalidRecordType-DTLS",
- config: Config{
- Bugs: ProtocolBugs{
- SendInvalidRecordType: true,
- },
- },
- shouldFail: true,
- expectedError: ":UNEXPECTED_RECORD:",
- },
- {
- name: "FalseStart-SkipServerSecondLeg",
- config: Config{
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- NextProtos: []string{"foo"},
- Bugs: ProtocolBugs{
- SkipNewSessionTicket: true,
- SkipChangeCipherSpec: true,
- SkipFinished: true,
- ExpectFalseStart: true,
- },
- },
- flags: []string{
- "-false-start",
- "-handshake-never-done",
- "-advertise-alpn", "\x03foo",
- },
- shimWritesFirst: true,
- shouldFail: true,
- expectedError: ":UNEXPECTED_RECORD:",
- },
- {
- name: "FalseStart-SkipServerSecondLeg-Implicit",
- config: Config{
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- NextProtos: []string{"foo"},
- Bugs: ProtocolBugs{
- SkipNewSessionTicket: true,
- SkipChangeCipherSpec: true,
- SkipFinished: true,
- },
- },
- flags: []string{
- "-implicit-handshake",
- "-false-start",
- "-handshake-never-done",
- "-advertise-alpn", "\x03foo",
- },
- shouldFail: true,
- expectedError: ":UNEXPECTED_RECORD:",
- },
- {
- testType: serverTest,
- name: "FailEarlyCallback",
- flags: []string{"-fail-early-callback"},
- shouldFail: true,
- expectedError: ":CONNECTION_REJECTED:",
- expectedLocalError: "remote error: access denied",
- },
- {
- name: "WrongMessageType",
- config: Config{
- Bugs: ProtocolBugs{
- WrongCertificateMessageType: true,
- },
- },
- shouldFail: true,
- expectedError: ":UNEXPECTED_MESSAGE:",
- expectedLocalError: "remote error: unexpected message",
- },
- {
- protocol: dtls,
- name: "WrongMessageType-DTLS",
- config: Config{
- Bugs: ProtocolBugs{
- WrongCertificateMessageType: true,
- },
- },
- shouldFail: true,
- expectedError: ":UNEXPECTED_MESSAGE:",
- expectedLocalError: "remote error: unexpected message",
- },
- {
- protocol: dtls,
- name: "FragmentMessageTypeMismatch-DTLS",
- config: Config{
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: 2,
- FragmentMessageTypeMismatch: true,
- },
- },
- shouldFail: true,
- expectedError: ":FRAGMENT_MISMATCH:",
- },
- {
- protocol: dtls,
- name: "FragmentMessageLengthMismatch-DTLS",
- config: Config{
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: 2,
- FragmentMessageLengthMismatch: true,
- },
- },
- shouldFail: true,
- expectedError: ":FRAGMENT_MISMATCH:",
- },
- {
- protocol: dtls,
- name: "SplitFragmentHeader-DTLS",
- config: Config{
- Bugs: ProtocolBugs{
- SplitFragmentHeader: true,
- },
- },
- shouldFail: true,
- expectedError: ":UNEXPECTED_MESSAGE:",
- },
- {
- protocol: dtls,
- name: "SplitFragmentBody-DTLS",
- config: Config{
- Bugs: ProtocolBugs{
- SplitFragmentBody: true,
- },
- },
- shouldFail: true,
- expectedError: ":UNEXPECTED_MESSAGE:",
- },
- {
- protocol: dtls,
- name: "SendEmptyFragments-DTLS",
- config: Config{
- Bugs: ProtocolBugs{
- SendEmptyFragments: true,
- },
- },
- },
- {
- name: "UnsupportedCipherSuite",
- config: Config{
- CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
- Bugs: ProtocolBugs{
- IgnorePeerCipherPreferences: true,
- },
- },
- flags: []string{"-cipher", "DEFAULT:!RC4"},
- shouldFail: true,
- expectedError: ":WRONG_CIPHER_RETURNED:",
- },
- {
- name: "UnsupportedCurve",
- config: Config{
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- // BoringSSL implements P-224 but doesn't enable it by
- // default.
- CurvePreferences: []CurveID{CurveP224},
- Bugs: ProtocolBugs{
- IgnorePeerCurvePreferences: true,
- },
- },
- shouldFail: true,
- expectedError: ":WRONG_CURVE:",
- },
- {
- name: "SendWarningAlerts",
- config: Config{
- Bugs: ProtocolBugs{
- SendWarningAlerts: alertAccessDenied,
- },
- },
- },
- {
- protocol: dtls,
- name: "SendWarningAlerts-DTLS",
- config: Config{
- Bugs: ProtocolBugs{
- SendWarningAlerts: alertAccessDenied,
- },
- },
- },
- {
- name: "BadFinished",
- config: Config{
- Bugs: ProtocolBugs{
- BadFinished: true,
- },
- },
- shouldFail: true,
- expectedError: ":DIGEST_CHECK_FAILED:",
- },
- {
- name: "FalseStart-BadFinished",
- config: Config{
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- NextProtos: []string{"foo"},
- Bugs: ProtocolBugs{
- BadFinished: true,
- ExpectFalseStart: true,
- },
- },
- flags: []string{
- "-false-start",
- "-handshake-never-done",
- "-advertise-alpn", "\x03foo",
- },
- shimWritesFirst: true,
- shouldFail: true,
- expectedError: ":DIGEST_CHECK_FAILED:",
- },
- {
- name: "NoFalseStart-NoALPN",
- config: Config{
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- Bugs: ProtocolBugs{
- ExpectFalseStart: true,
- AlertBeforeFalseStartTest: alertAccessDenied,
- },
- },
- flags: []string{
- "-false-start",
- },
- shimWritesFirst: true,
- shouldFail: true,
- expectedError: ":TLSV1_ALERT_ACCESS_DENIED:",
- expectedLocalError: "tls: peer did not false start: EOF",
- },
- {
- name: "NoFalseStart-NoAEAD",
- config: Config{
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
- NextProtos: []string{"foo"},
- Bugs: ProtocolBugs{
- ExpectFalseStart: true,
- AlertBeforeFalseStartTest: alertAccessDenied,
- },
- },
- flags: []string{
- "-false-start",
- "-advertise-alpn", "\x03foo",
- },
- shimWritesFirst: true,
- shouldFail: true,
- expectedError: ":TLSV1_ALERT_ACCESS_DENIED:",
- expectedLocalError: "tls: peer did not false start: EOF",
- },
- {
- name: "NoFalseStart-RSA",
- config: Config{
- CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
- NextProtos: []string{"foo"},
- Bugs: ProtocolBugs{
- ExpectFalseStart: true,
- AlertBeforeFalseStartTest: alertAccessDenied,
- },
- },
- flags: []string{
- "-false-start",
- "-advertise-alpn", "\x03foo",
- },
- shimWritesFirst: true,
- shouldFail: true,
- expectedError: ":TLSV1_ALERT_ACCESS_DENIED:",
- expectedLocalError: "tls: peer did not false start: EOF",
- },
- {
- name: "NoFalseStart-DHE_RSA",
- config: Config{
- CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
- NextProtos: []string{"foo"},
- Bugs: ProtocolBugs{
- ExpectFalseStart: true,
- AlertBeforeFalseStartTest: alertAccessDenied,
- },
- },
- flags: []string{
- "-false-start",
- "-advertise-alpn", "\x03foo",
- },
- shimWritesFirst: true,
- shouldFail: true,
- expectedError: ":TLSV1_ALERT_ACCESS_DENIED:",
- expectedLocalError: "tls: peer did not false start: EOF",
- },
- {
- testType: serverTest,
- name: "NoSupportedCurves",
- config: Config{
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- Bugs: ProtocolBugs{
- NoSupportedCurves: true,
- },
- },
- },
- {
- testType: serverTest,
- name: "NoCommonCurves",
- config: Config{
- CipherSuites: []uint16{
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
- TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
- },
- CurvePreferences: []CurveID{CurveP224},
- },
- expectedCipher: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
- },
- {
- protocol: dtls,
- name: "SendSplitAlert-Sync",
- config: Config{
- Bugs: ProtocolBugs{
- SendSplitAlert: true,
- },
- },
- },
- {
- protocol: dtls,
- name: "SendSplitAlert-Async",
- config: Config{
- Bugs: ProtocolBugs{
- SendSplitAlert: true,
- },
- },
- flags: []string{"-async"},
- },
- {
- protocol: dtls,
- name: "PackDTLSHandshake",
- config: Config{
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: 2,
- PackHandshakeFragments: 20,
- PackHandshakeRecords: 200,
- },
- },
- },
- {
- testType: serverTest,
- protocol: dtls,
- name: "NoRC4-DTLS",
- config: Config{
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA},
- Bugs: ProtocolBugs{
- EnableAllCiphersInDTLS: true,
- },
- },
- shouldFail: true,
- expectedError: ":NO_SHARED_CIPHER:",
- },
-}
+var testCases []testCase
-func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error {
+func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool) error {
var connDebug *recordingConn
var connDamage *damageAdaptor
if *flagDebug {
@@ -1183,6 +285,7 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i
tlsConn = Client(conn, config)
}
}
+ defer tlsConn.Close()
if err := tlsConn.Handshake(); err != nil {
return err
@@ -1235,6 +338,18 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i
return fmt.Errorf("SRTP profile mismatch: got %d, wanted %d", p, test.expectedSRTPProtectionProfile)
}
+ if test.expectedOCSPResponse != nil && !bytes.Equal(test.expectedOCSPResponse, tlsConn.OCSPResponse()) {
+ return fmt.Errorf("OCSP Response mismatch")
+ }
+
+ if test.expectedSCTList != nil && !bytes.Equal(test.expectedSCTList, connState.SCTList) {
+ return fmt.Errorf("SCT list mismatch")
+ }
+
+ if expected := test.expectedClientCertSignatureHash; expected != 0 && expected != connState.ClientCertSignatureHash {
+ return fmt.Errorf("expected client to sign handshake with hash %d, but got %d", expected, connState.ClientCertSignatureHash)
+ }
+
if test.exportKeyingMaterial > 0 {
actual := make([]byte, test.exportKeyingMaterial)
if _, err := io.ReadFull(tlsConn, actual); err != nil {
@@ -1271,6 +386,14 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i
}
}
+ for i := 0; i < test.sendEmptyRecords; i++ {
+ tlsConn.Write(nil)
+ }
+
+ for i := 0; i < test.sendWarningAlerts; i++ {
+ tlsConn.SendAlert(alertLevelWarning, alertUnexpectedMessage)
+ }
+
if test.renegotiate {
if test.renegotiateCiphers != nil {
config.CipherSuites = test.renegotiateCiphers
@@ -1288,6 +411,7 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i
connDamage.setDamage(false)
}
+ messageLen := test.messageLen
if messageLen < 0 {
if test.protocol == dtls {
return fmt.Errorf("messageLen < 0 not supported for DTLS tests")
@@ -1296,37 +420,57 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i
_, err := io.Copy(ioutil.Discard, tlsConn)
return err
}
-
if messageLen == 0 {
messageLen = 32
}
- testMessage := make([]byte, messageLen)
- for i := range testMessage {
- testMessage[i] = 0x42
+
+ messageCount := test.messageCount
+ if messageCount == 0 {
+ messageCount = 1
}
- tlsConn.Write(testMessage)
- buf := make([]byte, len(testMessage))
- if test.protocol == dtls {
- bufTmp := make([]byte, len(buf)+1)
- n, err := tlsConn.Read(bufTmp)
- if err != nil {
- return err
+ for j := 0; j < messageCount; j++ {
+ testMessage := make([]byte, messageLen)
+ for i := range testMessage {
+ testMessage[i] = 0x42 ^ byte(j)
}
- if n != len(buf) {
- return fmt.Errorf("bad reply; length mismatch (%d vs %d)", n, len(buf))
+ tlsConn.Write(testMessage)
+
+ for i := 0; i < test.sendEmptyRecords; i++ {
+ tlsConn.Write(nil)
}
- copy(buf, bufTmp)
- } else {
- _, err := io.ReadFull(tlsConn, buf)
- if err != nil {
- return err
+
+ for i := 0; i < test.sendWarningAlerts; i++ {
+ tlsConn.SendAlert(alertLevelWarning, alertUnexpectedMessage)
+ }
+
+ if test.shimShutsDown || test.expectMessageDropped {
+ // The shim will not respond.
+ continue
+ }
+
+ buf := make([]byte, len(testMessage))
+ if test.protocol == dtls {
+ bufTmp := make([]byte, len(buf)+1)
+ n, err := tlsConn.Read(bufTmp)
+ if err != nil {
+ return err
+ }
+ if n != len(buf) {
+ return fmt.Errorf("bad reply; length mismatch (%d vs %d)", n, len(buf))
+ }
+ copy(buf, bufTmp)
+ } else {
+ _, err := io.ReadFull(tlsConn, buf)
+ if err != nil {
+ return err
+ }
}
- }
- for i, v := range buf {
- if v != testMessage[i]^0xff {
- return fmt.Errorf("bad reply contents at byte %d", i)
+ for i, v := range buf {
+ if v != testMessage[i]^0xff {
+ return fmt.Errorf("bad reply contents at byte %d", i)
+ }
}
}
@@ -1382,7 +526,7 @@ func acceptOrWait(listener net.Listener, waitChan chan error) (net.Conn, error)
}
}
-func runTest(test *testCase, buildDir string, mallocNumToFail int64) error {
+func runTest(test *testCase, shimPath string, mallocNumToFail int64) error {
if !test.shouldFail && (len(test.expectedError) > 0 || len(test.expectedLocalError) > 0) {
panic("Error expected without shouldFail in " + test.name)
}
@@ -1391,6 +535,10 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error {
panic("expectResumeRejected without resumeSession in " + test.name)
}
+ if test.testType != clientTest && test.expectedClientCertSignatureHash != 0 {
+ panic("expectedClientCertSignatureHash non-zero with serverTest in " + test.name)
+ }
+
listener, err := net.ListenTCP("tcp4", &net.TCPAddr{IP: net.IP{127, 0, 0, 1}})
if err != nil {
panic(err)
@@ -1401,26 +549,30 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error {
}
}()
- shim_path := path.Join(buildDir, "ssl/test/bssl_shim")
flags := []string{"-port", strconv.Itoa(listener.Addr().(*net.TCPAddr).Port)}
if test.testType == serverTest {
flags = append(flags, "-server")
flags = append(flags, "-key-file")
if test.keyFile == "" {
- flags = append(flags, rsaKeyFile)
+ flags = append(flags, path.Join(*resourceDir, rsaKeyFile))
} else {
- flags = append(flags, test.keyFile)
+ flags = append(flags, path.Join(*resourceDir, test.keyFile))
}
flags = append(flags, "-cert-file")
if test.certFile == "" {
- flags = append(flags, rsaCertificateFile)
+ flags = append(flags, path.Join(*resourceDir, rsaCertificateFile))
} else {
- flags = append(flags, test.certFile)
+ flags = append(flags, path.Join(*resourceDir, test.certFile))
}
}
+ if test.digestPrefs != "" {
+ flags = append(flags, "-digest-prefs")
+ flags = append(flags, test.digestPrefs)
+ }
+
if test.protocol == dtls {
flags = append(flags, "-dtls")
}
@@ -1433,6 +585,10 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error {
flags = append(flags, "-shim-writes-first")
}
+ if test.shimShutsDown {
+ flags = append(flags, "-shim-shuts-down")
+ }
+
if test.exportKeyingMaterial > 0 {
flags = append(flags, "-export-keying-material", strconv.Itoa(test.exportKeyingMaterial))
flags = append(flags, "-export-label", test.exportLabel)
@@ -1453,11 +609,11 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error {
var shim *exec.Cmd
if *useValgrind {
- shim = valgrindOf(false, shim_path, flags...)
+ shim = valgrindOf(false, shimPath, flags...)
} else if *useGDB {
- shim = gdbOf(shim_path, flags...)
+ shim = gdbOf(shimPath, flags...)
} else {
- shim = exec.Command(shim_path, flags...)
+ shim = exec.Command(shimPath, flags...)
}
shim.Stdin = os.Stdin
var stdoutBuf, stderrBuf bytes.Buffer
@@ -1467,7 +623,7 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error {
shim.Env = os.Environ()
shim.Env = append(shim.Env, "MALLOC_NUMBER_TO_FAIL="+strconv.FormatInt(mallocNumToFail, 10))
if *mallocTestDebug {
- shim.Env = append(shim.Env, "MALLOC_ABORT_ON_FAIL=1")
+ shim.Env = append(shim.Env, "MALLOC_BREAK_ON_FAIL=1")
}
shim.Env = append(shim.Env, "_MALLOC_CHECK=1")
}
@@ -1479,8 +635,10 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error {
go func() { waitChan <- shim.Wait() }()
config := test.config
- config.ClientSessionCache = NewLRUClientSessionCache(1)
- config.ServerSessionCache = NewLRUServerSessionCache(1)
+ if !test.noSessionCache {
+ config.ClientSessionCache = NewLRUClientSessionCache(1)
+ config.ServerSessionCache = NewLRUServerSessionCache(1)
+ }
if test.testType == clientTest {
if len(config.Certificates) == 0 {
config.Certificates = []Certificate{getRSACertificate()}
@@ -1495,7 +653,7 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error {
conn, err := acceptOrWait(listener, waitChan)
if err == nil {
- err = doExchange(test, &config, conn, test.messageLen, false /* not a resumption */)
+ err = doExchange(test, &config, conn, false /* not a resumption */)
conn.Close()
}
@@ -1509,7 +667,12 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error {
if len(resumeConfig.Certificates) == 0 {
resumeConfig.Certificates = []Certificate{getRSACertificate()}
}
- if !test.newSessionsOnResume {
+ if test.newSessionsOnResume {
+ if !test.noSessionCache {
+ resumeConfig.ClientSessionCache = NewLRUClientSessionCache(1)
+ resumeConfig.ServerSessionCache = NewLRUServerSessionCache(1)
+ }
+ } else {
resumeConfig.SessionTicketKey = config.SessionTicketKey
resumeConfig.ClientSessionCache = config.ClientSessionCache
resumeConfig.ServerSessionCache = config.ServerSessionCache
@@ -1520,7 +683,7 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error {
var connResume net.Conn
connResume, err = acceptOrWait(listener, waitChan)
if err == nil {
- err = doExchange(test, &resumeConfig, connResume, test.messageLen, true /* resumption */)
+ err = doExchange(test, &resumeConfig, connResume, true /* resumption */)
connResume.Close()
}
}
@@ -1606,7 +769,6 @@ var testCipherSuites = []struct {
{"DHE-RSA-AES256-GCM", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
{"DHE-RSA-AES256-SHA", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
{"DHE-RSA-AES256-SHA256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
- {"DHE-RSA-CHACHA20-POLY1305", TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
{"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
{"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
{"ECDHE-ECDSA-AES128-SHA256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
@@ -1630,6 +792,7 @@ var testCipherSuites = []struct {
{"PSK-RC4-SHA", TLS_PSK_WITH_RC4_128_SHA},
{"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
{"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
+ {"NULL-SHA", TLS_RSA_WITH_NULL_SHA},
}
func hasComponent(suiteName, component string) bool {
@@ -1644,7 +807,7 @@ func isTLS12Only(suiteName string) bool {
}
func isDTLSCipher(suiteName string) bool {
- return !hasComponent(suiteName, "RC4")
+ return !hasComponent(suiteName, "RC4") && !hasComponent(suiteName, "NULL")
}
func bigFromHex(hex string) *big.Int {
@@ -1655,6 +818,1152 @@ func bigFromHex(hex string) *big.Int {
return ret
}
+func addBasicTests() {
+ basicTests := []testCase{
+ {
+ name: "BadRSASignature",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ InvalidSKXSignature: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_SIGNATURE:",
+ },
+ {
+ name: "BadECDSASignature",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ InvalidSKXSignature: true,
+ },
+ Certificates: []Certificate{getECDSACertificate()},
+ },
+ shouldFail: true,
+ expectedError: ":BAD_SIGNATURE:",
+ },
+ {
+ testType: serverTest,
+ name: "BadRSASignature-ClientAuth",
+ config: Config{
+ Bugs: ProtocolBugs{
+ InvalidCertVerifySignature: true,
+ },
+ Certificates: []Certificate{getRSACertificate()},
+ },
+ shouldFail: true,
+ expectedError: ":BAD_SIGNATURE:",
+ flags: []string{"-require-any-client-certificate"},
+ },
+ {
+ testType: serverTest,
+ name: "BadECDSASignature-ClientAuth",
+ config: Config{
+ Bugs: ProtocolBugs{
+ InvalidCertVerifySignature: true,
+ },
+ Certificates: []Certificate{getECDSACertificate()},
+ },
+ shouldFail: true,
+ expectedError: ":BAD_SIGNATURE:",
+ flags: []string{"-require-any-client-certificate"},
+ },
+ {
+ name: "BadECDSACurve",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ InvalidSKXCurve: true,
+ },
+ Certificates: []Certificate{getECDSACertificate()},
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CURVE:",
+ },
+ {
+ testType: serverTest,
+ name: "BadRSAVersion",
+ config: Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ Bugs: ProtocolBugs{
+ RsaClientKeyExchangeVersion: VersionTLS11,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
+ },
+ {
+ name: "NoFallbackSCSV",
+ config: Config{
+ Bugs: ProtocolBugs{
+ FailIfNotFallbackSCSV: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "no fallback SCSV found",
+ },
+ {
+ name: "SendFallbackSCSV",
+ config: Config{
+ Bugs: ProtocolBugs{
+ FailIfNotFallbackSCSV: true,
+ },
+ },
+ flags: []string{"-fallback-scsv"},
+ },
+ {
+ name: "ClientCertificateTypes",
+ config: Config{
+ ClientAuth: RequestClientCert,
+ ClientCertificateTypes: []byte{
+ CertTypeDSSSign,
+ CertTypeRSASign,
+ CertTypeECDSASign,
+ },
+ },
+ flags: []string{
+ "-expect-certificate-types",
+ base64.StdEncoding.EncodeToString([]byte{
+ CertTypeDSSSign,
+ CertTypeRSASign,
+ CertTypeECDSASign,
+ }),
+ },
+ },
+ {
+ name: "NoClientCertificate",
+ config: Config{
+ ClientAuth: RequireAnyClientCert,
+ },
+ shouldFail: true,
+ expectedLocalError: "client didn't provide a certificate",
+ },
+ {
+ name: "UnauthenticatedECDH",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ UnauthenticatedECDH: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ },
+ {
+ name: "SkipCertificateStatus",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ SkipCertificateStatus: true,
+ },
+ },
+ flags: []string{
+ "-enable-ocsp-stapling",
+ },
+ },
+ {
+ name: "SkipServerKeyExchange",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ SkipServerKeyExchange: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ },
+ {
+ name: "SkipChangeCipherSpec-Client",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SkipChangeCipherSpec: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
+ },
+ {
+ testType: serverTest,
+ name: "SkipChangeCipherSpec-Server",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SkipChangeCipherSpec: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
+ },
+ {
+ testType: serverTest,
+ name: "SkipChangeCipherSpec-Server-NPN",
+ config: Config{
+ NextProtos: []string{"bar"},
+ Bugs: ProtocolBugs{
+ SkipChangeCipherSpec: true,
+ },
+ },
+ flags: []string{
+ "-advertise-npn", "\x03foo\x03bar\x03baz",
+ },
+ shouldFail: true,
+ expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
+ },
+ {
+ name: "FragmentAcrossChangeCipherSpec-Client",
+ config: Config{
+ Bugs: ProtocolBugs{
+ FragmentAcrossChangeCipherSpec: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
+ },
+ {
+ testType: serverTest,
+ name: "FragmentAcrossChangeCipherSpec-Server",
+ config: Config{
+ Bugs: ProtocolBugs{
+ FragmentAcrossChangeCipherSpec: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
+ },
+ {
+ testType: serverTest,
+ name: "FragmentAcrossChangeCipherSpec-Server-NPN",
+ config: Config{
+ NextProtos: []string{"bar"},
+ Bugs: ProtocolBugs{
+ FragmentAcrossChangeCipherSpec: true,
+ },
+ },
+ flags: []string{
+ "-advertise-npn", "\x03foo\x03bar\x03baz",
+ },
+ shouldFail: true,
+ expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
+ },
+ {
+ testType: serverTest,
+ name: "Alert",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSpuriousAlert: alertRecordOverflow,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:",
+ },
+ {
+ protocol: dtls,
+ testType: serverTest,
+ name: "Alert-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSpuriousAlert: alertRecordOverflow,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:",
+ },
+ {
+ testType: serverTest,
+ name: "FragmentAlert",
+ config: Config{
+ Bugs: ProtocolBugs{
+ FragmentAlert: true,
+ SendSpuriousAlert: alertRecordOverflow,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_ALERT:",
+ },
+ {
+ protocol: dtls,
+ testType: serverTest,
+ name: "FragmentAlert-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ FragmentAlert: true,
+ SendSpuriousAlert: alertRecordOverflow,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_ALERT:",
+ },
+ {
+ testType: serverTest,
+ name: "EarlyChangeCipherSpec-server-1",
+ config: Config{
+ Bugs: ProtocolBugs{
+ EarlyChangeCipherSpec: 1,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":CCS_RECEIVED_EARLY:",
+ },
+ {
+ testType: serverTest,
+ name: "EarlyChangeCipherSpec-server-2",
+ config: Config{
+ Bugs: ProtocolBugs{
+ EarlyChangeCipherSpec: 2,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":CCS_RECEIVED_EARLY:",
+ },
+ {
+ name: "SkipNewSessionTicket",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SkipNewSessionTicket: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":CCS_RECEIVED_EARLY:",
+ },
+ {
+ testType: serverTest,
+ name: "FallbackSCSV",
+ config: Config{
+ MaxVersion: VersionTLS11,
+ Bugs: ProtocolBugs{
+ SendFallbackSCSV: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":INAPPROPRIATE_FALLBACK:",
+ },
+ {
+ testType: serverTest,
+ name: "FallbackSCSV-VersionMatch",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendFallbackSCSV: true,
+ },
+ },
+ },
+ {
+ testType: serverTest,
+ name: "FragmentedClientVersion",
+ config: Config{
+ Bugs: ProtocolBugs{
+ MaxHandshakeRecordLength: 1,
+ FragmentClientVersion: true,
+ },
+ },
+ expectedVersion: VersionTLS12,
+ },
+ {
+ testType: serverTest,
+ name: "MinorVersionTolerance",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendClientVersion: 0x03ff,
+ },
+ },
+ expectedVersion: VersionTLS12,
+ },
+ {
+ testType: serverTest,
+ name: "MajorVersionTolerance",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendClientVersion: 0x0400,
+ },
+ },
+ expectedVersion: VersionTLS12,
+ },
+ {
+ testType: serverTest,
+ name: "VersionTooLow",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendClientVersion: 0x0200,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNSUPPORTED_PROTOCOL:",
+ },
+ {
+ testType: serverTest,
+ name: "HttpGET",
+ sendPrefix: "GET / HTTP/1.0\n",
+ shouldFail: true,
+ expectedError: ":HTTP_REQUEST:",
+ },
+ {
+ testType: serverTest,
+ name: "HttpPOST",
+ sendPrefix: "POST / HTTP/1.0\n",
+ shouldFail: true,
+ expectedError: ":HTTP_REQUEST:",
+ },
+ {
+ testType: serverTest,
+ name: "HttpHEAD",
+ sendPrefix: "HEAD / HTTP/1.0\n",
+ shouldFail: true,
+ expectedError: ":HTTP_REQUEST:",
+ },
+ {
+ testType: serverTest,
+ name: "HttpPUT",
+ sendPrefix: "PUT / HTTP/1.0\n",
+ shouldFail: true,
+ expectedError: ":HTTP_REQUEST:",
+ },
+ {
+ testType: serverTest,
+ name: "HttpCONNECT",
+ sendPrefix: "CONNECT www.google.com:443 HTTP/1.0\n",
+ shouldFail: true,
+ expectedError: ":HTTPS_PROXY_REQUEST:",
+ },
+ {
+ testType: serverTest,
+ name: "Garbage",
+ sendPrefix: "blah",
+ shouldFail: true,
+ expectedError: ":WRONG_VERSION_NUMBER:",
+ },
+ {
+ name: "SkipCipherVersionCheck",
+ config: Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ MaxVersion: VersionTLS11,
+ Bugs: ProtocolBugs{
+ SkipCipherVersionCheck: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CIPHER_RETURNED:",
+ },
+ {
+ name: "RSAEphemeralKey",
+ config: Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
+ Bugs: ProtocolBugs{
+ RSAEphemeralKey: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ },
+ {
+ name: "DisableEverything",
+ flags: []string{"-no-tls12", "-no-tls11", "-no-tls1", "-no-ssl3"},
+ shouldFail: true,
+ expectedError: ":WRONG_SSL_VERSION:",
+ },
+ {
+ protocol: dtls,
+ name: "DisableEverything-DTLS",
+ flags: []string{"-no-tls12", "-no-tls1"},
+ shouldFail: true,
+ expectedError: ":WRONG_SSL_VERSION:",
+ },
+ {
+ name: "NoSharedCipher",
+ config: Config{
+ CipherSuites: []uint16{},
+ },
+ shouldFail: true,
+ expectedError: ":HANDSHAKE_FAILURE_ON_CLIENT_HELLO:",
+ },
+ {
+ protocol: dtls,
+ testType: serverTest,
+ name: "MTU",
+ config: Config{
+ Bugs: ProtocolBugs{
+ MaxPacketLength: 256,
+ },
+ },
+ flags: []string{"-mtu", "256"},
+ },
+ {
+ protocol: dtls,
+ testType: serverTest,
+ name: "MTUExceeded",
+ config: Config{
+ Bugs: ProtocolBugs{
+ MaxPacketLength: 255,
+ },
+ },
+ flags: []string{"-mtu", "256"},
+ shouldFail: true,
+ expectedLocalError: "dtls: exceeded maximum packet length",
+ },
+ {
+ name: "CertMismatchRSA",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ Certificates: []Certificate{getECDSACertificate()},
+ Bugs: ProtocolBugs{
+ SendCipherSuite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CERTIFICATE_TYPE:",
+ },
+ {
+ name: "CertMismatchECDSA",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Certificates: []Certificate{getRSACertificate()},
+ Bugs: ProtocolBugs{
+ SendCipherSuite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CERTIFICATE_TYPE:",
+ },
+ {
+ name: "EmptyCertificateList",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ EmptyCertificateList: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DECODE_ERROR:",
+ },
+ {
+ name: "TLSFatalBadPackets",
+ damageFirstWrite: true,
+ shouldFail: true,
+ expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
+ },
+ {
+ protocol: dtls,
+ name: "DTLSIgnoreBadPackets",
+ damageFirstWrite: true,
+ },
+ {
+ protocol: dtls,
+ name: "DTLSIgnoreBadPackets-Async",
+ damageFirstWrite: true,
+ flags: []string{"-async"},
+ },
+ {
+ name: "AppDataBeforeHandshake",
+ config: Config{
+ Bugs: ProtocolBugs{
+ AppDataBeforeHandshake: []byte("TEST MESSAGE"),
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ name: "AppDataBeforeHandshake-Empty",
+ config: Config{
+ Bugs: ProtocolBugs{
+ AppDataBeforeHandshake: []byte{},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ protocol: dtls,
+ name: "AppDataBeforeHandshake-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ AppDataBeforeHandshake: []byte("TEST MESSAGE"),
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ protocol: dtls,
+ name: "AppDataBeforeHandshake-DTLS-Empty",
+ config: Config{
+ Bugs: ProtocolBugs{
+ AppDataBeforeHandshake: []byte{},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ name: "AppDataAfterChangeCipherSpec",
+ config: Config{
+ Bugs: ProtocolBugs{
+ AppDataAfterChangeCipherSpec: []byte("TEST MESSAGE"),
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DATA_BETWEEN_CCS_AND_FINISHED:",
+ },
+ {
+ name: "AppDataAfterChangeCipherSpec-Empty",
+ config: Config{
+ Bugs: ProtocolBugs{
+ AppDataAfterChangeCipherSpec: []byte{},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DATA_BETWEEN_CCS_AND_FINISHED:",
+ },
+ {
+ protocol: dtls,
+ name: "AppDataAfterChangeCipherSpec-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ AppDataAfterChangeCipherSpec: []byte("TEST MESSAGE"),
+ },
+ },
+ // BoringSSL's DTLS implementation will drop the out-of-order
+ // application data.
+ },
+ {
+ protocol: dtls,
+ name: "AppDataAfterChangeCipherSpec-DTLS-Empty",
+ config: Config{
+ Bugs: ProtocolBugs{
+ AppDataAfterChangeCipherSpec: []byte{},
+ },
+ },
+ // BoringSSL's DTLS implementation will drop the out-of-order
+ // application data.
+ },
+ {
+ name: "AlertAfterChangeCipherSpec",
+ config: Config{
+ Bugs: ProtocolBugs{
+ AlertAfterChangeCipherSpec: alertRecordOverflow,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:",
+ },
+ {
+ protocol: dtls,
+ name: "AlertAfterChangeCipherSpec-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ AlertAfterChangeCipherSpec: alertRecordOverflow,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:",
+ },
+ {
+ protocol: dtls,
+ name: "ReorderHandshakeFragments-Small-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ ReorderHandshakeFragments: true,
+ // Small enough that every handshake message is
+ // fragmented.
+ MaxHandshakeRecordLength: 2,
+ },
+ },
+ },
+ {
+ protocol: dtls,
+ name: "ReorderHandshakeFragments-Large-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ ReorderHandshakeFragments: true,
+ // Large enough that no handshake message is
+ // fragmented.
+ MaxHandshakeRecordLength: 2048,
+ },
+ },
+ },
+ {
+ protocol: dtls,
+ name: "MixCompleteMessageWithFragments-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ ReorderHandshakeFragments: true,
+ MixCompleteMessageWithFragments: true,
+ MaxHandshakeRecordLength: 2,
+ },
+ },
+ },
+ {
+ name: "SendInvalidRecordType",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendInvalidRecordType: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ protocol: dtls,
+ name: "SendInvalidRecordType-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendInvalidRecordType: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ name: "FalseStart-SkipServerSecondLeg",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ SkipNewSessionTicket: true,
+ SkipChangeCipherSpec: true,
+ SkipFinished: true,
+ ExpectFalseStart: true,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ "-handshake-never-done",
+ "-advertise-alpn", "\x03foo",
+ },
+ shimWritesFirst: true,
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ name: "FalseStart-SkipServerSecondLeg-Implicit",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ SkipNewSessionTicket: true,
+ SkipChangeCipherSpec: true,
+ SkipFinished: true,
+ },
+ },
+ flags: []string{
+ "-implicit-handshake",
+ "-false-start",
+ "-handshake-never-done",
+ "-advertise-alpn", "\x03foo",
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ testType: serverTest,
+ name: "FailEarlyCallback",
+ flags: []string{"-fail-early-callback"},
+ shouldFail: true,
+ expectedError: ":CONNECTION_REJECTED:",
+ expectedLocalError: "remote error: access denied",
+ },
+ {
+ name: "WrongMessageType",
+ config: Config{
+ Bugs: ProtocolBugs{
+ WrongCertificateMessageType: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ expectedLocalError: "remote error: unexpected message",
+ },
+ {
+ protocol: dtls,
+ name: "WrongMessageType-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ WrongCertificateMessageType: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ expectedLocalError: "remote error: unexpected message",
+ },
+ {
+ protocol: dtls,
+ name: "FragmentMessageTypeMismatch-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ MaxHandshakeRecordLength: 2,
+ FragmentMessageTypeMismatch: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":FRAGMENT_MISMATCH:",
+ },
+ {
+ protocol: dtls,
+ name: "FragmentMessageLengthMismatch-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ MaxHandshakeRecordLength: 2,
+ FragmentMessageLengthMismatch: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":FRAGMENT_MISMATCH:",
+ },
+ {
+ protocol: dtls,
+ name: "SplitFragments-Header-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SplitFragments: 2,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ },
+ {
+ protocol: dtls,
+ name: "SplitFragments-Boundary-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SplitFragments: dtlsRecordHeaderLen,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":EXCESSIVE_MESSAGE_SIZE:",
+ },
+ {
+ protocol: dtls,
+ name: "SplitFragments-Body-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SplitFragments: dtlsRecordHeaderLen + 1,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":EXCESSIVE_MESSAGE_SIZE:",
+ },
+ {
+ protocol: dtls,
+ name: "SendEmptyFragments-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendEmptyFragments: true,
+ },
+ },
+ },
+ {
+ name: "UnsupportedCipherSuite",
+ config: Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ Bugs: ProtocolBugs{
+ IgnorePeerCipherPreferences: true,
+ },
+ },
+ flags: []string{"-cipher", "DEFAULT:!RC4"},
+ shouldFail: true,
+ expectedError: ":WRONG_CIPHER_RETURNED:",
+ },
+ {
+ name: "UnsupportedCurve",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ // BoringSSL implements P-224 but doesn't enable it by
+ // default.
+ CurvePreferences: []CurveID{CurveP224},
+ Bugs: ProtocolBugs{
+ IgnorePeerCurvePreferences: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CURVE:",
+ },
+ {
+ name: "BadFinished",
+ config: Config{
+ Bugs: ProtocolBugs{
+ BadFinished: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DIGEST_CHECK_FAILED:",
+ },
+ {
+ name: "FalseStart-BadFinished",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ BadFinished: true,
+ ExpectFalseStart: true,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ "-handshake-never-done",
+ "-advertise-alpn", "\x03foo",
+ },
+ shimWritesFirst: true,
+ shouldFail: true,
+ expectedError: ":DIGEST_CHECK_FAILED:",
+ },
+ {
+ name: "NoFalseStart-NoALPN",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ ExpectFalseStart: true,
+ AlertBeforeFalseStartTest: alertAccessDenied,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ },
+ shimWritesFirst: true,
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_ACCESS_DENIED:",
+ expectedLocalError: "tls: peer did not false start: EOF",
+ },
+ {
+ name: "NoFalseStart-NoAEAD",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ ExpectFalseStart: true,
+ AlertBeforeFalseStartTest: alertAccessDenied,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ "-advertise-alpn", "\x03foo",
+ },
+ shimWritesFirst: true,
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_ACCESS_DENIED:",
+ expectedLocalError: "tls: peer did not false start: EOF",
+ },
+ {
+ name: "NoFalseStart-RSA",
+ config: Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ ExpectFalseStart: true,
+ AlertBeforeFalseStartTest: alertAccessDenied,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ "-advertise-alpn", "\x03foo",
+ },
+ shimWritesFirst: true,
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_ACCESS_DENIED:",
+ expectedLocalError: "tls: peer did not false start: EOF",
+ },
+ {
+ name: "NoFalseStart-DHE_RSA",
+ config: Config{
+ CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ ExpectFalseStart: true,
+ AlertBeforeFalseStartTest: alertAccessDenied,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ "-advertise-alpn", "\x03foo",
+ },
+ shimWritesFirst: true,
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_ACCESS_DENIED:",
+ expectedLocalError: "tls: peer did not false start: EOF",
+ },
+ {
+ testType: serverTest,
+ name: "NoSupportedCurves",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ NoSupportedCurves: true,
+ },
+ },
+ },
+ {
+ testType: serverTest,
+ name: "NoCommonCurves",
+ config: Config{
+ CipherSuites: []uint16{
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ CurvePreferences: []CurveID{CurveP224},
+ },
+ expectedCipher: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ {
+ protocol: dtls,
+ name: "SendSplitAlert-Sync",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSplitAlert: true,
+ },
+ },
+ },
+ {
+ protocol: dtls,
+ name: "SendSplitAlert-Async",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSplitAlert: true,
+ },
+ },
+ flags: []string{"-async"},
+ },
+ {
+ protocol: dtls,
+ name: "PackDTLSHandshake",
+ config: Config{
+ Bugs: ProtocolBugs{
+ MaxHandshakeRecordLength: 2,
+ PackHandshakeFragments: 20,
+ PackHandshakeRecords: 200,
+ },
+ },
+ },
+ {
+ testType: serverTest,
+ protocol: dtls,
+ name: "NoRC4-DTLS",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+ Bugs: ProtocolBugs{
+ EnableAllCiphersInDTLS: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":NO_SHARED_CIPHER:",
+ },
+ {
+ name: "SendEmptyRecords-Pass",
+ sendEmptyRecords: 32,
+ },
+ {
+ name: "SendEmptyRecords",
+ sendEmptyRecords: 33,
+ shouldFail: true,
+ expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:",
+ },
+ {
+ name: "SendEmptyRecords-Async",
+ sendEmptyRecords: 33,
+ flags: []string{"-async"},
+ shouldFail: true,
+ expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:",
+ },
+ {
+ name: "SendWarningAlerts-Pass",
+ sendWarningAlerts: 4,
+ },
+ {
+ protocol: dtls,
+ name: "SendWarningAlerts-DTLS-Pass",
+ sendWarningAlerts: 4,
+ },
+ {
+ name: "SendWarningAlerts",
+ sendWarningAlerts: 5,
+ shouldFail: true,
+ expectedError: ":TOO_MANY_WARNING_ALERTS:",
+ },
+ {
+ name: "SendWarningAlerts-Async",
+ sendWarningAlerts: 5,
+ flags: []string{"-async"},
+ shouldFail: true,
+ expectedError: ":TOO_MANY_WARNING_ALERTS:",
+ },
+ {
+ name: "EmptySessionID",
+ config: Config{
+ SessionTicketsDisabled: true,
+ },
+ noSessionCache: true,
+ flags: []string{"-expect-no-session"},
+ },
+ {
+ name: "Unclean-Shutdown",
+ config: Config{
+ Bugs: ProtocolBugs{
+ NoCloseNotify: true,
+ ExpectCloseNotify: true,
+ },
+ },
+ shimShutsDown: true,
+ flags: []string{"-check-close-notify"},
+ shouldFail: true,
+ expectedError: "Unexpected SSL_shutdown result: -1 != 1",
+ },
+ {
+ name: "Unclean-Shutdown-Ignored",
+ config: Config{
+ Bugs: ProtocolBugs{
+ NoCloseNotify: true,
+ },
+ },
+ shimShutsDown: true,
+ },
+ {
+ name: "LargePlaintext",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendLargeRecords: true,
+ },
+ },
+ messageLen: maxPlaintext + 1,
+ shouldFail: true,
+ expectedError: ":DATA_LENGTH_TOO_LONG:",
+ },
+ {
+ protocol: dtls,
+ name: "LargePlaintext-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendLargeRecords: true,
+ },
+ },
+ messageLen: maxPlaintext + 1,
+ shouldFail: true,
+ expectedError: ":DATA_LENGTH_TOO_LONG:",
+ },
+ {
+ name: "LargeCiphertext",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendLargeRecords: true,
+ },
+ },
+ messageLen: maxPlaintext * 2,
+ shouldFail: true,
+ expectedError: ":ENCRYPTED_LENGTH_TOO_LONG:",
+ },
+ {
+ protocol: dtls,
+ name: "LargeCiphertext-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendLargeRecords: true,
+ },
+ },
+ messageLen: maxPlaintext * 2,
+ // Unlike the other four cases, DTLS drops records which
+ // are invalid before authentication, so the connection
+ // does not fail.
+ expectMessageDropped: true,
+ },
+ }
+ testCases = append(testCases, basicTests...)
+}
+
func addCipherSuiteTests() {
for _, suite := range testCipherSuites {
const psk = "12345"
@@ -1679,6 +1988,10 @@ func addCipherSuiteTests() {
"-psk", psk,
"-psk-identity", pskIdentity)
}
+ if hasComponent(suite.name, "NULL") {
+ // NULL ciphers must be explicitly enabled.
+ flags = append(flags, "-cipher", "DEFAULT:NULL-SHA")
+ }
for _, ver := range tlsVersions {
if ver.version < VersionTLS12 && isTLS12Only(suite.name) {
@@ -1752,6 +2065,47 @@ func addCipherSuiteTests() {
})
}
}
+
+ // Ensure both TLS and DTLS accept their maximum record sizes.
+ testCases = append(testCases, testCase{
+ name: suite.name + "-LargeRecord",
+ config: Config{
+ CipherSuites: []uint16{suite.id},
+ Certificates: []Certificate{cert},
+ PreSharedKey: []byte(psk),
+ PreSharedKeyIdentity: pskIdentity,
+ },
+ flags: flags,
+ messageLen: maxPlaintext,
+ })
+ testCases = append(testCases, testCase{
+ name: suite.name + "-LargeRecord-Extra",
+ config: Config{
+ CipherSuites: []uint16{suite.id},
+ Certificates: []Certificate{cert},
+ PreSharedKey: []byte(psk),
+ PreSharedKeyIdentity: pskIdentity,
+ Bugs: ProtocolBugs{
+ SendLargeRecords: true,
+ },
+ },
+ flags: append(flags, "-microsoft-big-sslv3-buffer"),
+ messageLen: maxPlaintext + 16384,
+ })
+ if isDTLSCipher(suite.name) {
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: suite.name + "-LargeRecord-DTLS",
+ config: Config{
+ CipherSuites: []uint16{suite.id},
+ Certificates: []Certificate{cert},
+ PreSharedKey: []byte(psk),
+ PreSharedKeyIdentity: pskIdentity,
+ },
+ flags: flags,
+ messageLen: maxPlaintext,
+ })
+ }
}
testCases = append(testCases, testCase{
@@ -1768,6 +2122,94 @@ func addCipherSuiteTests() {
shouldFail: true,
expectedError: "BAD_DH_P_LENGTH",
})
+
+ // versionSpecificCiphersTest specifies a test for the TLS 1.0 and TLS
+ // 1.1 specific cipher suite settings. A server is setup with the given
+ // cipher lists and then a connection is made for each member of
+ // expectations. The cipher suite that the server selects must match
+ // the specified one.
+ var versionSpecificCiphersTest = []struct {
+ ciphersDefault, ciphersTLS10, ciphersTLS11 string
+ // expectations is a map from TLS version to cipher suite id.
+ expectations map[uint16]uint16
+ }{
+ {
+ // Test that the null case (where no version-specific ciphers are set)
+ // works as expected.
+ "RC4-SHA:AES128-SHA", // default ciphers
+ "", // no ciphers specifically for TLS ≥ 1.0
+ "", // no ciphers specifically for TLS ≥ 1.1
+ map[uint16]uint16{
+ VersionSSL30: TLS_RSA_WITH_RC4_128_SHA,
+ VersionTLS10: TLS_RSA_WITH_RC4_128_SHA,
+ VersionTLS11: TLS_RSA_WITH_RC4_128_SHA,
+ VersionTLS12: TLS_RSA_WITH_RC4_128_SHA,
+ },
+ },
+ {
+ // With ciphers_tls10 set, TLS 1.0, 1.1 and 1.2 should get a different
+ // cipher.
+ "RC4-SHA:AES128-SHA", // default
+ "AES128-SHA", // these ciphers for TLS ≥ 1.0
+ "", // no ciphers specifically for TLS ≥ 1.1
+ map[uint16]uint16{
+ VersionSSL30: TLS_RSA_WITH_RC4_128_SHA,
+ VersionTLS10: TLS_RSA_WITH_AES_128_CBC_SHA,
+ VersionTLS11: TLS_RSA_WITH_AES_128_CBC_SHA,
+ VersionTLS12: TLS_RSA_WITH_AES_128_CBC_SHA,
+ },
+ },
+ {
+ // With ciphers_tls11 set, TLS 1.1 and 1.2 should get a different
+ // cipher.
+ "RC4-SHA:AES128-SHA", // default
+ "", // no ciphers specifically for TLS ≥ 1.0
+ "AES128-SHA", // these ciphers for TLS ≥ 1.1
+ map[uint16]uint16{
+ VersionSSL30: TLS_RSA_WITH_RC4_128_SHA,
+ VersionTLS10: TLS_RSA_WITH_RC4_128_SHA,
+ VersionTLS11: TLS_RSA_WITH_AES_128_CBC_SHA,
+ VersionTLS12: TLS_RSA_WITH_AES_128_CBC_SHA,
+ },
+ },
+ {
+ // With both ciphers_tls10 and ciphers_tls11 set, ciphers_tls11 should
+ // mask ciphers_tls10 for TLS 1.1 and 1.2.
+ "RC4-SHA:AES128-SHA", // default
+ "AES128-SHA", // these ciphers for TLS ≥ 1.0
+ "AES256-SHA", // these ciphers for TLS ≥ 1.1
+ map[uint16]uint16{
+ VersionSSL30: TLS_RSA_WITH_RC4_128_SHA,
+ VersionTLS10: TLS_RSA_WITH_AES_128_CBC_SHA,
+ VersionTLS11: TLS_RSA_WITH_AES_256_CBC_SHA,
+ VersionTLS12: TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ },
+ }
+
+ for i, test := range versionSpecificCiphersTest {
+ for version, expectedCipherSuite := range test.expectations {
+ flags := []string{"-cipher", test.ciphersDefault}
+ if len(test.ciphersTLS10) > 0 {
+ flags = append(flags, "-cipher-tls10", test.ciphersTLS10)
+ }
+ if len(test.ciphersTLS11) > 0 {
+ flags = append(flags, "-cipher-tls11", test.ciphersTLS11)
+ }
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: fmt.Sprintf("VersionSpecificCiphersTest-%d-%x", i, version),
+ config: Config{
+ MaxVersion: version,
+ MinVersion: version,
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA},
+ },
+ flags: flags,
+ expectedCipher: expectedCipherSuite,
+ })
+ }
+ }
}
func addBadECDSASignatureTests() {
@@ -1837,7 +2279,8 @@ func addCBCSplittingTests() {
MinVersion: VersionTLS10,
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
},
- messageLen: -1, // read until EOF
+ messageLen: -1, // read until EOF
+ resumeSession: true,
flags: []string{
"-async",
"-write-different-record-sizes",
@@ -1882,8 +2325,8 @@ func addClientAuthTests() {
ClientCAs: certPool,
},
flags: []string{
- "-cert-file", rsaCertificateFile,
- "-key-file", rsaKeyFile,
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
},
})
testCases = append(testCases, testCase{
@@ -1917,8 +2360,8 @@ func addClientAuthTests() {
ClientCAs: certPool,
},
flags: []string{
- "-cert-file", ecdsaCertificateFile,
- "-key-file", ecdsaKeyFile,
+ "-cert-file", path.Join(*resourceDir, ecdsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, ecdsaKeyFile),
},
})
}
@@ -2075,6 +2518,7 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol)
RenewTicketOnResume: true,
},
},
+ flags: []string{"-expect-ticket-renewal"},
resumeSession: true,
})
tests = append(tests, testCase{
@@ -2123,10 +2567,42 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol)
ClientAuth: RequireAnyClientCert,
},
flags: []string{
- "-cert-file", rsaCertificateFile,
- "-key-file", rsaKeyFile,
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
},
})
+ if async {
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "ClientAuth-Client-AsyncKey",
+ config: Config{
+ ClientAuth: RequireAnyClientCert,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-use-async-private-key",
+ },
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "Basic-Server-RSAAsyncKey",
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-use-async-private-key",
+ },
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "Basic-Server-ECDSAAsyncKey",
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, ecdsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, ecdsaKeyFile),
+ "-use-async-private-key",
+ },
+ })
+ }
tests = append(tests, testCase{
testType: serverTest,
name: "ClientAuth-Server",
@@ -2171,6 +2647,57 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol)
flags: []string{"-psk", "secret"},
})
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "OCSPStapling-Client",
+ flags: []string{
+ "-enable-ocsp-stapling",
+ "-expect-ocsp-response",
+ base64.StdEncoding.EncodeToString(testOCSPResponse),
+ "-verify-peer",
+ },
+ resumeSession: true,
+ })
+
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "OCSPStapling-Server",
+ expectedOCSPResponse: testOCSPResponse,
+ flags: []string{
+ "-ocsp-response",
+ base64.StdEncoding.EncodeToString(testOCSPResponse),
+ },
+ resumeSession: true,
+ })
+
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "CertificateVerificationSucceed",
+ flags: []string{
+ "-verify-peer",
+ },
+ })
+
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "CertificateVerificationFail",
+ flags: []string{
+ "-verify-fail",
+ "-verify-peer",
+ },
+ shouldFail: true,
+ expectedError: ":CERTIFICATE_VERIFY_FAILED:",
+ })
+
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "CertificateVerificationSoftFail",
+ flags: []string{
+ "-verify-fail",
+ "-expect-verify-result",
+ },
+ })
+
if protocol == tls {
tests = append(tests, testCase{
name: "Renegotiate-Client",
@@ -2292,7 +2819,7 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol)
config: Config{
RequestChannelID: true,
},
- flags: []string{"-send-channel-id", channelIDKeyFile},
+ flags: []string{"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile)},
resumeSession: true,
expectChannelID: true,
})
@@ -2311,6 +2838,33 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol)
resumeSession: true,
expectChannelID: true,
})
+
+ // Bidirectional shutdown with the runner initiating.
+ tests = append(tests, testCase{
+ name: "Shutdown-Runner",
+ config: Config{
+ Bugs: ProtocolBugs{
+ ExpectCloseNotify: true,
+ },
+ },
+ flags: []string{"-check-close-notify"},
+ })
+
+ // Bidirectional shutdown with the shim initiating. The runner,
+ // in the meantime, sends garbage before the close_notify which
+ // the shim must ignore.
+ tests = append(tests, testCase{
+ name: "Shutdown-Shim",
+ config: Config{
+ Bugs: ProtocolBugs{
+ ExpectCloseNotify: true,
+ },
+ },
+ shimShutsDown: true,
+ sendEmptyRecords: 1,
+ sendWarningAlerts: 1,
+ flags: []string{"-check-close-notify"},
+ })
} else {
tests = append(tests, testCase{
name: "SkipHelloVerifyRequest",
@@ -2721,6 +3275,70 @@ func addExtensionTests() {
expectedNextProtoType: alpn,
resumeSession: true,
})
+ var emptyString string
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ALPNClient-EmptyProtocolName",
+ config: Config{
+ NextProtos: []string{""},
+ Bugs: ProtocolBugs{
+ // A server returning an empty ALPN protocol
+ // should be rejected.
+ ALPNProtocol: &emptyString,
+ },
+ },
+ flags: []string{
+ "-advertise-alpn", "\x03foo",
+ },
+ shouldFail: true,
+ expectedError: ":PARSE_TLSEXT:",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ALPNServer-EmptyProtocolName",
+ config: Config{
+ // A ClientHello containing an empty ALPN protocol
+ // should be rejected.
+ NextProtos: []string{"foo", "", "baz"},
+ },
+ flags: []string{
+ "-select-alpn", "foo",
+ },
+ shouldFail: true,
+ expectedError: ":PARSE_TLSEXT:",
+ })
+ // Test that negotiating both NPN and ALPN is forbidden.
+ testCases = append(testCases, testCase{
+ name: "NegotiateALPNAndNPN",
+ config: Config{
+ NextProtos: []string{"foo", "bar", "baz"},
+ Bugs: ProtocolBugs{
+ NegotiateALPNAndNPN: true,
+ },
+ },
+ flags: []string{
+ "-advertise-alpn", "\x03foo",
+ "-select-next-proto", "foo",
+ },
+ shouldFail: true,
+ expectedError: ":NEGOTIATED_BOTH_NPN_AND_ALPN:",
+ })
+ testCases = append(testCases, testCase{
+ name: "NegotiateALPNAndNPN-Swapped",
+ config: Config{
+ NextProtos: []string{"foo", "bar", "baz"},
+ Bugs: ProtocolBugs{
+ NegotiateALPNAndNPN: true,
+ SwapNPNAndALPN: true,
+ },
+ },
+ flags: []string{
+ "-advertise-alpn", "\x03foo",
+ "-select-next-proto", "foo",
+ },
+ shouldFail: true,
+ expectedError: ":NEGOTIATED_BOTH_NPN_AND_ALPN:",
+ })
// Resume with a corrupt ticket.
testCases = append(testCases, testCase{
testType: serverTest,
@@ -2733,6 +3351,24 @@ func addExtensionTests() {
resumeSession: true,
expectResumeRejected: true,
})
+ // Test the ticket callback, with and without renewal.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TicketCallback",
+ resumeSession: true,
+ flags: []string{"-use-ticket-callback"},
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TicketCallback-Renew",
+ config: Config{
+ Bugs: ProtocolBugs{
+ ExpectNewTicket: true,
+ },
+ },
+ flags: []string{"-use-ticket-callback", "-renew-ticket"},
+ resumeSession: true,
+ })
// Resume with an oversized session id.
testCases = append(testCases, testCase{
testType: serverTest,
@@ -2822,22 +3458,39 @@ func addExtensionTests() {
shouldFail: true,
expectedError: ":BAD_SRTP_PROTECTION_PROFILE_LIST:",
})
- // Test OCSP stapling and SCT list.
+ // Test SCT list.
testCases = append(testCases, testCase{
- name: "OCSPStapling",
+ name: "SignedCertificateTimestampList-Client",
+ testType: clientTest,
flags: []string{
- "-enable-ocsp-stapling",
- "-expect-ocsp-response",
- base64.StdEncoding.EncodeToString(testOCSPResponse),
+ "-enable-signed-cert-timestamps",
+ "-expect-signed-cert-timestamps",
+ base64.StdEncoding.EncodeToString(testSCTList),
},
+ resumeSession: true,
})
testCases = append(testCases, testCase{
- name: "SignedCertificateTimestampList",
+ name: "SignedCertificateTimestampList-Server",
+ testType: serverTest,
flags: []string{
- "-enable-signed-cert-timestamps",
- "-expect-signed-cert-timestamps",
+ "-signed-cert-timestamps",
base64.StdEncoding.EncodeToString(testSCTList),
},
+ expectedSCTList: testSCTList,
+ resumeSession: true,
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ClientHelloPadding",
+ config: Config{
+ Bugs: ProtocolBugs{
+ RequireClientHelloSize: 512,
+ },
+ },
+ // This hostname just needs to be long enough to push the
+ // ClientHello into F5's danger zone between 256 and 511 bytes
+ // long.
+ flags: []string{"-host-name", "01234567890123456789012345678901234567890123456789012345678901234567890123456789.com"},
})
}
@@ -2956,7 +3609,33 @@ func addRenegotiationTests() {
expectedError: ":NO_RENEGOTIATION:",
expectedLocalError: "remote error: no renegotiation",
})
- // TODO(agl): test the renegotiation info SCSV.
+ // The server shouldn't echo the renegotiation extension unless
+ // requested by the client.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Renegotiate-Server-NoExt",
+ config: Config{
+ Bugs: ProtocolBugs{
+ NoRenegotiationInfo: true,
+ RequireRenegotiationInfo: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "renegotiation extension missing",
+ })
+ // The renegotiation SCSV should be sufficient for the server to echo
+ // the extension.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Renegotiate-Server-NoExt-SCSV",
+ config: Config{
+ Bugs: ProtocolBugs{
+ NoRenegotiationInfo: true,
+ SendRenegotiationSCSV: true,
+ RequireRenegotiationInfo: true,
+ },
+ },
+ })
testCases = append(testCases, testCase{
name: "Renegotiate-Client",
config: Config{
@@ -2989,8 +3668,7 @@ func addRenegotiationTests() {
expectedError: ":RENEGOTIATION_MISMATCH:",
})
testCases = append(testCases, testCase{
- name: "Renegotiate-Client-NoExt",
- renegotiate: true,
+ name: "Renegotiate-Client-NoExt",
config: Config{
Bugs: ProtocolBugs{
NoRenegotiationInfo: true,
@@ -3043,6 +3721,19 @@ func addRenegotiationTests() {
},
},
})
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-FalseStart",
+ renegotiate: true,
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ },
+ flags: []string{
+ "-false-start",
+ "-select-next-proto", "foo",
+ },
+ shimWritesFirst: true,
+ })
}
func addDTLSReplayTests() {
@@ -3050,43 +3741,39 @@ func addDTLSReplayTests() {
testCases = append(testCases, testCase{
protocol: dtls,
name: "DTLS-Replay",
+ messageCount: 200,
replayWrites: true,
})
- // Test the outgoing sequence number skipping by values larger
+ // Test the incoming sequence number skipping by values larger
// than the retransmit window.
testCases = append(testCases, testCase{
protocol: dtls,
name: "DTLS-Replay-LargeGaps",
config: Config{
Bugs: ProtocolBugs{
- SequenceNumberIncrement: 127,
+ SequenceNumberMapping: func(in uint64) uint64 {
+ return in * 127
+ },
},
},
+ messageCount: 200,
replayWrites: true,
})
-}
-func addFastRadioPaddingTests() {
- testCases = append(testCases, testCase{
- protocol: tls,
- name: "FastRadio-Padding",
- config: Config{
- Bugs: ProtocolBugs{
- RequireFastradioPadding: true,
- },
- },
- flags: []string{"-fastradio-padding"},
- })
+ // Test the incoming sequence number changing non-monotonically.
testCases = append(testCases, testCase{
protocol: dtls,
- name: "FastRadio-Padding-DTLS",
+ name: "DTLS-Replay-NonMonotonic",
config: Config{
Bugs: ProtocolBugs{
- RequireFastradioPadding: true,
+ SequenceNumberMapping: func(in uint64) uint64 {
+ return in ^ 31
+ },
},
},
- flags: []string{"-fastradio-padding"},
+ messageCount: 200,
+ replayWrites: true,
})
}
@@ -3116,8 +3803,8 @@ func addSigningHashTests() {
},
},
flags: []string{
- "-cert-file", rsaCertificateFile,
- "-key-file", rsaKeyFile,
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
},
})
@@ -3147,8 +3834,8 @@ func addSigningHashTests() {
},
},
flags: []string{
- "-cert-file", rsaCertificateFile,
- "-key-file", rsaKeyFile,
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
},
})
@@ -3178,8 +3865,8 @@ func addSigningHashTests() {
},
},
flags: []string{
- "-cert-file", rsaCertificateFile,
- "-key-file", rsaKeyFile,
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
},
})
@@ -3235,6 +3922,73 @@ func addSigningHashTests() {
shouldFail: true,
expectedError: ":WRONG_SIGNATURE_TYPE:",
})
+
+ // Test that the agreed upon digest respects the client preferences and
+ // the server digests.
+ testCases = append(testCases, testCase{
+ name: "Agree-Digest-Fallback",
+ config: Config{
+ ClientAuth: RequireAnyClientCert,
+ SignatureAndHashes: []signatureAndHash{
+ {signatureRSA, hashSHA512},
+ {signatureRSA, hashSHA1},
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ digestPrefs: "SHA256",
+ expectedClientCertSignatureHash: hashSHA1,
+ })
+ testCases = append(testCases, testCase{
+ name: "Agree-Digest-SHA256",
+ config: Config{
+ ClientAuth: RequireAnyClientCert,
+ SignatureAndHashes: []signatureAndHash{
+ {signatureRSA, hashSHA1},
+ {signatureRSA, hashSHA256},
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ digestPrefs: "SHA256,SHA1",
+ expectedClientCertSignatureHash: hashSHA256,
+ })
+ testCases = append(testCases, testCase{
+ name: "Agree-Digest-SHA1",
+ config: Config{
+ ClientAuth: RequireAnyClientCert,
+ SignatureAndHashes: []signatureAndHash{
+ {signatureRSA, hashSHA1},
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ digestPrefs: "SHA512,SHA256,SHA1",
+ expectedClientCertSignatureHash: hashSHA1,
+ })
+ testCases = append(testCases, testCase{
+ name: "Agree-Digest-Default",
+ config: Config{
+ ClientAuth: RequireAnyClientCert,
+ SignatureAndHashes: []signatureAndHash{
+ {signatureRSA, hashSHA256},
+ {signatureECDSA, hashSHA256},
+ {signatureRSA, hashSHA1},
+ {signatureECDSA, hashSHA1},
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ expectedClientCertSignatureHash: hashSHA256,
+ })
}
// timeouts is the retransmit schedule for BoringSSL. It doubles and
@@ -3441,7 +4195,111 @@ func addTLSUniqueTests() {
}
}
-func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) {
+func addCustomExtensionTests() {
+ expectedContents := "custom extension"
+ emptyString := ""
+
+ for _, isClient := range []bool{false, true} {
+ suffix := "Server"
+ flag := "-enable-server-custom-extension"
+ testType := serverTest
+ if isClient {
+ suffix = "Client"
+ flag = "-enable-client-custom-extension"
+ testType = clientTest
+ }
+
+ testCases = append(testCases, testCase{
+ testType: testType,
+ name: "CustomExtensions-" + suffix,
+ config: Config{
+ Bugs: ProtocolBugs{
+ CustomExtension: expectedContents,
+ ExpectedCustomExtension: &expectedContents,
+ },
+ },
+ flags: []string{flag},
+ })
+
+ // If the parse callback fails, the handshake should also fail.
+ testCases = append(testCases, testCase{
+ testType: testType,
+ name: "CustomExtensions-ParseError-" + suffix,
+ config: Config{
+ Bugs: ProtocolBugs{
+ CustomExtension: expectedContents + "foo",
+ ExpectedCustomExtension: &expectedContents,
+ },
+ },
+ flags: []string{flag},
+ shouldFail: true,
+ expectedError: ":CUSTOM_EXTENSION_ERROR:",
+ })
+
+ // If the add callback fails, the handshake should also fail.
+ testCases = append(testCases, testCase{
+ testType: testType,
+ name: "CustomExtensions-FailAdd-" + suffix,
+ config: Config{
+ Bugs: ProtocolBugs{
+ CustomExtension: expectedContents,
+ ExpectedCustomExtension: &expectedContents,
+ },
+ },
+ flags: []string{flag, "-custom-extension-fail-add"},
+ shouldFail: true,
+ expectedError: ":CUSTOM_EXTENSION_ERROR:",
+ })
+
+ // If the add callback returns zero, no extension should be
+ // added.
+ skipCustomExtension := expectedContents
+ if isClient {
+ // For the case where the client skips sending the
+ // custom extension, the server must not “echo” it.
+ skipCustomExtension = ""
+ }
+ testCases = append(testCases, testCase{
+ testType: testType,
+ name: "CustomExtensions-Skip-" + suffix,
+ config: Config{
+ Bugs: ProtocolBugs{
+ CustomExtension: skipCustomExtension,
+ ExpectedCustomExtension: &emptyString,
+ },
+ },
+ flags: []string{flag, "-custom-extension-skip"},
+ })
+ }
+
+ // The custom extension add callback should not be called if the client
+ // doesn't send the extension.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "CustomExtensions-NotCalled-Server",
+ config: Config{
+ Bugs: ProtocolBugs{
+ ExpectedCustomExtension: &emptyString,
+ },
+ },
+ flags: []string{"-enable-server-custom-extension", "-custom-extension-fail-add"},
+ })
+
+ // Test an unknown extension from the server.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "UnknownExtension-Client",
+ config: Config{
+ Bugs: ProtocolBugs{
+ CustomExtension: expectedContents,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ })
+}
+
+func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sync.WaitGroup) {
defer wg.Done()
for test := range c {
@@ -3449,11 +4307,11 @@ func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sy
if *mallocTest < 0 {
statusChan <- statusMsg{test: test, started: true}
- err = runTest(test, buildDir, -1)
+ err = runTest(test, shimPath, -1)
} else {
for mallocNumToFail := int64(*mallocTest); ; mallocNumToFail++ {
statusChan <- statusMsg{test: test, started: true}
- if err = runTest(test, buildDir, mallocNumToFail); err != errMoreMallocs {
+ if err = runTest(test, shimPath, mallocNumToFail); err != errMoreMallocs {
if err != nil {
fmt.Printf("\n\nmalloc test failed at %d: %s\n", mallocNumToFail, err)
}
@@ -3515,12 +4373,10 @@ func statusPrinter(doneChan chan *testOutput, statusChan chan statusMsg, total i
}
func main() {
- var flagTest *string = flag.String("test", "", "The name of a test to run, or empty to run all tests")
- var flagNumWorkers *int = flag.Int("num-workers", runtime.NumCPU(), "The number of workers to run in parallel.")
- var flagBuildDir *string = flag.String("build-dir", "../../../build", "The build directory to run the shim from.")
-
flag.Parse()
+ *resourceDir = path.Clean(*resourceDir)
+ addBasicTests()
addCipherSuiteTests()
addBadECDSASignatureTests()
addCBCPaddingTests()
@@ -3536,10 +4392,10 @@ func main() {
addRenegotiationTests()
addDTLSReplayTests()
addSigningHashTests()
- addFastRadioPaddingTests()
addDTLSRetransmitTests()
addExportKeyingMaterialTests()
addTLSUniqueTests()
+ addCustomExtensionTests()
for _, async := range []bool{false, true} {
for _, splitHandshake := range []bool{false, true} {
for _, protocol := range []protocol{tls, dtls} {
@@ -3550,21 +4406,19 @@ func main() {
var wg sync.WaitGroup
- numWorkers := *flagNumWorkers
-
- statusChan := make(chan statusMsg, numWorkers)
- testChan := make(chan *testCase, numWorkers)
+ statusChan := make(chan statusMsg, *numWorkers)
+ testChan := make(chan *testCase, *numWorkers)
doneChan := make(chan *testOutput)
go statusPrinter(doneChan, statusChan, len(testCases))
- for i := 0; i < numWorkers; i++ {
+ for i := 0; i < *numWorkers; i++ {
wg.Add(1)
- go worker(statusChan, testChan, *flagBuildDir, &wg)
+ go worker(statusChan, testChan, *shimPath, &wg)
}
for i := range testCases {
- if len(*flagTest) == 0 || *flagTest == testCases[i].name {
+ if len(*testToRun) == 0 || *testToRun == testCases[i].name {
testChan <- &testCases[i]
}
}
diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc
index 363b6f3..1c42b2e 100644
--- a/src/ssl/test/test_config.cc
+++ b/src/ssl/test/test_config.cc
@@ -65,12 +65,9 @@ const Flag<bool> kBoolFlags[] = {
{ "-expect-session-miss", &TestConfig::expect_session_miss },
{ "-expect-extended-master-secret",
&TestConfig::expect_extended_master_secret },
- { "-allow-unsafe-legacy-renegotiation",
- &TestConfig::allow_unsafe_legacy_renegotiation },
{ "-enable-ocsp-stapling", &TestConfig::enable_ocsp_stapling },
{ "-enable-signed-cert-timestamps",
&TestConfig::enable_signed_cert_timestamps },
- { "-fastradio-padding", &TestConfig::fastradio_padding },
{ "-implicit-handshake", &TestConfig::implicit_handshake },
{ "-use-early-callback", &TestConfig::use_early_callback },
{ "-fail-early-callback", &TestConfig::fail_early_callback },
@@ -82,9 +79,27 @@ const Flag<bool> kBoolFlags[] = {
{ "-reject-peer-renegotiations", &TestConfig::reject_peer_renegotiations },
{ "-no-legacy-server-connect", &TestConfig::no_legacy_server_connect },
{ "-tls-unique", &TestConfig::tls_unique },
+ { "-use-async-private-key", &TestConfig::use_async_private_key },
+ { "-expect-ticket-renewal", &TestConfig::expect_ticket_renewal },
+ { "-expect-no-session", &TestConfig::expect_no_session },
+ { "-use-ticket-callback", &TestConfig::use_ticket_callback },
+ { "-renew-ticket", &TestConfig::renew_ticket },
+ { "-enable-client-custom-extension",
+ &TestConfig::enable_client_custom_extension },
+ { "-enable-server-custom-extension",
+ &TestConfig::enable_server_custom_extension },
+ { "-custom-extension-skip", &TestConfig::custom_extension_skip },
+ { "-custom-extension-fail-add", &TestConfig::custom_extension_fail_add },
+ { "-check-close-notify", &TestConfig::check_close_notify },
+ { "-shim-shuts-down", &TestConfig::shim_shuts_down },
+ { "-microsoft-big-sslv3-buffer", &TestConfig::microsoft_big_sslv3_buffer },
+ { "-verify-fail", &TestConfig::verify_fail },
+ { "-verify-peer", &TestConfig::verify_peer },
+ { "-expect-verify-result", &TestConfig::expect_verify_result }
};
const Flag<std::string> kStringFlags[] = {
+ { "-digest-prefs", &TestConfig::digest_prefs },
{ "-key-file", &TestConfig::key_file },
{ "-cert-file", &TestConfig::cert_file },
{ "-expect-server-name", &TestConfig::expected_server_name },
@@ -101,6 +116,8 @@ const Flag<std::string> kStringFlags[] = {
{ "-psk-identity", &TestConfig::psk_identity },
{ "-srtp-profiles", &TestConfig::srtp_profiles },
{ "-cipher", &TestConfig::cipher },
+ { "-cipher-tls10", &TestConfig::cipher_tls10 },
+ { "-cipher-tls11", &TestConfig::cipher_tls11 },
{ "-export-label", &TestConfig::export_label },
{ "-export-context", &TestConfig::export_context },
};
@@ -111,6 +128,8 @@ const Flag<std::string> kBase64Flags[] = {
{ "-expect-ocsp-response", &TestConfig::expected_ocsp_response },
{ "-expect-signed-cert-timestamps",
&TestConfig::expected_signed_cert_timestamps },
+ { "-ocsp-response", &TestConfig::ocsp_response },
+ { "-signed-cert-timestamps", &TestConfig::signed_cert_timestamps },
};
const Flag<int> kIntFlags[] = {
diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h
index 5d753c8..9dea8e9 100644
--- a/src/ssl/test/test_config.h
+++ b/src/ssl/test/test_config.h
@@ -24,6 +24,7 @@ struct TestConfig {
bool is_dtls = false;
bool resume = false;
bool fallback_scsv = false;
+ std::string digest_prefs;
std::string key_file;
std::string cert_file;
std::string expected_server_name;
@@ -54,13 +55,11 @@ struct TestConfig {
bool expect_extended_master_secret = false;
std::string psk;
std::string psk_identity;
- bool allow_unsafe_legacy_renegotiation = false;
std::string srtp_profiles;
bool enable_ocsp_stapling = false;
std::string expected_ocsp_response;
bool enable_signed_cert_timestamps = false;
std::string expected_signed_cert_timestamps;
- bool fastradio_padding = false;
int min_version = 0;
int max_version = 0;
int mtu = 0;
@@ -71,6 +70,8 @@ struct TestConfig {
bool fail_ddos_callback = false;
bool fail_second_ddos_callback = false;
std::string cipher;
+ std::string cipher_tls10;
+ std::string cipher_tls11;
bool handshake_never_done = false;
int export_keying_material = 0;
std::string export_label;
@@ -79,6 +80,23 @@ struct TestConfig {
bool reject_peer_renegotiations = false;
bool no_legacy_server_connect = false;
bool tls_unique = false;
+ bool use_async_private_key = false;
+ bool expect_ticket_renewal = false;
+ bool expect_no_session = false;
+ bool use_ticket_callback = false;
+ bool renew_ticket = false;
+ bool enable_client_custom_extension = false;
+ bool enable_server_custom_extension = false;
+ bool custom_extension_skip = false;
+ bool custom_extension_fail_add = false;
+ std::string ocsp_response;
+ bool check_close_notify = false;
+ bool shim_shuts_down = false;
+ bool microsoft_big_sslv3_buffer = false;
+ bool verify_fail = false;
+ bool verify_peer = false;
+ bool expect_verify_result = false;
+ std::string signed_cert_timestamps;
};
bool ParseConfig(int argc, char **argv, TestConfig *out_config);
diff --git a/src/ssl/tls_record.c b/src/ssl/tls_record.c
new file mode 100644
index 0000000..36e31b4
--- /dev/null
+++ b/src/ssl/tls_record.c
@@ -0,0 +1,338 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+
+#include "internal.h"
+
+
+/* kMaxEmptyRecords is the number of consecutive, empty records that will be
+ * processed. Without this limit an attacker could send empty records at a
+ * faster rate than we can process and cause record processing to loop
+ * forever. */
+static const uint8_t kMaxEmptyRecords = 32;
+
+size_t ssl_record_prefix_len(const SSL *ssl) {
+ if (SSL_IS_DTLS(ssl)) {
+ return DTLS1_RT_HEADER_LENGTH +
+ SSL_AEAD_CTX_explicit_nonce_len(ssl->aead_read_ctx);
+ } else {
+ return SSL3_RT_HEADER_LENGTH +
+ SSL_AEAD_CTX_explicit_nonce_len(ssl->aead_read_ctx);
+ }
+}
+
+size_t ssl_seal_prefix_len(const SSL *ssl) {
+ if (SSL_IS_DTLS(ssl)) {
+ return DTLS1_RT_HEADER_LENGTH +
+ SSL_AEAD_CTX_explicit_nonce_len(ssl->aead_write_ctx);
+ } else {
+ size_t ret = SSL3_RT_HEADER_LENGTH +
+ SSL_AEAD_CTX_explicit_nonce_len(ssl->aead_write_ctx);
+ if (ssl->s3->need_record_splitting) {
+ ret += SSL3_RT_HEADER_LENGTH;
+ ret += ssl_cipher_get_record_split_len(ssl->aead_write_ctx->cipher);
+ }
+ return ret;
+ }
+}
+
+size_t ssl_max_seal_overhead(const SSL *ssl) {
+ if (SSL_IS_DTLS(ssl)) {
+ return DTLS1_RT_HEADER_LENGTH +
+ SSL_AEAD_CTX_max_overhead(ssl->aead_write_ctx);
+ } else {
+ size_t ret = SSL3_RT_HEADER_LENGTH +
+ SSL_AEAD_CTX_max_overhead(ssl->aead_write_ctx);
+ if (ssl->s3->need_record_splitting) {
+ ret *= 2;
+ }
+ return ret;
+ }
+}
+
+enum ssl_open_record_t tls_open_record(
+ SSL *ssl, uint8_t *out_type, uint8_t *out, size_t *out_len,
+ size_t *out_consumed, uint8_t *out_alert, size_t max_out, const uint8_t *in,
+ size_t in_len) {
+ CBS cbs;
+ CBS_init(&cbs, in, in_len);
+
+ /* Decode the record header. */
+ uint8_t type;
+ uint16_t version, ciphertext_len;
+ if (!CBS_get_u8(&cbs, &type) ||
+ !CBS_get_u16(&cbs, &version) ||
+ !CBS_get_u16(&cbs, &ciphertext_len)) {
+ *out_consumed = SSL3_RT_HEADER_LENGTH;
+ return ssl_open_record_partial;
+ }
+
+ /* Check the version. */
+ if ((ssl->s3->have_version && version != ssl->version) ||
+ (version >> 8) != SSL3_VERSION_MAJOR) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_NUMBER);
+ *out_alert = SSL_AD_PROTOCOL_VERSION;
+ return ssl_open_record_error;
+ }
+
+ /* Check the ciphertext length. */
+ size_t extra = 0;
+ if (ssl->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) {
+ extra = SSL3_RT_MAX_EXTRA;
+ }
+ if (ciphertext_len > SSL3_RT_MAX_ENCRYPTED_LENGTH + extra) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
+ *out_alert = SSL_AD_RECORD_OVERFLOW;
+ return ssl_open_record_error;
+ }
+
+ /* Extract the body. */
+ CBS body;
+ if (!CBS_get_bytes(&cbs, &body, ciphertext_len)) {
+ *out_consumed = SSL3_RT_HEADER_LENGTH + (size_t)ciphertext_len;
+ return ssl_open_record_partial;
+ }
+
+ if (ssl->msg_callback != NULL) {
+ ssl->msg_callback(0 /* read */, 0, SSL3_RT_HEADER, in,
+ SSL3_RT_HEADER_LENGTH, ssl, ssl->msg_callback_arg);
+ }
+
+ /* Decrypt the body. */
+ size_t plaintext_len;
+ if (!SSL_AEAD_CTX_open(ssl->aead_read_ctx, out, &plaintext_len, max_out,
+ type, version, ssl->s3->read_sequence, CBS_data(&body),
+ CBS_len(&body))) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
+ *out_alert = SSL_AD_BAD_RECORD_MAC;
+ return ssl_open_record_error;
+ }
+ if (!ssl3_record_sequence_update(ssl->s3->read_sequence, 8)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return ssl_open_record_error;
+ }
+
+ /* Check the plaintext length. */
+ if (plaintext_len > SSL3_RT_MAX_PLAIN_LENGTH + extra) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
+ *out_alert = SSL_AD_RECORD_OVERFLOW;
+ return ssl_open_record_error;
+ }
+
+ /* Limit the number of consecutive empty records. */
+ if (plaintext_len == 0) {
+ ssl->s3->empty_record_count++;
+ if (ssl->s3->empty_record_count > kMaxEmptyRecords) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_EMPTY_FRAGMENTS);
+ *out_alert = SSL_AD_UNEXPECTED_MESSAGE;
+ return ssl_open_record_error;
+ }
+ /* Apart from the limit, empty records are returned up to the caller. This
+ * allows the caller to reject records of the wrong type. */
+ } else {
+ ssl->s3->empty_record_count = 0;
+ }
+
+ *out_type = type;
+ *out_len = plaintext_len;
+ *out_consumed = in_len - CBS_len(&cbs);
+ return ssl_open_record_success;
+}
+
+static int do_seal_record(SSL *ssl, uint8_t *out, size_t *out_len,
+ size_t max_out, uint8_t type, const uint8_t *in,
+ size_t in_len) {
+ if (max_out < SSL3_RT_HEADER_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ /* Check the record header does not alias any part of the input.
+ * |SSL_AEAD_CTX_seal| will internally enforce other aliasing requirements. */
+ if (in < out + SSL3_RT_HEADER_LENGTH && out < in + in_len) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
+ return 0;
+ }
+
+ out[0] = type;
+
+ /* Some servers hang if initial ClientHello is larger than 256 bytes and
+ * record version number > TLS 1.0. */
+ uint16_t wire_version = ssl->version;
+ if (!ssl->s3->have_version && ssl->version > SSL3_VERSION) {
+ wire_version = TLS1_VERSION;
+ }
+ out[1] = wire_version >> 8;
+ out[2] = wire_version & 0xff;
+
+ size_t ciphertext_len;
+ if (!SSL_AEAD_CTX_seal(ssl->aead_write_ctx, out + SSL3_RT_HEADER_LENGTH,
+ &ciphertext_len, max_out - SSL3_RT_HEADER_LENGTH,
+ type, wire_version, ssl->s3->write_sequence, in,
+ in_len) ||
+ !ssl3_record_sequence_update(ssl->s3->write_sequence, 8)) {
+ return 0;
+ }
+
+ if (ciphertext_len >= 1 << 16) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return 0;
+ }
+ out[3] = ciphertext_len >> 8;
+ out[4] = ciphertext_len & 0xff;
+
+ *out_len = SSL3_RT_HEADER_LENGTH + ciphertext_len;
+
+ if (ssl->msg_callback) {
+ ssl->msg_callback(1 /* write */, 0, SSL3_RT_HEADER, out,
+ SSL3_RT_HEADER_LENGTH, ssl, ssl->msg_callback_arg);
+ }
+
+ return 1;
+}
+
+int tls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+ uint8_t type, const uint8_t *in, size_t in_len) {
+ size_t frag_len = 0;
+ if (ssl->s3->need_record_splitting && type == SSL3_RT_APPLICATION_DATA &&
+ in_len > 1) {
+ /* |do_seal_record| will notice if it clobbers |in[0]|, but not if it
+ * aliases the rest of |in|. */
+ if (in + 1 <= out && out < in + in_len) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
+ return 0;
+ }
+ /* Ensure |do_seal_record| does not write beyond |in[0]|. */
+ size_t frag_max_out = max_out;
+ if (out <= in + 1 && in + 1 < out + frag_max_out) {
+ frag_max_out = (size_t)(in + 1 - out);
+ }
+ if (!do_seal_record(ssl, out, &frag_len, frag_max_out, type, in, 1)) {
+ return 0;
+ }
+ in++;
+ in_len--;
+ out += frag_len;
+ max_out -= frag_len;
+
+ assert(SSL3_RT_HEADER_LENGTH +
+ ssl_cipher_get_record_split_len(ssl->aead_write_ctx->cipher) ==
+ frag_len);
+ }
+
+ if (!do_seal_record(ssl, out, out_len, max_out, type, in, in_len)) {
+ return 0;
+ }
+ *out_len += frag_len;
+ return 1;
+}