boringssl/ssl/tls13_both.cc

669 lines
22 KiB
C++
Raw Normal View History

/* 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. */
#include <openssl/ssl.h>
#include <assert.h>
#include <string.h>
#include <utility>
#include <openssl/bytestring.h>
#include <openssl/err.h>
#include <openssl/hkdf.h>
#include <openssl/mem.h>
#include <openssl/stack.h>
#include <openssl/x509.h>
#include "../crypto/internal.h"
#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 {
// kMaxKeyUpdates is the number of consecutive KeyUpdates that will be
// processed. Without this limit an attacker could force unbounded processing
// without being able to return application data.
static const uint8_t kMaxKeyUpdates = 32;
const uint8_t kHelloRetryRequest[SSL3_RANDOM_SIZE] = {
0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c,
0x02, 0x1e, 0x65, 0xb8, 0x91, 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb,
0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c,
};
const uint8_t kTLS12DowngradeRandom[8] = {0x44, 0x4f, 0x57, 0x4e,
0x47, 0x52, 0x44, 0x00};
const uint8_t kTLS13DowngradeRandom[8] = {0x44, 0x4f, 0x57, 0x4e,
0x47, 0x52, 0x44, 0x01};
bool tls13_get_cert_verify_signature_input(
SSL_HANDSHAKE *hs, Array<uint8_t> *out,
enum ssl_cert_verify_context_t cert_verify_context) {
ScopedCBB cbb;
if (!CBB_init(cbb.get(), 64 + 33 + 1 + 2 * EVP_MAX_MD_SIZE)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return false;
}
for (size_t i = 0; i < 64; i++) {
if (!CBB_add_u8(cbb.get(), 0x20)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return false;
}
}
Span<const char> context;
if (cert_verify_context == ssl_cert_verify_server) {
static const char kContext[] = "TLS 1.3, server CertificateVerify";
context = kContext;
} else if (cert_verify_context == ssl_cert_verify_client) {
static const char kContext[] = "TLS 1.3, client CertificateVerify";
context = kContext;
} else if (cert_verify_context == ssl_cert_verify_channel_id) {
static const char kContext[] = "TLS 1.3, Channel ID";
context = kContext;
} else {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return false;
}
// Note |context| includes the NUL byte separator.
if (!CBB_add_bytes(cbb.get(),
reinterpret_cast<const uint8_t *>(context.data()),
context.size())) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return false;
}
uint8_t context_hash[EVP_MAX_MD_SIZE];
size_t context_hash_len;
if (!hs->transcript.GetHash(context_hash, &context_hash_len) ||
!CBB_add_bytes(cbb.get(), context_hash, context_hash_len) ||
!CBBFinishArray(cbb.get(), out)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return false;
}
return true;
}
int tls13_process_certificate(SSL_HANDSHAKE *hs, const SSLMessage &msg,
int allow_anonymous) {
SSL *const ssl = hs->ssl;
CBS body = msg.body;
bssl::UniquePtr<CRYPTO_BUFFER> decompressed;
if (msg.type == SSL3_MT_COMPRESSED_CERTIFICATE) {
CBS compressed;
uint16_t alg_id;
uint32_t uncompressed_len;
if (!CBS_get_u16(&body, &alg_id) ||
!CBS_get_u24(&body, &uncompressed_len) ||
!CBS_get_u24_length_prefixed(&body, &compressed) ||
CBS_len(&body) != 0) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
return 0;
}
if (uncompressed_len > ssl->max_cert_list) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
OPENSSL_PUT_ERROR(SSL, SSL_R_UNCOMPRESSED_CERT_TOO_LARGE);
ERR_add_error_dataf("requested=%u",
static_cast<unsigned>(uncompressed_len));
return 0;
}
ssl_cert_decompression_func_t decompress = nullptr;
for (const auto* alg : ssl->ctx->cert_compression_algs.get()) {
if (alg->alg_id == alg_id) {
decompress = alg->decompress;
break;
}
}
if (decompress == nullptr) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERT_COMPRESSION_ALG);
ERR_add_error_dataf("alg=%d", static_cast<int>(alg_id));
return 0;
}
CRYPTO_BUFFER *decompressed_ptr = nullptr;
if (!decompress(ssl, &decompressed_ptr, uncompressed_len,
CBS_data(&compressed), CBS_len(&compressed))) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_DECOMPRESSION_FAILED);
ERR_add_error_dataf("alg=%d", static_cast<int>(alg_id));
return 0;
}
decompressed.reset(decompressed_ptr);
if (CRYPTO_BUFFER_len(decompressed_ptr) != uncompressed_len) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_DECOMPRESSION_FAILED);
ERR_add_error_dataf(
"alg=%d got=%u expected=%u", static_cast<int>(alg_id),
static_cast<unsigned>(CRYPTO_BUFFER_len(decompressed_ptr)),
static_cast<unsigned>(uncompressed_len));
return 0;
}
CBS_init(&body, CRYPTO_BUFFER_data(decompressed_ptr),
CRYPTO_BUFFER_len(decompressed_ptr));
} else {
assert(msg.type == SSL3_MT_CERTIFICATE);
}
CBS context, certificate_list;
if (!CBS_get_u8_length_prefixed(&body, &context) ||
CBS_len(&context) != 0 ||
!CBS_get_u24_length_prefixed(&body, &certificate_list) ||
CBS_len(&body) != 0) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
return 0;
}
UniquePtr<STACK_OF(CRYPTO_BUFFER)> certs(sk_CRYPTO_BUFFER_new_null());
if (!certs) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return 0;
}
const bool retain_sha256 =
SSL_CONFIG: new struct for sheddable handshake configuration. |SSL_CONFIG| is a container for bits of configuration that are unneeded after the handshake completes. By default it is retained for the life of the |SSL|, but it may be shed at the caller's option by calling SSL_set_shed_handshake_config(). This is incompatible with renegotiation, and with SSL_clear(). |SSL_CONFIG| is reachable by |ssl->config| and by |hs->config|. The latter is always non-NULL. To avoid null checks, I've changed the signature of a number of functions from |SSL*| arguments to |SSL_HANDSHAKE*| arguments. When configuration has been shed, setters that touch |SSL_CONFIG| return an error value if that is possible. Setters that return |void| do nothing. Getters that request |SSL_CONFIG| values will fail with an |assert| if the configuration has been shed. When asserts are compiled out, they will return an error value. The aim of this commit is to simplify analysis of split-handshakes by making it obvious that some bits of state have no effects beyond the handshake. It also cuts down on memory usage. Of note: |SSL_CTX| is still reachable after the configuration has been shed, and a couple things need to be retained only for the sake of post-handshake hooks. Perhaps these can be fixed in time. Change-Id: Idf09642e0518945b81a1e9fcd7331cc9cf7cc2d6 Bug: 123 Reviewed-on: https://boringssl-review.googlesource.com/27644 Commit-Queue: David Benjamin <davidben@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org> Reviewed-by: David Benjamin <davidben@google.com>
2018-04-13 23:51:30 +01:00
ssl->server && hs->config->retain_only_sha256_of_client_certs;
UniquePtr<EVP_PKEY> pkey;
while (CBS_len(&certificate_list) > 0) {
CBS certificate, extensions;
if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) ||
!CBS_get_u16_length_prefixed(&certificate_list, &extensions) ||
CBS_len(&certificate) == 0) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
return 0;
}
if (sk_CRYPTO_BUFFER_num(certs.get()) == 0) {
pkey = ssl_cert_parse_pubkey(&certificate);
if (!pkey) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
return 0;
}
// TLS 1.3 always uses certificate keys for signing thus the correct
// keyUsage is enforced.
if (!ssl_cert_check_digital_signature_key_usage(&certificate)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return 0;
}
if (retain_sha256) {
// Retain the hash of the leaf certificate if requested.
SHA256(CBS_data(&certificate), CBS_len(&certificate),
hs->new_session->peer_sha256);
}
}
UniquePtr<CRYPTO_BUFFER> buf(
CRYPTO_BUFFER_new_from_CBS(&certificate, ssl->ctx->pool));
if (!buf ||
!PushToStack(certs.get(), std::move(buf))) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return 0;
}
// Parse out the extensions.
bool have_status_request = false, have_sct = false;
CBS status_request, sct;
const SSL_EXTENSION_TYPE ext_types[] = {
{TLSEXT_TYPE_status_request, &have_status_request, &status_request},
{TLSEXT_TYPE_certificate_timestamp, &have_sct, &sct},
};
uint8_t alert = SSL_AD_DECODE_ERROR;
if (!ssl_parse_extensions(&extensions, &alert, ext_types,
OPENSSL_ARRAY_SIZE(ext_types),
0 /* reject unknown */)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return 0;
}
// All Certificate extensions are parsed, but only the leaf extensions are
// stored.
if (have_status_request) {
SSL_CONFIG: new struct for sheddable handshake configuration. |SSL_CONFIG| is a container for bits of configuration that are unneeded after the handshake completes. By default it is retained for the life of the |SSL|, but it may be shed at the caller's option by calling SSL_set_shed_handshake_config(). This is incompatible with renegotiation, and with SSL_clear(). |SSL_CONFIG| is reachable by |ssl->config| and by |hs->config|. The latter is always non-NULL. To avoid null checks, I've changed the signature of a number of functions from |SSL*| arguments to |SSL_HANDSHAKE*| arguments. When configuration has been shed, setters that touch |SSL_CONFIG| return an error value if that is possible. Setters that return |void| do nothing. Getters that request |SSL_CONFIG| values will fail with an |assert| if the configuration has been shed. When asserts are compiled out, they will return an error value. The aim of this commit is to simplify analysis of split-handshakes by making it obvious that some bits of state have no effects beyond the handshake. It also cuts down on memory usage. Of note: |SSL_CTX| is still reachable after the configuration has been shed, and a couple things need to be retained only for the sake of post-handshake hooks. Perhaps these can be fixed in time. Change-Id: Idf09642e0518945b81a1e9fcd7331cc9cf7cc2d6 Bug: 123 Reviewed-on: https://boringssl-review.googlesource.com/27644 Commit-Queue: David Benjamin <davidben@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org> Reviewed-by: David Benjamin <davidben@google.com>
2018-04-13 23:51:30 +01:00
if (ssl->server || !hs->config->ocsp_stapling_enabled) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
return 0;
}
uint8_t status_type;
CBS ocsp_response;
if (!CBS_get_u8(&status_request, &status_type) ||
status_type != TLSEXT_STATUSTYPE_ocsp ||
!CBS_get_u24_length_prefixed(&status_request, &ocsp_response) ||
CBS_len(&ocsp_response) == 0 ||
CBS_len(&status_request) != 0) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return 0;
}
if (sk_CRYPTO_BUFFER_num(certs.get()) == 1) {
hs->new_session->ocsp_response.reset(
CRYPTO_BUFFER_new_from_CBS(&ocsp_response, ssl->ctx->pool));
if (hs->new_session->ocsp_response == nullptr) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return 0;
}
}
}
if (have_sct) {
SSL_CONFIG: new struct for sheddable handshake configuration. |SSL_CONFIG| is a container for bits of configuration that are unneeded after the handshake completes. By default it is retained for the life of the |SSL|, but it may be shed at the caller's option by calling SSL_set_shed_handshake_config(). This is incompatible with renegotiation, and with SSL_clear(). |SSL_CONFIG| is reachable by |ssl->config| and by |hs->config|. The latter is always non-NULL. To avoid null checks, I've changed the signature of a number of functions from |SSL*| arguments to |SSL_HANDSHAKE*| arguments. When configuration has been shed, setters that touch |SSL_CONFIG| return an error value if that is possible. Setters that return |void| do nothing. Getters that request |SSL_CONFIG| values will fail with an |assert| if the configuration has been shed. When asserts are compiled out, they will return an error value. The aim of this commit is to simplify analysis of split-handshakes by making it obvious that some bits of state have no effects beyond the handshake. It also cuts down on memory usage. Of note: |SSL_CTX| is still reachable after the configuration has been shed, and a couple things need to be retained only for the sake of post-handshake hooks. Perhaps these can be fixed in time. Change-Id: Idf09642e0518945b81a1e9fcd7331cc9cf7cc2d6 Bug: 123 Reviewed-on: https://boringssl-review.googlesource.com/27644 Commit-Queue: David Benjamin <davidben@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org> Reviewed-by: David Benjamin <davidben@google.com>
2018-04-13 23:51:30 +01:00
if (ssl->server || !hs->config->signed_cert_timestamps_enabled) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
return 0;
}
if (!ssl_is_sct_list_valid(&sct)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return 0;
}
if (sk_CRYPTO_BUFFER_num(certs.get()) == 1) {
hs->new_session->signed_cert_timestamp_list.reset(
CRYPTO_BUFFER_new_from_CBS(&sct, ssl->ctx->pool));
if (hs->new_session->signed_cert_timestamp_list == nullptr) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return 0;
}
}
}
}
// Store a null certificate list rather than an empty one if the peer didn't
// send certificates.
if (sk_CRYPTO_BUFFER_num(certs.get()) == 0) {
certs.reset();
}
hs->peer_pubkey = std::move(pkey);
hs->new_session->certs = std::move(certs);
if (!ssl->ctx->x509_method->session_cache_objects(hs->new_session.get())) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return 0;
}
if (sk_CRYPTO_BUFFER_num(hs->new_session->certs.get()) == 0) {
if (!allow_anonymous) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_CERTIFICATE_REQUIRED);
return 0;
}
// OpenSSL returns X509_V_OK when no certificates are requested. This is
// classed by them as a bug, but it's assumed by at least NGINX.
hs->new_session->verify_result = X509_V_OK;
// No certificate, so nothing more to do.
return 1;
}
hs->new_session->peer_sha256_valid = retain_sha256;
return 1;
}
int tls13_process_certificate_verify(SSL_HANDSHAKE *hs, const SSLMessage &msg) {
SSL *const ssl = hs->ssl;
if (hs->peer_pubkey == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
CBS body = msg.body, signature;
uint16_t signature_algorithm;
if (!CBS_get_u16(&body, &signature_algorithm) ||
!CBS_get_u16_length_prefixed(&body, &signature) ||
CBS_len(&body) != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return 0;
}
uint8_t alert = SSL_AD_DECODE_ERROR;
if (!tls12_check_peer_sigalg(ssl, &alert, signature_algorithm)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return 0;
}
hs->new_session->peer_signature_algorithm = signature_algorithm;
Array<uint8_t> input;
if (!tls13_get_cert_verify_signature_input(
hs, &input,
ssl->server ? ssl_cert_verify_client : ssl_cert_verify_server)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return 0;
}
bool sig_ok = ssl_public_key_verify(ssl, signature, signature_algorithm,
hs->peer_pubkey.get(), input);
#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
sig_ok = true;
ERR_clear_error();
#endif
if (!sig_ok) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
return 0;
}
return 1;
}
int tls13_process_finished(SSL_HANDSHAKE *hs, const SSLMessage &msg,
int use_saved_value) {
SSL *const ssl = hs->ssl;
uint8_t verify_data_buf[EVP_MAX_MD_SIZE];
const uint8_t *verify_data;
size_t verify_data_len;
if (use_saved_value) {
assert(ssl->server);
verify_data = hs->expected_client_finished;
verify_data_len = hs->hash_len;
} else {
if (!tls13_finished_mac(hs, verify_data_buf, &verify_data_len,
!ssl->server)) {
return 0;
}
verify_data = verify_data_buf;
}
int finished_ok = CBS_mem_equal(&msg.body, verify_data, verify_data_len);
#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
finished_ok = 1;
#endif
if (!finished_ok) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED);
return 0;
}
return 1;
}
int tls13_add_certificate(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
CERT *const cert = hs->config->cert.get();
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
ScopedCBB cbb;
CBB *body, body_storage, certificate_list;
if (hs->cert_compression_negotiated) {
if (!CBB_init(cbb.get(), 1024)) {
return false;
}
body = cbb.get();
} else {
body = &body_storage;
if (!ssl->method->init_message(ssl, cbb.get(), body, SSL3_MT_CERTIFICATE)) {
return false;
}
}
if (// The request context is always empty in the handshake.
!CBB_add_u8(body, 0) ||
!CBB_add_u24_length_prefixed(body, &certificate_list)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
SSL_CONFIG: new struct for sheddable handshake configuration. |SSL_CONFIG| is a container for bits of configuration that are unneeded after the handshake completes. By default it is retained for the life of the |SSL|, but it may be shed at the caller's option by calling SSL_set_shed_handshake_config(). This is incompatible with renegotiation, and with SSL_clear(). |SSL_CONFIG| is reachable by |ssl->config| and by |hs->config|. The latter is always non-NULL. To avoid null checks, I've changed the signature of a number of functions from |SSL*| arguments to |SSL_HANDSHAKE*| arguments. When configuration has been shed, setters that touch |SSL_CONFIG| return an error value if that is possible. Setters that return |void| do nothing. Getters that request |SSL_CONFIG| values will fail with an |assert| if the configuration has been shed. When asserts are compiled out, they will return an error value. The aim of this commit is to simplify analysis of split-handshakes by making it obvious that some bits of state have no effects beyond the handshake. It also cuts down on memory usage. Of note: |SSL_CTX| is still reachable after the configuration has been shed, and a couple things need to be retained only for the sake of post-handshake hooks. Perhaps these can be fixed in time. Change-Id: Idf09642e0518945b81a1e9fcd7331cc9cf7cc2d6 Bug: 123 Reviewed-on: https://boringssl-review.googlesource.com/27644 Commit-Queue: David Benjamin <davidben@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org> Reviewed-by: David Benjamin <davidben@google.com>
2018-04-13 23:51:30 +01:00
if (!ssl_has_certificate(hs->config)) {
return ssl_add_message_cbb(ssl, cbb.get());
}
CRYPTO_BUFFER *leaf_buf = sk_CRYPTO_BUFFER_value(cert->chain.get(), 0);
CBB leaf, extensions;
if (!CBB_add_u24_length_prefixed(&certificate_list, &leaf) ||
!CBB_add_bytes(&leaf, CRYPTO_BUFFER_data(leaf_buf),
CRYPTO_BUFFER_len(leaf_buf)) ||
!CBB_add_u16_length_prefixed(&certificate_list, &extensions)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
if (hs->scts_requested && cert->signed_cert_timestamp_list != nullptr) {
CBB contents;
if (!CBB_add_u16(&extensions, TLSEXT_TYPE_certificate_timestamp) ||
!CBB_add_u16_length_prefixed(&extensions, &contents) ||
!CBB_add_bytes(
&contents,
CRYPTO_BUFFER_data(cert->signed_cert_timestamp_list.get()),
CRYPTO_BUFFER_len(cert->signed_cert_timestamp_list.get())) ||
!CBB_flush(&extensions)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
}
if (hs->ocsp_stapling_requested && cert->ocsp_response != NULL) {
CBB contents, ocsp_response;
if (!CBB_add_u16(&extensions, TLSEXT_TYPE_status_request) ||
!CBB_add_u16_length_prefixed(&extensions, &contents) ||
!CBB_add_u8(&contents, TLSEXT_STATUSTYPE_ocsp) ||
!CBB_add_u24_length_prefixed(&contents, &ocsp_response) ||
!CBB_add_bytes(&ocsp_response,
CRYPTO_BUFFER_data(cert->ocsp_response.get()),
CRYPTO_BUFFER_len(cert->ocsp_response.get())) ||
!CBB_flush(&extensions)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
}
for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(cert->chain.get()); i++) {
CRYPTO_BUFFER *cert_buf = sk_CRYPTO_BUFFER_value(cert->chain.get(), i);
CBB child;
if (!CBB_add_u24_length_prefixed(&certificate_list, &child) ||
!CBB_add_bytes(&child, CRYPTO_BUFFER_data(cert_buf),
CRYPTO_BUFFER_len(cert_buf)) ||
!CBB_add_u16(&certificate_list, 0 /* no extensions */)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
}
if (!hs->cert_compression_negotiated) {
return ssl_add_message_cbb(ssl, cbb.get());
}
Array<uint8_t> msg;
if (!CBBFinishArray(cbb.get(), &msg)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
const CertCompressionAlg *alg = nullptr;
for (const auto *candidate : ssl->ctx->cert_compression_algs.get()) {
if (candidate->alg_id == hs->cert_compression_alg_id) {
alg = candidate;
break;
}
}
if (alg == nullptr || alg->compress == nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
CBB compressed;
body = &body_storage;
if (!ssl->method->init_message(ssl, cbb.get(), body,
SSL3_MT_COMPRESSED_CERTIFICATE) ||
!CBB_add_u16(body, hs->cert_compression_alg_id) ||
!CBB_add_u24(body, msg.size()) ||
!CBB_add_u24_length_prefixed(body, &compressed) ||
!alg->compress(ssl, &compressed, msg.data(), msg.size()) ||
!ssl_add_message_cbb(ssl, cbb.get())) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
return 1;
}
Simplify ssl_private_key_* state machine points. The original motivation behind the sign/complete split was to avoid needlessly hashing the input on each pass through the state machine, but we're payload-based now and, in all cases, the payload is either cheap to compute or readily available. (Even the hashing worry was probably unnecessary.) Tweak ssl_private_key_{sign,decrypt} to automatically call ssl_private_key_complete as needed and take advantage of this in the handshake state machines: - TLS 1.3 signing now computes the payload each pass. The payload is small and we're already allocating a comparable-sized buffer each iteration to hold the signature. This shouldn't be a big deal. - TLS 1.2 decryption code still needs two states due to reading the message (fixed in new state machine style), but otherwise it just performs cheap idempotent tasks again. The PSK code is reshuffled to guarantee the callback is not called twice (though this was impossible anyway because we don't support RSA_PSK). - TLS 1.2 CertificateVerify signing is easy as the transcript is readily available. The buffer is released very slightly later, but it shouldn't matter. - TLS 1.2 ServerKeyExchange signing required some reshuffling. Assembling the ServerKeyExchange parameters is moved to the previous state. The signing payload has some randoms prepended. This is cheap enough, but a nuisance in C. Pre-prepend the randoms in hs->server_params. With this change, we are *nearly* rid of the A/B => same function pattern. BUG=128 Change-Id: Iec4fe0be7cfc88a6de027ba2760fae70794ea810 Reviewed-on: https://boringssl-review.googlesource.com/17265 Commit-Queue: David Benjamin <davidben@google.com> Commit-Queue: Steven Valdez <svaldez@google.com> Reviewed-by: Steven Valdez <svaldez@google.com>
2017-06-17 18:20:59 +01:00
enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
uint16_t signature_algorithm;
if (!tls1_choose_signature_algorithm(hs, &signature_algorithm)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
return ssl_private_key_failure;
}
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
ScopedCBB cbb;
CBB body;
if (!ssl->method->init_message(ssl, cbb.get(), &body,
SSL3_MT_CERTIFICATE_VERIFY) ||
!CBB_add_u16(&body, signature_algorithm)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return ssl_private_key_failure;
}
// Sign the digest.
CBB child;
const size_t max_sig_len = EVP_PKEY_size(hs->local_pubkey.get());
uint8_t *sig;
size_t sig_len;
if (!CBB_add_u16_length_prefixed(&body, &child) ||
!CBB_reserve(&child, &sig, max_sig_len)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return ssl_private_key_failure;
}
Array<uint8_t> msg;
Simplify ssl_private_key_* state machine points. The original motivation behind the sign/complete split was to avoid needlessly hashing the input on each pass through the state machine, but we're payload-based now and, in all cases, the payload is either cheap to compute or readily available. (Even the hashing worry was probably unnecessary.) Tweak ssl_private_key_{sign,decrypt} to automatically call ssl_private_key_complete as needed and take advantage of this in the handshake state machines: - TLS 1.3 signing now computes the payload each pass. The payload is small and we're already allocating a comparable-sized buffer each iteration to hold the signature. This shouldn't be a big deal. - TLS 1.2 decryption code still needs two states due to reading the message (fixed in new state machine style), but otherwise it just performs cheap idempotent tasks again. The PSK code is reshuffled to guarantee the callback is not called twice (though this was impossible anyway because we don't support RSA_PSK). - TLS 1.2 CertificateVerify signing is easy as the transcript is readily available. The buffer is released very slightly later, but it shouldn't matter. - TLS 1.2 ServerKeyExchange signing required some reshuffling. Assembling the ServerKeyExchange parameters is moved to the previous state. The signing payload has some randoms prepended. This is cheap enough, but a nuisance in C. Pre-prepend the randoms in hs->server_params. With this change, we are *nearly* rid of the A/B => same function pattern. BUG=128 Change-Id: Iec4fe0be7cfc88a6de027ba2760fae70794ea810 Reviewed-on: https://boringssl-review.googlesource.com/17265 Commit-Queue: David Benjamin <davidben@google.com> Commit-Queue: Steven Valdez <svaldez@google.com> Reviewed-by: Steven Valdez <svaldez@google.com>
2017-06-17 18:20:59 +01:00
if (!tls13_get_cert_verify_signature_input(
hs, &msg,
Simplify ssl_private_key_* state machine points. The original motivation behind the sign/complete split was to avoid needlessly hashing the input on each pass through the state machine, but we're payload-based now and, in all cases, the payload is either cheap to compute or readily available. (Even the hashing worry was probably unnecessary.) Tweak ssl_private_key_{sign,decrypt} to automatically call ssl_private_key_complete as needed and take advantage of this in the handshake state machines: - TLS 1.3 signing now computes the payload each pass. The payload is small and we're already allocating a comparable-sized buffer each iteration to hold the signature. This shouldn't be a big deal. - TLS 1.2 decryption code still needs two states due to reading the message (fixed in new state machine style), but otherwise it just performs cheap idempotent tasks again. The PSK code is reshuffled to guarantee the callback is not called twice (though this was impossible anyway because we don't support RSA_PSK). - TLS 1.2 CertificateVerify signing is easy as the transcript is readily available. The buffer is released very slightly later, but it shouldn't matter. - TLS 1.2 ServerKeyExchange signing required some reshuffling. Assembling the ServerKeyExchange parameters is moved to the previous state. The signing payload has some randoms prepended. This is cheap enough, but a nuisance in C. Pre-prepend the randoms in hs->server_params. With this change, we are *nearly* rid of the A/B => same function pattern. BUG=128 Change-Id: Iec4fe0be7cfc88a6de027ba2760fae70794ea810 Reviewed-on: https://boringssl-review.googlesource.com/17265 Commit-Queue: David Benjamin <davidben@google.com> Commit-Queue: Steven Valdez <svaldez@google.com> Reviewed-by: Steven Valdez <svaldez@google.com>
2017-06-17 18:20:59 +01:00
ssl->server ? ssl_cert_verify_server : ssl_cert_verify_client)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return ssl_private_key_failure;
}
Simplify ssl_private_key_* state machine points. The original motivation behind the sign/complete split was to avoid needlessly hashing the input on each pass through the state machine, but we're payload-based now and, in all cases, the payload is either cheap to compute or readily available. (Even the hashing worry was probably unnecessary.) Tweak ssl_private_key_{sign,decrypt} to automatically call ssl_private_key_complete as needed and take advantage of this in the handshake state machines: - TLS 1.3 signing now computes the payload each pass. The payload is small and we're already allocating a comparable-sized buffer each iteration to hold the signature. This shouldn't be a big deal. - TLS 1.2 decryption code still needs two states due to reading the message (fixed in new state machine style), but otherwise it just performs cheap idempotent tasks again. The PSK code is reshuffled to guarantee the callback is not called twice (though this was impossible anyway because we don't support RSA_PSK). - TLS 1.2 CertificateVerify signing is easy as the transcript is readily available. The buffer is released very slightly later, but it shouldn't matter. - TLS 1.2 ServerKeyExchange signing required some reshuffling. Assembling the ServerKeyExchange parameters is moved to the previous state. The signing payload has some randoms prepended. This is cheap enough, but a nuisance in C. Pre-prepend the randoms in hs->server_params. With this change, we are *nearly* rid of the A/B => same function pattern. BUG=128 Change-Id: Iec4fe0be7cfc88a6de027ba2760fae70794ea810 Reviewed-on: https://boringssl-review.googlesource.com/17265 Commit-Queue: David Benjamin <davidben@google.com> Commit-Queue: Steven Valdez <svaldez@google.com> Reviewed-by: Steven Valdez <svaldez@google.com>
2017-06-17 18:20:59 +01:00
enum ssl_private_key_result_t sign_result = ssl_private_key_sign(
hs, sig, &sig_len, max_sig_len, signature_algorithm, msg);
if (sign_result != ssl_private_key_success) {
return sign_result;
}
if (!CBB_did_write(&child, sig_len) ||
!ssl_add_message_cbb(ssl, cbb.get())) {
return ssl_private_key_failure;
}
return ssl_private_key_success;
}
int tls13_add_finished(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
size_t verify_data_len;
uint8_t verify_data[EVP_MAX_MD_SIZE];
if (!tls13_finished_mac(hs, verify_data, &verify_data_len, ssl->server)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED);
return 0;
}
ScopedCBB cbb;
CBB body;
if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_FINISHED) ||
!CBB_add_bytes(&body, verify_data, verify_data_len) ||
!ssl_add_message_cbb(ssl, cbb.get())) {
return 0;
}
return 1;
}
static int tls13_receive_key_update(SSL *ssl, const SSLMessage &msg) {
CBS body = msg.body;
uint8_t key_update_request;
if (!CBS_get_u8(&body, &key_update_request) ||
CBS_len(&body) != 0 ||
(key_update_request != SSL_KEY_UPDATE_NOT_REQUESTED &&
key_update_request != SSL_KEY_UPDATE_REQUESTED)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return 0;
}
if (!tls13_rotate_traffic_key(ssl, evp_aead_open)) {
return 0;
}
// Acknowledge the KeyUpdate
if (key_update_request == SSL_KEY_UPDATE_REQUESTED &&
!ssl->s3->key_update_pending) {
ScopedCBB cbb;
CBB body_cbb;
if (!ssl->method->init_message(ssl, cbb.get(), &body_cbb,
SSL3_MT_KEY_UPDATE) ||
!CBB_add_u8(&body_cbb, SSL_KEY_UPDATE_NOT_REQUESTED) ||
!ssl_add_message_cbb(ssl, cbb.get()) ||
!tls13_rotate_traffic_key(ssl, evp_aead_seal)) {
return 0;
}
// Suppress KeyUpdate acknowledgments until this change is written to the
// wire. This prevents us from accumulating write obligations when read and
// write progress at different rates. See RFC 8446, section 4.6.3.
ssl->s3->key_update_pending = true;
}
return 1;
}
int tls13_post_handshake(SSL *ssl, const SSLMessage &msg) {
if (msg.type == SSL3_MT_KEY_UPDATE) {
ssl->s3->key_update_count++;
if (ssl->s3->key_update_count > kMaxKeyUpdates) {
OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_KEY_UPDATES);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
return 0;
}
return tls13_receive_key_update(ssl, msg);
}
ssl->s3->key_update_count = 0;
if (msg.type == SSL3_MT_NEW_SESSION_TICKET && !ssl->server) {
return tls13_process_new_session_ticket(ssl, msg);
}
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
return 0;
}
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