external/boringssl: Sync to d18cb77.
This includes the following changes which are far too many to list here:
https://boringssl.googlesource.com/boringssl/+log/7b8b9c17db93ea5287575b437c77fb36eeb81b31..d18cb77864dcc4b5c7cb08c2331008c01165f34f
This also retires one function from android_compat_hacks.c which is no longer
necessary.
Change-Id: Ie00536d7ad815464b2b031f7bcd1b683e12c1623
diff --git a/src/ssl/d1_both.c b/src/ssl/d1_both.c
index ee4cbc9..cc95a70 100644
--- a/src/ssl/d1_both.c
+++ b/src/ssl/d1_both.c
@@ -115,14 +115,12 @@
#include <assert.h>
#include <limits.h>
-#include <stdio.h>
#include <string.h>
#include <openssl/buf.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
#include <openssl/rand.h>
#include <openssl/x509.h>
@@ -292,12 +290,11 @@
/* During the handshake, wbio is buffered to pack messages together. Flush the
* buffer if the ChangeCipherSpec would not fit in a packet. */
if (dtls1_max_record_size(ssl) == 0) {
- ssl->rwstate = SSL_WRITING;
int ret = BIO_flush(SSL_get_wbio(ssl));
if (ret <= 0) {
+ ssl->rwstate = SSL_WRITING;
return ret;
}
- ssl->rwstate = SSL_NOTHING;
}
static const uint8_t kChangeCipherSpec[1] = {SSL3_MT_CCS};
@@ -342,13 +339,12 @@
/* During the handshake, wbio is buffered to pack messages together. Flush
* the buffer if there isn't enough room to make progress. */
if (dtls1_max_record_size(ssl) < DTLS1_HM_HEADER_LENGTH + 1) {
- ssl->rwstate = SSL_WRITING;
int flush_ret = BIO_flush(SSL_get_wbio(ssl));
if (flush_ret <= 0) {
+ ssl->rwstate = SSL_WRITING;
ret = flush_ret;
goto err;
}
- ssl->rwstate = SSL_NOTHING;
assert(BIO_wpending(SSL_get_wbio(ssl)) == 0);
}
diff --git a/src/ssl/d1_clnt.c b/src/ssl/d1_clnt.c
index ad5eb50..2fc9094 100644
--- a/src/ssl/d1_clnt.c
+++ b/src/ssl/d1_clnt.c
@@ -115,7 +115,6 @@
#include <openssl/ssl.h>
#include <assert.h>
-#include <stdio.h>
#include <string.h>
#include <openssl/bn.h>
@@ -125,7 +124,6 @@
#include <openssl/err.h>
#include <openssl/md5.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
#include <openssl/rand.h>
#include "internal.h"
@@ -143,7 +141,6 @@
assert(!ssl->server);
assert(SSL_IS_DTLS(ssl));
- ERR_clear_error();
ERR_clear_system_error();
if (ssl->info_callback != NULL) {
@@ -152,8 +149,6 @@
cb = ssl->ctx->info_callback;
}
- ssl->in_handshake++;
-
for (;;) {
state = ssl->state;
@@ -368,10 +363,7 @@
ssl->state = SSL3_ST_CW_FINISHED_A;
ssl->init_num = 0;
- ssl->session->cipher = ssl->s3->tmp.new_cipher;
- if (!ssl->enc_method->setup_key_block(ssl) ||
- !ssl->enc_method->change_cipher_state(
- ssl, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
+ if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
ret = -1;
goto end;
}
@@ -383,10 +375,8 @@
dtls1_start_timer(ssl);
}
- ret =
- ssl3_send_finished(ssl, SSL3_ST_CW_FINISHED_A, SSL3_ST_CW_FINISHED_B,
- ssl->enc_method->client_finished_label,
- ssl->enc_method->client_finished_label_len);
+ ret = ssl3_send_finished(ssl, SSL3_ST_CW_FINISHED_A,
+ SSL3_ST_CW_FINISHED_B);
if (ret <= 0) {
goto end;
}
@@ -431,7 +421,7 @@
goto end;
}
- if (!ssl3_do_change_cipher_spec(ssl)) {
+ if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_CLIENT_READ)) {
ret = -1;
goto end;
}
@@ -457,12 +447,11 @@
break;
case SSL3_ST_CW_FLUSH:
- ssl->rwstate = SSL_WRITING;
if (BIO_flush(ssl->wbio) <= 0) {
+ ssl->rwstate = SSL_WRITING;
ret = -1;
goto end;
}
- ssl->rwstate = SSL_NOTHING;
ssl->state = ssl->s3->tmp.next_state;
break;
@@ -508,8 +497,6 @@
}
end:
- ssl->in_handshake--;
-
BUF_MEM_free(buf);
if (cb != NULL) {
cb(ssl, SSL_CB_CONNECT_EXIT, ret);
diff --git a/src/ssl/d1_lib.c b/src/ssl/d1_lib.c
index 7f08b06..e48fbf1 100644
--- a/src/ssl/d1_lib.c
+++ b/src/ssl/d1_lib.c
@@ -57,12 +57,11 @@
#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 <openssl/nid.h>
#include "internal.h"
@@ -110,11 +109,11 @@
ssl->d1 = d1;
- /* Set the version to the highest version for DTLS. This controls the initial
- * state of |ssl->enc_method| and what the API reports as the version prior to
- * negotiation.
+ /* Set the version to the highest supported version.
*
- * TODO(davidben): This is fragile and confusing. */
+ * TODO(davidben): Move this field into |s3|, have it store the normalized
+ * protocol version, and implement this pre-negotiation quirk in |SSL_version|
+ * at the API boundary rather than in internal state. */
ssl->version = DTLS1_2_VERSION;
return 1;
}
@@ -272,6 +271,10 @@
}
int DTLSv1_handle_timeout(SSL *ssl) {
+ ssl->rwstate = SSL_NOTHING;
+ /* Functions which use SSL_get_error must clear the error queue on entry. */
+ ERR_clear_error();
+
if (!SSL_IS_DTLS(ssl)) {
return -1;
}
diff --git a/src/ssl/d1_pkt.c b/src/ssl/d1_pkt.c
index f2ade3a..4690486 100644
--- a/src/ssl/d1_pkt.c
+++ b/src/ssl/d1_pkt.c
@@ -112,7 +112,6 @@
#include <openssl/ssl.h>
#include <assert.h>
-#include <stdio.h>
#include <string.h>
#include <openssl/buf.h>
@@ -186,6 +185,7 @@
}
int dtls1_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek) {
+ assert(!SSL_in_init(ssl));
return dtls1_read_bytes(ssl, SSL3_RT_APPLICATION_DATA, buf, len, peek);
}
@@ -233,7 +233,7 @@
* This function must handle any surprises the peer may have for us, such as
* Alert records (e.g. close_notify) and out of records. */
int dtls1_read_bytes(SSL *ssl, int type, unsigned char *buf, int len, int peek) {
- int al, i, ret;
+ int al, ret;
unsigned int n;
SSL3_RECORD *rr;
void (*cb)(const SSL *ssl, int type, int value) = NULL;
@@ -245,21 +245,7 @@
return -1;
}
- if (!ssl->in_handshake && SSL_in_init(ssl)) {
- /* type == SSL3_RT_APPLICATION_DATA */
- i = ssl->handshake_func(ssl);
- if (i < 0) {
- return i;
- }
- if (i == 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
- return -1;
- }
- }
-
start:
- ssl->rwstate = SSL_NOTHING;
-
/* ssl->s3->rrec.type - is the type of record
* ssl->s3->rrec.data - data
* ssl->s3->rrec.off - offset into 'data' for next read
@@ -291,7 +277,6 @@
* 'peek' mode) */
if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) {
rr->length = 0;
- ssl->rwstate = SSL_NOTHING;
return 0;
}
@@ -300,7 +285,7 @@
/* Make sure that we are not getting application data when we
* are doing a handshake for the first time. */
if (SSL_in_init(ssl) && (type == SSL3_RT_APPLICATION_DATA) &&
- (ssl->aead_read_ctx == NULL)) {
+ (ssl->s3->aead_read_ctx == NULL)) {
/* TODO(davidben): Is this check redundant with the handshake_func
* check? */
al = SSL_AD_UNEXPECTED_MESSAGE;
@@ -338,11 +323,10 @@
/* If we get here, then type != rr->type. */
- /* If an alert record, process one alert out of the record. Note that we allow
- * a single record to contain multiple alerts. */
+ /* If an alert record, process the alert. */
if (rr->type == SSL3_RT_ALERT) {
- /* Alerts may not be fragmented. */
- if (rr->length < 2) {
+ /* Alerts records may not contain fragmented or multiple alerts. */
+ if (rr->length != 2) {
al = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT);
goto f_err;
@@ -369,16 +353,14 @@
}
if (alert_level == SSL3_AL_WARNING) {
- ssl->s3->warn_alert = alert_descr;
if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
+ ssl->s3->clean_shutdown = 1;
ssl->shutdown |= SSL_RECEIVED_SHUTDOWN;
return 0;
}
} else if (alert_level == SSL3_AL_FATAL) {
char tmp[16];
- ssl->rwstate = SSL_NOTHING;
- ssl->s3->fatal_alert = 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);
@@ -403,8 +385,10 @@
* Application data must come in the encrypted epoch, and ChangeCipherSpec in
* the unencrypted epoch (we never renegotiate). Other cases fall through and
* fail with a fatal error. */
- if ((rr->type == SSL3_RT_APPLICATION_DATA && ssl->aead_read_ctx != NULL) ||
- (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC && ssl->aead_read_ctx == NULL)) {
+ if ((rr->type == SSL3_RT_APPLICATION_DATA &&
+ ssl->s3->aead_read_ctx != NULL) ||
+ (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC &&
+ ssl->s3->aead_read_ctx == NULL)) {
rr->length = 0;
goto start;
}
@@ -458,39 +442,23 @@
}
int dtls1_write_app_data(SSL *ssl, const void *buf_, int len) {
- int i;
-
- if (SSL_in_init(ssl) && !ssl->in_handshake) {
- i = ssl->handshake_func(ssl);
- if (i < 0) {
- return i;
- }
- if (i == 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
- return -1;
- }
- }
+ assert(!SSL_in_init(ssl));
if (len > SSL3_RT_MAX_PLAIN_LENGTH) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DTLS_MESSAGE_TOO_BIG);
return -1;
}
- i = dtls1_write_bytes(ssl, SSL3_RT_APPLICATION_DATA, buf_, len,
- dtls1_use_current_epoch);
- return i;
+ return dtls1_write_bytes(ssl, SSL3_RT_APPLICATION_DATA, buf_, len,
+ dtls1_use_current_epoch);
}
/* Call this to write data in records of type 'type' It will return <= 0 if not
* all data has been sent or non-blocking IO. */
int dtls1_write_bytes(SSL *ssl, int type, const void *buf, int len,
enum dtls1_use_epoch_t use_epoch) {
- int i;
-
assert(len <= SSL3_RT_MAX_PLAIN_LENGTH);
- ssl->rwstate = SSL_NOTHING;
- i = do_dtls1_write(ssl, type, buf, len, use_epoch);
- return i;
+ return do_dtls1_write(ssl, type, buf, len, use_epoch);
}
static int do_dtls1_write(SSL *ssl, int type, const uint8_t *buf,
@@ -537,42 +505,35 @@
}
int dtls1_dispatch_alert(SSL *ssl) {
- int i, j;
- void (*cb)(const SSL *ssl, int type, int value) = NULL;
- uint8_t buf[DTLS1_AL_HEADER_LENGTH];
- uint8_t *ptr = &buf[0];
-
ssl->s3->alert_dispatch = 0;
-
- memset(buf, 0x00, sizeof(buf));
- *ptr++ = ssl->s3->send_alert[0];
- *ptr++ = ssl->s3->send_alert[1];
-
- i = do_dtls1_write(ssl, SSL3_RT_ALERT, &buf[0], sizeof(buf),
- dtls1_use_current_epoch);
- if (i <= 0) {
+ int ret = do_dtls1_write(ssl, SSL3_RT_ALERT, &ssl->s3->send_alert[0], 2,
+ dtls1_use_current_epoch);
+ if (ret <= 0) {
ssl->s3->alert_dispatch = 1;
- } else {
- if (ssl->s3->send_alert[0] == SSL3_AL_FATAL) {
- (void)BIO_flush(ssl->wbio);
- }
-
- if (ssl->msg_callback) {
- ssl->msg_callback(1, ssl->version, SSL3_RT_ALERT, ssl->s3->send_alert, 2,
- ssl, ssl->msg_callback_arg);
- }
-
- if (ssl->info_callback != NULL) {
- cb = ssl->info_callback;
- } else if (ssl->ctx->info_callback != NULL) {
- cb = ssl->ctx->info_callback;
- }
-
- if (cb != NULL) {
- j = (ssl->s3->send_alert[0] << 8) | ssl->s3->send_alert[1];
- cb(ssl, SSL_CB_WRITE_ALERT, j);
- }
+ return ret;
}
- return i;
+ /* If the alert is fatal, flush the BIO now. */
+ if (ssl->s3->send_alert[0] == SSL3_AL_FATAL) {
+ BIO_flush(ssl->wbio);
+ }
+
+ if (ssl->msg_callback != NULL) {
+ ssl->msg_callback(1 /* write */, ssl->version, SSL3_RT_ALERT,
+ ssl->s3->send_alert, 2, ssl, ssl->msg_callback_arg);
+ }
+
+ void (*cb)(const SSL *ssl, int type, int value) = NULL;
+ if (ssl->info_callback != NULL) {
+ cb = ssl->info_callback;
+ } else if (ssl->ctx->info_callback != NULL) {
+ cb = ssl->ctx->info_callback;
+ }
+
+ if (cb != NULL) {
+ int alert = (ssl->s3->send_alert[0] << 8) | ssl->s3->send_alert[1];
+ cb(ssl, SSL_CB_WRITE_ALERT, alert);
+ }
+
+ return 1;
}
diff --git a/src/ssl/d1_srtp.c b/src/ssl/d1_srtp.c
index 5dba8ef..e7b1607 100644
--- a/src/ssl/d1_srtp.c
+++ b/src/ssl/d1_srtp.c
@@ -116,12 +116,10 @@
#include <openssl/ssl.h>
-#include <stdio.h>
#include <string.h>
#include <openssl/bytestring.h>
#include <openssl/err.h>
-#include <openssl/obj.h>
#include "internal.h"
@@ -212,7 +210,7 @@
return ssl->srtp_profiles;
}
- if (ssl->ctx != NULL && ssl->ctx->srtp_profiles != NULL) {
+ if (ssl->ctx->srtp_profiles != NULL) {
return ssl->ctx->srtp_profiles;
}
diff --git a/src/ssl/d1_srvr.c b/src/ssl/d1_srvr.c
index 3ba9411..d353281 100644
--- a/src/ssl/d1_srvr.c
+++ b/src/ssl/d1_srvr.c
@@ -115,7 +115,6 @@
#include <openssl/ssl.h>
#include <assert.h>
-#include <stdio.h>
#include <openssl/bn.h>
#include <openssl/buf.h>
@@ -123,7 +122,6 @@
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/md5.h>
-#include <openssl/obj.h>
#include <openssl/rand.h>
#include <openssl/x509.h>
@@ -141,7 +139,6 @@
assert(ssl->server);
assert(SSL_IS_DTLS(ssl));
- ERR_clear_error();
ERR_clear_system_error();
if (ssl->info_callback != NULL) {
@@ -150,8 +147,6 @@
cb = ssl->ctx->info_callback;
}
- ssl->in_handshake++;
-
for (;;) {
state = ssl->state;
@@ -307,12 +302,11 @@
break;
case SSL3_ST_SW_FLUSH:
- ssl->rwstate = SSL_WRITING;
if (BIO_flush(ssl->wbio) <= 0) {
+ ssl->rwstate = SSL_WRITING;
ret = -1;
goto end;
}
- ssl->rwstate = SSL_NOTHING;
ssl->state = ssl->s3->tmp.next_state;
break;
@@ -355,7 +349,7 @@
goto end;
}
- if (!ssl3_do_change_cipher_spec(ssl)) {
+ if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_SERVER_READ)) {
ret = -1;
goto end;
}
@@ -393,12 +387,6 @@
case SSL3_ST_SW_CHANGE_A:
case SSL3_ST_SW_CHANGE_B:
- ssl->session->cipher = ssl->s3->tmp.new_cipher;
- if (!ssl->enc_method->setup_key_block(ssl)) {
- ret = -1;
- goto end;
- }
-
ret = dtls1_send_change_cipher_spec(ssl, SSL3_ST_SW_CHANGE_A,
SSL3_ST_SW_CHANGE_B);
@@ -409,8 +397,7 @@
ssl->state = SSL3_ST_SW_FINISHED_A;
ssl->init_num = 0;
- if (!ssl->enc_method->change_cipher_state(
- ssl, SSL3_CHANGE_CIPHER_SERVER_WRITE)) {
+ if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_SERVER_WRITE)) {
ret = -1;
goto end;
}
@@ -419,9 +406,7 @@
case SSL3_ST_SW_FINISHED_A:
case SSL3_ST_SW_FINISHED_B:
ret = ssl3_send_finished(ssl, SSL3_ST_SW_FINISHED_A,
- SSL3_ST_SW_FINISHED_B,
- ssl->enc_method->server_finished_label,
- ssl->enc_method->server_finished_label_len);
+ SSL3_ST_SW_FINISHED_B);
if (ret <= 0) {
goto end;
}
@@ -476,7 +461,6 @@
}
end:
- ssl->in_handshake--;
BUF_MEM_free(buf);
if (cb != NULL) {
cb(ssl, SSL_CB_ACCEPT_EXIT, ret);
diff --git a/src/ssl/dtls_record.c b/src/ssl/dtls_record.c
index 940494a..eaf6df7 100644
--- a/src/ssl/dtls_record.c
+++ b/src/ssl/dtls_record.c
@@ -213,7 +213,7 @@
/* Decrypt the body. */
size_t plaintext_len;
- if (!SSL_AEAD_CTX_open(ssl->aead_read_ctx, out, &plaintext_len, max_out,
+ if (!SSL_AEAD_CTX_open(ssl->s3->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.
@@ -250,7 +250,7 @@
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;
+ SSL_AEAD_CTX *aead = ssl->s3->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
@@ -286,7 +286,7 @@
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)) {
+ !ssl_record_sequence_update(&seq[2], 6)) {
return 0;
}
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index 5acb598..982f304 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -346,6 +346,10 @@
/* Record layer. */
+/* ssl_record_sequence_update increments the sequence number in |seq|. It
+ * returns one on success and zero on wraparound. */
+int ssl_record_sequence_update(uint8_t *seq, size_t seq_len);
+
/* ssl_record_prefix_len returns the length of the prefix before the ciphertext
* of a record for |ssl|.
*
@@ -432,6 +436,14 @@
uint8_t type, const uint8_t *in, size_t in_len,
enum dtls1_use_epoch_t use_epoch);
+/* ssl_set_read_state sets |ssl|'s read cipher state to |aead_ctx|. It takes
+ * ownership of |aead_ctx|. */
+void ssl_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx);
+
+/* ssl_set_write_state sets |ssl|'s write cipher state to |aead_ctx|. It takes
+ * ownership of |aead_ctx|. */
+void ssl_set_write_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx);
+
/* Private key operations. */
@@ -519,7 +531,7 @@
#define SSL_CURVE_SECP256R1 23
#define SSL_CURVE_SECP384R1 24
#define SSL_CURVE_SECP521R1 25
-#define SSL_CURVE_ECDH_X25519 29
+#define SSL_CURVE_X25519 29
/* An SSL_ECDH_METHOD is an implementation of ECDH-like key exchanges for
* TLS. */
@@ -735,12 +747,6 @@
/* Check if an SSL structure is using DTLS */
#define SSL_IS_DTLS(ssl) (ssl->method->is_dtls)
-/* See if we need explicit IV */
-#define SSL_USE_EXPLICIT_IV(ssl) \
- (ssl->enc_method->enc_flags & SSL_ENC_FLAG_EXPLICIT_IV)
-/* See if we use signature algorithms extension and signature algorithm before
- * signatures. */
-#define SSL_USE_SIGALGS(ssl) (ssl->enc_method->enc_flags & SSL_ENC_FLAG_SIGALGS)
/* From RFC4492, used in encoding the curve type in ECParameters */
#define NAMED_CURVE_TYPE 3
@@ -797,6 +803,10 @@
* supported signature algorithms or curves. */
int (*cert_cb)(SSL *ssl, void *arg);
void *cert_cb_arg;
+
+ /* Optional X509_STORE for certificate validation. If NULL the parent SSL_CTX
+ * store is used instead. */
+ X509_STORE *verify_store;
} CERT;
/* SSL_METHOD is a compatibility structure to support the legacy version-locked
@@ -840,22 +850,16 @@
/* This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff It is a bit
* of a mess of functions, but hell, think of it as an opaque structure. */
struct ssl3_enc_method {
- int (*prf)(SSL *, uint8_t *, size_t, const uint8_t *, size_t, const char *,
- size_t, const uint8_t *, size_t, const uint8_t *, size_t);
- int (*setup_key_block)(SSL *);
- int (*generate_master_secret)(SSL *, uint8_t *, const uint8_t *, size_t);
- int (*change_cipher_state)(SSL *, int);
- int (*final_finish_mac)(SSL *, const char *, int, uint8_t *);
+ /* prf computes the PRF function for |ssl|. It writes |out_len| bytes to
+ * |out|, using |secret| as the secret and |label| as the label. |seed1| and
+ * |seed2| are concatenated to form the seed parameter. It returns one on
+ * success and zero on failure. */
+ int (*prf)(const SSL *ssl, uint8_t *out, size_t out_len,
+ const uint8_t *secret, size_t secret_len, const char *label,
+ size_t label_len, const uint8_t *seed1, size_t seed1_len,
+ const uint8_t *seed2, size_t seed2_len);
+ int (*final_finish_mac)(SSL *ssl, int from_server, uint8_t *out);
int (*cert_verify_mac)(SSL *, int, uint8_t *);
- const char *client_finished_label;
- int client_finished_label_len;
- const char *server_finished_label;
- int server_finished_label_len;
- int (*alert_value)(int);
- int (*export_keying_material)(SSL *, uint8_t *, size_t, const char *, size_t,
- const uint8_t *, size_t, int use_context);
- /* Various flags indicating protocol version requirements */
- unsigned int enc_flags;
};
#define SSL_HM_HEADER_LENGTH(ssl) ssl->method->hhlen
@@ -865,15 +869,6 @@
ssl->method->set_handshake_header(ssl, htype, len)
#define ssl_do_write(ssl) ssl->method->do_write(ssl)
-/* Values for enc_flags */
-
-/* Uses explicit IV for CBC mode */
-#define SSL_ENC_FLAG_EXPLICIT_IV 0x1
-/* Uses signature algorithms extension */
-#define SSL_ENC_FLAG_SIGALGS 0x2
-/* Uses SHA256 default PRF */
-#define SSL_ENC_FLAG_SHA256_PRF 0x4
-
/* lengths of messages */
#define DTLS1_COOKIE_LENGTH 256
@@ -966,12 +961,9 @@
} DTLS1_STATE;
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 *ssl);
int ssl_clear_bad_session(SSL *ssl);
CERT *ssl_cert_new(void);
CERT *ssl_cert_dup(CERT *cert);
@@ -1030,10 +1022,6 @@
int ssl3_send_certificate_status(SSL *ssl);
int ssl3_get_finished(SSL *ssl, int state_a, int state_b);
int ssl3_send_change_cipher_spec(SSL *ssl, int state_a, int state_b);
-int ssl3_prf(SSL *ssl, uint8_t *out, size_t out_len, const uint8_t *secret,
- size_t secret_len, const char *label, size_t label_len,
- const uint8_t *seed1, size_t seed1_len,
- const uint8_t *seed2, size_t seed2_len);
void ssl3_cleanup_key_block(SSL *ssl);
int ssl3_do_write(SSL *ssl, int type);
int ssl3_send_alert(SSL *ssl, int level, int desc);
@@ -1054,7 +1042,7 @@
int ssl3_cert_verify_hash(SSL *ssl, uint8_t *out, size_t *out_len,
const EVP_MD **out_md, int pkey_type);
-int ssl3_send_finished(SSL *ssl, int a, int b, const char *sender, int slen);
+int ssl3_send_finished(SSL *ssl, int a, int b);
int ssl3_supports_cipher(const SSL_CIPHER *cipher);
int ssl3_dispatch_alert(SSL *ssl);
int ssl3_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek);
@@ -1063,8 +1051,6 @@
int ssl3_read_bytes(SSL *ssl, int type, uint8_t *buf, int len, int peek);
int ssl3_write_app_data(SSL *ssl, const void *buf, int len);
int ssl3_write_bytes(SSL *ssl, int type, const void *buf, int len);
-int ssl3_final_finish_mac(SSL *ssl, const char *sender, int slen, uint8_t *p);
-int ssl3_cert_verify_mac(SSL *ssl, int md_nid, uint8_t *p);
int ssl3_output_cert_chain(SSL *ssl);
const SSL_CIPHER *ssl3_choose_cipher(
SSL *ssl, STACK_OF(SSL_CIPHER) *clnt,
@@ -1075,12 +1061,6 @@
int ssl3_accept(SSL *ssl);
int ssl3_connect(SSL *ssl);
-/* ssl3_record_sequence_update increments the sequence number in |seq|. It
- * returns one on success and zero on wraparound. */
-int ssl3_record_sequence_update(uint8_t *seq, size_t seq_len);
-
-int ssl3_do_change_cipher_spec(SSL *ssl);
-
int ssl3_set_handshake_header(SSL *ssl, int htype, unsigned long len);
int ssl3_handshake_write(SSL *ssl);
@@ -1159,29 +1139,11 @@
int ssl_init_wbio_buffer(SSL *ssl, int push);
void ssl_free_wbio_buffer(SSL *ssl);
-/* tls1_prf computes the TLS PRF function for |ssl| as described in RFC 5246,
- * section 5 and RFC 2246 section 5. It writes |out_len| bytes to |out|, using
- * |secret| as the secret and |label| as the label. |seed1| and |seed2| are
- * concatenated to form the seed parameter. It returns one on success and zero
- * on failure. */
-int tls1_prf(SSL *ssl, uint8_t *out, size_t out_len, const uint8_t *secret,
- size_t secret_len, const char *label, size_t label_len,
- const uint8_t *seed1, size_t seed1_len,
- const uint8_t *seed2, size_t seed2_len);
-
int tls1_change_cipher_state(SSL *ssl, int which);
int tls1_setup_key_block(SSL *ssl);
int tls1_handshake_digest(SSL *ssl, uint8_t *out, size_t out_len);
-int tls1_final_finish_mac(SSL *ssl, const char *str, int slen, uint8_t *p);
-int tls1_cert_verify_mac(SSL *ssl, int md_nid, uint8_t *p);
int tls1_generate_master_secret(SSL *ssl, uint8_t *out, const uint8_t *premaster,
size_t premaster_len);
-int tls1_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len,
- const char *label, size_t label_len,
- const uint8_t *context, size_t context_len,
- int use_context);
-int tls1_alert_code(int code);
-int ssl3_alert_code(int code);
char ssl_early_callback_init(struct ssl_early_callback_ctx *ctx);
@@ -1219,13 +1181,13 @@
#define tlsext_tick_md EVP_sha256
-/* 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
+/* tls_process_ticket processes a session ticket from the client. On success,
+ * it sets |*out_session| to the decrypted session or NULL if the ticket was
+ * rejected. If the ticket was valid, it sets |*out_renew_ticket| to whether
+ * the ticket should be renewed. 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,
+ int *out_renew_ticket, const uint8_t *ticket,
size_t ticket_len, const uint8_t *session_id,
size_t session_id_len);
@@ -1294,9 +1256,13 @@
*
* TODO(davidben): To normalize some DTLS-specific code, move away from using
* the wire version except at API boundaries. */
-uint16_t ssl3_version_from_wire(SSL *ssl, uint16_t wire_version);
+uint16_t ssl3_version_from_wire(const SSL *ssl, uint16_t wire_version);
-uint32_t ssl_get_algorithm_prf(SSL *ssl);
+/* ssl3_protocol_version returns |ssl|'s protocol version. It is an error to
+ * call this function before the version is determined. */
+uint16_t ssl3_protocol_version(const SSL *ssl);
+
+uint32_t ssl_get_algorithm_prf(const SSL *ssl);
int tls1_parse_peer_sigalgs(SSL *ssl, const CBS *sigalgs);
/* tls1_choose_signing_digest returns a digest for use with |ssl|'s private key
diff --git a/src/ssl/pqueue/pqueue.c b/src/ssl/pqueue/pqueue.c
index 14bd9b6..e689761 100644
--- a/src/ssl/pqueue/pqueue.c
+++ b/src/ssl/pqueue/pqueue.c
@@ -69,7 +69,7 @@
pitem *pitem_new(uint8_t prio64be[8], void *data) {
- pitem *item = (pitem *)OPENSSL_malloc(sizeof(pitem));
+ pitem *item = OPENSSL_malloc(sizeof(pitem));
if (item == NULL) {
return NULL;
}
@@ -91,7 +91,7 @@
}
pqueue pqueue_new(void) {
- pqueue_s *pq = (pqueue_s *)OPENSSL_malloc(sizeof(pqueue_s));
+ pqueue_s *pq = OPENSSL_malloc(sizeof(pqueue_s));
if (pq == NULL) {
return NULL;
}
diff --git a/src/ssl/s3_both.c b/src/ssl/s3_both.c
index 01a7e8c..5d364ab 100644
--- a/src/ssl/s3_both.c
+++ b/src/ssl/s3_both.c
@@ -114,7 +114,6 @@
#include <assert.h>
#include <limits.h>
-#include <stdio.h>
#include <string.h>
#include <openssl/buf.h>
@@ -122,7 +121,7 @@
#include <openssl/evp.h>
#include <openssl/mem.h>
#include <openssl/md5.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <openssl/x509.h>
@@ -156,15 +155,15 @@
return 0;
}
-int ssl3_send_finished(SSL *ssl, int a, int b, const char *sender, int slen) {
+int ssl3_send_finished(SSL *ssl, int a, int b) {
uint8_t *p;
int n;
if (ssl->state == a) {
p = ssl_handshake_start(ssl);
- n = ssl->enc_method->final_finish_mac(ssl, sender, slen,
- ssl->s3->tmp.finish_md);
+ n = ssl->s3->enc_method->final_finish_mac(ssl, ssl->server,
+ ssl->s3->tmp.finish_md);
if (n == 0) {
return 0;
}
@@ -202,25 +201,14 @@
/* ssl3_take_mac calculates the Finished MAC for the handshakes messages seen
* so far. */
static void ssl3_take_mac(SSL *ssl) {
- const char *sender;
- int slen;
-
/* If no new cipher setup then return immediately: other functions will set
* the appropriate error. */
if (ssl->s3->tmp.new_cipher == NULL) {
return;
}
- if (ssl->state & SSL_ST_CONNECT) {
- sender = ssl->enc_method->server_finished_label;
- slen = ssl->enc_method->server_finished_label_len;
- } else {
- sender = ssl->enc_method->client_finished_label;
- slen = ssl->enc_method->client_finished_label_len;
- }
-
- ssl->s3->tmp.peer_finish_md_len = ssl->enc_method->final_finish_mac(
- ssl, sender, slen, ssl->s3->tmp.peer_finish_md);
+ ssl->s3->tmp.peer_finish_md_len = ssl->s3->enc_method->final_finish_mac(
+ ssl, !ssl->server, ssl->s3->tmp.peer_finish_md);
}
int ssl3_get_finished(SSL *ssl, int a, int b) {
@@ -250,7 +238,12 @@
goto f_err;
}
- if (CRYPTO_memcmp(p, ssl->s3->tmp.peer_finish_md, finished_len) != 0) {
+ int finished_ret =
+ CRYPTO_memcmp(p, ssl->s3->tmp.peer_finish_md, finished_len);
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ finished_ret = 0;
+#endif
+ if (finished_ret != 0) {
al = SSL_AD_DECRYPT_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED);
goto f_err;
@@ -277,13 +270,6 @@
return 0;
}
-/* for these 2 messages, we need to
- * ssl->enc_read_ctx re-init
- * ssl->s3->read_sequence zero
- * ssl->s3->read_mac_secret re-init
- * ssl->session->read_sym_enc assign
- * ssl->session->read_compression assign
- * ssl->session->read_hash assign */
int ssl3_send_change_cipher_spec(SSL *ssl, int a, int b) {
if (ssl->state == a) {
*((uint8_t *)ssl->init_buf->data) = SSL3_MT_CCS;
@@ -407,7 +393,6 @@
int bytes_read =
ssl3_read_bytes(ssl, SSL3_RT_HANDSHAKE, &p[ssl->init_num], n, 0);
if (bytes_read <= 0) {
- ssl->rwstate = SSL_READING;
*ok = 0;
return bytes_read;
}
@@ -452,7 +437,7 @@
/* 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(ssl)) {
+ if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
EVP_MD_CTX mctx;
unsigned len;
@@ -467,15 +452,15 @@
}
*out_len = len;
} else if (pkey_type == EVP_PKEY_RSA) {
- if (ssl->enc_method->cert_verify_mac(ssl, NID_md5, out) == 0 ||
- ssl->enc_method->cert_verify_mac(ssl, NID_sha1,
- out + MD5_DIGEST_LENGTH) == 0) {
+ if (ssl->s3->enc_method->cert_verify_mac(ssl, NID_md5, out) == 0 ||
+ ssl->s3->enc_method->cert_verify_mac(ssl, NID_sha1,
+ out + MD5_DIGEST_LENGTH) == 0) {
return 0;
}
*out_len = MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH;
*out_md = EVP_md5_sha1();
} else if (pkey_type == EVP_PKEY_EC) {
- if (ssl->enc_method->cert_verify_mac(ssl, NID_sha1, out) == 0) {
+ if (ssl->s3->enc_method->cert_verify_mac(ssl, NID_sha1, out) == 0) {
return 0;
}
*out_len = SHA_DIGEST_LENGTH;
diff --git a/src/ssl/s3_clnt.c b/src/ssl/s3_clnt.c
index 5f68037..6f381cf 100644
--- a/src/ssl/s3_clnt.c
+++ b/src/ssl/s3_clnt.c
@@ -150,7 +150,6 @@
#include <openssl/ssl.h>
#include <assert.h>
-#include <stdio.h>
#include <string.h>
#include <openssl/bn.h>
@@ -163,7 +162,6 @@
#include <openssl/evp.h>
#include <openssl/md5.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
#include <openssl/rand.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
@@ -182,7 +180,6 @@
assert(!ssl->server);
assert(!SSL_IS_DTLS(ssl));
- ERR_clear_error();
ERR_clear_system_error();
if (ssl->info_callback != NULL) {
@@ -191,8 +188,6 @@
cb = ssl->ctx->info_callback;
}
- ssl->in_handshake++;
-
for (;;) {
state = ssl->state;
@@ -388,10 +383,7 @@
}
ssl->init_num = 0;
- ssl->session->cipher = ssl->s3->tmp.new_cipher;
- if (!ssl->enc_method->setup_key_block(ssl) ||
- !ssl->enc_method->change_cipher_state(
- ssl, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
+ if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
ret = -1;
goto end;
}
@@ -424,9 +416,7 @@
case SSL3_ST_CW_FINISHED_A:
case SSL3_ST_CW_FINISHED_B:
ret = ssl3_send_finished(ssl, SSL3_ST_CW_FINISHED_A,
- SSL3_ST_CW_FINISHED_B,
- ssl->enc_method->client_finished_label,
- ssl->enc_method->client_finished_label_len);
+ SSL3_ST_CW_FINISHED_B);
if (ret <= 0) {
goto end;
}
@@ -487,7 +477,7 @@
goto end;
}
- if (!ssl3_do_change_cipher_spec(ssl)) {
+ if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_CLIENT_READ)) {
ret = -1;
goto end;
}
@@ -511,12 +501,11 @@
break;
case SSL3_ST_CW_FLUSH:
- ssl->rwstate = SSL_WRITING;
if (BIO_flush(ssl->wbio) <= 0) {
+ ssl->rwstate = SSL_WRITING;
ret = -1;
goto end;
}
- ssl->rwstate = SSL_NOTHING;
ssl->state = ssl->s3->tmp.next_state;
break;
@@ -581,7 +570,6 @@
}
end:
- ssl->in_handshake--;
BUF_MEM_free(buf);
if (cb != NULL) {
cb(ssl, SSL_CB_CONNECT_EXIT, ret);
@@ -676,13 +664,12 @@
ssl->client_version = max_version;
}
- /* If the configured session has expired or was created at a version higher
- * than our maximum version, drop it. */
+ /* If the configured session has expired or was created at a disabled
+ * version, drop it. */
if (ssl->session != NULL &&
(ssl->session->session_id_length == 0 || ssl->session->not_resumable ||
ssl->session->timeout < (long)(time(NULL) - ssl->session->time) ||
- (!SSL_IS_DTLS(ssl) && ssl->session->ssl_version > ssl->version) ||
- (SSL_IS_DTLS(ssl) && ssl->session->ssl_version < ssl->version))) {
+ !ssl3_is_version_enabled(ssl, ssl->session->ssl_version))) {
SSL_set_session(ssl, NULL);
}
@@ -791,8 +778,8 @@
goto f_err;
}
ssl->version = server_version;
- ssl->enc_method = ssl3_get_enc_method(server_version);
- assert(ssl->enc_method != NULL);
+ ssl->s3->enc_method = ssl3_get_enc_method(server_version);
+ assert(ssl->s3->enc_method != NULL);
/* At this point, the connection's version is known and ssl->version is
* fixed. Begin enforcing the record-layer version. */
ssl->s3->have_version = 1;
@@ -841,8 +828,7 @@
/* If the cipher is disabled then we didn't sent it in the ClientHello, so if
* the server selected it, it's an error. */
if ((c->algorithm_mkey & ct->mask_k) || (c->algorithm_auth & ct->mask_a) ||
- SSL_CIPHER_get_min_version(c) >
- ssl3_version_from_wire(ssl, ssl->version)) {
+ SSL_CIPHER_get_min_version(c) > ssl3_protocol_version(ssl)) {
al = SSL_AD_ILLEGAL_PARAMETER;
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
goto f_err;
@@ -867,6 +853,8 @@
OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_VERSION_NOT_RETURNED);
goto f_err;
}
+ } else {
+ ssl->session->cipher = c;
}
ssl->s3->tmp.new_cipher = c;
@@ -878,7 +866,7 @@
/* If doing a full handshake with TLS 1.2, the server may request a client
* certificate which requires hashing the handshake transcript under a
* different hash. Otherwise, the handshake buffer may be released. */
- if (!SSL_USE_SIGALGS(ssl) || ssl->hit) {
+ if (ssl->hit || ssl3_protocol_version(ssl) < TLS1_2_VERSION) {
ssl3_free_handshake_buffer(ssl);
}
@@ -1060,19 +1048,16 @@
int ssl3_get_server_key_exchange(SSL *ssl) {
EVP_MD_CTX md_ctx;
int al, ok;
- long n, alg_k, alg_a;
EVP_PKEY *pkey = NULL;
- const EVP_MD *md = NULL;
DH *dh = NULL;
EC_KEY *ecdh = NULL;
EC_POINT *srvr_ecpoint = NULL;
- CBS server_key_exchange, server_key_exchange_orig, parameter;
/* use same message size as in ssl3_get_certificate_request() as
* ServerKeyExchange message may be skipped */
- n = ssl->method->ssl_get_message(ssl, SSL3_ST_CR_KEY_EXCH_A,
- SSL3_ST_CR_KEY_EXCH_B, -1, ssl->max_cert_list,
- ssl_hash_message, &ok);
+ long n = ssl->method->ssl_get_message(
+ ssl, SSL3_ST_CR_KEY_EXCH_A, SSL3_ST_CR_KEY_EXCH_B, -1, ssl->max_cert_list,
+ ssl_hash_message, &ok);
if (!ok) {
return n;
}
@@ -1097,11 +1082,12 @@
}
/* Retain a copy of the original CBS to compute the signature over. */
+ CBS server_key_exchange;
CBS_init(&server_key_exchange, ssl->init_msg, n);
- server_key_exchange_orig = server_key_exchange;
+ CBS server_key_exchange_orig = server_key_exchange;
- alg_k = ssl->s3->tmp.new_cipher->algorithm_mkey;
- alg_a = ssl->s3->tmp.new_cipher->algorithm_auth;
+ uint32_t alg_k = ssl->s3->tmp.new_cipher->algorithm_mkey;
+ uint32_t alg_a = ssl->s3->tmp.new_cipher->algorithm_auth;
EVP_MD_CTX_init(&md_ctx);
if (alg_a & SSL_aPSK) {
@@ -1224,6 +1210,7 @@
/* At this point, |server_key_exchange| contains the signature, if any, while
* |server_key_exchange_orig| contains the entire message. From that, derive
* a CBS containing just the parameter. */
+ CBS parameter;
CBS_init(¶meter, CBS_data(&server_key_exchange_orig),
CBS_len(&server_key_exchange_orig) - CBS_len(&server_key_exchange));
@@ -1234,7 +1221,8 @@
goto err;
}
- if (SSL_USE_SIGALGS(ssl)) {
+ const EVP_MD *md = NULL;
+ if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
uint8_t hash, signature;
if (!CBS_get_u8(&server_key_exchange, &hash) ||
!CBS_get_u8(&server_key_exchange, &signature)) {
@@ -1261,15 +1249,20 @@
goto f_err;
}
- if (!EVP_DigestVerifyInit(&md_ctx, NULL, md, NULL, pkey) ||
- !EVP_DigestVerifyUpdate(&md_ctx, ssl->s3->client_random,
- SSL3_RANDOM_SIZE) ||
- !EVP_DigestVerifyUpdate(&md_ctx, ssl->s3->server_random,
- SSL3_RANDOM_SIZE) ||
- !EVP_DigestVerifyUpdate(&md_ctx, CBS_data(¶meter),
- CBS_len(¶meter)) ||
- !EVP_DigestVerifyFinal(&md_ctx, CBS_data(&signature),
- CBS_len(&signature))) {
+ int sig_ok = EVP_DigestVerifyInit(&md_ctx, NULL, md, NULL, pkey) &&
+ EVP_DigestVerifyUpdate(&md_ctx, ssl->s3->client_random,
+ SSL3_RANDOM_SIZE) &&
+ EVP_DigestVerifyUpdate(&md_ctx, ssl->s3->server_random,
+ SSL3_RANDOM_SIZE) &&
+ EVP_DigestVerifyUpdate(&md_ctx, CBS_data(¶meter),
+ CBS_len(¶meter)) &&
+ EVP_DigestVerifyFinal(&md_ctx, CBS_data(&signature),
+ CBS_len(&signature));
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ sig_ok = 1;
+ ERR_clear_error();
+#endif
+ if (!sig_ok) {
/* bad signature */
al = SSL_AD_DECRYPT_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE);
@@ -1306,17 +1299,12 @@
int ssl3_get_certificate_request(SSL *ssl) {
int ok, ret = 0;
- unsigned long n;
X509_NAME *xn = NULL;
STACK_OF(X509_NAME) *ca_sk = NULL;
- CBS cbs;
- CBS certificate_types;
- CBS certificate_authorities;
- const uint8_t *data;
- n = ssl->method->ssl_get_message(ssl, SSL3_ST_CR_CERT_REQ_A,
- SSL3_ST_CR_CERT_REQ_B, -1, ssl->max_cert_list,
- ssl_hash_message, &ok);
+ long n = ssl->method->ssl_get_message(
+ ssl, SSL3_ST_CR_CERT_REQ_A, SSL3_ST_CR_CERT_REQ_B, -1, ssl->max_cert_list,
+ ssl_hash_message, &ok);
if (!ok) {
return n;
@@ -1334,10 +1322,11 @@
if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE_REQUEST) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
- OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_MESSAGE_TYPE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
goto err;
}
+ CBS cbs;
CBS_init(&cbs, ssl->init_msg, n);
ca_sk = sk_X509_NAME_new(ca_dn_cmp);
@@ -1347,6 +1336,7 @@
}
/* get the certificate types */
+ CBS certificate_types;
if (!CBS_get_u8_length_prefixed(&cbs, &certificate_types)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
@@ -1359,7 +1349,7 @@
goto err;
}
- if (SSL_USE_SIGALGS(ssl)) {
+ if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
CBS supported_signature_algorithms;
if (!CBS_get_u16_length_prefixed(&cbs, &supported_signature_algorithms) ||
!tls1_parse_peer_sigalgs(ssl, &supported_signature_algorithms)) {
@@ -1370,6 +1360,7 @@
}
/* get the CA RDNs */
+ CBS certificate_authorities;
if (!CBS_get_u16_length_prefixed(&cbs, &certificate_authorities)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_LENGTH_MISMATCH);
@@ -1385,25 +1376,13 @@
goto err;
}
- data = CBS_data(&distinguished_name);
-
+ const uint8_t *data = CBS_data(&distinguished_name);
/* A u16 length cannot overflow a long. */
xn = d2i_X509_NAME(NULL, &data, (long)CBS_len(&distinguished_name));
- if (xn == NULL) {
+ if (xn == NULL ||
+ data != CBS_data(&distinguished_name) + CBS_len(&distinguished_name)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB);
- goto err;
- }
-
- if (!CBS_skip(&distinguished_name, data - CBS_data(&distinguished_name))) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- if (CBS_len(&distinguished_name) != 0) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- OPENSSL_PUT_ERROR(SSL, SSL_R_CA_DN_LENGTH_MISMATCH);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto err;
}
@@ -1411,6 +1390,7 @@
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
+ xn = NULL;
}
/* we should setup a certificate to return.... */
@@ -1422,6 +1402,7 @@
ret = 1;
err:
+ X509_NAME_free(xn);
sk_X509_NAME_pop_free(ca_sk, X509_NAME_free);
return ret;
}
@@ -1755,8 +1736,8 @@
}
ssl->state = SSL3_ST_CW_KEY_EXCH_B;
- ssl->session->master_key_length = ssl->enc_method->generate_master_secret(
- ssl, ssl->session->master_key, pms, pms_len);
+ ssl->session->master_key_length =
+ tls1_generate_master_secret(ssl, ssl->session->master_key, pms, pms_len);
if (ssl->session->master_key_length == 0) {
goto err;
}
@@ -1768,6 +1749,7 @@
return ssl_do_write(ssl);
err:
+ CBB_cleanup(&cbb);
if (pms != NULL) {
OPENSSL_cleanse(pms, pms_len);
OPENSSL_free(pms);
@@ -1794,7 +1776,7 @@
if (ssl->state == SSL3_ST_CW_CERT_VRFY_A) {
/* Select and write out the digest type in TLS 1.2. */
const EVP_MD *md = NULL;
- if (SSL_USE_SIGALGS(ssl)) {
+ if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
md = tls1_choose_signing_digest(ssl);
if (!tls12_add_sigandhash(ssl, &cbb, md)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
@@ -1828,7 +1810,8 @@
/* Skip over the already written signature algorithm and retry the
* signature. */
uint8_t *ptr;
- if ((SSL_USE_SIGALGS(ssl) && !CBB_did_write(&cbb, 2)) ||
+ if ((ssl3_protocol_version(ssl) >= TLS1_2_VERSION &&
+ !CBB_did_write(&cbb, 2)) ||
!CBB_add_u16_length_prefixed(&cbb, &child) ||
!CBB_reserve(&child, &ptr, max_sig_len)) {
goto err;
@@ -1839,10 +1822,8 @@
switch (sign_result) {
case ssl_private_key_success:
- ssl->rwstate = SSL_NOTHING;
break;
case ssl_private_key_failure:
- ssl->rwstate = SSL_NOTHING;
goto err;
case ssl_private_key_retry:
ssl->rwstate = SSL_PRIVATE_KEY_OPERATION;
@@ -1872,23 +1853,18 @@
}
int ssl3_send_client_certificate(SSL *ssl) {
- X509 *x509 = NULL;
- EVP_PKEY *pkey = NULL;
- int i;
-
if (ssl->state == SSL3_ST_CW_CERT_A) {
- /* Let cert callback update client certificates if required */
+ /* Call cert_cb to update the certificate. */
if (ssl->cert->cert_cb) {
- i = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
- if (i < 0) {
+ int ret = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
+ if (ret < 0) {
ssl->rwstate = SSL_X509_LOOKUP;
return -1;
}
- if (i == 0) {
+ if (ret == 0) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return 0;
+ return -1;
}
- ssl->rwstate = SSL_NOTHING;
}
if (ssl3_has_client_certificate(ssl)) {
@@ -1898,52 +1874,42 @@
}
}
- /* We need to get a client cert */
if (ssl->state == SSL3_ST_CW_CERT_B) {
- /* If we get an error, we need to:
- * ssl->rwstate=SSL_X509_LOOKUP; return(-1);
- * We then get retried later */
- i = ssl_do_client_cert_cb(ssl, &x509, &pkey);
- if (i < 0) {
+ /* Call client_cert_cb to update the certificate. */
+ X509 *x509 = NULL;
+ EVP_PKEY *pkey = NULL;
+ int ret = ssl_do_client_cert_cb(ssl, &x509, &pkey);
+ if (ret < 0) {
ssl->rwstate = SSL_X509_LOOKUP;
return -1;
}
- ssl->rwstate = SSL_NOTHING;
- if (i == 1 && pkey != NULL && x509 != NULL) {
- ssl->state = SSL3_ST_CW_CERT_B;
- if (!SSL_use_certificate(ssl, x509) || !SSL_use_PrivateKey(ssl, pkey)) {
- i = 0;
- }
- } else if (i == 1) {
- i = 0;
- OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK);
- }
+ int setup_error = ret == 1 && (!SSL_use_certificate(ssl, x509) ||
+ !SSL_use_PrivateKey(ssl, pkey));
X509_free(x509);
EVP_PKEY_free(pkey);
- if (i && !ssl3_has_client_certificate(ssl)) {
- i = 0;
- }
- if (i == 0) {
- if (ssl->version == SSL3_VERSION) {
- ssl->s3->tmp.cert_req = 0;
- ssl3_send_alert(ssl, SSL3_AL_WARNING, SSL_AD_NO_CERTIFICATE);
- return 1;
- } else {
- ssl->s3->tmp.cert_req = 2;
- /* There is no client certificate, so the handshake buffer may be
- * released. */
- ssl3_free_handshake_buffer(ssl);
- }
+ if (setup_error) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return -1;
}
- /* Ok, we have a cert */
ssl->state = SSL3_ST_CW_CERT_C;
}
if (ssl->state == SSL3_ST_CW_CERT_C) {
- if (ssl->s3->tmp.cert_req == 2) {
- /* Send an empty Certificate message. */
+ if (!ssl3_has_client_certificate(ssl)) {
+ /* Without a client certificate, the handshake buffer may be released. */
+ ssl3_free_handshake_buffer(ssl);
+
+ if (ssl->version == SSL3_VERSION) {
+ /* In SSL 3.0, send no certificate by skipping both messages. */
+ ssl->s3->tmp.cert_req = 0;
+ ssl3_send_alert(ssl, SSL3_AL_WARNING, SSL_AD_NO_CERTIFICATE);
+ return 1;
+ }
+
+ /* In TLS, send an empty Certificate message. */
+ ssl->s3->tmp.cert_req = 2;
uint8_t *p = ssl_handshake_start(ssl);
l2n3(0, p);
if (!ssl_set_handshake_header(ssl, SSL3_MT_CERTIFICATE, 3)) {
@@ -1955,7 +1921,7 @@
ssl->state = SSL3_ST_CW_CERT_D;
}
- /* SSL3_ST_CW_CERT_D */
+ assert(ssl->state == SSL3_ST_CW_CERT_D);
return ssl_do_write(ssl);
}
@@ -1967,7 +1933,7 @@
assert(ssl->state == SSL3_ST_CW_NEXT_PROTO_A);
static const uint8_t kZero[32] = {0};
- size_t padding_len = 32 - ((ssl->next_proto_negotiated_len + 2) % 32);
+ size_t padding_len = 32 - ((ssl->s3->next_proto_negotiated_len + 2) % 32);
CBB cbb, child;
size_t length;
@@ -1975,8 +1941,8 @@
if (!CBB_init_fixed(&cbb, ssl_handshake_start(ssl),
ssl->init_buf->max - SSL_HM_HEADER_LENGTH(ssl)) ||
!CBB_add_u8_length_prefixed(&cbb, &child) ||
- !CBB_add_bytes(&child, ssl->next_proto_negotiated,
- ssl->next_proto_negotiated_len) ||
+ !CBB_add_bytes(&child, ssl->s3->next_proto_negotiated,
+ ssl->s3->next_proto_negotiated_len) ||
!CBB_add_u8_length_prefixed(&cbb, &child) ||
!CBB_add_bytes(&child, kZero, padding_len) ||
!CBB_finish(&cbb, NULL, &length) ||
@@ -2013,7 +1979,6 @@
ssl->rwstate = SSL_CHANNEL_ID_LOOKUP;
return -1;
}
- ssl->rwstate = SSL_NOTHING;
EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(ssl->tlsext_channel_id_private);
if (ec_key == NULL) {
@@ -2075,7 +2040,15 @@
if (ssl->ctx->client_cert_cb == NULL) {
return 0;
}
- return ssl->ctx->client_cert_cb(ssl, out_x509, out_pkey);
+
+ int ret = ssl->ctx->client_cert_cb(ssl, out_x509, out_pkey);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ assert(*out_x509 != NULL);
+ assert(*out_pkey != NULL);
+ return 1;
}
int ssl3_verify_server_cert(SSL *ssl) {
diff --git a/src/ssl/s3_enc.c b/src/ssl/s3_enc.c
index 89d861a..04aa08c 100644
--- a/src/ssl/s3_enc.c
+++ b/src/ssl/s3_enc.c
@@ -136,39 +136,24 @@
#include <openssl/ssl.h>
#include <assert.h>
-#include <stdio.h>
#include <string.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
#include <openssl/md5.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include "internal.h"
-static const uint8_t ssl3_pad_1[48] = {
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-};
+static int ssl3_handshake_mac(SSL *ssl, int md_nid, const char *sender,
+ size_t sender_len, uint8_t *p);
-static const uint8_t ssl3_pad_2[48] = {
- 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
- 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
- 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
- 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
-};
-
-static int ssl3_handshake_mac(SSL *ssl, int md_nid, const char *sender, int len,
- uint8_t *p);
-
-int ssl3_prf(SSL *ssl, 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) {
+static int ssl3_prf(const SSL *ssl, 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) {
EVP_MD_CTX md5;
EVP_MD_CTX sha1;
uint8_t buf[16], smd[SHA_DIGEST_LENGTH];
@@ -309,20 +294,23 @@
return 1;
}
-int ssl3_cert_verify_mac(SSL *ssl, int md_nid, uint8_t *p) {
+static int ssl3_cert_verify_mac(SSL *ssl, int md_nid, uint8_t *p) {
return ssl3_handshake_mac(ssl, md_nid, NULL, 0, p);
}
-int ssl3_final_finish_mac(SSL *ssl, const char *sender, int len, uint8_t *p) {
+static int ssl3_final_finish_mac(SSL *ssl, int from_server, uint8_t *out) {
+ const char *sender = from_server ? SSL3_MD_SERVER_FINISHED_CONST
+ : SSL3_MD_CLIENT_FINISHED_CONST;
+ const size_t sender_len = 4;
int ret, sha1len;
- ret = ssl3_handshake_mac(ssl, NID_md5, sender, len, p);
+ ret = ssl3_handshake_mac(ssl, NID_md5, sender, sender_len, out);
if (ret == 0) {
return 0;
}
- p += ret;
+ out += ret;
- sha1len = ssl3_handshake_mac(ssl, NID_sha1, sender, len, p);
+ sha1len = ssl3_handshake_mac(ssl, NID_sha1, sender, sender_len, out);
if (sha1len == 0) {
return 0;
}
@@ -331,8 +319,8 @@
return ret;
}
-static int ssl3_handshake_mac(SSL *ssl, int md_nid, const char *sender, int len,
- uint8_t *p) {
+static int ssl3_handshake_mac(SSL *ssl, int md_nid, const char *sender,
+ size_t sender_len, uint8_t *p) {
unsigned int ret;
size_t npad, n;
unsigned int i;
@@ -356,15 +344,29 @@
return 0;
}
+ static const uint8_t kPad1[48] = {
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ };
+
+ static const uint8_t kPad2[48] = {
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ };
+
n = EVP_MD_CTX_size(&ctx);
npad = (48 / n) * n;
if (sender != NULL) {
- EVP_DigestUpdate(&ctx, sender, len);
+ EVP_DigestUpdate(&ctx, sender, sender_len);
}
EVP_DigestUpdate(&ctx, ssl->session->master_key,
ssl->session->master_key_length);
- EVP_DigestUpdate(&ctx, ssl3_pad_1, npad);
+ EVP_DigestUpdate(&ctx, kPad1, npad);
EVP_DigestFinal_ex(&ctx, md_buf, &i);
if (!EVP_DigestInit_ex(&ctx, EVP_MD_CTX_md(&ctx), NULL)) {
@@ -374,7 +376,7 @@
}
EVP_DigestUpdate(&ctx, ssl->session->master_key,
ssl->session->master_key_length);
- EVP_DigestUpdate(&ctx, ssl3_pad_2, npad);
+ EVP_DigestUpdate(&ctx, kPad2, npad);
EVP_DigestUpdate(&ctx, md_buf, i);
EVP_DigestFinal_ex(&ctx, p, &ret);
@@ -383,114 +385,10 @@
return ret;
}
-int ssl3_record_sequence_update(uint8_t *seq, size_t seq_len) {
- size_t i;
- for (i = seq_len - 1; i < seq_len; i--) {
- ++seq[i];
- if (seq[i] != 0) {
- return 1;
- }
- }
- OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
- return 0;
-}
-int ssl3_alert_code(int code) {
- switch (code) {
- case SSL_AD_CLOSE_NOTIFY:
- return SSL3_AD_CLOSE_NOTIFY;
- case SSL_AD_UNEXPECTED_MESSAGE:
- return SSL3_AD_UNEXPECTED_MESSAGE;
-
- case SSL_AD_BAD_RECORD_MAC:
- return SSL3_AD_BAD_RECORD_MAC;
-
- case SSL_AD_DECRYPTION_FAILED:
- return SSL3_AD_BAD_RECORD_MAC;
-
- case SSL_AD_RECORD_OVERFLOW:
- return SSL3_AD_BAD_RECORD_MAC;
-
- case SSL_AD_DECOMPRESSION_FAILURE:
- return SSL3_AD_DECOMPRESSION_FAILURE;
-
- case SSL_AD_HANDSHAKE_FAILURE:
- return SSL3_AD_HANDSHAKE_FAILURE;
-
- case SSL_AD_NO_CERTIFICATE:
- return SSL3_AD_NO_CERTIFICATE;
-
- case SSL_AD_BAD_CERTIFICATE:
- return SSL3_AD_BAD_CERTIFICATE;
-
- case SSL_AD_UNSUPPORTED_CERTIFICATE:
- return SSL3_AD_UNSUPPORTED_CERTIFICATE;
-
- case SSL_AD_CERTIFICATE_REVOKED:
- return SSL3_AD_CERTIFICATE_REVOKED;
-
- case SSL_AD_CERTIFICATE_EXPIRED:
- return SSL3_AD_CERTIFICATE_EXPIRED;
-
- case SSL_AD_CERTIFICATE_UNKNOWN:
- return SSL3_AD_CERTIFICATE_UNKNOWN;
-
- case SSL_AD_ILLEGAL_PARAMETER:
- return SSL3_AD_ILLEGAL_PARAMETER;
-
- case SSL_AD_UNKNOWN_CA:
- return SSL3_AD_BAD_CERTIFICATE;
-
- case SSL_AD_ACCESS_DENIED:
- return SSL3_AD_HANDSHAKE_FAILURE;
-
- case SSL_AD_DECODE_ERROR:
- return SSL3_AD_HANDSHAKE_FAILURE;
-
- case SSL_AD_DECRYPT_ERROR:
- return SSL3_AD_HANDSHAKE_FAILURE;
-
- case SSL_AD_EXPORT_RESTRICTION:
- return SSL3_AD_HANDSHAKE_FAILURE;
-
- case SSL_AD_PROTOCOL_VERSION:
- return SSL3_AD_HANDSHAKE_FAILURE;
-
- case SSL_AD_INSUFFICIENT_SECURITY:
- return SSL3_AD_HANDSHAKE_FAILURE;
-
- case SSL_AD_INTERNAL_ERROR:
- return SSL3_AD_HANDSHAKE_FAILURE;
-
- case SSL_AD_USER_CANCELLED:
- return SSL3_AD_HANDSHAKE_FAILURE;
-
- case SSL_AD_NO_RENEGOTIATION:
- return -1; /* Don't send it. */
-
- case SSL_AD_UNSUPPORTED_EXTENSION:
- return SSL3_AD_HANDSHAKE_FAILURE;
-
- case SSL_AD_CERTIFICATE_UNOBTAINABLE:
- return SSL3_AD_HANDSHAKE_FAILURE;
-
- case SSL_AD_UNRECOGNIZED_NAME:
- return SSL3_AD_HANDSHAKE_FAILURE;
-
- case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE:
- return SSL3_AD_HANDSHAKE_FAILURE;
-
- case SSL_AD_BAD_CERTIFICATE_HASH_VALUE:
- return SSL3_AD_HANDSHAKE_FAILURE;
-
- case SSL_AD_UNKNOWN_PSK_IDENTITY:
- return TLS1_AD_UNKNOWN_PSK_IDENTITY;
-
- case SSL_AD_INAPPROPRIATE_FALLBACK:
- return SSL3_AD_INAPPROPRIATE_FALLBACK;
-
- default:
- return -1;
- }
-}
+const SSL3_ENC_METHOD SSLv3_enc_data = {
+ ssl3_prf,
+ ssl3_final_finish_mac,
+ ssl3_cert_verify_mac,
+};
diff --git a/src/ssl/s3_lib.c b/src/ssl/s3_lib.c
index 64f9f8c..7df046f 100644
--- a/src/ssl/s3_lib.c
+++ b/src/ssl/s3_lib.c
@@ -149,7 +149,6 @@
#include <openssl/ssl.h>
#include <assert.h>
-#include <stdio.h>
#include <string.h>
#include <openssl/buf.h>
@@ -158,25 +157,11 @@
#include <openssl/err.h>
#include <openssl/md5.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include "internal.h"
-const SSL3_ENC_METHOD SSLv3_enc_data = {
- ssl3_prf,
- tls1_setup_key_block,
- tls1_generate_master_secret,
- tls1_change_cipher_state,
- ssl3_final_finish_mac,
- ssl3_cert_verify_mac,
- SSL3_MD_CLIENT_FINISHED_CONST, 4,
- SSL3_MD_SERVER_FINISHED_CONST, 4,
- ssl3_alert_code,
- tls1_export_keying_material,
- 0,
-};
-
int ssl3_supports_cipher(const SSL_CIPHER *cipher) {
return 1;
}
@@ -211,11 +196,11 @@
ssl->s3 = s3;
- /* Set the version to the highest supported version for TLS. This controls the
- * initial state of |ssl->enc_method| and what the API reports as the version
- * prior to negotiation.
+ /* Set the version to the highest supported version.
*
- * TODO(davidben): This is fragile and confusing. */
+ * TODO(davidben): Move this field into |s3|, have it store the normalized
+ * protocol version, and implement this pre-negotiation quirk in |SSL_version|
+ * at the API boundary rather than in internal state. */
ssl->version = TLS1_2_VERSION;
return 1;
err:
@@ -239,7 +224,10 @@
OPENSSL_free(ssl->s3->tmp.peer_psk_identity_hint);
ssl3_free_handshake_buffer(ssl);
ssl3_free_handshake_hash(ssl);
+ OPENSSL_free(ssl->s3->next_proto_negotiated);
OPENSSL_free(ssl->s3->alpn_selected);
+ SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx);
+ SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx);
OPENSSL_cleanse(ssl->s3, sizeof *ssl->s3);
OPENSSL_free(ssl->s3);
@@ -262,7 +250,7 @@
return 0;
}
-int SSL_need_rsa(const SSL *ssl) {
+int SSL_need_tmp_RSA(const SSL *ssl) {
return 0;
}
@@ -322,23 +310,28 @@
return 1;
}
+static int is_p256_key(EVP_PKEY *private_key) {
+ const EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(private_key);
+ return ec_key != NULL &&
+ EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)) ==
+ NID_X9_62_prime256v1;
+}
+
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) {
+ if (!is_p256_key(private_key)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256);
return 0;
}
+
EVP_PKEY_free(ctx->tlsext_channel_id_private);
ctx->tlsext_channel_id_private = EVP_PKEY_up_ref(private_key);
+ ctx->tlsext_channel_id_enabled = 1;
+
return 1;
}
int SSL_set1_tls_channel_id(SSL *ssl, EVP_PKEY *private_key) {
- EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(private_key);
- if (ec_key == NULL ||
- EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)) !=
- NID_X9_62_prime256v1) {
+ if (!is_p256_key(private_key)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256);
return 0;
}
@@ -365,7 +358,9 @@
if (name == NULL) {
return 1;
}
- if (strlen(name) > TLSEXT_MAXLEN_host_name) {
+
+ size_t len = strlen(name);
+ if (len == 0 || len > TLSEXT_MAXLEN_host_name) {
OPENSSL_PUT_ERROR(SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME);
return 0;
}
@@ -452,17 +447,15 @@
return ssl->cipher_list;
}
- if (ssl->version >= TLS1_1_VERSION && ssl->ctx != NULL &&
- ssl->ctx->cipher_list_tls11 != NULL) {
+ if (ssl->version >= TLS1_1_VERSION && ssl->ctx->cipher_list_tls11 != NULL) {
return ssl->ctx->cipher_list_tls11;
}
- if (ssl->version >= TLS1_VERSION && ssl->ctx != NULL &&
- ssl->ctx->cipher_list_tls10 != NULL) {
+ if (ssl->version >= TLS1_VERSION && ssl->ctx->cipher_list_tls10 != NULL) {
return ssl->ctx->cipher_list_tls10;
}
- if (ssl->ctx != NULL && ssl->ctx->cipher_list != NULL) {
+ if (ssl->ctx->cipher_list != NULL) {
return ssl->ctx->cipher_list;
}
@@ -505,8 +498,7 @@
ok = 1;
/* Check the TLS version. */
- if (SSL_CIPHER_get_min_version(c) >
- ssl3_version_from_wire(ssl, ssl->version)) {
+ if (SSL_CIPHER_get_min_version(c) > ssl3_protocol_version(ssl)) {
ok = 0;
}
@@ -578,10 +570,10 @@
/* If we are using default SHA1+MD5 algorithms switch to new SHA256 PRF and
* handshake macs if required. */
-uint32_t ssl_get_algorithm_prf(SSL *ssl) {
+uint32_t ssl_get_algorithm_prf(const SSL *ssl) {
uint32_t algorithm_prf = ssl->s3->tmp.new_cipher->algorithm_prf;
- if (ssl->enc_method->enc_flags & SSL_ENC_FLAG_SHA256_PRF &&
- algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT) {
+ if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT &&
+ ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
return SSL_HANDSHAKE_MAC_SHA256;
}
return algorithm_prf;
diff --git a/src/ssl/s3_pkt.c b/src/ssl/s3_pkt.c
index 4c1133c..d9c21d4 100644
--- a/src/ssl/s3_pkt.c
+++ b/src/ssl/s3_pkt.c
@@ -110,7 +110,6 @@
#include <assert.h>
#include <limits.h>
-#include <stdio.h>
#include <string.h>
#include <openssl/buf.h>
@@ -183,6 +182,8 @@
}
int ssl3_write_app_data(SSL *ssl, const void *buf, int len) {
+ assert(!SSL_in_init(ssl) || SSL_in_false_start(ssl));
+
return ssl3_write_bytes(ssl, SSL3_RT_APPLICATION_DATA, buf, len);
}
@@ -190,25 +191,12 @@
* not all data has been sent or non-blocking IO. */
int ssl3_write_bytes(SSL *ssl, int type, const void *buf_, int len) {
const uint8_t *buf = buf_;
- unsigned int tot, n, nw;
- int i;
+ unsigned tot, n, nw;
- ssl->rwstate = SSL_NOTHING;
assert(ssl->s3->wnum <= INT_MAX);
tot = ssl->s3->wnum;
ssl->s3->wnum = 0;
- if (!ssl->in_handshake && SSL_in_init(ssl) && !SSL_in_false_start(ssl)) {
- i = ssl->handshake_func(ssl);
- if (i < 0) {
- return i;
- }
- if (i == 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
- return -1;
- }
- }
-
/* Ensure that if we end up with a smaller value of data to write out than
* the the original len from a write which didn't complete for non-blocking
* I/O and also somehow ended up avoiding the check for this in
@@ -232,19 +220,19 @@
nw = n;
}
- i = do_ssl3_write(ssl, type, &buf[tot], nw);
- if (i <= 0) {
+ int ret = do_ssl3_write(ssl, type, &buf[tot], nw);
+ if (ret <= 0) {
ssl->s3->wnum = tot;
- return i;
+ return ret;
}
- if (i == (int)n || (type == SSL3_RT_APPLICATION_DATA &&
- (ssl->mode & SSL_MODE_ENABLE_PARTIAL_WRITE))) {
- return tot + i;
+ if (ret == (int)n || (type == SSL3_RT_APPLICATION_DATA &&
+ (ssl->mode & SSL_MODE_ENABLE_PARTIAL_WRITE))) {
+ return tot + ret;
}
- n -= i;
- tot += i;
+ n -= ret;
+ tot += ret;
}
}
@@ -315,6 +303,7 @@
}
int ssl3_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek) {
+ assert(!SSL_in_init(ssl));
return ssl3_read_bytes(ssl, SSL3_RT_APPLICATION_DATA, buf, len, peek);
}
@@ -387,26 +376,7 @@
return -1;
}
- /* This may require multiple iterations. False Start will cause
- * |ssl->handshake_func| to signal success one step early, but the handshake
- * must be completely finished before other modes are accepted.
- *
- * TODO(davidben): Move this check up to a higher level. */
- while (!ssl->in_handshake && SSL_in_init(ssl)) {
- assert(type == SSL3_RT_APPLICATION_DATA);
- i = ssl->handshake_func(ssl);
- if (i < 0) {
- return i;
- }
- if (i == 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
- return -1;
- }
- }
-
start:
- ssl->rwstate = SSL_NOTHING;
-
/* ssl->s3->rrec.type - is the type of record
* ssl->s3->rrec.data - data
* ssl->s3->rrec.off - offset into 'data' for next read
@@ -427,7 +397,6 @@
* 'peek' mode) */
if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) {
rr->length = 0;
- ssl->rwstate = SSL_NOTHING;
return 0;
}
@@ -437,7 +406,7 @@
/* Make sure that we are not getting application data when we are doing a
* handshake for the first time. */
if (SSL_in_init(ssl) && type == SSL3_RT_APPLICATION_DATA &&
- ssl->aead_read_ctx == NULL) {
+ ssl->s3->aead_read_ctx == NULL) {
/* TODO(davidben): Is this check redundant with the handshake_func
* check? */
al = SSL_AD_UNEXPECTED_MESSAGE;
@@ -546,11 +515,10 @@
goto start;
}
- /* If an alert record, process one alert out of the record. Note that we allow
- * a single record to contain multiple alerts. */
+ /* If an alert record, process the alert. */
if (rr->type == SSL3_RT_ALERT) {
- /* Alerts may not be fragmented. */
- if (rr->length < 2) {
+ /* Alerts records may not contain fragmented or multiple alerts. */
+ if (rr->length != 2) {
al = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT);
goto f_err;
@@ -577,25 +545,12 @@
}
if (alert_level == SSL3_AL_WARNING) {
- ssl->s3->warn_alert = alert_descr;
if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
+ ssl->s3->clean_shutdown = 1;
ssl->shutdown |= SSL_RECEIVED_SHUTDOWN;
return 0;
}
- /* This is a warning but we receive it if we requested renegotiation and
- * the peer denied it. Terminate with a fatal alert because if
- * application tried to renegotiatie it presumably had a good reason and
- * expects it to succeed.
- *
- * In future we might have a renegotiation where we don't care if the
- * peer refused it where we carry on. */
- else if (alert_descr == SSL_AD_NO_RENEGOTIATION) {
- al = SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION);
- goto f_err;
- }
-
ssl->s3->warning_alert_count++;
if (ssl->s3->warning_alert_count > kMaxWarningAlerts) {
al = SSL_AD_UNEXPECTED_MESSAGE;
@@ -605,8 +560,6 @@
} else if (alert_level == SSL3_AL_FATAL) {
char tmp[16];
- ssl->rwstate = SSL_NOTHING;
- ssl->s3->fatal_alert = 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);
@@ -637,46 +590,7 @@
return -1;
}
-int ssl3_do_change_cipher_spec(SSL *ssl) {
- int i;
-
- if (ssl->state & SSL_ST_ACCEPT) {
- i = SSL3_CHANGE_CIPHER_SERVER_READ;
- } else {
- i = SSL3_CHANGE_CIPHER_CLIENT_READ;
- }
-
- if (ssl->s3->tmp.key_block == NULL) {
- if (ssl->session == NULL || ssl->session->master_key_length == 0) {
- /* might happen if dtls1_read_bytes() calls this */
- OPENSSL_PUT_ERROR(SSL, SSL_R_CCS_RECEIVED_EARLY);
- return 0;
- }
-
- ssl->session->cipher = ssl->s3->tmp.new_cipher;
- if (!ssl->enc_method->setup_key_block(ssl)) {
- return 0;
- }
- }
-
- if (!ssl->enc_method->change_cipher_state(ssl, i)) {
- return 0;
- }
-
- return 1;
-}
-
int ssl3_send_alert(SSL *ssl, int level, int desc) {
- /* Map tls/ssl alert value to correct one */
- desc = ssl->enc_method->alert_value(desc);
- if (ssl->version == SSL3_VERSION && desc == SSL_AD_PROTOCOL_VERSION) {
- /* SSL 3.0 does not have protocol_version alerts */
- desc = SSL_AD_HANDSHAKE_FAILURE;
- }
- if (desc < 0) {
- return -1;
- }
-
/* If a fatal one, remove from cache */
if (level == 2 && ssl->session != NULL) {
SSL_CTX_remove_session(ssl->ctx, ssl->session);
@@ -697,36 +611,34 @@
}
int ssl3_dispatch_alert(SSL *ssl) {
- int i, j;
- void (*cb)(const SSL *ssl, int type, int value) = NULL;
-
ssl->s3->alert_dispatch = 0;
- i = do_ssl3_write(ssl, SSL3_RT_ALERT, &ssl->s3->send_alert[0], 2);
- if (i <= 0) {
+ int ret = do_ssl3_write(ssl, SSL3_RT_ALERT, &ssl->s3->send_alert[0], 2);
+ if (ret <= 0) {
ssl->s3->alert_dispatch = 1;
- } else {
- /* Alert sent to BIO. If it is important, flush it now. If the message
- * does not get sent due to non-blocking IO, we will not worry too much. */
- if (ssl->s3->send_alert[0] == SSL3_AL_FATAL) {
- BIO_flush(ssl->wbio);
- }
-
- if (ssl->msg_callback) {
- ssl->msg_callback(1, ssl->version, SSL3_RT_ALERT, ssl->s3->send_alert, 2,
- ssl, ssl->msg_callback_arg);
- }
-
- if (ssl->info_callback != NULL) {
- cb = ssl->info_callback;
- } else if (ssl->ctx->info_callback != NULL) {
- cb = ssl->ctx->info_callback;
- }
-
- if (cb != NULL) {
- j = (ssl->s3->send_alert[0] << 8) | ssl->s3->send_alert[1];
- cb(ssl, SSL_CB_WRITE_ALERT, j);
- }
+ return ret;
}
- return i;
+ /* If the alert is fatal, flush the BIO now. */
+ if (ssl->s3->send_alert[0] == SSL3_AL_FATAL) {
+ BIO_flush(ssl->wbio);
+ }
+
+ if (ssl->msg_callback != NULL) {
+ ssl->msg_callback(1 /* write */, ssl->version, SSL3_RT_ALERT,
+ ssl->s3->send_alert, 2, ssl, ssl->msg_callback_arg);
+ }
+
+ void (*cb)(const SSL *ssl, int type, int value) = NULL;
+ if (ssl->info_callback != NULL) {
+ cb = ssl->info_callback;
+ } else if (ssl->ctx->info_callback != NULL) {
+ cb = ssl->ctx->info_callback;
+ }
+
+ if (cb != NULL) {
+ int alert = (ssl->s3->send_alert[0] << 8) | ssl->s3->send_alert[1];
+ cb(ssl, SSL_CB_WRITE_ALERT, alert);
+ }
+
+ return 1;
}
diff --git a/src/ssl/s3_srvr.c b/src/ssl/s3_srvr.c
index 49a1a95..f06ee56 100644
--- a/src/ssl/s3_srvr.c
+++ b/src/ssl/s3_srvr.c
@@ -149,7 +149,6 @@
#include <openssl/ssl.h>
#include <assert.h>
-#include <stdio.h>
#include <string.h>
#include <openssl/bn.h>
@@ -164,7 +163,7 @@
#include <openssl/hmac.h>
#include <openssl/md5.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <openssl/x509.h>
@@ -185,7 +184,6 @@
assert(ssl->server);
assert(!SSL_IS_DTLS(ssl));
- ERR_clear_error();
ERR_clear_system_error();
if (ssl->info_callback != NULL) {
@@ -194,8 +192,6 @@
cb = ssl->ctx->info_callback;
}
- ssl->in_handshake++;
-
if (ssl->cert == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET);
return -1;
@@ -375,12 +371,11 @@
* in PR#1939. The proposed fix doesn't completely resolve this issue
* as buggy implementations of BIO_CTRL_PENDING still exist. So instead
* we just flush unconditionally. */
- ssl->rwstate = SSL_WRITING;
if (BIO_flush(ssl->wbio) <= 0) {
+ ssl->rwstate = SSL_WRITING;
ret = -1;
goto end;
}
- ssl->rwstate = SSL_NOTHING;
ssl->state = ssl->s3->tmp.next_state;
break;
@@ -425,7 +420,7 @@
goto end;
}
- if (!ssl3_do_change_cipher_spec(ssl)) {
+ if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_SERVER_READ)) {
ret = -1;
goto end;
}
@@ -502,12 +497,6 @@
case SSL3_ST_SW_CHANGE_A:
case SSL3_ST_SW_CHANGE_B:
- ssl->session->cipher = ssl->s3->tmp.new_cipher;
- if (!ssl->enc_method->setup_key_block(ssl)) {
- ret = -1;
- goto end;
- }
-
ret = ssl3_send_change_cipher_spec(ssl, SSL3_ST_SW_CHANGE_A,
SSL3_ST_SW_CHANGE_B);
if (ret <= 0) {
@@ -516,8 +505,7 @@
ssl->state = SSL3_ST_SW_FINISHED_A;
ssl->init_num = 0;
- if (!ssl->enc_method->change_cipher_state(
- ssl, SSL3_CHANGE_CIPHER_SERVER_WRITE)) {
+ if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_SERVER_WRITE)) {
ret = -1;
goto end;
}
@@ -526,9 +514,7 @@
case SSL3_ST_SW_FINISHED_A:
case SSL3_ST_SW_FINISHED_B:
ret = ssl3_send_finished(ssl, SSL3_ST_SW_FINISHED_A,
- SSL3_ST_SW_FINISHED_B,
- ssl->enc_method->server_finished_label,
- ssl->enc_method->server_finished_label_len);
+ SSL3_ST_SW_FINISHED_B);
if (ret <= 0) {
goto end;
}
@@ -590,7 +576,6 @@
}
end:
- ssl->in_handshake--;
BUF_MEM_free(buf);
if (cb != NULL) {
cb(ssl, SSL_CB_ACCEPT_EXIT, ret);
@@ -880,8 +865,8 @@
goto f_err;
}
ssl->version = version;
- ssl->enc_method = ssl3_get_enc_method(version);
- assert(ssl->enc_method != NULL);
+ ssl->s3->enc_method = ssl3_get_enc_method(version);
+ assert(ssl->s3->enc_method != NULL);
/* At this point, the connection's version is known and |ssl->version| is
* fixed. Begin enforcing the record-layer version. */
ssl->s3->have_version = 1;
@@ -1050,7 +1035,6 @@
ssl->rwstate = SSL_X509_LOOKUP;
goto err;
}
- ssl->rwstate = SSL_NOTHING;
}
c = ssl3_choose_cipher(ssl, ciphers, ssl_get_cipher_preferences(ssl));
@@ -1059,6 +1043,7 @@
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER);
goto f_err;
}
+ ssl->session->cipher = c;
ssl->s3->tmp.new_cipher = c;
/* Determine whether to request a client certificate. */
@@ -1085,7 +1070,8 @@
/* In TLS 1.2, client authentication requires hashing the handshake transcript
* under a different hash. Otherwise, release the handshake buffer. */
- if (!SSL_USE_SIGALGS(ssl) || !ssl->s3->tmp.cert_request) {
+ if (!ssl->s3->tmp.cert_request ||
+ ssl3_protocol_version(ssl) < TLS1_2_VERSION) {
ssl3_free_handshake_buffer(ssl);
}
@@ -1305,7 +1291,7 @@
/* Determine signature algorithm. */
const EVP_MD *md;
- if (SSL_USE_SIGALGS(ssl)) {
+ if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
md = tls1_choose_signing_digest(ssl);
if (!tls12_add_sigandhash(ssl, &cbb, md)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
@@ -1353,13 +1339,11 @@
switch (sign_result) {
case ssl_private_key_success:
- ssl->rwstate = SSL_NOTHING;
if (!CBB_did_write(&child, sig_len)) {
goto err;
}
break;
case ssl_private_key_failure:
- ssl->rwstate = SSL_NOTHING;
goto err;
case ssl_private_key_retry:
/* Discard the unfinished signature and save the state of |cbb| for the
@@ -1405,7 +1389,7 @@
p += n;
n++;
- if (SSL_USE_SIGALGS(ssl)) {
+ if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
const uint8_t *psigs;
nl = tls12_get_psigalgs(ssl, &psigs);
s2n(nl, p);
@@ -1576,10 +1560,8 @@
switch (decrypt_result) {
case ssl_private_key_success:
- ssl->rwstate = SSL_NOTHING;
break;
case ssl_private_key_failure:
- ssl->rwstate = SSL_NOTHING;
goto err;
case ssl_private_key_retry:
ssl->rwstate = SSL_PRIVATE_KEY_OPERATION;
@@ -1587,7 +1569,11 @@
goto err;
}
- assert(decrypt_len == rsa_size);
+ if (decrypt_len != rsa_size) {
+ al = SSL_AD_DECRYPT_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED);
+ goto f_err;
+ }
/* Prepare a random premaster, to be used on invalid padding. See RFC 5246,
* section 7.4.7.1. */
@@ -1706,7 +1692,7 @@
}
/* Compute the master secret */
- ssl->session->master_key_length = ssl->enc_method->generate_master_secret(
+ ssl->session->master_key_length = tls1_generate_master_secret(
ssl, ssl->session->master_key, premaster_secret, premaster_secret_len);
if (ssl->session->master_key_length == 0) {
goto err;
@@ -1772,7 +1758,7 @@
CBS_init(&certificate_verify, ssl->init_msg, n);
/* Determine the digest type if needbe. */
- if (SSL_USE_SIGALGS(ssl)) {
+ if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
uint8_t hash, signature_type;
if (!CBS_get_u8(&certificate_verify, &hash) ||
!CBS_get_u8(&certificate_verify, &signature_type)) {
@@ -1809,10 +1795,15 @@
if (pctx == NULL) {
goto err;
}
- if (!EVP_PKEY_verify_init(pctx) ||
- !EVP_PKEY_CTX_set_signature_md(pctx, md) ||
- !EVP_PKEY_verify(pctx, CBS_data(&signature), CBS_len(&signature), digest,
- digest_length)) {
+ int sig_ok = EVP_PKEY_verify_init(pctx) &&
+ EVP_PKEY_CTX_set_signature_md(pctx, md) &&
+ EVP_PKEY_verify(pctx, CBS_data(&signature), CBS_len(&signature),
+ digest, digest_length);
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ sig_ok = 1;
+ ERR_clear_error();
+#endif
+ if (!sig_ok) {
al = SSL_AD_DECRYPT_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE);
goto f_err;
@@ -1833,7 +1824,7 @@
}
int ssl3_get_client_certificate(SSL *ssl) {
- int i, ok, al, ret = -1;
+ int ok, al, ret = -1;
X509 *x = NULL;
unsigned long n;
STACK_OF(X509) *sk = NULL;
@@ -1841,6 +1832,7 @@
CBS certificate_msg, certificate_list;
int is_first_certificate = 1;
+ assert(ssl->s3->tmp.cert_request);
n = ssl->method->ssl_get_message(ssl, SSL3_ST_SR_CERT_A, SSL3_ST_SR_CERT_B,
-1, (long)ssl->max_cert_list,
ssl_hash_message, &ok);
@@ -1849,29 +1841,23 @@
return n;
}
- if (ssl->s3->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE) {
- if ((ssl->verify_mode & SSL_VERIFY_PEER) &&
- (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
- 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 (ssl->version > SSL3_VERSION && ssl->s3->tmp.cert_request) {
- OPENSSL_PUT_ERROR(SSL,
- SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST);
- al = SSL_AD_UNEXPECTED_MESSAGE;
- goto f_err;
- }
- ssl->s3->tmp.reuse_message = 1;
-
- return 1;
- }
-
if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE) {
+ if (ssl->version == SSL3_VERSION &&
+ ssl->s3->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE) {
+ /* In SSL 3.0, the Certificate message is omitted to signal no certificate. */
+ if ((ssl->verify_mode & SSL_VERIFY_PEER) &&
+ (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ goto f_err;
+ }
+
+ ssl->s3->tmp.reuse_message = 1;
+ return 1;
+ }
+
al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_MESSAGE_TYPE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
goto f_err;
}
@@ -1940,15 +1926,14 @@
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATES_RETURNED);
goto f_err;
} else if ((ssl->verify_mode & SSL_VERIFY_PEER) &&
- (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
+ (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
/* Fail for TLS only if we required a certificate */
OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
al = SSL_AD_HANDSHAKE_FAILURE;
goto f_err;
}
} else {
- i = ssl_verify_cert_chain(ssl, sk);
- if (i <= 0) {
+ if (ssl_verify_cert_chain(ssl, sk) <= 0) {
al = ssl_verify_alarm_type(ssl->verify_result);
OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED);
goto f_err;
@@ -2156,8 +2141,8 @@
if (!CBS_get_u8_length_prefixed(&next_protocol, &selected_protocol) ||
!CBS_get_u8_length_prefixed(&next_protocol, &padding) ||
CBS_len(&next_protocol) != 0 ||
- !CBS_stow(&selected_protocol, &ssl->next_proto_negotiated,
- &ssl->next_proto_negotiated_len)) {
+ !CBS_stow(&selected_protocol, &ssl->s3->next_proto_negotiated,
+ &ssl->s3->next_proto_negotiated_len)) {
return 0;
}
diff --git a/src/ssl/ssl_aead_ctx.c b/src/ssl/ssl_aead_ctx.c
index 8829679..4de9d45 100644
--- a/src/ssl/ssl_aead_ctx.c
+++ b/src/ssl/ssl_aead_ctx.c
@@ -56,7 +56,7 @@
enc_key_len += fixed_iv_len;
}
- SSL_AEAD_CTX *aead_ctx = (SSL_AEAD_CTX *)OPENSSL_malloc(sizeof(SSL_AEAD_CTX));
+ SSL_AEAD_CTX *aead_ctx = OPENSSL_malloc(sizeof(SSL_AEAD_CTX));
if (aead_ctx == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return NULL;
@@ -111,6 +111,10 @@
}
size_t SSL_AEAD_CTX_explicit_nonce_len(SSL_AEAD_CTX *aead) {
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ aead = NULL;
+#endif
+
if (aead != NULL && aead->variable_nonce_included_in_record) {
return aead->variable_nonce_len;
}
@@ -118,11 +122,15 @@
}
size_t SSL_AEAD_CTX_max_overhead(SSL_AEAD_CTX *aead) {
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ aead = NULL;
+#endif
+
if (aead == NULL) {
return 0;
}
return EVP_AEAD_max_overhead(aead->ctx.aead) +
- SSL_AEAD_CTX_explicit_nonce_len(aead);
+ SSL_AEAD_CTX_explicit_nonce_len(aead);
}
/* ssl_aead_ctx_get_ad writes the additional data for |aead| into |out| and
@@ -149,6 +157,10 @@
size_t max_out, uint8_t type, uint16_t wire_version,
const uint8_t seqnum[8], const uint8_t *in,
size_t in_len) {
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ aead = NULL;
+#endif
+
if (aead == NULL) {
/* Handle the initial NULL cipher. */
if (in_len > max_out) {
@@ -222,6 +234,10 @@
size_t max_out, uint8_t type, uint16_t wire_version,
const uint8_t seqnum[8], const uint8_t *in,
size_t in_len) {
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ aead = NULL;
+#endif
+
if (aead == NULL) {
/* Handle the initial NULL cipher. */
if (in_len > max_out) {
diff --git a/src/ssl/ssl_buffer.c b/src/ssl/ssl_buffer.c
index 7fd74e4..272b13b 100644
--- a/src/ssl/ssl_buffer.c
+++ b/src/ssl/ssl_buffer.c
@@ -113,12 +113,11 @@
}
/* 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) {
+ ssl->rwstate = SSL_READING;
return ret;
}
- ssl->rwstate = SSL_NOTHING;
/* |BIO_read| was bound by |buf->cap|, so this cannot overflow. */
buf->len = (uint16_t)ret;
return 1;
@@ -136,13 +135,12 @@
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) {
+ ssl->rwstate = SSL_READING;
return ret;
}
- ssl->rwstate = SSL_NOTHING;
/* |BIO_read| was bound by |buf->cap - buf->len|, so this cannot
* overflow. */
buf->len += (uint16_t)ret;
@@ -268,12 +266,11 @@
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) {
+ ssl->rwstate = SSL_WRITING;
return ret;
}
- ssl->rwstate = SSL_NOTHING;
consume_buffer(buf, (size_t)ret);
}
ssl_write_buffer_clear(ssl);
@@ -286,16 +283,15 @@
return 1;
}
- ssl->rwstate = SSL_WRITING;
int ret = BIO_write(ssl->wbio, buf->buf + buf->offset, buf->len);
if (ret <= 0) {
+ ssl->rwstate = SSL_WRITING;
/* If the write failed, drop the write buffer anyway. Datagram transports
* can't write half a packet, so the caller is expected to retry from the
* top. */
ssl_write_buffer_clear(ssl);
return ret;
}
- ssl->rwstate = SSL_NOTHING;
ssl_write_buffer_clear(ssl);
return 1;
}
diff --git a/src/ssl/ssl_cert.c b/src/ssl/ssl_cert.c
index 4952cfd..0eb0d8b 100644
--- a/src/ssl/ssl_cert.c
+++ b/src/ssl/ssl_cert.c
@@ -139,7 +139,7 @@
}
CERT *ssl_cert_new(void) {
- CERT *ret = (CERT *)OPENSSL_malloc(sizeof(CERT));
+ CERT *ret = OPENSSL_malloc(sizeof(CERT));
if (ret == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return NULL;
@@ -150,7 +150,7 @@
}
CERT *ssl_cert_dup(CERT *cert) {
- CERT *ret = (CERT *)OPENSSL_malloc(sizeof(CERT));
+ CERT *ret = OPENSSL_malloc(sizeof(CERT));
if (ret == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return NULL;
@@ -185,9 +185,16 @@
}
}
+ ret->key_method = cert->key_method;
+
ret->cert_cb = cert->cert_cb;
ret->cert_cb_arg = cert->cert_cb_arg;
+ if (cert->verify_store != NULL) {
+ X509_STORE_up_ref(cert->verify_store);
+ ret->verify_store = cert->verify_store;
+ }
+
return ret;
err:
@@ -220,6 +227,7 @@
ssl_cert_clear_certs(c);
OPENSSL_free(c->peer_sigalgs);
OPENSSL_free(c->digest_nids);
+ X509_STORE_free(c->verify_store);
OPENSSL_free(c);
}
@@ -279,10 +287,15 @@
return 0;
}
+ X509_STORE *verify_store = ssl->ctx->cert_store;
+ if (ssl->cert->verify_store != NULL) {
+ verify_store = ssl->cert->verify_store;
+ }
+
X509 *leaf = sk_X509_value(cert_chain, 0);
int ret = 0;
X509_STORE_CTX ctx;
- if (!X509_STORE_CTX_init(&ctx, ssl->ctx->cert_store, leaf, cert_chain)) {
+ if (!X509_STORE_CTX_init(&ctx, verify_store, leaf, cert_chain)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
return 0;
}
@@ -409,13 +422,18 @@
uint8_t *p;
n = i2d_X509(x, NULL);
- if (!BUF_MEM_grow_clean(buf, (int)(n + (*l) + 3))) {
+ if (n < 0 || !BUF_MEM_grow_clean(buf, (int)(n + (*l) + 3))) {
OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
return 0;
}
p = (uint8_t *)&(buf->data[*l]);
l2n3(n, p);
- i2d_X509(x, &p);
+ n = i2d_X509(x, &p);
+ if (n < 0) {
+ /* This shouldn't happen. */
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ return 0;
+ }
*l += n + 3;
return 1;
@@ -475,6 +493,33 @@
return 1;
}
+static int set_cert_store(X509_STORE **store_ptr, X509_STORE *new_store, int take_ref) {
+ X509_STORE_free(*store_ptr);
+ *store_ptr = new_store;
+
+ if (new_store != NULL && take_ref) {
+ X509_STORE_up_ref(new_store);
+ }
+
+ return 1;
+}
+
+int SSL_CTX_set0_verify_cert_store(SSL_CTX *ctx, X509_STORE *store) {
+ return set_cert_store(&ctx->cert->verify_store, store, 0);
+}
+
+int SSL_CTX_set1_verify_cert_store(SSL_CTX *ctx, X509_STORE *store) {
+ return set_cert_store(&ctx->cert->verify_store, store, 1);
+}
+
+int SSL_set0_verify_cert_store(SSL *ssl, X509_STORE *store) {
+ return set_cert_store(&ssl->cert->verify_store, store, 0);
+}
+
+int SSL_set1_verify_cert_store(SSL *ssl, X509_STORE *store) {
+ return set_cert_store(&ssl->cert->verify_store, store, 1);
+}
+
int SSL_CTX_set0_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) {
return ssl_cert_set0_chain(ctx->cert, chain);
}
diff --git a/src/ssl/ssl_cipher.c b/src/ssl/ssl_cipher.c
index 77fa8fa..58ce582 100644
--- a/src/ssl/ssl_cipher.c
+++ b/src/ssl/ssl_cipher.c
@@ -141,7 +141,6 @@
#include <openssl/ssl.h>
#include <assert.h>
-#include <stdio.h>
#include <string.h>
#include <openssl/buf.h>
@@ -1392,7 +1391,7 @@
/* Now we have to collect the available ciphers from the compiled in ciphers.
* We cannot get more than the number compiled in, so it is used for
* allocation. */
- co_list = (CIPHER_ORDER *)OPENSSL_malloc(sizeof(CIPHER_ORDER) * kCiphersLen);
+ co_list = OPENSSL_malloc(sizeof(CIPHER_ORDER) * kCiphersLen);
if (co_list == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return NULL;
@@ -1417,10 +1416,10 @@
* AES_GCM. Of the two CHACHA20 variants, the new one is preferred over the
* old one. */
if (EVP_has_aes_hardware()) {
- ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256GCM, ~0u, 0, CIPHER_ADD, -1, 0,
- &head, &tail);
ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128GCM, ~0u, 0, CIPHER_ADD, -1, 0,
&head, &tail);
+ ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256GCM, ~0u, 0, CIPHER_ADD, -1, 0,
+ &head, &tail);
ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_CHACHA20POLY1305, ~0u, 0, CIPHER_ADD,
-1, 0, &head, &tail);
ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_CHACHA20POLY1305_OLD, ~0u, 0,
@@ -1430,24 +1429,24 @@
-1, 0, &head, &tail);
ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_CHACHA20POLY1305_OLD, ~0u, 0,
CIPHER_ADD, -1, 0, &head, &tail);
- ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256GCM, ~0u, 0, CIPHER_ADD, -1, 0,
- &head, &tail);
ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128GCM, ~0u, 0, CIPHER_ADD, -1, 0,
&head, &tail);
+ ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256GCM, ~0u, 0, CIPHER_ADD, -1, 0,
+ &head, &tail);
}
- /* Then the legacy non-AEAD ciphers: AES_256_CBC, AES-128_CBC, RC4_128_SHA,
- * RC4_128_MD5, 3DES_EDE_CBC_SHA. */
- ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256, ~0u, 0, CIPHER_ADD, -1, 0,
- &head, &tail);
+ /* Then the legacy non-AEAD ciphers: AES_128_CBC, AES_256_CBC,
+ * 3DES_EDE_CBC_SHA, RC4_128_SHA, RC4_128_MD5. */
ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128, ~0u, 0, CIPHER_ADD, -1, 0,
&head, &tail);
+ ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256, ~0u, 0, CIPHER_ADD, -1, 0,
+ &head, &tail);
+ ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_3DES, ~0u, 0, CIPHER_ADD, -1, 0, &head,
+ &tail);
ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_RC4, ~SSL_MD5, 0, CIPHER_ADD, -1, 0,
&head, &tail);
ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_RC4, SSL_MD5, 0, CIPHER_ADD, -1, 0,
&head, &tail);
- ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_3DES, ~0u, 0, CIPHER_ADD, -1, 0, &head,
- &tail);
/* Temporarily enable everything else for sorting */
ssl_cipher_apply_rule(0, ~0u, ~0u, ~0u, ~0u, 0, CIPHER_ADD, -1, 0, &head,
@@ -1577,6 +1576,10 @@
return (cipher->algorithm_mac & SSL_SHA1) != 0;
}
+int SSL_CIPHER_has_SHA256_HMAC(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_mac & SSL_SHA256) != 0;
+}
+
int SSL_CIPHER_is_AESGCM(const SSL_CIPHER *cipher) {
return (cipher->algorithm_enc & (SSL_AES128GCM | SSL_AES256GCM)) != 0;
}
@@ -1804,7 +1807,6 @@
int len) {
const char *kx, *au, *enc, *mac;
uint32_t alg_mkey, alg_auth, alg_enc, alg_mac;
- static const char *format = "%-23s Kx=%-8s Au=%-4s Enc=%-9s Mac=%-4s\n";
alg_mkey = cipher->algorithm_mkey;
alg_auth = cipher->algorithm_auth;
@@ -1928,7 +1930,8 @@
return "Buffer too small";
}
- BIO_snprintf(buf, len, format, cipher->name, kx, au, enc, mac);
+ BIO_snprintf(buf, len, "%-23s Kx=%-8s Au=%-4s Enc=%-9s Mac=%-4s\n",
+ cipher->name, kx, au, enc, mac);
return buf;
}
diff --git a/src/ssl/ssl_ecdh.c b/src/ssl/ssl_ecdh.c
index 45c5b26..d48c93f 100644
--- a/src/ssl/ssl_ecdh.c
+++ b/src/ssl/ssl_ecdh.c
@@ -23,7 +23,7 @@
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include "internal.h"
@@ -65,21 +65,12 @@
}
} while (BN_is_zero(private_key));
- /* Compute the corresponding public key. */
+ /* Compute the corresponding public key and serialize it. */
public_key = EC_POINT_new(group);
if (public_key == NULL ||
- !EC_POINT_mul(group, public_key, private_key, NULL, NULL, bn_ctx)) {
- goto err;
- }
-
- /* Serialize the public key. */
- size_t len = EC_POINT_point2oct(
- group, public_key, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, bn_ctx);
- uint8_t *ptr;
- if (len == 0 ||
- !CBB_add_space(out, &ptr, len) ||
- EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED, ptr,
- len, bn_ctx) != len) {
+ !EC_POINT_mul(group, public_key, private_key, NULL, NULL, bn_ctx) ||
+ !EC_POINT_point2cbb(out, group, public_key, POINT_CONVERSION_UNCOMPRESSED,
+ bn_ctx)) {
goto err;
}
@@ -93,9 +84,12 @@
return ret;
}
-int ssl_ec_point_compute_secret(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
- size_t *out_secret_len, uint8_t *out_alert,
- const uint8_t *peer_key, size_t peer_key_len) {
+static int ssl_ec_point_compute_secret(SSL_ECDH_CTX *ctx,
+ uint8_t **out_secret,
+ size_t *out_secret_len,
+ uint8_t *out_alert,
+ const uint8_t *peer_key,
+ size_t peer_key_len) {
BIGNUM *private_key = (BIGNUM *)ctx->data;
assert(private_key != NULL);
*out_alert = SSL_AD_INTERNAL_ERROR;
@@ -297,8 +291,8 @@
ssl_ec_point_compute_secret,
},
{
- NID_x25519,
- SSL_CURVE_ECDH_X25519,
+ NID_X25519,
+ SSL_CURVE_X25519,
"X25519",
ssl_x25519_cleanup,
ssl_x25519_generate_keypair,
diff --git a/src/ssl/ssl_file.c b/src/ssl/ssl_file.c
index 42cf800..748d50c 100644
--- a/src/ssl/ssl_file.c
+++ b/src/ssl/ssl_file.c
@@ -121,7 +121,6 @@
#include <openssl/stack.h>
#include <openssl/x509.h>
-#include "../crypto/directory.h"
#include "internal.h"
@@ -247,53 +246,6 @@
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;
diff --git a/src/ssl/ssl_lib.c b/src/ssl/ssl_lib.c
index 08578a6..d62cdae 100644
--- a/src/ssl/ssl_lib.c
+++ b/src/ssl/ssl_lib.c
@@ -141,7 +141,6 @@
#include <openssl/ssl.h>
#include <assert.h>
-#include <stdio.h>
#include <string.h>
#include <openssl/bytestring.h>
@@ -150,7 +149,6 @@
#include <openssl/err.h>
#include <openssl/lhash.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
#include <openssl/rand.h>
#include <openssl/x509v3.h>
@@ -181,12 +179,21 @@
return 1;
}
-static uint32_t ssl_session_hash(const SSL_SESSION *a) {
+static uint32_t ssl_session_hash(const SSL_SESSION *sess) {
+ const uint8_t *session_id = sess->session_id;
+
+ uint8_t tmp_storage[sizeof(uint32_t)];
+ if (sess->session_id_length < sizeof(tmp_storage)) {
+ memset(tmp_storage, 0, sizeof(tmp_storage));
+ memcpy(tmp_storage, sess->session_id, sess->session_id_length);
+ session_id = tmp_storage;
+ }
+
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);
+ ((uint32_t)session_id[0]) |
+ ((uint32_t)session_id[1] << 8) |
+ ((uint32_t)session_id[2] << 16) |
+ ((uint32_t)session_id[3] << 24);
return hash;
}
@@ -221,7 +228,7 @@
goto err;
}
- ret = (SSL_CTX *)OPENSSL_malloc(sizeof(SSL_CTX));
+ ret = OPENSSL_malloc(sizeof(SSL_CTX));
if (ret == NULL) {
goto err;
}
@@ -353,7 +360,7 @@
return NULL;
}
- SSL *ssl = (SSL *)OPENSSL_malloc(sizeof(SSL));
+ SSL *ssl = OPENSSL_malloc(sizeof(SSL));
if (ssl == NULL) {
goto err;
}
@@ -417,8 +424,6 @@
if (!ssl->method->ssl_new(ssl)) {
goto err;
}
- ssl->enc_method = ssl3_get_enc_method(ssl->version);
- assert(ssl->enc_method != NULL);
ssl->rwstate = SSL_NOTHING;
@@ -486,8 +491,6 @@
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);
@@ -497,7 +500,6 @@
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) {
@@ -513,8 +515,6 @@
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) {
@@ -522,8 +522,6 @@
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) {
@@ -550,6 +548,10 @@
BIO *SSL_get_wbio(const SSL *ssl) { return ssl->wbio; }
int SSL_do_handshake(SSL *ssl) {
+ ssl->rwstate = SSL_NOTHING;
+ /* Functions which use SSL_get_error must clear the error queue on entry. */
+ ERR_clear_error();
+
if (ssl->handshake_func == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_TYPE_NOT_SET);
return -1;
@@ -563,91 +565,117 @@
}
int SSL_connect(SSL *ssl) {
- if (ssl->handshake_func == 0) {
+ if (ssl->handshake_func == NULL) {
/* 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;
- }
+ assert(ssl->handshake_func == ssl->method->ssl_connect);
- return ssl->handshake_func(ssl);
+ return SSL_do_handshake(ssl);
}
int SSL_accept(SSL *ssl) {
- if (ssl->handshake_func == 0) {
+ if (ssl->handshake_func == NULL) {
/* 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);
+ assert(ssl->handshake_func == ssl->method->ssl_accept);
+
+ return SSL_do_handshake(ssl);
+}
+
+static int ssl_read_impl(SSL *ssl, void *buf, int num, int peek) {
+ ssl->rwstate = SSL_NOTHING;
+ /* Functions which use SSL_get_error must clear the error queue on entry. */
+ ERR_clear_error();
+ ERR_clear_system_error();
+
+ if (ssl->handshake_func == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
return -1;
}
- return ssl->handshake_func(ssl);
+ if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) {
+ return 0;
+ }
+
+ /* This may require multiple iterations. False Start will cause
+ * |ssl->handshake_func| to signal success one step early, but the handshake
+ * must be completely finished before other modes are accepted. */
+ while (SSL_in_init(ssl)) {
+ int ret = SSL_do_handshake(ssl);
+ if (ret < 0) {
+ return ret;
+ }
+ if (ret == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
+ return -1;
+ }
+ }
+
+ return ssl->method->ssl_read_app_data(ssl, buf, num, peek);
}
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);
+ return ssl_read_impl(ssl, buf, num, 0 /* consume bytes */);
}
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);
+ return ssl_read_impl(ssl, buf, num, 1 /* peek */);
}
int SSL_write(SSL *ssl, const void *buf, int num) {
- if (ssl->handshake_func == 0) {
+ ssl->rwstate = SSL_NOTHING;
+ /* Functions which use SSL_get_error must clear the error queue on entry. */
+ ERR_clear_error();
+ ERR_clear_system_error();
+
+ if (ssl->handshake_func == NULL) {
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();
+ /* If necessary, complete the handshake implicitly. */
+ if (SSL_in_init(ssl) && !SSL_in_false_start(ssl)) {
+ int ret = SSL_do_handshake(ssl);
+ if (ret < 0) {
+ return ret;
+ }
+ if (ret == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
+ return -1;
+ }
+ }
+
return ssl->method->ssl_write_app_data(ssl, buf, num);
}
int SSL_shutdown(SSL *ssl) {
+ ssl->rwstate = SSL_NOTHING;
+ /* Functions which use SSL_get_error must clear the error queue on entry. */
+ ERR_clear_error();
+
/* Note that this function behaves differently from what one might expect.
* Return values are 0 for no success (yet), 1 for success; but calling it
* once is usually not enough, even if blocking I/O is used (see
* ssl3_shutdown). */
- if (ssl->handshake_func == 0) {
+ if (ssl->handshake_func == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
return -1;
}
+ /* We can't shutdown properly if we are in the middle of a handshake. */
if (SSL_in_init(ssl)) {
- return 1;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SHUTDOWN_WHILE_IN_INIT);
+ return -1;
}
/* Do nothing if configured not to send a close_notify. */
@@ -710,8 +738,7 @@
}
if (ret_code == 0) {
- if ((ssl->shutdown & SSL_RECEIVED_SHUTDOWN) &&
- (ssl->s3->warn_alert == SSL_AD_CLOSE_NOTIFY)) {
+ if ((ssl->shutdown & SSL_RECEIVED_SHUTDOWN) && ssl->s3->clean_shutdown) {
/* The socket was cleanly shut down with a close_notify. */
return SSL_ERROR_ZERO_RETURN;
}
@@ -997,7 +1024,7 @@
}
int SSL_set_fd(SSL *ssl, int fd) {
- BIO *bio = BIO_new(BIO_s_fd());
+ BIO *bio = BIO_new(BIO_s_socket());
if (bio == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
return 0;
@@ -1009,9 +1036,9 @@
int SSL_set_wfd(SSL *ssl, int fd) {
if (ssl->rbio == NULL ||
- BIO_method_type(ssl->rbio) != BIO_TYPE_FD ||
+ BIO_method_type(ssl->rbio) != BIO_TYPE_SOCKET ||
BIO_get_fd(ssl->rbio, NULL) != fd) {
- BIO *bio = BIO_new(BIO_s_fd());
+ BIO *bio = BIO_new(BIO_s_socket());
if (bio == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
return 0;
@@ -1026,9 +1053,9 @@
}
int SSL_set_rfd(SSL *ssl, int fd) {
- if (ssl->wbio == NULL || BIO_method_type(ssl->wbio) != BIO_TYPE_FD ||
+ if (ssl->wbio == NULL || BIO_method_type(ssl->wbio) != BIO_TYPE_SOCKET ||
BIO_get_fd(ssl->wbio, NULL) != fd) {
- BIO *bio = BIO_new(BIO_s_fd());
+ BIO *bio = BIO_new(BIO_s_socket());
if (bio == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
return 0;
@@ -1187,7 +1214,7 @@
ssl->max_cert_list = (uint32_t)max_cert_list;
}
-void SSL_CTX_set_max_send_fragment(SSL_CTX *ctx, size_t max_send_fragment) {
+int SSL_CTX_set_max_send_fragment(SSL_CTX *ctx, size_t max_send_fragment) {
if (max_send_fragment < 512) {
max_send_fragment = 512;
}
@@ -1195,9 +1222,11 @@
max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
}
ctx->max_send_fragment = (uint16_t)max_send_fragment;
+
+ return 1;
}
-void SSL_set_max_send_fragment(SSL *ssl, size_t max_send_fragment) {
+int SSL_set_max_send_fragment(SSL *ssl, size_t max_send_fragment) {
if (max_send_fragment < 512) {
max_send_fragment = 512;
}
@@ -1205,6 +1234,8 @@
max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
}
ssl->max_send_fragment = (uint16_t)max_send_fragment;
+
+ return 1;
}
int SSL_set_mtu(SSL *ssl, unsigned mtu) {
@@ -1254,17 +1285,15 @@
return ssl->cipher_list->ciphers;
}
- if (ssl->version >= TLS1_1_VERSION && ssl->ctx != NULL &&
- ssl->ctx->cipher_list_tls11 != NULL) {
+ if (ssl->version >= TLS1_1_VERSION && ssl->ctx->cipher_list_tls11 != NULL) {
return ssl->ctx->cipher_list_tls11->ciphers;
}
- if (ssl->version >= TLS1_VERSION && ssl->ctx != NULL &&
- ssl->ctx->cipher_list_tls10 != NULL) {
+ if (ssl->version >= TLS1_VERSION && ssl->ctx->cipher_list_tls10 != NULL) {
return ssl->ctx->cipher_list_tls10->ciphers;
}
- if (ssl->ctx != NULL && ssl->ctx->cipher_list != NULL) {
+ if (ssl->ctx->cipher_list != NULL) {
return ssl->ctx->cipher_list->ciphers;
}
@@ -1282,7 +1311,7 @@
return ssl->cipher_list_by_id;
}
- if (ssl->ctx != NULL && ssl->ctx->cipher_list_by_id != NULL) {
+ if (ssl->ctx->cipher_list_by_id != NULL) {
return ssl->ctx->cipher_list_by_id;
}
@@ -1574,11 +1603,11 @@
void SSL_get0_next_proto_negotiated(const SSL *ssl, const uint8_t **out_data,
unsigned *out_len) {
- *out_data = ssl->next_proto_negotiated;
+ *out_data = ssl->s3->next_proto_negotiated;
if (*out_data == NULL) {
*out_len = 0;
} else {
- *out_len = ssl->next_proto_negotiated_len;
+ *out_len = ssl->s3->next_proto_negotiated_len;
}
}
@@ -1643,18 +1672,6 @@
}
}
-int SSL_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len,
- const char *label, size_t label_len,
- const uint8_t *context, size_t context_len,
- int use_context) {
- if (ssl->version < TLS1_VERSION) {
- return 0;
- }
-
- return ssl->enc_method->export_keying_material(
- ssl, out, out_len, label, label_len, context, context_len, use_context);
-}
-
void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx,
int (*cb)(X509_STORE_CTX *store_ctx,
void *arg),
@@ -1822,13 +1839,6 @@
return ssl_get_version(session->ssl_version);
}
-void ssl_clear_cipher_ctx(SSL *ssl) {
- SSL_AEAD_CTX_free(ssl->aead_read_ctx);
- ssl->aead_read_ctx = NULL;
- SSL_AEAD_CTX_free(ssl->aead_write_ctx);
- ssl->aead_write_ctx = NULL;
-}
-
X509 *SSL_get_certificate(const SSL *ssl) {
if (ssl->cert != NULL) {
return ssl->cert->x509;
@@ -1862,16 +1872,18 @@
}
const SSL_CIPHER *SSL_get_current_cipher(const SSL *ssl) {
- if (ssl->aead_write_ctx == NULL) {
+ if (ssl->s3->aead_write_ctx == NULL) {
return NULL;
}
- return ssl->aead_write_ctx->cipher;
+ return ssl->s3->aead_write_ctx->cipher;
}
const COMP_METHOD *SSL_get_current_compression(SSL *ssl) { return NULL; }
const COMP_METHOD *SSL_get_current_expansion(SSL *ssl) { return NULL; }
+int *SSL_get_server_tmp_key(SSL *ssl, EVP_PKEY **out_key) { return 0; }
+
int ssl_init_wbio_buffer(SSL *ssl, int push) {
BIO *bbio;
@@ -1995,6 +2007,14 @@
void SSL_set_state(SSL *ssl, int state) { }
+char *SSL_get_shared_ciphers(const SSL *ssl, char *buf, int len) {
+ if (len <= 0) {
+ return NULL;
+ }
+ buf[0] = '\0';
+ return buf;
+}
+
void SSL_set_verify_result(SSL *ssl, long result) {
ssl->verify_result = result;
}
@@ -2305,15 +2325,11 @@
return &SSLv3_enc_data;
case TLS1_VERSION:
- return &TLSv1_enc_data;
-
- case DTLS1_VERSION:
case TLS1_1_VERSION:
- return &TLSv1_1_enc_data;
-
- case DTLS1_2_VERSION:
case TLS1_2_VERSION:
- return &TLSv1_2_enc_data;
+ case DTLS1_VERSION:
+ case DTLS1_2_VERSION:
+ return &TLSv1_enc_data;
default:
return NULL;
@@ -2495,7 +2511,7 @@
}
}
-uint16_t ssl3_version_from_wire(SSL *ssl, uint16_t wire_version) {
+uint16_t ssl3_version_from_wire(const SSL *ssl, uint16_t wire_version) {
if (!SSL_IS_DTLS(ssl)) {
return wire_version;
}
@@ -2516,6 +2532,11 @@
return version;
}
+uint16_t ssl3_protocol_version(const SSL *ssl) {
+ assert(ssl->s3->have_version);
+ return ssl3_version_from_wire(ssl, ssl->version);
+}
+
int SSL_cache_hit(SSL *ssl) { return SSL_session_reused(ssl); }
int SSL_is_server(SSL *ssl) { return ssl->server; }
@@ -2541,23 +2562,24 @@
int SSL_get_rc4_state(const SSL *ssl, const RC4_KEY **read_key,
const RC4_KEY **write_key) {
- if (ssl->aead_read_ctx == NULL || ssl->aead_write_ctx == NULL) {
+ if (ssl->s3->aead_read_ctx == NULL || ssl->s3->aead_write_ctx == NULL) {
return 0;
}
- return EVP_AEAD_CTX_get_rc4_state(&ssl->aead_read_ctx->ctx, read_key) &&
- EVP_AEAD_CTX_get_rc4_state(&ssl->aead_write_ctx->ctx, write_key);
+ return EVP_AEAD_CTX_get_rc4_state(&ssl->s3->aead_read_ctx->ctx, read_key) &&
+ EVP_AEAD_CTX_get_rc4_state(&ssl->s3->aead_write_ctx->ctx, write_key);
}
int SSL_get_ivs(const SSL *ssl, const uint8_t **out_read_iv,
const uint8_t **out_write_iv, size_t *out_iv_len) {
- if (ssl->aead_read_ctx == NULL || ssl->aead_write_ctx == NULL) {
+ if (ssl->s3->aead_read_ctx == NULL || ssl->s3->aead_write_ctx == NULL) {
return 0;
}
size_t write_iv_len;
- if (!EVP_AEAD_CTX_get_iv(&ssl->aead_read_ctx->ctx, out_read_iv, out_iv_len) ||
- !EVP_AEAD_CTX_get_iv(&ssl->aead_write_ctx->ctx, out_write_iv,
+ if (!EVP_AEAD_CTX_get_iv(&ssl->s3->aead_read_ctx->ctx, out_read_iv,
+ out_iv_len) ||
+ !EVP_AEAD_CTX_get_iv(&ssl->s3->aead_write_ctx->ctx, out_write_iv,
&write_iv_len) ||
*out_iv_len != write_iv_len) {
return 0;
@@ -2566,10 +2588,69 @@
return 1;
}
+static uint64_t be_to_u64(const uint8_t in[8]) {
+ return (((uint64_t)in[0]) << 56) | (((uint64_t)in[1]) << 48) |
+ (((uint64_t)in[2]) << 40) | (((uint64_t)in[3]) << 32) |
+ (((uint64_t)in[4]) << 24) | (((uint64_t)in[5]) << 16) |
+ (((uint64_t)in[6]) << 8) | ((uint64_t)in[7]);
+}
+
+uint64_t SSL_get_read_sequence(const SSL *ssl) {
+ /* TODO(davidben): Internally represent sequence numbers as uint64_t. */
+ if (SSL_IS_DTLS(ssl)) {
+ /* max_seq_num already includes the epoch. */
+ assert(ssl->d1->r_epoch == (ssl->d1->bitmap.max_seq_num >> 48));
+ return ssl->d1->bitmap.max_seq_num;
+ }
+ return be_to_u64(ssl->s3->read_sequence);
+}
+
+uint64_t SSL_get_write_sequence(const SSL *ssl) {
+ uint64_t ret = be_to_u64(ssl->s3->write_sequence);
+ if (SSL_IS_DTLS(ssl)) {
+ assert((ret >> 48) == 0);
+ ret |= ((uint64_t)ssl->d1->w_epoch) << 48;
+ }
+ return ret;
+}
+
uint8_t SSL_get_server_key_exchange_hash(const SSL *ssl) {
return ssl->s3->tmp.server_key_exchange_hash;
}
+size_t SSL_get_client_random(const SSL *ssl, uint8_t *out, size_t max_out) {
+ if (max_out == 0) {
+ return sizeof(ssl->s3->client_random);
+ }
+ if (max_out > sizeof(ssl->s3->client_random)) {
+ max_out = sizeof(ssl->s3->client_random);
+ }
+ memcpy(out, ssl->s3->client_random, max_out);
+ return max_out;
+}
+
+size_t SSL_get_server_random(const SSL *ssl, uint8_t *out, size_t max_out) {
+ if (max_out == 0) {
+ return sizeof(ssl->s3->server_random);
+ }
+ if (max_out > sizeof(ssl->s3->server_random)) {
+ max_out = sizeof(ssl->s3->server_random);
+ }
+ memcpy(out, ssl->s3->server_random, max_out);
+ return max_out;
+}
+
+const SSL_CIPHER *SSL_get_pending_cipher(const SSL *ssl) {
+ if (!SSL_in_init(ssl)) {
+ return NULL;
+ }
+ return ssl->s3->tmp.new_cipher;
+}
+
+void SSL_CTX_set_retain_only_sha256_of_client_certs(SSL_CTX *ctx, int enabled) {
+ ctx->retain_only_sha256_of_client_certs = !!enabled;
+}
+
int SSL_clear(SSL *ssl) {
if (ssl->method == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_METHOD_SPECIFIED);
@@ -2608,12 +2689,6 @@
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).
*
@@ -2627,8 +2702,6 @@
if (!ssl->method->ssl_new(ssl)) {
return 0;
}
- 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;
diff --git a/src/ssl/ssl_rsa.c b/src/ssl/ssl_rsa.c
index 990979b..c17d2da 100644
--- a/src/ssl/ssl_rsa.c
+++ b/src/ssl/ssl_rsa.c
@@ -326,6 +326,11 @@
ssl->cert->key_method = key_method;
}
+void SSL_CTX_set_private_key_method(SSL_CTX *ctx,
+ const SSL_PRIVATE_KEY_METHOD *key_method) {
+ ctx->cert->key_method = key_method;
+}
+
int SSL_set_private_key_digest_prefs(SSL *ssl, const int *digest_nids,
size_t num_digests) {
OPENSSL_free(ssl->cert->digest_nids);
diff --git a/src/ssl/ssl_session.c b/src/ssl/ssl_session.c
index 3d59bc3..12d065e 100644
--- a/src/ssl/ssl_session.c
+++ b/src/ssl/ssl_session.c
@@ -136,7 +136,6 @@
#include <openssl/ssl.h>
#include <assert.h>
-#include <stdio.h>
#include <string.h>
#include <openssl/err.h>
@@ -161,7 +160,7 @@
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));
+ SSL_SESSION *session = OPENSSL_malloc(sizeof(SSL_SESSION));
if (session == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return 0;
@@ -232,6 +231,19 @@
return session->peer;
}
+size_t SSL_SESSION_get_master_key(const SSL_SESSION *session, uint8_t *out,
+ size_t max_out) {
+ /* TODO(davidben): Fix master_key_length's type and remove these casts. */
+ if (max_out == 0) {
+ return (size_t)session->master_key_length;
+ }
+ if (max_out > (size_t)session->master_key_length) {
+ max_out = (size_t)session->master_key_length;
+ }
+ memcpy(out, session->master_key, max_out);
+ return max_out;
+}
+
long SSL_SESSION_set_time(SSL_SESSION *session, long time) {
if (session == NULL) {
return 0;
@@ -430,7 +442,7 @@
/* This is used only by servers. */
assert(ssl->server);
SSL_SESSION *session = NULL;
- int send_ticket = 0;
+ int renew_ticket = 0;
/* If tickets are disabled, always behave as if no tickets are present. */
const uint8_t *ticket = NULL;
@@ -440,24 +452,27 @@
ssl->version > SSL3_VERSION &&
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,
+ int from_cache = 0;
+ if (tickets_supported && ticket_len > 0) {
+ if (!tls_process_ticket(ssl, &session, &renew_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. */
+ /* The client didn't send a ticket, so the session ID is a real ID. */
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;
}
+ from_cache = 1;
}
if (session == NULL ||
session->sid_ctx_length != ssl->sid_ctx_length ||
memcmp(session->sid_ctx, ssl->sid_ctx, ssl->sid_ctx_length) != 0) {
+ /* The client did not offer a suitable ticket or session ID. If supported,
+ * the new session should use a ticket. */
goto no_session;
}
@@ -471,11 +486,12 @@
* effectively disable the session cache by accident without anyone
* noticing). */
OPENSSL_PUT_ERROR(SSL, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED);
- goto fatal_error;
+ SSL_SESSION_free(session);
+ return ssl_session_error;
}
if (session->timeout < (long)(time(NULL) - session->time)) {
- if (!tickets_supported) {
+ if (from_cache) {
/* The session was from the cache, so remove it. */
SSL_CTX_remove_session(ssl->initial_ctx, session);
}
@@ -483,13 +499,9 @@
}
*out_session = session;
- *out_send_ticket = send_ticket;
+ *out_send_ticket = renew_ticket;
return ssl_session_success;
-fatal_error:
- SSL_SESSION_free(session);
- return ssl_session_error;
-
no_session:
*out_session = NULL;
*out_send_ticket = tickets_supported;
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index 9558f1c..590a2c1 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -18,13 +18,16 @@
#include <algorithm>
#include <string>
+#include <utility>
#include <vector>
#include <openssl/base64.h>
#include <openssl/bio.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
+#include <openssl/pem.h>
#include <openssl/ssl.h>
+#include <openssl/x509.h>
#include "test/scoped_types.h"
#include "../crypto/test/test_util.h"
@@ -38,215 +41,178 @@
struct CipherTest {
// The rule string to apply.
const char *rule;
- // The list of expected ciphers, in order, terminated with -1.
- const ExpectedCipher *expected;
+ // The list of expected ciphers, in order.
+ std::vector<ExpectedCipher> expected;
};
-// Selecting individual ciphers should work.
-static const char kRule1[] =
- "ECDHE-ECDSA-CHACHA20-POLY1305:"
- "ECDHE-RSA-CHACHA20-POLY1305:"
- "ECDHE-ECDSA-AES128-GCM-SHA256:"
- "ECDHE-RSA-AES128-GCM-SHA256";
-
-static const ExpectedCipher kExpected1[] = {
- { TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0 },
- { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD, 0 },
- { TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0 },
- { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD, 0 },
- { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 },
- { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
- { 0, 0 },
-};
-
-// + reorders selected ciphers to the end, keeping their relative
-// order.
-static const char kRule2[] =
- "ECDHE-ECDSA-CHACHA20-POLY1305:"
- "ECDHE-RSA-CHACHA20-POLY1305:"
- "ECDHE-ECDSA-AES128-GCM-SHA256:"
- "ECDHE-RSA-AES128-GCM-SHA256:"
- "+aRSA";
-
-static const ExpectedCipher kExpected2[] = {
- { TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0 },
- { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD, 0 },
- { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 },
- { TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0 },
- { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD, 0 },
- { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
- { 0, 0 },
-};
-
-// ! banishes ciphers from future selections.
-static const char kRule3[] =
- "!aRSA:"
- "ECDHE-ECDSA-CHACHA20-POLY1305:"
- "ECDHE-RSA-CHACHA20-POLY1305:"
- "ECDHE-ECDSA-AES128-GCM-SHA256:"
- "ECDHE-RSA-AES128-GCM-SHA256";
-
-static const ExpectedCipher kExpected3[] = {
- { TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0 },
- { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD, 0 },
- { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 },
- { 0, 0 },
-};
-
-// Multiple masks can be ANDed in a single rule.
-static const char kRule4[] = "kRSA+AESGCM+AES128";
-
-static const ExpectedCipher kExpected4[] = {
- { TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0 },
- { 0, 0 },
-};
-
-// - removes selected ciphers, but preserves their order for future
-// selections. Select AES_128_GCM, but order the key exchanges RSA,
-// DHE_RSA, ECDHE_RSA.
-static const char kRule5[] =
- "ALL:-kECDHE:-kDHE:-kRSA:-ALL:"
- "AESGCM+AES128+aRSA";
-
-static const ExpectedCipher kExpected5[] = {
- { TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0 },
- { TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
- { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
- { 0, 0 },
-};
-
-// Unknown selectors are no-ops.
-static const char kRule6[] =
- "ECDHE-ECDSA-CHACHA20-POLY1305:"
- "ECDHE-RSA-CHACHA20-POLY1305:"
- "ECDHE-ECDSA-AES128-GCM-SHA256:"
- "ECDHE-RSA-AES128-GCM-SHA256:"
- "BOGUS1:-BOGUS2:+BOGUS3:!BOGUS4";
-
-static const ExpectedCipher kExpected6[] = {
- { TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0 },
- { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD, 0 },
- { TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0 },
- { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD, 0 },
- { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 },
- { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
- { 0, 0 },
-};
-
-// Square brackets specify equi-preference groups.
-static const char kRule7[] =
- "[ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES128-GCM-SHA256]:"
- "[ECDHE-RSA-CHACHA20-POLY1305]:"
- "ECDHE-RSA-AES128-GCM-SHA256";
-
-static const ExpectedCipher kExpected7[] = {
- { TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 1 },
- { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD, 1 },
- { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 },
- { TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 1 },
- { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD, 0 },
- { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
- { 0, 0 },
-};
-
-// @STRENGTH performs a stable strength-sort of the selected
-// ciphers and only the selected ciphers.
-static const char kRule8[] =
- // To simplify things, banish all but {ECDHE_RSA,RSA} x
- // {CHACHA20,AES_256_CBC,AES_128_CBC,RC4} x SHA1.
- "!kEDH:!AESGCM:!3DES:!SHA256:!MD5:!SHA384:"
- // Order some ciphers backwards by strength.
- "ALL:-CHACHA20:-AES256:-AES128:-RC4:-ALL:"
- // Select ECDHE ones and sort them by strength. Ties should resolve
- // based on the order above.
- "kECDHE:@STRENGTH:-ALL:"
- // Now bring back everything uses RSA. ECDHE_RSA should be first,
- // sorted by strength. Then RSA, backwards by strength.
- "aRSA";
-
-static const ExpectedCipher kExpected8[] = {
- { TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA, 0 },
- { TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0 },
- { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD, 0 },
- { TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA, 0 },
- { TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA, 0 },
- { SSL3_CK_RSA_RC4_128_SHA, 0 },
- { TLS1_CK_RSA_WITH_AES_128_SHA, 0 },
- { TLS1_CK_RSA_WITH_AES_256_SHA, 0 },
- { 0, 0 },
-};
-
-// Exact ciphers may not be used in multi-part rules; they are treated
-// as unknown aliases.
-static const char kRule9[] =
- "ECDHE-ECDSA-AES128-GCM-SHA256:"
- "ECDHE-RSA-AES128-GCM-SHA256:"
- "!ECDHE-RSA-AES128-GCM-SHA256+RSA:"
- "!ECDSA+ECDHE-ECDSA-AES128-GCM-SHA256";
-
-static const ExpectedCipher kExpected9[] = {
- { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 },
- { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
- { 0, 0 },
-};
-
-// SSLv3 matches everything that existed before TLS 1.2.
-static const char kRule10[] = "AES128-SHA:AES128-SHA256:!SSLv3";
-
-static const ExpectedCipher kExpected10[] = {
- { TLS1_CK_RSA_WITH_AES_128_SHA256, 0 },
- { 0, 0 },
-};
-
-// TLSv1.2 matches everything added in TLS 1.2.
-static const char kRule11[] = "AES128-SHA:AES128-SHA256:!TLSv1.2";
-
-static const ExpectedCipher kExpected11[] = {
- { TLS1_CK_RSA_WITH_AES_128_SHA, 0 },
- { 0, 0 },
-};
-
-// The two directives have no intersection.
-static const char kRule12[] = "AES128-SHA:AES128-SHA256:!TLSv1.2+SSLv3";
-
-static const ExpectedCipher kExpected12[] = {
- { TLS1_CK_RSA_WITH_AES_128_SHA, 0 },
- { TLS1_CK_RSA_WITH_AES_128_SHA256, 0 },
- { 0, 0 },
-};
-
-// The shared name of the CHACHA20_POLY1305 variants behaves like a cipher name
-// and not an alias. It may not be used in a multipart rule. (That the shared
-// name works is covered by the standard tests.)
-static const char kRule13[] =
- "ECDHE-ECDSA-CHACHA20-POLY1305:"
- "ECDHE-RSA-CHACHA20-POLY1305:"
- "!ECDHE-RSA-CHACHA20-POLY1305+RSA:"
- "!ECDSA+ECDHE-ECDSA-CHACHA20-POLY1305";
-
-static const ExpectedCipher kExpected13[] = {
- { TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0 },
- { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD, 0 },
- { TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0 },
- { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD, 0 },
- { 0, 0 },
-};
-
-static CipherTest kCipherTests[] = {
- { kRule1, kExpected1 },
- { kRule2, kExpected2 },
- { kRule3, kExpected3 },
- { kRule4, kExpected4 },
- { kRule5, kExpected5 },
- { kRule6, kExpected6 },
- { kRule7, kExpected7 },
- { kRule8, kExpected8 },
- { kRule9, kExpected9 },
- { kRule10, kExpected10 },
- { kRule11, kExpected11 },
- { kRule12, kExpected12 },
- { kRule13, kExpected13 },
- { NULL, NULL },
+static const CipherTest kCipherTests[] = {
+ // Selecting individual ciphers should work.
+ {
+ "ECDHE-ECDSA-CHACHA20-POLY1305:"
+ "ECDHE-RSA-CHACHA20-POLY1305:"
+ "ECDHE-ECDSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES128-GCM-SHA256",
+ {
+ {TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD, 0},
+ {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ },
+ // + reorders selected ciphers to the end, keeping their relative order.
+ {
+ "ECDHE-ECDSA-CHACHA20-POLY1305:"
+ "ECDHE-RSA-CHACHA20-POLY1305:"
+ "ECDHE-ECDSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES128-GCM-SHA256:"
+ "+aRSA",
+ {
+ {TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD, 0},
+ {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ },
+ // ! banishes ciphers from future selections.
+ {
+ "!aRSA:"
+ "ECDHE-ECDSA-CHACHA20-POLY1305:"
+ "ECDHE-RSA-CHACHA20-POLY1305:"
+ "ECDHE-ECDSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES128-GCM-SHA256",
+ {
+ {TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD, 0},
+ {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ },
+ // Multiple masks can be ANDed in a single rule.
+ {
+ "kRSA+AESGCM+AES128",
+ {
+ {TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ },
+ // - removes selected ciphers, but preserves their order for future
+ // selections. Select AES_128_GCM, but order the key exchanges RSA, DHE_RSA,
+ // ECDHE_RSA.
+ {
+ "ALL:-kECDHE:-kDHE:-kRSA:-ALL:"
+ "AESGCM+AES128+aRSA",
+ {
+ {TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0},
+ {TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ },
+ // Unknown selectors are no-ops.
+ {
+ "ECDHE-ECDSA-CHACHA20-POLY1305:"
+ "ECDHE-RSA-CHACHA20-POLY1305:"
+ "ECDHE-ECDSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES128-GCM-SHA256:"
+ "BOGUS1:-BOGUS2:+BOGUS3:!BOGUS4",
+ {
+ {TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD, 0},
+ {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ },
+ // Square brackets specify equi-preference groups.
+ {
+ "[ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES128-GCM-SHA256]:"
+ "[ECDHE-RSA-CHACHA20-POLY1305]:"
+ "ECDHE-RSA-AES128-GCM-SHA256",
+ {
+ {TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 1},
+ {TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD, 1},
+ {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 1},
+ {TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ },
+ // @STRENGTH performs a stable strength-sort of the selected ciphers and
+ // only the selected ciphers.
+ {
+ // To simplify things, banish all but {ECDHE_RSA,RSA} x
+ // {CHACHA20,AES_256_CBC,AES_128_CBC,RC4} x SHA1.
+ "!kEDH:!AESGCM:!3DES:!SHA256:!MD5:!SHA384:"
+ // Order some ciphers backwards by strength.
+ "ALL:-CHACHA20:-AES256:-AES128:-RC4:-ALL:"
+ // Select ECDHE ones and sort them by strength. Ties should resolve
+ // based on the order above.
+ "kECDHE:@STRENGTH:-ALL:"
+ // Now bring back everything uses RSA. ECDHE_RSA should be first, sorted
+ // by strength. Then RSA, backwards by strength.
+ "aRSA",
+ {
+ {TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA, 0},
+ {SSL3_CK_RSA_RC4_128_SHA, 0},
+ {TLS1_CK_RSA_WITH_AES_128_SHA, 0},
+ {TLS1_CK_RSA_WITH_AES_256_SHA, 0},
+ },
+ },
+ // Exact ciphers may not be used in multi-part rules; they are treated
+ // as unknown aliases.
+ {
+ "ECDHE-ECDSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES128-GCM-SHA256:"
+ "!ECDHE-RSA-AES128-GCM-SHA256+RSA:"
+ "!ECDSA+ECDHE-ECDSA-AES128-GCM-SHA256",
+ {
+ {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ },
+ // SSLv3 matches everything that existed before TLS 1.2.
+ {
+ "AES128-SHA:AES128-SHA256:!SSLv3",
+ {
+ {TLS1_CK_RSA_WITH_AES_128_SHA256, 0},
+ },
+ },
+ // TLSv1.2 matches everything added in TLS 1.2.
+ {
+ "AES128-SHA:AES128-SHA256:!TLSv1.2",
+ {
+ {TLS1_CK_RSA_WITH_AES_128_SHA, 0},
+ },
+ },
+ // The two directives have no intersection.
+ {
+ "AES128-SHA:AES128-SHA256:!TLSv1.2+SSLv3",
+ {
+ {TLS1_CK_RSA_WITH_AES_128_SHA, 0},
+ {TLS1_CK_RSA_WITH_AES_128_SHA256, 0},
+ },
+ },
+ // The shared name of the CHACHA20_POLY1305 variants behaves like a cipher
+ // name and not an alias. It may not be used in a multipart rule. (That the
+ // shared name works is covered by the standard tests.)
+ {
+ "ECDHE-ECDSA-CHACHA20-POLY1305:"
+ "ECDHE-RSA-CHACHA20-POLY1305:"
+ "!ECDHE-RSA-CHACHA20-POLY1305+RSA:"
+ "!ECDSA+ECDHE-ECDSA-CHACHA20-POLY1305",
+ {
+ {TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD, 0},
+ },
+ },
};
static const char *kBadRules[] = {
@@ -270,7 +236,6 @@
"[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:!FOO",
"[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:-FOO",
"[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:@STRENGTH",
- NULL,
};
static const char *kMustNotIncludeNull[] = {
@@ -287,7 +252,6 @@
"SSLv3",
"TLSv1",
"TLSv1.2",
- NULL
};
static void PrintCipherPreferenceList(ssl_cipher_preference_list_st *list) {
@@ -310,36 +274,35 @@
}
}
-static bool TestCipherRule(CipherTest *t) {
+static bool TestCipherRule(const CipherTest &t) {
ScopedSSL_CTX ctx(SSL_CTX_new(TLS_method()));
if (!ctx) {
return false;
}
- if (!SSL_CTX_set_cipher_list(ctx.get(), t->rule)) {
- fprintf(stderr, "Error testing cipher rule '%s'\n", t->rule);
+ if (!SSL_CTX_set_cipher_list(ctx.get(), t.rule)) {
+ fprintf(stderr, "Error testing cipher rule '%s'\n", t.rule);
return false;
}
// Compare the two lists.
- size_t i;
- for (i = 0; i < sk_SSL_CIPHER_num(ctx->cipher_list->ciphers); i++) {
+ if (sk_SSL_CIPHER_num(ctx->cipher_list->ciphers) != t.expected.size()) {
+ fprintf(stderr, "Error: cipher rule '%s' evaluated to:\n", t.rule);
+ PrintCipherPreferenceList(ctx->cipher_list);
+ return false;
+ }
+
+ for (size_t i = 0; i < t.expected.size(); i++) {
const SSL_CIPHER *cipher =
sk_SSL_CIPHER_value(ctx->cipher_list->ciphers, i);
- if (t->expected[i].id != SSL_CIPHER_get_id(cipher) ||
- t->expected[i].in_group_flag != ctx->cipher_list->in_group_flags[i]) {
- fprintf(stderr, "Error: cipher rule '%s' evaluated to:\n", t->rule);
+ if (t.expected[i].id != SSL_CIPHER_get_id(cipher) ||
+ t.expected[i].in_group_flag != ctx->cipher_list->in_group_flags[i]) {
+ fprintf(stderr, "Error: cipher rule '%s' evaluated to:\n", t.rule);
PrintCipherPreferenceList(ctx->cipher_list);
return false;
}
}
- if (t->expected[i].id != 0) {
- fprintf(stderr, "Error: cipher rule '%s' evaluated to:\n", t->rule);
- PrintCipherPreferenceList(ctx->cipher_list);
- return false;
- }
-
return true;
}
@@ -362,26 +325,26 @@
}
static bool TestCipherRules() {
- for (size_t i = 0; kCipherTests[i].rule != NULL; i++) {
- if (!TestCipherRule(&kCipherTests[i])) {
+ for (const CipherTest &test : kCipherTests) {
+ if (!TestCipherRule(test)) {
return false;
}
}
- for (size_t i = 0; kBadRules[i] != NULL; i++) {
+ for (const char *rule : kBadRules) {
ScopedSSL_CTX ctx(SSL_CTX_new(SSLv23_server_method()));
if (!ctx) {
return false;
}
- if (SSL_CTX_set_cipher_list(ctx.get(), kBadRules[i])) {
- fprintf(stderr, "Cipher rule '%s' unexpectedly succeeded\n", kBadRules[i]);
+ if (SSL_CTX_set_cipher_list(ctx.get(), rule)) {
+ fprintf(stderr, "Cipher rule '%s' unexpectedly succeeded\n", rule);
return false;
}
ERR_clear_error();
}
- for (size_t i = 0; kMustNotIncludeNull[i] != NULL; i++) {
- if (!TestRuleDoesNotIncludeNull(kMustNotIncludeNull[i])) {
+ for (const char *rule : kMustNotIncludeNull) {
+ if (!TestRuleDoesNotIncludeNull(rule)) {
return false;
}
}
@@ -932,23 +895,6 @@
return ret;
}
-// TODO(davidben): Switch this to a |std::vector<ScopedSSL_SESSION>| once we can
-// rely on a move-aware |std::vector|.
-class ScopedSessionVector {
- public:
- explicit ScopedSessionVector(std::vector<SSL_SESSION*> *sessions)
- : sessions_(sessions) {}
-
- ~ScopedSessionVector() {
- for (SSL_SESSION *session : *sessions_) {
- SSL_SESSION_free(session);
- }
- }
-
- private:
- std::vector<SSL_SESSION*> *const sessions_;
-};
-
// Test that the internal session cache behaves as expected.
static bool TestInternalSessionCache() {
ScopedSSL_CTX ctx(SSL_CTX_new(TLS_method()));
@@ -957,38 +903,38 @@
}
// Prepare 10 test sessions.
- std::vector<SSL_SESSION*> sessions;
- ScopedSessionVector cleanup(&sessions);
+ std::vector<ScopedSSL_SESSION> sessions;
for (int i = 0; i < 10; i++) {
ScopedSSL_SESSION session = CreateTestSession(i);
if (!session) {
return false;
}
- sessions.push_back(session.release());
+ sessions.push_back(std::move(session));
}
SSL_CTX_sess_set_cache_size(ctx.get(), 5);
// Insert all the test sessions.
- for (SSL_SESSION *session : sessions) {
- if (!SSL_CTX_add_session(ctx.get(), session)) {
+ for (const auto &session : sessions) {
+ if (!SSL_CTX_add_session(ctx.get(), session.get())) {
return false;
}
}
// Only the last five should be in the list.
- std::vector<SSL_SESSION*> expected;
- expected.push_back(sessions[9]);
- expected.push_back(sessions[8]);
- expected.push_back(sessions[7]);
- expected.push_back(sessions[6]);
- expected.push_back(sessions[5]);
+ std::vector<SSL_SESSION*> expected = {
+ sessions[9].get(),
+ sessions[8].get(),
+ sessions[7].get(),
+ sessions[6].get(),
+ sessions[5].get(),
+ };
if (!ExpectCache(ctx.get(), expected)) {
return false;
}
// Inserting an element already in the cache should fail.
- if (SSL_CTX_add_session(ctx.get(), sessions[7]) ||
+ if (SSL_CTX_add_session(ctx.get(), sessions[7].get()) ||
!ExpectCache(ctx.get(), expected)) {
return false;
}
@@ -999,32 +945,34 @@
if (!collision || !SSL_CTX_add_session(ctx.get(), collision.get())) {
return false;
}
- expected.clear();
- expected.push_back(collision.get());
- expected.push_back(sessions[9]);
- expected.push_back(sessions[8]);
- expected.push_back(sessions[6]);
- expected.push_back(sessions[5]);
+ expected = {
+ collision.get(),
+ sessions[9].get(),
+ sessions[8].get(),
+ sessions[6].get(),
+ sessions[5].get(),
+ };
if (!ExpectCache(ctx.get(), expected)) {
return false;
}
// Removing sessions behaves correctly.
- if (!SSL_CTX_remove_session(ctx.get(), sessions[6])) {
+ if (!SSL_CTX_remove_session(ctx.get(), sessions[6].get())) {
return false;
}
- expected.clear();
- expected.push_back(collision.get());
- expected.push_back(sessions[9]);
- expected.push_back(sessions[8]);
- expected.push_back(sessions[5]);
+ expected = {
+ collision.get(),
+ sessions[9].get(),
+ sessions[8].get(),
+ sessions[5].get(),
+ };
if (!ExpectCache(ctx.get(), expected)) {
return false;
}
// Removing sessions requires an exact match.
- if (SSL_CTX_remove_session(ctx.get(), sessions[0]) ||
- SSL_CTX_remove_session(ctx.get(), sessions[7]) ||
+ if (SSL_CTX_remove_session(ctx.get(), sessions[0].get()) ||
+ SSL_CTX_remove_session(ctx.get(), sessions[7].get()) ||
!ExpectCache(ctx.get(), expected)) {
return false;
}
@@ -1032,6 +980,157 @@
return true;
}
+static uint16_t EpochFromSequence(uint64_t seq) {
+ return static_cast<uint16_t>(seq >> 48);
+}
+
+static ScopedX509 GetTestCertificate() {
+ static const char kCertPEM[] =
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIICWDCCAcGgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV\n"
+ "BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX\n"
+ "aWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBF\n"
+ "MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50\n"
+ "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n"
+ "gQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLci\n"
+ "HnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfV\n"
+ "W28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo1AwTjAdBgNV\n"
+ "HQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4f\n"
+ "Zbf6Vr5sp3Xaha8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQA76Hht\n"
+ "ldY9avcTGSwbwoiuIqv0jTL1fHFnzy3RHMLDh+Lpvolc5DSrSJHCP5WuK0eeJXhr\n"
+ "T5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4f\n"
+ "j2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==\n"
+ "-----END CERTIFICATE-----\n";
+ ScopedBIO bio(BIO_new_mem_buf(kCertPEM, strlen(kCertPEM)));
+ return ScopedX509(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+}
+
+static ScopedEVP_PKEY GetTestKey() {
+ static const char kKeyPEM[] =
+ "-----BEGIN RSA PRIVATE KEY-----\n"
+ "MIICXgIBAAKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92\n"
+ "kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiF\n"
+ "KKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQAB\n"
+ "AoGBAIBy09Fd4DOq/Ijp8HeKuCMKTHqTW1xGHshLQ6jwVV2vWZIn9aIgmDsvkjCe\n"
+ "i6ssZvnbjVcwzSoByhjN8ZCf/i15HECWDFFh6gt0P5z0MnChwzZmvatV/FXCT0j+\n"
+ "WmGNB/gkehKjGXLLcjTb6dRYVJSCZhVuOLLcbWIV10gggJQBAkEA8S8sGe4ezyyZ\n"
+ "m4e9r95g6s43kPqtj5rewTsUxt+2n4eVodD+ZUlCULWVNAFLkYRTBCASlSrm9Xhj\n"
+ "QpmWAHJUkQJBAOVzQdFUaewLtdOJoPCtpYoY1zd22eae8TQEmpGOR11L6kbxLQsk\n"
+ "aMly/DOnOaa82tqAGTdqDEZgSNmCeKKknmECQAvpnY8GUOVAubGR6c+W90iBuQLj\n"
+ "LtFp/9ihd2w/PoDwrHZaoUYVcT4VSfJQog/k7kjE4MYXYWL8eEKg3WTWQNECQQDk\n"
+ "104Wi91Umd1PzF0ijd2jXOERJU1wEKe6XLkYYNHWQAe5l4J4MWj9OdxFXAxIuuR/\n"
+ "tfDwbqkta4xcux67//khAkEAvvRXLHTaa6VFzTaiiO8SaFsHV3lQyXOtMrBpB5jd\n"
+ "moZWgjHvB2W9Ckn7sDqsPB+U2tyX0joDdQEyuiMECDY8oQ==\n"
+ "-----END RSA PRIVATE KEY-----\n";
+ ScopedBIO bio(BIO_new_mem_buf(kKeyPEM, strlen(kKeyPEM)));
+ return ScopedEVP_PKEY(
+ PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
+}
+
+static bool TestSequenceNumber(bool dtls) {
+ ScopedSSL_CTX client_ctx(SSL_CTX_new(dtls ? DTLS_method() : TLS_method()));
+ ScopedSSL_CTX server_ctx(SSL_CTX_new(dtls ? DTLS_method() : TLS_method()));
+ if (!client_ctx || !server_ctx) {
+ return false;
+ }
+
+ ScopedX509 cert = GetTestCertificate();
+ ScopedEVP_PKEY key = GetTestKey();
+ if (!cert || !key ||
+ !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) {
+ return false;
+ }
+
+ // Create a client and server connected to each other.
+ ScopedSSL client(SSL_new(client_ctx.get())), server(SSL_new(server_ctx.get()));
+ if (!client || !server) {
+ return false;
+ }
+ SSL_set_connect_state(client.get());
+ SSL_set_accept_state(server.get());
+
+ BIO *bio1, *bio2;
+ if (!BIO_new_bio_pair(&bio1, 0, &bio2, 0)) {
+ return false;
+ }
+ // SSL_set_bio takes ownership.
+ SSL_set_bio(client.get(), bio1, bio1);
+ SSL_set_bio(server.get(), bio2, bio2);
+
+ // Drive both their handshakes to completion.
+ for (;;) {
+ int client_ret = SSL_do_handshake(client.get());
+ int client_err = SSL_get_error(client.get(), client_ret);
+ if (client_err != SSL_ERROR_NONE &&
+ client_err != SSL_ERROR_WANT_READ &&
+ client_err != SSL_ERROR_WANT_WRITE) {
+ fprintf(stderr, "Client error: %d\n", client_err);
+ return false;
+ }
+
+ int server_ret = SSL_do_handshake(server.get());
+ int server_err = SSL_get_error(server.get(), server_ret);
+ if (server_err != SSL_ERROR_NONE &&
+ server_err != SSL_ERROR_WANT_READ &&
+ server_err != SSL_ERROR_WANT_WRITE) {
+ fprintf(stderr, "Server error: %d\n", server_err);
+ return false;
+ }
+
+ if (client_ret == 1 && server_ret == 1) {
+ break;
+ }
+ }
+
+ uint64_t client_read_seq = SSL_get_read_sequence(client.get());
+ uint64_t client_write_seq = SSL_get_write_sequence(client.get());
+ uint64_t server_read_seq = SSL_get_read_sequence(server.get());
+ uint64_t server_write_seq = SSL_get_write_sequence(server.get());
+
+ if (dtls) {
+ // Both client and server must be at epoch 1.
+ if (EpochFromSequence(client_read_seq) != 1 ||
+ EpochFromSequence(client_write_seq) != 1 ||
+ EpochFromSequence(server_read_seq) != 1 ||
+ EpochFromSequence(server_write_seq) != 1) {
+ fprintf(stderr, "Bad epochs.\n");
+ return false;
+ }
+
+ // The next record to be written should exceed the largest received.
+ if (client_write_seq <= server_read_seq ||
+ server_write_seq <= client_read_seq) {
+ fprintf(stderr, "Inconsistent sequence numbers.\n");
+ return false;
+ }
+ } else {
+ // The next record to be written should equal the next to be received.
+ if (client_write_seq != server_read_seq ||
+ server_write_seq != client_write_seq) {
+ fprintf(stderr, "Inconsistent sequence numbers.\n");
+ return false;
+ }
+ }
+
+ // Send a record from client to server.
+ uint8_t byte = 0;
+ if (SSL_write(client.get(), &byte, 1) != 1 ||
+ SSL_read(server.get(), &byte, 1) != 1) {
+ fprintf(stderr, "Could not send byte.\n");
+ return false;
+ }
+
+ // The client write and server read sequence numbers should have incremented.
+ if (client_write_seq + 1 != SSL_get_write_sequence(client.get()) ||
+ server_read_seq + 1 != SSL_get_read_sequence(server.get())) {
+ fprintf(stderr, "Sequence numbers did not increment.\n");\
+ return false;
+ }
+
+ return true;
+}
+
int main() {
CRYPTO_library_init();
@@ -1053,7 +1152,9 @@
!TestCipherGetRFCName() ||
!TestPaddingExtension() ||
!TestClientCAList() ||
- !TestInternalSessionCache()) {
+ !TestInternalSessionCache() ||
+ !TestSequenceNumber(false /* TLS */) ||
+ !TestSequenceNumber(true /* DTLS */)) {
ERR_print_errors_fp(stderr);
return 1;
}
diff --git a/src/ssl/t1_enc.c b/src/ssl/t1_enc.c
index 0f1d683..b599207 100644
--- a/src/ssl/t1_enc.c
+++ b/src/ssl/t1_enc.c
@@ -136,7 +136,6 @@
#include <openssl/ssl.h>
#include <assert.h>
-#include <stdio.h>
#include <string.h>
#include <openssl/err.h>
@@ -144,7 +143,7 @@
#include <openssl/hmac.h>
#include <openssl/md5.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include <openssl/rand.h>
#include "internal.h"
@@ -224,11 +223,10 @@
return ret;
}
-int tls1_prf(SSL *ssl, 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) {
-
+static int tls1_prf(const SSL *ssl, 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) {
if (out_len == 0) {
return 1;
}
@@ -260,15 +258,12 @@
return 1;
}
-static int tls1_generate_key_block(SSL *ssl, uint8_t *out, size_t out_len) {
- return ssl->enc_method->prf(
- ssl, out, out_len, ssl->session->master_key,
- ssl->session->master_key_length, TLS_MD_KEY_EXPANSION_CONST,
- TLS_MD_KEY_EXPANSION_CONST_SIZE, ssl->s3->server_random, SSL3_RANDOM_SIZE,
- ssl->s3->client_random, SSL3_RANDOM_SIZE);
-}
-
int tls1_change_cipher_state(SSL *ssl, int which) {
+ /* Ensure the key block is set up. */
+ if (!tls1_setup_key_block(ssl)) {
+ return 0;
+ }
+
/* is_read is true if we have just read a ChangeCipherSpec message - i.e. we
* need to update the read cipherspec. Otherwise we have just written one. */
const char is_read = (which & SSL3_CC_READ) != 0;
@@ -277,63 +272,28 @@
* or a server reading a client's ChangeCipherSpec. */
const char use_client_keys = which == SSL3_CHANGE_CIPHER_CLIENT_WRITE ||
which == SSL3_CHANGE_CIPHER_SERVER_READ;
- const uint8_t *client_write_mac_secret, *server_write_mac_secret, *mac_secret;
- const uint8_t *client_write_key, *server_write_key, *key;
- const uint8_t *client_write_iv, *server_write_iv, *iv;
- const EVP_AEAD *aead = ssl->s3->tmp.new_aead;
- size_t key_len, iv_len, mac_secret_len;
- const uint8_t *key_data;
- /* Reset sequence number to zero. */
- if (is_read) {
- if (SSL_IS_DTLS(ssl)) {
- ssl->d1->r_epoch++;
- memset(&ssl->d1->bitmap, 0, sizeof(ssl->d1->bitmap));
- }
- memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence));
- } else {
- if (SSL_IS_DTLS(ssl)) {
- ssl->d1->w_epoch++;
- memcpy(ssl->d1->last_write_sequence, ssl->s3->write_sequence,
- sizeof(ssl->s3->write_sequence));
- }
- memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence));
- }
+ size_t mac_secret_len = ssl->s3->tmp.new_mac_secret_len;
+ size_t key_len = ssl->s3->tmp.new_key_len;
+ size_t iv_len = ssl->s3->tmp.new_fixed_iv_len;
+ assert((mac_secret_len + key_len + iv_len) * 2 ==
+ ssl->s3->tmp.key_block_length);
- mac_secret_len = ssl->s3->tmp.new_mac_secret_len;
- iv_len = ssl->s3->tmp.new_fixed_iv_len;
-
- if (aead == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- key_len = EVP_AEAD_key_length(aead);
- if (mac_secret_len > 0) {
- /* For "stateful" AEADs (i.e. compatibility with pre-AEAD cipher
- * suites) the key length reported by |EVP_AEAD_key_length| will
- * include the MAC and IV key bytes. */
- if (key_len < mac_secret_len + iv_len) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- key_len -= mac_secret_len + iv_len;
- }
-
- key_data = ssl->s3->tmp.key_block;
- client_write_mac_secret = key_data;
+ const uint8_t *key_data = ssl->s3->tmp.key_block;
+ const uint8_t *client_write_mac_secret = key_data;
key_data += mac_secret_len;
- server_write_mac_secret = key_data;
+ const uint8_t *server_write_mac_secret = key_data;
key_data += mac_secret_len;
- client_write_key = key_data;
+ const uint8_t *client_write_key = key_data;
key_data += key_len;
- server_write_key = key_data;
+ const uint8_t *server_write_key = key_data;
key_data += key_len;
- client_write_iv = key_data;
+ const uint8_t *client_write_iv = key_data;
key_data += iv_len;
- server_write_iv = key_data;
+ const uint8_t *server_write_iv = key_data;
key_data += iv_len;
+ const uint8_t *mac_secret, *key, *iv;
if (use_client_keys) {
mac_secret = client_write_mac_secret;
key = client_write_key;
@@ -344,50 +304,51 @@
iv = server_write_iv;
}
- if (key_data - ssl->s3->tmp.key_block != ssl->s3->tmp.key_block_length) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ SSL_AEAD_CTX *aead_ctx =
+ SSL_AEAD_CTX_new(is_read ? evp_aead_open : evp_aead_seal,
+ ssl3_protocol_version(ssl), ssl->s3->tmp.new_cipher, key,
+ key_len, mac_secret, mac_secret_len, iv, iv_len);
+ if (aead_ctx == NULL) {
return 0;
}
if (is_read) {
- SSL_AEAD_CTX_free(ssl->aead_read_ctx);
- ssl->aead_read_ctx = SSL_AEAD_CTX_new(
- evp_aead_open, ssl3_version_from_wire(ssl, ssl->version),
- ssl->s3->tmp.new_cipher, key, key_len, mac_secret, mac_secret_len, iv,
- iv_len);
- return ssl->aead_read_ctx != NULL;
+ ssl_set_read_state(ssl, aead_ctx);
+ } else {
+ ssl_set_write_state(ssl, aead_ctx);
}
+ return 1;
+}
- SSL_AEAD_CTX_free(ssl->aead_write_ctx);
- ssl->aead_write_ctx = SSL_AEAD_CTX_new(
- evp_aead_seal, ssl3_version_from_wire(ssl, ssl->version),
- ssl->s3->tmp.new_cipher, key, key_len, mac_secret, mac_secret_len, iv,
- iv_len);
- return ssl->aead_write_ctx != NULL;
+size_t SSL_get_key_block_len(const SSL *ssl) {
+ return 2 * ((size_t)ssl->s3->tmp.new_mac_secret_len +
+ (size_t)ssl->s3->tmp.new_key_len +
+ (size_t)ssl->s3->tmp.new_fixed_iv_len);
+}
+
+int SSL_generate_key_block(const SSL *ssl, uint8_t *out, size_t out_len) {
+ return ssl->s3->enc_method->prf(
+ ssl, out, out_len, ssl->session->master_key,
+ ssl->session->master_key_length, TLS_MD_KEY_EXPANSION_CONST,
+ TLS_MD_KEY_EXPANSION_CONST_SIZE, ssl->s3->server_random, SSL3_RANDOM_SIZE,
+ ssl->s3->client_random, SSL3_RANDOM_SIZE);
}
int tls1_setup_key_block(SSL *ssl) {
- uint8_t *p;
- const EVP_AEAD *aead = NULL;
- int ret = 0;
- size_t mac_secret_len, fixed_iv_len, variable_iv_len, key_len;
- size_t key_block_len;
-
if (ssl->s3->tmp.key_block_length != 0) {
return 1;
}
- if (ssl->session->cipher == NULL) {
- goto cipher_unavailable_err;
- }
-
- if (!ssl_cipher_get_evp_aead(&aead, &mac_secret_len, &fixed_iv_len,
+ const EVP_AEAD *aead = NULL;
+ size_t mac_secret_len, fixed_iv_len;
+ if (ssl->session->cipher == NULL ||
+ !ssl_cipher_get_evp_aead(&aead, &mac_secret_len, &fixed_iv_len,
ssl->session->cipher,
- ssl3_version_from_wire(ssl, ssl->version))) {
- goto cipher_unavailable_err;
+ ssl3_protocol_version(ssl))) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
+ return 0;
}
- key_len = EVP_AEAD_key_length(aead);
- variable_iv_len = EVP_AEAD_nonce_length(aead);
+ size_t key_len = EVP_AEAD_key_length(aead);
if (mac_secret_len > 0) {
/* For "stateful" AEADs (i.e. compatibility with pre-AEAD cipher suites) the
* key length reported by |EVP_AEAD_key_length| will include the MAC key
@@ -397,53 +358,38 @@
return 0;
}
key_len -= mac_secret_len + fixed_iv_len;
- } else {
- /* The nonce is split into a fixed portion and a variable portion. */
- if (variable_iv_len < fixed_iv_len) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- variable_iv_len -= fixed_iv_len;
}
assert(mac_secret_len < 256);
+ assert(key_len < 256);
assert(fixed_iv_len < 256);
- assert(variable_iv_len < 256);
- ssl->s3->tmp.new_aead = aead;
ssl->s3->tmp.new_mac_secret_len = (uint8_t)mac_secret_len;
+ ssl->s3->tmp.new_key_len = (uint8_t)key_len;
ssl->s3->tmp.new_fixed_iv_len = (uint8_t)fixed_iv_len;
- ssl->s3->tmp.new_variable_iv_len = (uint8_t)variable_iv_len;
- key_block_len = key_len + mac_secret_len + fixed_iv_len;
- key_block_len *= 2;
+ size_t key_block_len = SSL_get_key_block_len(ssl);
ssl3_cleanup_key_block(ssl);
- p = (uint8_t *)OPENSSL_malloc(key_block_len);
- if (p == NULL) {
+ uint8_t *keyblock = OPENSSL_malloc(key_block_len);
+ if (keyblock == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- goto err;
+ return 0;
}
- ssl->s3->tmp.key_block_length = key_block_len;
- ssl->s3->tmp.key_block = p;
-
- if (!tls1_generate_key_block(ssl, p, key_block_len)) {
- goto err;
+ if (!SSL_generate_key_block(ssl, keyblock, key_block_len)) {
+ OPENSSL_free(keyblock);
+ return 0;
}
- ret = 1;
-
-err:
- return ret;
-
-cipher_unavailable_err:
- OPENSSL_PUT_ERROR(SSL, SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
- return 0;
+ assert(key_block_len < 256);
+ ssl->s3->tmp.key_block_length = (uint8_t)key_block_len;
+ ssl->s3->tmp.key_block = keyblock;
+ return 1;
}
-int tls1_cert_verify_mac(SSL *ssl, int md_nid, uint8_t *out) {
+static int tls1_cert_verify_mac(SSL *ssl, int md_nid, uint8_t *out) {
const EVP_MD_CTX *ctx_template;
if (md_nid == NID_md5) {
ctx_template = &ssl->s3->handshake_md5;
@@ -512,57 +458,58 @@
return (int)(md5_len + len);
}
-int tls1_final_finish_mac(SSL *ssl, const char *str, int slen, uint8_t *out) {
- uint8_t buf[2 * EVP_MAX_MD_SIZE];
- int err = 0;
- int digests_len;
-
+static int tls1_final_finish_mac(SSL *ssl, int from_server, uint8_t *out) {
/* At this point, the handshake should have released the handshake buffer on
* its own. */
assert(ssl->s3->handshake_buffer == NULL);
- digests_len = tls1_handshake_digest(ssl, buf, sizeof(buf));
+ const char *label = TLS_MD_CLIENT_FINISH_CONST;
+ size_t label_len = TLS_MD_SERVER_FINISH_CONST_SIZE;
+ if (from_server) {
+ label = TLS_MD_SERVER_FINISH_CONST;
+ label_len = TLS_MD_SERVER_FINISH_CONST_SIZE;
+ }
+
+ uint8_t buf[EVP_MAX_MD_SIZE];
+ int digests_len = tls1_handshake_digest(ssl, buf, sizeof(buf));
if (digests_len < 0) {
- err = 1;
- digests_len = 0;
- }
-
- if (!ssl->enc_method->prf(ssl, out, 12, ssl->session->master_key,
- ssl->session->master_key_length, str, slen, buf,
- digests_len, NULL, 0)) {
- err = 1;
- }
-
- if (err) {
return 0;
- } else {
- return 12;
}
+
+ static const size_t kFinishedLen = 12;
+ if (!ssl->s3->enc_method->prf(ssl, out, kFinishedLen,
+ ssl->session->master_key,
+ ssl->session->master_key_length, label,
+ label_len, buf, digests_len, NULL, 0)) {
+ return 0;
+ }
+
+ return (int)kFinishedLen;
}
int tls1_generate_master_secret(SSL *ssl, uint8_t *out,
const uint8_t *premaster,
size_t premaster_len) {
if (ssl->s3->tmp.extended_master_secret) {
- uint8_t digests[2 * EVP_MAX_MD_SIZE];
+ uint8_t digests[EVP_MAX_MD_SIZE];
int digests_len = tls1_handshake_digest(ssl, digests, sizeof(digests));
if (digests_len == -1) {
return 0;
}
- if (!ssl->enc_method->prf(ssl, out, SSL3_MASTER_SECRET_SIZE, premaster,
- premaster_len,
- TLS_MD_EXTENDED_MASTER_SECRET_CONST,
- TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE, digests,
- digests_len, NULL, 0)) {
+ if (!ssl->s3->enc_method->prf(ssl, out, SSL3_MASTER_SECRET_SIZE, premaster,
+ premaster_len,
+ TLS_MD_EXTENDED_MASTER_SECRET_CONST,
+ TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE,
+ digests, digests_len, NULL, 0)) {
return 0;
}
} else {
- if (!ssl->enc_method->prf(ssl, out, SSL3_MASTER_SECRET_SIZE, premaster,
- premaster_len, TLS_MD_MASTER_SECRET_CONST,
- TLS_MD_MASTER_SECRET_CONST_SIZE,
- ssl->s3->client_random, SSL3_RANDOM_SIZE,
- ssl->s3->server_random, SSL3_RANDOM_SIZE)) {
+ if (!ssl->s3->enc_method->prf(ssl, out, SSL3_MASTER_SECRET_SIZE, premaster,
+ premaster_len, TLS_MD_MASTER_SECRET_CONST,
+ TLS_MD_MASTER_SECRET_CONST_SIZE,
+ ssl->s3->client_random, SSL3_RANDOM_SIZE,
+ ssl->s3->server_random, SSL3_RANDOM_SIZE)) {
return 0;
}
}
@@ -570,12 +517,11 @@
return SSL3_MASTER_SECRET_SIZE;
}
-int tls1_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len,
- const char *label, size_t label_len,
- const uint8_t *context, size_t context_len,
- int use_context) {
+int SSL_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len,
+ const char *label, size_t label_len,
+ const uint8_t *context, size_t context_len,
+ int use_context) {
if (!ssl->s3->have_version || ssl->version == SSL3_VERSION) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
@@ -601,108 +547,16 @@
memcpy(seed + 2 * SSL3_RANDOM_SIZE + 2, context, context_len);
}
- int ret = ssl->enc_method->prf(ssl, out, out_len, ssl->session->master_key,
- ssl->session->master_key_length, label,
- label_len, seed, seed_len, NULL, 0);
+ int ret =
+ ssl->s3->enc_method->prf(ssl, out, out_len, ssl->session->master_key,
+ ssl->session->master_key_length, label,
+ label_len, seed, seed_len, NULL, 0);
OPENSSL_free(seed);
return ret;
}
-int tls1_alert_code(int code) {
- switch (code) {
- case SSL_AD_CLOSE_NOTIFY:
- return SSL3_AD_CLOSE_NOTIFY;
-
- case SSL_AD_UNEXPECTED_MESSAGE:
- return SSL3_AD_UNEXPECTED_MESSAGE;
-
- case SSL_AD_BAD_RECORD_MAC:
- return SSL3_AD_BAD_RECORD_MAC;
-
- case SSL_AD_DECRYPTION_FAILED:
- return TLS1_AD_DECRYPTION_FAILED;
-
- case SSL_AD_RECORD_OVERFLOW:
- return TLS1_AD_RECORD_OVERFLOW;
-
- case SSL_AD_DECOMPRESSION_FAILURE:
- return SSL3_AD_DECOMPRESSION_FAILURE;
-
- case SSL_AD_HANDSHAKE_FAILURE:
- return SSL3_AD_HANDSHAKE_FAILURE;
-
- case SSL_AD_NO_CERTIFICATE:
- return -1;
-
- case SSL_AD_BAD_CERTIFICATE:
- return SSL3_AD_BAD_CERTIFICATE;
-
- case SSL_AD_UNSUPPORTED_CERTIFICATE:
- return SSL3_AD_UNSUPPORTED_CERTIFICATE;
-
- case SSL_AD_CERTIFICATE_REVOKED:
- return SSL3_AD_CERTIFICATE_REVOKED;
-
- case SSL_AD_CERTIFICATE_EXPIRED:
- return SSL3_AD_CERTIFICATE_EXPIRED;
-
- case SSL_AD_CERTIFICATE_UNKNOWN:
- return SSL3_AD_CERTIFICATE_UNKNOWN;
-
- case SSL_AD_ILLEGAL_PARAMETER:
- return SSL3_AD_ILLEGAL_PARAMETER;
-
- case SSL_AD_UNKNOWN_CA:
- return TLS1_AD_UNKNOWN_CA;
-
- case SSL_AD_ACCESS_DENIED:
- return TLS1_AD_ACCESS_DENIED;
-
- case SSL_AD_DECODE_ERROR:
- return TLS1_AD_DECODE_ERROR;
-
- case SSL_AD_DECRYPT_ERROR:
- return TLS1_AD_DECRYPT_ERROR;
- case SSL_AD_EXPORT_RESTRICTION:
- return TLS1_AD_EXPORT_RESTRICTION;
-
- case SSL_AD_PROTOCOL_VERSION:
- return TLS1_AD_PROTOCOL_VERSION;
-
- case SSL_AD_INSUFFICIENT_SECURITY:
- return TLS1_AD_INSUFFICIENT_SECURITY;
-
- case SSL_AD_INTERNAL_ERROR:
- return TLS1_AD_INTERNAL_ERROR;
-
- case SSL_AD_USER_CANCELLED:
- return TLS1_AD_USER_CANCELLED;
-
- case SSL_AD_NO_RENEGOTIATION:
- return TLS1_AD_NO_RENEGOTIATION;
-
- case SSL_AD_UNSUPPORTED_EXTENSION:
- return TLS1_AD_UNSUPPORTED_EXTENSION;
-
- case SSL_AD_CERTIFICATE_UNOBTAINABLE:
- return TLS1_AD_CERTIFICATE_UNOBTAINABLE;
-
- case SSL_AD_UNRECOGNIZED_NAME:
- return TLS1_AD_UNRECOGNIZED_NAME;
-
- case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE:
- return TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
-
- case SSL_AD_BAD_CERTIFICATE_HASH_VALUE:
- return TLS1_AD_BAD_CERTIFICATE_HASH_VALUE;
-
- case SSL_AD_UNKNOWN_PSK_IDENTITY:
- return TLS1_AD_UNKNOWN_PSK_IDENTITY;
-
- case SSL_AD_INAPPROPRIATE_FALLBACK:
- return SSL3_AD_INAPPROPRIATE_FALLBACK;
-
- default:
- return -1;
- }
-}
+const SSL3_ENC_METHOD TLSv1_enc_data = {
+ tls1_prf,
+ tls1_final_finish_mac,
+ tls1_cert_verify_mac,
+};
diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c
index 5aea08b..eac9579 100644
--- a/src/ssl/t1_lib.c
+++ b/src/ssl/t1_lib.c
@@ -110,7 +110,6 @@
#include <assert.h>
#include <limits.h>
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -120,7 +119,7 @@
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include <openssl/rand.h>
#include <openssl/type_check.h>
@@ -130,48 +129,6 @@
static int ssl_check_clienthello_tlsext(SSL *ssl);
static int ssl_check_serverhello_tlsext(SSL *ssl);
-const SSL3_ENC_METHOD TLSv1_enc_data = {
- tls1_prf,
- tls1_setup_key_block,
- tls1_generate_master_secret,
- tls1_change_cipher_state,
- tls1_final_finish_mac,
- tls1_cert_verify_mac,
- TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
- TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
- tls1_alert_code,
- tls1_export_keying_material,
- 0,
-};
-
-const SSL3_ENC_METHOD TLSv1_1_enc_data = {
- tls1_prf,
- tls1_setup_key_block,
- tls1_generate_master_secret,
- tls1_change_cipher_state,
- tls1_final_finish_mac,
- tls1_cert_verify_mac,
- TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
- TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
- tls1_alert_code,
- tls1_export_keying_material,
- SSL_ENC_FLAG_EXPLICIT_IV,
-};
-
-const SSL3_ENC_METHOD TLSv1_2_enc_data = {
- tls1_prf,
- tls1_setup_key_block,
- tls1_generate_master_secret,
- tls1_change_cipher_state,
- tls1_final_finish_mac,
- tls1_cert_verify_mac,
- TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
- TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
- tls1_alert_code,
- tls1_export_keying_material,
- SSL_ENC_FLAG_EXPLICIT_IV|SSL_ENC_FLAG_SIGALGS|SSL_ENC_FLAG_SHA256_PRF,
-};
-
static int compare_uint16_t(const void *p1, const void *p2) {
uint16_t u1 = *((const uint16_t *)p1);
uint16_t u2 = *((const uint16_t *)p2);
@@ -211,8 +168,7 @@
return 1;
}
- extension_types =
- (uint16_t *)OPENSSL_malloc(sizeof(uint16_t) * num_extensions);
+ extension_types = OPENSSL_malloc(sizeof(uint16_t) * num_extensions);
if (extension_types == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto done;
@@ -336,6 +292,7 @@
}
static const uint16_t eccurves_default[] = {
+ SSL_CURVE_X25519,
SSL_CURVE_SECP256R1,
SSL_CURVE_SECP384R1,
#if defined(BORINGSSL_ANDROID_SYSTEM)
@@ -418,7 +375,7 @@
uint16_t *curve_ids;
size_t i;
- curve_ids = (uint16_t *)OPENSSL_malloc(ncurves * sizeof(uint16_t));
+ curve_ids = OPENSSL_malloc(ncurves * sizeof(uint16_t));
if (curve_ids == NULL) {
return 0;
}
@@ -551,7 +508,6 @@
tlsext_sigalg(TLSEXT_hash_sha512)
tlsext_sigalg(TLSEXT_hash_sha384)
tlsext_sigalg(TLSEXT_hash_sha256)
- tlsext_sigalg(TLSEXT_hash_sha224)
tlsext_sigalg(TLSEXT_hash_sha1)
};
@@ -731,82 +687,44 @@
return 1;
}
- /* The servername extension is treated as follows:
- *
- * - Only the hostname type is supported with a maximum length of 255.
- * - The servername is rejected if too long or if it contains zeros, in
- * which case an fatal alert is generated.
- * - The servername field is maintained together with the session cache.
- * - When a session is resumed, the servername 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;
-
+ CBS server_name_list, host_name;
+ uint8_t name_type;
if (!CBS_get_u16_length_prefixed(contents, &server_name_list) ||
- CBS_len(&server_name_list) == 0 ||
+ !CBS_get_u8(&server_name_list, &name_type) ||
+ /* Although the server_name extension was intended to be extensible to
+ * new name types and multiple names, OpenSSL 1.0.x had a bug which meant
+ * different name types will cause an error. Further, RFC 4366 originally
+ * defined syntax inextensibly. RFC 6066 corrected this mistake, but
+ * adding new name types is no longer feasible.
+ *
+ * Act as if the extensibility does not exist to simplify parsing. */
+ !CBS_get_u16_length_prefixed(&server_name_list, &host_name) ||
+ CBS_len(&server_name_list) != 0 ||
CBS_len(contents) != 0) {
return 0;
}
- /* Decode each ServerName in the extension. */
- while (CBS_len(&server_name_list) > 0) {
- uint8_t name_type;
- CBS host_name;
+ if (name_type != TLSEXT_NAMETYPE_host_name ||
+ CBS_len(&host_name) == 0 ||
+ CBS_len(&host_name) > TLSEXT_MAXLEN_host_name ||
+ CBS_contains_zero_byte(&host_name)) {
+ *out_alert = SSL_AD_UNRECOGNIZED_NAME;
+ return 0;
+ }
- if (!CBS_get_u8(&server_name_list, &name_type) ||
- !CBS_get_u16_length_prefixed(&server_name_list, &host_name)) {
+ /* TODO(davidben): SNI should be resolved before resumption. We have the
+ * early callback as a replacement, but we should fix the current callback
+ * and avoid the need for |SSL_CTX_set_session_id_context|. */
+ if (!ssl->hit) {
+ assert(ssl->session->tlsext_hostname == NULL);
+
+ /* Copy the hostname as a string. */
+ if (!CBS_strdup(&host_name, &ssl->session->tlsext_hostname)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
- /* Only host_name is supported. */
- if (name_type != TLSEXT_NAMETYPE_host_name) {
- continue;
- }
-
- if (have_seen_host_name) {
- /* The ServerNameList MUST NOT contain more than one name of the same
- * name_type. */
- return 0;
- }
-
- have_seen_host_name = 1;
-
- if (CBS_len(&host_name) == 0 ||
- CBS_len(&host_name) > TLSEXT_MAXLEN_host_name ||
- CBS_contains_zero_byte(&host_name)) {
- *out_alert = SSL_AD_UNRECOGNIZED_NAME;
- return 0;
- }
-
- if (!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;
- }
+ ssl->s3->tmp.should_ack_sni = 1;
}
return 1;
@@ -975,7 +893,7 @@
/* Extended Master Secret.
*
- * https://tools.ietf.org/html/draft-ietf-tls-session-hash-05 */
+ * https://tools.ietf.org/html/rfc7627 */
static void ext_ems_init(SSL *ssl) {
ssl->s3->tmp.extended_master_secret = 0;
@@ -1185,6 +1103,7 @@
static void ext_ocsp_init(SSL *ssl) {
ssl->s3->tmp.certificate_status_expected = 0;
+ ssl->tlsext_status_type = -1;
}
static int ext_ocsp_add_clienthello(SSL *ssl, CBB *out) {
@@ -1202,6 +1121,7 @@
return 0;
}
+ ssl->tlsext_status_type = TLSEXT_STATUSTYPE_ocsp;
return 1;
}
@@ -1317,14 +1237,14 @@
return 0;
}
- OPENSSL_free(ssl->next_proto_negotiated);
- ssl->next_proto_negotiated = BUF_memdup(selected, selected_len);
- if (ssl->next_proto_negotiated == NULL) {
+ OPENSSL_free(ssl->s3->next_proto_negotiated);
+ ssl->s3->next_proto_negotiated = BUF_memdup(selected, selected_len);
+ if (ssl->s3->next_proto_negotiated == NULL) {
*out_alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
- ssl->next_proto_negotiated_len = selected_len;
+ ssl->s3->next_proto_negotiated_len = selected_len;
ssl->s3->next_proto_neg_seen = 1;
return 1;
@@ -1945,9 +1865,7 @@
return 0;
}
- ssl->s3->tmp.peer_ellipticcurvelist =
- (uint16_t *)OPENSSL_malloc(CBS_len(&elliptic_curve_list));
-
+ ssl->s3->tmp.peer_ellipticcurvelist = OPENSSL_malloc(CBS_len(&elliptic_curve_list));
if (ssl->s3->tmp.peer_ellipticcurvelist == NULL) {
*out_alert = SSL_AD_INTERNAL_ERROR;
return 0;
@@ -2081,6 +1999,9 @@
ext_ec_point_parse_clienthello,
ext_ec_point_add_serverhello,
},
+ /* The final extension must be non-empty. WebSphere Application Server 7.0 is
+ * intolerant to the last extension being zero-length. See
+ * https://crbug.com/363583. */
{
TLSEXT_TYPE_elliptic_curves,
ext_ec_curves_init,
@@ -2167,9 +2088,10 @@
* 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
+ /* Extensions take at least four bytes to encode. Always include at least
* one byte of data if including the extension. WebSphere Application
- * Server 7.0 is intolerant to the last extension being zero-length. */
+ * Server 7.0 is intolerant to the last extension being zero-length. See
+ * https://crbug.com/363583. */
if (padding_len >= 4 + 1) {
padding_len -= 4;
} else {
@@ -2411,14 +2333,10 @@
int ret = SSL_TLSEXT_ERR_NOACK;
int al = SSL_AD_UNRECOGNIZED_NAME;
- /* The handling of the ECPointFormats extension is done elsewhere, namely in
- * ssl3_choose_cipher in s3_lib.c. */
-
- if (ssl->ctx != NULL && ssl->ctx->tlsext_servername_callback != 0) {
+ if (ssl->ctx->tlsext_servername_callback != 0) {
ret = ssl->ctx->tlsext_servername_callback(ssl, &al,
- ssl->ctx->tlsext_servername_arg);
- } else if (ssl->initial_ctx != NULL &&
- ssl->initial_ctx->tlsext_servername_callback != 0) {
+ ssl->ctx->tlsext_servername_arg);
+ } else if (ssl->initial_ctx->tlsext_servername_callback != 0) {
ret = ssl->initial_ctx->tlsext_servername_callback(
ssl, &al, ssl->initial_ctx->tlsext_servername_arg);
}
@@ -2445,11 +2363,10 @@
int ret = SSL_TLSEXT_ERR_OK;
int al = SSL_AD_UNRECOGNIZED_NAME;
- if (ssl->ctx != NULL && ssl->ctx->tlsext_servername_callback != 0) {
+ if (ssl->ctx->tlsext_servername_callback != 0) {
ret = ssl->ctx->tlsext_servername_callback(ssl, &al,
- ssl->ctx->tlsext_servername_arg);
- } else if (ssl->initial_ctx != NULL &&
- ssl->initial_ctx->tlsext_servername_callback != 0) {
+ ssl->ctx->tlsext_servername_arg);
+ } else if (ssl->initial_ctx->tlsext_servername_callback != 0) {
ret = ssl->initial_ctx->tlsext_servername_callback(
ssl, &al, ssl->initial_ctx->tlsext_servername_arg);
}
@@ -2484,7 +2401,7 @@
}
int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session,
- int *out_send_ticket, const uint8_t *ticket,
+ int *out_renew_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. */
@@ -2496,19 +2413,13 @@
EVP_CIPHER_CTX cipher_ctx;
EVP_CIPHER_CTX_init(&cipher_ctx);
- *out_send_ticket = 0;
+ *out_renew_ticket = 0;
*out_session = NULL;
if (session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) {
goto done;
}
- 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
@@ -2530,7 +2441,7 @@
goto done;
}
if (cb_ret == 2) {
- *out_send_ticket = 1;
+ *out_renew_ticket = 1;
}
} else {
/* Check the key name matches. */
@@ -2609,12 +2520,12 @@
int id;
} tls12_lookup;
-static const tls12_lookup tls12_md[] = {{NID_md5, TLSEXT_hash_md5},
- {NID_sha1, TLSEXT_hash_sha1},
- {NID_sha224, TLSEXT_hash_sha224},
- {NID_sha256, TLSEXT_hash_sha256},
- {NID_sha384, TLSEXT_hash_sha384},
- {NID_sha512, TLSEXT_hash_sha512}};
+static const tls12_lookup tls12_md[] = {
+ {NID_sha1, TLSEXT_hash_sha1},
+ {NID_sha256, TLSEXT_hash_sha256},
+ {NID_sha384, TLSEXT_hash_sha384},
+ {NID_sha512, TLSEXT_hash_sha512},
+};
static const tls12_lookup tls12_sig[] = {{EVP_PKEY_RSA, TLSEXT_signature_rsa},
{EVP_PKEY_EC, TLSEXT_signature_ecdsa}};
@@ -2648,15 +2559,9 @@
const EVP_MD *tls12_get_hash(uint8_t hash_alg) {
switch (hash_alg) {
- case TLSEXT_hash_md5:
- return EVP_md5();
-
case TLSEXT_hash_sha1:
return EVP_sha1();
- case TLSEXT_hash_sha224:
- return EVP_sha224();
-
case TLSEXT_hash_sha256:
return EVP_sha256();
@@ -2691,7 +2596,7 @@
int tls1_parse_peer_sigalgs(SSL *ssl, const CBS *in_sigalgs) {
/* Extension ignored for inappropriate versions */
- if (!SSL_USE_SIGALGS(ssl)) {
+ if (ssl3_protocol_version(ssl) < TLS1_2_VERSION) {
return 1;
}
@@ -2742,7 +2647,7 @@
size_t i, j;
static const int kDefaultDigestList[] = {NID_sha256, NID_sha384, NID_sha512,
- NID_sha224, NID_sha1};
+ NID_sha1};
const int *digest_nids = kDefaultDigestList;
size_t num_digest_nids =
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index 74674a4..5effa58 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -46,7 +46,7 @@
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/hmac.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
@@ -138,13 +138,20 @@
return (TestState *)SSL_get_ex_data(ssl, g_state_index);
}
+static ScopedX509 LoadCertificate(const std::string &file) {
+ ScopedBIO bio(BIO_new(BIO_s_file()));
+ if (!bio || !BIO_read_filename(bio.get(), file.c_str())) {
+ return nullptr;
+ }
+ return ScopedX509(PEM_read_bio_X509(bio.get(), NULL, NULL, NULL));
+}
+
static ScopedEVP_PKEY LoadPrivateKey(const std::string &file) {
ScopedBIO bio(BIO_new(BIO_s_file()));
if (!bio || !BIO_read_filename(bio.get(), file.c_str())) {
return nullptr;
}
- ScopedEVP_PKEY pkey(PEM_read_bio_PrivateKey(bio.get(), NULL, NULL, NULL));
- return pkey;
+ return ScopedEVP_PKEY(PEM_read_bio_PrivateKey(bio.get(), NULL, NULL, NULL));
}
static int AsyncPrivateKeyType(SSL *ssl) {
@@ -291,9 +298,9 @@
}
};
-static bool InstallCertificate(SSL *ssl) {
+static bool GetCertificate(SSL *ssl, ScopedX509 *out_x509,
+ ScopedEVP_PKEY *out_pkey) {
const TestConfig *config = GetConfigPtr(ssl);
- TestState *test_state = GetTestState(ssl);
if (!config->digest_prefs.empty()) {
std::unique_ptr<char, Free<char>> digest_prefs(
@@ -317,21 +324,16 @@
}
if (!config->key_file.empty()) {
- if (config->async) {
- 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)) {
+ *out_pkey = LoadPrivateKey(config->key_file.c_str());
+ if (!*out_pkey) {
return false;
}
}
- if (!config->cert_file.empty() &&
- !SSL_use_certificate_file(ssl, config->cert_file.c_str(),
- SSL_FILETYPE_PEM)) {
- return false;
+ if (!config->cert_file.empty()) {
+ *out_x509 = LoadCertificate(config->cert_file.c_str());
+ if (!*out_x509) {
+ return false;
+ }
}
if (!config->ocsp_response.empty() &&
!SSL_CTX_set_ocsp_response(ssl->ctx,
@@ -342,6 +344,31 @@
return true;
}
+static bool InstallCertificate(SSL *ssl) {
+ ScopedX509 x509;
+ ScopedEVP_PKEY pkey;
+ if (!GetCertificate(ssl, &x509, &pkey)) {
+ return false;
+ }
+
+ if (pkey) {
+ TestState *test_state = GetTestState(ssl);
+ const TestConfig *config = GetConfigPtr(ssl);
+ if (config->async) {
+ test_state->private_key = std::move(pkey);
+ SSL_set_private_key_method(ssl, &g_async_private_key_method);
+ } else if (!SSL_use_PrivateKey(ssl, pkey.get())) {
+ return false;
+ }
+ }
+
+ if (x509 && !SSL_use_certificate(ssl, x509.get())) {
+ return false;
+ }
+
+ return true;
+}
+
static int SelectCertificateCallback(const struct ssl_early_callback_ctx *ctx) {
const TestConfig *config = GetConfigPtr(ctx->ssl);
GetTestState(ctx->ssl)->early_callback_called = true;
@@ -394,6 +421,28 @@
return 1;
}
+static int ClientCertCallback(SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey) {
+ if (GetConfigPtr(ssl)->async && !GetTestState(ssl)->cert_ready) {
+ return -1;
+ }
+
+ ScopedX509 x509;
+ ScopedEVP_PKEY pkey;
+ if (!GetCertificate(ssl, &x509, &pkey)) {
+ return -1;
+ }
+
+ // Return zero for no certificate.
+ if (!x509) {
+ return 0;
+ }
+
+ // Asynchronous private keys are not supported with client_cert_cb.
+ *out_x509 = x509.release();
+ *out_pkey = pkey.release();
+ return 1;
+}
+
static int VerifySucceed(X509_STORE_CTX *store_ctx, void *arg) {
SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(store_ctx,
SSL_get_ex_data_X509_STORE_CTX_idx());
@@ -444,7 +493,7 @@
static int AlpnSelectCallback(SSL* ssl, const uint8_t** out, uint8_t* outlen,
const uint8_t* in, unsigned inlen, void* arg) {
const TestConfig *config = GetConfigPtr(ssl);
- if (config->select_alpn.empty()) {
+ if (config->decline_alpn) {
return SSL_TLSEXT_ERR_NOACK;
}
@@ -732,6 +781,9 @@
}
ScopedDH dh(DH_get_2048_256(NULL));
+ if (!dh) {
+ return nullptr;
+ }
if (config->use_sparse_dh_prime) {
// This prime number is 2^1024 + 643 – a value just above a power of two.
@@ -747,10 +799,12 @@
!BN_set_word(dh->g, 2)) {
return nullptr;
}
+ BN_free(dh->q);
+ dh->q = NULL;
dh->priv_length = 0;
}
- if (!dh || !SSL_CTX_set_tmp_dh(ssl_ctx.get(), dh.get())) {
+ if (!SSL_CTX_set_tmp_dh(ssl_ctx.get(), dh.get())) {
return nullptr;
}
@@ -766,6 +820,10 @@
SSL_CTX_set_select_certificate_cb(ssl_ctx.get(), SelectCertificateCallback);
+ if (config->use_old_client_cert_callback) {
+ SSL_CTX_set_client_cert_cb(ssl_ctx.get(), ClientCertCallback);
+ }
+
SSL_CTX_set_next_protos_advertised_cb(
ssl_ctx.get(), NextProtosAdvertisedCallback, NULL);
if (!config->select_next_proto.empty()) {
@@ -773,7 +831,7 @@
NULL);
}
- if (!config->select_alpn.empty()) {
+ if (!config->select_alpn.empty() || config->decline_alpn) {
SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), AlpnSelectCallback, NULL);
}
@@ -1138,9 +1196,8 @@
!SSL_set_mode(ssl.get(), SSL_MODE_SEND_FALLBACK_SCSV)) {
return false;
}
- if (!config->use_early_callback) {
+ if (!config->use_early_callback && !config->use_old_client_cert_callback) {
if (config->async) {
- // TODO(davidben): Also test |s->ctx->client_cert_cb| on the client.
SSL_set_cert_cb(ssl.get(), CertCallback, NULL);
} else if (!InstallCertificate(ssl.get())) {
return false;
@@ -1253,7 +1310,7 @@
}
if (config->enable_all_curves) {
static const int kAllCurves[] = {
- NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, NID_x25519,
+ NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, NID_X25519,
};
if (!SSL_set1_curves(ssl.get(), kAllCurves,
sizeof(kAllCurves) / sizeof(kAllCurves[0]))) {
@@ -1274,12 +1331,18 @@
if (config->is_dtls) {
ScopedBIO packeted =
PacketedBioCreate(&GetTestState(ssl.get())->clock_delta);
+ if (!packeted) {
+ return false;
+ }
BIO_push(packeted.get(), bio.release());
bio = std::move(packeted);
}
if (config->async) {
ScopedBIO async_scoped =
config->is_dtls ? AsyncBioCreateDatagram() : AsyncBioCreate();
+ if (!async_scoped) {
+ return false;
+ }
BIO_push(async_scoped.get(), bio.release());
GetTestState(ssl.get())->async_bio = async_scoped.get();
bio = std::move(async_scoped);
@@ -1483,7 +1546,16 @@
return true;
}
+class StderrDelimiter {
+ public:
+ ~StderrDelimiter() { fprintf(stderr, "--- DONE ---\n"); }
+};
+
int main(int argc, char **argv) {
+ // To distinguish ASan's output from ours, add a trailing message to stderr.
+ // Anything following this line will be considered an error.
+ StderrDelimiter delimiter;
+
#if defined(OPENSSL_WINDOWS)
/* Initialize Winsock. */
WORD wsa_version = MAKEWORD(2, 2);
diff --git a/src/ssl/test/runner/alert.go b/src/ssl/test/runner/alert.go
index 541216e..7db6826 100644
--- a/src/ssl/test/runner/alert.go
+++ b/src/ssl/test/runner/alert.go
@@ -22,6 +22,7 @@
alertRecordOverflow alert = 22
alertDecompressionFailure alert = 30
alertHandshakeFailure alert = 40
+ alertNoCertficate alert = 41
alertBadCertificate alert = 42
alertUnsupportedCertificate alert = 43
alertCertificateRevoked alert = 44
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index db3c675..2e9ce04 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -424,6 +424,10 @@
// to be wrong.
InvalidSKXCurve bool
+ // InvalidECDHPoint, if true, causes the ECC points in
+ // ServerKeyExchange or ClientKeyExchange messages to be invalid.
+ InvalidECDHPoint bool
+
// BadECDSAR controls ways in which the 'r' value of an ECDSA signature
// can be invalid.
BadECDSAR BadValue
@@ -469,6 +473,10 @@
// NewSessionTicket message despite promising to in ServerHello.
SkipNewSessionTicket bool
+ // SkipClientCertificate causes the client to skip the Certificate
+ // message.
+ SkipClientCertificate bool
+
// SkipChangeCipherSpec causes the implementation to skip
// sending the ChangeCipherSpec message (and adjusting cipher
// state accordingly for the Finished message).
@@ -517,6 +525,10 @@
// two records.
FragmentAlert bool
+ // DoubleAlert will cause all alerts to be sent as two copies packed
+ // within one record.
+ DoubleAlert bool
+
// SendSpuriousAlert, if non-zero, will cause an spurious, unwanted
// alert to be sent.
SendSpuriousAlert alert
@@ -814,6 +826,14 @@
// BadHelloRequest, if not nil, is what to send instead of a
// HelloRequest.
BadHelloRequest []byte
+
+ // RequireSessionTickets, if true, causes the client to require new
+ // sessions use session tickets instead of session IDs.
+ RequireSessionTickets bool
+
+ // NullAllCiphers, if true, causes every cipher to behave like the null
+ // cipher.
+ NullAllCiphers bool
}
func (c *Config) serverInit() {
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index cb60a92..43548e8 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -189,6 +189,11 @@
hc.nextMac = nil
hc.config = config
hc.incEpoch()
+
+ if config.Bugs.NullAllCiphers {
+ hc.cipher = nil
+ hc.mac = nil
+ }
return nil
}
@@ -837,6 +842,9 @@
if c.config.Bugs.FragmentAlert {
c.writeRecord(recordTypeAlert, c.tmp[0:1])
c.writeRecord(recordTypeAlert, c.tmp[1:2])
+ } else if c.config.Bugs.DoubleAlert {
+ copy(c.tmp[2:4], c.tmp[0:2])
+ c.writeRecord(recordTypeAlert, c.tmp[0:4])
} else {
c.writeRecord(recordTypeAlert, c.tmp[0:2])
}
@@ -851,7 +859,7 @@
// L < c.out.Mutex.
func (c *Conn) sendAlert(err alert) error {
level := byte(alertLevelError)
- if err == alertNoRenegotiation || err == alertCloseNotify {
+ if err == alertNoRenegotiation || err == alertCloseNotify || err == alertNoCertficate {
level = alertLevelWarning
}
return c.SendAlert(level, err)
diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go
index 64630ba..67609fc 100644
--- a/src/ssl/test/runner/handshake_client.go
+++ b/src/ssl/test/runner/handshake_client.go
@@ -363,6 +363,9 @@
}
if sessionCache != nil && hs.session != nil && session != hs.session {
+ if c.config.Bugs.RequireSessionTickets && len(hs.session.sessionTicket) == 0 {
+ return errors.New("tls: new session used session IDs instead of tickets")
+ }
sessionCache.Put(cacheKey, hs.session)
}
@@ -561,15 +564,20 @@
hs.writeServerHash(shd.marshal())
// If the server requested a certificate then we have to send a
- // Certificate message, even if it's empty because we don't have a
- // certificate to send.
+ // Certificate message in TLS, even if it's empty because we don't have
+ // a certificate to send. In SSL 3.0, skip the message and send a
+ // no_certificate warning alert.
if certRequested {
- certMsg := new(certificateMsg)
- if chainToSend != nil {
- certMsg.certificates = chainToSend.Certificate
+ if c.vers == VersionSSL30 && chainToSend == nil {
+ c.sendAlert(alertNoCertficate)
+ } else if !c.config.Bugs.SkipClientCertificate {
+ certMsg := new(certificateMsg)
+ if chainToSend != nil {
+ certMsg.certificates = chainToSend.Certificate
+ }
+ hs.writeClientHash(certMsg.marshal())
+ c.writeRecord(recordTypeHandshake, certMsg.marshal())
}
- hs.writeClientHash(certMsg.marshal())
- c.writeRecord(recordTypeHandshake, certMsg.marshal())
}
preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, leaf)
diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go
index 530ddbc..092f51e 100644
--- a/src/ssl/test/runner/handshake_messages.go
+++ b/src/ssl/test/runner/handshake_messages.go
@@ -349,7 +349,7 @@
z = z[4:]
}
if m.extendedMasterSecret {
- // https://tools.ietf.org/html/draft-ietf-tls-session-hash-01
+ // https://tools.ietf.org/html/rfc7627
z[0] = byte(extensionExtendedMasterSecret >> 8)
z[1] = byte(extensionExtendedMasterSecret & 0xff)
z = z[4:]
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index 0232772..d2cac98 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -626,13 +626,22 @@
// certificate message, even if it's empty.
if config.ClientAuth >= RequestClientCert {
var certMsg *certificateMsg
- if certMsg, ok = msg.(*certificateMsg); !ok {
+ var certificates [][]byte
+ if certMsg, ok = msg.(*certificateMsg); ok {
+ if c.vers == VersionSSL30 && len(certMsg.certificates) == 0 {
+ return errors.New("tls: empty certificate message in SSL 3.0")
+ }
+
+ hs.writeClientHash(certMsg.marshal())
+ certificates = certMsg.certificates
+ } else if c.vers != VersionSSL30 {
+ // In TLS, the Certificate message is required. In SSL
+ // 3.0, the peer skips it when sending no certificates.
c.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(certMsg, msg)
}
- hs.writeClientHash(certMsg.marshal())
- if len(certMsg.certificates) == 0 {
+ if len(certificates) == 0 {
// The client didn't actually send a certificate
switch config.ClientAuth {
case RequireAnyClientCert, RequireAndVerifyClientCert:
@@ -641,14 +650,16 @@
}
}
- pub, err = hs.processCertsFromClient(certMsg.certificates)
+ pub, err = hs.processCertsFromClient(certificates)
if err != nil {
return err
}
- msg, err = c.readHandshake()
- if err != nil {
- return err
+ if ok {
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
}
}
diff --git a/src/ssl/test/runner/key_agreement.go b/src/ssl/test/runner/key_agreement.go
index 4f399d9..54aa3d3 100644
--- a/src/ssl/test/runner/key_agreement.go
+++ b/src/ssl/test/runner/key_agreement.go
@@ -312,8 +312,7 @@
copy(peerKeyCopy[:], peerKey)
curve25519.ScalarMult(&out, &e.privateKey, &peerKeyCopy)
- // Per draft-irtf-cfrg-curves-11, reject the all-zero value in constant
- // time.
+ // Per RFC 7748, reject the all-zero value in constant time.
var zeros [32]byte
if subtle.ConstantTimeCompare(zeros[:], out[:]) == 1 {
return nil, errors.New("tls: X25519 value with wrong order")
@@ -567,6 +566,9 @@
}
serverECDHParams[3] = byte(len(publicKey))
copy(serverECDHParams[4:], publicKey)
+ if config.Bugs.InvalidECDHPoint {
+ serverECDHParams[4] ^= 0xff
+ }
return ka.auth.signParameters(config, cert, clientHello, hello, serverECDHParams)
}
@@ -623,6 +625,9 @@
ckx.ciphertext = make([]byte, 1+len(publicKey))
ckx.ciphertext[0] = byte(len(publicKey))
copy(ckx.ciphertext[1:], publicKey)
+ if config.Bugs.InvalidECDHPoint {
+ ckx.ciphertext[1] ^= 0xff
+ }
return preMasterSecret, ckx, nil
}
diff --git a/src/ssl/test/runner/prf.go b/src/ssl/test/runner/prf.go
index 8521aba..f1b26de 100644
--- a/src/ssl/test/runner/prf.go
+++ b/src/ssl/test/runner/prf.go
@@ -153,7 +153,7 @@
// extendedMasterFromPreMasterSecret generates the master secret from the
// pre-master secret when the Triple Handshake fix is in effect. See
-// https://tools.ietf.org/html/draft-ietf-tls-session-hash-01
+// https://tools.ietf.org/html/rfc7627
func extendedMasterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret []byte, h finishedHash) []byte {
masterSecret := make([]byte, masterSecretLength)
prfForVersion(version, suite)(masterSecret, preMasterSecret, extendedMasterSecretLabel, h.Sum())
diff --git a/src/ssl/test/runner/recordingconn.go b/src/ssl/test/runner/recordingconn.go
index 39deb19..752610e 100644
--- a/src/ssl/test/runner/recordingconn.go
+++ b/src/ssl/test/runner/recordingconn.go
@@ -92,6 +92,17 @@
}
}
+func (r *recordingConn) Transcript() []byte {
+ var ret []byte
+ for _, flow := range r.flows {
+ if flow.flowType != writeFlow {
+ continue
+ }
+ ret = append(ret, flow.data...)
+ }
+ return ret
+}
+
func parseTestData(r io.Reader) (flows [][]byte, err error) {
var currentFlow []byte
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index 45bb0b7..5b746c6 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -37,6 +37,9 @@
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.")
+ fuzzer = flag.Bool("fuzzer", false, "If true, tests against a BoringSSL built in fuzzer mode.")
+ transcriptDir = flag.String("transcript-dir", "", "The directory in which to write transcripts.")
+ timeout = flag.Int("timeout", 15, "The number of seconds to wait for a read or write to bssl_shim.")
)
const (
@@ -244,15 +247,68 @@
var testCases []testCase
+func writeTranscript(test *testCase, isResume bool, data []byte) {
+ if len(data) == 0 {
+ return
+ }
+
+ protocol := "tls"
+ if test.protocol == dtls {
+ protocol = "dtls"
+ }
+
+ side := "client"
+ if test.testType == serverTest {
+ side = "server"
+ }
+
+ dir := path.Join(*transcriptDir, protocol, side)
+ if err := os.MkdirAll(dir, 0755); err != nil {
+ fmt.Fprintf(os.Stderr, "Error making %s: %s\n", dir, err)
+ return
+ }
+
+ name := test.name
+ if isResume {
+ name += "-Resume"
+ } else {
+ name += "-Normal"
+ }
+
+ if err := ioutil.WriteFile(path.Join(dir, name), data, 0644); err != nil {
+ fmt.Fprintf(os.Stderr, "Error writing %s: %s\n", name, err)
+ }
+}
+
+// A timeoutConn implements an idle timeout on each Read and Write operation.
+type timeoutConn struct {
+ net.Conn
+ timeout time.Duration
+}
+
+func (t *timeoutConn) Read(b []byte) (int, error) {
+ if err := t.SetReadDeadline(time.Now().Add(t.timeout)); err != nil {
+ return 0, err
+ }
+ return t.Conn.Read(b)
+}
+
+func (t *timeoutConn) Write(b []byte) (int, error) {
+ if err := t.SetWriteDeadline(time.Now().Add(t.timeout)); err != nil {
+ return 0, err
+ }
+ return t.Conn.Write(b)
+}
+
func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool) error {
- var connDamage *damageAdaptor
+ conn = &timeoutConn{conn, time.Duration(*timeout) * time.Second}
if test.protocol == dtls {
config.Bugs.PacketAdaptor = newPacketAdaptor(conn)
conn = config.Bugs.PacketAdaptor
}
- if *flagDebug {
+ if *flagDebug || len(*transcriptDir) != 0 {
local, peer := "client", "server"
if test.testType == clientTest {
local, peer = peer, local
@@ -264,9 +320,14 @@
peer: peer,
}
conn = connDebug
- defer func() {
- connDebug.WriteTo(os.Stdout)
- }()
+ if *flagDebug {
+ defer connDebug.WriteTo(os.Stdout)
+ }
+ if len(*transcriptDir) != 0 {
+ defer func() {
+ writeTranscript(test, isResume, connDebug.Transcript())
+ }()
+ }
if config.Bugs.PacketAdaptor != nil {
config.Bugs.PacketAdaptor.debug = connDebug
@@ -277,6 +338,7 @@
conn = newReplayAdaptor(conn)
}
+ var connDamage *damageAdaptor
if test.damageFirstWrite {
connDamage = newDamageAdaptor(conn)
conn = connDamage
@@ -686,6 +748,9 @@
config.ServerName = "test"
}
}
+ if *fuzzer {
+ config.Bugs.NullAllCiphers = true
+ }
conn, err := acceptOrWait(listener, waitChan)
if err == nil {
@@ -713,6 +778,9 @@
resumeConfig.ClientSessionCache = config.ClientSessionCache
resumeConfig.ServerSessionCache = config.ServerSessionCache
}
+ if *fuzzer {
+ resumeConfig.Bugs.NullAllCiphers = true
+ }
} else {
resumeConfig = config
}
@@ -736,8 +804,18 @@
}
}
- stdout := string(stdoutBuf.Bytes())
- stderr := string(stderrBuf.Bytes())
+ // Account for Windows line endings.
+ stdout := strings.Replace(string(stdoutBuf.Bytes()), "\r\n", "\n", -1)
+ stderr := strings.Replace(string(stderrBuf.Bytes()), "\r\n", "\n", -1)
+
+ // Separate the errors from the shim and those from tools like
+ // AddressSanitizer.
+ var extraStderr string
+ if stderrParts := strings.SplitN(stderr, "--- DONE ---\n", 2); len(stderrParts) == 2 {
+ stderr = stderrParts[0]
+ extraStderr = stderrParts[1]
+ }
+
failed := err != nil || childErr != nil
correctFailure := len(test.expectedError) == 0 || strings.Contains(stderr, test.expectedError)
localError := "none"
@@ -769,8 +847,8 @@
return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s", msg, localError, childError, stdout, stderr)
}
- if !*useValgrind && !failed && len(stderr) > 0 {
- println(stderr)
+ if !*useValgrind && (len(extraStderr) > 0 || (!failed && len(stderr) > 0)) {
+ return fmt.Errorf("unexpected error output:\n%s\n%s", stderr, extraStderr)
}
return nil
@@ -1128,6 +1206,31 @@
},
{
testType: serverTest,
+ name: "DoubleAlert",
+ config: Config{
+ Bugs: ProtocolBugs{
+ DoubleAlert: true,
+ SendSpuriousAlert: alertRecordOverflow,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_ALERT:",
+ },
+ {
+ protocol: dtls,
+ testType: serverTest,
+ name: "DoubleAlert-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ DoubleAlert: true,
+ SendSpuriousAlert: alertRecordOverflow,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_ALERT:",
+ },
+ {
+ testType: serverTest,
name: "EarlyChangeCipherSpec-server-1",
config: Config{
Bugs: ProtocolBugs{
@@ -1708,7 +1811,18 @@
expectedError: ":WRONG_CURVE:",
},
{
- name: "BadFinished",
+ name: "BadFinished-Client",
+ config: Config{
+ Bugs: ProtocolBugs{
+ BadFinished: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DIGEST_CHECK_FAILED:",
+ },
+ {
+ testType: serverTest,
+ name: "BadFinished-Server",
config: Config{
Bugs: ProtocolBugs{
BadFinished: true,
@@ -2088,6 +2202,40 @@
shouldFail: true,
expectedError: ":BAD_HELLO_REQUEST:",
},
+ {
+ testType: serverTest,
+ name: "SupportTicketsWithSessionID",
+ config: Config{
+ SessionTicketsDisabled: true,
+ },
+ resumeConfig: &Config{},
+ resumeSession: true,
+ },
+ {
+ name: "InvalidECDHPoint-Client",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ CurvePreferences: []CurveID{CurveP256},
+ Bugs: ProtocolBugs{
+ InvalidECDHPoint: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":INVALID_ENCODING:",
+ },
+ {
+ testType: serverTest,
+ name: "InvalidECDHPoint-Server",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ CurvePreferences: []CurveID{CurveP256},
+ Bugs: ProtocolBugs{
+ InvalidECDHPoint: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":INVALID_ENCODING:",
+ },
}
testCases = append(testCases, basicTests...)
}
@@ -2280,6 +2428,16 @@
flags: []string{"-use-sparse-dh-prime"},
})
+ // The server must be tolerant to bogus ciphers.
+ const bogusCipher = 0x1234
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "UnknownCipher",
+ config: Config{
+ CipherSuites: []uint16{bogusCipher, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ },
+ })
+
// 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
@@ -2383,7 +2541,7 @@
},
},
shouldFail: true,
- expectedError: "SIGNATURE",
+ expectedError: ":BAD_SIGNATURE:",
})
}
}
@@ -2409,7 +2567,7 @@
},
},
shouldFail: true,
- expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
+ expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
})
// OpenSSL previously had an issue where the first byte of padding in
// 255 bytes of padding wasn't checked.
@@ -2424,7 +2582,7 @@
},
messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
shouldFail: true,
- expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
+ expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
})
}
@@ -2523,6 +2681,39 @@
})
}
}
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "RequireAnyClientCertificate",
+ flags: []string{"-require-any-client-certificate"},
+ shouldFail: true,
+ expectedError: ":PEER_DID_NOT_RETURN_A_CERTIFICATE:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "RequireAnyClientCertificate-SSL3",
+ config: Config{
+ MaxVersion: VersionSSL30,
+ },
+ flags: []string{"-require-any-client-certificate"},
+ shouldFail: true,
+ expectedError: ":PEER_DID_NOT_RETURN_A_CERTIFICATE:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SkipClientCertificate",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SkipClientCertificate: true,
+ },
+ },
+ // Setting SSL_VERIFY_PEER allows anonymous clients.
+ flags: []string{"-verify-peer"},
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ })
}
func addExtendedMasterSecretTests() {
@@ -2667,6 +2858,8 @@
tests = append(tests, testCase{
name: "Basic-Client",
resumeSession: true,
+ // Ensure session tickets are used, not session IDs.
+ noSessionCache: true,
})
tests = append(tests, testCase{
name: "Basic-Client-RenewTicket",
@@ -2691,8 +2884,13 @@
resumeSession: true,
})
tests = append(tests, testCase{
- testType: serverTest,
- name: "Basic-Server",
+ testType: serverTest,
+ name: "Basic-Server",
+ config: Config{
+ Bugs: ProtocolBugs{
+ RequireSessionTickets: true,
+ },
+ },
resumeSession: true,
})
tests = append(tests, testCase{
@@ -2719,6 +2917,46 @@
// TLS client auth.
tests = append(tests, testCase{
testType: clientTest,
+ name: "ClientAuth-NoCertificate-Client",
+ config: Config{
+ ClientAuth: RequestClientCert,
+ },
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "ClientAuth-NoCertificate-Server",
+ // Setting SSL_VERIFY_PEER allows anonymous clients.
+ flags: []string{"-verify-peer"},
+ })
+ if protocol == tls {
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "ClientAuth-NoCertificate-Client-SSL3",
+ config: Config{
+ MaxVersion: VersionSSL30,
+ ClientAuth: RequestClientCert,
+ },
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "ClientAuth-NoCertificate-Server-SSL3",
+ config: Config{
+ MaxVersion: VersionSSL30,
+ },
+ // Setting SSL_VERIFY_PEER allows anonymous clients.
+ flags: []string{"-verify-peer"},
+ })
+ }
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "ClientAuth-NoCertificate-OldCallback",
+ config: Config{
+ ClientAuth: RequestClientCert,
+ },
+ flags: []string{"-use-old-client-cert-callback"},
+ })
+ tests = append(tests, testCase{
+ testType: clientTest,
name: "ClientAuth-RSA-Client",
config: Config{
ClientAuth: RequireAnyClientCert,
@@ -2739,6 +2977,19 @@
"-key-file", path.Join(*resourceDir, ecdsaKeyFile),
},
})
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "ClientAuth-OldCallback",
+ config: Config{
+ ClientAuth: RequireAnyClientCert,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-use-old-client-cert-callback",
+ },
+ })
+
if async {
// Test async keys against each key exchange.
tests = append(tests, testCase{
@@ -3223,11 +3474,7 @@
} else {
shouldFail = true
expectedError = ":UNSUPPORTED_PROTOCOL:"
- if runnerVers.version > VersionSSL30 {
- expectedLocalError = "remote error: protocol version not supported"
- } else {
- expectedLocalError = "remote error: handshake failure"
- }
+ expectedLocalError = "remote error: protocol version not supported"
}
testCases = append(testCases, testCase{
@@ -3381,6 +3628,16 @@
expectedNextProtoType: alpn,
resumeSession: true,
})
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ALPNServer-Decline",
+ config: Config{
+ NextProtos: []string{"foo", "bar", "baz"},
+ },
+ flags: []string{"-decline-alpn"},
+ expectNoNextProto: true,
+ resumeSession: true,
+ })
// Test that the server prefers ALPN over NPN.
testCases = append(testCases, testCase{
testType: serverTest,
@@ -4087,7 +4344,6 @@
id uint8
}{
{"SHA1", hashSHA1},
- {"SHA224", hashSHA224},
{"SHA256", hashSHA256},
{"SHA384", hashSHA384},
{"SHA512", hashSHA512},
@@ -4668,6 +4924,17 @@
flags: []string{"-enable-all-curves"},
})
}
+
+ // The server must be tolerant to bogus curves.
+ const bogusCurve = 0x1234
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "UnknownCurve",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ CurvePreferences: []CurveID{bogusCurve, CurveP256},
+ },
+ })
}
func addKeyExchangeInfoTests() {
@@ -4845,11 +5112,17 @@
go worker(statusChan, testChan, *shimPath, &wg)
}
+ var foundTest bool
for i := range testCases {
if len(*testToRun) == 0 || *testToRun == testCases[i].name {
+ foundTest = true
testChan <- &testCases[i]
}
}
+ if !foundTest {
+ fmt.Fprintf(os.Stderr, "No test named '%s'\n", *testToRun)
+ os.Exit(1)
+ }
close(testChan)
wg.Wait()
diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc
index 1cf316d..67a017d 100644
--- a/src/ssl/test/test_config.cc
+++ b/src/ssl/test/test_config.cc
@@ -62,6 +62,7 @@
{ "-no-ssl3", &TestConfig::no_ssl3 },
{ "-shim-writes-first", &TestConfig::shim_writes_first },
{ "-expect-session-miss", &TestConfig::expect_session_miss },
+ { "-decline-alpn", &TestConfig::decline_alpn },
{ "-expect-extended-master-secret",
&TestConfig::expect_extended_master_secret },
{ "-enable-ocsp-stapling", &TestConfig::enable_ocsp_stapling },
@@ -98,6 +99,8 @@
{ "-p384-only", &TestConfig::p384_only },
{ "-enable-all-curves", &TestConfig::enable_all_curves },
{ "-use-sparse-dh-prime", &TestConfig::use_sparse_dh_prime },
+ { "-use-old-client-cert-callback",
+ &TestConfig::use_old_client_cert_callback },
};
const Flag<std::string> kStringFlags[] = {
@@ -178,12 +181,14 @@
size_t len;
if (!EVP_DecodedLength(&len, strlen(argv[i]))) {
fprintf(stderr, "Invalid base64: %s\n", argv[i]);
+ return false;
}
std::unique_ptr<uint8_t[]> decoded(new uint8_t[len]);
if (!EVP_DecodeBase64(decoded.get(), &len, len,
reinterpret_cast<const uint8_t *>(argv[i]),
strlen(argv[i]))) {
fprintf(stderr, "Invalid base64: %s\n", argv[i]);
+ return false;
}
base64_field->assign(reinterpret_cast<const char *>(decoded.get()), len);
continue;
diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h
index 4e0a46a..fe117d8 100644
--- a/src/ssl/test/test_config.h
+++ b/src/ssl/test/test_config.h
@@ -50,6 +50,7 @@
std::string expected_alpn;
std::string expected_advertised_alpn;
std::string select_alpn;
+ bool decline_alpn = false;
bool expect_session_miss = false;
bool expect_extended_master_secret = false;
std::string psk;
@@ -102,6 +103,7 @@
bool enable_all_curves = false;
bool use_sparse_dh_prime = false;
int expect_key_exchange_info = 0;
+ bool use_old_client_cert_callback = false;
};
bool ParseConfig(int argc, char **argv, TestConfig *out_config);
diff --git a/src/ssl/tls_record.c b/src/ssl/tls_record.c
index 3381eae..b71da17 100644
--- a/src/ssl/tls_record.c
+++ b/src/ssl/tls_record.c
@@ -109,6 +109,7 @@
#include <openssl/ssl.h>
#include <assert.h>
+#include <string.h>
#include <openssl/bytestring.h>
#include <openssl/err.h>
@@ -125,31 +126,44 @@
/* ssl_needs_record_splitting returns one if |ssl|'s current outgoing cipher
* state needs record-splitting and zero otherwise. */
static int ssl_needs_record_splitting(const SSL *ssl) {
- return !SSL_USE_EXPLICIT_IV(ssl) && ssl->aead_write_ctx != NULL &&
+ return ssl->s3->aead_write_ctx != NULL &&
+ ssl3_protocol_version(ssl) < TLS1_1_VERSION &&
(ssl->mode & SSL_MODE_CBC_RECORD_SPLITTING) != 0 &&
- SSL_CIPHER_is_block_cipher(ssl->aead_write_ctx->cipher);
+ SSL_CIPHER_is_block_cipher(ssl->s3->aead_write_ctx->cipher);
+}
+
+int ssl_record_sequence_update(uint8_t *seq, size_t seq_len) {
+ size_t i;
+ for (i = seq_len - 1; i < seq_len; i--) {
+ ++seq[i];
+ if (seq[i] != 0) {
+ return 1;
+ }
+ }
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return 0;
}
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);
+ SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_read_ctx);
} else {
return SSL3_RT_HEADER_LENGTH +
- SSL_AEAD_CTX_explicit_nonce_len(ssl->aead_read_ctx);
+ SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->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);
+ SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx);
} else {
size_t ret = SSL3_RT_HEADER_LENGTH +
- SSL_AEAD_CTX_explicit_nonce_len(ssl->aead_write_ctx);
+ SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx);
if (ssl_needs_record_splitting(ssl)) {
ret += SSL3_RT_HEADER_LENGTH;
- ret += ssl_cipher_get_record_split_len(ssl->aead_write_ctx->cipher);
+ ret += ssl_cipher_get_record_split_len(ssl->s3->aead_write_ctx->cipher);
}
return ret;
}
@@ -158,10 +172,10 @@
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);
+ SSL_AEAD_CTX_max_overhead(ssl->s3->aead_write_ctx);
} else {
size_t ret = SSL3_RT_HEADER_LENGTH +
- SSL_AEAD_CTX_max_overhead(ssl->aead_write_ctx);
+ SSL_AEAD_CTX_max_overhead(ssl->s3->aead_write_ctx);
if (ssl_needs_record_splitting(ssl)) {
ret *= 2;
}
@@ -215,14 +229,14 @@
/* Decrypt the body. */
size_t plaintext_len;
- if (!SSL_AEAD_CTX_open(ssl->aead_read_ctx, out, &plaintext_len, max_out,
+ if (!SSL_AEAD_CTX_open(ssl->s3->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)) {
+ if (!ssl_record_sequence_update(ssl->s3->read_sequence, 8)) {
*out_alert = SSL_AD_INTERNAL_ERROR;
return ssl_open_record_error;
}
@@ -280,11 +294,11 @@
out[2] = wire_version & 0xff;
size_t ciphertext_len;
- if (!SSL_AEAD_CTX_seal(ssl->aead_write_ctx, out + SSL3_RT_HEADER_LENGTH,
+ if (!SSL_AEAD_CTX_seal(ssl->s3->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)) {
+ !ssl_record_sequence_update(ssl->s3->write_sequence, 8)) {
return 0;
}
@@ -329,9 +343,11 @@
out += frag_len;
max_out -= frag_len;
- assert(SSL3_RT_HEADER_LENGTH +
- ssl_cipher_get_record_split_len(ssl->aead_write_ctx->cipher) ==
+#if !defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ assert(SSL3_RT_HEADER_LENGTH + ssl_cipher_get_record_split_len(
+ ssl->s3->aead_write_ctx->cipher) ==
frag_len);
+#endif
}
if (!do_seal_record(ssl, out, out_len, max_out, type, in, in_len)) {
@@ -340,3 +356,26 @@
*out_len += frag_len;
return 1;
}
+
+void ssl_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) {
+ if (SSL_IS_DTLS(ssl)) {
+ ssl->d1->r_epoch++;
+ memset(&ssl->d1->bitmap, 0, sizeof(ssl->d1->bitmap));
+ }
+ memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence));
+
+ SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx);
+ ssl->s3->aead_read_ctx = aead_ctx;
+}
+
+void ssl_set_write_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) {
+ if (SSL_IS_DTLS(ssl)) {
+ ssl->d1->w_epoch++;
+ memcpy(ssl->d1->last_write_sequence, ssl->s3->write_sequence,
+ sizeof(ssl->s3->write_sequence));
+ }
+ memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence));
+
+ SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx);
+ ssl->s3->aead_write_ctx = aead_ctx;
+}