2016-07-11 18:19:03 +01:00
|
|
|
/* Copyright (c) 2016, 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. */
|
|
|
|
|
2017-07-13 04:00:28 +01:00
|
|
|
/* Per C99, various stdint.h macros are unavailable in C++ unless some macros
|
|
|
|
* are defined. C++11 overruled this decision, but older Android NDKs still
|
|
|
|
* require it. */
|
|
|
|
#if !defined(__STDC_LIMIT_MACROS)
|
|
|
|
#define __STDC_LIMIT_MACROS
|
|
|
|
#endif
|
|
|
|
|
2016-07-11 18:19:03 +01:00
|
|
|
#include <openssl/ssl.h>
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2016-10-31 23:20:42 +00:00
|
|
|
#include <openssl/aead.h>
|
2016-07-11 18:19:03 +01:00
|
|
|
#include <openssl/bytestring.h>
|
|
|
|
#include <openssl/digest.h>
|
|
|
|
#include <openssl/err.h>
|
|
|
|
#include <openssl/mem.h>
|
|
|
|
#include <openssl/rand.h>
|
|
|
|
#include <openssl/stack.h>
|
|
|
|
|
2016-12-13 06:07:13 +00:00
|
|
|
#include "../crypto/internal.h"
|
2016-07-11 18:19:03 +01:00
|
|
|
#include "internal.h"
|
|
|
|
|
|
|
|
|
Move libssl's internals into the bssl namespace.
This is horrible, but everything else I tried was worse. The goal with
this CL is to take the extern "C" out of ssl/internal.h and move most
symbols to namespace bssl, so we can start using C++ helpers and
destructors without worry.
Complications:
- Public API functions must be extern "C" and match their declaration in
ssl.h, which is unnamespaced. C++ really does not want you to
interleave namespaced and unnamespaced things. One can actually write
a namespaced extern "C" function, but this means, from C++'s
perspective, the function is namespaced. Trying to namespace the
public header would worked but ended up too deep a rabbithole.
- Our STACK_OF macros do not work right in namespaces.
- The typedefs for our exposed but opaque types are visible in the
header files and copied into consuming projects as forward
declarations. We ultimately want to give SSL a destructor, but
clobbering an unnamespaced ssl_st::~ssl_st seems bad manners.
- MSVC complains about ambiguous names if one typedefs SSL to bssl::SSL.
This CL opts for:
- ssl/*.cc must begin with #define BORINGSSL_INTERNAL_CXX_TYPES. This
informs the public headers to create forward declarations which are
compatible with our namespaces.
- For now, C++-defined type FOO ends up at bssl::FOO with a typedef
outside. Later I imagine we'll rename many of them.
- Internal functions get namespace bssl, so we stop worrying about
stomping the tls1_prf symbol. Exported C functions are stuck as they
are. Rather than try anything weird, bite the bullet and reorder files
which have a mix of public and private functions. I expect that over
time, the public functions will become fairly small as we move logic
to more idiomatic C++.
Files without any public C functions can just be written normally.
- To avoid MSVC troubles, some bssl types are renamed to CPlusPlusStyle
in advance of them being made idiomatic C++.
Bug: 132
Change-Id: Ic931895e117c38b14ff8d6e5a273e868796c7581
Reviewed-on: https://boringssl-review.googlesource.com/18124
Reviewed-by: David Benjamin <davidben@google.com>
2017-07-18 21:34:25 +01:00
|
|
|
namespace bssl {
|
|
|
|
|
2016-07-11 18:19:03 +01:00
|
|
|
enum server_hs_state_t {
|
2017-02-03 04:33:21 +00:00
|
|
|
state_select_parameters = 0,
|
2017-03-10 22:47:18 +00:00
|
|
|
state_select_session,
|
2016-07-18 17:40:30 +01:00
|
|
|
state_send_hello_retry_request,
|
|
|
|
state_process_second_client_hello,
|
2016-07-11 18:19:03 +01:00
|
|
|
state_send_server_hello,
|
|
|
|
state_send_server_certificate_verify,
|
|
|
|
state_send_server_finished,
|
2017-01-11 16:34:52 +00:00
|
|
|
state_read_second_client_flight,
|
2017-06-13 17:45:25 +01:00
|
|
|
state_process_change_cipher_spec,
|
2017-01-11 16:34:52 +00:00
|
|
|
state_process_end_of_early_data,
|
2016-07-11 18:19:03 +01:00
|
|
|
state_process_client_certificate,
|
|
|
|
state_process_client_certificate_verify,
|
2016-09-24 00:25:11 +01:00
|
|
|
state_process_channel_id,
|
2016-07-11 18:19:03 +01:00
|
|
|
state_process_client_finished,
|
2016-07-27 16:10:52 +01:00
|
|
|
state_send_new_session_ticket,
|
2016-07-11 18:19:03 +01:00
|
|
|
state_done,
|
|
|
|
};
|
|
|
|
|
2016-07-18 17:40:30 +01:00
|
|
|
static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0};
|
|
|
|
|
2016-11-17 07:43:08 +00:00
|
|
|
static int resolve_ecdhe_secret(SSL_HANDSHAKE *hs, int *out_need_retry,
|
2016-12-04 04:15:13 +00:00
|
|
|
SSL_CLIENT_HELLO *client_hello) {
|
2016-11-17 07:43:08 +00:00
|
|
|
SSL *const ssl = hs->ssl;
|
2016-07-18 17:40:30 +01:00
|
|
|
*out_need_retry = 0;
|
|
|
|
|
2016-09-06 19:13:43 +01:00
|
|
|
/* We only support connections that include an ECDHE key exchange. */
|
2016-07-18 17:40:30 +01:00
|
|
|
CBS key_share;
|
2016-12-04 04:15:13 +00:00
|
|
|
if (!ssl_client_hello_get_extension(client_hello, &key_share,
|
|
|
|
TLSEXT_TYPE_key_share)) {
|
2016-07-18 17:40:30 +01:00
|
|
|
OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_KEY_SHARE);
|
|
|
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_MISSING_EXTENSION);
|
2016-11-16 10:10:08 +00:00
|
|
|
return 0;
|
2016-07-18 17:40:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int found_key_share;
|
|
|
|
uint8_t *dhe_secret;
|
|
|
|
size_t dhe_secret_len;
|
2016-09-21 00:24:40 +01:00
|
|
|
uint8_t alert = SSL_AD_DECODE_ERROR;
|
2016-11-17 08:11:16 +00:00
|
|
|
if (!ssl_ext_key_share_parse_clienthello(hs, &found_key_share, &dhe_secret,
|
2016-08-02 21:55:05 +01:00
|
|
|
&dhe_secret_len, &alert,
|
|
|
|
&key_share)) {
|
2016-07-18 17:40:30 +01:00
|
|
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found_key_share) {
|
|
|
|
*out_need_retry = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-17 07:43:08 +00:00
|
|
|
int ok = tls13_advance_key_schedule(hs, dhe_secret, dhe_secret_len);
|
2016-07-18 17:40:30 +01:00
|
|
|
OPENSSL_free(dhe_secret);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2017-07-10 17:57:25 +01:00
|
|
|
static int ssl_ext_supported_versions_add_serverhello(SSL_HANDSHAKE *hs,
|
|
|
|
CBB *out) {
|
|
|
|
CBB contents;
|
|
|
|
if (!CBB_add_u16(out, TLSEXT_TYPE_supported_versions) ||
|
|
|
|
!CBB_add_u16_length_prefixed(out, &contents) ||
|
|
|
|
!CBB_add_u16(&contents, hs->ssl->version) ||
|
|
|
|
!CBB_flush(out)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-11-16 10:07:53 +00:00
|
|
|
static const SSL_CIPHER *choose_tls13_cipher(
|
2016-12-04 04:15:13 +00:00
|
|
|
const SSL *ssl, const SSL_CLIENT_HELLO *client_hello) {
|
2016-11-16 10:07:53 +00:00
|
|
|
if (client_hello->cipher_suites_len % 2 != 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
CBS cipher_suites;
|
|
|
|
CBS_init(&cipher_suites, client_hello->cipher_suites,
|
|
|
|
client_hello->cipher_suites_len);
|
|
|
|
|
|
|
|
const int aes_is_fine = EVP_has_aes_hardware();
|
Negotiate ciphers before resumption.
This changes our resumption strategy. Before, we would negotiate ciphers
only on fresh handshakes. On resumption, we would blindly use whatever
was in the session.
Instead, evaluate cipher suite preferences on every handshake.
Resumption requires that the saved cipher suite match the one that would
have been negotiated anyway. If client or server preferences changed
sufficiently, we decline the session.
This is much easier to reason about (we always pick the best cipher
suite), simpler, and avoids getting stuck under old preferences if
tickets are continuously renewed. Notably, although TLS 1.2 ticket
renewal does not work in practice, TLS 1.3 will renew tickets like
there's no tomorrow.
It also means we don't need dedicated code to avoid resuming a cipher
which has since been disabled. (That dedicated code was a little odd
anyway since the mask_k, etc., checks didn't occur. When cert_cb was
skipped on resumption, one could resume without ever configuring a
certificate! So we couldn't know whether to mask off RSA or ECDSA cipher
suites.)
Add tests which assert on this new arrangement.
BUG=116
Change-Id: Id40d851ccd87e06c46c6ec272527fd8ece8abfc6
Reviewed-on: https://boringssl-review.googlesource.com/11847
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2016-11-16 10:05:33 +00:00
|
|
|
const uint16_t version = ssl3_protocol_version(ssl);
|
2016-11-16 10:07:53 +00:00
|
|
|
|
|
|
|
const SSL_CIPHER *best = NULL;
|
|
|
|
while (CBS_len(&cipher_suites) > 0) {
|
|
|
|
uint16_t cipher_suite;
|
|
|
|
if (!CBS_get_u16(&cipher_suites, &cipher_suite)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
Negotiate ciphers before resumption.
This changes our resumption strategy. Before, we would negotiate ciphers
only on fresh handshakes. On resumption, we would blindly use whatever
was in the session.
Instead, evaluate cipher suite preferences on every handshake.
Resumption requires that the saved cipher suite match the one that would
have been negotiated anyway. If client or server preferences changed
sufficiently, we decline the session.
This is much easier to reason about (we always pick the best cipher
suite), simpler, and avoids getting stuck under old preferences if
tickets are continuously renewed. Notably, although TLS 1.2 ticket
renewal does not work in practice, TLS 1.3 will renew tickets like
there's no tomorrow.
It also means we don't need dedicated code to avoid resuming a cipher
which has since been disabled. (That dedicated code was a little odd
anyway since the mask_k, etc., checks didn't occur. When cert_cb was
skipped on resumption, one could resume without ever configuring a
certificate! So we couldn't know whether to mask off RSA or ECDSA cipher
suites.)
Add tests which assert on this new arrangement.
BUG=116
Change-Id: Id40d851ccd87e06c46c6ec272527fd8ece8abfc6
Reviewed-on: https://boringssl-review.googlesource.com/11847
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2016-11-16 10:05:33 +00:00
|
|
|
/* Limit to TLS 1.3 ciphers we know about. */
|
2016-11-16 10:07:53 +00:00
|
|
|
const SSL_CIPHER *candidate = SSL_get_cipher_by_value(cipher_suite);
|
Negotiate ciphers before resumption.
This changes our resumption strategy. Before, we would negotiate ciphers
only on fresh handshakes. On resumption, we would blindly use whatever
was in the session.
Instead, evaluate cipher suite preferences on every handshake.
Resumption requires that the saved cipher suite match the one that would
have been negotiated anyway. If client or server preferences changed
sufficiently, we decline the session.
This is much easier to reason about (we always pick the best cipher
suite), simpler, and avoids getting stuck under old preferences if
tickets are continuously renewed. Notably, although TLS 1.2 ticket
renewal does not work in practice, TLS 1.3 will renew tickets like
there's no tomorrow.
It also means we don't need dedicated code to avoid resuming a cipher
which has since been disabled. (That dedicated code was a little odd
anyway since the mask_k, etc., checks didn't occur. When cert_cb was
skipped on resumption, one could resume without ever configuring a
certificate! So we couldn't know whether to mask off RSA or ECDSA cipher
suites.)
Add tests which assert on this new arrangement.
BUG=116
Change-Id: Id40d851ccd87e06c46c6ec272527fd8ece8abfc6
Reviewed-on: https://boringssl-review.googlesource.com/11847
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2016-11-16 10:05:33 +00:00
|
|
|
if (candidate == NULL ||
|
|
|
|
SSL_CIPHER_get_min_version(candidate) > version ||
|
|
|
|
SSL_CIPHER_get_max_version(candidate) < version) {
|
2016-11-16 10:07:53 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TLS 1.3 removes legacy ciphers, so honor the client order, but prefer
|
|
|
|
* ChaCha20 if we do not have AES hardware. */
|
|
|
|
if (aes_is_fine) {
|
|
|
|
return candidate;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (candidate->algorithm_enc == SSL_CHACHA20POLY1305) {
|
|
|
|
return candidate;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (best == NULL) {
|
|
|
|
best = candidate;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
2017-03-26 04:24:23 +01:00
|
|
|
static int add_new_session_tickets(SSL_HANDSHAKE *hs) {
|
|
|
|
SSL *const ssl = hs->ssl;
|
|
|
|
/* TLS 1.3 recommends single-use tickets, so issue multiple tickets in case
|
|
|
|
* the client makes several connections before getting a renewal. */
|
|
|
|
static const int kNumTickets = 2;
|
|
|
|
|
|
|
|
/* Rebase the session timestamp so that it is measured from ticket
|
|
|
|
* issuance. */
|
2017-07-20 19:49:15 +01:00
|
|
|
ssl_session_rebase_time(ssl, hs->new_session.get());
|
2017-03-26 04:24:23 +01:00
|
|
|
|
|
|
|
for (int i = 0; i < kNumTickets; i++) {
|
2017-07-20 19:49:15 +01:00
|
|
|
if (!RAND_bytes((uint8_t *)&hs->new_session->ticket_age_add, 4)) {
|
2017-07-20 04:57:40 +01:00
|
|
|
return 0;
|
2017-03-26 04:24:23 +01:00
|
|
|
}
|
2017-07-20 19:49:15 +01:00
|
|
|
hs->new_session->ticket_age_add_valid = 1;
|
2017-03-26 04:24:23 +01:00
|
|
|
|
2017-07-20 04:57:40 +01:00
|
|
|
ScopedCBB cbb;
|
2017-03-26 04:24:23 +01:00
|
|
|
CBB body, ticket, extensions;
|
2017-07-20 04:57:40 +01:00
|
|
|
if (!ssl->method->init_message(ssl, cbb.get(), &body,
|
2017-03-26 04:24:23 +01:00
|
|
|
SSL3_MT_NEW_SESSION_TICKET) ||
|
2017-07-20 19:49:15 +01:00
|
|
|
!CBB_add_u32(&body, hs->new_session->timeout) ||
|
|
|
|
!CBB_add_u32(&body, hs->new_session->ticket_age_add) ||
|
2017-03-26 04:24:23 +01:00
|
|
|
!CBB_add_u16_length_prefixed(&body, &ticket) ||
|
2017-07-20 19:49:15 +01:00
|
|
|
!ssl_encrypt_ticket(ssl, &ticket, hs->new_session.get()) ||
|
2017-03-26 04:24:23 +01:00
|
|
|
!CBB_add_u16_length_prefixed(&body, &extensions)) {
|
2017-07-20 04:57:40 +01:00
|
|
|
return 0;
|
2017-03-26 04:24:23 +01:00
|
|
|
}
|
|
|
|
|
2017-03-30 22:33:24 +01:00
|
|
|
if (ssl->cert->enable_early_data) {
|
2017-07-20 19:49:15 +01:00
|
|
|
hs->new_session->ticket_max_early_data = kMaxEarlyDataAccepted;
|
2017-03-26 04:24:23 +01:00
|
|
|
|
|
|
|
CBB early_data_info;
|
|
|
|
if (!CBB_add_u16(&extensions, TLSEXT_TYPE_ticket_early_data_info) ||
|
|
|
|
!CBB_add_u16_length_prefixed(&extensions, &early_data_info) ||
|
2017-07-20 19:49:15 +01:00
|
|
|
!CBB_add_u32(&early_data_info,
|
|
|
|
hs->new_session->ticket_max_early_data) ||
|
2017-03-26 04:24:23 +01:00
|
|
|
!CBB_flush(&extensions)) {
|
2017-07-20 04:57:40 +01:00
|
|
|
return 0;
|
2017-03-26 04:24:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add a fake extension. See draft-davidben-tls-grease-01. */
|
|
|
|
if (!CBB_add_u16(&extensions,
|
|
|
|
ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) ||
|
|
|
|
!CBB_add_u16(&extensions, 0 /* empty */)) {
|
2017-07-20 04:57:40 +01:00
|
|
|
return 0;
|
2017-03-26 04:24:23 +01:00
|
|
|
}
|
|
|
|
|
2017-07-20 04:57:40 +01:00
|
|
|
if (!ssl_add_message_cbb(ssl, cbb.get())) {
|
|
|
|
return 0;
|
2017-03-26 04:24:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-11-14 01:32:04 +00:00
|
|
|
static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) {
|
2017-03-10 22:47:18 +00:00
|
|
|
/* At this point, most ClientHello extensions have already been processed by
|
|
|
|
* the common handshake logic. Resolve the remaining non-PSK parameters. */
|
2016-11-14 01:32:04 +00:00
|
|
|
SSL *const ssl = hs->ssl;
|
2016-12-20 23:55:16 +00:00
|
|
|
|
2016-12-04 04:15:13 +00:00
|
|
|
SSL_CLIENT_HELLO client_hello;
|
|
|
|
if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
|
2017-06-13 17:45:25 +01:00
|
|
|
ssl->init_num) ||
|
|
|
|
client_hello.session_id_len > sizeof(hs->session_id)) {
|
2016-11-16 10:07:53 +00:00
|
|
|
OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
|
|
|
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
2017-06-13 17:45:25 +01:00
|
|
|
OPENSSL_memcpy(hs->session_id, client_hello.session_id,
|
|
|
|
client_hello.session_id_len);
|
|
|
|
hs->session_id_len = client_hello.session_id_len;
|
|
|
|
|
Negotiate ciphers before resumption.
This changes our resumption strategy. Before, we would negotiate ciphers
only on fresh handshakes. On resumption, we would blindly use whatever
was in the session.
Instead, evaluate cipher suite preferences on every handshake.
Resumption requires that the saved cipher suite match the one that would
have been negotiated anyway. If client or server preferences changed
sufficiently, we decline the session.
This is much easier to reason about (we always pick the best cipher
suite), simpler, and avoids getting stuck under old preferences if
tickets are continuously renewed. Notably, although TLS 1.2 ticket
renewal does not work in practice, TLS 1.3 will renew tickets like
there's no tomorrow.
It also means we don't need dedicated code to avoid resuming a cipher
which has since been disabled. (That dedicated code was a little odd
anyway since the mask_k, etc., checks didn't occur. When cert_cb was
skipped on resumption, one could resume without ever configuring a
certificate! So we couldn't know whether to mask off RSA or ECDSA cipher
suites.)
Add tests which assert on this new arrangement.
BUG=116
Change-Id: Id40d851ccd87e06c46c6ec272527fd8ece8abfc6
Reviewed-on: https://boringssl-review.googlesource.com/11847
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2016-11-16 10:05:33 +00:00
|
|
|
/* Negotiate the cipher suite. */
|
2017-02-10 01:01:26 +00:00
|
|
|
hs->new_cipher = choose_tls13_cipher(ssl, &client_hello);
|
|
|
|
if (hs->new_cipher == NULL) {
|
Negotiate ciphers before resumption.
This changes our resumption strategy. Before, we would negotiate ciphers
only on fresh handshakes. On resumption, we would blindly use whatever
was in the session.
Instead, evaluate cipher suite preferences on every handshake.
Resumption requires that the saved cipher suite match the one that would
have been negotiated anyway. If client or server preferences changed
sufficiently, we decline the session.
This is much easier to reason about (we always pick the best cipher
suite), simpler, and avoids getting stuck under old preferences if
tickets are continuously renewed. Notably, although TLS 1.2 ticket
renewal does not work in practice, TLS 1.3 will renew tickets like
there's no tomorrow.
It also means we don't need dedicated code to avoid resuming a cipher
which has since been disabled. (That dedicated code was a little odd
anyway since the mask_k, etc., checks didn't occur. When cert_cb was
skipped on resumption, one could resume without ever configuring a
certificate! So we couldn't know whether to mask off RSA or ECDSA cipher
suites.)
Add tests which assert on this new arrangement.
BUG=116
Change-Id: Id40d851ccd87e06c46c6ec272527fd8ece8abfc6
Reviewed-on: https://boringssl-review.googlesource.com/11847
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2016-11-16 10:05:33 +00:00
|
|
|
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER);
|
|
|
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
2017-03-10 22:47:18 +00:00
|
|
|
/* HTTP/2 negotiation depends on the cipher suite, so ALPN negotiation was
|
|
|
|
* deferred. Complete it now. */
|
|
|
|
uint8_t alert = SSL_AD_DECODE_ERROR;
|
|
|
|
if (!ssl_negotiate_alpn(hs, &alert, &client_hello)) {
|
|
|
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
2017-01-12 18:17:07 +00:00
|
|
|
/* The PRF hash is now known. Set up the key schedule and hash the
|
|
|
|
* ClientHello. */
|
|
|
|
if (!tls13_init_key_schedule(hs) ||
|
|
|
|
!ssl_hash_current_message(hs)) {
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
2017-03-10 22:47:18 +00:00
|
|
|
hs->tls13_state = state_select_session;
|
|
|
|
return ssl_hs_ok;
|
|
|
|
}
|
2017-01-12 18:17:07 +00:00
|
|
|
|
2017-03-10 22:47:18 +00:00
|
|
|
static enum ssl_ticket_aead_result_t select_session(
|
|
|
|
SSL_HANDSHAKE *hs, uint8_t *out_alert, SSL_SESSION **out_session,
|
|
|
|
int32_t *out_ticket_age_skew, const SSL_CLIENT_HELLO *client_hello) {
|
|
|
|
SSL *const ssl = hs->ssl;
|
|
|
|
*out_session = NULL;
|
2016-11-01 17:39:36 +00:00
|
|
|
|
2017-03-10 22:47:18 +00:00
|
|
|
/* Decode the ticket if we agreed on a PSK key exchange mode. */
|
|
|
|
CBS pre_shared_key;
|
|
|
|
if (!hs->accept_psk_mode ||
|
|
|
|
!ssl_client_hello_get_extension(client_hello, &pre_shared_key,
|
|
|
|
TLSEXT_TYPE_pre_shared_key)) {
|
|
|
|
return ssl_ticket_aead_ignore_ticket;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that the pre_shared_key extension is the last extension in
|
|
|
|
* ClientHello. */
|
|
|
|
if (CBS_data(&pre_shared_key) + CBS_len(&pre_shared_key) !=
|
|
|
|
client_hello->extensions + client_hello->extensions_len) {
|
|
|
|
OPENSSL_PUT_ERROR(SSL, SSL_R_PRE_SHARED_KEY_MUST_BE_LAST);
|
|
|
|
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
|
|
|
|
return ssl_ticket_aead_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
CBS ticket, binders;
|
|
|
|
uint32_t client_ticket_age;
|
|
|
|
if (!ssl_ext_pre_shared_key_parse_clienthello(hs, &ticket, &binders,
|
|
|
|
&client_ticket_age, out_alert,
|
|
|
|
&pre_shared_key)) {
|
|
|
|
return ssl_ticket_aead_error;
|
2016-11-01 17:39:36 +00:00
|
|
|
}
|
|
|
|
|
2017-03-10 22:47:18 +00:00
|
|
|
/* TLS 1.3 session tickets are renewed separately as part of the
|
|
|
|
* NewSessionTicket. */
|
|
|
|
int unused_renew;
|
|
|
|
SSL_SESSION *session = NULL;
|
|
|
|
enum ssl_ticket_aead_result_t ret =
|
|
|
|
ssl_process_ticket(ssl, &session, &unused_renew, CBS_data(&ticket),
|
|
|
|
CBS_len(&ticket), NULL, 0);
|
|
|
|
switch (ret) {
|
|
|
|
case ssl_ticket_aead_success:
|
|
|
|
break;
|
|
|
|
case ssl_ticket_aead_error:
|
|
|
|
*out_alert = SSL_AD_INTERNAL_ERROR;
|
|
|
|
return ret;
|
|
|
|
default:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ssl_session_is_resumable(hs, session) ||
|
|
|
|
/* Historically, some TLS 1.3 tickets were missing ticket_age_add. */
|
|
|
|
!session->ticket_age_add_valid) {
|
2016-07-29 19:32:55 +01:00
|
|
|
SSL_SESSION_free(session);
|
2017-03-10 22:47:18 +00:00
|
|
|
return ssl_ticket_aead_ignore_ticket;
|
2016-07-29 19:32:55 +01:00
|
|
|
}
|
|
|
|
|
2017-03-10 22:47:18 +00:00
|
|
|
/* Recover the client ticket age and convert to seconds. */
|
|
|
|
client_ticket_age -= session->ticket_age_add;
|
|
|
|
client_ticket_age /= 1000;
|
2017-03-03 20:05:56 +00:00
|
|
|
|
2017-03-10 22:47:18 +00:00
|
|
|
struct OPENSSL_timeval now;
|
|
|
|
ssl_get_current_time(ssl, &now);
|
2017-03-03 20:05:56 +00:00
|
|
|
|
2017-03-10 22:47:18 +00:00
|
|
|
/* Compute the server ticket age in seconds. */
|
|
|
|
assert(now.tv_sec >= session->time);
|
|
|
|
uint64_t server_ticket_age = now.tv_sec - session->time;
|
2017-03-03 20:05:56 +00:00
|
|
|
|
2017-03-10 22:47:18 +00:00
|
|
|
/* To avoid overflowing |hs->ticket_age_skew|, we will not resume
|
|
|
|
* 68-year-old sessions. */
|
|
|
|
if (server_ticket_age > INT32_MAX) {
|
|
|
|
SSL_SESSION_free(session);
|
|
|
|
return ssl_ticket_aead_ignore_ticket;
|
2017-03-03 20:05:56 +00:00
|
|
|
}
|
|
|
|
|
2017-03-10 22:47:18 +00:00
|
|
|
/* TODO(davidben,svaldez): Measure this value to decide on tolerance. For
|
|
|
|
* now, accept all values. https://crbug.com/boringssl/113. */
|
|
|
|
*out_ticket_age_skew =
|
|
|
|
(int32_t)client_ticket_age - (int32_t)server_ticket_age;
|
Negotiate ciphers before resumption.
This changes our resumption strategy. Before, we would negotiate ciphers
only on fresh handshakes. On resumption, we would blindly use whatever
was in the session.
Instead, evaluate cipher suite preferences on every handshake.
Resumption requires that the saved cipher suite match the one that would
have been negotiated anyway. If client or server preferences changed
sufficiently, we decline the session.
This is much easier to reason about (we always pick the best cipher
suite), simpler, and avoids getting stuck under old preferences if
tickets are continuously renewed. Notably, although TLS 1.2 ticket
renewal does not work in practice, TLS 1.3 will renew tickets like
there's no tomorrow.
It also means we don't need dedicated code to avoid resuming a cipher
which has since been disabled. (That dedicated code was a little odd
anyway since the mask_k, etc., checks didn't occur. When cert_cb was
skipped on resumption, one could resume without ever configuring a
certificate! So we couldn't know whether to mask off RSA or ECDSA cipher
suites.)
Add tests which assert on this new arrangement.
BUG=116
Change-Id: Id40d851ccd87e06c46c6ec272527fd8ece8abfc6
Reviewed-on: https://boringssl-review.googlesource.com/11847
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2016-11-16 10:05:33 +00:00
|
|
|
|
2017-03-10 22:47:18 +00:00
|
|
|
/* Check the PSK binder. */
|
|
|
|
if (!tls13_verify_psk_binder(hs, session, &binders)) {
|
|
|
|
SSL_SESSION_free(session);
|
|
|
|
*out_alert = SSL_AD_DECRYPT_ERROR;
|
|
|
|
return ssl_ticket_aead_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
*out_session = session;
|
|
|
|
return ssl_ticket_aead_success;
|
|
|
|
}
|
Negotiate ciphers before resumption.
This changes our resumption strategy. Before, we would negotiate ciphers
only on fresh handshakes. On resumption, we would blindly use whatever
was in the session.
Instead, evaluate cipher suite preferences on every handshake.
Resumption requires that the saved cipher suite match the one that would
have been negotiated anyway. If client or server preferences changed
sufficiently, we decline the session.
This is much easier to reason about (we always pick the best cipher
suite), simpler, and avoids getting stuck under old preferences if
tickets are continuously renewed. Notably, although TLS 1.2 ticket
renewal does not work in practice, TLS 1.3 will renew tickets like
there's no tomorrow.
It also means we don't need dedicated code to avoid resuming a cipher
which has since been disabled. (That dedicated code was a little odd
anyway since the mask_k, etc., checks didn't occur. When cert_cb was
skipped on resumption, one could resume without ever configuring a
certificate! So we couldn't know whether to mask off RSA or ECDSA cipher
suites.)
Add tests which assert on this new arrangement.
BUG=116
Change-Id: Id40d851ccd87e06c46c6ec272527fd8ece8abfc6
Reviewed-on: https://boringssl-review.googlesource.com/11847
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2016-11-16 10:05:33 +00:00
|
|
|
|
2017-03-10 22:47:18 +00:00
|
|
|
static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
|
|
|
|
SSL *const ssl = hs->ssl;
|
|
|
|
SSL_CLIENT_HELLO client_hello;
|
|
|
|
if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
|
|
|
|
ssl->init_num)) {
|
|
|
|
OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
|
|
|
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t alert = SSL_AD_DECODE_ERROR;
|
|
|
|
SSL_SESSION *session = NULL;
|
|
|
|
switch (select_session(hs, &alert, &session, &ssl->s3->ticket_age_skew,
|
|
|
|
&client_hello)) {
|
|
|
|
case ssl_ticket_aead_ignore_ticket:
|
|
|
|
assert(session == NULL);
|
|
|
|
if (!ssl_get_new_session(hs, 1 /* server */)) {
|
Negotiate ciphers before resumption.
This changes our resumption strategy. Before, we would negotiate ciphers
only on fresh handshakes. On resumption, we would blindly use whatever
was in the session.
Instead, evaluate cipher suite preferences on every handshake.
Resumption requires that the saved cipher suite match the one that would
have been negotiated anyway. If client or server preferences changed
sufficiently, we decline the session.
This is much easier to reason about (we always pick the best cipher
suite), simpler, and avoids getting stuck under old preferences if
tickets are continuously renewed. Notably, although TLS 1.2 ticket
renewal does not work in practice, TLS 1.3 will renew tickets like
there's no tomorrow.
It also means we don't need dedicated code to avoid resuming a cipher
which has since been disabled. (That dedicated code was a little odd
anyway since the mask_k, etc., checks didn't occur. When cert_cb was
skipped on resumption, one could resume without ever configuring a
certificate! So we couldn't know whether to mask off RSA or ECDSA cipher
suites.)
Add tests which assert on this new arrangement.
BUG=116
Change-Id: Id40d851ccd87e06c46c6ec272527fd8ece8abfc6
Reviewed-on: https://boringssl-review.googlesource.com/11847
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2016-11-16 10:05:33 +00:00
|
|
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
2017-03-10 22:47:18 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ssl_ticket_aead_success:
|
|
|
|
/* Carry over authentication information from the previous handshake into
|
|
|
|
* a fresh session. */
|
|
|
|
hs->new_session = SSL_SESSION_dup(session, SSL_SESSION_DUP_AUTH_ONLY);
|
2017-01-11 16:34:52 +00:00
|
|
|
|
|
|
|
if (/* Early data must be acceptable for this ticket. */
|
2017-03-30 22:33:24 +01:00
|
|
|
ssl->cert->enable_early_data &&
|
2017-01-11 16:34:52 +00:00
|
|
|
session->ticket_max_early_data != 0 &&
|
|
|
|
/* The client must have offered early data. */
|
|
|
|
hs->early_data_offered &&
|
2017-03-26 02:54:16 +01:00
|
|
|
/* Channel ID is incompatible with 0-RTT. */
|
|
|
|
!ssl->s3->tlsext_channel_id_valid &&
|
2017-01-11 16:34:52 +00:00
|
|
|
/* The negotiated ALPN must match the one in the ticket. */
|
|
|
|
ssl->s3->alpn_selected_len == session->early_alpn_len &&
|
|
|
|
OPENSSL_memcmp(ssl->s3->alpn_selected, session->early_alpn,
|
|
|
|
ssl->s3->alpn_selected_len) == 0) {
|
|
|
|
ssl->early_data_accepted = 1;
|
|
|
|
}
|
|
|
|
|
2016-11-01 17:39:36 +00:00
|
|
|
SSL_SESSION_free(session);
|
2017-03-10 22:47:18 +00:00
|
|
|
if (hs->new_session == NULL) {
|
|
|
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
2016-11-01 17:39:36 +00:00
|
|
|
|
2017-03-10 22:47:18 +00:00
|
|
|
ssl->s3->session_reused = 1;
|
|
|
|
|
|
|
|
/* Resumption incorporates fresh key material, so refresh the timeout. */
|
2017-07-20 19:49:15 +01:00
|
|
|
ssl_session_renew_timeout(ssl, hs->new_session.get(),
|
2017-03-10 22:47:18 +00:00
|
|
|
ssl->session_ctx->session_psk_dhe_timeout);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ssl_ticket_aead_error:
|
|
|
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
|
2016-07-29 19:32:55 +01:00
|
|
|
return ssl_hs_error;
|
2017-01-28 19:00:32 +00:00
|
|
|
|
2017-03-10 22:47:18 +00:00
|
|
|
case ssl_ticket_aead_retry:
|
|
|
|
hs->tls13_state = state_select_session;
|
|
|
|
return ssl_hs_pending_ticket;
|
2016-07-11 18:19:03 +01:00
|
|
|
}
|
|
|
|
|
2017-03-10 22:47:18 +00:00
|
|
|
/* Record connection properties in the new session. */
|
|
|
|
hs->new_session->cipher = hs->new_cipher;
|
2016-07-11 18:19:03 +01:00
|
|
|
|
2017-03-10 22:47:18 +00:00
|
|
|
if (hs->hostname != NULL) {
|
|
|
|
OPENSSL_free(hs->new_session->tlsext_hostname);
|
2017-07-20 19:49:15 +01:00
|
|
|
hs->new_session->tlsext_hostname = BUF_strdup(hs->hostname.get());
|
2017-03-10 22:47:18 +00:00
|
|
|
if (hs->new_session->tlsext_hostname == NULL) {
|
|
|
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
2016-10-31 22:01:13 +00:00
|
|
|
}
|
2016-09-06 19:13:43 +01:00
|
|
|
|
2017-01-11 16:34:52 +00:00
|
|
|
/* Store the initial negotiated ALPN in the session. */
|
2017-02-14 18:20:40 +00:00
|
|
|
if (ssl->s3->alpn_selected != NULL) {
|
2017-07-13 04:00:28 +01:00
|
|
|
hs->new_session->early_alpn = (uint8_t *)BUF_memdup(
|
|
|
|
ssl->s3->alpn_selected, ssl->s3->alpn_selected_len);
|
2017-02-10 01:01:26 +00:00
|
|
|
if (hs->new_session->early_alpn == NULL) {
|
2017-02-14 18:20:40 +00:00
|
|
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
2017-02-10 01:01:26 +00:00
|
|
|
hs->new_session->early_alpn_len = ssl->s3->alpn_selected_len;
|
2017-02-14 18:20:40 +00:00
|
|
|
}
|
|
|
|
|
2017-03-10 22:47:18 +00:00
|
|
|
if (ssl->ctx->dos_protection_cb != NULL &&
|
|
|
|
ssl->ctx->dos_protection_cb(&client_hello) == 0) {
|
|
|
|
/* Connection rejected for DOS reasons. */
|
|
|
|
OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
|
|
|
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
2016-11-30 16:24:40 +00:00
|
|
|
/* Incorporate the PSK into the running secret. */
|
2016-07-29 19:32:55 +01:00
|
|
|
if (ssl->s3->session_reused) {
|
2017-02-10 01:01:26 +00:00
|
|
|
if (!tls13_advance_key_schedule(hs, hs->new_session->master_key,
|
|
|
|
hs->new_session->master_key_length)) {
|
2016-07-29 19:32:55 +01:00
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
2017-01-12 18:17:07 +00:00
|
|
|
} else if (!tls13_advance_key_schedule(hs, kZeroes, hs->hash_len)) {
|
2016-07-11 18:19:03 +01:00
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
2017-01-11 16:34:52 +00:00
|
|
|
if (ssl->early_data_accepted) {
|
|
|
|
if (!tls13_derive_early_secrets(hs)) {
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
} else if (hs->early_data_offered) {
|
|
|
|
ssl->s3->skip_early_data = 1;
|
|
|
|
}
|
|
|
|
|
Negotiate ciphers before resumption.
This changes our resumption strategy. Before, we would negotiate ciphers
only on fresh handshakes. On resumption, we would blindly use whatever
was in the session.
Instead, evaluate cipher suite preferences on every handshake.
Resumption requires that the saved cipher suite match the one that would
have been negotiated anyway. If client or server preferences changed
sufficiently, we decline the session.
This is much easier to reason about (we always pick the best cipher
suite), simpler, and avoids getting stuck under old preferences if
tickets are continuously renewed. Notably, although TLS 1.2 ticket
renewal does not work in practice, TLS 1.3 will renew tickets like
there's no tomorrow.
It also means we don't need dedicated code to avoid resuming a cipher
which has since been disabled. (That dedicated code was a little odd
anyway since the mask_k, etc., checks didn't occur. When cert_cb was
skipped on resumption, one could resume without ever configuring a
certificate! So we couldn't know whether to mask off RSA or ECDSA cipher
suites.)
Add tests which assert on this new arrangement.
BUG=116
Change-Id: Id40d851ccd87e06c46c6ec272527fd8ece8abfc6
Reviewed-on: https://boringssl-review.googlesource.com/11847
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2016-11-16 10:05:33 +00:00
|
|
|
ssl->method->received_flight(ssl);
|
|
|
|
|
2016-07-11 18:19:03 +01:00
|
|
|
/* Resolve ECDHE and incorporate it into the secret. */
|
2016-07-18 17:40:30 +01:00
|
|
|
int need_retry;
|
2016-11-17 07:43:08 +00:00
|
|
|
if (!resolve_ecdhe_secret(hs, &need_retry, &client_hello)) {
|
2016-07-18 17:40:30 +01:00
|
|
|
if (need_retry) {
|
2017-01-11 16:34:52 +00:00
|
|
|
ssl->early_data_accepted = 0;
|
|
|
|
ssl->s3->skip_early_data = 1;
|
2016-12-11 18:30:41 +00:00
|
|
|
hs->tls13_state = state_send_hello_retry_request;
|
2016-07-18 17:40:30 +01:00
|
|
|
return ssl_hs_ok;
|
2016-07-11 18:19:03 +01:00
|
|
|
}
|
2016-07-18 17:40:30 +01:00
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
2016-07-11 18:19:03 +01:00
|
|
|
|
2016-12-11 18:30:41 +00:00
|
|
|
hs->tls13_state = state_send_server_hello;
|
2016-07-18 17:40:30 +01:00
|
|
|
return ssl_hs_ok;
|
|
|
|
}
|
2016-07-11 18:19:03 +01:00
|
|
|
|
2016-11-14 01:32:04 +00:00
|
|
|
static enum ssl_hs_wait_t do_send_hello_retry_request(SSL_HANDSHAKE *hs) {
|
|
|
|
SSL *const ssl = hs->ssl;
|
2017-07-20 04:57:40 +01:00
|
|
|
ScopedCBB cbb;
|
|
|
|
CBB body, extensions;
|
2016-07-18 17:40:30 +01:00
|
|
|
uint16_t group_id;
|
2017-07-20 04:57:40 +01:00
|
|
|
if (!ssl->method->init_message(ssl, cbb.get(), &body,
|
2016-07-18 17:40:30 +01:00
|
|
|
SSL3_MT_HELLO_RETRY_REQUEST) ||
|
|
|
|
!CBB_add_u16(&body, ssl->version) ||
|
2016-11-17 08:20:47 +00:00
|
|
|
!tls1_get_shared_group(hs, &group_id) ||
|
2016-07-18 17:40:30 +01:00
|
|
|
!CBB_add_u16_length_prefixed(&body, &extensions) ||
|
2016-10-08 02:10:38 +01:00
|
|
|
!CBB_add_u16(&extensions, TLSEXT_TYPE_key_share) ||
|
|
|
|
!CBB_add_u16(&extensions, 2 /* length */) ||
|
|
|
|
!CBB_add_u16(&extensions, group_id) ||
|
2017-07-20 04:57:40 +01:00
|
|
|
!ssl_add_message_cbb(ssl, cbb.get())) {
|
2016-07-18 17:40:30 +01:00
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
2016-12-11 18:30:41 +00:00
|
|
|
hs->tls13_state = state_process_second_client_hello;
|
2016-07-18 17:40:30 +01:00
|
|
|
return ssl_hs_flush_and_read_message;
|
|
|
|
}
|
|
|
|
|
2016-11-14 01:32:04 +00:00
|
|
|
static enum ssl_hs_wait_t do_process_second_client_hello(SSL_HANDSHAKE *hs) {
|
|
|
|
SSL *const ssl = hs->ssl;
|
2017-01-21 19:13:39 +00:00
|
|
|
if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_HELLO)) {
|
2016-07-18 17:40:30 +01:00
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
2016-12-04 04:15:13 +00:00
|
|
|
SSL_CLIENT_HELLO client_hello;
|
|
|
|
if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
|
|
|
|
ssl->init_num)) {
|
2016-07-18 17:40:30 +01:00
|
|
|
OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
|
|
|
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
int need_retry;
|
2016-11-17 07:43:08 +00:00
|
|
|
if (!resolve_ecdhe_secret(hs, &need_retry, &client_hello)) {
|
2016-07-18 17:40:30 +01:00
|
|
|
if (need_retry) {
|
|
|
|
/* Only send one HelloRetryRequest. */
|
|
|
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
|
|
|
|
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
|
2016-07-11 18:19:03 +01:00
|
|
|
}
|
2016-07-18 17:40:30 +01:00
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
2017-01-12 18:17:07 +00:00
|
|
|
if (!ssl_hash_current_message(hs)) {
|
2016-07-11 18:19:03 +01:00
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
2016-07-22 16:39:29 +01:00
|
|
|
ssl->method->received_flight(ssl);
|
2016-12-11 18:30:41 +00:00
|
|
|
hs->tls13_state = state_send_server_hello;
|
2016-07-11 18:19:03 +01:00
|
|
|
return ssl_hs_ok;
|
|
|
|
}
|
|
|
|
|
2016-11-14 01:32:04 +00:00
|
|
|
static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
|
|
|
|
SSL *const ssl = hs->ssl;
|
2017-01-13 00:44:57 +00:00
|
|
|
|
2017-07-10 17:57:25 +01:00
|
|
|
uint16_t version = ssl->version;
|
|
|
|
if (ssl->version == TLS1_3_EXPERIMENT_VERSION) {
|
|
|
|
version = TLS1_2_VERSION;
|
|
|
|
}
|
|
|
|
|
2017-01-13 00:44:57 +00:00
|
|
|
/* Send a ServerHello. */
|
2017-07-20 04:57:40 +01:00
|
|
|
ScopedCBB cbb;
|
|
|
|
CBB body, extensions, session_id;
|
|
|
|
if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_SERVER_HELLO) ||
|
2017-07-10 17:57:25 +01:00
|
|
|
!CBB_add_u16(&body, version) ||
|
2016-07-11 18:19:03 +01:00
|
|
|
!RAND_bytes(ssl->s3->server_random, sizeof(ssl->s3->server_random)) ||
|
|
|
|
!CBB_add_bytes(&body, ssl->s3->server_random, SSL3_RANDOM_SIZE) ||
|
2017-06-13 17:45:25 +01:00
|
|
|
(ssl->version == TLS1_3_EXPERIMENT_VERSION &&
|
|
|
|
(!CBB_add_u8_length_prefixed(&body, &session_id) ||
|
|
|
|
!CBB_add_bytes(&session_id, hs->session_id, hs->session_id_len))) ||
|
2017-02-10 01:01:26 +00:00
|
|
|
!CBB_add_u16(&body, ssl_cipher_get_value(hs->new_cipher)) ||
|
2017-06-13 17:45:25 +01:00
|
|
|
(ssl->version == TLS1_3_EXPERIMENT_VERSION && !CBB_add_u8(&body, 0)) ||
|
2016-07-11 18:19:03 +01:00
|
|
|
!CBB_add_u16_length_prefixed(&body, &extensions) ||
|
2016-11-17 08:11:16 +00:00
|
|
|
!ssl_ext_pre_shared_key_add_serverhello(hs, &extensions) ||
|
2017-03-02 21:05:03 +00:00
|
|
|
!ssl_ext_key_share_add_serverhello(hs, &extensions) ||
|
2017-07-10 17:57:25 +01:00
|
|
|
(ssl->version == TLS1_3_EXPERIMENT_VERSION &&
|
|
|
|
!ssl_ext_supported_versions_add_serverhello(hs, &extensions)) ||
|
2017-07-20 04:57:40 +01:00
|
|
|
!ssl_add_message_cbb(ssl, cbb.get())) {
|
|
|
|
return ssl_hs_error;
|
2016-07-11 18:19:03 +01:00
|
|
|
}
|
|
|
|
|
2017-06-13 17:45:25 +01:00
|
|
|
if (ssl->version == TLS1_3_EXPERIMENT_VERSION &&
|
|
|
|
!ssl3_add_change_cipher_spec(ssl)) {
|
2017-07-20 04:57:40 +01:00
|
|
|
return ssl_hs_error;
|
2017-06-13 17:45:25 +01:00
|
|
|
}
|
|
|
|
|
2017-01-13 00:44:57 +00:00
|
|
|
/* Derive and enable the handshake traffic secrets. */
|
2016-12-16 16:29:28 +00:00
|
|
|
if (!tls13_derive_handshake_secrets(hs) ||
|
|
|
|
!tls13_set_traffic_key(ssl, evp_aead_seal, hs->server_handshake_secret,
|
|
|
|
hs->hash_len)) {
|
2017-07-20 04:57:40 +01:00
|
|
|
return ssl_hs_error;
|
2016-07-11 18:19:03 +01:00
|
|
|
}
|
|
|
|
|
2017-01-13 00:44:57 +00:00
|
|
|
/* Send EncryptedExtensions. */
|
2017-07-20 04:57:40 +01:00
|
|
|
if (!ssl->method->init_message(ssl, cbb.get(), &body,
|
2016-07-11 18:19:03 +01:00
|
|
|
SSL3_MT_ENCRYPTED_EXTENSIONS) ||
|
2016-12-03 07:20:34 +00:00
|
|
|
!ssl_add_serverhello_tlsext(hs, &body) ||
|
2017-07-20 04:57:40 +01:00
|
|
|
!ssl_add_message_cbb(ssl, cbb.get())) {
|
|
|
|
return ssl_hs_error;
|
2016-07-11 18:19:03 +01:00
|
|
|
}
|
|
|
|
|
2017-07-01 15:50:56 +01:00
|
|
|
if (!ssl->s3->session_reused) {
|
|
|
|
/* Determine whether to request a client certificate. */
|
|
|
|
hs->cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER);
|
|
|
|
/* Only request a certificate if Channel ID isn't negotiated. */
|
|
|
|
if ((ssl->verify_mode & SSL_VERIFY_PEER_IF_NO_OBC) &&
|
|
|
|
ssl->s3->tlsext_channel_id_valid) {
|
|
|
|
hs->cert_request = 0;
|
|
|
|
}
|
2016-07-11 18:19:03 +01:00
|
|
|
}
|
|
|
|
|
2017-01-13 00:44:57 +00:00
|
|
|
/* Send a CertificateRequest, if necessary. */
|
|
|
|
if (hs->cert_request) {
|
|
|
|
CBB sigalgs_cbb;
|
2017-07-20 04:57:40 +01:00
|
|
|
if (!ssl->method->init_message(ssl, cbb.get(), &body,
|
2017-01-13 00:44:57 +00:00
|
|
|
SSL3_MT_CERTIFICATE_REQUEST) ||
|
2017-03-28 21:38:29 +01:00
|
|
|
!CBB_add_u8(&body, 0 /* no certificate_request_context. */) ||
|
|
|
|
!CBB_add_u16_length_prefixed(&body, &sigalgs_cbb) ||
|
|
|
|
!tls12_add_verify_sigalgs(ssl, &sigalgs_cbb) ||
|
|
|
|
!ssl_add_client_CA_list(ssl, &body) ||
|
2017-01-13 00:44:57 +00:00
|
|
|
!CBB_add_u16(&body, 0 /* empty certificate_extensions. */) ||
|
2017-07-20 04:57:40 +01:00
|
|
|
!ssl_add_message_cbb(ssl, cbb.get())) {
|
|
|
|
return ssl_hs_error;
|
2016-07-11 18:19:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-13 00:44:57 +00:00
|
|
|
/* Send the server Certificate message, if necessary. */
|
|
|
|
if (!ssl->s3->session_reused) {
|
|
|
|
if (!ssl_has_certificate(ssl)) {
|
|
|
|
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET);
|
2017-07-20 04:57:40 +01:00
|
|
|
return ssl_hs_error;
|
2017-01-13 00:44:57 +00:00
|
|
|
}
|
|
|
|
|
2017-01-13 00:46:50 +00:00
|
|
|
if (!tls13_add_certificate(hs)) {
|
2017-07-20 04:57:40 +01:00
|
|
|
return ssl_hs_error;
|
2017-01-13 00:44:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
hs->tls13_state = state_send_server_certificate_verify;
|
|
|
|
return ssl_hs_ok;
|
2016-07-11 18:19:03 +01:00
|
|
|
}
|
|
|
|
|
2017-01-13 00:44:57 +00:00
|
|
|
hs->tls13_state = state_send_server_finished;
|
2017-01-13 00:31:28 +00:00
|
|
|
return ssl_hs_ok;
|
2016-07-11 18:19:03 +01:00
|
|
|
}
|
|
|
|
|
2017-06-17 18:20:59 +01:00
|
|
|
static enum ssl_hs_wait_t do_send_server_certificate_verify(SSL_HANDSHAKE *hs) {
|
|
|
|
switch (tls13_add_certificate_verify(hs)) {
|
2016-07-11 18:19:03 +01:00
|
|
|
case ssl_private_key_success:
|
2016-12-11 18:30:41 +00:00
|
|
|
hs->tls13_state = state_send_server_finished;
|
2017-01-13 00:31:28 +00:00
|
|
|
return ssl_hs_ok;
|
2016-07-11 18:19:03 +01:00
|
|
|
|
|
|
|
case ssl_private_key_retry:
|
2017-06-17 18:20:59 +01:00
|
|
|
hs->tls13_state = state_send_server_certificate_verify;
|
2016-07-11 18:19:03 +01:00
|
|
|
return ssl_hs_private_key_operation;
|
|
|
|
|
|
|
|
case ssl_private_key_failure:
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(0);
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
2016-11-14 01:32:04 +00:00
|
|
|
static enum ssl_hs_wait_t do_send_server_finished(SSL_HANDSHAKE *hs) {
|
|
|
|
SSL *const ssl = hs->ssl;
|
2017-01-13 00:46:50 +00:00
|
|
|
if (!tls13_add_finished(hs) ||
|
2017-01-13 00:31:28 +00:00
|
|
|
/* Update the secret to the master secret and derive traffic keys. */
|
|
|
|
!tls13_advance_key_schedule(hs, kZeroes, hs->hash_len) ||
|
2016-11-17 07:43:08 +00:00
|
|
|
!tls13_derive_application_secrets(hs) ||
|
2016-11-01 17:39:36 +00:00
|
|
|
!tls13_set_traffic_key(ssl, evp_aead_seal, hs->server_traffic_secret_0,
|
|
|
|
hs->hash_len)) {
|
2016-07-11 18:19:03 +01:00
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
2017-03-26 04:24:23 +01:00
|
|
|
if (ssl->early_data_accepted) {
|
|
|
|
/* If accepting 0-RTT, we send tickets half-RTT. This gets the tickets on
|
|
|
|
* the wire sooner and also avoids triggering a write on |SSL_read| when
|
|
|
|
* processing the client Finished. This requires computing the client
|
|
|
|
* Finished early. See draft-ietf-tls-tls13-18, section 4.5.1. */
|
|
|
|
size_t finished_len;
|
|
|
|
if (!tls13_finished_mac(hs, hs->expected_client_finished, &finished_len,
|
|
|
|
0 /* client */)) {
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (finished_len != hs->hash_len) {
|
|
|
|
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Feed the predicted Finished into the transcript. This allows us to derive
|
|
|
|
* the resumption secret early and send half-RTT tickets.
|
|
|
|
*
|
|
|
|
* TODO(davidben): This will need to be updated for DTLS 1.3. */
|
|
|
|
assert(!SSL_is_dtls(hs->ssl));
|
2017-07-13 04:00:28 +01:00
|
|
|
assert(hs->hash_len <= 0xff);
|
2017-07-19 21:38:21 +01:00
|
|
|
uint8_t header[4] = {SSL3_MT_FINISHED, 0, 0,
|
|
|
|
static_cast<uint8_t>(hs->hash_len)};
|
|
|
|
if (!hs->transcript.Update(header, sizeof(header)) ||
|
|
|
|
!hs->transcript.Update(hs->expected_client_finished, hs->hash_len) ||
|
|
|
|
!tls13_derive_resumption_secret(hs) || !add_new_session_tickets(hs)) {
|
2017-03-26 04:24:23 +01:00
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-11 16:34:52 +00:00
|
|
|
hs->tls13_state = state_read_second_client_flight;
|
|
|
|
return ssl_hs_flush;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum ssl_hs_wait_t do_read_second_client_flight(SSL_HANDSHAKE *hs) {
|
|
|
|
SSL *const ssl = hs->ssl;
|
|
|
|
if (ssl->early_data_accepted) {
|
|
|
|
if (!tls13_set_traffic_key(ssl, evp_aead_open, hs->early_traffic_secret,
|
|
|
|
hs->hash_len)) {
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
2016-12-19 18:19:29 +00:00
|
|
|
hs->can_early_write = 1;
|
|
|
|
hs->can_early_read = 1;
|
2017-03-09 19:56:07 +00:00
|
|
|
hs->in_early_data = 1;
|
2017-01-11 16:34:52 +00:00
|
|
|
hs->tls13_state = state_process_end_of_early_data;
|
|
|
|
return ssl_hs_read_end_of_early_data;
|
|
|
|
}
|
|
|
|
hs->tls13_state = state_process_end_of_early_data;
|
|
|
|
return ssl_hs_ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum ssl_hs_wait_t do_process_end_of_early_data(SSL_HANDSHAKE *hs) {
|
2017-06-13 17:45:25 +01:00
|
|
|
hs->tls13_state = state_process_change_cipher_spec;
|
|
|
|
/* If early data was accepted, the ChangeCipherSpec message will be in the
|
|
|
|
* discarded early data. */
|
|
|
|
if (hs->early_data_offered && !hs->ssl->early_data_accepted) {
|
|
|
|
return ssl_hs_ok;
|
|
|
|
}
|
|
|
|
return hs->ssl->version == TLS1_3_EXPERIMENT_VERSION
|
|
|
|
? ssl_hs_read_change_cipher_spec
|
|
|
|
: ssl_hs_ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum ssl_hs_wait_t do_process_change_cipher_spec(SSL_HANDSHAKE *hs) {
|
2017-01-11 16:34:52 +00:00
|
|
|
SSL *const ssl = hs->ssl;
|
|
|
|
if (!tls13_set_traffic_key(ssl, evp_aead_open, hs->client_handshake_secret,
|
|
|
|
hs->hash_len)) {
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
2017-03-26 04:24:23 +01:00
|
|
|
hs->tls13_state = ssl->early_data_accepted ? state_process_client_finished
|
|
|
|
: state_process_client_certificate;
|
2017-01-11 16:34:52 +00:00
|
|
|
return ssl_hs_read_message;
|
2016-07-11 18:19:03 +01:00
|
|
|
}
|
|
|
|
|
2016-11-14 01:32:04 +00:00
|
|
|
static enum ssl_hs_wait_t do_process_client_certificate(SSL_HANDSHAKE *hs) {
|
|
|
|
SSL *const ssl = hs->ssl;
|
|
|
|
if (!hs->cert_request) {
|
2016-08-02 00:16:46 +01:00
|
|
|
/* OpenSSL returns X509_V_OK when no certificates are requested. This is
|
2016-08-18 21:40:28 +01:00
|
|
|
* classed by them as a bug, but it's assumed by at least NGINX. */
|
2017-02-10 01:01:26 +00:00
|
|
|
hs->new_session->verify_result = X509_V_OK;
|
2016-08-02 00:16:46 +01:00
|
|
|
|
2016-07-11 18:19:03 +01:00
|
|
|
/* Skip this state. */
|
2016-12-11 18:30:41 +00:00
|
|
|
hs->tls13_state = state_process_channel_id;
|
2016-07-11 18:19:03 +01:00
|
|
|
return ssl_hs_ok;
|
|
|
|
}
|
|
|
|
|
2016-08-02 01:16:31 +01:00
|
|
|
const int allow_anonymous =
|
|
|
|
(ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) == 0;
|
|
|
|
|
2017-01-21 19:13:39 +00:00
|
|
|
if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) ||
|
2016-12-12 19:46:09 +00:00
|
|
|
!tls13_process_certificate(hs, allow_anonymous) ||
|
2017-01-12 18:17:07 +00:00
|
|
|
!ssl_hash_current_message(hs)) {
|
2016-07-11 18:19:03 +01:00
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
2016-12-11 18:30:41 +00:00
|
|
|
hs->tls13_state = state_process_client_certificate_verify;
|
2016-07-11 18:19:03 +01:00
|
|
|
return ssl_hs_read_message;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum ssl_hs_wait_t do_process_client_certificate_verify(
|
2016-11-14 01:32:04 +00:00
|
|
|
SSL_HANDSHAKE *hs) {
|
|
|
|
SSL *const ssl = hs->ssl;
|
2017-02-10 01:01:26 +00:00
|
|
|
if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) == 0) {
|
2016-07-11 18:19:03 +01:00
|
|
|
/* Skip this state. */
|
2016-12-11 18:30:41 +00:00
|
|
|
hs->tls13_state = state_process_channel_id;
|
2016-07-11 18:19:03 +01:00
|
|
|
return ssl_hs_ok;
|
|
|
|
}
|
|
|
|
|
2017-07-11 21:13:10 +01:00
|
|
|
switch (ssl_verify_peer_cert(hs)) {
|
|
|
|
case ssl_verify_ok:
|
|
|
|
break;
|
|
|
|
case ssl_verify_invalid:
|
|
|
|
return ssl_hs_error;
|
|
|
|
case ssl_verify_retry:
|
|
|
|
hs->tls13_state = state_process_client_certificate_verify;
|
|
|
|
return ssl_hs_certificate_verify;
|
|
|
|
}
|
|
|
|
|
2017-01-21 19:13:39 +00:00
|
|
|
if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) ||
|
2016-12-12 19:46:09 +00:00
|
|
|
!tls13_process_certificate_verify(hs) ||
|
2017-01-12 18:17:07 +00:00
|
|
|
!ssl_hash_current_message(hs)) {
|
2016-11-16 10:10:08 +00:00
|
|
|
return ssl_hs_error;
|
2016-07-11 18:19:03 +01:00
|
|
|
}
|
|
|
|
|
2016-12-11 18:30:41 +00:00
|
|
|
hs->tls13_state = state_process_channel_id;
|
2016-09-24 00:25:11 +01:00
|
|
|
return ssl_hs_read_message;
|
|
|
|
}
|
|
|
|
|
2016-11-14 01:32:04 +00:00
|
|
|
static enum ssl_hs_wait_t do_process_channel_id(SSL_HANDSHAKE *hs) {
|
2017-01-12 18:17:07 +00:00
|
|
|
if (!hs->ssl->s3->tlsext_channel_id_valid) {
|
2016-12-11 18:30:41 +00:00
|
|
|
hs->tls13_state = state_process_client_finished;
|
2016-09-24 00:25:11 +01:00
|
|
|
return ssl_hs_ok;
|
|
|
|
}
|
|
|
|
|
2017-01-12 18:17:07 +00:00
|
|
|
if (!ssl_check_message_type(hs->ssl, SSL3_MT_CHANNEL_ID) ||
|
|
|
|
!tls1_verify_channel_id(hs) ||
|
|
|
|
!ssl_hash_current_message(hs)) {
|
2016-09-24 00:25:11 +01:00
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
2016-12-11 18:30:41 +00:00
|
|
|
hs->tls13_state = state_process_client_finished;
|
2016-07-11 18:19:03 +01:00
|
|
|
return ssl_hs_read_message;
|
|
|
|
}
|
|
|
|
|
2016-11-14 01:32:04 +00:00
|
|
|
static enum ssl_hs_wait_t do_process_client_finished(SSL_HANDSHAKE *hs) {
|
|
|
|
SSL *const ssl = hs->ssl;
|
2017-01-21 19:13:39 +00:00
|
|
|
if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED) ||
|
2017-03-26 04:24:23 +01:00
|
|
|
/* If early data was accepted, we've already computed the client Finished
|
|
|
|
* and derived the resumption secret. */
|
|
|
|
!tls13_process_finished(hs, ssl->early_data_accepted) ||
|
2016-07-11 18:19:03 +01:00
|
|
|
/* evp_aead_seal keys have already been switched. */
|
2016-11-01 17:39:36 +00:00
|
|
|
!tls13_set_traffic_key(ssl, evp_aead_open, hs->client_traffic_secret_0,
|
2017-03-26 04:24:23 +01:00
|
|
|
hs->hash_len)) {
|
2016-07-11 18:19:03 +01:00
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
2016-07-22 16:39:29 +01:00
|
|
|
ssl->method->received_flight(ssl);
|
2016-11-03 20:59:25 +00:00
|
|
|
|
2017-03-26 04:24:23 +01:00
|
|
|
if (!ssl->early_data_accepted) {
|
|
|
|
if (!ssl_hash_current_message(hs) ||
|
|
|
|
!tls13_derive_resumption_secret(hs)) {
|
|
|
|
return ssl_hs_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We send post-handshake tickets as part of the handshake in 1-RTT. */
|
|
|
|
hs->tls13_state = state_send_new_session_ticket;
|
|
|
|
return ssl_hs_ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
hs->tls13_state = state_done;
|
2016-07-11 18:19:03 +01:00
|
|
|
return ssl_hs_ok;
|
|
|
|
}
|
|
|
|
|
2016-11-14 01:32:04 +00:00
|
|
|
static enum ssl_hs_wait_t do_send_new_session_ticket(SSL_HANDSHAKE *hs) {
|
2016-11-01 17:39:36 +00:00
|
|
|
/* If the client doesn't accept resumption with PSK_DHE_KE, don't send a
|
|
|
|
* session ticket. */
|
|
|
|
if (!hs->accept_psk_mode) {
|
2016-12-11 18:30:41 +00:00
|
|
|
hs->tls13_state = state_done;
|
2016-11-01 17:39:36 +00:00
|
|
|
return ssl_hs_ok;
|
|
|
|
}
|
|
|
|
|
2017-03-26 04:24:23 +01:00
|
|
|
if (!add_new_session_tickets(hs)) {
|
|
|
|
return ssl_hs_error;
|
2016-11-03 21:19:16 +00:00
|
|
|
}
|
2016-07-27 16:10:52 +01:00
|
|
|
|
2017-01-13 00:31:28 +00:00
|
|
|
hs->tls13_state = state_done;
|
|
|
|
return ssl_hs_flush;
|
2016-07-27 16:10:52 +01:00
|
|
|
}
|
|
|
|
|
2016-11-14 01:32:04 +00:00
|
|
|
enum ssl_hs_wait_t tls13_server_handshake(SSL_HANDSHAKE *hs) {
|
2016-12-11 18:30:41 +00:00
|
|
|
while (hs->tls13_state != state_done) {
|
2016-07-11 18:19:03 +01:00
|
|
|
enum ssl_hs_wait_t ret = ssl_hs_error;
|
2017-07-13 04:00:28 +01:00
|
|
|
enum server_hs_state_t state =
|
|
|
|
static_cast<enum server_hs_state_t>(hs->tls13_state);
|
2016-07-11 18:19:03 +01:00
|
|
|
switch (state) {
|
2016-08-10 01:00:32 +01:00
|
|
|
case state_select_parameters:
|
2016-11-14 01:32:04 +00:00
|
|
|
ret = do_select_parameters(hs);
|
2016-08-10 01:00:32 +01:00
|
|
|
break;
|
2017-03-10 22:47:18 +00:00
|
|
|
case state_select_session:
|
|
|
|
ret = do_select_session(hs);
|
|
|
|
break;
|
2016-07-18 17:40:30 +01:00
|
|
|
case state_send_hello_retry_request:
|
2016-11-14 01:32:04 +00:00
|
|
|
ret = do_send_hello_retry_request(hs);
|
2016-07-18 17:40:30 +01:00
|
|
|
break;
|
|
|
|
case state_process_second_client_hello:
|
2016-11-14 01:32:04 +00:00
|
|
|
ret = do_process_second_client_hello(hs);
|
2016-07-18 17:40:30 +01:00
|
|
|
break;
|
2016-07-11 18:19:03 +01:00
|
|
|
case state_send_server_hello:
|
2016-11-14 01:32:04 +00:00
|
|
|
ret = do_send_server_hello(hs);
|
2016-07-11 18:19:03 +01:00
|
|
|
break;
|
|
|
|
case state_send_server_certificate_verify:
|
2017-06-17 18:20:59 +01:00
|
|
|
ret = do_send_server_certificate_verify(hs);
|
2017-01-11 16:34:52 +00:00
|
|
|
break;
|
2016-07-11 18:19:03 +01:00
|
|
|
case state_send_server_finished:
|
2016-11-14 01:32:04 +00:00
|
|
|
ret = do_send_server_finished(hs);
|
2016-07-11 18:19:03 +01:00
|
|
|
break;
|
2017-01-11 16:34:52 +00:00
|
|
|
case state_read_second_client_flight:
|
|
|
|
ret = do_read_second_client_flight(hs);
|
|
|
|
break;
|
|
|
|
case state_process_end_of_early_data:
|
|
|
|
ret = do_process_end_of_early_data(hs);
|
|
|
|
break;
|
2017-06-13 17:45:25 +01:00
|
|
|
case state_process_change_cipher_spec:
|
|
|
|
ret = do_process_change_cipher_spec(hs);
|
|
|
|
break;
|
2016-07-11 18:19:03 +01:00
|
|
|
case state_process_client_certificate:
|
2016-11-14 01:32:04 +00:00
|
|
|
ret = do_process_client_certificate(hs);
|
2016-07-11 18:19:03 +01:00
|
|
|
break;
|
|
|
|
case state_process_client_certificate_verify:
|
2016-11-14 01:32:04 +00:00
|
|
|
ret = do_process_client_certificate_verify(hs);
|
2016-07-11 18:19:03 +01:00
|
|
|
break;
|
2016-09-24 00:25:11 +01:00
|
|
|
case state_process_channel_id:
|
2016-11-14 01:32:04 +00:00
|
|
|
ret = do_process_channel_id(hs);
|
2016-09-24 00:25:11 +01:00
|
|
|
break;
|
2016-07-11 18:19:03 +01:00
|
|
|
case state_process_client_finished:
|
2016-11-14 01:32:04 +00:00
|
|
|
ret = do_process_client_finished(hs);
|
2016-07-11 18:19:03 +01:00
|
|
|
break;
|
2016-07-27 16:10:52 +01:00
|
|
|
case state_send_new_session_ticket:
|
2016-11-14 01:32:04 +00:00
|
|
|
ret = do_send_new_session_ticket(hs);
|
2016-07-27 16:10:52 +01:00
|
|
|
break;
|
2016-07-11 18:19:03 +01:00
|
|
|
case state_done:
|
|
|
|
ret = ssl_hs_ok;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret != ssl_hs_ok) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ssl_hs_ok;
|
|
|
|
}
|
Move libssl's internals into the bssl namespace.
This is horrible, but everything else I tried was worse. The goal with
this CL is to take the extern "C" out of ssl/internal.h and move most
symbols to namespace bssl, so we can start using C++ helpers and
destructors without worry.
Complications:
- Public API functions must be extern "C" and match their declaration in
ssl.h, which is unnamespaced. C++ really does not want you to
interleave namespaced and unnamespaced things. One can actually write
a namespaced extern "C" function, but this means, from C++'s
perspective, the function is namespaced. Trying to namespace the
public header would worked but ended up too deep a rabbithole.
- Our STACK_OF macros do not work right in namespaces.
- The typedefs for our exposed but opaque types are visible in the
header files and copied into consuming projects as forward
declarations. We ultimately want to give SSL a destructor, but
clobbering an unnamespaced ssl_st::~ssl_st seems bad manners.
- MSVC complains about ambiguous names if one typedefs SSL to bssl::SSL.
This CL opts for:
- ssl/*.cc must begin with #define BORINGSSL_INTERNAL_CXX_TYPES. This
informs the public headers to create forward declarations which are
compatible with our namespaces.
- For now, C++-defined type FOO ends up at bssl::FOO with a typedef
outside. Later I imagine we'll rename many of them.
- Internal functions get namespace bssl, so we stop worrying about
stomping the tls1_prf symbol. Exported C functions are stuck as they
are. Rather than try anything weird, bite the bullet and reorder files
which have a mix of public and private functions. I expect that over
time, the public functions will become fairly small as we move logic
to more idiomatic C++.
Files without any public C functions can just be written normally.
- To avoid MSVC troubles, some bssl types are renamed to CPlusPlusStyle
in advance of them being made idiomatic C++.
Bug: 132
Change-Id: Ic931895e117c38b14ff8d6e5a273e868796c7581
Reviewed-on: https://boringssl-review.googlesource.com/18124
Reviewed-by: David Benjamin <davidben@google.com>
2017-07-18 21:34:25 +01:00
|
|
|
|
|
|
|
} // namespace bssl
|