diff options
author | Adam Langley <agl@google.com> | 2015-06-04 17:45:09 -0700 |
---|---|---|
committer | Adam Langley <agl@google.com> | 2015-06-05 16:18:35 -0700 |
commit | f4e427204234da139fd0585def4b4e22502e33f0 (patch) | |
tree | 2aa613266128178591aa10ef500a92702ddbe054 /src/ssl | |
parent | 0d4deb2be14e6590f332920f62b84ef04d153ed1 (diff) | |
download | external_boringssl-f4e427204234da139fd0585def4b4e22502e33f0.zip external_boringssl-f4e427204234da139fd0585def4b4e22502e33f0.tar.gz external_boringssl-f4e427204234da139fd0585def4b4e22502e33f0.tar.bz2 |
Bump revision of BoringSSL.
This depends on https://android-review.googlesource.com/#/c/153481/
af0e32c Add SSL_get_tls_unique.
691992b Minor typo fix in comment.
cc1e3df Make CBS_get_any_asn1_element accept only DER.
0976096 bytestring: Test out_header_len != NULL before writing.
ba5934b Tighten up EMS resumption behaviour.
b0eef0a runner: minor tidyups.
9f8ef2d Add |EVP_get_digestbyname|.
b7326b0 Implement |PEM_def_callback| and call it where appropriate.
e26e590 Avoid unused variable warnings with assert.
efad697 Sync vs_toolschain.py up with Chromium.
39da317 Empty commit to kick the bots.
1550a84 Allow compilation for armv6
9a4996e Fix compilation of sha256-armv4.S when using -march=armv6
485a50a Match the ifdef check in bsaes-armv7.S
e216288 Unexport and prune EVP_MD_CTX flags.
af8731f Remove HMAC_CTX_set_flags.
bf3208b Add additional HMAC tests.
a1c90a5 Further tidy up cipher logic.
0fa4012 Add a test that DTLS does not support RC4.
9a980ab Fold TLS1_PRF_* into SSL_HANDSHAKE_MAC_*
29864b5 Remove SSL_CIPHER_ALGORITHM2_AEAD.
904dc72 Fold away SSL_PROTOCOL_METHOD hooks shared between TLS and DTLS.
a602277 Split ssl_read_bytes hook into app_data and close_notify hooks.
c933a47 Switch the ssl_write_bytes hook to ssl_write_app_data.
2c36792 EVP_Digest*Update, EVP_DigestFinal, and HMAC_Update can never fail.
e2375e1 Low-level hash 'final' functions cannot fail.
049756b Fix integer types in low-level hash functions.
338e067 Reject sessions with the wrong structure version.
f297e02 Reject unknown fields in d2i_SSL_SESSION.
8a228f5 Disable the malloc interceptor without glibc.
bd15a8e Fix DTLS handling of multiple records in a packet.
15eaafb Fix bn_test's bc output and shut it up a little.
efd8eb3 Tidy up overflows in obj_cmp.
05ead68 Readd CRYPTO_{LOCK|UNLOCK|READ|WRITE}.
71106ad Add |BIO_read_asn1| to read a single ASN.1 object.
eb930b8 Fix signed/unsigned warning in bn_test.cc.
b3a7b51 Fix off-by-one in BN_rand
074cc04 Reject negative shifts for BN_rshift and BN_lshift.
75fb74a aes/asm/bsaes-armv7.pl: fix compilation with Xcode 6.3.
ff81e10 Add OPENSSL_PUT_ERROR line to X509V3_parse_list.
1590811 Fix typo in valid_star.
e76ccae Release handshake buffer when sending no certificate.
5f04b65 Release the handshake buffer on the client for abbreviated handshakes.
5c1ce29 Decide whether or not to request client certificates early.
4b30b28 Remove server-side renego session resumption check.
5aea93e Deprecate and no-op SSL_VERIFY_CLIENT_ONCE.
34a1635 Remove fake RLE compression OID.
9c0918f Fix typo in objects.txt
91af02a Add some comments and tweak assertions for cbc.c.
74d8bc2 Don't make SSL_MODE_*HELLO_TIME configurable.
7b5aff4 Have consumers supply OPENSSL_C11_ATOMIC.
ac63748 Revert "tool: we don't need -lrt."
444dce4 Do-nothing fns |OpenSSL_add_all_ciphers| and |OpenSSL_add_all_digests|.
ece089c Deprecate and no-op SSL_set_state.
be05c63 Remove compatibility s->version checks.
8ec8810 Remove SSL_in_before and SSL_ST_BEFORE.
cd90f3a Remove renegotiation deferral logic.
44d3eed Forbid caller-initiated renegotiations and all renego as a servers.
3d59e04 Fix test used for not-in-place CBC mode.
5f387e3 Remove s->renegotiate check in SSL_clear.
20f6e97 Switch three more renegotiate checks to initial_handshake_complete.
d23d5a5 Remove remnants of DTLS renegotiate.
9a41d1b Deprecate SSL_*_read_ahead and enforce DTLS packet boundaries.
76e48c5 Fix Windows mode.
3fa65f0 Fix some malloc test crashs.
0b635c5 Add malloc test support to unit tests.
3e3090d Pass a dtls1_use_epoch enum down to dtls1_seal_record.
31a0779 Factor SSL_AEAD_CTX into a dedicated type.
69d07d9 Get version-related functions from crypto.h rather than ssl.h.
b487df6 Pull version, option, and mode APIs into their own sections.
7270cfc Prune version constants.
7ef9fff Remove ssl_ok.
afc9ecd Unexport ssl_get_new_session and ssl_update_cache.
3b7456e Fix some documentation typos.
b480428 Also skip #elif lines.
6deacb3 Parse macros in getNameFromDecl.
4831c33 Document some core SSL_CTX and SSL methods.
4dab297 Don't use struct names in ssl.h.
760b1dd Tidy up state machine coverage tests.
3629c7b Add client peer-initiated renego to the state machine tests.
cff0b90 Add client-side tests for renegotiation_info enforcement.
6bff1ca Specify argc and argv arguments to refcount_test:main.
12a4768 Try to fix MSVC and __STDC_VERSION__ again.
cb56c2a Cast refcounts to _Atomic before use.
0d1d0d5 Try again to only test __STDC_VERSION__ when defined.
7b348dc Disable C11 atomics on OS X.
04edcc8 Tag the mutex functions with OPENSSL_EXPORT.
6e1f645 Don't test __STDC_VERSION__ unless it's defined.
552df47 Remove leftovers of the old-style locks.
6fb174e Remove last references to named locks.
4bdb6e4 Remove remaining calls to the old lock functions.
03163f3 Remove |CRYPTO_add|.
0b5e390 Convert reference counts in ssl/
0da323a Convert reference counts in crypto/
6f2e733 Add infrastructure for reference counts.
daaff93 Use C11 _Static_assert where available.
dc8c739 Implement |DES_ede2_cbc_encrypt|.
a7997f1 Set minimum DH group size to 1024 bits.
4a7b70d Add LICENSE file.
b3a262c Fix |SSLeay|.
f0320d3 Fix use after free in X509.
3dacff9 Always include x86_64-gcc.c in the standalone build.
9660032 Don't use x86_64-gcc.c with NO_ASM.
81091d5 Don't use uninitialized memory in RAND_bytes.
d72e284 Support arbitrary elliptic curve groups.
a07c0fc Fix SSL_get_current_cipher.
4b27d9f Never resume sessions on renegotiations.
785e07b Copy ecdsa_meth in EC_KEY_copy.
08dc68d Define no-op options consistently.
e6df054 Add s->s3->initial_handshake_complete.
897e5e0 Default renegotiations to off.
4690bb5 Port cipher_test to file_test.
771a138 Add missing #include for abort()
de12d6c Mind the end of the buffer in aligned case of generic RC4 implementation.
5694b3a Fix invalid assert in CRYPTO_ctr128_encrypt.
9b68e72 Define compatibility function |ERR_remove_state|.
2607383 Fix generate_build_files.py to account for crypto/test.
af3d5bd Add no-op |RAND_load_file| function for compatibility.
58e95fc Remove a spurious semicolon after |DECLARE_LHASH_OF|.
3c65171 Add buffer.h for compatibility.
c85373d Use EVP_AEAD_CTX in crypto/cipher/internal.h.
Change-Id: Ife3698f4520572e1fca48732c6a1cbd4254ec85c
Diffstat (limited to 'src/ssl')
38 files changed, 2104 insertions, 2305 deletions
diff --git a/src/ssl/CMakeLists.txt b/src/ssl/CMakeLists.txt index 9cc6de4..cf5a29d 100644 --- a/src/ssl/CMakeLists.txt +++ b/src/ssl/CMakeLists.txt @@ -19,6 +19,7 @@ add_library( s3_meth.c s3_pkt.c s3_srvr.c + ssl_aead_ctx.c ssl_algs.c ssl_asn1.c ssl_cert.c @@ -39,6 +40,8 @@ add_executable( ssl_test ssl_test.cc + + $<TARGET_OBJECTS:test_support> ) target_link_libraries(ssl_test ssl crypto) diff --git a/src/ssl/d1_both.c b/src/ssl/d1_both.c index 662f518..ac35a66 100644 --- a/src/ssl/d1_both.c +++ b/src/ssl/d1_both.c @@ -259,11 +259,10 @@ static void dtls1_hm_fragment_mark(hm_fragment *frag, size_t start, /* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or * SSL3_RT_CHANGE_CIPHER_SPEC) */ -int dtls1_do_write(SSL *s, int type) { +int dtls1_do_write(SSL *s, int type, enum dtls1_use_epoch_t use_epoch) { int ret; int curr_mtu; unsigned int len, frag_off; - size_t max_overhead = 0; /* AHA! Figure out the MTU, and stick to the right size */ if (s->d1->mtu < dtls1_min_mtu() && @@ -286,12 +285,7 @@ int dtls1_do_write(SSL *s, int type) { } /* Determine the maximum overhead of the current cipher. */ - if (s->aead_write_ctx != NULL) { - max_overhead = EVP_AEAD_max_overhead(s->aead_write_ctx->ctx.aead); - if (s->aead_write_ctx->variable_nonce_included_in_record) { - max_overhead += s->aead_write_ctx->variable_nonce_len; - } - } + size_t max_overhead = SSL_AEAD_CTX_max_overhead(s->aead_write_ctx); frag_off = 0; while (s->init_num) { @@ -356,7 +350,8 @@ int dtls1_do_write(SSL *s, int type) { len = s->init_num; } - ret = dtls1_write_bytes(s, type, &s->init_buf->data[s->init_off], len); + ret = dtls1_write_bytes(s, type, &s->init_buf->data[s->init_off], len, + use_epoch); if (ret < 0) { return -1; } @@ -409,8 +404,7 @@ static int dtls1_discard_fragment_body(SSL *s, size_t frag_len) { uint8_t discard[256]; while (frag_len > 0) { size_t chunk = frag_len < sizeof(discard) ? frag_len : sizeof(discard); - int ret = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, discard, chunk, - 0); + int ret = dtls1_read_bytes(s, SSL3_RT_HANDSHAKE, discard, chunk, 0); if (ret != chunk) { return 0; } @@ -485,8 +479,8 @@ static int dtls1_process_fragment(SSL *s) { * body across two records. Change this interface to consume the fragment in * one pass. */ uint8_t header[DTLS1_HM_HEADER_LENGTH]; - int ret = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, header, - DTLS1_HM_HEADER_LENGTH, 0); + int ret = dtls1_read_bytes(s, SSL3_RT_HANDSHAKE, header, + DTLS1_HM_HEADER_LENGTH, 0); if (ret <= 0) { return ret; } @@ -538,8 +532,8 @@ static int dtls1_process_fragment(SSL *s) { assert(msg_len > 0); /* Read the body of the fragment. */ - ret = s->method->ssl_read_bytes( - s, SSL3_RT_HANDSHAKE, frag->fragment + frag_off, frag_len, 0); + ret = dtls1_read_bytes(s, SSL3_RT_HANDSHAKE, frag->fragment + frag_off, + frag_len, 0); if (ret != frag_len) { OPENSSL_PUT_ERROR(SSL, dtls1_process_fragment, SSL_R_UNEXPECTED_MESSAGE); ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); @@ -690,7 +684,7 @@ int dtls1_send_change_cipher_spec(SSL *s, int a, int b) { } /* SSL3_ST_CW_CHANGE_B */ - return dtls1_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC); + return dtls1_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC, dtls1_use_current_epoch); } int dtls1_read_failed(SSL *s, int code) { @@ -730,7 +724,6 @@ static int dtls1_retransmit_message(SSL *s, hm_fragment *frag) { int ret; /* XDTLS: for now assuming that read/writes are blocking */ unsigned long header_length; - uint8_t save_write_sequence[8]; /* assert(s->init_num == 0); assert(s->init_off == 0); */ @@ -749,45 +742,18 @@ static int dtls1_retransmit_message(SSL *s, hm_fragment *frag) { frag->msg_header.msg_len, frag->msg_header.seq, 0, frag->msg_header.frag_len); - /* Save current state. */ - SSL_AEAD_CTX *aead_write_ctx = s->aead_write_ctx; - uint16_t epoch = s->d1->w_epoch; - /* DTLS renegotiation is unsupported, so only epochs 0 (NULL cipher) and 1 * (negotiated cipher) exist. */ - assert(epoch == 0 || epoch == 1); - assert(frag->msg_header.epoch <= epoch); - const int fragment_from_previous_epoch = (epoch == 1 && - frag->msg_header.epoch == 0); - if (fragment_from_previous_epoch) { - /* Rewind to the previous epoch. - * - * TODO(davidben): Instead of swapping out connection-global state, this - * logic should pass a "use previous epoch" parameter down to lower-level - * functions. */ - s->d1->w_epoch = frag->msg_header.epoch; - s->aead_write_ctx = NULL; - memcpy(save_write_sequence, s->s3->write_sequence, - sizeof(s->s3->write_sequence)); - memcpy(s->s3->write_sequence, s->d1->last_write_sequence, - sizeof(s->s3->write_sequence)); - } else { - /* Otherwise the messages must be from the same epoch. */ - assert(frag->msg_header.epoch == epoch); + assert(s->d1->w_epoch == 0 || s->d1->w_epoch == 1); + assert(frag->msg_header.epoch <= s->d1->w_epoch); + enum dtls1_use_epoch_t use_epoch = dtls1_use_current_epoch; + if (s->d1->w_epoch == 1 && frag->msg_header.epoch == 0) { + use_epoch = dtls1_use_previous_epoch; } ret = dtls1_do_write(s, frag->msg_header.is_ccs ? SSL3_RT_CHANGE_CIPHER_SPEC - : SSL3_RT_HANDSHAKE); - - if (fragment_from_previous_epoch) { - /* Restore the current epoch. */ - s->aead_write_ctx = aead_write_ctx; - s->d1->w_epoch = epoch; - memcpy(s->d1->last_write_sequence, s->s3->write_sequence, - sizeof(s->s3->write_sequence)); - memcpy(s->s3->write_sequence, save_write_sequence, - sizeof(s->s3->write_sequence)); - } + : SSL3_RT_HANDSHAKE, + use_epoch); (void)BIO_flush(SSL_get_wbio(s)); return ret; @@ -917,9 +883,3 @@ void dtls1_get_message_header(uint8_t *data, n2l3(data, msg_hdr->frag_off); n2l3(data, msg_hdr->frag_len); } - -int dtls1_shutdown(SSL *s) { - int ret; - ret = ssl3_shutdown(s); - return ret; -} diff --git a/src/ssl/d1_clnt.c b/src/ssl/d1_clnt.c index 1827a67..92fb8f6 100644 --- a/src/ssl/d1_clnt.c +++ b/src/ssl/d1_clnt.c @@ -155,12 +155,7 @@ int dtls1_connect(SSL *s) { state = s->state; switch (s->state) { - case SSL_ST_RENEGOTIATE: - s->renegotiate = 1; - s->state = SSL_ST_CONNECT; - /* break */ case SSL_ST_CONNECT: - case SSL_ST_BEFORE | SSL_ST_CONNECT: if (cb != NULL) { cb(s, SSL_CB_HANDSHAKE_START, 1); } @@ -472,8 +467,7 @@ int dtls1_connect(SSL *s) { ssl_free_wbio_buffer(s); s->init_num = 0; - s->renegotiate = 0; - s->new_session = 0; + s->s3->initial_handshake_complete = 1; ssl_update_cache(s, SSL_SESS_CACHE_CLIENT); diff --git a/src/ssl/d1_lib.c b/src/ssl/d1_lib.c index e53156f..ef7a9c9 100644 --- a/src/ssl/d1_lib.c +++ b/src/ssl/d1_lib.c @@ -151,14 +151,9 @@ void dtls1_free(SSL *s) { s->d1 = NULL; } -const SSL_CIPHER *dtls1_get_cipher(size_t i) { - const SSL_CIPHER *ciph = ssl3_get_cipher(i); +int dtls1_supports_cipher(const SSL_CIPHER *cipher) { /* DTLS does not support stream ciphers. */ - if (ciph == NULL || ciph->algorithm_enc == SSL_RC4) { - return NULL; - } - - return ciph; + return cipher->algorithm_enc != SSL_RC4; } void dtls1_start_timer(SSL *s) { @@ -338,5 +333,5 @@ int dtls1_set_handshake_header(SSL *s, int htype, unsigned long len) { } int dtls1_handshake_write(SSL *s) { - return dtls1_do_write(s, SSL3_RT_HANDSHAKE); + return dtls1_do_write(s, SSL3_RT_HANDSHAKE, dtls1_use_current_epoch); } diff --git a/src/ssl/d1_meth.c b/src/ssl/d1_meth.c index a11fbdd..d90f75b 100644 --- a/src/ssl/d1_meth.c +++ b/src/ssl/d1_meth.c @@ -64,21 +64,14 @@ static const SSL_PROTOCOL_METHOD DTLS_protocol_method = { dtls1_free, dtls1_accept, dtls1_connect, - ssl3_read, - ssl3_peek, - ssl3_write, - dtls1_shutdown, - ssl3_renegotiate, - ssl3_renegotiate_check, dtls1_get_message, - dtls1_read_bytes, - dtls1_write_app_data_bytes, + dtls1_read_app_data, + dtls1_read_close_notify, + dtls1_write_app_data, dtls1_dispatch_alert, ssl3_ctrl, ssl3_ctx_ctrl, - ssl3_pending, - ssl3_num_ciphers, - dtls1_get_cipher, + dtls1_supports_cipher, DTLS1_HM_HEADER_LENGTH, dtls1_set_handshake_header, dtls1_handshake_write, diff --git a/src/ssl/d1_pkt.c b/src/ssl/d1_pkt.c index 9e056ac..553499f 100644 --- a/src/ssl/d1_pkt.c +++ b/src/ssl/d1_pkt.c @@ -185,25 +185,11 @@ static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap); static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap); static int dtls1_process_record(SSL *s); static int do_dtls1_write(SSL *s, int type, const uint8_t *buf, - unsigned int len); + unsigned int len, enum dtls1_use_epoch_t use_epoch); static int dtls1_process_record(SSL *s) { int al; - SSL3_RECORD *rr; - - rr = &(s->s3->rrec); - - /* At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length, and - * we have that many bytes in s->packet. */ - rr->input = &(s->packet[DTLS1_RT_HEADER_LENGTH]); - - /* ok, we can now read from 's->packet' data into 'rr' rr->input points at - * rr->length bytes, which need to be copied into rr->data by either the - * decryption or by the decompression When the data is 'copied' into the - * rr->data buffer, rr->input will be pointed at the new buffer */ - - /* We now have - encrypted [ MAC [ compressed [ plain ] ] ] rr->length bytes - * of encrypted compressed stuff. */ + SSL3_RECORD *rr = &s->s3->rrec; /* check is not needed I believe */ if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) { @@ -213,10 +199,23 @@ static int dtls1_process_record(SSL *s) { goto f_err; } - /* decrypt in place in 'rr->input' */ - rr->data = rr->input; + /* |rr->data| points to |rr->length| bytes of ciphertext in |s->packet|. */ + rr->data = &s->packet[DTLS1_RT_HEADER_LENGTH]; + + uint8_t seq[8]; + seq[0] = rr->epoch >> 8; + seq[1] = rr->epoch & 0xff; + memcpy(&seq[2], &rr->seq_num[2], 6); - if (!s->enc_method->enc(s, 0)) { + /* Decrypt the packet in-place. Note it is important that |SSL_AEAD_CTX_open| + * not write beyond |rr->length|. There may be another record in the packet. + * + * TODO(davidben): This assumes |s->version| is the same as the record-layer + * version which isn't always true, but it only differs with the NULL cipher + * which ignores the parameter. */ + size_t plaintext_len; + if (!SSL_AEAD_CTX_open(s->aead_read_ctx, rr->data, &plaintext_len, rr->length, + rr->type, s->version, seq, rr->data, rr->length)) { /* Bad packets are silently dropped in DTLS. Clear the error queue of any * errors decryption may have added. */ ERR_clear_error(); @@ -225,19 +224,20 @@ static int dtls1_process_record(SSL *s) { goto err; } - if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH) { + if (plaintext_len > SSL3_RT_MAX_PLAIN_LENGTH) { al = SSL_AD_RECORD_OVERFLOW; OPENSSL_PUT_ERROR(SSL, dtls1_process_record, SSL_R_DATA_LENGTH_TOO_LONG); goto f_err; } + assert(plaintext_len < (1u << 16)); + rr->length = plaintext_len; rr->off = 0; /* So at this point the following is true * ssl->s3->rrec.type is the type of record * ssl->s3->rrec.length == number of bytes in record * ssl->s3->rrec.off == offset to first valid byte - * ssl->s3->rrec.data == where to take bytes from, increment - * after use :-). */ + * ssl->s3->rrec.data == the first byte of the record body. */ /* we have pulled in a full packet so zero things */ s->packet_length = 0; @@ -260,11 +260,11 @@ err: * * used only by dtls1_read_bytes */ int dtls1_get_record(SSL *s) { - int ssl_major, ssl_minor; - int i, n; + uint8_t ssl_major, ssl_minor; + int n; SSL3_RECORD *rr; - unsigned char *p = NULL; - unsigned short version; + uint8_t *p = NULL; + uint16_t version; rr = &(s->s3->rrec); @@ -298,7 +298,7 @@ again: rr->type = *(p++); ssl_major = *(p++); ssl_minor = *(p++); - version = (ssl_major << 8) | ssl_minor; + version = (((uint16_t)ssl_major) << 8) | ssl_minor; /* sequence number is 64 bits, with top 2 bytes = epoch */ n2s(p, rr->epoch); @@ -344,14 +344,9 @@ again: if (rr->length > s->packet_length - DTLS1_RT_HEADER_LENGTH) { /* now s->packet_length == DTLS1_RT_HEADER_LENGTH */ - i = rr->length; - n = ssl3_read_n(s, i, 1); - if (n <= 0) { - return n; /* error or non-blocking io */ - } - - /* this packet contained a partial record, dump it */ - if (n != i) { + n = ssl3_read_n(s, rr->length, 1); + /* This packet contained a partial record, dump it. */ + if (n != rr->length) { rr->length = 0; s->packet_length = 0; goto again; @@ -393,6 +388,14 @@ again: return 1; } +int dtls1_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek) { + return dtls1_read_bytes(ssl, SSL3_RT_APPLICATION_DATA, buf, len, peek); +} + +void dtls1_read_close_notify(SSL *ssl) { + dtls1_read_bytes(ssl, 0, NULL, 0, 0); +} + /* Return up to 'len' payload bytes received in 'type' records. * 'type' is one of the following: * @@ -674,7 +677,7 @@ err: return -1; } -int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len) { +int dtls1_write_app_data(SSL *s, const void *buf_, int len) { int i; if (SSL_in_init(s) && !s->in_handshake) { @@ -683,130 +686,133 @@ int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len) { return i; } if (i == 0) { - OPENSSL_PUT_ERROR(SSL, dtls1_write_app_data_bytes, - SSL_R_SSL_HANDSHAKE_FAILURE); + OPENSSL_PUT_ERROR(SSL, dtls1_write_app_data, SSL_R_SSL_HANDSHAKE_FAILURE); return -1; } } if (len > SSL3_RT_MAX_PLAIN_LENGTH) { - OPENSSL_PUT_ERROR(SSL, dtls1_write_app_data_bytes, - SSL_R_DTLS_MESSAGE_TOO_BIG); + OPENSSL_PUT_ERROR(SSL, dtls1_write_app_data, SSL_R_DTLS_MESSAGE_TOO_BIG); return -1; } - i = dtls1_write_bytes(s, type, buf_, len); + i = dtls1_write_bytes(s, SSL3_RT_APPLICATION_DATA, buf_, len, + dtls1_use_current_epoch); return i; } /* Call this to write data in records of type 'type' It will return <= 0 if not * all data has been sent or non-blocking IO. */ -int dtls1_write_bytes(SSL *s, int type, const void *buf, int len) { +int dtls1_write_bytes(SSL *s, int type, const void *buf, int len, + enum dtls1_use_epoch_t use_epoch) { int i; assert(len <= SSL3_RT_MAX_PLAIN_LENGTH); s->rwstate = SSL_NOTHING; - i = do_dtls1_write(s, type, buf, len); + i = do_dtls1_write(s, type, buf, len, use_epoch); return i; } -static int do_dtls1_write(SSL *s, int type, const uint8_t *buf, - unsigned int len) { - uint8_t *p, *pseq; - int i; - int prefix_len = 0; - int eivlen = 0; - SSL3_RECORD *wr; - SSL3_BUFFER *wb; - - /* ssl3_write_pending drops the write if |BIO_write| fails in DTLS, so there - * is never pending data. */ - assert(s->s3->wbuf.left == 0); - - /* If we have an alert to send, lets send it */ - if (s->s3->alert_dispatch) { - i = s->method->ssl_dispatch_alert(s); - if (i <= 0) { - return i; - } - /* if it went, fall through and send more stuff */ +/* dtls1_seal_record seals a new record of type |type| and plaintext |in| and + * writes it to |out|. At most |max_out| bytes will be written. It returns one + * on success and zero on error. On success, it updates the write sequence + * number. */ +static int dtls1_seal_record(SSL *s, uint8_t *out, size_t *out_len, + size_t max_out, uint8_t type, const uint8_t *in, + size_t in_len, enum dtls1_use_epoch_t use_epoch) { + if (max_out < DTLS1_RT_HEADER_LENGTH) { + OPENSSL_PUT_ERROR(SSL, dtls1_seal_record, SSL_R_BUFFER_TOO_SMALL); + return 0; } - if (len == 0) { - return 0; + /* Determine the parameters for the current epoch. */ + uint16_t epoch = s->d1->w_epoch; + SSL_AEAD_CTX *aead = s->aead_write_ctx; + uint8_t *seq = s->s3->write_sequence; + if (use_epoch == dtls1_use_previous_epoch) { + /* DTLS renegotiation is unsupported, so only epochs 0 (NULL cipher) and 1 + * (negotiated cipher) exist. */ + assert(s->d1->w_epoch == 1); + epoch = s->d1->w_epoch - 1; + aead = NULL; + seq = s->d1->last_write_sequence; } - wr = &(s->s3->wrec); - wb = &(s->s3->wbuf); + out[0] = type; - if (wb->buf == NULL && !ssl3_setup_write_buffer(s)) { - return -1; - } - p = wb->buf + prefix_len; + uint16_t wire_version = s->s3->have_version ? s->version : DTLS1_VERSION; + out[1] = wire_version >> 8; + out[2] = wire_version & 0xff; - /* write the header */ + out[3] = epoch >> 8; + out[4] = epoch & 0xff; + memcpy(&out[5], &seq[2], 6); - *(p++) = type & 0xff; - wr->type = type; - /* Special case: for hello verify request, client version 1.0 and - * we haven't decided which version to use yet send back using - * version 1.0 header: otherwise some clients will ignore it. - */ - if (!s->s3->have_version) { - *(p++) = DTLS1_VERSION >> 8; - *(p++) = DTLS1_VERSION & 0xff; - } else { - *(p++) = s->version >> 8; - *(p++) = s->version & 0xff; + size_t ciphertext_len; + if (!SSL_AEAD_CTX_seal(aead, out + DTLS1_RT_HEADER_LENGTH, &ciphertext_len, + max_out - DTLS1_RT_HEADER_LENGTH, type, wire_version, + &out[3] /* seq */, in, in_len) || + !ssl3_record_sequence_update(&seq[2], 6)) { + return 0; + } + + if (ciphertext_len >= 1 << 16) { + OPENSSL_PUT_ERROR(SSL, dtls1_seal_record, ERR_R_OVERFLOW); + return 0; } + out[11] = ciphertext_len >> 8; + out[12] = ciphertext_len & 0xff; - /* field where we are to write out packet epoch, seq num and len */ - pseq = p; - p += 10; + *out_len = DTLS1_RT_HEADER_LENGTH + ciphertext_len; - /* Leave room for the variable nonce for AEADs which specify it explicitly. */ - if (s->aead_write_ctx != NULL && - s->aead_write_ctx->variable_nonce_included_in_record) { - eivlen = s->aead_write_ctx->variable_nonce_len; + if (s->msg_callback) { + s->msg_callback(1 /* write */, 0, SSL3_RT_HEADER, out, + DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg); } - /* Assemble the input for |s->enc_method->enc|. The input is the plaintext - * with |eivlen| bytes of space prepended for the explicit nonce. */ - wr->input = p; - wr->length = eivlen + len; - memcpy(p + eivlen, buf, len); + return 1; +} - /* Encrypt in-place, so the output also goes into |p|. */ - wr->data = p; +static int do_dtls1_write(SSL *s, int type, const uint8_t *buf, + unsigned int len, enum dtls1_use_epoch_t use_epoch) { + SSL3_BUFFER *wb = &s->s3->wbuf; - if (!s->enc_method->enc(s, 1)) { - goto err; - } + /* ssl3_write_pending drops the write if |BIO_write| fails in DTLS, so there + * is never pending data. */ + assert(s->s3->wbuf.left == 0); - /* there's only one epoch between handshake and app data */ - s2n(s->d1->w_epoch, pseq); + /* If we have an alert to send, lets send it */ + if (s->s3->alert_dispatch) { + int ret = s->method->ssl_dispatch_alert(s); + if (ret <= 0) { + return ret; + } + /* if it went, fall through and send more stuff */ + } - memcpy(pseq, &(s->s3->write_sequence[2]), 6); - pseq += 6; - s2n(wr->length, pseq); + if (wb->buf == NULL && !ssl3_setup_write_buffer(s)) { + return -1; + } - if (s->msg_callback) { - s->msg_callback(1, 0, SSL3_RT_HEADER, pseq - DTLS1_RT_HEADER_LENGTH, - DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg); + if (len == 0) { + return 0; } - /* we should now have wr->data pointing to the encrypted data, which is - * wr->length long */ - wr->type = type; /* not needed but helps for debugging */ - wr->length += DTLS1_RT_HEADER_LENGTH; + /* Align the output so the ciphertext is aligned to |SSL3_ALIGN_PAYLOAD|. */ + uintptr_t align = (uintptr_t)wb->buf + DTLS1_RT_HEADER_LENGTH; + align = (0 - align) & (SSL3_ALIGN_PAYLOAD - 1); + uint8_t *out = wb->buf + align; + wb->offset = align; + size_t max_out = wb->len - wb->offset; - if (!ssl3_record_sequence_update(&s->s3->write_sequence[2], 6)) { - goto err; + size_t ciphertext_len; + if (!dtls1_seal_record(s, out, &ciphertext_len, max_out, type, buf, len, + use_epoch)) { + return -1; } /* now let's set up wb */ - wb->left = prefix_len + wr->length; - wb->offset = 0; + wb->left = ciphertext_len; /* memorize arguments so that ssl3_write_pending can detect bad write retries * later */ @@ -817,9 +823,6 @@ static int do_dtls1_write(SSL *s, int type, const uint8_t *buf, /* we now just need to write the buffer */ return ssl3_write_pending(s, type, buf, len); - -err: - return -1; } static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap) { @@ -877,7 +880,8 @@ int dtls1_dispatch_alert(SSL *s) { *ptr++ = s->s3->send_alert[0]; *ptr++ = s->s3->send_alert[1]; - i = do_dtls1_write(s, SSL3_RT_ALERT, &buf[0], sizeof(buf)); + i = do_dtls1_write(s, SSL3_RT_ALERT, &buf[0], sizeof(buf), + dtls1_use_current_epoch); if (i <= 0) { s->s3->alert_dispatch = 1; } else { diff --git a/src/ssl/d1_srvr.c b/src/ssl/d1_srvr.c index e314910..e49a3f0 100644 --- a/src/ssl/d1_srvr.c +++ b/src/ssl/d1_srvr.c @@ -159,12 +159,7 @@ int dtls1_accept(SSL *s) { state = s->state; switch (s->state) { - case SSL_ST_RENEGOTIATE: - s->renegotiate = 1; - /* s->state=SSL_ST_ACCEPT; */ - case SSL_ST_ACCEPT: - case SSL_ST_BEFORE | SSL_ST_ACCEPT: if (cb != NULL) { cb(s, SSL_CB_HANDSHAKE_START, 1); } @@ -181,49 +176,18 @@ int dtls1_accept(SSL *s) { s->init_num = 0; - if (s->state != SSL_ST_RENEGOTIATE) { - if (!ssl_init_wbio_buffer(s, 1)) { - ret = -1; - goto end; - } - - if (!ssl3_init_finished_mac(s)) { - OPENSSL_PUT_ERROR(SSL, dtls1_accept, ERR_R_INTERNAL_ERROR); - ret = -1; - goto end; - } - - s->state = SSL3_ST_SR_CLNT_HELLO_A; - } else { - /* s->state == SSL_ST_RENEGOTIATE, * we will just send a - * HelloRequest */ - s->state = SSL3_ST_SW_HELLO_REQ_A; - } - - break; - - case SSL3_ST_SW_HELLO_REQ_A: - case SSL3_ST_SW_HELLO_REQ_B: - s->shutdown = 0; - dtls1_clear_record_buffer(s); - dtls1_start_timer(s); - ret = ssl3_send_hello_request(s); - if (ret <= 0) { + if (!ssl_init_wbio_buffer(s, 1)) { + ret = -1; goto end; } - s->s3->tmp.next_state = SSL3_ST_SR_CLNT_HELLO_A; - s->state = SSL3_ST_SW_FLUSH; - s->init_num = 0; if (!ssl3_init_finished_mac(s)) { OPENSSL_PUT_ERROR(SSL, dtls1_accept, ERR_R_INTERNAL_ERROR); ret = -1; goto end; } - break; - case SSL3_ST_SW_HELLO_REQ_C: - s->state = SSL_ST_OK; + s->state = SSL3_ST_SR_CLNT_HELLO_A; break; case SSL3_ST_SR_CLNT_HELLO_A: @@ -242,7 +206,6 @@ int dtls1_accept(SSL *s) { case SSL3_ST_SW_SRVR_HELLO_A: case SSL3_ST_SW_SRVR_HELLO_B: - s->renegotiate = 2; dtls1_start_timer(s); ret = ssl3_send_server_hello(s); if (ret <= 0) { @@ -310,29 +273,17 @@ int dtls1_accept(SSL *s) { case SSL3_ST_SW_CERT_REQ_A: case SSL3_ST_SW_CERT_REQ_B: - if (/* don't request cert unless asked for it: */ - !(s->verify_mode & SSL_VERIFY_PEER) || - /* if SSL_VERIFY_CLIENT_ONCE is set, - * don't request cert during re-negotiation: */ - ((s->session->peer != NULL) && - (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) || - /* With normal PSK Certificates and - * Certificate Requests are omitted */ - (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { - /* no cert request */ - skip = 1; - s->s3->tmp.cert_request = 0; - s->state = SSL3_ST_SW_SRVR_DONE_A; - } else { - s->s3->tmp.cert_request = 1; + if (s->s3->tmp.cert_request) { dtls1_start_timer(s); ret = ssl3_send_certificate_request(s); if (ret <= 0) { goto end; } - s->state = SSL3_ST_SW_SRVR_DONE_A; - s->init_num = 0; + } else { + skip = 1; } + s->state = SSL3_ST_SW_SRVR_DONE_A; + s->init_num = 0; break; case SSL3_ST_SW_SRVR_DONE_A: @@ -470,17 +421,12 @@ int dtls1_accept(SSL *s) { ssl_free_wbio_buffer(s); s->init_num = 0; + s->s3->initial_handshake_complete = 1; - if (s->renegotiate == 2) { - /* skipped if we just sent a HelloRequest */ - s->renegotiate = 0; - s->new_session = 0; + ssl_update_cache(s, SSL_SESS_CACHE_SERVER); - ssl_update_cache(s, SSL_SESS_CACHE_SERVER); - - if (cb != NULL) { - cb(s, SSL_CB_HANDSHAKE_DONE, 1); - } + if (cb != NULL) { + cb(s, SSL_CB_HANDSHAKE_DONE, 1); } ret = 1; diff --git a/src/ssl/internal.h b/src/ssl/internal.h index 3bd749d..7d9a5ad 100644 --- a/src/ssl/internal.h +++ b/src/ssl/internal.h @@ -215,19 +215,6 @@ * one, update the table in ssl_cipher.c. */ #define SSL_MAX_DIGEST 4 -#define TLS1_PRF_DGST_MASK (0xff << TLS1_PRF_DGST_SHIFT) - -#define TLS1_PRF_DGST_SHIFT 10 -#define TLS1_PRF_MD5 (SSL_HANDSHAKE_MAC_MD5 << TLS1_PRF_DGST_SHIFT) -#define TLS1_PRF_SHA1 (SSL_HANDSHAKE_MAC_SHA << TLS1_PRF_DGST_SHIFT) -#define TLS1_PRF_SHA256 (SSL_HANDSHAKE_MAC_SHA256 << TLS1_PRF_DGST_SHIFT) -#define TLS1_PRF_SHA384 (SSL_HANDSHAKE_MAC_SHA384 << TLS1_PRF_DGST_SHIFT) -#define TLS1_PRF (TLS1_PRF_MD5 | TLS1_PRF_SHA1) - -/* SSL_CIPHER_ALGORITHM2_AEAD is a flag in SSL_CIPHER.algorithm2 which - * indicates that the cipher is implemented via an EVP_AEAD. */ -#define SSL_CIPHER_ALGORITHM2_AEAD (1 << 23) - /* SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD is a flag in * SSL_CIPHER.algorithm2 which indicates that the variable part of the nonce is * included as a prefix of the record. (AES-GCM, for example, does with with an @@ -273,6 +260,9 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, #define SSL_PKEY_ECC 2 #define SSL_PKEY_NUM 3 +/* ssl_cipher_get_value returns the cipher suite id of |cipher|. */ +uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher); + /* ssl_cipher_get_cert_index returns the |SSL_PKEY_*| value corresponding to the * certificate type of |cipher| or -1 if there is none. */ int ssl_cipher_get_cert_index(const SSL_CIPHER *cipher); @@ -291,6 +281,75 @@ int ssl_cipher_has_server_public_key(const SSL_CIPHER *cipher); int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher); +/* Encryption layer. */ + +/* SSL_AEAD_CTX contains information about an AEAD that is being used to encrypt + * an SSL connection. */ +struct ssl_aead_ctx_st { + const SSL_CIPHER *cipher; + EVP_AEAD_CTX ctx; + /* fixed_nonce contains any bytes of the nonce that are fixed for all + * records. */ + uint8_t fixed_nonce[8]; + uint8_t fixed_nonce_len, variable_nonce_len; + /* variable_nonce_included_in_record is non-zero if the variable nonce + * for a record is included as a prefix before the ciphertext. */ + char variable_nonce_included_in_record; + /* random_variable_nonce is non-zero if the variable nonce is + * randomly generated, rather than derived from the sequence + * number. */ + char random_variable_nonce; + /* omit_length_in_ad is non-zero if the length should be omitted in the + * AEAD's ad parameter. */ + char omit_length_in_ad; + /* omit_version_in_ad is non-zero if the version should be omitted + * in the AEAD's ad parameter. */ + char omit_version_in_ad; +} /* SSL_AEAD_CTX */; + +/* SSL_AEAD_CTX_new creates a newly-allocated |SSL_AEAD_CTX| using the supplied + * key material. It returns NULL on error. Only one of |SSL_AEAD_CTX_open| or + * |SSL_AEAD_CTX_seal| may be used with the resulting object, depending on + * |direction|. |version| is the normalized protocol version, so DTLS 1.0 is + * represented as 0x0301, not 0xffef. */ +SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction, + uint16_t version, const SSL_CIPHER *cipher, + const uint8_t *enc_key, size_t enc_key_len, + const uint8_t *mac_key, size_t mac_key_len, + const uint8_t *fixed_iv, size_t fixed_iv_len); + +/* SSL_AEAD_CTX_free frees |ctx|. */ +void SSL_AEAD_CTX_free(SSL_AEAD_CTX *ctx); + +/* SSL_AEAD_CTX_explicit_nonce_len returns the length of the explicit nonce for + * |ctx|, if any. |ctx| may be NULL to denote the null cipher. */ +size_t SSL_AEAD_CTX_explicit_nonce_len(SSL_AEAD_CTX *ctx); + +/* SSL_AEAD_CTX_max_overhead returns the maximum overhead of calling + * |SSL_AEAD_CTX_seal|. |ctx| may be NULL to denote the null cipher. */ +size_t SSL_AEAD_CTX_max_overhead(SSL_AEAD_CTX *ctx); + +/* SSL_AEAD_CTX_open authenticates and decrypts |in_len| bytes from |in| and + * writes the result to |out|. It returns one on success and zero on + * error. |ctx| may be NULL to denote the null cipher. + * + * If |in| and |out| alias then |out| must be <= |in| + |explicit_nonce_len|. */ +int SSL_AEAD_CTX_open(SSL_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, + size_t max_out, uint8_t type, uint16_t wire_version, + const uint8_t seqnum[8], const uint8_t *in, + size_t in_len); + +/* SSL_AEAD_CTX_seal encrypts and authenticates |in_len| bytes from |in| and + * writes the result to |out|. It returns one on success and zero on + * error. |ctx| may be NULL to denote the null cipher. + * + * If |in| and |out| alias then |out| + |explicit_nonce_len| must be <= |in| */ +int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, + size_t max_out, uint8_t type, uint16_t wire_version, + const uint8_t seqnum[8], const uint8_t *in, + size_t in_len); + + /* Underdocumented functions. * * Functions below here haven't been touched up and may be underdocumented. */ @@ -568,23 +627,18 @@ struct ssl_protocol_method_st { void (*ssl_free)(SSL *s); int (*ssl_accept)(SSL *s); int (*ssl_connect)(SSL *s); - int (*ssl_read)(SSL *s, void *buf, int len); - int (*ssl_peek)(SSL *s, void *buf, int len); - int (*ssl_write)(SSL *s, const void *buf, int len); - int (*ssl_shutdown)(SSL *s); - int (*ssl_renegotiate)(SSL *s); - int (*ssl_renegotiate_check)(SSL *s); long (*ssl_get_message)(SSL *s, int header_state, int body_state, int msg_type, long max, enum ssl_hash_message_t hash_message, int *ok); - int (*ssl_read_bytes)(SSL *s, int type, uint8_t *buf, int len, int peek); - int (*ssl_write_bytes)(SSL *s, int type, const void *buf_, int len); + int (*ssl_read_app_data)(SSL *s, uint8_t *buf, int len, int peek); + void (*ssl_read_close_notify)(SSL *s); + int (*ssl_write_app_data)(SSL *s, const void *buf_, int len); int (*ssl_dispatch_alert)(SSL *s); long (*ssl_ctrl)(SSL *s, int cmd, long larg, void *parg); long (*ssl_ctx_ctrl)(SSL_CTX *ctx, int cmd, long larg, void *parg); - int (*ssl_pending)(const SSL *s); - size_t (*num_ciphers)(void); - const SSL_CIPHER *(*get_cipher)(size_t i); + /* supports_cipher returns one if |cipher| is supported by this protocol and + * zero otherwise. */ + int (*supports_cipher)(const SSL_CIPHER *cipher); /* Handshake header length */ unsigned int hhlen; /* Set the handshake header */ @@ -596,7 +650,6 @@ struct ssl_protocol_method_st { /* This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff It is a bit * of a mess of functions, but hell, think of it as an opaque structure. */ struct ssl3_enc_method { - int (*enc)(SSL *, int); int (*prf)(SSL *, uint8_t *, size_t, const uint8_t *, size_t, const char *, size_t, const uint8_t *, size_t, const uint8_t *, size_t); int (*setup_key_block)(SSL *); @@ -634,29 +687,6 @@ struct ssl3_enc_method { * may apply to others in future. */ #define SSL_ENC_FLAG_TLS1_2_CIPHERS 0x8 -/* ssl_aead_ctx_st contains information about an AEAD that is being used to - * encrypt an SSL connection. */ -struct ssl_aead_ctx_st { - EVP_AEAD_CTX ctx; - /* fixed_nonce contains any bytes of the nonce that are fixed for all - * records. */ - uint8_t fixed_nonce[8]; - uint8_t fixed_nonce_len, variable_nonce_len, tag_len; - /* variable_nonce_included_in_record is non-zero if the variable nonce - * for a record is included as a prefix before the ciphertext. */ - char variable_nonce_included_in_record; - /* random_variable_nonce is non-zero if the variable nonce is - * randomly generated, rather than derived from the sequence - * number. */ - char random_variable_nonce; - /* omit_length_in_ad is non-zero if the length should be omitted in the - * AEAD's ad parameter. */ - char omit_length_in_ad; - /* omit_version_in_ad is non-zero if the version should be omitted - * in the AEAD's ad parameter. */ - char omit_version_in_ad; -}; - /* lengths of messages */ #define DTLS1_COOKIE_LENGTH 256 @@ -757,8 +787,6 @@ typedef struct dtls1_state_st { unsigned int change_cipher_spec_ok; } DTLS1_STATE; -extern const SSL_CIPHER ssl3_ciphers[]; - extern const SSL3_ENC_METHOD TLSv1_enc_data; extern const SSL3_ENC_METHOD TLSv1_1_enc_data; extern const SSL3_ENC_METHOD TLSv1_2_enc_data; @@ -773,9 +801,8 @@ void ssl_cert_free(CERT *c); SESS_CERT *ssl_sess_cert_new(void); void ssl_sess_cert_free(SESS_CERT *sc); int ssl_set_peer_cert_type(SESS_CERT *c, int type); +int ssl_get_new_session(SSL *s, int session); int ssl_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx); -int ssl_cipher_id_cmp(const void *in_a, const void *in_b); -int ssl_cipher_ptr_id_cmp(const SSL_CIPHER **ap, const SSL_CIPHER **bp); STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs); int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, uint8_t *p); struct ssl_cipher_preference_list_st *ssl_cipher_preference_list_dup( @@ -799,6 +826,7 @@ int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags); int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref); CERT_PKEY *ssl_get_server_send_pkey(const SSL *s); EVP_PKEY *ssl_get_sign_pkey(SSL *s, const SSL_CIPHER *c); +void ssl_update_cache(SSL *s, int mode); int ssl_cert_type(EVP_PKEY *pkey); /* ssl_get_compatible_server_ciphers determines the key exchange and @@ -810,10 +838,11 @@ void ssl_get_compatible_server_ciphers(SSL *s, uint32_t *out_mask_k, STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s); int ssl_verify_alarm_type(long type); -int ssl_fill_hello_random(SSL *s, int server, uint8_t *field, size_t len); -const SSL_CIPHER *ssl3_get_cipher_by_value(uint16_t value); -uint16_t ssl3_get_cipher_value(const SSL_CIPHER *c); +/* ssl_fill_hello_random fills a client_random or server_random field of length + * |len|. It returns one on success and zero on failure. */ +int ssl_fill_hello_random(uint8_t *out, size_t len, int is_server); + int ssl3_init_finished_mac(SSL *s); int ssl3_send_server_certificate(SSL *s); int ssl3_send_new_session_ticket(SSL *s); @@ -845,13 +874,13 @@ int ssl3_cert_verify_hash(SSL *s, uint8_t *out, size_t *out_len, const EVP_MD **out_md, EVP_PKEY *pkey); int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen); -size_t ssl3_num_ciphers(void); -const SSL_CIPHER *ssl3_get_cipher(size_t i); -int ssl3_renegotiate(SSL *ssl); -int ssl3_renegotiate_check(SSL *ssl); +int ssl3_supports_cipher(const SSL_CIPHER *cipher); int ssl3_dispatch_alert(SSL *s); int ssl3_expect_change_cipher_spec(SSL *s); +int ssl3_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek); +void ssl3_read_close_notify(SSL *ssl); int ssl3_read_bytes(SSL *s, 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 *s, int type, const void *buf, int len); int ssl3_final_finish_mac(SSL *s, const char *sender, int slen, uint8_t *p); int ssl3_cert_verify_mac(SSL *s, int md_nid, uint8_t *p); @@ -876,13 +905,8 @@ int ssl3_new(SSL *s); void ssl3_free(SSL *s); int ssl3_accept(SSL *s); int ssl3_connect(SSL *s); -int ssl3_read(SSL *s, void *buf, int len); -int ssl3_peek(SSL *s, void *buf, int len); -int ssl3_write(SSL *s, const void *buf, int len); -int ssl3_shutdown(SSL *s); long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg); long ssl3_ctx_ctrl(SSL_CTX *s, int cmd, long larg, void *parg); -int ssl3_pending(const SSL *s); /* ssl3_record_sequence_update increments the sequence number in |seq|. It * returns one on success and zero on wraparound. */ @@ -893,16 +917,24 @@ int ssl3_do_change_cipher_spec(SSL *ssl); int ssl3_set_handshake_header(SSL *s, int htype, unsigned long len); int ssl3_handshake_write(SSL *s); -int dtls1_do_write(SSL *s, int type); +enum dtls1_use_epoch_t { + dtls1_use_previous_epoch, + dtls1_use_current_epoch, +}; + +int dtls1_do_write(SSL *s, int type, enum dtls1_use_epoch_t use_epoch); int ssl3_read_n(SSL *s, int n, int extend); +int dtls1_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek); +void dtls1_read_close_notify(SSL *ssl); int dtls1_read_bytes(SSL *s, int type, uint8_t *buf, int len, int peek); int ssl3_write_pending(SSL *s, int type, const uint8_t *buf, unsigned int len); void dtls1_set_message_header(SSL *s, uint8_t mt, unsigned long len, unsigned short seq_num, unsigned long frag_off, unsigned long frag_len); -int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf, int len); -int dtls1_write_bytes(SSL *s, int type, const void *buf, int len); +int dtls1_write_app_data(SSL *s, const void *buf, int len); +int dtls1_write_bytes(SSL *s, int type, const void *buf, int len, + enum dtls1_use_epoch_t use_epoch); int dtls1_send_change_cipher_spec(SSL *s, int a, int b); int dtls1_send_finished(SSL *s, int a, int b, const char *sender, int slen); @@ -917,7 +949,7 @@ int dtls1_check_timeout_num(SSL *s); int dtls1_set_handshake_header(SSL *s, int type, unsigned long len); int dtls1_handshake_write(SSL *s); -const SSL_CIPHER *dtls1_get_cipher(size_t i); +int dtls1_supports_cipher(const SSL_CIPHER *cipher); void dtls1_start_timer(SSL *s); void dtls1_stop_timer(SSL *s); int dtls1_is_timer_expired(SSL *s); @@ -949,7 +981,6 @@ int ssl3_get_initial_bytes(SSL *s); int ssl3_get_v2_client_hello(SSL *s); int ssl3_get_client_hello(SSL *s); int ssl3_send_server_hello(SSL *s); -int ssl3_send_hello_request(SSL *s); int ssl3_send_server_key_exchange(SSL *s); int ssl3_send_certificate_request(SSL *s); int ssl3_send_server_done(SSL *s); @@ -963,7 +994,6 @@ int dtls1_new(SSL *s); int dtls1_accept(SSL *s); int dtls1_connect(SSL *s); void dtls1_free(SSL *s); -int dtls1_shutdown(SSL *s); long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, enum ssl_hash_message_t hash_message, int *ok); @@ -985,7 +1015,6 @@ int tls1_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret, int tls1_change_cipher_state(SSL *s, int which); int tls1_setup_key_block(SSL *s); -int tls1_enc(SSL *s, int snd); int tls1_handshake_digest(SSL *s, uint8_t *out, size_t out_len); int tls1_final_finish_mac(SSL *s, const char *str, int slen, uint8_t *p); int tls1_cert_verify_mac(SSL *s, int md_nid, uint8_t *p); @@ -997,7 +1026,6 @@ int tls1_export_keying_material(SSL *s, uint8_t *out, size_t out_len, int use_context); int tls1_alert_code(int code); int ssl3_alert_code(int code); -int ssl_ok(SSL *s); int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s); diff --git a/src/ssl/pqueue/CMakeLists.txt b/src/ssl/pqueue/CMakeLists.txt index 9f14020..53d2a8b 100644 --- a/src/ssl/pqueue/CMakeLists.txt +++ b/src/ssl/pqueue/CMakeLists.txt @@ -12,6 +12,8 @@ add_executable( pqueue_test pqueue_test.c + + $<TARGET_OBJECTS:test_support> ) target_link_libraries(pqueue_test ssl crypto) diff --git a/src/ssl/pqueue/pqueue_test.c b/src/ssl/pqueue/pqueue_test.c index cb688f7..5a68fc4 100644 --- a/src/ssl/pqueue/pqueue_test.c +++ b/src/ssl/pqueue/pqueue_test.c @@ -72,7 +72,7 @@ static int fixed_random(void) { for (i = 0; i < NUM_ITEMS; i++) { priority[7] = ordering[i]; item = pitem_new(priority, &ordering[i]); - if (pqueue_insert(q, item) != item) { + if (item == NULL || pqueue_insert(q, item) != item) { return 0; } } @@ -82,7 +82,7 @@ static int fixed_random(void) { for (i = 0; i < NUM_ITEMS; i++) { priority[7] = ordering[i]; item = pitem_new(priority, &ordering[i]); - if (pqueue_insert(q, item) != NULL) { + if (item == NULL || pqueue_insert(q, item) != NULL) { return 0; } pitem_free(item); diff --git a/src/ssl/s3_both.c b/src/ssl/s3_both.c index b78f6d3..06338b7 100644 --- a/src/ssl/s3_both.c +++ b/src/ssl/s3_both.c @@ -195,8 +195,8 @@ int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen) { return ssl_do_write(s); } -/* ssl3_take_mac calculates the Finished MAC for the handshakes messages seen to - * far. */ +/* ssl3_take_mac calculates the Finished MAC for the handshakes messages seen + * so far. */ static void ssl3_take_mac(SSL *s) { const char *sender; int slen; @@ -357,8 +357,8 @@ long ssl3_get_message(SSL *s, int header_state, int body_state, int msg_type, for (;;) { while (s->init_num < 4) { - int bytes_read = s->method->ssl_read_bytes( - s, SSL3_RT_HANDSHAKE, &p[s->init_num], 4 - s->init_num, 0); + int bytes_read = ssl3_read_bytes(s, SSL3_RT_HANDSHAKE, &p[s->init_num], + 4 - s->init_num, 0); if (bytes_read <= 0) { *ok = 0; return bytes_read; @@ -413,8 +413,8 @@ long ssl3_get_message(SSL *s, int header_state, int body_state, int msg_type, p = s->init_msg; n = s->s3->tmp.message_size - s->init_num; while (n > 0) { - int bytes_read = - s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &p[s->init_num], n, 0); + int bytes_read = ssl3_read_bytes(s, SSL3_RT_HANDSHAKE, &p[s->init_num], n, + 0); if (bytes_read <= 0) { s->rwstate = SSL_READING; *ok = 0; @@ -667,20 +667,10 @@ int ssl3_release_read_buffer(SSL *s) { return 1; } -/* ssl_fill_hello_random fills a client_random or server_random field of length - * |len|. Returns 0 on failure or 1 on success. */ -int ssl_fill_hello_random(SSL *s, int server, uint8_t *result, size_t len) { - int send_time = 0; - - if (server) { - send_time = (s->mode & SSL_MODE_SEND_SERVERHELLO_TIME) != 0; - } else { - send_time = (s->mode & SSL_MODE_SEND_CLIENTHELLO_TIME) != 0; - } - - if (send_time) { +int ssl_fill_hello_random(uint8_t *out, size_t len, int is_server) { + if (is_server) { const uint32_t current_time = time(NULL); - uint8_t *p = result; + uint8_t *p = out; if (len < 4) { return 0; @@ -691,6 +681,6 @@ int ssl_fill_hello_random(SSL *s, int server, uint8_t *result, size_t len) { p[3] = current_time; return RAND_bytes(p + 4, len - 4); } else { - return RAND_bytes(result, len); + return RAND_bytes(out, len); } } diff --git a/src/ssl/s3_clnt.c b/src/ssl/s3_clnt.c index d01acae..159e2d7 100644 --- a/src/ssl/s3_clnt.c +++ b/src/ssl/s3_clnt.c @@ -193,25 +193,11 @@ int ssl3_connect(SSL *s) { state = s->state; switch (s->state) { - case SSL_ST_RENEGOTIATE: - s->renegotiate = 1; - s->state = SSL_ST_CONNECT; - /* fallthrough */ case SSL_ST_CONNECT: - case SSL_ST_BEFORE | SSL_ST_CONNECT: if (cb != NULL) { cb(s, SSL_CB_HANDSHAKE_START, 1); } - if ((s->version >> 8) != 3) { - /* TODO(davidben): Some consumers clear |s->version| to break the - * handshake in a callback. Remove this when they're using proper - * APIs. */ - OPENSSL_PUT_ERROR(SSL, ssl3_connect, ERR_R_INTERNAL_ERROR); - ret = -1; - goto end; - } - if (s->init_buf == NULL) { buf = BUF_MEM_new(); if (buf == NULL || @@ -457,7 +443,7 @@ int ssl3_connect(SSL *s) { ssl3_can_false_start(s) && /* No False Start on renegotiation (would complicate the state * machine). */ - s->s3->previous_server_finished_len == 0) { + !s->s3->initial_handshake_complete) { s->s3->tmp.next_state = SSL3_ST_FALSE_START; } else { /* Allow NewSessionTicket if ticket expected */ @@ -551,9 +537,8 @@ int ssl3_connect(SSL *s) { ssl_free_wbio_buffer(s); s->init_num = 0; - s->renegotiate = 0; - s->new_session = 0; s->s3->tmp.in_false_start = 0; + s->s3->initial_handshake_complete = 1; ssl_update_cache(s, SSL_SESS_CACHE_CLIENT); @@ -625,7 +610,8 @@ int ssl3_send_client_hello(SSL *s) { /* If resending the ClientHello in DTLS after a HelloVerifyRequest, don't * renegerate the client_random. The random must be reused. */ if ((!SSL_IS_DTLS(s) || !s->d1->send_cookie) && - !ssl_fill_hello_random(s, 0, p, sizeof(s->s3->client_random))) { + !ssl_fill_hello_random(p, sizeof(s->s3->client_random), + 0 /* client */)) { goto err; } @@ -666,7 +652,8 @@ int ssl3_send_client_hello(SSL *s) { p += SSL3_RANDOM_SIZE; /* Session ID */ - if (s->new_session || s->session == NULL) { + if (s->s3->initial_handshake_complete || s->session == NULL) { + /* Renegotiations do not participate in session resumption. */ i = 0; } else { i = s->session->session_id_length; @@ -778,6 +765,7 @@ int ssl3_get_server_hello(SSL *s) { goto f_err; } + assert(s->s3->have_version == s->s3->initial_handshake_complete); if (!s->s3->have_version) { if (!ssl3_is_version_enabled(s, server_version)) { OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_UNSUPPORTED_PROTOCOL); @@ -804,8 +792,9 @@ int ssl3_get_server_hello(SSL *s) { memcpy(s->s3->server_random, CBS_data(&server_random), SSL3_RANDOM_SIZE); assert(s->session == NULL || s->session->session_id_length > 0); - if (s->session != NULL && CBS_mem_equal(&session_id, s->session->session_id, - s->session->session_id_length)) { + if (!s->s3->initial_handshake_complete && s->session != NULL && + CBS_mem_equal(&session_id, s->session->session_id, + s->session->session_id_length)) { if (s->sid_ctx_length != s->session->sid_ctx_length || memcmp(s->session->sid_ctx, s->sid_ctx, s->sid_ctx_length)) { /* actually a client application bug */ @@ -827,7 +816,7 @@ int ssl3_get_server_hello(SSL *s) { memcpy(s->session->session_id, CBS_data(&session_id), CBS_len(&session_id)); } - c = ssl3_get_cipher_by_value(cipher_suite); + c = SSL_get_cipher_by_value(cipher_suite); if (c == NULL) { /* unknown cipher */ al = SSL_AD_ILLEGAL_PARAMETER; @@ -876,9 +865,10 @@ int ssl3_get_server_hello(SSL *s) { } s->s3->tmp.new_cipher = c; - /* Don't digest cached records if no sigalgs: we may need them for client - * authentication. */ - if (!SSL_USE_SIGALGS(s) && + /* If doing a full handshake with TLS 1.2, the server may request a client + * certificate which requires hashing the handshake transcript under a + * different hash. Otherwise, release the handshake buffer. */ + if ((!SSL_USE_SIGALGS(s) || s->hit) && !ssl3_digest_cached_records(s, free_handshake_buffer)) { goto f_err; } @@ -905,6 +895,19 @@ int ssl3_get_server_hello(SSL *s) { goto f_err; } + if (s->hit && + s->s3->tmp.extended_master_secret != s->session->extended_master_secret) { + al = SSL_AD_HANDSHAKE_FAILURE; + if (s->session->extended_master_secret) { + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, + SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION); + } else { + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, + SSL_R_RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION); + } + goto f_err; + } + return 1; f_err: @@ -1185,7 +1188,7 @@ int ssl3_get_server_key_exchange(SSL *s) { goto err; } - if (DH_size(dh) < 512 / 8) { + if (DH_num_bits(dh) < 1024) { OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_BAD_DH_P_LENGTH); goto err; @@ -2128,6 +2131,13 @@ int ssl3_send_client_certificate(SSL *s) { return 1; } else { s->s3->tmp.cert_req = 2; + /* There is no client certificate, so the handshake buffer may be + * released. */ + if (s->s3->handshake_buffer && + !ssl3_digest_cached_records(s, free_handshake_buffer)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + return -1; + } } } diff --git a/src/ssl/s3_lib.c b/src/ssl/s3_lib.c index 92c923e..1c28a73 100644 --- a/src/ssl/s3_lib.c +++ b/src/ssl/s3_lib.c @@ -160,327 +160,7 @@ #include "internal.h" -#define SSL3_NUM_CIPHERS (sizeof(ssl3_ciphers) / sizeof(SSL_CIPHER)) - -/* list of available SSLv3 ciphers (sorted by id) */ -const SSL_CIPHER ssl3_ciphers[] = { - /* The RSA ciphers */ - /* Cipher 04 */ - { - SSL3_TXT_RSA_RC4_128_MD5, SSL3_CK_RSA_RC4_128_MD5, SSL_kRSA, SSL_aRSA, - SSL_RC4, SSL_MD5, SSL_SSLV3, SSL_MEDIUM, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, - }, - - /* Cipher 05 */ - { - SSL3_TXT_RSA_RC4_128_SHA, SSL3_CK_RSA_RC4_128_SHA, SSL_kRSA, SSL_aRSA, - SSL_RC4, SSL_SHA1, SSL_SSLV3, SSL_MEDIUM, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, - }, - - /* Cipher 0A */ - { - SSL3_TXT_RSA_DES_192_CBC3_SHA, SSL3_CK_RSA_DES_192_CBC3_SHA, SSL_kRSA, - SSL_aRSA, SSL_3DES, SSL_SHA1, SSL_SSLV3, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 112, 168, - }, - - - /* New AES ciphersuites */ - - /* Cipher 2F */ - { - TLS1_TXT_RSA_WITH_AES_128_SHA, TLS1_CK_RSA_WITH_AES_128_SHA, SSL_kRSA, - SSL_aRSA, SSL_AES128, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, - }, - - /* Cipher 33 */ - { - TLS1_TXT_DHE_RSA_WITH_AES_128_SHA, TLS1_CK_DHE_RSA_WITH_AES_128_SHA, - SSL_kDHE, SSL_aRSA, SSL_AES128, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, - }, - - /* Cipher 35 */ - { - TLS1_TXT_RSA_WITH_AES_256_SHA, TLS1_CK_RSA_WITH_AES_256_SHA, SSL_kRSA, - SSL_aRSA, SSL_AES256, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256, - }, - - /* Cipher 39 */ - { - TLS1_TXT_DHE_RSA_WITH_AES_256_SHA, TLS1_CK_DHE_RSA_WITH_AES_256_SHA, - SSL_kDHE, SSL_aRSA, SSL_AES256, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256, - }, - - - /* TLS v1.2 ciphersuites */ - - /* Cipher 3C */ - { - TLS1_TXT_RSA_WITH_AES_128_SHA256, TLS1_CK_RSA_WITH_AES_128_SHA256, - SSL_kRSA, SSL_aRSA, SSL_AES128, SSL_SHA256, SSL_TLSV1_2, - SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 128, 128, - }, - - /* Cipher 3D */ - { - TLS1_TXT_RSA_WITH_AES_256_SHA256, TLS1_CK_RSA_WITH_AES_256_SHA256, - SSL_kRSA, SSL_aRSA, SSL_AES256, SSL_SHA256, SSL_TLSV1_2, - SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 256, 256, - }, - - /* Cipher 67 */ - { - TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256, - TLS1_CK_DHE_RSA_WITH_AES_128_SHA256, SSL_kDHE, SSL_aRSA, SSL_AES128, - SSL_SHA256, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 128, 128, - }, - - /* Cipher 6B */ - { - TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256, - TLS1_CK_DHE_RSA_WITH_AES_256_SHA256, SSL_kDHE, SSL_aRSA, SSL_AES256, - SSL_SHA256, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 256, 256, - }, - - /* Cipher 8A */ - { - TLS1_TXT_PSK_WITH_RC4_128_SHA, TLS1_CK_PSK_WITH_RC4_128_SHA, SSL_kPSK, - SSL_aPSK, SSL_RC4, SSL_SHA1, SSL_TLSV1, SSL_MEDIUM, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, - }, - - /* Cipher 8C */ - { - TLS1_TXT_PSK_WITH_AES_128_CBC_SHA, TLS1_CK_PSK_WITH_AES_128_CBC_SHA, - SSL_kPSK, SSL_aPSK, SSL_AES128, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, - }, - - /* Cipher 8D */ - { - TLS1_TXT_PSK_WITH_AES_256_CBC_SHA, TLS1_CK_PSK_WITH_AES_256_CBC_SHA, - SSL_kPSK, SSL_aPSK, SSL_AES256, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256, - }, - - - /* GCM ciphersuites from RFC5288 */ - - /* Cipher 9C */ - { - TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256, - TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, SSL_kRSA, SSL_aRSA, SSL_AES128GCM, - SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256 | SSL_CIPHER_ALGORITHM2_AEAD | - SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, - 128, 128, - }, - - /* Cipher 9D */ - { - TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384, - TLS1_CK_RSA_WITH_AES_256_GCM_SHA384, SSL_kRSA, SSL_aRSA, SSL_AES256GCM, - SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384 | SSL_CIPHER_ALGORITHM2_AEAD | - SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, - 256, 256, - }, - - /* Cipher 9E */ - { - TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256, - TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256, SSL_kDHE, SSL_aRSA, SSL_AES128GCM, - SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256 | SSL_CIPHER_ALGORITHM2_AEAD | - SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, - 128, 128, - }, - - /* Cipher 9F */ - { - TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384, - TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384, SSL_kDHE, SSL_aRSA, SSL_AES256GCM, - SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384 | SSL_CIPHER_ALGORITHM2_AEAD | - SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, - 256, 256, - }, - - /* Cipher C007 */ - { - TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA, - TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA, SSL_kECDHE, SSL_aECDSA, SSL_RC4, - SSL_SHA1, SSL_TLSV1, SSL_MEDIUM, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, - 128, - }, - - /* Cipher C009 */ - { - TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, SSL_kECDHE, SSL_aECDSA, - SSL_AES128, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, - }, - - /* Cipher C00A */ - { - TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, SSL_kECDHE, SSL_aECDSA, - SSL_AES256, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256, - }, - - /* Cipher C011 */ - { - TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA, TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA, - SSL_kECDHE, SSL_aRSA, SSL_RC4, SSL_SHA1, SSL_TLSV1, SSL_MEDIUM, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, - }, - - /* Cipher C013 */ - { - TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA, - TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA, SSL_kECDHE, SSL_aRSA, SSL_AES128, - SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128, - }, - - /* Cipher C014 */ - { - TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA, - TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA, SSL_kECDHE, SSL_aRSA, SSL_AES256, - SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256, - }, - - - /* HMAC based TLS v1.2 ciphersuites from RFC5289 */ - - /* Cipher C023 */ - { - TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_SHA256, - TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256, SSL_kECDHE, SSL_aECDSA, - SSL_AES128, SSL_SHA256, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 128, 128, - }, - - /* Cipher C024 */ - { - TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_SHA384, - TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384, SSL_kECDHE, SSL_aECDSA, - SSL_AES256, SSL_SHA384, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, 256, 256, - }, - - /* Cipher C027 */ - { - TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256, - TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256, SSL_kECDHE, SSL_aRSA, SSL_AES128, - SSL_SHA256, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 128, 128, - }, - - /* Cipher C028 */ - { - TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384, - TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384, SSL_kECDHE, SSL_aRSA, SSL_AES256, - SSL_SHA384, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, 256, 256, - }, - - - /* GCM based TLS v1.2 ciphersuites from RFC5289 */ - - /* Cipher C02B */ - { - TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, SSL_kECDHE, SSL_aECDSA, - SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256 | SSL_CIPHER_ALGORITHM2_AEAD | - SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, - 128, 128, - }, - - /* Cipher C02C */ - { - TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, SSL_kECDHE, SSL_aECDSA, - SSL_AES256GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384 | SSL_CIPHER_ALGORITHM2_AEAD | - SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, - 256, 256, - }, - - /* Cipher C02F */ - { - TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, SSL_kECDHE, SSL_aRSA, - SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256 | SSL_CIPHER_ALGORITHM2_AEAD | - SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, - 128, 128, - }, - - /* Cipher C030 */ - { - TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, SSL_kECDHE, SSL_aRSA, - SSL_AES256GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, - SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384 | SSL_CIPHER_ALGORITHM2_AEAD | - SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, - 256, 256, - }, - - - /* ECDH PSK ciphersuites */ - - /* Cipher CAFE */ -#if !defined(ANDROID) - { - TLS1_TXT_ECDHE_PSK_WITH_AES_128_GCM_SHA256, - TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256, SSL_kECDHE, SSL_aPSK, - SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH, - SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256 | SSL_CIPHER_ALGORITHM2_AEAD | - SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, - 128, 128, - }, - - { - TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305, - TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, SSL_kECDHE, SSL_aRSA, - SSL_CHACHA20POLY1305, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH, - SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256 | SSL_CIPHER_ALGORITHM2_AEAD, - 256, 0, - }, - - { - TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, - TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, SSL_kECDHE, SSL_aECDSA, - SSL_CHACHA20POLY1305, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH, - SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256 | SSL_CIPHER_ALGORITHM2_AEAD, - 256, 0, - }, - - { - TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305, - TLS1_CK_DHE_RSA_CHACHA20_POLY1305, SSL_kDHE, SSL_aRSA, - SSL_CHACHA20POLY1305, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH, - SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256 | SSL_CIPHER_ALGORITHM2_AEAD, - 256, 0, - }, -#endif -}; - const SSL3_ENC_METHOD SSLv3_enc_data = { - tls1_enc, ssl3_prf, tls1_setup_key_block, tls1_generate_master_secret, @@ -494,23 +174,8 @@ const SSL3_ENC_METHOD SSLv3_enc_data = { 0, }; -size_t ssl3_num_ciphers(void) { return SSL3_NUM_CIPHERS; } - -const SSL_CIPHER *ssl3_get_cipher(size_t i) { - if (i >= SSL3_NUM_CIPHERS) { - return NULL; - } - - return &ssl3_ciphers[SSL3_NUM_CIPHERS - 1 - i]; -} - -int ssl3_pending(const SSL *s) { - if (s->rstate == SSL_ST_READ_BODY) { - return 0; - } - - return (s->s3->rrec.type == SSL3_RT_APPLICATION_DATA) ? s->s3->rrec.length - : 0; +int ssl3_supports_cipher(const SSL_CIPHER *cipher) { + return 1; } int ssl3_set_handshake_header(SSL *s, int htype, unsigned long len) { @@ -535,7 +200,6 @@ int ssl3_new(SSL *s) { } memset(s3, 0, sizeof *s3); memset(s3->rrec.seq_num, 0, sizeof(s3->rrec.seq_num)); - memset(s3->wrec.seq_num, 0, sizeof(s3->wrec.seq_num)); s->s3 = s3; @@ -948,27 +612,6 @@ int SSL_CTX_set_tlsext_ticket_key_cb( return 1; } -/* ssl3_get_cipher_by_value returns the SSL_CIPHER with value |value| or NULL - * if none exists. - * - * This function needs to check if the ciphers required are actually - * available. */ -const SSL_CIPHER *ssl3_get_cipher_by_value(uint16_t value) { - SSL_CIPHER c; - - c.id = 0x03000000L | value; - return bsearch(&c, ssl3_ciphers, SSL3_NUM_CIPHERS, sizeof(SSL_CIPHER), - ssl_cipher_id_cmp); -} - -/* ssl3_get_cipher_by_value returns the cipher value of |c|. */ -uint16_t ssl3_get_cipher_value(const SSL_CIPHER *c) { - uint32_t id = c->id; - /* All ciphers are SSLv3 now. */ - assert((id & 0xff000000) == 0x03000000); - return id & 0xffff; -} - struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *s) { if (s->cipher_list != NULL) { return s->cipher_list; @@ -1121,106 +764,14 @@ static int ssl3_set_req_cert_type(CERT *c, const uint8_t *p, size_t len) { return 1; } -int ssl3_shutdown(SSL *s) { - int ret; - - /* Do nothing if configured not to send a close_notify. */ - if (s->quiet_shutdown) { - s->shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN; - return 1; - } - - if (!(s->shutdown & SSL_SENT_SHUTDOWN)) { - s->shutdown |= SSL_SENT_SHUTDOWN; - ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_CLOSE_NOTIFY); - - /* our shutdown alert has been sent now, and if it still needs to be - * written, s->s3->alert_dispatch will be true */ - if (s->s3->alert_dispatch) { - return -1; /* return WANT_WRITE */ - } - } else if (s->s3->alert_dispatch) { - /* resend it if not sent */ - ret = s->method->ssl_dispatch_alert(s); - if (ret == -1) { - /* we only get to return -1 here the 2nd/Nth invocation, we must have - * already signalled return 0 upon a previous invoation, return - * WANT_WRITE */ - return ret; - } - } else if (!(s->shutdown & SSL_RECEIVED_SHUTDOWN)) { - /* If we are waiting for a close from our peer, we are closed */ - s->method->ssl_read_bytes(s, 0, NULL, 0, 0); - if (!(s->shutdown & SSL_RECEIVED_SHUTDOWN)) { - return -1; /* return WANT_READ */ - } - } - - if (s->shutdown == (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN) && - !s->s3->alert_dispatch) { - return 1; - } else { - return 0; - } -} - -int ssl3_write(SSL *s, const void *buf, int len) { - ERR_clear_system_error(); - if (s->s3->renegotiate) { - ssl3_renegotiate_check(s); - } - - return s->method->ssl_write_bytes(s, SSL3_RT_APPLICATION_DATA, buf, len); -} - -static int ssl3_read_internal(SSL *s, void *buf, int len, int peek) { - ERR_clear_system_error(); - if (s->s3->renegotiate) { - ssl3_renegotiate_check(s); - } - - return s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, buf, len, peek); -} - -int ssl3_read(SSL *s, void *buf, int len) { - return ssl3_read_internal(s, buf, len, 0); -} - -int ssl3_peek(SSL *s, void *buf, int len) { - return ssl3_read_internal(s, buf, len, 1); -} - -int ssl3_renegotiate(SSL *s) { - if (s->handshake_func == NULL) { - return 1; - } - - s->s3->renegotiate = 1; - return 1; -} - -int ssl3_renegotiate_check(SSL *s) { - if (s->s3->renegotiate && s->s3->rbuf.left == 0 && s->s3->wbuf.left == 0 && - !SSL_in_init(s)) { - /* if we are the server, and we have sent a 'RENEGOTIATE' message, we - * need to go to SSL_ST_ACCEPT. */ - s->state = SSL_ST_RENEGOTIATE; - s->s3->renegotiate = 0; - s->s3->total_renegotiations++; - return 1; - } - - return 0; -} - /* If we are using default SHA1+MD5 algorithms switch to new SHA256 PRF and * handshake macs if required. */ uint32_t ssl_get_algorithm2(SSL *s) { - static const uint32_t kMask = SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF; + static const uint32_t kMask = SSL_HANDSHAKE_MAC_DEFAULT; uint32_t alg2 = s->s3->tmp.new_cipher->algorithm2; if (s->enc_method->enc_flags & SSL_ENC_FLAG_SHA256_PRF && (alg2 & kMask) == kMask) { - return SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256; + return SSL_HANDSHAKE_MAC_SHA256; } return alg2; } diff --git a/src/ssl/s3_meth.c b/src/ssl/s3_meth.c index 28b9051..66bbb29 100644 --- a/src/ssl/s3_meth.c +++ b/src/ssl/s3_meth.c @@ -63,21 +63,14 @@ static const SSL_PROTOCOL_METHOD TLS_protocol_method = { ssl3_free, ssl3_accept, ssl3_connect, - ssl3_read, - ssl3_peek, - ssl3_write, - ssl3_shutdown, - ssl3_renegotiate, - ssl3_renegotiate_check, ssl3_get_message, - ssl3_read_bytes, - ssl3_write_bytes, + ssl3_read_app_data, + ssl3_read_close_notify, + ssl3_write_app_data, ssl3_dispatch_alert, ssl3_ctrl, ssl3_ctx_ctrl, - ssl3_pending, - ssl3_num_ciphers, - ssl3_get_cipher, + ssl3_supports_cipher, SSL3_HM_HEADER_LENGTH, ssl3_set_handshake_header, ssl3_handshake_write, diff --git a/src/ssl/s3_pkt.c b/src/ssl/s3_pkt.c index c42d000..4a9ae83 100644 --- a/src/ssl/s3_pkt.c +++ b/src/ssl/s3_pkt.c @@ -129,9 +129,13 @@ int ssl3_read_n(SSL *s, int n, int extend) { * if |extend| is 1, increase packet by another n bytes. * * The packet will be in the sub-array of |s->s3->rbuf.buf| specified by - * |s->packet| and |s->packet_length|. (If |s->read_ahead| is set and |extend| - * is 0, additional bytes may be read into |rbuf|, up to the size of the - * buffer.) */ + * |s->packet| and |s->packet_length|. (If DTLS and |extend| is 0, additional + * bytes will be read into |rbuf|, up to the size of the buffer.) + * + * TODO(davidben): |dtls1_get_record| and |ssl3_get_record| have very + * different needs. Separate the two record layers. In DTLS, |BIO_read| is + * called at most once, and only when |extend| is 0. In TLS, the buffer never + * contains more than one record. */ int i, len, left; uintptr_t align = 0; uint8_t *pkt; @@ -173,10 +177,10 @@ int ssl3_read_n(SSL *s, int n, int extend) { /* ... now we can act as if 'extend' was set */ } - /* For DTLS/UDP reads should not span multiple packets because the read - * operation returns the whole packet at once (as long as it fits into the - * buffer). */ - if (SSL_IS_DTLS(s) && left > 0 && n > left) { + /* In DTLS, if there is leftover data from the previous packet or |extend| is + * true, clamp to the previous read. DTLS records may not span packet + * boundaries. */ + if (SSL_IS_DTLS(s) && n > left && (left > 0 || extend)) { n = left; } @@ -207,7 +211,7 @@ int ssl3_read_n(SSL *s, int n, int extend) { } int max = n; - if (s->read_ahead && !extend) { + if (SSL_IS_DTLS(s) && !extend) { max = rb->len - rb->offset; } @@ -262,16 +266,14 @@ int ssl3_read_n(SSL *s, int n, int extend) { * ssl->s3->rrec.length - number of bytes */ /* used only by ssl3_read_bytes */ static int ssl3_get_record(SSL *s) { - int ssl_major, ssl_minor, al; - int n, i, ret = -1; - SSL3_RECORD *rr; + uint8_t ssl_major, ssl_minor; + int al, n, i, ret = -1; + SSL3_RECORD *rr = &s->s3->rrec; uint8_t *p; - short version; + uint16_t version; size_t extra; unsigned empty_record_count = 0; - rr = &s->s3->rrec; - again: /* check if we have the header */ if (s->rstate != SSL_ST_READ_BODY || @@ -296,7 +298,7 @@ again: rr->type = *(p++); ssl_major = *(p++); ssl_minor = *(p++); - version = (ssl_major << 8) | ssl_minor; + version = (((uint16_t)ssl_major) << 8) | ssl_minor; n2s(p, rr->length); if (s->s3->have_version && version != s->version) { @@ -339,40 +341,40 @@ again: s->rstate = SSL_ST_READ_HEADER; /* set state for later operations */ - /* At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length, and - * we have that many bytes in s->packet. */ - rr->input = &s->packet[SSL3_RT_HEADER_LENGTH]; - - /* ok, we can now read from |s->packet| data into |rr|. |rr->input| points at - * |rr->length| bytes, which need to be copied into |rr->data| by decryption. - * When the data is 'copied' into the |rr->data| buffer, |rr->input| will be - * pointed at the new buffer. */ + /* |rr->data| points to |rr->length| bytes of ciphertext in |s->packet|. */ + rr->data = &s->packet[SSL3_RT_HEADER_LENGTH]; - /* We now have - encrypted [ MAC [ compressed [ plain ] ] ] - * rr->length bytes of encrypted compressed stuff. */ - - /* decrypt in place in 'rr->input' */ - rr->data = rr->input; - - if (!s->enc_method->enc(s, 0)) { + /* Decrypt the packet in-place. + * + * TODO(davidben): This assumes |s->version| is the same as the record-layer + * version which isn't always true, but it only differs with the NULL cipher + * which ignores the parameter. */ + size_t plaintext_len; + if (!SSL_AEAD_CTX_open(s->aead_read_ctx, rr->data, &plaintext_len, rr->length, + rr->type, s->version, s->s3->read_sequence, rr->data, + rr->length)) { al = SSL_AD_BAD_RECORD_MAC; OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); goto f_err; } - - if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH + extra) { + if (!ssl3_record_sequence_update(s->s3->read_sequence, 8)) { + goto err; + } + if (plaintext_len > SSL3_RT_MAX_PLAIN_LENGTH + extra) { al = SSL_AD_RECORD_OVERFLOW; OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_DATA_LENGTH_TOO_LONG); goto f_err; } + assert(plaintext_len <= (1u << 16)); + rr->length = plaintext_len; rr->off = 0; /* So at this point the following is true: * ssl->s3->rrec.type is the type of record; * ssl->s3->rrec.length is the number of bytes in the record; * ssl->s3->rrec.off is the offset to first valid byte; - * ssl->s3->rrec.data is where to take bytes from (increment after use). */ + * ssl->s3->rrec.data the first byte of the record body. */ /* we have pulled in a full packet so zero things */ s->packet_length = 0; @@ -396,6 +398,10 @@ err: return ret; } +int ssl3_write_app_data(SSL *ssl, const void *buf, int len) { + return ssl3_write_bytes(ssl, SSL3_RT_APPLICATION_DATA, buf, len); +} + /* 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 ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) { @@ -471,8 +477,8 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) { /* ssl3_seal_record seals a new record of type |type| and plaintext |in| and * writes it to |out|. At most |max_out| bytes will be written. It returns one - * on success and zero on error. On success, |s->s3->wrec| is updated to include - * the new record. */ + * on success and zero on error. On success, it updates the write sequence + * number. */ static int ssl3_seal_record(SSL *s, uint8_t *out, size_t *out_len, size_t max_out, uint8_t type, const uint8_t *in, size_t in_len) { @@ -485,61 +491,30 @@ static int ssl3_seal_record(SSL *s, uint8_t *out, size_t *out_len, /* Some servers hang if initial ClientHello is larger than 256 bytes and * record version number > TLS 1.0. */ + uint16_t wire_version = s->version; if (!s->s3->have_version && s->version > SSL3_VERSION) { - out[1] = TLS1_VERSION >> 8; - out[2] = TLS1_VERSION & 0xff; - } else { - out[1] = s->version >> 8; - out[2] = s->version & 0xff; + wire_version = TLS1_VERSION; } + out[1] = wire_version >> 8; + out[2] = wire_version & 0xff; - size_t explicit_nonce_len = 0; - if (s->aead_write_ctx != NULL && - s->aead_write_ctx->variable_nonce_included_in_record) { - explicit_nonce_len = s->aead_write_ctx->variable_nonce_len; - } - size_t max_overhead = 0; - if (s->aead_write_ctx != NULL) { - max_overhead = s->aead_write_ctx->tag_len; - } - - /* Assemble the input for |s->enc_method->enc|. The input is the plaintext - * with |explicit_nonce_len| bytes of space prepended for the explicit - * nonce. The input is copied into |out| and then encrypted in-place to take - * advantage of alignment. - * - * TODO(davidben): |tls1_enc| should accept its inputs and outputs directly - * rather than looking up in |wrec| and friends. The |max_overhead| bounds - * check would also be unnecessary if |max_out| were passed down. */ - SSL3_RECORD *wr = &s->s3->wrec; - size_t plaintext_len = in_len + explicit_nonce_len; - if (plaintext_len < in_len || plaintext_len > INT_MAX || - plaintext_len + max_overhead < plaintext_len) { - OPENSSL_PUT_ERROR(SSL, ssl3_seal_record, ERR_R_OVERFLOW); - return 0; - } - if (max_out - SSL3_RT_HEADER_LENGTH < plaintext_len + max_overhead) { - OPENSSL_PUT_ERROR(SSL, ssl3_seal_record, SSL_R_BUFFER_TOO_SMALL); - return 0; - } - wr->type = type; - wr->input = out + SSL3_RT_HEADER_LENGTH; - wr->data = wr->input; - wr->length = plaintext_len; - memcpy(wr->input + explicit_nonce_len, in, in_len); - - if (!s->enc_method->enc(s, 1)) { + size_t ciphertext_len; + if (!SSL_AEAD_CTX_seal(s->aead_write_ctx, out + SSL3_RT_HEADER_LENGTH, + &ciphertext_len, max_out - SSL3_RT_HEADER_LENGTH, + type, wire_version, s->s3->write_sequence, in, + in_len) || + !ssl3_record_sequence_update(s->s3->write_sequence, 8)) { return 0; } - /* |wr->length| has now been set to the ciphertext length. */ - if (wr->length >= 1 << 16) { + if (ciphertext_len >= 1 << 16) { OPENSSL_PUT_ERROR(SSL, ssl3_seal_record, ERR_R_OVERFLOW); return 0; } - out[3] = wr->length >> 8; - out[4] = wr->length & 0xff; - *out_len = SSL3_RT_HEADER_LENGTH + (size_t)wr->length; + out[3] = ciphertext_len >> 8; + out[4] = ciphertext_len & 0xff; + + *out_len = SSL3_RT_HEADER_LENGTH + ciphertext_len; if (s->msg_callback) { s->msg_callback(1 /* write */, 0, SSL3_RT_HEADER, out, SSL3_RT_HEADER_LENGTH, @@ -696,6 +671,14 @@ int ssl3_expect_change_cipher_spec(SSL *s) { return 1; } +int ssl3_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek) { + return ssl3_read_bytes(ssl, SSL3_RT_APPLICATION_DATA, buf, len, peek); +} + +void ssl3_read_close_notify(SSL *ssl) { + ssl3_read_bytes(ssl, 0, NULL, 0, 0); +} + /* Return up to 'len' payload bytes received in 'type' records. * 'type' is one of the following: * @@ -859,22 +842,18 @@ start: return n; } - - /* If we get here, then type != rr->type; if we have a handshake message, - * then it was unexpected (Hello Request or Client Hello). */ - - /* In case of record types for which we have 'fragment' storage, fill that so - * that we can process the data at a fixed place. */ + /* Process unexpected records. */ if (rr->type == SSL3_RT_HANDSHAKE) { /* If peer renegotiations are disabled, all out-of-order handshake records - * are fatal. */ - if (s->reject_peer_renegotiations) { + * are fatal. Renegotiations as a server are never supported. */ + if (!s->accept_peer_renegotiations || s->server) { al = SSL_AD_NO_RENEGOTIATION; OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_NO_RENEGOTIATION); goto f_err; } + /* HelloRequests may be fragmented across multiple records. */ const size_t size = sizeof(s->s3->handshake_fragment); const size_t avail = size - s->s3->handshake_fragment_len; const size_t todo = (rr->length < avail) ? rr->length : avail; @@ -886,45 +865,53 @@ start: if (s->s3->handshake_fragment_len < size) { goto start; /* fragment was too small */ } - } - /* s->s3->handshake_fragment_len == 4 iff rr->type == SSL3_RT_HANDSHAKE; - * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */ - - /* If we are a client, check for an incoming 'Hello Request': */ - if (!s->server && s->s3->handshake_fragment_len >= 4 && - s->s3->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST && - s->session != NULL && s->session->cipher != NULL) { - s->s3->handshake_fragment_len = 0; - - if (s->s3->handshake_fragment[1] != 0 || + /* Parse out and consume a HelloRequest. */ + if (s->s3->handshake_fragment[0] != SSL3_MT_HELLO_REQUEST || + s->s3->handshake_fragment[1] != 0 || s->s3->handshake_fragment[2] != 0 || s->s3->handshake_fragment[3] != 0) { al = SSL_AD_DECODE_ERROR; OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_BAD_HELLO_REQUEST); goto f_err; } + s->s3->handshake_fragment_len = 0; if (s->msg_callback) { s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->s3->handshake_fragment, 4, s, s->msg_callback_arg); } - if (SSL_is_init_finished(s) && !s->s3->renegotiate) { - ssl3_renegotiate(s); - if (ssl3_renegotiate_check(s)) { - i = s->handshake_func(s); - if (i < 0) { - return i; - } - if (i == 0) { - OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE); - return -1; - } - } + if (!SSL_is_init_finished(s) || !s->s3->initial_handshake_complete) { + /* This cannot happen. If a handshake is in progress, |type| must be + * |SSL3_RT_HANDSHAKE|. */ + assert(0); + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, ERR_R_INTERNAL_ERROR); + goto err; + } + + /* Renegotiation is only supported at quiescent points in the application + * protocol, namely in HTTPS, just before reading the HTTP response. Require + * the record-layer be idle and avoid complexities of sending a handshake + * record while an application_data record is being written. */ + if (s->s3->wbuf.left != 0 || s->s3->rbuf.left != 0) { + al = SSL_AD_NO_RENEGOTIATION; + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_NO_RENEGOTIATION); + goto f_err; + } + + /* Begin a new handshake. */ + s->state = SSL_ST_CONNECT; + i = s->handshake_func(s); + if (i < 0) { + return i; + } + if (i == 0) { + OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE); + return -1; } - /* we either finished a handshake or ignored the request, now try again to - * obtain the (application) data we were asked for */ + + /* The handshake completed synchronously. Continue reading records. */ goto start; } @@ -1043,25 +1030,6 @@ start: } } - /* Unexpected handshake message (Client Hello, or protocol violation) */ - if (s->s3->handshake_fragment_len >= 4 && !s->in_handshake) { - if ((s->state & SSL_ST_MASK) == SSL_ST_OK) { - s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT; - s->renegotiate = 1; - s->new_session = 1; - } - i = s->handshake_func(s); - if (i < 0) { - return i; - } - if (i == 0) { - OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE); - return -1; - } - - goto start; - } - /* We already handled these. */ assert(rr->type != SSL3_RT_CHANGE_CIPHER_SPEC && rr->type != SSL3_RT_ALERT && rr->type != SSL3_RT_HANDSHAKE); diff --git a/src/ssl/s3_srvr.c b/src/ssl/s3_srvr.c index 3cc3032..a72e17e 100644 --- a/src/ssl/s3_srvr.c +++ b/src/ssl/s3_srvr.c @@ -207,79 +207,11 @@ int ssl3_accept(SSL *s) { state = s->state; switch (s->state) { - case SSL_ST_RENEGOTIATE: - /* This state is the renegotiate entry point. It sends a HelloRequest - * and nothing else. */ - s->renegotiate = 1; - - if (cb != NULL) { - cb(s, SSL_CB_HANDSHAKE_START, 1); - } - - if (s->init_buf == NULL) { - buf = BUF_MEM_new(); - if (!buf || !BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { - ret = -1; - goto end; - } - s->init_buf = buf; - buf = NULL; - } - s->init_num = 0; - - if (!s->s3->send_connection_binding && - !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) { - /* Server attempting to renegotiate with client that doesn't support - * secure renegotiation. */ - OPENSSL_PUT_ERROR(SSL, ssl3_accept, - SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); - ret = -1; - goto end; - } - - s->state = SSL3_ST_SW_HELLO_REQ_A; - break; - - case SSL3_ST_SW_HELLO_REQ_A: - case SSL3_ST_SW_HELLO_REQ_B: - s->shutdown = 0; - ret = ssl3_send_hello_request(s); - if (ret <= 0) { - goto end; - } - s->s3->tmp.next_state = SSL3_ST_SW_HELLO_REQ_C; - s->state = SSL3_ST_SW_FLUSH; - s->init_num = 0; - - if (!ssl3_init_finished_mac(s)) { - OPENSSL_PUT_ERROR(SSL, ssl3_accept, ERR_R_INTERNAL_ERROR); - ret = -1; - goto end; - } - break; - - case SSL3_ST_SW_HELLO_REQ_C: - s->state = SSL_ST_OK; - break; - case SSL_ST_ACCEPT: - case SSL_ST_BEFORE | SSL_ST_ACCEPT: - /* This state is the entry point for the handshake itself (initial and - * renegotiation). */ if (cb != NULL) { cb(s, SSL_CB_HANDSHAKE_START, 1); } - if ((s->version >> 8) != 3) { - /* TODO(davidben): Some consumers clear |s->version| to break the - * handshake in a callback. Remove this when they're using proper - * APIs. */ - OPENSSL_PUT_ERROR(SSL, ssl3_accept, ERR_R_INTERNAL_ERROR); - ret = -1; - goto end; - } - if (s->init_buf == NULL) { buf = BUF_MEM_new(); if (!buf || !BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { @@ -337,7 +269,6 @@ int ssl3_accept(SSL *s) { if (ret <= 0) { goto end; } - s->renegotiate = 2; s->state = SSL3_ST_SW_SRVR_HELLO_A; s->init_num = 0; break; @@ -406,35 +337,16 @@ int ssl3_accept(SSL *s) { case SSL3_ST_SW_CERT_REQ_A: case SSL3_ST_SW_CERT_REQ_B: - if (/* don't request cert unless asked for it: */ - !(s->verify_mode & SSL_VERIFY_PEER) || - /* Don't request a certificate if an obc was presented */ - ((s->verify_mode & SSL_VERIFY_PEER_IF_NO_OBC) && - s->s3->tlsext_channel_id_valid) || - /* if SSL_VERIFY_CLIENT_ONCE is set, - * don't request cert during re-negotiation: */ - ((s->session->peer != NULL) && - (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) || - /* With normal PSK Certificates and - * Certificate Requests are omitted */ - (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { - /* no cert request */ - skip = 1; - s->s3->tmp.cert_request = 0; - s->state = SSL3_ST_SW_SRVR_DONE_A; - if (s->s3->handshake_buffer && - !ssl3_digest_cached_records(s, free_handshake_buffer)) { - return -1; - } - } else { - s->s3->tmp.cert_request = 1; + if (s->s3->tmp.cert_request) { ret = ssl3_send_certificate_request(s); if (ret <= 0) { goto end; } - s->state = SSL3_ST_SW_SRVR_DONE_A; - s->init_num = 0; + } else { + skip = 1; } + s->state = SSL3_ST_SW_SRVR_DONE_A; + s->init_num = 0; break; case SSL3_ST_SW_SRVR_DONE_A: @@ -640,16 +552,12 @@ int ssl3_accept(SSL *s) { s->session->peer = NULL; } - if (s->renegotiate == 2) { - /* skipped if we just sent a HelloRequest */ - s->renegotiate = 0; - s->new_session = 0; + s->s3->initial_handshake_complete = 1; - ssl_update_cache(s, SSL_SESS_CACHE_SERVER); + ssl_update_cache(s, SSL_SESS_CACHE_SERVER); - if (cb != NULL) { - cb(s, SSL_CB_HANDSHAKE_DONE, 1); - } + if (cb != NULL) { + cb(s, SSL_CB_HANDSHAKE_DONE, 1); } ret = 1; @@ -898,20 +806,8 @@ int ssl3_get_v2_client_hello(SSL *s) { return 1; } -int ssl3_send_hello_request(SSL *s) { - if (s->state == SSL3_ST_SW_HELLO_REQ_A) { - if (!ssl_set_handshake_header(s, SSL3_MT_HELLO_REQUEST, 0)) { - return -1; - } - s->state = SSL3_ST_SW_HELLO_REQ_B; - } - - /* SSL3_ST_SW_HELLO_REQ_B */ - return ssl_do_write(s); -} - int ssl3_get_client_hello(SSL *s) { - int i, ok, al = SSL_AD_INTERNAL_ERROR, ret = -1; + int ok, al = SSL_AD_INTERNAL_ERROR, ret = -1; long n; const SSL_CIPHER *c; STACK_OF(SSL_CIPHER) *ciphers = NULL; @@ -1011,6 +907,11 @@ int ssl3_get_client_hello(SSL *s) { } } + /* Note: This codepath may run twice if |ssl_get_prev_session| completes + * asynchronously. + * + * TODO(davidben): Clean up the order of events around ClientHello + * processing. */ if (!s->s3->have_version) { /* Select version to use */ uint16_t version = ssl3_get_mutual_version(s, client_version); @@ -1034,41 +935,49 @@ int ssl3_get_client_hello(SSL *s) { } s->hit = 0; - /* Versions before 0.9.7 always allow clients to resume sessions in - * renegotiation. 0.9.7 and later allow this by default, but optionally - * ignore resumption requests with flag - * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (it's a new flag rather than - * a change to default behavior so that applications relying on this for - * security won't even compile against older library versions). - * - * 1.0.1 and later also have a function SSL_renegotiate_abbreviated() to - * request renegotiation but not a new session (s->new_session remains - * unset): for servers, this essentially just means that the - * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION setting will be ignored. */ - if (s->new_session && - (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)) { - if (!ssl_get_new_session(s, 1)) { - goto err; - } - } else { - i = ssl_get_prev_session(s, &early_ctx); - if (i == PENDING_SESSION) { - s->rwstate = SSL_PENDING_SESSION; - goto err; - } else if (i == -1) { - goto err; - } + int session_ret = ssl_get_prev_session(s, &early_ctx); + if (session_ret == PENDING_SESSION) { + s->rwstate = SSL_PENDING_SESSION; + goto err; + } else if (session_ret == -1) { + goto err; + } - /* Only resume if the session's version matches the negotiated version: - * most clients do not accept a mismatch. */ - if (i == 1 && s->version == s->session->ssl_version) { - s->hit = 1; - } else { - /* No session was found or it was unacceptable. */ - if (!ssl_get_new_session(s, 1)) { - goto err; - } + /* The EMS state is needed when making the resumption decision, but + * extensions are not normally parsed until later. This detects the EMS + * extension for the resumption decision and it's checked against the result + * of the normal parse later in this function. */ + const uint8_t *ems_data; + size_t ems_len; + int have_extended_master_secret = + s->version != SSL3_VERSION && + SSL_early_callback_ctx_extension_get(&early_ctx, + TLSEXT_TYPE_extended_master_secret, + &ems_data, &ems_len) && + ems_len == 0; + + if (session_ret == 1) { + if (s->session->extended_master_secret && + !have_extended_master_secret) { + /* A ClientHello without EMS that attempts to resume a session with EMS + * is fatal to the connection. */ + al = SSL_AD_HANDSHAKE_FAILURE; + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, + SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION); + goto f_err; } + + s->hit = + /* Only resume if the session's version matches the negotiated version: + * most clients do not accept a mismatch. */ + s->version == s->session->ssl_version && + /* If the client offers the EMS extension, but the previous session + * didn't use it, then negotiate a new session. */ + have_extended_master_secret == s->session->extended_master_secret; + } + + if (!s->hit && !ssl_get_new_session(s, 1)) { + goto err; } if (s->ctx->dos_protection_cb != NULL && s->ctx->dos_protection_cb(&early_ctx) == 0) { @@ -1141,6 +1050,12 @@ int ssl3_get_client_hello(SSL *s) { goto f_err; } + if (have_extended_master_secret != s->s3->tmp.extended_master_secret) { + al = SSL_AD_INTERNAL_ERROR; + OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_EMS_STATE_INCONSISTENT); + goto f_err; + } + /* Given ciphers and SSL_get_ciphers, we must pick a cipher */ if (!s->hit) { if (ciphers == NULL) { @@ -1171,12 +1086,27 @@ int ssl3_get_client_hello(SSL *s) { goto f_err; } s->s3->tmp.new_cipher = c; + + /* Determine whether to request a client certificate. */ + s->s3->tmp.cert_request = !!(s->verify_mode & SSL_VERIFY_PEER); + /* Only request a certificate if Channel ID isn't negotiated. */ + if ((s->verify_mode & SSL_VERIFY_PEER_IF_NO_OBC) && + s->s3->tlsext_channel_id_valid) { + s->s3->tmp.cert_request = 0; + } + /* Plain PSK forbids Certificate and CertificateRequest. */ + if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK) { + s->s3->tmp.cert_request = 0; + } } else { /* Session-id reuse */ s->s3->tmp.new_cipher = s->session->cipher; + s->s3->tmp.cert_request = 0; } - if ((!SSL_USE_SIGALGS(s) || !(s->verify_mode & SSL_VERIFY_PEER)) && + /* In TLS 1.2, client authentication requires hashing the handshake transcript + * under a different hash. Otherwise, release the handshake buffer. */ + if ((!SSL_USE_SIGALGS(s) || !s->s3->tmp.cert_request) && !ssl3_digest_cached_records(s, free_handshake_buffer)) { goto f_err; } @@ -1235,7 +1165,8 @@ int ssl3_send_server_hello(SSL *s) { *(p++) = s->version & 0xff; /* Random stuff */ - if (!ssl_fill_hello_random(s, 1, s->s3->server_random, SSL3_RANDOM_SIZE)) { + if (!ssl_fill_hello_random(s->s3->server_random, SSL3_RANDOM_SIZE, + 1 /* server */)) { OPENSSL_PUT_ERROR(SSL, ssl3_send_server_hello, ERR_R_INTERNAL_ERROR); return -1; } @@ -1268,7 +1199,7 @@ int ssl3_send_server_hello(SSL *s) { p += sl; /* put the cipher */ - s2n(ssl3_get_cipher_value(s->s3->tmp.new_cipher), p); + s2n(ssl_cipher_get_value(s->s3->tmp.new_cipher), p); /* put the compression method */ *(p++) = 0; diff --git a/src/ssl/ssl_aead_ctx.c b/src/ssl/ssl_aead_ctx.c new file mode 100644 index 0000000..c2fba1d --- /dev/null +++ b/src/ssl/ssl_aead_ctx.c @@ -0,0 +1,257 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include <assert.h> +#include <string.h> + +#include <openssl/aead.h> +#include <openssl/err.h> +#include <openssl/rand.h> +#include <openssl/type_check.h> + +#include "internal.h" + + +OPENSSL_COMPILE_ASSERT(EVP_AEAD_MAX_NONCE_LENGTH < 256, + variable_nonce_len_doesnt_fit_in_uint8_t); + +SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction, + uint16_t version, const SSL_CIPHER *cipher, + const uint8_t *enc_key, size_t enc_key_len, + const uint8_t *mac_key, size_t mac_key_len, + const uint8_t *fixed_iv, size_t fixed_iv_len) { + const EVP_AEAD *aead; + size_t discard; + if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard, cipher, version)) { + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_new, ERR_R_INTERNAL_ERROR); + return 0; + } + + uint8_t merged_key[EVP_AEAD_MAX_KEY_LENGTH]; + if (mac_key_len > 0) { + /* This is a "stateful" AEAD (for compatibility with pre-AEAD cipher + * suites). */ + if (mac_key_len + enc_key_len + fixed_iv_len > sizeof(merged_key)) { + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_new, ERR_R_INTERNAL_ERROR); + return 0; + } + memcpy(merged_key, mac_key, mac_key_len); + memcpy(merged_key + mac_key_len, enc_key, enc_key_len); + memcpy(merged_key + mac_key_len + enc_key_len, fixed_iv, fixed_iv_len); + enc_key = merged_key; + enc_key_len += mac_key_len; + enc_key_len += fixed_iv_len; + } + + SSL_AEAD_CTX *aead_ctx = (SSL_AEAD_CTX *)OPENSSL_malloc(sizeof(SSL_AEAD_CTX)); + if (aead_ctx == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_new, ERR_R_MALLOC_FAILURE); + return NULL; + } + memset(aead_ctx, 0, sizeof(SSL_AEAD_CTX)); + aead_ctx->cipher = cipher; + + if (!EVP_AEAD_CTX_init_with_direction( + &aead_ctx->ctx, aead, enc_key, enc_key_len, + EVP_AEAD_DEFAULT_TAG_LENGTH, direction)) { + OPENSSL_free(aead_ctx); + return NULL; + } + + assert(EVP_AEAD_nonce_length(aead) <= EVP_AEAD_MAX_NONCE_LENGTH); + aead_ctx->variable_nonce_len = (uint8_t)EVP_AEAD_nonce_length(aead); + if (mac_key_len == 0) { + /* For a real AEAD, the IV is the fixed part of the nonce. */ + if (fixed_iv_len > sizeof(aead_ctx->fixed_nonce) || + fixed_iv_len > aead_ctx->variable_nonce_len) { + SSL_AEAD_CTX_free(aead_ctx); + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_new, ERR_R_INTERNAL_ERROR); + return 0; + } + aead_ctx->variable_nonce_len -= fixed_iv_len; + + memcpy(aead_ctx->fixed_nonce, fixed_iv, fixed_iv_len); + aead_ctx->fixed_nonce_len = fixed_iv_len; + aead_ctx->variable_nonce_included_in_record = + (cipher->algorithm2 & + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD) != 0; + } else { + aead_ctx->variable_nonce_included_in_record = 1; + aead_ctx->random_variable_nonce = 1; + aead_ctx->omit_length_in_ad = 1; + aead_ctx->omit_version_in_ad = (version == SSL3_VERSION); + } + + return aead_ctx; +} + +void SSL_AEAD_CTX_free(SSL_AEAD_CTX *aead) { + if (aead == NULL) { + return; + } + EVP_AEAD_CTX_cleanup(&aead->ctx); + OPENSSL_free(aead); +} + +size_t SSL_AEAD_CTX_explicit_nonce_len(SSL_AEAD_CTX *aead) { + if (aead != NULL && aead->variable_nonce_included_in_record) { + return aead->variable_nonce_len; + } + return 0; +} + +size_t SSL_AEAD_CTX_max_overhead(SSL_AEAD_CTX *aead) { + if (aead == NULL) { + return 0; + } + return EVP_AEAD_max_overhead(aead->ctx.aead) + + SSL_AEAD_CTX_explicit_nonce_len(aead); +} + +/* ssl_aead_ctx_get_ad writes the additional data for |aead| into |out| and + * returns the number of bytes written. */ +static size_t ssl_aead_ctx_get_ad(SSL_AEAD_CTX *aead, uint8_t out[13], + uint8_t type, uint16_t wire_version, + const uint8_t seqnum[8], + size_t plaintext_len) { + memcpy(out, seqnum, 8); + size_t len = 8; + out[len++] = type; + if (!aead->omit_version_in_ad) { + out[len++] = (uint8_t)(wire_version >> 8); + out[len++] = (uint8_t)wire_version; + } + if (!aead->omit_length_in_ad) { + out[len++] = (uint8_t)(plaintext_len >> 8); + out[len++] = (uint8_t)plaintext_len; + } + return len; +} + +int SSL_AEAD_CTX_open(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len, + 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 (aead == NULL) { + /* Handle the initial NULL cipher. */ + if (in_len > max_out) { + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_open, SSL_R_BUFFER_TOO_SMALL); + return 0; + } + memmove(out, in, in_len); + *out_len = in_len; + return 1; + } + + /* TLS 1.2 AEADs include the length in the AD and are assumed to have fixed + * overhead. Otherwise the parameter is unused. */ + size_t plaintext_len = 0; + if (!aead->omit_length_in_ad) { + size_t overhead = SSL_AEAD_CTX_max_overhead(aead); + if (in_len < overhead) { + /* Publicly invalid. */ + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_open, SSL_R_BAD_PACKET_LENGTH); + return 0; + } + plaintext_len = in_len - overhead; + } + uint8_t ad[13]; + size_t ad_len = ssl_aead_ctx_get_ad(aead, ad, type, wire_version, seqnum, + plaintext_len); + + /* Assemble the nonce. */ + uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH]; + size_t nonce_len = 0; + memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len); + nonce_len += aead->fixed_nonce_len; + if (aead->variable_nonce_included_in_record) { + if (in_len < aead->variable_nonce_len) { + /* Publicly invalid. */ + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_open, SSL_R_BAD_PACKET_LENGTH); + return 0; + } + memcpy(nonce + nonce_len, in, aead->variable_nonce_len); + in += aead->variable_nonce_len; + in_len -= aead->variable_nonce_len; + } else { + assert(aead->variable_nonce_len == 8); + memcpy(nonce + nonce_len, seqnum, aead->variable_nonce_len); + } + nonce_len += aead->variable_nonce_len; + + return EVP_AEAD_CTX_open(&aead->ctx, out, out_len, max_out, nonce, nonce_len, + in, in_len, ad, ad_len); +} + +int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len, + 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 (aead == NULL) { + /* Handle the initial NULL cipher. */ + if (in_len > max_out) { + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_seal, SSL_R_BUFFER_TOO_SMALL); + return 0; + } + memmove(out, in, in_len); + *out_len = in_len; + return 1; + } + + uint8_t ad[13]; + size_t ad_len = ssl_aead_ctx_get_ad(aead, ad, type, wire_version, seqnum, + in_len); + + /* Assemble the nonce. */ + uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH]; + size_t nonce_len = 0; + memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len); + nonce_len += aead->fixed_nonce_len; + if (aead->random_variable_nonce) { + assert(aead->variable_nonce_included_in_record); + if (!RAND_bytes(nonce + nonce_len, aead->variable_nonce_len)) { + return 0; + } + } else { + /* When sending we use the sequence number as the variable part of the + * nonce. */ + assert(aead->variable_nonce_len == 8); + memcpy(nonce + nonce_len, ad, aead->variable_nonce_len); + } + nonce_len += aead->variable_nonce_len; + + /* Emit the variable nonce if included in the record. */ + size_t extra_len = 0; + if (aead->variable_nonce_included_in_record) { + if (max_out < aead->variable_nonce_len) { + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_seal, SSL_R_BUFFER_TOO_SMALL); + return 0; + } + if (out < in + in_len && in < out + aead->variable_nonce_len) { + OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_seal, SSL_R_OUTPUT_ALIASES_INPUT); + return 0; + } + memcpy(out, nonce + aead->fixed_nonce_len, aead->variable_nonce_len); + extra_len = aead->variable_nonce_len; + out += aead->variable_nonce_len; + max_out -= aead->variable_nonce_len; + } + + if (!EVP_AEAD_CTX_seal(&aead->ctx, out, out_len, max_out, nonce, nonce_len, + in, in_len, ad, ad_len)) { + return 0; + } + *out_len += extra_len; + return 1; +} diff --git a/src/ssl/ssl_asn1.c b/src/ssl/ssl_asn1.c index eb0c725..d1ac1b6 100644 --- a/src/ssl/ssl_asn1.c +++ b/src/ssl/ssl_asn1.c @@ -477,13 +477,17 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) { } if (!CBS_get_optional_asn1_bool(&session, &extended_master_secret, kExtendedMasterSecretTag, - 0 /* default to false */)) { + 0 /* default to false */) || + CBS_len(&session) != 0) { OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION); goto err; } ret->extended_master_secret = extended_master_secret; - /* Ignore |version|. The structure version number is ignored. */ + if (version != SSL_SESSION_ASN1_VERSION) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION); + goto err; + } /* Only support SSLv3/TLS and DTLS. */ if ((ssl_version >> 8) != SSL3_VERSION_MAJOR && @@ -498,7 +502,7 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) { OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_CIPHER_CODE_WRONG_LENGTH); goto err; } - ret->cipher = ssl3_get_cipher_by_value(cipher_value); + ret->cipher = SSL_get_cipher_by_value(cipher_value); if (ret->cipher == NULL) { OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_UNSUPPORTED_CIPHER); goto err; diff --git a/src/ssl/ssl_cert.c b/src/ssl/ssl_cert.c index 770912b..f1fd675 100644 --- a/src/ssl/ssl_cert.c +++ b/src/ssl/ssl_cert.c @@ -128,33 +128,22 @@ #include "../crypto/dh/internal.h" #include "../crypto/directory.h" +#include "../crypto/internal.h" #include "internal.h" -int SSL_get_ex_data_X509_STORE_CTX_idx(void) { - static int ssl_x509_store_ctx_idx = -1; - int got_write_lock = 0; - - CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); - - if (ssl_x509_store_ctx_idx < 0) { - CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); - CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); - got_write_lock = 1; - - if (ssl_x509_store_ctx_idx < 0) { - ssl_x509_store_ctx_idx = X509_STORE_CTX_get_ex_new_index( - 0, "SSL for verify callback", NULL, NULL, NULL); - } - } +static CRYPTO_once_t g_x509_store_ex_data_index_once; +static int g_x509_store_ex_data_index; - if (got_write_lock) { - CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); - } else { - CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); - } +static void ssl_x509_store_ex_data_index_init(void) { + g_x509_store_ex_data_index = X509_STORE_CTX_get_ex_new_index( + 0, "SSL for verify callback", NULL, NULL, NULL); +} - return ssl_x509_store_ctx_idx; +int SSL_get_ex_data_X509_STORE_CTX_idx(void) { + CRYPTO_once(&g_x509_store_ex_data_index_once, + ssl_x509_store_ex_data_index_init); + return g_x509_store_ex_data_index; } CERT *ssl_cert_new(void) { @@ -269,12 +258,12 @@ CERT *ssl_cert_dup(CERT *cert) { ret->cert_cb_arg = cert->cert_cb_arg; if (cert->verify_store) { - CRYPTO_add(&cert->verify_store->references, 1, CRYPTO_LOCK_X509_STORE); + CRYPTO_refcount_inc(&cert->verify_store->references); ret->verify_store = cert->verify_store; } if (cert->chain_store) { - CRYPTO_add(&cert->chain_store->references, 1, CRYPTO_LOCK_X509_STORE); + CRYPTO_refcount_inc(&cert->chain_store->references); ret->chain_store = cert->chain_store; } @@ -731,8 +720,6 @@ int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, const char *filename; int ret = 0; - CRYPTO_w_lock(CRYPTO_LOCK_READDIR); - /* Note that a side effect is that the CAs will be sorted by name */ while ((filename = OPENSSL_DIR_read(&d, dir))) { char buf[1024]; @@ -763,7 +750,6 @@ err: if (d) { OPENSSL_DIR_end(&d); } - CRYPTO_w_unlock(CRYPTO_LOCK_READDIR); return ret; } @@ -977,7 +963,7 @@ int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref) { *pstore = store; if (ref && store) { - CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE); + CRYPTO_refcount_inc(&store->references); } return 1; } diff --git a/src/ssl/ssl_cipher.c b/src/ssl/ssl_cipher.c index a9c8536..5e617b1 100644 --- a/src/ssl/ssl_cipher.c +++ b/src/ssl/ssl_cipher.c @@ -152,6 +152,325 @@ #include "internal.h" +/* kCiphers is an array of all supported ciphers, sorted by id. */ +const SSL_CIPHER kCiphers[] = { + /* The RSA ciphers */ + /* Cipher 04 */ + { + SSL3_TXT_RSA_RC4_128_MD5, SSL3_CK_RSA_RC4_128_MD5, SSL_kRSA, SSL_aRSA, + SSL_RC4, SSL_MD5, SSL_SSLV3, SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT, 128, 128, + }, + + /* Cipher 05 */ + { + SSL3_TXT_RSA_RC4_128_SHA, SSL3_CK_RSA_RC4_128_SHA, SSL_kRSA, SSL_aRSA, + SSL_RC4, SSL_SHA1, SSL_SSLV3, SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT, 128, 128, + }, + + /* Cipher 0A */ + { + SSL3_TXT_RSA_DES_192_CBC3_SHA, SSL3_CK_RSA_DES_192_CBC3_SHA, SSL_kRSA, + SSL_aRSA, SSL_3DES, SSL_SHA1, SSL_SSLV3, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT, 112, 168, + }, + + + /* New AES ciphersuites */ + + /* Cipher 2F */ + { + TLS1_TXT_RSA_WITH_AES_128_SHA, TLS1_CK_RSA_WITH_AES_128_SHA, SSL_kRSA, + SSL_aRSA, SSL_AES128, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT, 128, 128, + }, + + /* Cipher 33 */ + { + TLS1_TXT_DHE_RSA_WITH_AES_128_SHA, TLS1_CK_DHE_RSA_WITH_AES_128_SHA, + SSL_kDHE, SSL_aRSA, SSL_AES128, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT, 128, 128, + }, + + /* Cipher 35 */ + { + TLS1_TXT_RSA_WITH_AES_256_SHA, TLS1_CK_RSA_WITH_AES_256_SHA, SSL_kRSA, + SSL_aRSA, SSL_AES256, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT, 256, 256, + }, + + /* Cipher 39 */ + { + TLS1_TXT_DHE_RSA_WITH_AES_256_SHA, TLS1_CK_DHE_RSA_WITH_AES_256_SHA, + SSL_kDHE, SSL_aRSA, SSL_AES256, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT, 256, 256, + }, + + + /* TLS v1.2 ciphersuites */ + + /* Cipher 3C */ + { + TLS1_TXT_RSA_WITH_AES_128_SHA256, TLS1_CK_RSA_WITH_AES_128_SHA256, + SSL_kRSA, SSL_aRSA, SSL_AES128, SSL_SHA256, SSL_TLSV1_2, + SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256, 128, 128, + }, + + /* Cipher 3D */ + { + TLS1_TXT_RSA_WITH_AES_256_SHA256, TLS1_CK_RSA_WITH_AES_256_SHA256, + SSL_kRSA, SSL_aRSA, SSL_AES256, SSL_SHA256, SSL_TLSV1_2, + SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256, 256, 256, + }, + + /* Cipher 67 */ + { + TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256, + TLS1_CK_DHE_RSA_WITH_AES_128_SHA256, SSL_kDHE, SSL_aRSA, SSL_AES128, + SSL_SHA256, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256, 128, 128, + }, + + /* Cipher 6B */ + { + TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256, + TLS1_CK_DHE_RSA_WITH_AES_256_SHA256, SSL_kDHE, SSL_aRSA, SSL_AES256, + SSL_SHA256, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256, 256, 256, + }, + + /* Cipher 8A */ + { + TLS1_TXT_PSK_WITH_RC4_128_SHA, TLS1_CK_PSK_WITH_RC4_128_SHA, SSL_kPSK, + SSL_aPSK, SSL_RC4, SSL_SHA1, SSL_TLSV1, SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT, 128, 128, + }, + + /* Cipher 8C */ + { + TLS1_TXT_PSK_WITH_AES_128_CBC_SHA, TLS1_CK_PSK_WITH_AES_128_CBC_SHA, + SSL_kPSK, SSL_aPSK, SSL_AES128, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT, 128, 128, + }, + + /* Cipher 8D */ + { + TLS1_TXT_PSK_WITH_AES_256_CBC_SHA, TLS1_CK_PSK_WITH_AES_256_CBC_SHA, + SSL_kPSK, SSL_aPSK, SSL_AES256, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT, 256, 256, + }, + + + /* GCM ciphersuites from RFC5288 */ + + /* Cipher 9C */ + { + TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256, + TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, SSL_kRSA, SSL_aRSA, SSL_AES128GCM, + SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, + 128, 128, + }, + + /* Cipher 9D */ + { + TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384, + TLS1_CK_RSA_WITH_AES_256_GCM_SHA384, SSL_kRSA, SSL_aRSA, SSL_AES256GCM, + SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, + 256, 256, + }, + + /* Cipher 9E */ + { + TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256, + TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256, SSL_kDHE, SSL_aRSA, SSL_AES128GCM, + SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, + 128, 128, + }, + + /* Cipher 9F */ + { + TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384, + TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384, SSL_kDHE, SSL_aRSA, SSL_AES256GCM, + SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, + 256, 256, + }, + + /* Cipher C007 */ + { + TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA, + TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA, SSL_kECDHE, SSL_aECDSA, SSL_RC4, + SSL_SHA1, SSL_TLSV1, SSL_MEDIUM, SSL_HANDSHAKE_MAC_DEFAULT, 128, + 128, + }, + + /* Cipher C009 */ + { + TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, SSL_kECDHE, SSL_aECDSA, + SSL_AES128, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT, 128, 128, + }, + + /* Cipher C00A */ + { + TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, SSL_kECDHE, SSL_aECDSA, + SSL_AES256, SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT, 256, 256, + }, + + /* Cipher C011 */ + { + TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA, TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA, + SSL_kECDHE, SSL_aRSA, SSL_RC4, SSL_SHA1, SSL_TLSV1, SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT, 128, 128, + }, + + /* Cipher C013 */ + { + TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA, SSL_kECDHE, SSL_aRSA, SSL_AES128, + SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT, 128, 128, + }, + + /* Cipher C014 */ + { + TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA, + TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA, SSL_kECDHE, SSL_aRSA, SSL_AES256, + SSL_SHA1, SSL_TLSV1, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT, 256, 256, + }, + + + /* HMAC based TLS v1.2 ciphersuites from RFC5289 */ + + /* Cipher C023 */ + { + TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_SHA256, + TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256, SSL_kECDHE, SSL_aECDSA, + SSL_AES128, SSL_SHA256, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256, 128, 128, + }, + + /* Cipher C024 */ + { + TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_SHA384, + TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384, SSL_kECDHE, SSL_aECDSA, + SSL_AES256, SSL_SHA384, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384, 256, 256, + }, + + /* Cipher C027 */ + { + TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256, + TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256, SSL_kECDHE, SSL_aRSA, SSL_AES128, + SSL_SHA256, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256, 128, 128, + }, + + /* Cipher C028 */ + { + TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384, + TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384, SSL_kECDHE, SSL_aRSA, SSL_AES256, + SSL_SHA384, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384, 256, 256, + }, + + + /* GCM based TLS v1.2 ciphersuites from RFC5289 */ + + /* Cipher C02B */ + { + TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, SSL_kECDHE, SSL_aECDSA, + SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, + 128, 128, + }, + + /* Cipher C02C */ + { + TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, SSL_kECDHE, SSL_aECDSA, + SSL_AES256GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, + 256, 256, + }, + + /* Cipher C02F */ + { + TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, SSL_kECDHE, SSL_aRSA, + SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, + 128, 128, + }, + + /* Cipher C030 */ + { + TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, SSL_kECDHE, SSL_aRSA, + SSL_AES256GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, + 256, 256, + }, + + +#if !defined(ANDROID) + /* ECDH PSK ciphersuites */ + + /* Cipher CAFE */ + { + TLS1_TXT_ECDHE_PSK_WITH_AES_128_GCM_SHA256, + TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256, SSL_kECDHE, SSL_aPSK, + SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH, + SSL_HANDSHAKE_MAC_SHA256 | + SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, + 128, 128, + }, + + { + TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305, + TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, SSL_kECDHE, SSL_aRSA, + SSL_CHACHA20POLY1305, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH, + SSL_HANDSHAKE_MAC_SHA256, + 256, 0, + }, + + { + TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, SSL_kECDHE, SSL_aECDSA, + SSL_CHACHA20POLY1305, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH, + SSL_HANDSHAKE_MAC_SHA256, + 256, 0, + }, + + { + TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305, + TLS1_CK_DHE_RSA_CHACHA20_POLY1305, SSL_kDHE, SSL_aRSA, + SSL_CHACHA20POLY1305, SSL_AEAD, SSL_TLSV1_2, SSL_HIGH, + SSL_HANDSHAKE_MAC_SHA256, + 256, 0, + }, +#endif +}; + +static const size_t kCiphersLen = sizeof(kCiphers) / sizeof(kCiphers[0]); + struct handshake_digest { uint32_t mask; const EVP_MD *(*md_func)(void); @@ -193,71 +512,96 @@ typedef struct cipher_alias_st { uint32_t algo_strength; } CIPHER_ALIAS; -static const CIPHER_ALIAS kCipherAliases[] = - { - {SSL_TXT_ALL, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u}, - - /* The "COMPLEMENTOFDEFAULT" rule is omitted. It matches nothing. */ - - /* key exchange aliases - * (some of those using only a single bit here combine - * multiple key exchange algs according to the RFCs, - * e.g. kEDH combines DHE_DSS and DHE_RSA) */ - {SSL_TXT_kRSA, SSL_kRSA, ~0u, ~0u, ~0u, ~0u, ~0u}, - - {SSL_TXT_kDHE, SSL_kDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, - {SSL_TXT_kEDH, SSL_kDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, - {SSL_TXT_DH, SSL_kDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, - - {SSL_TXT_kECDHE, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, - {SSL_TXT_kEECDH, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, - {SSL_TXT_ECDH, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, - - {SSL_TXT_kPSK, SSL_kPSK, ~0u, ~0u, ~0u, ~0u, ~0u}, - - /* server authentication aliases */ - {SSL_TXT_aRSA, ~0u, SSL_aRSA, ~0u, ~0u, ~0u, ~0u}, - {SSL_TXT_aECDSA, ~0u, SSL_aECDSA, ~0u, ~0u, ~0u, ~0u}, - {SSL_TXT_ECDSA, ~0u, SSL_aECDSA, ~0u, ~0u, ~0u, ~0u}, - {SSL_TXT_aPSK, ~0u, SSL_aPSK, ~0u, ~0u, ~0u, ~0u}, - - /* aliases combining key exchange and server authentication */ - {SSL_TXT_DHE, SSL_kDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, - {SSL_TXT_EDH, SSL_kDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, - {SSL_TXT_ECDHE, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, - {SSL_TXT_EECDH, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, - {SSL_TXT_RSA, SSL_kRSA, SSL_aRSA, ~0u, ~0u, ~0u, ~0u}, - {SSL_TXT_PSK, SSL_kPSK, SSL_aPSK, ~0u, ~0u, ~0u, ~0u}, - - /* symmetric encryption aliases */ - {SSL_TXT_3DES, ~0u, ~0u, SSL_3DES, ~0u, ~0u, ~0u}, - {SSL_TXT_RC4, ~0u, ~0u, SSL_RC4, ~0u, ~0u, ~0u}, - {SSL_TXT_AES128, ~0u, ~0u, SSL_AES128 | SSL_AES128GCM, ~0u, ~0u, ~0u}, - {SSL_TXT_AES256, ~0u, ~0u, SSL_AES256 | SSL_AES256GCM, ~0u, ~0u, ~0u}, - {SSL_TXT_AES, ~0u, ~0u, SSL_AES, ~0u, ~0u, ~0u}, - {SSL_TXT_AES_GCM, ~0u, ~0u, SSL_AES128GCM | SSL_AES256GCM, ~0u, ~0u, ~0u}, - {SSL_TXT_CHACHA20, ~0u, ~0u, SSL_CHACHA20POLY1305, ~0u, ~0u, ~0u}, - - /* MAC aliases */ - {SSL_TXT_MD5, ~0u, ~0u, ~0u, SSL_MD5, ~0u, ~0u}, - {SSL_TXT_SHA1, ~0u, ~0u, ~0u, SSL_SHA1, ~0u, ~0u}, - {SSL_TXT_SHA, ~0u, ~0u, ~0u, SSL_SHA1, ~0u, ~0u}, - {SSL_TXT_SHA256, ~0u, ~0u, ~0u, SSL_SHA256, ~0u, ~0u}, - {SSL_TXT_SHA384, ~0u, ~0u, ~0u, SSL_SHA384, ~0u, ~0u}, - - /* protocol version aliases */ - {SSL_TXT_SSLV3, ~0u, ~0u, ~0u, ~0u, SSL_SSLV3, ~0u}, - {SSL_TXT_TLSV1, ~0u, ~0u, ~0u, ~0u, SSL_TLSV1, ~0u}, - {SSL_TXT_TLSV1_2, ~0u, ~0u, ~0u, ~0u, SSL_TLSV1_2, ~0u}, - - /* strength classes */ - {SSL_TXT_MEDIUM, ~0u, ~0u, ~0u, ~0u, ~0u, SSL_MEDIUM}, - {SSL_TXT_HIGH, ~0u, ~0u, ~0u, ~0u, ~0u, SSL_HIGH}, - /* FIPS 140-2 approved ciphersuite */ - {SSL_TXT_FIPS, ~0u, ~0u, ~0u, ~0u, ~0u, SSL_FIPS}, +static const CIPHER_ALIAS kCipherAliases[] = { + {SSL_TXT_ALL, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u}, + + /* The "COMPLEMENTOFDEFAULT" rule is omitted. It matches nothing. */ + + /* key exchange aliases + * (some of those using only a single bit here combine + * multiple key exchange algs according to the RFCs, + * e.g. kEDH combines DHE_DSS and DHE_RSA) */ + {SSL_TXT_kRSA, SSL_kRSA, ~0u, ~0u, ~0u, ~0u, ~0u}, + + {SSL_TXT_kDHE, SSL_kDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, + {SSL_TXT_kEDH, SSL_kDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, + {SSL_TXT_DH, SSL_kDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, + + {SSL_TXT_kECDHE, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, + {SSL_TXT_kEECDH, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, + {SSL_TXT_ECDH, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, + + {SSL_TXT_kPSK, SSL_kPSK, ~0u, ~0u, ~0u, ~0u, ~0u}, + + /* server authentication aliases */ + {SSL_TXT_aRSA, ~0u, SSL_aRSA, ~0u, ~0u, ~0u, ~0u}, + {SSL_TXT_aECDSA, ~0u, SSL_aECDSA, ~0u, ~0u, ~0u, ~0u}, + {SSL_TXT_ECDSA, ~0u, SSL_aECDSA, ~0u, ~0u, ~0u, ~0u}, + {SSL_TXT_aPSK, ~0u, SSL_aPSK, ~0u, ~0u, ~0u, ~0u}, + + /* aliases combining key exchange and server authentication */ + {SSL_TXT_DHE, SSL_kDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, + {SSL_TXT_EDH, SSL_kDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, + {SSL_TXT_ECDHE, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, + {SSL_TXT_EECDH, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u}, + {SSL_TXT_RSA, SSL_kRSA, SSL_aRSA, ~0u, ~0u, ~0u, ~0u}, + {SSL_TXT_PSK, SSL_kPSK, SSL_aPSK, ~0u, ~0u, ~0u, ~0u}, + + /* symmetric encryption aliases */ + {SSL_TXT_3DES, ~0u, ~0u, SSL_3DES, ~0u, ~0u, ~0u}, + {SSL_TXT_RC4, ~0u, ~0u, SSL_RC4, ~0u, ~0u, ~0u}, + {SSL_TXT_AES128, ~0u, ~0u, SSL_AES128 | SSL_AES128GCM, ~0u, ~0u, ~0u}, + {SSL_TXT_AES256, ~0u, ~0u, SSL_AES256 | SSL_AES256GCM, ~0u, ~0u, ~0u}, + {SSL_TXT_AES, ~0u, ~0u, SSL_AES, ~0u, ~0u, ~0u}, + {SSL_TXT_AES_GCM, ~0u, ~0u, SSL_AES128GCM | SSL_AES256GCM, ~0u, ~0u, ~0u}, + {SSL_TXT_CHACHA20, ~0u, ~0u, SSL_CHACHA20POLY1305, ~0u, ~0u, ~0u}, + + /* MAC aliases */ + {SSL_TXT_MD5, ~0u, ~0u, ~0u, SSL_MD5, ~0u, ~0u}, + {SSL_TXT_SHA1, ~0u, ~0u, ~0u, SSL_SHA1, ~0u, ~0u}, + {SSL_TXT_SHA, ~0u, ~0u, ~0u, SSL_SHA1, ~0u, ~0u}, + {SSL_TXT_SHA256, ~0u, ~0u, ~0u, SSL_SHA256, ~0u, ~0u}, + {SSL_TXT_SHA384, ~0u, ~0u, ~0u, SSL_SHA384, ~0u, ~0u}, + + /* protocol version aliases */ + {SSL_TXT_SSLV3, ~0u, ~0u, ~0u, ~0u, SSL_SSLV3, ~0u}, + {SSL_TXT_TLSV1, ~0u, ~0u, ~0u, ~0u, SSL_TLSV1, ~0u}, + {SSL_TXT_TLSV1_2, ~0u, ~0u, ~0u, ~0u, SSL_TLSV1_2, ~0u}, + + /* strength classes */ + {SSL_TXT_MEDIUM, ~0u, ~0u, ~0u, ~0u, ~0u, SSL_MEDIUM}, + {SSL_TXT_HIGH, ~0u, ~0u, ~0u, ~0u, ~0u, SSL_HIGH}, + /* FIPS 140-2 approved ciphersuite */ + {SSL_TXT_FIPS, ~0u, ~0u, ~0u, ~0u, ~0u, SSL_FIPS}, }; -#define NUM_CIPHER_ALIASES (sizeof(kCipherAliases) / sizeof(kCipherAliases[0])) +static const size_t kCipherAliasesLen = + sizeof(kCipherAliases) / sizeof(kCipherAliases[0]); + +static int ssl_cipher_id_cmp(const void *in_a, const void *in_b) { + const SSL_CIPHER *a = in_a; + const SSL_CIPHER *b = in_b; + + if (a->id > b->id) { + return 1; + } else if (a->id < b->id) { + return -1; + } else { + return 0; + } +} + +static int ssl_cipher_ptr_id_cmp(const SSL_CIPHER **a, const SSL_CIPHER **b) { + return ssl_cipher_id_cmp(*a, *b); +} + +const SSL_CIPHER *SSL_get_cipher_by_value(uint16_t value) { + SSL_CIPHER c; + + c.id = 0x03000000L | value; + return bsearch(&c, kCiphers, kCiphersLen, sizeof(SSL_CIPHER), + ssl_cipher_id_cmp); +} int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead, size_t *out_mac_secret_len, @@ -439,22 +783,17 @@ static void ll_append_head(CIPHER_ORDER **head, CIPHER_ORDER *curr, } static void ssl_cipher_collect_ciphers(const SSL_PROTOCOL_METHOD *ssl_method, - size_t num_of_ciphers, CIPHER_ORDER *co_list, CIPHER_ORDER **head_p, CIPHER_ORDER **tail_p) { - size_t i, co_list_num; - - /* We have num_of_ciphers descriptions compiled in, depending on the method - * selected (SSLv2 and/or SSLv3, TLSv1 etc). These will later be sorted in a - * linked list with at most num entries. */ - - /* Get the initial list of ciphers */ - co_list_num = 0; /* actual count of ciphers */ - for (i = 0; i < num_of_ciphers; i++) { - const SSL_CIPHER *c = ssl_method->get_cipher(i); - if (c != NULL) { - co_list[co_list_num].cipher = c; + /* The set of ciphers is static, but some subset may be unsupported by + * |ssl_method|, so the list may be smaller. */ + size_t co_list_num = 0; + size_t i; + for (i = 0; i < kCiphersLen; i++) { + const SSL_CIPHER *cipher = &kCiphers[i]; + if (ssl_method->supports_cipher(cipher)) { + co_list[co_list_num].cipher = cipher; co_list[co_list_num].next = NULL; co_list[co_list_num].prev = NULL; co_list[co_list_num].active = 0; @@ -777,10 +1116,9 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, /* Look for a matching exact cipher. These aren't allowed in multipart * rules. */ if (!multi && ch != '+') { - size_t num_ciphers = ssl_method->num_ciphers(); - for (j = 0; j < num_ciphers; j++) { - const SSL_CIPHER *cipher = ssl_method->get_cipher(j); - if (cipher != NULL && rule_equals(cipher->name, buf, buf_len)) { + for (j = 0; j < kCiphersLen; j++) { + const SSL_CIPHER *cipher = &kCiphers[j]; + if (rule_equals(cipher->name, buf, buf_len)) { cipher_id = cipher->id; break; } @@ -788,7 +1126,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, } if (cipher_id == 0) { /* If not an exact cipher, look for a matching cipher alias. */ - for (j = 0; j < NUM_CIPHER_ALIASES; j++) { + for (j = 0; j < kCipherAliasesLen; j++) { if (rule_equals(kCipherAliases[j].name, buf, buf_len)) { alg_mkey &= kCipherAliases[j].algorithm_mkey; alg_auth &= kCipherAliases[j].algorithm_auth; @@ -799,7 +1137,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, break; } } - if (j == NUM_CIPHER_ALIASES) { + if (j == kCipherAliasesLen) { alg_mkey = alg_auth = alg_enc = alg_mac = alg_ssl = algo_strength = 0; } } @@ -853,7 +1191,6 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, STACK_OF(SSL_CIPHER) **out_cipher_list_by_id, const char *rule_str) { int ok; - size_t num_of_ciphers; STACK_OF(SSL_CIPHER) *cipherstack = NULL, *tmp_cipher_list = NULL; const char *rule_p; CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr; @@ -869,23 +1206,21 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, /* Now we have to collect the available ciphers from the compiled in ciphers. * We cannot get more than the number compiled in, so it is used for * allocation. */ - num_of_ciphers = ssl_method->num_ciphers(); - co_list = - (CIPHER_ORDER *)OPENSSL_malloc(sizeof(CIPHER_ORDER) * num_of_ciphers); + co_list = (CIPHER_ORDER *)OPENSSL_malloc(sizeof(CIPHER_ORDER) * kCiphersLen); if (co_list == NULL) { OPENSSL_PUT_ERROR(SSL, ssl_create_cipher_list, ERR_R_MALLOC_FAILURE); return NULL; } - ssl_cipher_collect_ciphers(ssl_method, num_of_ciphers, co_list, &head, &tail); + ssl_cipher_collect_ciphers(ssl_method, co_list, &head, &tail); /* Now arrange all ciphers by preference: * TODO(davidben): Compute this order once and copy it. */ /* Everything else being equal, prefer ECDHE_ECDSA then ECDHE_RSA over other * key exchange mechanisms */ - ssl_cipher_apply_rule(0, SSL_kECDHE, SSL_aECDSA, ~0u, ~0u, ~0u, ~0u, - CIPHER_ADD, -1, 0, &head, &tail); + ssl_cipher_apply_rule(0, SSL_kECDHE, SSL_aECDSA, ~0u, ~0u, ~0u, ~0u, + CIPHER_ADD, -1, 0, &head, &tail); ssl_cipher_apply_rule(0, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u, CIPHER_ADD, -1, 0, &head, &tail); ssl_cipher_apply_rule(0, SSL_kECDHE, ~0u, ~0u, ~0u, ~0u, ~0u, CIPHER_DEL, -1, @@ -963,7 +1298,7 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, goto err; } - in_group_flags = OPENSSL_malloc(num_of_ciphers); + in_group_flags = OPENSSL_malloc(kCiphersLen); if (!in_group_flags) { goto err; } @@ -1032,6 +1367,13 @@ err: uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *cipher) { return cipher->id; } +uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher) { + uint32_t id = cipher->id; + /* All ciphers are SSLv3. */ + assert((id & 0xff000000) == 0x03000000); + return id & 0xffff; +} + int SSL_CIPHER_is_AES(const SSL_CIPHER *cipher) { return (cipher->algorithm_enc & SSL_AES) != 0; } @@ -1122,7 +1464,8 @@ static const char *ssl_cipher_get_enc_name(const SSL_CIPHER *cipher) { } static const char *ssl_cipher_get_prf_name(const SSL_CIPHER *cipher) { - if ((cipher->algorithm2 & TLS1_PRF) == TLS1_PRF) { + if ((cipher->algorithm2 & SSL_HANDSHAKE_MAC_DEFAULT) == + SSL_HANDSHAKE_MAC_DEFAULT) { /* Before TLS 1.2, the PRF component is the hash used in the HMAC, which is * only ever MD5 or SHA-1. */ switch (cipher->algorithm_mac) { @@ -1134,9 +1477,9 @@ static const char *ssl_cipher_get_prf_name(const SSL_CIPHER *cipher) { assert(0); return "UNKNOWN"; } - } else if (cipher->algorithm2 & TLS1_PRF_SHA256) { + } else if (cipher->algorithm2 & SSL_HANDSHAKE_MAC_SHA256) { return "SHA256"; - } else if (cipher->algorithm2 & TLS1_PRF_SHA384) { + } else if (cipher->algorithm2 & SSL_HANDSHAKE_MAC_SHA384) { return "SHA384"; } else { assert(0); diff --git a/src/ssl/ssl_lib.c b/src/ssl/ssl_lib.c index 6c8e2c9..e95226f 100644 --- a/src/ssl/ssl_lib.c +++ b/src/ssl/ssl_lib.c @@ -167,80 +167,75 @@ static const size_t kMaxHandshakeSize = (1u << 24) - 1; static CRYPTO_EX_DATA_CLASS g_ex_data_class_ssl = CRYPTO_EX_DATA_CLASS_INIT; static CRYPTO_EX_DATA_CLASS g_ex_data_class_ssl_ctx = CRYPTO_EX_DATA_CLASS_INIT; -int SSL_clear(SSL *s) { - if (s->method == NULL) { +int SSL_clear(SSL *ssl) { + if (ssl->method == NULL) { OPENSSL_PUT_ERROR(SSL, SSL_clear, SSL_R_NO_METHOD_SPECIFIED); return 0; } - if (ssl_clear_bad_session(s)) { - SSL_SESSION_free(s->session); - s->session = NULL; + if (ssl_clear_bad_session(ssl)) { + SSL_SESSION_free(ssl->session); + ssl->session = NULL; } - s->hit = 0; - s->shutdown = 0; + ssl->hit = 0; + ssl->shutdown = 0; - if (s->renegotiate) { - OPENSSL_PUT_ERROR(SSL, SSL_clear, ERR_R_INTERNAL_ERROR); - return 0; - } - - /* SSL_clear may be called before or after the |s| is initialized in either + /* SSL_clear may be called before or after the |ssl| is initialized in either * accept or connect state. In the latter case, SSL_clear should preserve the - * half and reset |s->state| accordingly. */ - if (s->handshake_func != NULL) { - if (s->server) { - SSL_set_accept_state(s); + * half and reset |ssl->state| accordingly. */ + if (ssl->handshake_func != NULL) { + if (ssl->server) { + SSL_set_accept_state(ssl); } else { - SSL_set_connect_state(s); + SSL_set_connect_state(ssl); } } else { - assert(s->state == 0); + assert(ssl->state == 0); } - /* TODO(davidben): Some state on |s| is reset both in |SSL_new| and + /* TODO(davidben): Some state on |ssl| is reset both in |SSL_new| and * |SSL_clear| because it is per-connection state rather than configuration - * state. Per-connection state should be on |s->s3| and |s->d1| so it is + * state. Per-connection state should be on |ssl->s3| and |ssl->d1| so it is * naturally reset at the right points between |SSL_new|, |SSL_clear|, and * |ssl3_new|. */ - s->rwstate = SSL_NOTHING; - s->rstate = SSL_ST_READ_HEADER; + ssl->rwstate = SSL_NOTHING; + ssl->rstate = SSL_ST_READ_HEADER; - BUF_MEM_free(s->init_buf); - s->init_buf = NULL; + BUF_MEM_free(ssl->init_buf); + ssl->init_buf = NULL; - s->packet = NULL; - s->packet_length = 0; + ssl->packet = NULL; + ssl->packet_length = 0; - ssl_clear_cipher_ctx(s); + ssl_clear_cipher_ctx(ssl); - OPENSSL_free(s->next_proto_negotiated); - s->next_proto_negotiated = NULL; - s->next_proto_negotiated_len = 0; + OPENSSL_free(ssl->next_proto_negotiated); + ssl->next_proto_negotiated = NULL; + ssl->next_proto_negotiated_len = 0; - /* The s->d1->mtu is simultaneously configuration (preserved across + /* The ssl->d1->mtu is simultaneously configuration (preserved across * clear) and connection-specific state (gets reset). * * TODO(davidben): Avoid this. */ unsigned mtu = 0; - if (s->d1 != NULL) { - mtu = s->d1->mtu; + if (ssl->d1 != NULL) { + mtu = ssl->d1->mtu; } - s->method->ssl_free(s); - if (!s->method->ssl_new(s)) { + ssl->method->ssl_free(ssl); + if (!ssl->method->ssl_new(ssl)) { return 0; } - s->enc_method = ssl3_get_enc_method(s->version); - assert(s->enc_method != NULL); + ssl->enc_method = ssl3_get_enc_method(ssl->version); + assert(ssl->enc_method != NULL); - if (SSL_IS_DTLS(s) && (SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) { - s->d1->mtu = mtu; + if (SSL_IS_DTLS(ssl) && (SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) { + ssl->d1->mtu = mtu; } - s->client_version = s->version; + ssl->client_version = ssl->version; return 1; } @@ -275,7 +270,6 @@ SSL *SSL_new(SSL_CTX *ctx) { goto err; } - s->read_ahead = ctx->read_ahead; s->msg_callback = ctx->msg_callback; s->msg_callback_arg = ctx->msg_callback_arg; s->verify_mode = ctx->verify_mode; @@ -293,10 +287,10 @@ SSL *SSL_new(SSL_CTX *ctx) { s->quiet_shutdown = ctx->quiet_shutdown; s->max_send_fragment = ctx->max_send_fragment; - CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX); + CRYPTO_refcount_inc(&ctx->references); s->ctx = ctx; s->tlsext_ticket_expected = 0; - CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX); + CRYPTO_refcount_inc(&ctx->references); s->initial_ctx = ctx; if (ctx->tlsext_ecpointformatlist) { s->tlsext_ecpointformatlist = BUF_memdup( @@ -396,9 +390,7 @@ int SSL_set_session_id_context(SSL *ssl, const uint8_t *sid_ctx, } int SSL_CTX_set_generate_session_id(SSL_CTX *ctx, GEN_SESSION_CB cb) { - CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); ctx->generate_session_id = cb; - CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); return 1; } @@ -424,9 +416,9 @@ int SSL_has_matching_session_id(const SSL *ssl, const uint8_t *id, r.session_id_length = id_len; memcpy(r.session_id, id, id_len); - CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); + CRYPTO_MUTEX_lock_read(&ssl->ctx->lock); p = lh_SSL_SESSION_retrieve(ssl->ctx->sessions, &r); - CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); + CRYPTO_MUTEX_unlock(&ssl->ctx->lock); return p != NULL; } @@ -525,60 +517,60 @@ X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl) { return ssl->param; } void SSL_certs_clear(SSL *s) { ssl_cert_clear_certs(s->cert); } -void SSL_free(SSL *s) { - if (s == NULL) { +void SSL_free(SSL *ssl) { + if (ssl == NULL) { return; } - X509_VERIFY_PARAM_free(s->param); + X509_VERIFY_PARAM_free(ssl->param); - CRYPTO_free_ex_data(&g_ex_data_class_ssl, s, &s->ex_data); + CRYPTO_free_ex_data(&g_ex_data_class_ssl, ssl, &ssl->ex_data); - if (s->bbio != NULL) { + if (ssl->bbio != NULL) { /* If the buffering BIO is in place, pop it off */ - if (s->bbio == s->wbio) { - s->wbio = BIO_pop(s->wbio); + if (ssl->bbio == ssl->wbio) { + ssl->wbio = BIO_pop(ssl->wbio); } - BIO_free(s->bbio); - s->bbio = NULL; + BIO_free(ssl->bbio); + ssl->bbio = NULL; } - int free_wbio = s->wbio != s->rbio; - BIO_free_all(s->rbio); + int free_wbio = ssl->wbio != ssl->rbio; + BIO_free_all(ssl->rbio); if (free_wbio) { - BIO_free_all(s->wbio); + BIO_free_all(ssl->wbio); } - BUF_MEM_free(s->init_buf); + BUF_MEM_free(ssl->init_buf); /* add extra stuff */ - ssl_cipher_preference_list_free(s->cipher_list); - sk_SSL_CIPHER_free(s->cipher_list_by_id); + ssl_cipher_preference_list_free(ssl->cipher_list); + sk_SSL_CIPHER_free(ssl->cipher_list_by_id); - ssl_clear_bad_session(s); - SSL_SESSION_free(s->session); + ssl_clear_bad_session(ssl); + SSL_SESSION_free(ssl->session); - ssl_clear_cipher_ctx(s); + ssl_clear_cipher_ctx(ssl); - ssl_cert_free(s->cert); + ssl_cert_free(ssl->cert); - OPENSSL_free(s->tlsext_hostname); - SSL_CTX_free(s->initial_ctx); - OPENSSL_free(s->tlsext_ecpointformatlist); - OPENSSL_free(s->tlsext_ellipticcurvelist); - OPENSSL_free(s->alpn_client_proto_list); - EVP_PKEY_free(s->tlsext_channel_id_private); - OPENSSL_free(s->psk_identity_hint); - sk_X509_NAME_pop_free(s->client_CA, X509_NAME_free); - OPENSSL_free(s->next_proto_negotiated); - sk_SRTP_PROTECTION_PROFILE_free(s->srtp_profiles); + OPENSSL_free(ssl->tlsext_hostname); + SSL_CTX_free(ssl->initial_ctx); + OPENSSL_free(ssl->tlsext_ecpointformatlist); + OPENSSL_free(ssl->tlsext_ellipticcurvelist); + OPENSSL_free(ssl->alpn_client_proto_list); + EVP_PKEY_free(ssl->tlsext_channel_id_private); + OPENSSL_free(ssl->psk_identity_hint); + sk_X509_NAME_pop_free(ssl->client_CA, X509_NAME_free); + OPENSSL_free(ssl->next_proto_negotiated); + sk_SRTP_PROTECTION_PROFILE_free(ssl->srtp_profiles); - if (s->method != NULL) { - s->method->ssl_free(s); + if (ssl->method != NULL) { + ssl->method->ssl_free(ssl); } - SSL_CTX_free(s->ctx); + SSL_CTX_free(ssl->ctx); - OPENSSL_free(s); + OPENSSL_free(ssl); } void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio) { @@ -758,21 +750,21 @@ void SSL_set_verify_depth(SSL *s, int depth) { X509_VERIFY_PARAM_set_depth(s->param, depth); } -int SSL_CTX_get_read_ahead(const SSL_CTX *ctx) { return ctx->read_ahead; } +int SSL_CTX_get_read_ahead(const SSL_CTX *ctx) { return 0; } -int SSL_get_read_ahead(const SSL *s) { return s->read_ahead; } +int SSL_get_read_ahead(const SSL *s) { return 0; } -void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes) { ctx->read_ahead = !!yes; } +void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes) { } -void SSL_set_read_ahead(SSL *s, int yes) { s->read_ahead = !!yes; } +void SSL_set_read_ahead(SSL *s, int yes) { } int SSL_pending(const SSL *s) { - /* SSL_pending cannot work properly if read-ahead is enabled - * (SSL_[CTX_]ctrl(..., SSL_CTRL_SET_READ_AHEAD, 1, NULL)), and it is - * impossible to fix since SSL_pending cannot report errors that may be - * observed while scanning the new data. (Note that SSL_pending() is often - * used as a boolean value, so we'd better not return -1.). */ - return s->method->ssl_pending(s); + if (s->rstate == SSL_ST_READ_BODY) { + return 0; + } + + return (s->s3->rrec.type == SSL3_RT_APPLICATION_DATA) ? s->s3->rrec.length + : 0; } X509 *SSL_get_peer_certificate(const SSL *s) { @@ -895,7 +887,8 @@ int SSL_read(SSL *s, void *buf, int num) { return 0; } - return s->method->ssl_read(s, buf, num); + ERR_clear_system_error(); + return s->method->ssl_read_app_data(s, buf, num, 0); } int SSL_peek(SSL *s, void *buf, int num) { @@ -908,7 +901,8 @@ int SSL_peek(SSL *s, void *buf, int num) { return 0; } - return s->method->ssl_peek(s, buf, num); + ERR_clear_system_error(); + return s->method->ssl_read_app_data(s, buf, num, 1); } int SSL_write(SSL *s, const void *buf, int num) { @@ -923,7 +917,8 @@ int SSL_write(SSL *s, const void *buf, int num) { return -1; } - return s->method->ssl_write(s, buf, num); + ERR_clear_system_error(); + return s->method->ssl_write_app_data(s, buf, num); } int SSL_shutdown(SSL *s) { @@ -937,32 +932,58 @@ int SSL_shutdown(SSL *s) { return -1; } - if (!SSL_in_init(s)) { - return s->method->ssl_shutdown(s); + if (SSL_in_init(s)) { + return 1; } - return 1; -} + /* Do nothing if configured not to send a close_notify. */ + if (s->quiet_shutdown) { + s->shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN; + return 1; + } -int SSL_renegotiate(SSL *s) { - if (SSL_IS_DTLS(s)) { - /* Renegotiation is not supported for DTLS. */ - OPENSSL_PUT_ERROR(SSL, SSL_renegotiate, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; + if (!(s->shutdown & SSL_SENT_SHUTDOWN)) { + s->shutdown |= SSL_SENT_SHUTDOWN; + ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_CLOSE_NOTIFY); + + /* our shutdown alert has been sent now, and if it still needs to be + * written, s->s3->alert_dispatch will be true */ + if (s->s3->alert_dispatch) { + return -1; /* return WANT_WRITE */ + } + } else if (s->s3->alert_dispatch) { + /* resend it if not sent */ + int ret = s->method->ssl_dispatch_alert(s); + if (ret == -1) { + /* we only get to return -1 here the 2nd/Nth invocation, we must have + * already signalled return 0 upon a previous invoation, return + * WANT_WRITE */ + return ret; + } + } else if (!(s->shutdown & SSL_RECEIVED_SHUTDOWN)) { + /* If we are waiting for a close from our peer, we are closed */ + s->method->ssl_read_close_notify(s); + if (!(s->shutdown & SSL_RECEIVED_SHUTDOWN)) { + return -1; /* return WANT_READ */ + } } - if (s->renegotiate == 0) { - s->renegotiate = 1; + if (s->shutdown == (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN) && + !s->s3->alert_dispatch) { + return 1; + } else { + return 0; } +} - s->new_session = 1; - return s->method->ssl_renegotiate(s); +int SSL_renegotiate(SSL *ssl) { + /* Caller-initiated renegotiation is not supported. */ + OPENSSL_PUT_ERROR(SSL, SSL_renegotiate, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; } -int SSL_renegotiate_pending(SSL *s) { - /* becomes true when negotiation is requested; false again once a handshake - * has finished */ - return s->renegotiate != 0; +int SSL_renegotiate_pending(SSL *ssl) { + return SSL_in_init(ssl) && ssl->s3->initial_handshake_complete; } uint32_t SSL_CTX_set_options(SSL_CTX *ctx, uint32_t options) { @@ -1101,34 +1122,6 @@ long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) { return ctx->method->ssl_ctx_ctrl(ctx, cmd, larg, parg); } -int ssl_cipher_id_cmp(const void *in_a, const void *in_b) { - long l; - const SSL_CIPHER *a = in_a; - const SSL_CIPHER *b = in_b; - const long a_id = a->id; - const long b_id = b->id; - - l = a_id - b_id; - if (l == 0L) { - return 0; - } else { - return (l > 0) ? 1 : -1; - } -} - -int ssl_cipher_ptr_id_cmp(const SSL_CIPHER **ap, const SSL_CIPHER **bp) { - long l; - const long a_id = (*ap)->id; - const long b_id = (*bp)->id; - - l = a_id - b_id; - if (l == 0) { - return 0; - } else { - return (l > 0) ? 1 : -1; - } -} - /* return a STACK of the ciphers available for the SSL and in order of * preference */ STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s) { @@ -1267,7 +1260,7 @@ int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, uint8_t *p) { c->algorithm_auth & ct->mask_a) { continue; } - s2n(ssl3_get_cipher_value(c), p); + s2n(ssl_cipher_get_value(c), p); } /* If all ciphers were disabled, return the error to the caller. */ @@ -1276,7 +1269,7 @@ int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, uint8_t *p) { } /* Add SCSVs. */ - if (!s->renegotiate) { + if (!s->s3->initial_handshake_complete) { s2n(SSL3_CK_SCSV & 0xffff, p); } @@ -1319,7 +1312,7 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) { /* Check for SCSV. */ if (s->s3 && cipher_suite == (SSL3_CK_SCSV & 0xffff)) { /* SCSV is fatal if renegotiating. */ - if (s->renegotiate) { + if (s->s3->initial_handshake_complete) { OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING); ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); @@ -1342,7 +1335,7 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) { continue; } - c = ssl3_get_cipher_by_value(cipher_suite); + c = SSL_get_cipher_by_value(cipher_suite); if (c != NULL && !sk_SSL_CIPHER_push(sk, c)) { OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, ERR_R_MALLOC_FAILURE); goto err; @@ -1629,10 +1622,10 @@ static int ssl_session_cmp(const SSL_SESSION *a, const SSL_SESSION *b) { return memcmp(a->session_id, b->session_id, a->session_id_length); } -SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) { +SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) { SSL_CTX *ret = NULL; - if (meth == NULL) { + if (method == NULL) { OPENSSL_PUT_ERROR(SSL, SSL_CTX_new, SSL_R_NULL_SSL_METHOD_PASSED); return NULL; } @@ -1649,7 +1642,9 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) { memset(ret, 0, sizeof(SSL_CTX)); - ret->method = meth->method; + ret->method = method->method; + + CRYPTO_MUTEX_init(&ret->lock); ret->cert_store = NULL; ret->session_cache_mode = SSL_SESS_CACHE_SERVER; @@ -1674,7 +1669,6 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) { ret->app_verify_arg = NULL; ret->max_cert_list = SSL_MAX_CERT_LIST_DEFAULT; - ret->read_ahead = 0; ret->msg_callback = 0; ret->msg_callback_arg = NULL; ret->verify_mode = SSL_VERIFY_NONE; @@ -1743,9 +1737,9 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) { /* Lock the SSL_CTX to the specified version, for compatibility with legacy * uses of SSL_METHOD. */ - if (meth->version != 0) { - SSL_CTX_set_max_version(ret, meth->version); - SSL_CTX_set_min_version(ret, meth->version); + if (method->version != 0) { + SSL_CTX_set_max_version(ret, method->version); + SSL_CTX_set_min_version(ret, method->version); } return ret; @@ -1759,7 +1753,7 @@ err2: void SSL_CTX_free(SSL_CTX *ctx) { if (ctx == NULL || - CRYPTO_add(&ctx->references, -1, CRYPTO_LOCK_SSL_CTX) > 0) { + !CRYPTO_refcount_dec_and_test_zero(&ctx->references)) { return; } @@ -1775,6 +1769,7 @@ void SSL_CTX_free(SSL_CTX *ctx) { CRYPTO_free_ex_data(&g_ex_data_class_ssl_ctx, ctx, &ctx->ex_data); + CRYPTO_MUTEX_cleanup(&ctx->lock); lh_SSL_SESSION_free(ctx->sessions); X509_STORE_free(ctx->cert_store); ssl_cipher_preference_list_free(ctx->cipher_list); @@ -1997,13 +1992,13 @@ void ssl_update_cache(SSL *s, int mode) { (ctx->session_cache_mode & mode) == mode) { /* Automatically flush the internal session cache every 255 connections. */ int flush_cache = 0; - CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + CRYPTO_MUTEX_lock_write(&ctx->lock); ctx->handshakes_since_cache_flush++; if (ctx->handshakes_since_cache_flush >= 255) { flush_cache = 1; ctx->handshakes_since_cache_flush = 0; } - CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); + CRYPTO_MUTEX_unlock(&ctx->lock); if (flush_cache) { SSL_CTX_flush_sessions(ctx, (unsigned long)time(NULL)); @@ -2124,30 +2119,28 @@ int SSL_do_handshake(SSL *s) { return -1; } - s->method->ssl_renegotiate_check(s); - if (SSL_in_init(s)) { ret = s->handshake_func(s); } return ret; } -void SSL_set_accept_state(SSL *s) { - s->server = 1; - s->shutdown = 0; - s->state = SSL_ST_ACCEPT | SSL_ST_BEFORE; - s->handshake_func = s->method->ssl_accept; +void SSL_set_accept_state(SSL *ssl) { + ssl->server = 1; + ssl->shutdown = 0; + ssl->state = SSL_ST_ACCEPT; + ssl->handshake_func = ssl->method->ssl_accept; /* clear the current cipher */ - ssl_clear_cipher_ctx(s); + ssl_clear_cipher_ctx(ssl); } -void SSL_set_connect_state(SSL *s) { - s->server = 0; - s->shutdown = 0; - s->state = SSL_ST_CONNECT | SSL_ST_BEFORE; - s->handshake_func = s->method->ssl_connect; +void SSL_set_connect_state(SSL *ssl) { + ssl->server = 0; + ssl->shutdown = 0; + ssl->state = SSL_ST_CONNECT; + ssl->handshake_func = ssl->method->ssl_connect; /* clear the current cipher */ - ssl_clear_cipher_ctx(s); + ssl_clear_cipher_ctx(ssl); } static const char *ssl_get_version(int version) { @@ -2184,17 +2177,10 @@ const char *SSL_SESSION_get_version(const SSL_SESSION *sess) { } void ssl_clear_cipher_ctx(SSL *s) { - if (s->aead_read_ctx != NULL) { - EVP_AEAD_CTX_cleanup(&s->aead_read_ctx->ctx); - OPENSSL_free(s->aead_read_ctx); - s->aead_read_ctx = NULL; - } - - if (s->aead_write_ctx != NULL) { - EVP_AEAD_CTX_cleanup(&s->aead_write_ctx->ctx); - OPENSSL_free(s->aead_write_ctx); - s->aead_write_ctx = NULL; - } + SSL_AEAD_CTX_free(s->aead_read_ctx); + s->aead_read_ctx = NULL; + SSL_AEAD_CTX_free(s->aead_write_ctx); + s->aead_write_ctx = NULL; } X509 *SSL_get_certificate(const SSL *s) { @@ -2230,11 +2216,10 @@ EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx) { } const SSL_CIPHER *SSL_get_current_cipher(const SSL *s) { - if (s->session != NULL && s->session->cipher != NULL) { - return s->session->cipher; + if (s->aead_write_ctx == NULL) { + return NULL; } - - return NULL; + return s->aead_write_ctx->cipher; } const void *SSL_get_current_compression(SSL *s) { return NULL; } @@ -2322,7 +2307,7 @@ SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx) { ssl_cert_free(ssl->cert); ssl->cert = ssl_cert_dup(ctx->cert); - CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX); + CRYPTO_refcount_inc(&ctx->references); SSL_CTX_free(ssl->ctx); /* decrement reference count */ ssl->ctx = ctx; @@ -2354,7 +2339,7 @@ void (*SSL_get_info_callback(const SSL *ssl))(const SSL * /*ssl*/, int /*type*/, int SSL_state(const SSL *ssl) { return ssl->state; } -void SSL_set_state(SSL *ssl, int state) { ssl->state = state; } +void SSL_set_state(SSL *ssl, int state) { } void SSL_set_verify_result(SSL *ssl, long arg) { ssl->verify_result = arg; } @@ -2397,8 +2382,6 @@ void *SSL_CTX_get_ex_data(const SSL_CTX *s, int idx) { return CRYPTO_get_ex_data(&s->ex_data, idx); } -int ssl_ok(SSL *s) { return 1; } - X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) { return ctx->cert_store; } @@ -2626,9 +2609,9 @@ int ssl_ctx_log_rsa_client_key_exchange(SSL_CTX *ctx, return 0; } - CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + CRYPTO_MUTEX_lock_write(&ctx->lock); ret = BIO_write(bio, out, out_len) >= 0 && BIO_flush(bio); - CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); + CRYPTO_MUTEX_unlock(&ctx->lock); OPENSSL_free(out); return ret; @@ -2666,9 +2649,9 @@ int ssl_ctx_log_master_secret(SSL_CTX *ctx, const uint8_t *client_random, return 0; } - CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + CRYPTO_MUTEX_lock_write(&ctx->lock); ret = BIO_write(bio, out, out_len) >= 0 && BIO_flush(bio); - CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); + CRYPTO_MUTEX_unlock(&ctx->lock); OPENSSL_free(out); return ret; @@ -2929,11 +2912,7 @@ void SSL_enable_fastradio_padding(SSL *s, char on_off) { } void SSL_set_reject_peer_renegotiations(SSL *s, int reject) { - s->reject_peer_renegotiations = !!reject; -} - -const SSL_CIPHER *SSL_get_cipher_by_value(uint16_t value) { - return ssl3_get_cipher_by_value(value); + s->accept_peer_renegotiations = !reject; } int SSL_get_rc4_state(const SSL *ssl, const RC4_KEY **read_key, @@ -2946,6 +2925,41 @@ int SSL_get_rc4_state(const SSL *ssl, const RC4_KEY **read_key, EVP_AEAD_CTX_get_rc4_state(&ssl->aead_write_ctx->ctx, write_key); } +int SSL_get_tls_unique(const SSL *ssl, uint8_t *out, size_t *out_len, + size_t max_out) { + /* The tls-unique value is the first Finished message in the handshake, which + * is the client's in a full handshake and the server's for a resumption. See + * https://tools.ietf.org/html/rfc5929#section-3.1. */ + const uint8_t *finished = ssl->s3->previous_client_finished; + size_t finished_len = ssl->s3->previous_client_finished_len; + if (ssl->hit) { + /* tls-unique is broken for resumed sessions unless EMS is used. */ + if (!ssl->session->extended_master_secret) { + goto err; + } + finished = ssl->s3->previous_server_finished; + finished_len = ssl->s3->previous_server_finished_len; + } + + if (!ssl->s3->initial_handshake_complete || + ssl->version < TLS1_VERSION) { + goto err; + } + + *out_len = finished_len; + if (finished_len > max_out) { + *out_len = max_out; + } + + memcpy(out, finished, *out_len); + return 1; + +err: + *out_len = 0; + memset(out, 0, max_out); + return 0; +} + int SSL_CTX_sess_connect(const SSL_CTX *ctx) { return 0; } int SSL_CTX_sess_connect_good(const SSL_CTX *ctx) { return 0; } int SSL_CTX_sess_connect_renegotiate(const SSL_CTX *ctx) { return 0; } diff --git a/src/ssl/ssl_sess.c b/src/ssl/ssl_sess.c index 3eb428f..9ab4585 100644 --- a/src/ssl/ssl_sess.c +++ b/src/ssl/ssl_sess.c @@ -295,13 +295,11 @@ int ssl_get_new_session(SSL *s, int session) { } /* Choose which callback will set the session ID */ - CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); if (s->generate_session_id) { cb = s->generate_session_id; } else if (s->initial_ctx->generate_session_id) { cb = s->initial_ctx->generate_session_id; } - CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); /* Choose a session ID */ tmp = ss->session_id_length; @@ -419,10 +417,14 @@ int ssl_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx) { return 0; } memcpy(data.session_id, ctx->session_id, ctx->session_id_len); - CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); - ret = SSL_SESSION_up_ref(lh_SSL_SESSION_retrieve(s->initial_ctx->sessions, - &data)); - CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); + + CRYPTO_MUTEX_lock_read(&s->initial_ctx->lock); + ret = lh_SSL_SESSION_retrieve(s->initial_ctx->sessions, &data); + CRYPTO_MUTEX_unlock(&s->initial_ctx->lock); + + if (ret != NULL) { + SSL_SESSION_up_ref(ret); + } } if (try_session_cache && ret == NULL && @@ -524,8 +526,9 @@ int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) { SSL_SESSION_up_ref(c); /* if session c is in already in cache, we take back the increment later */ - CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + CRYPTO_MUTEX_lock_write(&ctx->lock); if (!lh_SSL_SESSION_insert(ctx->sessions, &s, c)) { + CRYPTO_MUTEX_unlock(&ctx->lock); return 0; } @@ -566,7 +569,7 @@ int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) { } } - CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); + CRYPTO_MUTEX_unlock(&ctx->lock); return ret; } @@ -580,7 +583,7 @@ static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lock) { if (c != NULL && c->session_id_length != 0) { if (lock) { - CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + CRYPTO_MUTEX_lock_write(&ctx->lock); } r = lh_SSL_SESSION_retrieve(ctx->sessions, c); if (r == c) { @@ -590,7 +593,7 @@ static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lock) { } if (lock) { - CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); + CRYPTO_MUTEX_unlock(&ctx->lock); } if (ret) { @@ -607,14 +610,14 @@ static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lock) { SSL_SESSION *SSL_SESSION_up_ref(SSL_SESSION *session) { if (session) { - CRYPTO_add(&session->references, 1, CRYPTO_LOCK_SSL_SESSION); + CRYPTO_refcount_inc(&session->references); } return session; } void SSL_SESSION_free(SSL_SESSION *session) { if (session == NULL || - CRYPTO_add(&session->references, -1, CRYPTO_LOCK_SSL_SESSION) > 0) { + !CRYPTO_refcount_dec_and_test_zero(&session->references)) { return; } @@ -741,18 +744,18 @@ static void timeout_doall_arg(SSL_SESSION *sess, void *void_param) { } } -void SSL_CTX_flush_sessions(SSL_CTX *s, long t) { +void SSL_CTX_flush_sessions(SSL_CTX *ctx, long t) { TIMEOUT_PARAM tp; - tp.ctx = s; - tp.cache = s->sessions; + tp.ctx = ctx; + tp.cache = ctx->sessions; if (tp.cache == NULL) { return; } tp.time = t; - CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + CRYPTO_MUTEX_lock_write(&ctx->lock); lh_SSL_SESSION_doall_arg(tp.cache, timeout_doall_arg, &tp); - CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); + CRYPTO_MUTEX_unlock(&ctx->lock); } int ssl_clear_bad_session(SSL *s) { diff --git a/src/ssl/ssl_stat.c b/src/ssl/ssl_stat.c index 8bed9ad..fa5541b 100644 --- a/src/ssl/ssl_stat.c +++ b/src/ssl/ssl_stat.c @@ -105,14 +105,6 @@ const char *SSL_state_string_long(const SSL *s) { str = "SSL renegotiate ciphers"; break; - case SSL_ST_BEFORE | SSL_ST_CONNECT: - str = "before/connect initialization"; - break; - - case SSL_ST_BEFORE | SSL_ST_ACCEPT: - str = "before/accept initialization"; - break; - /* SSLv3 additions */ case SSL3_ST_CW_CLNT_HELLO_A: str = "SSLv3 write client hello A"; diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc index 7886304..b29d28c 100644 --- a/src/ssl/ssl_test.cc +++ b/src/ssl/ssl_test.cc @@ -335,6 +335,30 @@ static const char kCustomSession[] = "q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG" "BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBLADBAEF"; +// kBadSessionExtraField is a custom serialized SSL_SESSION generated by replacing +// the final (optional) element of |kCustomSession| with tag number 30. +static const char kBadSessionExtraField[] = + "MIIBdgIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ" + "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH" + "IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tqAcE" + "BXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXqKwOBfF9vE4KX0Nxe" + "LwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362zZnY27GpTw+Kwd751" + "CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3+inbMaVigtK4PLyP" + "q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG" + "BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBL4DBAEF"; + +// kBadSessionVersion is a custom serialized SSL_SESSION generated by replacing +// the version of |kCustomSession| with 2. +static const char kBadSessionVersion[] = + "MIIBdgIBAgICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ" + "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH" + "IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tqAcE" + "BXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXqKwOBfF9vE4KX0Nxe" + "LwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362zZnY27GpTw+Kwd751" + "CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3+inbMaVigtK4PLyP" + "q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG" + "BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBLADBAEF"; + static bool DecodeBase64(std::vector<uint8_t> *out, const char *in) { size_t len; if (!EVP_DecodedLength(&len, strlen(in))) { @@ -416,6 +440,23 @@ static bool TestSSL_SESSIONEncoding(const char *input_b64) { return true; } +static bool TestBadSSL_SESSIONEncoding(const char *input_b64) { + std::vector<uint8_t> input; + if (!DecodeBase64(&input, input_b64)) { + return false; + } + + // Verify that the SSL_SESSION fails to decode. + const uint8_t *ptr = bssl::vector_data(&input); + ScopedSSL_SESSION session(d2i_SSL_SESSION(NULL, &ptr, input.size())); + if (session) { + fprintf(stderr, "d2i_SSL_SESSION unexpectedly succeeded\n"); + return false; + } + ERR_clear_error(); + return true; +} + static bool TestDefaultVersion(uint16_t version, const SSL_METHOD *(*method)(void)) { ScopedSSL_CTX ctx(SSL_CTX_new(method())); @@ -431,6 +472,9 @@ static bool CipherGetRFCName(std::string *out, uint16_t value) { return false; } ScopedOpenSSLString rfc_name(SSL_CIPHER_get_rfc_name(cipher)); + if (!rfc_name) { + return false; + } out->assign(rfc_name.get()); return true; } @@ -491,6 +535,8 @@ int main(void) { if (!TestCipherRules() || !TestSSL_SESSIONEncoding(kOpenSSLSession) || !TestSSL_SESSIONEncoding(kCustomSession) || + !TestBadSSL_SESSIONEncoding(kBadSessionExtraField) || + !TestBadSSL_SESSIONEncoding(kBadSessionVersion) || !TestDefaultVersion(0, &TLS_method) || !TestDefaultVersion(SSL3_VERSION, &SSLv3_method) || !TestDefaultVersion(TLS1_VERSION, &TLSv1_method) || diff --git a/src/ssl/t1_enc.c b/src/ssl/t1_enc.c index 3eaffe7..6bd80c3 100644 --- a/src/ssl/t1_enc.c +++ b/src/ssl/t1_enc.c @@ -245,7 +245,7 @@ int tls1_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret, /* Count number of digests and partition |secret| evenly. */ count = 0; for (idx = 0; ssl_get_handshake_digest(&m, &md, idx); idx++) { - if ((m << TLS1_PRF_DGST_SHIFT) & ssl_get_algorithm2(s)) { + if (m & ssl_get_algorithm2(s)) { count++; } } @@ -260,7 +260,7 @@ int tls1_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret, S1 = secret; memset(out, 0, out_len); for (idx = 0; ssl_get_handshake_digest(&m, &md, idx); idx++) { - if ((m << TLS1_PRF_DGST_SHIFT) & ssl_get_algorithm2(s)) { + if (m & ssl_get_algorithm2(s)) { /* If |count| is 2 and |secret_len| is odd, |secret| is partitioned into * two halves with an overlapping byte. */ if (!tls1_P_hash(tmp, out_len, md, S1, len + (secret_len & 1), @@ -292,114 +292,6 @@ static int tls1_generate_key_block(SSL *s, uint8_t *out, size_t out_len) { SSL3_RANDOM_SIZE); } -/* tls1_aead_ctx_init allocates |*aead_ctx|, if needed and returns 1. It - * returns 0 on malloc error. */ -static int tls1_aead_ctx_init(SSL_AEAD_CTX **aead_ctx) { - if (*aead_ctx != NULL) { - EVP_AEAD_CTX_cleanup(&(*aead_ctx)->ctx); - } else { - *aead_ctx = (SSL_AEAD_CTX *)OPENSSL_malloc(sizeof(SSL_AEAD_CTX)); - if (*aead_ctx == NULL) { - OPENSSL_PUT_ERROR(SSL, tls1_aead_ctx_init, ERR_R_MALLOC_FAILURE); - return 0; - } - } - - return 1; -} - -static int tls1_change_cipher_state_aead(SSL *s, char is_read, - const uint8_t *key, unsigned key_len, - const uint8_t *iv, unsigned iv_len, - const uint8_t *mac_secret, - unsigned mac_secret_len) { - const EVP_AEAD *aead = s->s3->tmp.new_aead; - SSL_AEAD_CTX *aead_ctx; - /* merged_key is used to merge the MAC, cipher, and IV keys for an AEAD which - * simulates pre-AEAD cipher suites. */ - uint8_t merged_key[EVP_AEAD_MAX_KEY_LENGTH]; - - if (mac_secret_len > 0) { - /* This is a "stateful" AEAD (for compatibility with pre-AEAD cipher - * suites). */ - if (mac_secret_len + key_len + iv_len > sizeof(merged_key)) { - OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state_aead, - ERR_R_INTERNAL_ERROR); - return 0; - } - memcpy(merged_key, mac_secret, mac_secret_len); - memcpy(merged_key + mac_secret_len, key, key_len); - memcpy(merged_key + mac_secret_len + key_len, iv, iv_len); - key = merged_key; - key_len += mac_secret_len; - key_len += iv_len; - } - - if (is_read) { - if (!tls1_aead_ctx_init(&s->aead_read_ctx)) { - return 0; - } - aead_ctx = s->aead_read_ctx; - } else { - if (SSL_IS_DTLS(s) && s->aead_write_ctx != NULL) { - /* DTLS renegotiation is unsupported, so a CCS can only switch away from - * the NULL cipher. This simplifies renegotiation. */ - OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state_aead, - ERR_R_INTERNAL_ERROR); - return 0; - } - if (!tls1_aead_ctx_init(&s->aead_write_ctx)) { - return 0; - } - aead_ctx = s->aead_write_ctx; - } - - if (!EVP_AEAD_CTX_init_with_direction( - &aead_ctx->ctx, aead, key, key_len, EVP_AEAD_DEFAULT_TAG_LENGTH, - is_read ? evp_aead_open : evp_aead_seal)) { - OPENSSL_free(aead_ctx); - if (is_read) { - s->aead_read_ctx = NULL; - } else { - s->aead_write_ctx = NULL; - } - - return 0; - } - - if (mac_secret_len == 0) { - /* For a real AEAD, the IV is the fixed part of the nonce. */ - if (iv_len > sizeof(aead_ctx->fixed_nonce)) { - OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state_aead, ERR_R_INTERNAL_ERROR); - return 0; - } - - memcpy(aead_ctx->fixed_nonce, iv, iv_len); - aead_ctx->fixed_nonce_len = iv_len; - aead_ctx->variable_nonce_included_in_record = - (s->s3->tmp.new_cipher->algorithm2 & - SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD) != 0; - aead_ctx->random_variable_nonce = 0; - aead_ctx->omit_length_in_ad = 0; - } else { - aead_ctx->fixed_nonce_len = 0; - aead_ctx->variable_nonce_included_in_record = 1; - aead_ctx->random_variable_nonce = 1; - aead_ctx->omit_length_in_ad = 1; - } - aead_ctx->variable_nonce_len = s->s3->tmp.new_variable_iv_len; - aead_ctx->omit_version_in_ad = (s->version == SSL3_VERSION); - - if (aead_ctx->variable_nonce_len + aead_ctx->fixed_nonce_len != - EVP_AEAD_nonce_length(aead)) { - OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state_aead, ERR_R_INTERNAL_ERROR); - return 0; - } - aead_ctx->tag_len = EVP_AEAD_max_overhead(aead); - - return 1; -} - int tls1_change_cipher_state(SSL *s, int which) { /* 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. */ @@ -470,8 +362,21 @@ int tls1_change_cipher_state(SSL *s, int which) { return 0; } - return tls1_change_cipher_state_aead(s, is_read, key, key_len, iv, iv_len, - mac_secret, mac_secret_len); + if (is_read) { + SSL_AEAD_CTX_free(s->aead_read_ctx); + s->aead_read_ctx = SSL_AEAD_CTX_new( + evp_aead_open, ssl3_version_from_wire(s, s->version), + s->s3->tmp.new_cipher, key, key_len, mac_secret, mac_secret_len, iv, + iv_len); + return s->aead_read_ctx != NULL; + } else { + SSL_AEAD_CTX_free(s->aead_write_ctx); + s->aead_write_ctx = SSL_AEAD_CTX_new( + evp_aead_seal, ssl3_version_from_wire(s, s->version), + s->s3->tmp.new_cipher, key, key_len, mac_secret, mac_secret_len, iv, + iv_len); + return s->aead_write_ctx != NULL; + } } int tls1_setup_key_block(SSL *s) { @@ -564,153 +469,6 @@ cipher_unavailable_err: return 0; } -/* tls1_enc encrypts/decrypts the record in |s->wrec| / |s->rrec|, - * respectively. It returns one on success and zero on failure. */ -int tls1_enc(SSL *s, int send) { - SSL3_RECORD *rec; - const SSL_AEAD_CTX *aead; - - if (send) { - rec = &s->s3->wrec; - aead = s->aead_write_ctx; - } else { - rec = &s->s3->rrec; - aead = s->aead_read_ctx; - } - - if (aead == NULL) { - /* Handle the initial NULL cipher. */ - memmove(rec->data, rec->input, rec->length); - rec->input = rec->data; - return 1; - } - - uint8_t ad[13], *seq, *in, *out, nonce[EVP_AEAD_MAX_NONCE_LENGTH]; - unsigned nonce_used; - size_t n, ad_len; - - seq = send ? s->s3->write_sequence : s->s3->read_sequence; - - if (SSL_IS_DTLS(s)) { - uint8_t dtlsseq[9], *p = dtlsseq; - - s2n(send ? s->d1->w_epoch : s->d1->r_epoch, p); - memcpy(p, &seq[2], 6); - memcpy(ad, dtlsseq, 8); - } else { - memcpy(ad, seq, 8); - if (!ssl3_record_sequence_update(seq, 8)) { - return 0; - } - } - - ad[8] = rec->type; - ad_len = 9; - if (!aead->omit_version_in_ad) { - ad[ad_len++] = (uint8_t)(s->version >> 8); - ad[ad_len++] = (uint8_t)(s->version); - } - - if (aead->fixed_nonce_len + aead->variable_nonce_len > sizeof(nonce)) { - OPENSSL_PUT_ERROR(SSL, tls1_enc, ERR_R_INTERNAL_ERROR); - return 0; - } - - memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len); - nonce_used = aead->fixed_nonce_len; - - if (send) { - size_t len = rec->length; - size_t eivlen = 0; - in = rec->input; - out = rec->data; - - uint8_t *variable_nonce = nonce + nonce_used; - if (aead->random_variable_nonce) { - assert(aead->variable_nonce_included_in_record); - if (!RAND_bytes(nonce + nonce_used, aead->variable_nonce_len)) { - return 0; - } - } else { - /* When sending we use the sequence number as the variable part of the - * nonce. */ - if (aead->variable_nonce_len != 8) { - OPENSSL_PUT_ERROR(SSL, tls1_enc, ERR_R_INTERNAL_ERROR); - return 0; - } - memcpy(nonce + nonce_used, ad, aead->variable_nonce_len); - } - nonce_used += aead->variable_nonce_len; - - /* in do_ssl3_write, rec->input is moved forward by variable_nonce_len in - * order to leave space for the variable nonce. Thus we can copy the - * sequence number bytes into place without overwriting any of the - * plaintext. */ - if (aead->variable_nonce_included_in_record) { - memcpy(out, variable_nonce, aead->variable_nonce_len); - len -= aead->variable_nonce_len; - eivlen = aead->variable_nonce_len; - } - - if (!aead->omit_length_in_ad) { - ad[ad_len++] = len >> 8; - ad[ad_len++] = len & 0xff; - } - - if (!EVP_AEAD_CTX_seal(&aead->ctx, out + eivlen, &n, len + aead->tag_len, - nonce, nonce_used, in + eivlen, len, ad, ad_len)) { - return 0; - } - - if (aead->variable_nonce_included_in_record) { - n += aead->variable_nonce_len; - } - } else { - /* receive */ - size_t len = rec->length; - - if (rec->data != rec->input) { - OPENSSL_PUT_ERROR(SSL, tls1_enc, ERR_R_INTERNAL_ERROR); - return 0; - } - out = in = rec->input; - - if (len < aead->variable_nonce_len) { - return 0; - } - memcpy(nonce + nonce_used, - aead->variable_nonce_included_in_record ? in : ad, - aead->variable_nonce_len); - nonce_used += aead->variable_nonce_len; - - if (aead->variable_nonce_included_in_record) { - in += aead->variable_nonce_len; - len -= aead->variable_nonce_len; - out += aead->variable_nonce_len; - } - - if (!aead->omit_length_in_ad) { - if (len < aead->tag_len) { - return 0; - } - size_t plaintext_len = len - aead->tag_len; - - ad[ad_len++] = plaintext_len >> 8; - ad[ad_len++] = plaintext_len & 0xff; - } - - if (!EVP_AEAD_CTX_open(&aead->ctx, out, &n, rec->length, nonce, nonce_used, in, - len, ad, ad_len)) { - return 0; - } - - rec->data = rec->input = out; - } - - rec->length = n; - return 1; -} - int tls1_cert_verify_mac(SSL *s, int md_nid, uint8_t *out) { unsigned int ret; EVP_MD_CTX ctx, *d = NULL; @@ -796,6 +554,11 @@ int tls1_final_finish_mac(SSL *s, const char *str, int slen, uint8_t *out) { int err = 0; int digests_len; + /* At this point, the handshake should have released the handshake buffer on + * its own. + * TODO(davidben): Apart from initialization, the handshake buffer should be + * orthogonal to the handshake digest. https://crbug.com/492371 */ + assert(s->s3->handshake_buffer == NULL); if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, free_handshake_buffer)) { return 0; diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c index 58b7f04..9e5c011 100644 --- a/src/ssl/t1_lib.c +++ b/src/ssl/t1_lib.c @@ -129,7 +129,6 @@ static int ssl_check_clienthello_tlsext(SSL *s); static int ssl_check_serverhello_tlsext(SSL *s); const SSL3_ENC_METHOD TLSv1_enc_data = { - tls1_enc, tls1_prf, tls1_setup_key_block, tls1_generate_master_secret, @@ -144,7 +143,6 @@ const SSL3_ENC_METHOD TLSv1_enc_data = { }; const SSL3_ENC_METHOD TLSv1_1_enc_data = { - tls1_enc, tls1_prf, tls1_setup_key_block, tls1_generate_master_secret, @@ -159,7 +157,6 @@ const SSL3_ENC_METHOD TLSv1_1_enc_data = { }; const SSL3_ENC_METHOD TLSv1_2_enc_data = { - tls1_enc, tls1_prf, tls1_setup_key_block, tls1_generate_master_secret, @@ -874,7 +871,7 @@ uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit, } /* Add RI if renegotiating */ - if (s->renegotiate) { + if (s->s3->initial_handshake_complete) { int el; if (!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0)) { @@ -908,7 +905,12 @@ uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit, if (!(SSL_get_options(s) & SSL_OP_NO_TICKET)) { int ticklen = 0; - if (!s->new_session && s->session && s->session->tlsext_tick) { + /* Renegotiation does not participate in session resumption. However, still + * advertise the extension to avoid potentially breaking servers which carry + * over the state from the previous handshake, such as OpenSSL servers + * without upstream's 3c3f0259238594d77264a78944d409f2127642c4. */ + if (!s->s3->initial_handshake_complete && s->session != NULL && + s->session->tlsext_tick != NULL) { ticklen = s->session->tlsext_ticklen; } @@ -957,7 +959,7 @@ uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit, s2n(0, ret); } - if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len && + if (s->ctx->next_proto_select_cb && !s->s3->initial_handshake_complete && !SSL_IS_DTLS(s)) { /* The client advertises an emtpy extension to indicate its support for * Next Protocol Negotiation */ @@ -968,7 +970,7 @@ uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit, s2n(0, ret); } - if (s->signed_cert_timestamps_enabled && !s->s3->tmp.finish_md_len) { + if (s->signed_cert_timestamps_enabled) { /* The client advertises an empty extension to indicate its support for * certificate timestamps. */ if (limit - ret - 4 < 0) { @@ -978,7 +980,7 @@ uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit, s2n(0, ret); } - if (s->alpn_client_proto_list && !s->s3->tmp.finish_md_len) { + if (s->alpn_client_proto_list && !s->s3->initial_handshake_complete) { if ((size_t)(limit - ret) < 6 + s->alpn_client_proto_list_len) { return NULL; } @@ -1587,29 +1589,16 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) { return 0; } } else if (type == TLSEXT_TYPE_next_proto_neg && - s->s3->tmp.finish_md_len == 0 && s->s3->alpn_selected == NULL && - !SSL_IS_DTLS(s)) { + !s->s3->initial_handshake_complete && + s->s3->alpn_selected == NULL && !SSL_IS_DTLS(s)) { /* The extension must be empty. */ if (CBS_len(&extension) != 0) { *out_alert = SSL_AD_DECODE_ERROR; return 0; } - - /* We shouldn't accept this extension on a renegotiation. - * - * s->new_session will be set on renegotiation, but we probably shouldn't - * rely that it couldn't be set on the initial renegotation too in - * certain cases (when there's some other reason to disallow resuming an - * earlier session -- the current code won't be doing anything like that, - * but this might change). - - * A valid sign that there's been a previous handshake in this connection - * is if s->s3->tmp.finish_md_len > 0. (We are talking about a check - * that will happen in the Hello protocol round, well before a new - * Finished message could have been computed.) */ s->s3->next_proto_neg_seen = 1; } else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation && - s->ctx->alpn_select_cb && s->s3->tmp.finish_md_len == 0) { + s->ctx->alpn_select_cb && !s->s3->initial_handshake_complete) { if (!tls1_alpn_handle_client_hello(s, &extension, out_alert)) { return 0; } @@ -1652,7 +1641,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) { ri_check: /* Need RI if renegotiating */ - if (!renegotiate_seen && s->renegotiate && + if (!renegotiate_seen && s->s3->initial_handshake_complete && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) { *out_alert = SSL_AD_HANDSHAKE_FAILURE; OPENSSL_PUT_ERROR(SSL, ssl_scan_clienthello_tlsext, @@ -1791,8 +1780,7 @@ static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) { /* Set a flag to expect a CertificateStatus message */ s->s3->tmp.certificate_status_expected = 1; } else if (type == TLSEXT_TYPE_next_proto_neg && - s->s3->tmp.finish_md_len == 0 && - !SSL_IS_DTLS(s)) { + !s->s3->initial_handshake_complete && !SSL_IS_DTLS(s)) { uint8_t *selected; uint8_t selected_len; @@ -1824,7 +1812,8 @@ static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) { s->next_proto_negotiated_len = selected_len; s->s3->next_proto_neg_seen = 1; - } else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation) { + } else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation && + !s->s3->initial_handshake_complete) { CBS protocol_name_list, protocol_name; /* We must have requested it. */ diff --git a/src/ssl/test/CMakeLists.txt b/src/ssl/test/CMakeLists.txt index a0d7a5e..3b07903 100644 --- a/src/ssl/test/CMakeLists.txt +++ b/src/ssl/test/CMakeLists.txt @@ -5,9 +5,10 @@ add_executable( async_bio.cc bssl_shim.cc - malloc.cc packeted_bio.cc test_config.cc + + $<TARGET_OBJECTS:test_support> ) target_link_libraries(bssl_shim ssl crypto) diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc index 1cf96f2..40cb149 100644 --- a/src/ssl/test/bssl_shim.cc +++ b/src/ssl/test/bssl_shim.cc @@ -406,14 +406,6 @@ static ScopedSSL_CTX SetupCtx(const TestConfig *config) { return nullptr; } - if (config->is_dtls) { - // DTLS needs read-ahead to function on a datagram BIO. - // - // TODO(davidben): this should not be necessary. DTLS code should only - // expect a datagram BIO. - SSL_CTX_set_read_ahead(ssl_ctx.get(), 1); - } - if (!SSL_CTX_set_cipher_list(ssl_ctx.get(), "ALL")) { return nullptr; } @@ -599,6 +591,9 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx, if (config->allow_unsafe_legacy_renegotiation) { SSL_set_options(ssl.get(), SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); } + if (config->no_legacy_server_connect) { + SSL_clear_options(ssl.get(), SSL_OP_LEGACY_SERVER_CONNECT); + } if (!config->expected_channel_id.empty()) { SSL_enable_tls_channel_id(ssl.get()); } @@ -660,8 +655,9 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx, !SSL_set_cipher_list(ssl.get(), config->cipher.c_str())) { return false; } - if (config->reject_peer_renegotiations) { - SSL_set_reject_peer_renegotiations(ssl.get(), 1); + if (!config->reject_peer_renegotiations) { + /* Renegotiations are disabled by default. */ + SSL_set_reject_peer_renegotiations(ssl.get(), 0); } int sock = Connect(config->port); @@ -703,6 +699,11 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx, } } + if (SSL_get_current_cipher(ssl.get()) != nullptr) { + fprintf(stderr, "non-null cipher before handshake\n"); + return false; + } + int ret; if (config->implicit_handshake) { if (config->is_server) { @@ -722,6 +723,11 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx, return false; } + if (SSL_get_current_cipher(ssl.get()) == nullptr) { + fprintf(stderr, "null cipher after handshake\n"); + return false; + } + if (is_resume && (!!SSL_session_reused(ssl.get()) == config->expect_session_miss)) { fprintf(stderr, "session was%s reused\n", @@ -834,30 +840,6 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx, } } - if (config->renegotiate) { - if (config->async) { - fprintf(stderr, "-renegotiate is not supported with -async.\n"); - return false; - } - if (config->implicit_handshake) { - fprintf(stderr, "-renegotiate is not supported with -implicit-handshake.\n"); - return false; - } - - SSL_renegotiate(ssl.get()); - - ret = SSL_do_handshake(ssl.get()); - if (ret != 1) { - return false; - } - - SSL_set_state(ssl.get(), SSL_ST_ACCEPT); - ret = SSL_do_handshake(ssl.get()); - if (ret != 1) { - return false; - } - } - if (config->export_keying_material > 0) { std::vector<uint8_t> result( static_cast<size_t>(config->export_keying_material)); @@ -874,6 +856,26 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx, } } + if (config->tls_unique) { + uint8_t tls_unique[16]; + size_t tls_unique_len; + if (!SSL_get_tls_unique(ssl.get(), tls_unique, &tls_unique_len, + sizeof(tls_unique))) { + fprintf(stderr, "failed to get tls-unique\n"); + return false; + } + + if (tls_unique_len != 12) { + fprintf(stderr, "expected 12 bytes of tls-unique but got %u", + static_cast<unsigned>(tls_unique_len)); + return false; + } + + if (WriteAll(ssl.get(), tls_unique, tls_unique_len) < 0) { + return false; + } + } + if (config->write_different_record_sizes) { if (config->is_dtls) { fprintf(stderr, "write_different_record_sizes not supported for DTLS\n"); diff --git a/src/ssl/test/malloc.cc b/src/ssl/test/malloc.cc deleted file mode 100644 index 2ec5582..0000000 --- a/src/ssl/test/malloc.cc +++ /dev/null @@ -1,139 +0,0 @@ -/* Copyright (c) 2014, Google Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - -#include <openssl/base.h> - -#if defined(__has_feature) -#if __has_feature(address_sanitizer) -#define OPENSSL_ASAN -#endif -#endif - -// This file isn't built on ARM or Aarch64 because we link statically in those -// builds and trying to override malloc in a static link doesn't work. It's also -// disabled on ASan builds as this interferes with ASan's malloc interceptor. -// -// TODO(davidben): See if this and ASan's interceptors can be made to coexist. -#if defined(__linux__) && !defined(OPENSSL_ARM) && \ - !defined(OPENSSL_AARCH64) && !defined(OPENSSL_ASAN) - -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include <new> - - -/* This file defines overrides for the standard allocation functions that allow - * a given allocation to be made to fail for testing. If the program is run - * with MALLOC_NUMBER_TO_FAIL set to a base-10 number then that allocation will - * return NULL. If MALLOC_ABORT_ON_FAIL is also defined then the allocation - * will abort() rather than return NULL. - * - * This code is not thread safe. */ - -static uint64_t current_malloc_count = 0; -static uint64_t malloc_number_to_fail = 0; -static char failure_enabled = 0, abort_on_fail = 0; -static int in_call = 0; - -extern "C" { -/* These are other names for the standard allocation functions. */ -extern void *__libc_malloc(size_t size); -extern void *__libc_calloc(size_t num_elems, size_t size); -extern void *__libc_realloc(void *ptr, size_t size); -} - -static void exit_handler(void) { - if (failure_enabled && current_malloc_count > malloc_number_to_fail) { - _exit(88); - } -} - -static void cpp_new_handler() { - // Return to try again. It won't fail a second time. - return; -} - -/* should_fail_allocation returns true if the current allocation should fail. */ -static int should_fail_allocation() { - static int init = 0; - char should_fail; - - if (in_call) { - return 0; - } - - in_call = 1; - - if (!init) { - const char *env = getenv("MALLOC_NUMBER_TO_FAIL"); - if (env != NULL && env[0] != 0) { - char *endptr; - malloc_number_to_fail = strtoull(env, &endptr, 10); - if (*endptr == 0) { - failure_enabled = 1; - atexit(exit_handler); - std::set_new_handler(cpp_new_handler); - } - } - abort_on_fail = (NULL != getenv("MALLOC_ABORT_ON_FAIL")); - init = 1; - } - - in_call = 0; - - if (!failure_enabled) { - return 0; - } - - should_fail = (current_malloc_count == malloc_number_to_fail); - current_malloc_count++; - - if (should_fail && abort_on_fail) { - abort(); - } - return should_fail; -} - -extern "C" { - -void *malloc(size_t size) { - if (should_fail_allocation()) { - return NULL; - } - - return __libc_malloc(size); -} - -void *calloc(size_t num_elems, size_t size) { - if (should_fail_allocation()) { - return NULL; - } - - return __libc_calloc(num_elems, size); -} - -void *realloc(void *ptr, size_t size) { - if (should_fail_allocation()) { - return NULL; - } - - return __libc_realloc(ptr, size); -} - -} // extern "C" - -#endif /* defined(linux) && !ARM && !AARCH64 && !ASAN */ diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go index 4ac7250..edebba1 100644 --- a/src/ssl/test/runner/common.go +++ b/src/ssl/test/runner/common.go @@ -188,6 +188,7 @@ type ConnectionState struct { VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates ChannelID *ecdsa.PublicKey // the channel ID for this connection SRTPProtectionProfile uint16 // the negotiated DTLS-SRTP protection profile + TLSUnique []byte } // ClientAuthType declares the policy the server will follow for @@ -478,7 +479,9 @@ type ProtocolBugs struct { // MaxHandshakeRecordLength, if non-zero, is the maximum size of a // handshake record. Handshake messages will be split into multiple // records at the specified size, except that the client_version will - // never be fragmented. + // never be fragmented. For DTLS, it is the maximum handshake fragment + // size, not record size; DTLS allows multiple handshake fragments in a + // single handshake record. See |PackHandshakeFragments|. MaxHandshakeRecordLength int // FragmentClientVersion will allow MaxHandshakeRecordLength to apply to @@ -681,13 +684,14 @@ type ProtocolBugs struct { // fragments in DTLS. SendEmptyFragments bool - // NeverResumeOnRenego, if true, causes renegotiations to always be full - // handshakes. - NeverResumeOnRenego bool + // SendSplitAlert, if true, causes an alert to be sent with the header + // and record body split across multiple packets. The peer should + // discard these packets rather than process it. + SendSplitAlert bool - // NoSignatureAlgorithmsOnRenego, if true, causes renegotiations to omit - // the signature_algorithms extension. - NoSignatureAlgorithmsOnRenego bool + // FailIfResumeOnRenego, if true, causes renegotiations to fail if the + // client offers a resumption or the server accepts one. + FailIfResumeOnRenego bool // IgnorePeerCipherPreferences, if true, causes the peer's cipher // preferences to be ignored. @@ -707,6 +711,22 @@ type ProtocolBugs struct { // BadFinished, if true, causes the Finished hash to be broken. BadFinished bool + + // DHGroupPrime, if not nil, is used to define the (finite field) + // Diffie-Hellman group. The generator used is always two. + DHGroupPrime *big.Int + + // PackHandshakeFragments, if true, causes handshake fragments to be + // packed into individual handshake records, up to the specified record + // size. + PackHandshakeFragments int + + // PackHandshakeRecords, if true, causes handshake records to be packed + // into individual packets, up to the specified packet size. + PackHandshakeRecords int + + // EnableAllCiphersInDTLS, if true, causes RC4 to be enabled in DTLS. + EnableAllCiphersInDTLS bool } func (c *Config) serverInit() { diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go index fd198ca..adbc1c3 100644 --- a/src/ssl/test/runner/conn.go +++ b/src/ssl/test/runner/conn.go @@ -44,7 +44,11 @@ type Conn struct { // opposed to the ones presented by the server. verifiedChains [][]*x509.Certificate // serverName contains the server name indicated by the client, if any. - serverName string + serverName string + // firstFinished contains the first Finished hash sent during the + // handshake. This is the "tls-unique" channel binding value. + firstFinished [12]byte + clientRandom, serverRandom [32]byte masterSecret [48]byte @@ -1260,6 +1264,15 @@ func (c *Conn) Handshake() error { return nil } + if c.isDTLS && c.config.Bugs.SendSplitAlert { + c.conn.Write([]byte{ + byte(recordTypeAlert), // type + 0xfe, 0xff, // version + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // sequence + 0x0, 0x2, // length + }) + c.conn.Write([]byte{alertLevelError, byte(alertInternalError)}) + } if c.isClient { c.handshakeErr = c.clientHandshake() } else { @@ -1290,6 +1303,7 @@ func (c *Conn) ConnectionState() ConnectionState { state.ServerName = c.serverName state.ChannelID = c.channelID state.SRTPProtectionProfile = c.srtpProtectionProfile + state.TLSUnique = c.firstFinished[:] } return state diff --git a/src/ssl/test/runner/dtls.go b/src/ssl/test/runner/dtls.go index 85c4247..50f7786 100644 --- a/src/ssl/test/runner/dtls.go +++ b/src/ssl/test/runner/dtls.go @@ -196,6 +196,8 @@ func (c *Conn) dtlsFlushHandshake() error { return nil } + // This is a test-only DTLS implementation, so there is no need to + // retain |c.pendingFragments| for a future retransmit. var fragments [][]byte fragments, c.pendingFragments = c.pendingFragments, fragments @@ -208,38 +210,66 @@ func (c *Conn) dtlsFlushHandshake() error { fragments = tmp } - // Send them all. + maxRecordLen := c.config.Bugs.PackHandshakeFragments + maxPacketLen := c.config.Bugs.PackHandshakeRecords + + // Pack handshake fragments into records. + var records [][]byte for _, fragment := range fragments { if c.config.Bugs.SplitFragmentHeader { - if _, err := c.dtlsWriteRawRecord(recordTypeHandshake, fragment[:2]); err != nil { - return err - } - fragment = fragment[2:] - } else if c.config.Bugs.SplitFragmentBody && len(fragment) > 12 { - if _, err := c.dtlsWriteRawRecord(recordTypeHandshake, fragment[:13]); err != nil { - return err + records = append(records, fragment[:2]) + records = append(records, fragment[2:]) + } else if c.config.Bugs.SplitFragmentBody { + if len(fragment) > 12 { + records = append(records, fragment[:13]) + records = append(records, fragment[13:]) + } else { + records = append(records, fragment) } - fragment = fragment[13:] + } else if i := len(records) - 1; len(records) > 0 && len(records[i])+len(fragment) <= maxRecordLen { + records[i] = append(records[i], fragment...) + } else { + // The fragment will be appended to, so copy it. + records = append(records, append([]byte{}, fragment...)) + } + } + + // Format them into packets. + var packets [][]byte + for _, record := range records { + b, err := c.dtlsSealRecord(recordTypeHandshake, record) + if err != nil { + return err + } + + if i := len(packets) - 1; len(packets) > 0 && len(packets[i])+len(b.data) <= maxPacketLen { + packets[i] = append(packets[i], b.data...) + } else { + // The sealed record will be appended to and reused by + // |c.out|, so copy it. + packets = append(packets, append([]byte{}, b.data...)) } + c.out.freeBlock(b) + } - // TODO(davidben): A real DTLS implementation needs to - // retransmit handshake messages. For testing purposes, we don't - // actually care. - if _, err := c.dtlsWriteRawRecord(recordTypeHandshake, fragment); err != nil { + // Send all the packets. + for _, packet := range packets { + if _, err := c.conn.Write(packet); err != nil { return err } } return nil } -func (c *Conn) dtlsWriteRawRecord(typ recordType, data []byte) (n int, err error) { +// dtlsSealRecord seals a record into a block from |c.out|'s pool. +func (c *Conn) dtlsSealRecord(typ recordType, data []byte) (b *block, err error) { recordHeaderLen := dtlsRecordHeaderLen maxLen := c.config.Bugs.MaxHandshakeRecordLength if maxLen <= 0 { maxLen = 1024 } - b := c.out.newBlock() + b = c.out.newBlock() explicitIVLen := 0 explicitIVIsSeq := false @@ -286,6 +316,14 @@ func (c *Conn) dtlsWriteRawRecord(typ recordType, data []byte) (n int, err error } copy(b.data[recordHeaderLen+explicitIVLen:], data) c.out.encrypt(b, explicitIVLen) + return +} + +func (c *Conn) dtlsWriteRawRecord(typ recordType, data []byte) (n int, err error) { + b, err := c.dtlsSealRecord(typ, data) + if err != nil { + return + } _, err = c.conn.Write(b.data) if err != nil { diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go index 0dac05d..a950313 100644 --- a/src/ssl/test/runner/handshake_client.go +++ b/src/ssl/test/runner/handshake_client.go @@ -115,7 +115,7 @@ NextCipherSuite: continue } // Don't advertise non-DTLS cipher suites on DTLS. - if c.isDTLS && suite.flags&suiteNoDTLS != 0 { + if c.isDTLS && suite.flags&suiteNoDTLS != 0 && !c.config.Bugs.EnableAllCiphersInDTLS { continue } hello.cipherSuites = append(hello.cipherSuites, suiteId) @@ -133,16 +133,13 @@ NextCipherSuite: return errors.New("tls: short read from Rand: " + err.Error()) } - if hello.vers >= VersionTLS12 && !c.config.Bugs.NoSignatureAndHashes && (c.cipherSuite == nil || !c.config.Bugs.NoSignatureAlgorithmsOnRenego) { + if hello.vers >= VersionTLS12 && !c.config.Bugs.NoSignatureAndHashes { hello.signatureAndHashes = c.config.signatureAndHashesForClient() } var session *ClientSessionState var cacheKey string sessionCache := c.config.ClientSessionCache - if c.config.Bugs.NeverResumeOnRenego && c.cipherSuite != nil { - sessionCache = nil - } if sessionCache != nil { hello.ticketSupported = !c.config.SessionTicketsDisabled @@ -316,10 +313,10 @@ NextCipherSuite: if err := hs.readSessionTicket(); err != nil { return err } - if err := hs.readFinished(); err != nil { + if err := hs.readFinished(c.firstFinished[:]); err != nil { return err } - if err := hs.sendFinished(isResume); err != nil { + if err := hs.sendFinished(nil, isResume); err != nil { return err } } else { @@ -329,7 +326,7 @@ NextCipherSuite: if err := hs.establishKeys(); err != nil { return err } - if err := hs.sendFinished(isResume); err != nil { + if err := hs.sendFinished(c.firstFinished[:], isResume); err != nil { return err } // Most retransmits are triggered by a timeout, but the final @@ -344,7 +341,7 @@ NextCipherSuite: if err := hs.readSessionTicket(); err != nil { return err } - if err := hs.readFinished(); err != nil { + if err := hs.readFinished(nil); err != nil { return err } } @@ -727,6 +724,12 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) { } if hs.serverResumedSession() { + // For test purposes, assert that the server never accepts the + // resumption offer on renegotiation. + if c.cipherSuite != nil && c.config.Bugs.FailIfResumeOnRenego { + return false, errors.New("tls: server resumed session on renegotiation") + } + // Restore masterSecret and peerCerts from previous state hs.masterSecret = hs.session.masterSecret c.peerCertificates = hs.session.serverCertificates @@ -737,7 +740,7 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) { return false, nil } -func (hs *clientHandshakeState) readFinished() error { +func (hs *clientHandshakeState) readFinished(out []byte) error { c := hs.c c.readRecord(recordTypeChangeCipherSpec) @@ -764,6 +767,7 @@ func (hs *clientHandshakeState) readFinished() error { } } c.serverVerify = append(c.serverVerify[:0], serverFinished.verifyData...) + copy(out, serverFinished.verifyData) hs.writeServerHash(serverFinished.marshal()) return nil } @@ -807,7 +811,7 @@ func (hs *clientHandshakeState) readSessionTicket() error { return nil } -func (hs *clientHandshakeState) sendFinished(isResume bool) error { +func (hs *clientHandshakeState) sendFinished(out []byte, isResume bool) error { c := hs.c var postCCSBytes []byte @@ -859,6 +863,7 @@ func (hs *clientHandshakeState) sendFinished(isResume bool) error { } else { finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret) } + copy(out, finished.verifyData) if c.config.Bugs.BadFinished { finished.verifyData[0]++ } diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go index 59ed9df..85cc0d2 100644 --- a/src/ssl/test/runner/handshake_server.go +++ b/src/ssl/test/runner/handshake_server.go @@ -69,7 +69,7 @@ func (c *Conn) serverHandshake() error { return err } } - if err := hs.sendFinished(); err != nil { + if err := hs.sendFinished(c.firstFinished[:]); err != nil { return err } // Most retransmits are triggered by a timeout, but the final @@ -81,7 +81,7 @@ func (c *Conn) serverHandshake() error { }); err != nil { return err } - if err := hs.readFinished(isResume); err != nil { + if err := hs.readFinished(nil, isResume); err != nil { return err } c.didResume = true @@ -94,7 +94,7 @@ func (c *Conn) serverHandshake() error { if err := hs.establishKeys(); err != nil { return err } - if err := hs.readFinished(isResume); err != nil { + if err := hs.readFinished(c.firstFinished[:], isResume); err != nil { return err } if c.config.Bugs.AlertBeforeFalseStartTest != 0 { @@ -108,7 +108,7 @@ func (c *Conn) serverHandshake() error { if err := hs.sendSessionTicket(); err != nil { return err } - if err := hs.sendFinished(); err != nil { + if err := hs.sendFinished(nil); err != nil { return err } } @@ -274,6 +274,10 @@ Curves: hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation } + if c.config.Bugs.NoRenegotiationInfo { + hs.hello.secureRenegotiation = nil + } + hs.hello.compressionMethod = compressionNone hs.hello.duplicateExtension = c.config.Bugs.DuplicateExtension if len(hs.clientHello.serverName) > 0 { @@ -333,6 +337,12 @@ Curves: _, hs.ecdsaOk = hs.cert.PrivateKey.(*ecdsa.PrivateKey) + // For test purposes, check that the peer never offers a session when + // renegotiating. + if c.cipherSuite != nil && len(hs.clientHello.sessionId) > 0 && c.config.Bugs.FailIfResumeOnRenego { + return false, errors.New("tls: offered resumption on renegotiation") + } + if hs.checkForResumption() { return true, nil } @@ -382,10 +392,6 @@ Curves: func (hs *serverHandshakeState) checkForResumption() bool { c := hs.c - if c.config.Bugs.NeverResumeOnRenego && c.cipherSuite != nil { - return false - } - if len(hs.clientHello.sessionTicket) > 0 { if c.config.SessionTicketsDisabled { return false @@ -748,7 +754,7 @@ func (hs *serverHandshakeState) establishKeys() error { return nil } -func (hs *serverHandshakeState) readFinished(isResume bool) error { +func (hs *serverHandshakeState) readFinished(out []byte, isResume bool) error { c := hs.c c.readRecord(recordTypeChangeCipherSpec) @@ -817,6 +823,7 @@ func (hs *serverHandshakeState) readFinished(isResume bool) error { return errors.New("tls: client's Finished message is incorrect") } c.clientVerify = append(c.clientVerify[:0], clientFinished.verifyData...) + copy(out, clientFinished.verifyData) hs.writeClientHash(clientFinished.marshal()) return nil @@ -853,11 +860,12 @@ func (hs *serverHandshakeState) sendSessionTicket() error { return nil } -func (hs *serverHandshakeState) sendFinished() error { +func (hs *serverHandshakeState) sendFinished(out []byte) error { c := hs.c finished := new(finishedMsg) finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret) + copy(out, finished.verifyData) if c.config.Bugs.BadFinished { finished.verifyData[0]++ } diff --git a/src/ssl/test/runner/key_agreement.go b/src/ssl/test/runner/key_agreement.go index 5e44b54..2ee0087 100644 --- a/src/ssl/test/runner/key_agreement.go +++ b/src/ssl/test/runner/key_agreement.go @@ -561,11 +561,18 @@ type dheKeyAgreement struct { } func (ka *dheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { - // 2048-bit MODP Group with 256-bit Prime Order Subgroup (RFC - // 5114, Section 2.3) - ka.p, _ = new(big.Int).SetString("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597", 16) - ka.g, _ = new(big.Int).SetString("3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659", 16) - q, _ := new(big.Int).SetString("8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3", 16) + var q *big.Int + if p := config.Bugs.DHGroupPrime; p != nil { + ka.p = p + ka.g = big.NewInt(2) + q = p + } else { + // 2048-bit MODP Group with 256-bit Prime Order Subgroup (RFC + // 5114, Section 2.3) + ka.p, _ = new(big.Int).SetString("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597", 16) + ka.g, _ = new(big.Int).SetString("3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659", 16) + q, _ = new(big.Int).SetString("8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3", 16) + } var err error ka.xOurs, err = rand.Int(config.rand(), q) diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go index ec2fede..bd03cb1 100644 --- a/src/ssl/test/runner/runner.go +++ b/src/ssl/test/runner/runner.go @@ -11,6 +11,7 @@ import ( "fmt" "io" "io/ioutil" + "math/big" "net" "os" "os/exec" @@ -160,6 +161,10 @@ type testCase struct { // resumeSession controls whether a second connection should be tested // which attempts to resume the first session. resumeSession bool + // expectResumeRejected, if true, specifies that the attempted + // resumption must be rejected by the client. This is only valid for a + // serverTest. + expectResumeRejected bool // resumeConfig, if not nil, points to a Config to be used on // resumption. Unless newSessionsOnResume is set, // SessionTicketKey, ServerSessionCache, and @@ -196,6 +201,9 @@ type testCase struct { // flags, if not empty, contains a list of command-line flags that will // be passed to the shim program. flags []string + // testTLSUnique, if true, causes the shim to send the tls-unique value + // which will be compared against the expected value. + testTLSUnique bool } var testCases = []testCase{ @@ -1085,6 +1093,49 @@ var testCases = []testCase{ }, expectedCipher: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, }, + { + protocol: dtls, + name: "SendSplitAlert-Sync", + config: Config{ + Bugs: ProtocolBugs{ + SendSplitAlert: true, + }, + }, + }, + { + protocol: dtls, + name: "SendSplitAlert-Async", + config: Config{ + Bugs: ProtocolBugs{ + SendSplitAlert: true, + }, + }, + flags: []string{"-async"}, + }, + { + protocol: dtls, + name: "PackDTLSHandshake", + config: Config{ + Bugs: ProtocolBugs{ + MaxHandshakeRecordLength: 2, + PackHandshakeFragments: 20, + PackHandshakeRecords: 200, + }, + }, + }, + { + testType: serverTest, + protocol: dtls, + name: "NoRC4-DTLS", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}, + Bugs: ProtocolBugs{ + EnableAllCiphersInDTLS: true, + }, + }, + shouldFail: true, + expectedError: ":NO_SHARED_CIPHER:", + }, } func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error { @@ -1144,16 +1195,20 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i if isResume && test.expectedResumeVersion != 0 { expectedVersion = test.expectedResumeVersion } - if vers := tlsConn.ConnectionState().Version; expectedVersion != 0 && vers != expectedVersion { + connState := tlsConn.ConnectionState() + if vers := connState.Version; expectedVersion != 0 && vers != expectedVersion { return fmt.Errorf("got version %x, expected %x", vers, expectedVersion) } - if cipher := tlsConn.ConnectionState().CipherSuite; test.expectedCipher != 0 && cipher != test.expectedCipher { + if cipher := connState.CipherSuite; test.expectedCipher != 0 && cipher != test.expectedCipher { return fmt.Errorf("got cipher %x, expected %x", cipher, test.expectedCipher) } + if didResume := connState.DidResume; isResume && didResume == test.expectResumeRejected { + return fmt.Errorf("didResume is %t, but we expected the opposite", didResume) + } if test.expectChannelID { - channelID := tlsConn.ConnectionState().ChannelID + channelID := connState.ChannelID if channelID == nil { return fmt.Errorf("no channel ID negotiated") } @@ -1165,18 +1220,18 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i } if expected := test.expectedNextProto; expected != "" { - if actual := tlsConn.ConnectionState().NegotiatedProtocol; actual != expected { + if actual := connState.NegotiatedProtocol; actual != expected { return fmt.Errorf("next proto mismatch: got %s, wanted %s", actual, expected) } } if test.expectedNextProtoType != 0 { - if (test.expectedNextProtoType == alpn) != tlsConn.ConnectionState().NegotiatedProtocolFromALPN { + if (test.expectedNextProtoType == alpn) != connState.NegotiatedProtocolFromALPN { return fmt.Errorf("next proto type mismatch") } } - if p := tlsConn.ConnectionState().SRTPProtectionProfile; p != test.expectedSRTPProtectionProfile { + if p := connState.SRTPProtectionProfile; p != test.expectedSRTPProtectionProfile { return fmt.Errorf("SRTP profile mismatch: got %d, wanted %d", p, test.expectedSRTPProtectionProfile) } @@ -1194,6 +1249,17 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i } } + if test.testTLSUnique { + var peersValue [12]byte + if _, err := io.ReadFull(tlsConn, peersValue[:]); err != nil { + return err + } + expected := tlsConn.ConnectionState().TLSUnique + if !bytes.Equal(peersValue[:], expected) { + return fmt.Errorf("tls-unique mismatch: peer sent %x, but %x was expected", peersValue[:], expected) + } + } + if test.shimWritesFirst { var buf [5]byte _, err := io.ReadFull(tlsConn, buf[:]) @@ -1321,6 +1387,10 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error { panic("Error expected without shouldFail in " + test.name) } + if test.expectResumeRejected && !test.resumeSession { + panic("expectResumeRejected without resumeSession in " + test.name) + } + listener, err := net.ListenTCP("tcp4", &net.TCPAddr{IP: net.IP{127, 0, 0, 1}}) if err != nil { panic(err) @@ -1371,6 +1441,13 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error { flags = append(flags, "-use-export-context") } } + if test.expectResumeRejected { + flags = append(flags, "-expect-session-miss") + } + + if test.testTLSUnique { + flags = append(flags, "-tls-unique") + } flags = append(flags, test.flags...) @@ -1569,6 +1646,14 @@ func isDTLSCipher(suiteName string) bool { return !hasComponent(suiteName, "RC4") } +func bigFromHex(hex string) *big.Int { + ret, ok := new(big.Int).SetString(hex, 16) + if !ok { + panic("failed to parse hex number 0x" + hex) + } + return ret +} + func addCipherSuiteTests() { for _, suite := range testCipherSuites { const psk = "12345" @@ -1667,6 +1752,21 @@ func addCipherSuiteTests() { } } } + + testCases = append(testCases, testCase{ + name: "WeakDH", + config: Config{ + CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256}, + Bugs: ProtocolBugs{ + // This is a 1023-bit prime number, generated + // with: + // openssl gendh 1023 | openssl asn1parse -i + DHGroupPrime: bigFromHex("518E9B7930CE61C6E445C8360584E5FC78D9137C0FFDC880B495D5338ADF7689951A6821C17A76B3ACB8E0156AEA607B7EC406EBEDBB84D8376EB8FE8F8BA1433488BEE0C3EDDFD3A32DBB9481980A7AF6C96BFCF490A094CFFB2B8192C1BB5510B77B658436E27C2D4D023FE3718222AB0CA1273995B51F6D625A4944D0DD4B"), + }, + }, + shouldFail: true, + expectedError: "BAD_DH_P_LENGTH", + }) } func addBadECDSASignatureTests() { @@ -1866,245 +1966,235 @@ func addExtendedMasterSecretTests() { } } - // When a session is resumed, it should still be aware that its master - // secret was generated via EMS and thus it's safe to use tls-unique. - testCases = append(testCases, testCase{ - name: "ExtendedMasterSecret-Resume", - config: Config{ - Bugs: ProtocolBugs{ - RequireExtendedMasterSecret: true, - }, - }, - flags: []string{expectEMSFlag}, - resumeSession: true, - }) + for _, isClient := range []bool{false, true} { + for _, supportedInFirstConnection := range []bool{false, true} { + for _, supportedInResumeConnection := range []bool{false, true} { + boolToWord := func(b bool) string { + if b { + return "Yes" + } + return "No" + } + suffix := boolToWord(supportedInFirstConnection) + "To" + boolToWord(supportedInResumeConnection) + "-" + if isClient { + suffix += "Client" + } else { + suffix += "Server" + } + + supportedConfig := Config{ + Bugs: ProtocolBugs{ + RequireExtendedMasterSecret: true, + }, + } + + noSupportConfig := Config{ + Bugs: ProtocolBugs{ + NoExtendedMasterSecret: true, + }, + } + + test := testCase{ + name: "ExtendedMasterSecret-" + suffix, + resumeSession: true, + } + + if !isClient { + test.testType = serverTest + } + + if supportedInFirstConnection { + test.config = supportedConfig + } else { + test.config = noSupportConfig + } + + if supportedInResumeConnection { + test.resumeConfig = &supportedConfig + } else { + test.resumeConfig = &noSupportConfig + } + + switch suffix { + case "YesToYes-Client", "YesToYes-Server": + // When a session is resumed, it should + // still be aware that its master + // secret was generated via EMS and + // thus it's safe to use tls-unique. + test.flags = []string{expectEMSFlag} + case "NoToYes-Server": + // If an original connection did not + // contain EMS, but a resumption + // handshake does, then a server should + // not resume the session. + test.expectResumeRejected = true + case "YesToNo-Server": + // Resuming an EMS session without the + // EMS extension should cause the + // server to abort the connection. + test.shouldFail = true + test.expectedError = ":RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION:" + case "NoToYes-Client": + // A client should abort a connection + // where the server resumed a non-EMS + // session but echoed the EMS + // extension. + test.shouldFail = true + test.expectedError = ":RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION:" + case "YesToNo-Client": + // A client should abort a connection + // where the server didn't echo EMS + // when the session used it. + test.shouldFail = true + test.expectedError = ":RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION:" + } + + testCases = append(testCases, test) + } + } + } } // Adds tests that try to cover the range of the handshake state machine, under // various conditions. Some of these are redundant with other tests, but they // only cover the synchronous case. func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) { - var suffix string - var flags []string - var maxHandshakeRecordLength int - if protocol == dtls { - suffix = "-DTLS" - } - if async { - suffix += "-Async" - flags = append(flags, "-async") - } else { - suffix += "-Sync" - } - if splitHandshake { - suffix += "-SplitHandshakeRecords" - maxHandshakeRecordLength = 1 - } + var tests []testCase // Basic handshake, with resumption. Client and server, // session ID and session ticket. - testCases = append(testCases, testCase{ - protocol: protocol, - name: "Basic-Client" + suffix, - config: Config{ - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, - }, - flags: flags, + tests = append(tests, testCase{ + name: "Basic-Client", resumeSession: true, }) - testCases = append(testCases, testCase{ - protocol: protocol, - name: "Basic-Client-RenewTicket" + suffix, + tests = append(tests, testCase{ + name: "Basic-Client-RenewTicket", config: Config{ Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - RenewTicketOnResume: true, + RenewTicketOnResume: true, }, }, - flags: flags, resumeSession: true, }) - testCases = append(testCases, testCase{ - protocol: protocol, - name: "Basic-Client-NoTicket" + suffix, + tests = append(tests, testCase{ + name: "Basic-Client-NoTicket", config: Config{ SessionTicketsDisabled: true, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: flags, resumeSession: true, }) - testCases = append(testCases, testCase{ - protocol: protocol, - name: "Basic-Client-Implicit" + suffix, - config: Config{ - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, - }, - flags: append(flags, "-implicit-handshake"), + tests = append(tests, testCase{ + name: "Basic-Client-Implicit", + flags: []string{"-implicit-handshake"}, resumeSession: true, }) - testCases = append(testCases, testCase{ - protocol: protocol, - testType: serverTest, - name: "Basic-Server" + suffix, - config: Config{ - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, - }, - flags: flags, + tests = append(tests, testCase{ + testType: serverTest, + name: "Basic-Server", resumeSession: true, }) - testCases = append(testCases, testCase{ - protocol: protocol, + tests = append(tests, testCase{ testType: serverTest, - name: "Basic-Server-NoTickets" + suffix, + name: "Basic-Server-NoTickets", config: Config{ SessionTicketsDisabled: true, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: flags, resumeSession: true, }) - testCases = append(testCases, testCase{ - protocol: protocol, - testType: serverTest, - name: "Basic-Server-Implicit" + suffix, - config: Config{ - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, - }, - flags: append(flags, "-implicit-handshake"), + tests = append(tests, testCase{ + testType: serverTest, + name: "Basic-Server-Implicit", + flags: []string{"-implicit-handshake"}, resumeSession: true, }) - testCases = append(testCases, testCase{ - protocol: protocol, - testType: serverTest, - name: "Basic-Server-EarlyCallback" + suffix, - config: Config{ - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, - }, - flags: append(flags, "-use-early-callback"), + tests = append(tests, testCase{ + testType: serverTest, + name: "Basic-Server-EarlyCallback", + flags: []string{"-use-early-callback"}, resumeSession: true, }) // TLS client auth. - testCases = append(testCases, testCase{ - protocol: protocol, + tests = append(tests, testCase{ testType: clientTest, - name: "ClientAuth-Client" + suffix, + name: "ClientAuth-Client", config: Config{ ClientAuth: RequireAnyClientCert, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: append(flags, + flags: []string{ "-cert-file", rsaCertificateFile, - "-key-file", rsaKeyFile), + "-key-file", rsaKeyFile, + }, }) - testCases = append(testCases, testCase{ - protocol: protocol, + tests = append(tests, testCase{ testType: serverTest, - name: "ClientAuth-Server" + suffix, + name: "ClientAuth-Server", config: Config{ Certificates: []Certificate{rsaCertificate}, }, - flags: append(flags, "-require-any-client-certificate"), + flags: []string{"-require-any-client-certificate"}, }) // No session ticket support; server doesn't send NewSessionTicket. - testCases = append(testCases, testCase{ - protocol: protocol, - name: "SessionTicketsDisabled-Client" + suffix, + tests = append(tests, testCase{ + name: "SessionTicketsDisabled-Client", config: Config{ SessionTicketsDisabled: true, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: flags, }) - testCases = append(testCases, testCase{ - protocol: protocol, + tests = append(tests, testCase{ testType: serverTest, - name: "SessionTicketsDisabled-Server" + suffix, + name: "SessionTicketsDisabled-Server", config: Config{ SessionTicketsDisabled: true, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: flags, }) // Skip ServerKeyExchange in PSK key exchange if there's no // identity hint. - testCases = append(testCases, testCase{ - protocol: protocol, - name: "EmptyPSKHint-Client" + suffix, + tests = append(tests, testCase{ + name: "EmptyPSKHint-Client", config: Config{ CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA}, PreSharedKey: []byte("secret"), - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: append(flags, "-psk", "secret"), + flags: []string{"-psk", "secret"}, }) - testCases = append(testCases, testCase{ - protocol: protocol, + tests = append(tests, testCase{ testType: serverTest, - name: "EmptyPSKHint-Server" + suffix, + name: "EmptyPSKHint-Server", config: Config{ CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA}, PreSharedKey: []byte("secret"), - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: append(flags, "-psk", "secret"), + flags: []string{"-psk", "secret"}, }) if protocol == tls { + tests = append(tests, testCase{ + name: "Renegotiate-Client", + renegotiate: true, + }) // NPN on client and server; results in post-handshake message. - testCases = append(testCases, testCase{ - protocol: protocol, - name: "NPN-Client" + suffix, + tests = append(tests, testCase{ + name: "NPN-Client", config: Config{ NextProtos: []string{"foo"}, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: append(flags, "-select-next-proto", "foo"), + flags: []string{"-select-next-proto", "foo"}, expectedNextProto: "foo", expectedNextProtoType: npn, }) - testCases = append(testCases, testCase{ - protocol: protocol, + tests = append(tests, testCase{ testType: serverTest, - name: "NPN-Server" + suffix, + name: "NPN-Server", config: Config{ NextProtos: []string{"bar"}, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: append(flags, + flags: []string{ "-advertise-npn", "\x03foo\x03bar\x03baz", - "-expect-next-proto", "bar"), + "-expect-next-proto", "bar", + }, expectedNextProto: "bar", expectedNextProtoType: npn, }) @@ -2112,146 +2202,148 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) // TODO(davidben): Add tests for when False Start doesn't trigger. // Client does False Start and negotiates NPN. - testCases = append(testCases, testCase{ - protocol: protocol, - name: "FalseStart" + suffix, + tests = append(tests, testCase{ + name: "FalseStart", config: Config{ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, NextProtos: []string{"foo"}, Bugs: ProtocolBugs{ - ExpectFalseStart: true, - MaxHandshakeRecordLength: maxHandshakeRecordLength, + ExpectFalseStart: true, }, }, - flags: append(flags, + flags: []string{ "-false-start", - "-select-next-proto", "foo"), + "-select-next-proto", "foo", + }, shimWritesFirst: true, resumeSession: true, }) // Client does False Start and negotiates ALPN. - testCases = append(testCases, testCase{ - protocol: protocol, - name: "FalseStart-ALPN" + suffix, + tests = append(tests, testCase{ + name: "FalseStart-ALPN", config: Config{ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, NextProtos: []string{"foo"}, Bugs: ProtocolBugs{ - ExpectFalseStart: true, - MaxHandshakeRecordLength: maxHandshakeRecordLength, + ExpectFalseStart: true, }, }, - flags: append(flags, + flags: []string{ "-false-start", - "-advertise-alpn", "\x03foo"), + "-advertise-alpn", "\x03foo", + }, shimWritesFirst: true, resumeSession: true, }) // Client does False Start but doesn't explicitly call // SSL_connect. - testCases = append(testCases, testCase{ - protocol: protocol, - name: "FalseStart-Implicit" + suffix, + tests = append(tests, testCase{ + name: "FalseStart-Implicit", config: Config{ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, NextProtos: []string{"foo"}, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: append(flags, + flags: []string{ "-implicit-handshake", "-false-start", - "-advertise-alpn", "\x03foo"), + "-advertise-alpn", "\x03foo", + }, }) // False Start without session tickets. - testCases = append(testCases, testCase{ - name: "FalseStart-SessionTicketsDisabled" + suffix, + tests = append(tests, testCase{ + name: "FalseStart-SessionTicketsDisabled", config: Config{ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, NextProtos: []string{"foo"}, SessionTicketsDisabled: true, Bugs: ProtocolBugs{ - ExpectFalseStart: true, - MaxHandshakeRecordLength: maxHandshakeRecordLength, + ExpectFalseStart: true, }, }, - flags: append(flags, + flags: []string{ "-false-start", "-select-next-proto", "foo", - ), + }, shimWritesFirst: true, }) // Server parses a V2ClientHello. - testCases = append(testCases, testCase{ - protocol: protocol, + tests = append(tests, testCase{ testType: serverTest, - name: "SendV2ClientHello" + suffix, + name: "SendV2ClientHello", config: Config{ // Choose a cipher suite that does not involve // elliptic curves, so no extensions are // involved. CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - SendV2ClientHello: true, + SendV2ClientHello: true, }, }, - flags: flags, }) // Client sends a Channel ID. - testCases = append(testCases, testCase{ - protocol: protocol, - name: "ChannelID-Client" + suffix, + tests = append(tests, testCase{ + name: "ChannelID-Client", config: Config{ RequestChannelID: true, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: append(flags, - "-send-channel-id", channelIDKeyFile, - ), + flags: []string{"-send-channel-id", channelIDKeyFile}, resumeSession: true, expectChannelID: true, }) // Server accepts a Channel ID. - testCases = append(testCases, testCase{ - protocol: protocol, + tests = append(tests, testCase{ testType: serverTest, - name: "ChannelID-Server" + suffix, + name: "ChannelID-Server", config: Config{ ChannelID: channelIDKey, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: append(flags, + flags: []string{ "-expect-channel-id", base64.StdEncoding.EncodeToString(channelIDBytes), - ), + }, resumeSession: true, expectChannelID: true, }) } else { - testCases = append(testCases, testCase{ - protocol: protocol, - name: "SkipHelloVerifyRequest" + suffix, + tests = append(tests, testCase{ + name: "SkipHelloVerifyRequest", config: Config{ Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - SkipHelloVerifyRequest: true, + SkipHelloVerifyRequest: true, }, }, - flags: flags, }) } + + var suffix string + var flags []string + var maxHandshakeRecordLength int + if protocol == dtls { + suffix = "-DTLS" + } + if async { + suffix += "-Async" + flags = append(flags, "-async") + } else { + suffix += "-Sync" + } + if splitHandshake { + suffix += "-SplitHandshakeRecords" + maxHandshakeRecordLength = 1 + } + for _, test := range tests { + test.protocol = protocol + test.name += suffix + test.config.Bugs.MaxHandshakeRecordLength = maxHandshakeRecordLength + test.flags = append(test.flags, flags...) + testCases = append(testCases, test) + } } func addDDoSCallbackTests() { @@ -2637,8 +2729,8 @@ func addExtensionTests() { CorruptTicket: true, }, }, - resumeSession: true, - flags: []string{"-expect-session-miss"}, + resumeSession: true, + expectResumeRejected: true, }) // Resume with an oversized session id. testCases = append(testCases, testCase{ @@ -2799,7 +2891,6 @@ func addResumptionVersionTests() { testCases = append(testCases, testCase{ protocol: protocol, name: "Resume-Client-NoResume" + suffix, - flags: []string{"-expect-session-miss"}, resumeSession: true, config: Config{ MaxVersion: sessionVers.version, @@ -2811,24 +2902,21 @@ func addResumptionVersionTests() { CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, }, newSessionsOnResume: true, + expectResumeRejected: true, expectedResumeVersion: resumeVers.version, }) - var flags []string - if sessionVers.version != resumeVers.version { - flags = append(flags, "-expect-session-miss") - } testCases = append(testCases, testCase{ protocol: protocol, testType: serverTest, name: "Resume-Server" + suffix, - flags: flags, resumeSession: true, config: Config{ MaxVersion: sessionVers.version, CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, }, - expectedVersion: sessionVers.version, + expectedVersion: sessionVers.version, + expectResumeRejected: sessionVers.version != resumeVers.version, resumeConfig: &Config{ MaxVersion: resumeVers.version, CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, @@ -2857,57 +2945,50 @@ func addResumptionVersionTests() { } func addRenegotiationTests() { + // Servers cannot renegotiate. testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server", - flags: []string{"-renegotiate"}, - shimWritesFirst: true, + testType: serverTest, + name: "Renegotiate-Server-Forbidden", + renegotiate: true, + flags: []string{"-reject-peer-renegotiations"}, + shouldFail: true, + expectedError: ":NO_RENEGOTIATION:", + expectedLocalError: "remote error: no renegotiation", }) + // TODO(agl): test the renegotiation info SCSV. testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-Full", + name: "Renegotiate-Client", config: Config{ Bugs: ProtocolBugs{ - NeverResumeOnRenego: true, + FailIfResumeOnRenego: true, }, }, - flags: []string{"-renegotiate"}, - shimWritesFirst: true, + renegotiate: true, }) testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-EmptyExt", + name: "Renegotiate-Client-EmptyExt", + renegotiate: true, config: Config{ Bugs: ProtocolBugs{ EmptyRenegotiationInfo: true, }, }, - flags: []string{"-renegotiate"}, - shimWritesFirst: true, - shouldFail: true, - expectedError: ":RENEGOTIATION_MISMATCH:", + shouldFail: true, + expectedError: ":RENEGOTIATION_MISMATCH:", }) testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-BadExt", + name: "Renegotiate-Client-BadExt", + renegotiate: true, config: Config{ Bugs: ProtocolBugs{ BadRenegotiationInfo: true, }, }, - flags: []string{"-renegotiate"}, - shimWritesFirst: true, - shouldFail: true, - expectedError: ":RENEGOTIATION_MISMATCH:", - }) - testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-ClientInitiated", - renegotiate: true, + shouldFail: true, + expectedError: ":RENEGOTIATION_MISMATCH:", }) testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-ClientInitiated-NoExt", + name: "Renegotiate-Client-NoExt", renegotiate: true, config: Config{ Bugs: ProtocolBugs{ @@ -2916,75 +2997,16 @@ func addRenegotiationTests() { }, shouldFail: true, expectedError: ":UNSAFE_LEGACY_RENEGOTIATION_DISABLED:", + flags: []string{"-no-legacy-server-connect"}, }) testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-ClientInitiated-NoExt-Allowed", + name: "Renegotiate-Client-NoExt-Allowed", renegotiate: true, config: Config{ Bugs: ProtocolBugs{ NoRenegotiationInfo: true, }, }, - flags: []string{"-allow-unsafe-legacy-renegotiation"}, - }) - testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-ClientInitiated-Forbidden", - renegotiate: true, - flags: []string{"-reject-peer-renegotiations"}, - shouldFail: true, - expectedError: ":NO_RENEGOTIATION:", - expectedLocalError: "remote error: no renegotiation", - }) - // Regression test for CVE-2015-0291. - testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-NoSignatureAlgorithms", - config: Config{ - Bugs: ProtocolBugs{ - NeverResumeOnRenego: true, - NoSignatureAlgorithmsOnRenego: true, - }, - }, - flags: []string{"-renegotiate"}, - shimWritesFirst: true, - }) - // TODO(agl): test the renegotiation info SCSV. - testCases = append(testCases, testCase{ - name: "Renegotiate-Client", - renegotiate: true, - }) - testCases = append(testCases, testCase{ - name: "Renegotiate-Client-Full", - config: Config{ - Bugs: ProtocolBugs{ - NeverResumeOnRenego: true, - }, - }, - renegotiate: true, - }) - testCases = append(testCases, testCase{ - name: "Renegotiate-Client-EmptyExt", - renegotiate: true, - config: Config{ - Bugs: ProtocolBugs{ - EmptyRenegotiationInfo: true, - }, - }, - shouldFail: true, - expectedError: ":RENEGOTIATION_MISMATCH:", - }) - testCases = append(testCases, testCase{ - name: "Renegotiate-Client-BadExt", - renegotiate: true, - config: Config{ - Bugs: ProtocolBugs{ - BadRenegotiationInfo: true, - }, - }, - shouldFail: true, - expectedError: ":RENEGOTIATION_MISMATCH:", }) testCases = append(testCases, testCase{ name: "Renegotiate-Client-SwitchCiphers", @@ -3365,6 +3387,59 @@ func addExportKeyingMaterialTests() { }) } +func addTLSUniqueTests() { + for _, isClient := range []bool{false, true} { + for _, isResumption := range []bool{false, true} { + for _, hasEMS := range []bool{false, true} { + var suffix string + if isResumption { + suffix = "Resume-" + } else { + suffix = "Full-" + } + + if hasEMS { + suffix += "EMS-" + } else { + suffix += "NoEMS-" + } + + if isClient { + suffix += "Client" + } else { + suffix += "Server" + } + + test := testCase{ + name: "TLSUnique-" + suffix, + testTLSUnique: true, + config: Config{ + Bugs: ProtocolBugs{ + NoExtendedMasterSecret: !hasEMS, + }, + }, + } + + if isResumption { + test.resumeSession = true + test.resumeConfig = &Config{ + Bugs: ProtocolBugs{ + NoExtendedMasterSecret: !hasEMS, + }, + } + } + + if isResumption && !hasEMS { + test.shouldFail = true + test.expectedError = "failed to get tls-unique" + } + + testCases = append(testCases, test) + } + } + } +} + func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) { defer wg.Done() @@ -3463,6 +3538,7 @@ func main() { addFastRadioPaddingTests() addDTLSRetransmitTests() addExportKeyingMaterialTests() + addTLSUniqueTests() for _, async := range []bool{false, true} { for _, splitHandshake := range []bool{false, true} { for _, protocol := range []protocol{tls, dtls} { diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc index 25906f7..363b6f3 100644 --- a/src/ssl/test/test_config.cc +++ b/src/ssl/test/test_config.cc @@ -65,7 +65,6 @@ const Flag<bool> kBoolFlags[] = { { "-expect-session-miss", &TestConfig::expect_session_miss }, { "-expect-extended-master-secret", &TestConfig::expect_extended_master_secret }, - { "-renegotiate", &TestConfig::renegotiate }, { "-allow-unsafe-legacy-renegotiation", &TestConfig::allow_unsafe_legacy_renegotiation }, { "-enable-ocsp-stapling", &TestConfig::enable_ocsp_stapling }, @@ -81,6 +80,8 @@ const Flag<bool> kBoolFlags[] = { { "-handshake-never-done", &TestConfig::handshake_never_done }, { "-use-export-context", &TestConfig::use_export_context }, { "-reject-peer-renegotiations", &TestConfig::reject_peer_renegotiations }, + { "-no-legacy-server-connect", &TestConfig::no_legacy_server_connect }, + { "-tls-unique", &TestConfig::tls_unique }, }; const Flag<std::string> kStringFlags[] = { diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h index f107a0f..5d753c8 100644 --- a/src/ssl/test/test_config.h +++ b/src/ssl/test/test_config.h @@ -54,7 +54,6 @@ struct TestConfig { bool expect_extended_master_secret = false; std::string psk; std::string psk_identity; - bool renegotiate = false; bool allow_unsafe_legacy_renegotiation = false; std::string srtp_profiles; bool enable_ocsp_stapling = false; @@ -78,6 +77,8 @@ struct TestConfig { std::string export_context; bool use_export_context = false; bool reject_peer_renegotiations = false; + bool no_legacy_server_connect = false; + bool tls_unique = false; }; bool ParseConfig(int argc, char **argv, TestConfig *out_config); |