Migrate TLS 1.2 and below state machines to the new style.
Bug: 128
Change-Id: Ief3779b1c43dd34a154a0f1d2f94d0da756bc07a
Reviewed-on: https://boringssl-review.googlesource.com/19144
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/ssl/CMakeLists.txt b/ssl/CMakeLists.txt
index d9d2eb5..912327b 100644
--- a/ssl/CMakeLists.txt
+++ b/ssl/CMakeLists.txt
@@ -11,6 +11,7 @@
d1_srtp.cc
dtls_method.cc
dtls_record.cc
+ handshake.cc
handshake_client.cc
handshake_server.cc
s3_both.cc
diff --git a/ssl/handshake.cc b/ssl/handshake.cc
new file mode 100644
index 0000000..ec6213f
--- /dev/null
+++ b/ssl/handshake.cc
@@ -0,0 +1,566 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+namespace bssl {
+
+SSL_HANDSHAKE::SSL_HANDSHAKE(SSL *ssl_arg)
+ : ssl(ssl_arg),
+ scts_requested(0),
+ needs_psk_binder(0),
+ received_hello_retry_request(0),
+ received_custom_extension(0),
+ accept_psk_mode(0),
+ cert_request(0),
+ certificate_status_expected(0),
+ ocsp_stapling_requested(0),
+ should_ack_sni(0),
+ in_false_start(0),
+ in_early_data(0),
+ early_data_offered(0),
+ can_early_read(0),
+ can_early_write(0),
+ next_proto_neg_seen(0),
+ ticket_expected(0),
+ extended_master_secret(0),
+ pending_private_key_op(0) {
+}
+
+SSL_HANDSHAKE::~SSL_HANDSHAKE() {
+ OPENSSL_cleanse(secret, sizeof(secret));
+ OPENSSL_cleanse(early_traffic_secret, sizeof(early_traffic_secret));
+ OPENSSL_cleanse(client_handshake_secret, sizeof(client_handshake_secret));
+ OPENSSL_cleanse(server_handshake_secret, sizeof(server_handshake_secret));
+ OPENSSL_cleanse(client_traffic_secret_0, sizeof(client_traffic_secret_0));
+ OPENSSL_cleanse(server_traffic_secret_0, sizeof(server_traffic_secret_0));
+ OPENSSL_free(cookie);
+ OPENSSL_free(key_share_bytes);
+ OPENSSL_free(ecdh_public_key);
+ OPENSSL_free(peer_sigalgs);
+ OPENSSL_free(peer_supported_group_list);
+ OPENSSL_free(peer_key);
+ OPENSSL_free(server_params);
+ ssl->ctx->x509_method->hs_flush_cached_ca_names(this);
+ OPENSSL_free(certificate_types);
+
+ if (key_block != NULL) {
+ OPENSSL_cleanse(key_block, key_block_len);
+ OPENSSL_free(key_block);
+ }
+}
+
+SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl) {
+ UniquePtr<SSL_HANDSHAKE> hs = MakeUnique<SSL_HANDSHAKE>(ssl);
+ if (!hs ||
+ !hs->transcript.Init()) {
+ return nullptr;
+ }
+ return hs.release();
+}
+
+void ssl_handshake_free(SSL_HANDSHAKE *hs) { Delete(hs); }
+
+int ssl_check_message_type(SSL *ssl, const SSLMessage &msg, int type) {
+ if (msg.type != type) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
+ ERR_add_error_dataf("got type %d, wanted type %d", msg.type, type);
+ return 0;
+ }
+
+ return 1;
+}
+
+int ssl_add_message_cbb(SSL *ssl, CBB *cbb) {
+ uint8_t *msg;
+ size_t len;
+ if (!ssl->method->finish_message(ssl, cbb, &msg, &len) ||
+ !ssl->method->add_message(ssl, msg, len)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+size_t ssl_max_handshake_message_len(const SSL *ssl) {
+ /* kMaxMessageLen is the default maximum message size for handshakes which do
+ * not accept peer certificate chains. */
+ static const size_t kMaxMessageLen = 16384;
+
+ if (SSL_in_init(ssl)) {
+ if ((!ssl->server || (ssl->verify_mode & SSL_VERIFY_PEER)) &&
+ kMaxMessageLen < ssl->max_cert_list) {
+ return ssl->max_cert_list;
+ }
+ return kMaxMessageLen;
+ }
+
+ if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+ /* In TLS 1.2 and below, the largest acceptable post-handshake message is
+ * a HelloRequest. */
+ return 0;
+ }
+
+ if (ssl->server) {
+ /* The largest acceptable post-handshake message for a server is a
+ * KeyUpdate. We will never initiate post-handshake auth. */
+ return 1;
+ }
+
+ /* Clients must accept NewSessionTicket and CertificateRequest, so allow the
+ * default size. */
+ return kMaxMessageLen;
+}
+
+bool ssl_hash_message(SSL_HANDSHAKE *hs, const SSLMessage &msg) {
+ /* V2ClientHello messages are pre-hashed. */
+ if (msg.is_v2_hello) {
+ return true;
+ }
+
+ return hs->transcript.Update(CBS_data(&msg.raw), CBS_len(&msg.raw));
+}
+
+int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert,
+ const SSL_EXTENSION_TYPE *ext_types,
+ size_t num_ext_types, int ignore_unknown) {
+ /* Reset everything. */
+ for (size_t i = 0; i < num_ext_types; i++) {
+ *ext_types[i].out_present = 0;
+ CBS_init(ext_types[i].out_data, NULL, 0);
+ }
+
+ CBS copy = *cbs;
+ while (CBS_len(©) != 0) {
+ uint16_t type;
+ CBS data;
+ if (!CBS_get_u16(©, &type) ||
+ !CBS_get_u16_length_prefixed(©, &data)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ const SSL_EXTENSION_TYPE *ext_type = NULL;
+ for (size_t i = 0; i < num_ext_types; i++) {
+ if (type == ext_types[i].type) {
+ ext_type = &ext_types[i];
+ break;
+ }
+ }
+
+ if (ext_type == NULL) {
+ if (ignore_unknown) {
+ continue;
+ }
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
+ return 0;
+ }
+
+ /* Duplicate ext_types are forbidden. */
+ if (*ext_type->out_present) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+
+ *ext_type->out_present = 1;
+ *ext_type->out_data = data;
+ }
+
+ return 1;
+}
+
+static void set_crypto_buffer(CRYPTO_BUFFER **dest, CRYPTO_BUFFER *src) {
+ /* TODO(davidben): Remove this helper once |SSL_SESSION| can use |UniquePtr|
+ * and |UniquePtr| has up_ref helpers. */
+ CRYPTO_BUFFER_free(*dest);
+ *dest = src;
+ if (src != nullptr) {
+ CRYPTO_BUFFER_up_ref(src);
+ }
+}
+
+enum ssl_verify_result_t ssl_verify_peer_cert(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ const SSL_SESSION *prev_session = ssl->s3->established_session;
+ if (prev_session != NULL) {
+ /* If renegotiating, the server must not change the server certificate. See
+ * https://mitls.org/pages/attacks/3SHAKE. We never resume on renegotiation,
+ * so this check is sufficient to ensure the reported peer certificate never
+ * changes on renegotiation. */
+ assert(!ssl->server);
+ if (sk_CRYPTO_BUFFER_num(prev_session->certs) !=
+ sk_CRYPTO_BUFFER_num(hs->new_session->certs)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SERVER_CERT_CHANGED);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return ssl_verify_invalid;
+ }
+
+ for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(hs->new_session->certs); i++) {
+ const CRYPTO_BUFFER *old_cert =
+ sk_CRYPTO_BUFFER_value(prev_session->certs, i);
+ const CRYPTO_BUFFER *new_cert =
+ sk_CRYPTO_BUFFER_value(hs->new_session->certs, i);
+ if (CRYPTO_BUFFER_len(old_cert) != CRYPTO_BUFFER_len(new_cert) ||
+ OPENSSL_memcmp(CRYPTO_BUFFER_data(old_cert),
+ CRYPTO_BUFFER_data(new_cert),
+ CRYPTO_BUFFER_len(old_cert)) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SERVER_CERT_CHANGED);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return ssl_verify_invalid;
+ }
+ }
+
+ /* The certificate is identical, so we may skip re-verifying the
+ * certificate. Since we only authenticated the previous one, copy other
+ * authentication from the established session and ignore what was newly
+ * received. */
+ set_crypto_buffer(&hs->new_session->ocsp_response,
+ prev_session->ocsp_response);
+ set_crypto_buffer(&hs->new_session->signed_cert_timestamp_list,
+ prev_session->signed_cert_timestamp_list);
+ hs->new_session->verify_result = prev_session->verify_result;
+ return ssl_verify_ok;
+ }
+
+ uint8_t alert = SSL_AD_CERTIFICATE_UNKNOWN;
+ enum ssl_verify_result_t ret;
+ if (ssl->custom_verify_callback != nullptr) {
+ ret = ssl->custom_verify_callback(ssl, &alert);
+ switch (ret) {
+ case ssl_verify_ok:
+ hs->new_session->verify_result = X509_V_OK;
+ break;
+ case ssl_verify_invalid:
+ hs->new_session->verify_result = X509_V_ERR_APPLICATION_VERIFICATION;
+ break;
+ case ssl_verify_retry:
+ break;
+ }
+ } else {
+ ret = ssl->ctx->x509_method->session_verify_cert_chain(
+ hs->new_session.get(), ssl, &alert)
+ ? ssl_verify_ok
+ : ssl_verify_invalid;
+ }
+
+ if (ret == ssl_verify_invalid) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ }
+
+ return ret;
+}
+
+uint16_t ssl_get_grease_value(const SSL *ssl, enum ssl_grease_index_t index) {
+ /* Use the client_random or server_random for entropy. This both avoids
+ * calling |RAND_bytes| on a single byte repeatedly and ensures the values are
+ * deterministic. This allows the same ClientHello be sent twice for a
+ * HelloRetryRequest or the same group be advertised in both supported_groups
+ * and key_shares. */
+ uint16_t ret = ssl->server ? ssl->s3->server_random[index]
+ : ssl->s3->client_random[index];
+ /* The first four bytes of server_random are a timestamp prior to TLS 1.3, but
+ * servers have no fields to GREASE until TLS 1.3. */
+ assert(!ssl->server || ssl3_protocol_version(ssl) >= TLS1_3_VERSION);
+ /* This generates a random value of the form 0xωaωa, for all 0 ≤ ω < 16. */
+ ret = (ret & 0xf0) | 0x0a;
+ ret |= ret << 8;
+ return ret;
+}
+
+enum ssl_hs_wait_t ssl_get_finished(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ SSLMessage msg;
+ if (!ssl->method->get_message(ssl, &msg)) {
+ return ssl_hs_read_message;
+ }
+
+ if (!ssl_check_message_type(ssl, msg, SSL3_MT_FINISHED)) {
+ return ssl_hs_error;
+ }
+
+ /* Snapshot the finished hash before incorporating the new message. */
+ uint8_t finished[EVP_MAX_MD_SIZE];
+ size_t finished_len;
+ if (!hs->transcript.GetFinishedMAC(finished, &finished_len,
+ SSL_get_session(ssl), !ssl->server,
+ ssl3_protocol_version(ssl)) ||
+ !ssl_hash_message(hs, msg)) {
+ return ssl_hs_error;
+ }
+
+ int finished_ok = CBS_mem_equal(&msg.body, finished, finished_len);
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ finished_ok = 1;
+#endif
+ if (!finished_ok) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED);
+ return ssl_hs_error;
+ }
+
+ /* Copy the Finished so we can use it for renegotiation checks. */
+ if (ssl->version != SSL3_VERSION) {
+ if (finished_len > sizeof(ssl->s3->previous_client_finished) ||
+ finished_len > sizeof(ssl->s3->previous_server_finished)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+
+ if (ssl->server) {
+ OPENSSL_memcpy(ssl->s3->previous_client_finished, finished, finished_len);
+ ssl->s3->previous_client_finished_len = finished_len;
+ } else {
+ OPENSSL_memcpy(ssl->s3->previous_server_finished, finished, finished_len);
+ ssl->s3->previous_server_finished_len = finished_len;
+ }
+ }
+
+ ssl->method->next_message(ssl);
+ return ssl_hs_ok;
+}
+
+int ssl_run_handshake(SSL_HANDSHAKE *hs, int *out_early_return) {
+ SSL *const ssl = hs->ssl;
+ for (;;) {
+ /* Resolve the operation the handshake was waiting on. */
+ switch (hs->wait) {
+ case ssl_hs_error:
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
+ return -1;
+
+ case ssl_hs_flush: {
+ int ret = ssl->method->flush_flight(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+ break;
+ }
+
+ case ssl_hs_read_server_hello:
+ case ssl_hs_read_message: {
+ int ret = ssl->method->read_message(ssl);
+ if (ret <= 0) {
+ uint32_t err = ERR_peek_error();
+ if (hs->wait == ssl_hs_read_server_hello &&
+ ERR_GET_LIB(err) == ERR_LIB_SSL &&
+ ERR_GET_REASON(err) == SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE) {
+ /* Add a dedicated error code to the queue for a handshake_failure
+ * alert in response to ClientHello. This matches NSS's client
+ * behavior and gives a better error on a (probable) failure to
+ * negotiate initial parameters. Note: this error code comes after
+ * the original one.
+ *
+ * See https://crbug.com/446505. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO);
+ }
+ return ret;
+ }
+ break;
+ }
+
+ case ssl_hs_read_change_cipher_spec: {
+ int ret = ssl->method->read_change_cipher_spec(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+ break;
+ }
+
+ case ssl_hs_read_end_of_early_data: {
+ if (ssl->s3->hs->can_early_read) {
+ /* While we are processing early data, the handshake returns early. */
+ *out_early_return = 1;
+ return 1;
+ }
+ hs->wait = ssl_hs_ok;
+ break;
+ }
+
+ case ssl_hs_certificate_selection_pending:
+ ssl->rwstate = SSL_CERTIFICATE_SELECTION_PENDING;
+ hs->wait = ssl_hs_ok;
+ return -1;
+
+ case ssl_hs_x509_lookup:
+ ssl->rwstate = SSL_X509_LOOKUP;
+ hs->wait = ssl_hs_ok;
+ return -1;
+
+ case ssl_hs_channel_id_lookup:
+ ssl->rwstate = SSL_CHANNEL_ID_LOOKUP;
+ hs->wait = ssl_hs_ok;
+ return -1;
+
+ case ssl_hs_private_key_operation:
+ ssl->rwstate = SSL_PRIVATE_KEY_OPERATION;
+ hs->wait = ssl_hs_ok;
+ return -1;
+
+ case ssl_hs_pending_session:
+ ssl->rwstate = SSL_PENDING_SESSION;
+ hs->wait = ssl_hs_ok;
+ return -1;
+
+ case ssl_hs_pending_ticket:
+ ssl->rwstate = SSL_PENDING_TICKET;
+ hs->wait = ssl_hs_ok;
+ return -1;
+
+ case ssl_hs_certificate_verify:
+ ssl->rwstate = SSL_CERTIFICATE_VERIFY;
+ hs->wait = ssl_hs_ok;
+ return -1;
+
+ case ssl_hs_early_data_rejected:
+ ssl->rwstate = SSL_EARLY_DATA_REJECTED;
+ /* Cause |SSL_write| to start failing immediately. */
+ hs->can_early_write = 0;
+ return -1;
+
+ case ssl_hs_early_return:
+ *out_early_return = 1;
+ hs->wait = ssl_hs_ok;
+ return 1;
+
+ case ssl_hs_ok:
+ break;
+ }
+
+ /* Run the state machine again. */
+ hs->wait = ssl->do_handshake(hs);
+ if (hs->wait == ssl_hs_error) {
+ /* Don't loop around to avoid a stray |SSL_R_SSL_HANDSHAKE_FAILURE| the
+ * first time around. */
+ return -1;
+ }
+ if (hs->wait == ssl_hs_ok) {
+ /* The handshake has completed. */
+ return 1;
+ }
+
+ /* Otherwise, loop to the beginning and resolve what was blocking the
+ * handshake. */
+ }
+}
+
+} // namespace bssl
diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc
index f018c0e..b1c48d8 100644
--- a/ssl/handshake_client.cc
+++ b/ssl/handshake_client.cc
@@ -4,21 +4,21 @@
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
- *
+ *
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
+ *
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,10 +33,10 @@
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
+ * 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
+ *
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -48,7 +48,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
@@ -62,7 +62,7 @@
* are met:
*
* 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
+ * notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
@@ -110,7 +110,7 @@
/* ====================================================================
* Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
*
- * Portions of the attached software ("Contribution") are developed by
+ * Portions of the attached software ("Contribution") are developed by
* SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
*
* The Contribution is licensed pursuant to the OpenSSL open source
@@ -150,6 +150,7 @@
#include <openssl/ssl.h>
#include <assert.h>
+#include <limits.h>
#include <string.h>
#include <utility>
@@ -172,377 +173,32 @@
namespace bssl {
-static int ssl3_send_client_hello(SSL_HANDSHAKE *hs);
-static int dtls1_get_hello_verify_request(SSL_HANDSHAKE *hs);
-static int ssl3_get_server_hello(SSL_HANDSHAKE *hs);
-static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs);
-static int ssl3_get_cert_status(SSL_HANDSHAKE *hs);
-static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs);
-static int ssl3_get_certificate_request(SSL_HANDSHAKE *hs);
-static int ssl3_get_server_hello_done(SSL_HANDSHAKE *hs);
-static int ssl3_send_client_certificate(SSL_HANDSHAKE *hs);
-static int ssl3_send_client_key_exchange(SSL_HANDSHAKE *hs);
-static int ssl3_send_cert_verify(SSL_HANDSHAKE *hs);
-static int ssl3_send_next_proto(SSL_HANDSHAKE *hs);
-static int ssl3_send_channel_id(SSL_HANDSHAKE *hs);
-static int ssl3_get_new_session_ticket(SSL_HANDSHAKE *hs);
-
-int ssl3_connect(SSL_HANDSHAKE *hs) {
- SSL *const ssl = hs->ssl;
- int ret = -1;
-
- assert(ssl->handshake_func == ssl3_connect);
- assert(!ssl->server);
-
- for (;;) {
- int state = hs->state;
-
- switch (hs->state) {
- case SSL_ST_INIT:
- ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_START, 1);
- hs->state = SSL3_ST_CW_CLNT_HELLO_A;
- break;
-
- case SSL3_ST_CW_CLNT_HELLO_A:
- ret = ssl3_send_client_hello(hs);
- if (ret <= 0) {
- goto end;
- }
-
- if (!SSL_is_dtls(ssl) || ssl->d1->send_cookie) {
- if (hs->early_data_offered) {
- if (!tls13_init_early_key_schedule(hs) ||
- !tls13_advance_key_schedule(hs, ssl->session->master_key,
- ssl->session->master_key_length) ||
- !tls13_derive_early_secrets(hs) ||
- !tls13_set_traffic_key(ssl, evp_aead_seal,
- hs->early_traffic_secret,
- hs->hash_len)) {
- ret = -1;
- goto end;
- }
- hs->next_state = SSL3_ST_WRITE_EARLY_DATA;
- } else {
- hs->next_state = SSL3_ST_CR_SRVR_HELLO_A;
- }
- } else {
- hs->next_state = DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A;
- }
- hs->state = SSL3_ST_CW_FLUSH;
- break;
-
- case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
- assert(SSL_is_dtls(ssl));
- ret = dtls1_get_hello_verify_request(hs);
- if (ret <= 0) {
- goto end;
- }
- if (ssl->d1->send_cookie) {
- hs->state = SSL3_ST_CW_CLNT_HELLO_A;
- } else {
- hs->state = SSL3_ST_CR_SRVR_HELLO_A;
- }
- break;
-
- case SSL3_ST_WRITE_EARLY_DATA:
- /* Stash the early data session, so connection properties may be queried
- * out of it. */
- hs->in_early_data = 1;
- SSL_SESSION_up_ref(ssl->session);
- hs->early_session.reset(ssl->session);
-
- hs->state = SSL3_ST_CR_SRVR_HELLO_A;
- hs->can_early_write = 1;
- ret = 1;
- goto end;
-
- case SSL3_ST_CR_SRVR_HELLO_A:
- ret = ssl3_get_server_hello(hs);
- if (hs->state == SSL_ST_TLS13) {
- break;
- }
- if (ret <= 0) {
- goto end;
- }
-
- if (ssl->session != NULL) {
- hs->state = SSL3_ST_CR_SESSION_TICKET_A;
- } else {
- hs->state = SSL3_ST_CR_CERT_A;
- }
- break;
-
- case SSL3_ST_CR_CERT_A:
- if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
- ret = ssl3_get_server_certificate(hs);
- if (ret <= 0) {
- goto end;
- }
- }
- hs->state = SSL3_ST_CR_CERT_STATUS_A;
- break;
-
- case SSL3_ST_CR_CERT_STATUS_A:
- if (hs->certificate_status_expected) {
- ret = ssl3_get_cert_status(hs);
- if (ret <= 0) {
- goto end;
- }
- }
- hs->state = SSL3_ST_VERIFY_SERVER_CERT;
- break;
-
- case SSL3_ST_VERIFY_SERVER_CERT:
- if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
- switch (ssl_verify_peer_cert(hs)) {
- case ssl_verify_ok:
- break;
- case ssl_verify_invalid:
- ret = -1;
- goto end;
- case ssl_verify_retry:
- ssl->rwstate = SSL_CERTIFICATE_VERIFY;
- ret = -1;
- goto end;
- }
- }
- hs->state = SSL3_ST_CR_KEY_EXCH_A;
- break;
-
- case SSL3_ST_CR_KEY_EXCH_A:
- ret = ssl3_get_server_key_exchange(hs);
- if (ret <= 0) {
- goto end;
- }
- hs->state = SSL3_ST_CR_CERT_REQ_A;
- break;
-
- case SSL3_ST_CR_CERT_REQ_A:
- if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
- ret = ssl3_get_certificate_request(hs);
- if (ret <= 0) {
- goto end;
- }
- }
- hs->state = SSL3_ST_CR_SRVR_DONE_A;
- break;
-
- case SSL3_ST_CR_SRVR_DONE_A:
- ret = ssl3_get_server_hello_done(hs);
- if (ret <= 0) {
- goto end;
- }
- hs->state = SSL3_ST_CW_CERT_A;
- break;
-
- case SSL3_ST_CW_CERT_A:
- if (hs->cert_request) {
- ret = ssl3_send_client_certificate(hs);
- if (ret <= 0) {
- goto end;
- }
- }
- hs->state = SSL3_ST_CW_KEY_EXCH_A;
- break;
-
- case SSL3_ST_CW_KEY_EXCH_A:
- ret = ssl3_send_client_key_exchange(hs);
- if (ret <= 0) {
- goto end;
- }
- hs->state = SSL3_ST_CW_CERT_VRFY_A;
- break;
-
- case SSL3_ST_CW_CERT_VRFY_A:
- if (hs->cert_request && ssl_has_certificate(ssl)) {
- ret = ssl3_send_cert_verify(hs);
- if (ret <= 0) {
- goto end;
- }
- }
- hs->state = SSL3_ST_CW_CHANGE;
- break;
-
- case SSL3_ST_CW_CHANGE:
- if (!ssl->method->add_change_cipher_spec(ssl) ||
- !tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
- ret = -1;
- goto end;
- }
-
- hs->state = SSL3_ST_CW_NEXT_PROTO_A;
- break;
-
- case SSL3_ST_CW_NEXT_PROTO_A:
- if (hs->next_proto_neg_seen) {
- ret = ssl3_send_next_proto(hs);
- if (ret <= 0) {
- goto end;
- }
- }
- hs->state = SSL3_ST_CW_CHANNEL_ID_A;
- break;
-
- case SSL3_ST_CW_CHANNEL_ID_A:
- if (ssl->s3->tlsext_channel_id_valid) {
- ret = ssl3_send_channel_id(hs);
- if (ret <= 0) {
- goto end;
- }
- }
- hs->state = SSL3_ST_CW_FINISHED_A;
- break;
-
- case SSL3_ST_CW_FINISHED_A:
- ret = ssl3_send_finished(hs);
- if (ret <= 0) {
- goto end;
- }
- hs->state = SSL3_ST_CW_FLUSH;
-
- if (ssl->session != NULL) {
- hs->next_state = SSL3_ST_FINISH_CLIENT_HANDSHAKE;
- } else {
- /* This is a non-resumption handshake. If it involves ChannelID, then
- * record the handshake hashes at this point in the session so that
- * any resumption of this session with ChannelID can sign those
- * hashes. */
- ret = tls1_record_handshake_hashes_for_channel_id(hs);
- if (ret <= 0) {
- goto end;
- }
- if ((SSL_get_mode(ssl) & SSL_MODE_ENABLE_FALSE_START) &&
- ssl3_can_false_start(ssl) &&
- /* No False Start on renegotiation (would complicate the state
- * machine). */
- !ssl->s3->initial_handshake_complete) {
- hs->next_state = SSL3_ST_FALSE_START;
- } else {
- hs->next_state = SSL3_ST_CR_SESSION_TICKET_A;
- }
- }
- break;
-
- case SSL3_ST_FALSE_START:
- hs->state = SSL3_ST_CR_SESSION_TICKET_A;
- hs->in_false_start = 1;
- hs->can_early_write = 1;
- ret = 1;
- goto end;
-
- case SSL3_ST_CR_SESSION_TICKET_A:
- if (hs->ticket_expected) {
- ret = ssl3_get_new_session_ticket(hs);
- if (ret <= 0) {
- goto end;
- }
- }
- hs->state = SSL3_ST_CR_CHANGE;
- break;
-
- case SSL3_ST_CR_CHANGE:
- ret = ssl->method->read_change_cipher_spec(ssl);
- if (ret <= 0) {
- goto end;
- }
-
- if (!tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_CLIENT_READ)) {
- ret = -1;
- goto end;
- }
- hs->state = SSL3_ST_CR_FINISHED_A;
- break;
-
- case SSL3_ST_CR_FINISHED_A:
- ret = ssl3_get_finished(hs);
- if (ret <= 0) {
- goto end;
- }
-
- if (ssl->session != NULL) {
- hs->state = SSL3_ST_CW_CHANGE;
- } else {
- hs->state = SSL3_ST_FINISH_CLIENT_HANDSHAKE;
- }
- break;
-
- case SSL3_ST_CW_FLUSH:
- ret = ssl->method->flush_flight(ssl);
- if (ret <= 0) {
- goto end;
- }
- hs->state = hs->next_state;
- break;
-
- case SSL_ST_TLS13: {
- int early_return = 0;
- ret = tls13_handshake(hs, &early_return);
- if (ret <= 0) {
- goto end;
- }
-
- if (early_return) {
- ret = 1;
- goto end;
- }
-
- hs->state = SSL3_ST_FINISH_CLIENT_HANDSHAKE;
- break;
- }
-
- case SSL3_ST_FINISH_CLIENT_HANDSHAKE:
- ssl->method->on_handshake_complete(ssl);
-
- SSL_SESSION_free(ssl->s3->established_session);
- if (ssl->session != NULL) {
- SSL_SESSION_up_ref(ssl->session);
- ssl->s3->established_session = ssl->session;
- } else {
- /* We make a copy of the session in order to maintain the immutability
- * of the new established_session due to False Start. The caller may
- * have taken a reference to the temporary session. */
- ssl->s3->established_session =
- SSL_SESSION_dup(hs->new_session.get(), SSL_SESSION_DUP_ALL)
- .release();
- if (ssl->s3->established_session == NULL) {
- ret = -1;
- goto end;
- }
- /* Renegotiations do not participate in session resumption. */
- if (!ssl->s3->initial_handshake_complete) {
- ssl->s3->established_session->not_resumable = 0;
- }
-
- hs->new_session.reset();
- }
-
- hs->state = SSL_ST_OK;
- break;
-
- case SSL_ST_OK: {
- ssl->s3->initial_handshake_complete = 1;
- ssl_update_cache(hs, SSL_SESS_CACHE_CLIENT);
-
- ret = 1;
- ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_DONE, 1);
- goto end;
- }
-
- default:
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE);
- ret = -1;
- goto end;
- }
-
- if (hs->state != state) {
- ssl_do_info_callback(ssl, SSL_CB_CONNECT_LOOP, 1);
- }
- }
-
-end:
- ssl_do_info_callback(ssl, SSL_CB_CONNECT_EXIT, ret);
- return ret;
-}
+enum ssl_client_hs_state_t {
+ state_start_connect = 0,
+ state_send_client_hello,
+ state_enter_early_data,
+ state_read_hello_verify_request,
+ state_read_server_hello,
+ state_tls13,
+ state_read_server_certificate,
+ state_read_certificate_status,
+ state_verify_server_certificate,
+ state_read_server_key_exchange,
+ state_read_certificate_request,
+ state_read_server_hello_done,
+ state_send_client_certificate,
+ state_send_client_key_exchange,
+ state_send_client_certificate_verify,
+ state_send_second_client_flight,
+ state_send_channel_id,
+ state_send_client_finished,
+ state_finish_flight,
+ state_read_session_ticket,
+ state_process_change_cipher_spec,
+ state_read_server_finished,
+ state_finish_client_handshake,
+ state_done,
+};
/* ssl_get_client_disabled sets |*out_mask_a| and |*out_mask_k| to masks of
* disabled algorithms. */
@@ -702,99 +358,6 @@
return ssl->method->add_message(ssl, msg, len);
}
-static int ssl3_send_client_hello(SSL_HANDSHAKE *hs) {
- SSL *const ssl = hs->ssl;
- /* The handshake buffer is reset on every ClientHello. Notably, in DTLS, we
- * may send multiple ClientHellos if we receive HelloVerifyRequest. */
- if (!hs->transcript.Init()) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
- }
-
- /* Freeze the version range. */
- if (!ssl_get_version_range(ssl, &hs->min_version, &hs->max_version)) {
- return -1;
- }
-
- /* Always advertise the ClientHello version from the original maximum version,
- * even on renegotiation. The static RSA key exchange uses this field, and
- * some servers fail when it changes across handshakes. */
- if (SSL_is_dtls(hs->ssl)) {
- hs->client_version =
- hs->max_version >= TLS1_2_VERSION ? DTLS1_2_VERSION : DTLS1_VERSION;
- } else {
- hs->client_version =
- hs->max_version >= TLS1_2_VERSION ? TLS1_2_VERSION : hs->max_version;
- }
-
- /* If the configured session has expired or was created at a disabled
- * version, drop it. */
- if (ssl->session != NULL) {
- if (ssl->session->is_server ||
- !ssl_supports_version(hs, ssl->session->ssl_version) ||
- (ssl->session->session_id_length == 0 &&
- ssl->session->tlsext_ticklen == 0) ||
- ssl->session->not_resumable ||
- !ssl_session_is_time_valid(ssl, ssl->session)) {
- ssl_set_session(ssl, NULL);
- }
- }
-
- /* If resending the ClientHello in DTLS after a HelloVerifyRequest, don't
- * renegerate the client_random. The random must be reused. */
- if ((!SSL_is_dtls(ssl) || !ssl->d1->send_cookie) &&
- !RAND_bytes(ssl->s3->client_random, sizeof(ssl->s3->client_random))) {
- return -1;
- }
-
- /* Initialize a random session ID for the experimental TLS 1.3 variant
- * requiring a session id. */
- if (ssl->tls13_variant == tls13_experiment) {
- hs->session_id_len = sizeof(hs->session_id);
- if (!RAND_bytes(hs->session_id, hs->session_id_len)) {
- return -1;
- }
- }
-
- if (!ssl_write_client_hello(hs)) {
- return -1;
- }
-
- return 1;
-}
-
-static int dtls1_get_hello_verify_request(SSL_HANDSHAKE *hs) {
- SSL *const ssl = hs->ssl;
- SSLMessage msg;
- int ret = ssl_read_message(ssl, &msg);
- if (ret <= 0) {
- return ret;
- }
-
- if (msg.type != DTLS1_MT_HELLO_VERIFY_REQUEST) {
- ssl->d1->send_cookie = false;
- return 1;
- }
-
- CBS hello_verify_request = msg.body, cookie;
- uint16_t server_version;
- if (!CBS_get_u16(&hello_verify_request, &server_version) ||
- !CBS_get_u8_length_prefixed(&hello_verify_request, &cookie) ||
- CBS_len(&cookie) > sizeof(ssl->d1->cookie) ||
- CBS_len(&hello_verify_request) != 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return -1;
- }
-
- OPENSSL_memcpy(ssl->d1->cookie, CBS_data(&cookie), CBS_len(&cookie));
- ssl->d1->cookie_len = CBS_len(&cookie);
-
- ssl->d1->send_cookie = true;
- ssl->method->next_message(ssl);
- return 1;
-}
-
static int parse_server_version(SSL_HANDSHAKE *hs, uint16_t *out,
const SSLMessage &msg) {
SSL *const ssl = hs->ssl;
@@ -866,34 +429,160 @@
return 1;
}
-static int ssl3_get_server_hello(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_start_connect(SSL_HANDSHAKE *hs) {
+ ssl_do_info_callback(hs->ssl, SSL_CB_HANDSHAKE_START, 1);
+ hs->state = state_send_client_hello;
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_send_client_hello(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+
+ /* The handshake buffer is reset on every ClientHello. Notably, in DTLS, we
+ * may send multiple ClientHellos if we receive HelloVerifyRequest. */
+ if (!hs->transcript.Init()) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+
+ /* Freeze the version range. */
+ if (!ssl_get_version_range(ssl, &hs->min_version, &hs->max_version)) {
+ return ssl_hs_error;
+ }
+
+ /* Always advertise the ClientHello version from the original maximum version,
+ * even on renegotiation. The static RSA key exchange uses this field, and
+ * some servers fail when it changes across handshakes. */
+ if (SSL_is_dtls(hs->ssl)) {
+ hs->client_version =
+ hs->max_version >= TLS1_2_VERSION ? DTLS1_2_VERSION : DTLS1_VERSION;
+ } else {
+ hs->client_version =
+ hs->max_version >= TLS1_2_VERSION ? TLS1_2_VERSION : hs->max_version;
+ }
+
+ /* If the configured session has expired or was created at a disabled
+ * version, drop it. */
+ if (ssl->session != NULL) {
+ if (ssl->session->is_server ||
+ !ssl_supports_version(hs, ssl->session->ssl_version) ||
+ (ssl->session->session_id_length == 0 &&
+ ssl->session->tlsext_ticklen == 0) ||
+ ssl->session->not_resumable ||
+ !ssl_session_is_time_valid(ssl, ssl->session)) {
+ ssl_set_session(ssl, NULL);
+ }
+ }
+
+ /* If resending the ClientHello in DTLS after a HelloVerifyRequest, don't
+ * renegerate the client_random. The random must be reused. */
+ if ((!SSL_is_dtls(ssl) || !ssl->d1->send_cookie) &&
+ !RAND_bytes(ssl->s3->client_random, sizeof(ssl->s3->client_random))) {
+ return ssl_hs_error;
+ }
+
+ /* Initialize a random session ID for the experimental TLS 1.3 variant
+ * requiring a session id. */
+ if (ssl->tls13_variant == tls13_experiment) {
+ hs->session_id_len = sizeof(hs->session_id);
+ if (!RAND_bytes(hs->session_id, hs->session_id_len)) {
+ return ssl_hs_error;
+ }
+ }
+
+ if (!ssl_write_client_hello(hs)) {
+ return ssl_hs_error;
+ }
+
+ hs->state = state_enter_early_data;
+ return ssl_hs_flush;
+}
+
+static enum ssl_hs_wait_t do_enter_early_data(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+
+ if (SSL_is_dtls(ssl) && !ssl->d1->send_cookie) {
+ hs->state = state_read_hello_verify_request;
+ return ssl_hs_ok;
+ }
+
+ if (!hs->early_data_offered) {
+ hs->state = state_read_server_hello;
+ return ssl_hs_ok;
+ }
+
+ if (!tls13_init_early_key_schedule(hs) ||
+ !tls13_advance_key_schedule(hs, ssl->session->master_key,
+ ssl->session->master_key_length) ||
+ !tls13_derive_early_secrets(hs) ||
+ !tls13_set_traffic_key(ssl, evp_aead_seal, hs->early_traffic_secret,
+ hs->hash_len)) {
+ return ssl_hs_error;
+ }
+
+ /* Stash the early data session, so connection properties may be queried out
+ * of it. */
+ hs->in_early_data = 1;
+ SSL_SESSION_up_ref(ssl->session);
+ hs->early_session.reset(ssl->session);
+ hs->can_early_write = 1;
+
+ hs->state = state_read_server_hello;
+ return ssl_hs_early_return;
+}
+
+static enum ssl_hs_wait_t do_read_hello_verify_request(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+
+ assert(SSL_is_dtls(ssl));
+
+ SSLMessage msg;
+ if (!ssl->method->get_message(ssl, &msg)) {
+ return ssl_hs_read_message;
+ }
+
+ if (msg.type != DTLS1_MT_HELLO_VERIFY_REQUEST) {
+ ssl->d1->send_cookie = false;
+ hs->state = state_read_server_hello;
+ return ssl_hs_ok;
+ }
+
+ CBS hello_verify_request = msg.body, cookie;
+ uint16_t server_version;
+ if (!CBS_get_u16(&hello_verify_request, &server_version) ||
+ !CBS_get_u8_length_prefixed(&hello_verify_request, &cookie) ||
+ CBS_len(&cookie) > sizeof(ssl->d1->cookie) ||
+ CBS_len(&hello_verify_request) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return ssl_hs_error;
+ }
+
+ OPENSSL_memcpy(ssl->d1->cookie, CBS_data(&cookie), CBS_len(&cookie));
+ ssl->d1->cookie_len = CBS_len(&cookie);
+
+ ssl->d1->send_cookie = true;
+ ssl->method->next_message(ssl);
+ hs->state = state_send_client_hello;
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
SSLMessage msg;
- int ret = ssl_read_message(ssl, &msg);
- if (ret <= 0) {
- uint32_t err = ERR_peek_error();
- if (ERR_GET_LIB(err) == ERR_LIB_SSL &&
- ERR_GET_REASON(err) == SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE) {
- /* Add a dedicated error code to the queue for a handshake_failure alert
- * in response to ClientHello. This matches NSS's client behavior and
- * gives a better error on a (probable) failure to negotiate initial
- * parameters. Note: this error code comes after the original one.
- *
- * See https://crbug.com/446505. */
- OPENSSL_PUT_ERROR(SSL, SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO);
- }
- return ret;
+ if (!ssl->method->get_message(ssl, &msg)) {
+ return ssl_hs_read_server_hello;
}
uint16_t server_version;
if (!parse_server_version(hs, &server_version, msg)) {
- return -1;
+ return ssl_hs_error;
}
if (!ssl_supports_version(hs, server_version)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_PROTOCOL_VERSION);
- return -1;
+ return ssl_hs_error;
}
assert(ssl->s3->have_version == ssl->s3->initial_handshake_complete);
@@ -905,25 +594,24 @@
} else if (server_version != ssl->version) {
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SSL_VERSION);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_PROTOCOL_VERSION);
- return -1;
+ return ssl_hs_error;
}
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
- hs->state = SSL_ST_TLS13;
- hs->do_tls13_handshake = tls13_client_handshake;
- return 1;
+ hs->state = state_tls13;
+ return ssl_hs_ok;
}
if (hs->early_data_offered) {
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_ON_EARLY_DATA);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_PROTOCOL_VERSION);
- return -1;
+ return ssl_hs_error;
}
ssl_clear_tls13_state(hs);
if (!ssl_check_message_type(ssl, msg, SSL3_MT_SERVER_HELLO)) {
- return -1;
+ return ssl_hs_error;
}
CBS server_hello = msg.body, server_random, session_id;
@@ -937,7 +625,7 @@
!CBS_get_u8(&server_hello, &compression_method)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
/* Copy over the server random. */
@@ -958,7 +646,7 @@
ssl_set_session(ssl, NULL);
if (!ssl_get_new_session(hs, 0 /* client */)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
/* Note: session_id could be empty. */
hs->new_session->session_id_length = CBS_len(&session_id);
@@ -971,7 +659,7 @@
/* unknown cipher */
OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_RETURNED);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return -1;
+ return ssl_hs_error;
}
/* The cipher must be allowed in the selected version and enabled. */
@@ -983,26 +671,26 @@
!sk_SSL_CIPHER_find(SSL_get_ciphers(ssl), NULL, cipher)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return -1;
+ return ssl_hs_error;
}
if (ssl->session != NULL) {
if (ssl->session->ssl_version != ssl->version) {
OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_VERSION_NOT_RETURNED);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return -1;
+ return ssl_hs_error;
}
if (ssl->session->cipher != cipher) {
OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return -1;
+ return ssl_hs_error;
}
if (!ssl_session_is_context_valid(ssl, ssl->session)) {
/* This is actually a client application bug. */
OPENSSL_PUT_ERROR(SSL,
SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return -1;
+ return ssl_hs_error;
}
} else {
hs->new_session->cipher = cipher;
@@ -1014,7 +702,7 @@
if (!hs->transcript.InitHash(ssl3_protocol_version(ssl), hs->new_cipher) ||
!ssl_hash_message(hs, msg)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
/* If doing a full handshake, the server may request a client certificate
@@ -1029,13 +717,13 @@
if (compression_method != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return -1;
+ return ssl_hs_error;
}
/* TLS extensions */
if (!ssl_parse_serverhello_tlsext(hs, &server_hello)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
- return -1;
+ return ssl_hs_error;
}
/* There should be nothing left over in the record. */
@@ -1043,7 +731,7 @@
/* wrong packet length */
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
if (ssl->session != NULL &&
@@ -1054,24 +742,46 @@
OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION);
}
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
- return -1;
+ return ssl_hs_error;
}
ssl->method->next_message(ssl);
- return 1;
+
+ if (ssl->session != NULL) {
+ hs->state = state_read_session_ticket;
+ return ssl_hs_ok;
+ }
+
+ hs->state = state_read_server_certificate;
+ return ssl_hs_ok;
}
-static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_tls13(SSL_HANDSHAKE *hs) {
+ enum ssl_hs_wait_t wait = tls13_client_handshake(hs);
+ if (wait == ssl_hs_ok) {
+ hs->state = state_finish_client_handshake;
+ return ssl_hs_ok;
+ }
+
+ return wait;
+}
+
+static enum ssl_hs_wait_t do_read_server_certificate(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+
+ if (!ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
+ hs->state = state_read_certificate_status;
+ return ssl_hs_ok;
+ }
+
SSLMessage msg;
- int ret = ssl_read_message(ssl, &msg);
- if (ret <= 0) {
- return ret;
+ if (!ssl->method->get_message(ssl, &msg)) {
+ return ssl_hs_read_message;
}
if (!ssl_check_message_type(ssl, msg, SSL3_MT_CERTIFICATE) ||
!ssl_hash_message(hs, msg)) {
- return -1;
+ return ssl_hs_error;
}
CBS body = msg.body;
@@ -1080,7 +790,7 @@
if (!ssl_parse_cert_chain(&alert, &chain, &hs->peer_pubkey, NULL, &body,
ssl->ctx->pool)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
- return -1;
+ return ssl_hs_error;
}
sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free);
hs->new_session->certs = chain.release();
@@ -1090,36 +800,44 @@
!ssl->ctx->x509_method->session_cache_objects(hs->new_session.get())) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
if (!ssl_check_leaf_certificate(
hs, hs->peer_pubkey.get(),
sk_CRYPTO_BUFFER_value(hs->new_session->certs, 0))) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return -1;
+ return ssl_hs_error;
}
ssl->method->next_message(ssl);
- return 1;
+
+ hs->state = state_read_certificate_status;
+ return ssl_hs_ok;
}
-static int ssl3_get_cert_status(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_certificate_status(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+
+ if (!hs->certificate_status_expected) {
+ hs->state = state_verify_server_certificate;
+ return ssl_hs_ok;
+ }
+
SSLMessage msg;
- int ret = ssl_read_message(ssl, &msg);
- if (ret <= 0) {
- return ret;
+ if (!ssl->method->get_message(ssl, &msg)) {
+ return ssl_hs_read_message;
}
if (msg.type != SSL3_MT_CERTIFICATE_STATUS) {
/* A server may send status_request in ServerHello and then change
* its mind about sending CertificateStatus. */
- return 1;
+ hs->state = state_verify_server_certificate;
+ return ssl_hs_ok;
}
if (!ssl_hash_message(hs, msg)) {
- return -1;
+ return ssl_hs_error;
}
CBS certificate_status = msg.body, ocsp_response;
@@ -1131,7 +849,7 @@
CBS_len(&certificate_status) != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
CRYPTO_BUFFER_free(hs->new_session->ocsp_response);
@@ -1139,19 +857,40 @@
CRYPTO_BUFFER_new_from_CBS(&ocsp_response, ssl->ctx->pool);
if (hs->new_session->ocsp_response == nullptr) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
ssl->method->next_message(ssl);
- return 1;
+
+ hs->state = state_verify_server_certificate;
+ return ssl_hs_ok;
}
-static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_verify_server_certificate(SSL_HANDSHAKE *hs) {
+ if (!ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
+ hs->state = state_read_server_key_exchange;
+ return ssl_hs_ok;
+ }
+
+ switch (ssl_verify_peer_cert(hs)) {
+ case ssl_verify_ok:
+ break;
+ case ssl_verify_invalid:
+ return ssl_hs_error;
+ case ssl_verify_retry:
+ hs->state = state_verify_server_certificate;
+ return ssl_hs_certificate_verify;
+ }
+
+ hs->state = state_read_server_key_exchange;
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_read_server_key_exchange(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
SSLMessage msg;
- int ret = ssl_read_message(ssl, &msg);
- if (ret <= 0) {
- return ret;
+ if (!ssl->method->get_message(ssl, &msg)) {
+ return ssl_hs_read_message;
}
if (msg.type != SSL3_MT_SERVER_KEY_EXCHANGE) {
@@ -1159,14 +898,15 @@
if (ssl_cipher_requires_server_key_exchange(hs->new_cipher)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
- return -1;
+ return ssl_hs_error;
}
- return 1;
+ hs->state = state_read_certificate_request;
+ return ssl_hs_ok;
}
if (!ssl_hash_message(hs, msg)) {
- return -1;
+ return ssl_hs_error;
}
uint32_t alg_k = hs->new_cipher->algorithm_mkey;
@@ -1180,7 +920,7 @@
&psk_identity_hint)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
/* Store PSK identity hint for later use, hint is used in
@@ -1194,7 +934,7 @@
CBS_contains_zero_byte(&psk_identity_hint)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
- return -1;
+ return ssl_hs_error;
}
/* Save non-empty identity hints as a C string. Empty identity hints we
@@ -1207,7 +947,7 @@
!CBS_strdup(&psk_identity_hint, &raw)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
hs->peer_psk_identity_hint.reset(raw);
}
@@ -1223,7 +963,7 @@
!CBS_get_u8_length_prefixed(&server_key_exchange, &point)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
hs->new_session->group_id = group_id;
@@ -1231,19 +971,19 @@
if (!tls1_check_group_id(ssl, group_id)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return -1;
+ return ssl_hs_error;
}
/* Initialize ECDH and save the peer public key for later. */
hs->key_share = SSLKeyShare::Create(group_id);
if (!hs->key_share ||
!CBS_stow(&point, &hs->peer_key, &hs->peer_key_len)) {
- return -1;
+ return ssl_hs_error;
}
} else if (!(alg_k & SSL_kPSK)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
- return -1;
+ return ssl_hs_error;
}
/* At this point, |server_key_exchange| contains the signature, if any, while
@@ -1260,19 +1000,19 @@
if (!CBS_get_u16(&server_key_exchange, &signature_algorithm)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
uint8_t alert = SSL_AD_DECODE_ERROR;
if (!tls12_check_peer_sigalg(ssl, &alert, signature_algorithm)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
- return -1;
+ return ssl_hs_error;
}
hs->new_session->peer_signature_algorithm = signature_algorithm;
} else if (!tls1_get_legacy_signature_algorithm(&signature_algorithm,
hs->peer_pubkey.get())) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_CERTIFICATE);
- return -1;
+ return ssl_hs_error;
}
/* The last field in |server_key_exchange| is the signature. */
@@ -1281,7 +1021,7 @@
CBS_len(&server_key_exchange) != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
ScopedCBB transcript;
@@ -1298,7 +1038,7 @@
!CBB_finish(transcript.get(), &transcript_data, &transcript_len)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
int sig_ok = ssl_public_key_verify(
@@ -1314,7 +1054,7 @@
/* bad signature */
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
- return -1;
+ return ssl_hs_error;
}
} else {
/* PSK ciphers are the only supported certificate-less ciphers. */
@@ -1323,32 +1063,39 @@
if (CBS_len(&server_key_exchange) > 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_EXTRA_DATA_IN_MESSAGE);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
}
ssl->method->next_message(ssl);
- return 1;
+ hs->state = state_read_certificate_request;
+ return ssl_hs_ok;
}
-static int ssl3_get_certificate_request(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_certificate_request(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+
+ if (!ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
+ hs->state = state_read_server_hello_done;
+ return ssl_hs_ok;
+ }
+
SSLMessage msg;
- int ret = ssl_read_message(ssl, &msg);
- if (ret <= 0) {
- return ret;
+ if (!ssl->method->get_message(ssl, &msg)) {
+ return ssl_hs_read_message;
}
if (msg.type == SSL3_MT_SERVER_HELLO_DONE) {
/* If we get here we don't need the handshake buffer as we won't be doing
* client auth. */
hs->transcript.FreeBuffer();
- return 1;
+ hs->state = state_read_server_hello_done;
+ return ssl_hs_ok;
}
if (!ssl_check_message_type(ssl, msg, SSL3_MT_CERTIFICATE_REQUEST) ||
!ssl_hash_message(hs, msg)) {
- return -1;
+ return ssl_hs_error;
}
/* Get the certificate types. */
@@ -1356,13 +1103,13 @@
if (!CBS_get_u8_length_prefixed(&body, &certificate_types)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
if (!CBS_stow(&certificate_types, &hs->certificate_types,
&hs->num_certificate_types)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
@@ -1371,7 +1118,7 @@
!tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
}
@@ -1380,59 +1127,68 @@
ssl_parse_client_CA_list(ssl, &alert, &body);
if (!ca_names) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
- return -1;
+ return ssl_hs_error;
}
if (CBS_len(&body) != 0) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
hs->cert_request = 1;
hs->ca_names = std::move(ca_names);
ssl->ctx->x509_method->hs_flush_cached_ca_names(hs);
+
ssl->method->next_message(ssl);
- return 1;
+ hs->state = state_read_server_hello_done;
+ return ssl_hs_ok;
}
-static int ssl3_get_server_hello_done(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_server_hello_done(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
SSLMessage msg;
- int ret = ssl_read_message(ssl, &msg);
- if (ret <= 0) {
- return ret;
+ if (!ssl->method->get_message(ssl, &msg)) {
+ return ssl_hs_read_message;
}
if (!ssl_check_message_type(ssl, msg, SSL3_MT_SERVER_HELLO_DONE) ||
!ssl_hash_message(hs, msg)) {
- return -1;
+ return ssl_hs_error;
}
/* ServerHelloDone is empty. */
if (CBS_len(&msg.body) != 0) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
ssl->method->next_message(ssl);
- return 1;
+ hs->state = state_send_client_certificate;
+ return ssl_hs_ok;
}
-static int ssl3_send_client_certificate(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_send_client_certificate(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+
+ /* The peer didn't request a certificate. */
+ if (!hs->cert_request) {
+ hs->state = state_send_client_key_exchange;
+ return ssl_hs_ok;
+ }
+
/* Call cert_cb to update the certificate. */
- if (ssl->cert->cert_cb) {
- int ret = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
- if (ret < 0) {
- ssl->rwstate = SSL_X509_LOOKUP;
- return -1;
- }
- if (ret == 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
+ if (ssl->cert->cert_cb != NULL) {
+ int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
+ if (rv == 0) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return -1;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
+ return ssl_hs_error;
+ }
+ if (rv < 0) {
+ hs->state = state_send_client_certificate;
+ return ssl_hs_x509_lookup;
}
}
@@ -1444,29 +1200,33 @@
if (ssl->version == SSL3_VERSION) {
if (!ssl->method->add_alert(ssl, SSL3_AL_WARNING,
SSL_AD_NO_CERTIFICATE)) {
- return -1;
+ return ssl_hs_error;
}
- return 1;
+ hs->state = state_send_client_key_exchange;
+ return ssl_hs_ok;
}
}
if (!ssl_on_certificate_selected(hs) ||
!ssl3_output_cert_chain(ssl)) {
- return -1;
+ return ssl_hs_error;
}
- return 1;
+
+
+ hs->state = state_send_client_key_exchange;
+ return ssl_hs_ok;
}
static_assert(sizeof(size_t) >= sizeof(unsigned),
"size_t is smaller than unsigned");
-static int ssl3_send_client_key_exchange(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_send_client_key_exchange(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
ScopedCBB cbb;
CBB body;
if (!ssl->method->init_message(ssl, cbb.get(), &body,
SSL3_MT_CLIENT_KEY_EXCHANGE)) {
- return -1;
+ return ssl_hs_error;
}
uint8_t *pms = NULL;
@@ -1628,36 +1388,43 @@
OPENSSL_cleanse(pms, pms_len);
OPENSSL_free(pms);
- return 1;
+ hs->state = state_send_client_certificate_verify;
+ return ssl_hs_ok;
err:
if (pms != NULL) {
OPENSSL_cleanse(pms, pms_len);
OPENSSL_free(pms);
}
- return -1;
+ return ssl_hs_error;
+
}
-static int ssl3_send_cert_verify(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
- assert(ssl_has_private_key(ssl));
+ if (!hs->cert_request || !ssl_has_certificate(ssl)) {
+ hs->state = state_send_second_client_flight;
+ return ssl_hs_ok;
+ }
+
+ assert(ssl_has_private_key(ssl));
ScopedCBB cbb;
CBB body, child;
if (!ssl->method->init_message(ssl, cbb.get(), &body,
SSL3_MT_CERTIFICATE_VERIFY)) {
- return -1;
+ return ssl_hs_error;
}
uint16_t signature_algorithm;
if (!tls1_choose_signature_algorithm(hs, &signature_algorithm)) {
- return -1;
+ return ssl_hs_error;
}
if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
/* Write out the digest type in TLS 1.2. */
if (!CBB_add_u16(&body, signature_algorithm)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
}
@@ -1666,7 +1433,7 @@
uint8_t *ptr;
if (!CBB_add_u16_length_prefixed(&body, &child) ||
!CBB_reserve(&child, &ptr, max_sig_len)) {
- return -1;
+ return ssl_hs_error;
}
size_t sig_len = max_sig_len;
@@ -1675,21 +1442,21 @@
if (ssl3_protocol_version(ssl) == SSL3_VERSION) {
if (ssl->cert->key_method != NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY);
- return -1;
+ return ssl_hs_error;
}
uint8_t digest[EVP_MAX_MD_SIZE];
size_t digest_len;
if (!hs->transcript.GetSSL3CertVerifyHash(
digest, &digest_len, hs->new_session.get(), signature_algorithm)) {
- return -1;
+ return ssl_hs_error;
}
UniquePtr<EVP_PKEY_CTX> pctx(EVP_PKEY_CTX_new(ssl->cert->privatekey, NULL));
if (!pctx ||
!EVP_PKEY_sign_init(pctx.get()) ||
!EVP_PKEY_sign(pctx.get(), ptr, &sig_len, digest, digest_len)) {
- return -1;
+ return ssl_hs_error;
}
} else {
switch (ssl_private_key_sign(
@@ -1698,53 +1465,70 @@
case ssl_private_key_success:
break;
case ssl_private_key_failure:
- return -1;
+ return ssl_hs_error;
case ssl_private_key_retry:
- ssl->rwstate = SSL_PRIVATE_KEY_OPERATION;
- return -1;
+ hs->state = state_send_client_certificate_verify;
+ return ssl_hs_private_key_operation;
}
}
if (!CBB_did_write(&child, sig_len) ||
!ssl_add_message_cbb(ssl, cbb.get())) {
- return -1;
+ return ssl_hs_error;
}
/* The handshake buffer is no longer necessary. */
hs->transcript.FreeBuffer();
- return 1;
+
+ hs->state = state_send_second_client_flight;
+ return ssl_hs_ok;
}
-static int ssl3_send_next_proto(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_send_second_client_flight(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
- static const uint8_t kZero[32] = {0};
- size_t padding_len = 32 - ((ssl->s3->next_proto_negotiated_len + 2) % 32);
- ScopedCBB cbb;
- CBB body, child;
- if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_NEXT_PROTO) ||
- !CBB_add_u8_length_prefixed(&body, &child) ||
- !CBB_add_bytes(&child, ssl->s3->next_proto_negotiated,
- ssl->s3->next_proto_negotiated_len) ||
- !CBB_add_u8_length_prefixed(&body, &child) ||
- !CBB_add_bytes(&child, kZero, padding_len) ||
- !ssl_add_message_cbb(ssl, cbb.get())) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
+ if (!ssl->method->add_change_cipher_spec(ssl) ||
+ !tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
+ return ssl_hs_error;
}
- return 1;
+ if (hs->next_proto_neg_seen) {
+ static const uint8_t kZero[32] = {0};
+ size_t padding_len = 32 - ((ssl->s3->next_proto_negotiated_len + 2) % 32);
+
+ ScopedCBB cbb;
+ CBB body, child;
+ if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_NEXT_PROTO) ||
+ !CBB_add_u8_length_prefixed(&body, &child) ||
+ !CBB_add_bytes(&child, ssl->s3->next_proto_negotiated,
+ ssl->s3->next_proto_negotiated_len) ||
+ !CBB_add_u8_length_prefixed(&body, &child) ||
+ !CBB_add_bytes(&child, kZero, padding_len) ||
+ !ssl_add_message_cbb(ssl, cbb.get())) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+ }
+
+ hs->state = state_send_channel_id;
+ return ssl_hs_ok;
}
-static int ssl3_send_channel_id(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_send_channel_id(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+
+ if (!ssl->s3->tlsext_channel_id_valid) {
+ hs->state = state_send_client_finished;
+ return ssl_hs_ok;
+ }
+
if (!ssl_do_channel_id_callback(ssl)) {
- return -1;
+ return ssl_hs_error;
}
if (ssl->tlsext_channel_id_private == NULL) {
- ssl->rwstate = SSL_CHANNEL_ID_LOOKUP;
- return -1;
+ hs->state = state_send_channel_id;
+ return ssl_hs_channel_id_lookup;
}
ScopedCBB cbb;
@@ -1753,23 +1537,67 @@
!tls1_write_channel_id(hs, &body) ||
!ssl_add_message_cbb(ssl, cbb.get())) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
- return 1;
+ hs->state = state_send_client_finished;
+ return ssl_hs_ok;
}
-static int ssl3_get_new_session_ticket(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_send_client_finished(SSL_HANDSHAKE *hs) {
+ if (!ssl3_send_finished(hs)) {
+ return ssl_hs_error;
+ }
+
+ hs->state = state_finish_flight;
+ return ssl_hs_flush;
+}
+
+static enum ssl_hs_wait_t do_finish_flight(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+ if (ssl->session != NULL) {
+ hs->state = state_finish_client_handshake;
+ return ssl_hs_ok;
+ }
+
+ /* This is a full handshake. If it involves ChannelID, then record the
+ * handshake hashes at this point in the session so that any resumption of
+ * this session with ChannelID can sign those hashes. */
+ if (!tls1_record_handshake_hashes_for_channel_id(hs)) {
+ return ssl_hs_error;
+ }
+
+ hs->state = state_read_session_ticket;
+
+ if ((SSL_get_mode(ssl) & SSL_MODE_ENABLE_FALSE_START) &&
+ ssl3_can_false_start(ssl) &&
+ /* No False Start on renegotiation (would complicate the state
+ * machine). */
+ !ssl->s3->initial_handshake_complete) {
+ hs->in_false_start = 1;
+ hs->can_early_write = 1;
+ return ssl_hs_early_return;
+ }
+
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_read_session_ticket(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+
+ if (!hs->ticket_expected) {
+ hs->state = state_process_change_cipher_spec;
+ return ssl_hs_read_change_cipher_spec;
+ }
+
SSLMessage msg;
- int ret = ssl_read_message(ssl, &msg);
- if (ret <= 0) {
- return ret;
+ if (!ssl->method->get_message(ssl, &msg)) {
+ return ssl_hs_read_message;
}
if (!ssl_check_message_type(ssl, msg, SSL3_MT_NEW_SESSION_TICKET) ||
!ssl_hash_message(hs, msg)) {
- return -1;
+ return ssl_hs_error;
}
CBS new_session_ticket = msg.body, ticket;
@@ -1779,7 +1607,7 @@
CBS_len(&new_session_ticket) != 0) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
if (CBS_len(&ticket) == 0) {
@@ -1788,7 +1616,8 @@
* |ssl_update_cache| so is cleared here to avoid an unnecessary update. */
hs->ticket_expected = 0;
ssl->method->next_message(ssl);
- return 1;
+ hs->state = state_process_change_cipher_spec;
+ return ssl_hs_read_change_cipher_spec;
}
SSL_SESSION *session = hs->new_session.get();
@@ -1802,7 +1631,7 @@
if (!renewed_session) {
/* This should never happen. */
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
session = renewed_session.get();
}
@@ -1812,7 +1641,7 @@
if (!CBS_stow(&ticket, &session->tlsext_tick, &session->tlsext_ticklen)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- return -1;
+ return ssl_hs_error;
}
session->tlsext_tick_lifetime_hint = tlsext_tick_lifetime_hint;
@@ -1822,7 +1651,7 @@
if (!EVP_Digest(CBS_data(&ticket), CBS_len(&ticket),
session->session_id, &session->session_id_length,
EVP_sha256(), NULL)) {
- return -1;
+ return ssl_hs_error;
}
if (renewed_session) {
@@ -1832,7 +1661,217 @@
}
ssl->method->next_message(ssl);
- return 1;
+ hs->state = state_process_change_cipher_spec;
+ return ssl_hs_read_change_cipher_spec;
}
-} // namespace bssl
+static enum ssl_hs_wait_t do_process_change_cipher_spec(SSL_HANDSHAKE *hs) {
+ if (!tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_CLIENT_READ)) {
+ return ssl_hs_error;
+ }
+
+ hs->state = state_read_server_finished;
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_read_server_finished(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ enum ssl_hs_wait_t wait = ssl_get_finished(hs);
+ if (wait != ssl_hs_ok) {
+ return wait;
+ }
+
+ if (ssl->session != NULL) {
+ hs->state = state_send_second_client_flight;
+ return ssl_hs_ok;
+ }
+
+ hs->state = state_finish_client_handshake;
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_finish_client_handshake(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+
+ ssl->method->on_handshake_complete(ssl);
+
+ SSL_SESSION_free(ssl->s3->established_session);
+ if (ssl->session != NULL) {
+ SSL_SESSION_up_ref(ssl->session);
+ ssl->s3->established_session = ssl->session;
+ } else {
+ /* We make a copy of the session in order to maintain the immutability
+ * of the new established_session due to False Start. The caller may
+ * have taken a reference to the temporary session. */
+ ssl->s3->established_session =
+ SSL_SESSION_dup(hs->new_session.get(), SSL_SESSION_DUP_ALL)
+ .release();
+ if (ssl->s3->established_session == NULL) {
+ return ssl_hs_error;
+ }
+ /* Renegotiations do not participate in session resumption. */
+ if (!ssl->s3->initial_handshake_complete) {
+ ssl->s3->established_session->not_resumable = 0;
+ }
+
+ hs->new_session.reset();
+ }
+
+ ssl->s3->initial_handshake_complete = 1;
+ ssl_update_cache(hs, SSL_SESS_CACHE_CLIENT);
+
+ hs->state = state_done;
+ return ssl_hs_ok;
+}
+
+enum ssl_hs_wait_t ssl_client_handshake(SSL_HANDSHAKE *hs) {
+ while (hs->state != state_done) {
+ enum ssl_hs_wait_t ret = ssl_hs_error;
+ enum ssl_client_hs_state_t state =
+ static_cast<enum ssl_client_hs_state_t>(hs->state);
+ switch (state) {
+ case state_start_connect:
+ ret = do_start_connect(hs);
+ break;
+ case state_send_client_hello:
+ ret = do_send_client_hello(hs);
+ break;
+ case state_enter_early_data:
+ ret = do_enter_early_data(hs);
+ break;
+ case state_read_hello_verify_request:
+ ret = do_read_hello_verify_request(hs);
+ break;
+ case state_read_server_hello:
+ ret = do_read_server_hello(hs);
+ break;
+ case state_tls13:
+ ret = do_tls13(hs);
+ break;
+ case state_read_server_certificate:
+ ret = do_read_server_certificate(hs);
+ break;
+ case state_read_certificate_status:
+ ret = do_read_certificate_status(hs);
+ break;
+ case state_verify_server_certificate:
+ ret = do_verify_server_certificate(hs);
+ break;
+ case state_read_server_key_exchange:
+ ret = do_read_server_key_exchange(hs);
+ break;
+ case state_read_certificate_request:
+ ret = do_read_certificate_request(hs);
+ break;
+ case state_read_server_hello_done:
+ ret = do_read_server_hello_done(hs);
+ break;
+ case state_send_client_certificate:
+ ret = do_send_client_certificate(hs);
+ break;
+ case state_send_client_key_exchange:
+ ret = do_send_client_key_exchange(hs);
+ break;
+ case state_send_client_certificate_verify:
+ ret = do_send_client_certificate_verify(hs);
+ break;
+ case state_send_second_client_flight:
+ ret = do_send_second_client_flight(hs);
+ break;
+ case state_send_channel_id:
+ ret = do_send_channel_id(hs);
+ break;
+ case state_send_client_finished:
+ ret = do_send_client_finished(hs);
+ break;
+ case state_finish_flight:
+ ret = do_finish_flight(hs);
+ break;
+ case state_read_session_ticket:
+ ret = do_read_session_ticket(hs);
+ break;
+ case state_process_change_cipher_spec:
+ ret = do_process_change_cipher_spec(hs);
+ break;
+ case state_read_server_finished:
+ ret = do_read_server_finished(hs);
+ break;
+ case state_finish_client_handshake:
+ ret = do_finish_client_handshake(hs);
+ break;
+ case state_done:
+ ret = ssl_hs_ok;
+ break;
+ }
+
+ if (hs->state != state) {
+ ssl_do_info_callback(hs->ssl, SSL_CB_CONNECT_LOOP, 1);
+ }
+
+ if (ret != ssl_hs_ok) {
+ return ret;
+ }
+ }
+
+ ssl_do_info_callback(hs->ssl, SSL_CB_HANDSHAKE_DONE, 1);
+ return ssl_hs_ok;
+}
+
+const char *ssl_client_handshake_state(SSL_HANDSHAKE *hs) {
+ enum ssl_client_hs_state_t state =
+ static_cast<enum ssl_client_hs_state_t>(hs->state);
+ switch (state) {
+ case state_start_connect:
+ return "TLS client start_connect";
+ case state_send_client_hello:
+ return "TLS client send_client_hello";
+ case state_enter_early_data:
+ return "TLS client enter_early_data";
+ case state_read_hello_verify_request:
+ return "TLS client read_hello_verify_request";
+ case state_read_server_hello:
+ return "TLS client read_server_hello";
+ case state_tls13:
+ return tls13_client_handshake_state(hs);
+ case state_read_server_certificate:
+ return "TLS client read_server_certificate";
+ case state_read_certificate_status:
+ return "TLS client read_certificate_status";
+ case state_verify_server_certificate:
+ return "TLS client verify_server_certificate";
+ case state_read_server_key_exchange:
+ return "TLS client read_server_key_exchange";
+ case state_read_certificate_request:
+ return "TLS client read_certificate_request";
+ case state_read_server_hello_done:
+ return "TLS client read_server_hello_done";
+ case state_send_client_certificate:
+ return "TLS client send_client_certificate";
+ case state_send_client_key_exchange:
+ return "TLS client send_client_key_exchange";
+ case state_send_client_certificate_verify:
+ return "TLS client send_client_certificate_verify";
+ case state_send_second_client_flight:
+ return "TLS client send_second_client_flight";
+ case state_send_channel_id:
+ return "TLS client send_channel_id";
+ case state_send_client_finished:
+ return "TLS client send_client_finished";
+ case state_finish_flight:
+ return "TLS client finish_flight";
+ case state_read_session_ticket:
+ return "TLS client read_session_ticket";
+ case state_process_change_cipher_spec:
+ return "TLS client process_change_cipher_spec";
+ case state_read_server_finished:
+ return "TLS client read_server_finished";
+ case state_finish_client_handshake:
+ return "TLS client finish_client_handshake";
+ case state_done:
+ return "TLS client done";
+ }
+
+ return "TLS client unknown";
+}
+
+}
diff --git a/ssl/handshake_server.cc b/ssl/handshake_server.cc
index 2d5b85e..b1df9f9 100644
--- a/ssl/handshake_server.cc
+++ b/ssl/handshake_server.cc
@@ -4,21 +4,21 @@
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
- *
+ *
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
+ *
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,10 +33,10 @@
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
+ * 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
+ *
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -48,7 +48,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
@@ -62,7 +62,7 @@
* are met:
*
* 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
+ * notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
@@ -110,7 +110,7 @@
/* ====================================================================
* Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
*
- * Portions of the attached software ("Contribution") are developed by
+ * Portions of the attached software ("Contribution") are developed by
* SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
*
* The Contribution is licensed pursuant to the OpenSSL open source
@@ -172,284 +172,29 @@
namespace bssl {
-static int ssl3_read_client_hello(SSL_HANDSHAKE *hs);
-static int ssl3_select_certificate(SSL_HANDSHAKE *hs);
-static int ssl3_select_parameters(SSL_HANDSHAKE *hs);
-static int ssl3_send_server_hello(SSL_HANDSHAKE *hs);
-static int ssl3_send_server_certificate(SSL_HANDSHAKE *hs);
-static int ssl3_send_server_key_exchange(SSL_HANDSHAKE *hs);
-static int ssl3_send_server_hello_done(SSL_HANDSHAKE *hs);
-static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs);
-static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs);
-static int ssl3_get_cert_verify(SSL_HANDSHAKE *hs);
-static int ssl3_get_next_proto(SSL_HANDSHAKE *hs);
-static int ssl3_get_channel_id(SSL_HANDSHAKE *hs);
-static int ssl3_send_server_finished(SSL_HANDSHAKE *hs);
-
-int ssl3_accept(SSL_HANDSHAKE *hs) {
- SSL *const ssl = hs->ssl;
- int ret = -1;
-
- assert(ssl->handshake_func == ssl3_accept);
- assert(ssl->server);
-
- for (;;) {
- int state = hs->state;
-
- switch (hs->state) {
- case SSL_ST_INIT:
- ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_START, 1);
- hs->state = SSL3_ST_SR_CLNT_HELLO_A;
- break;
-
- case SSL3_ST_SR_CLNT_HELLO_A:
- ret = ssl3_read_client_hello(hs);
- if (ret <= 0) {
- goto end;
- }
- hs->state = SSL3_ST_SR_CLNT_HELLO_B;
- break;
-
- case SSL3_ST_SR_CLNT_HELLO_B:
- ret = ssl3_select_certificate(hs);
- if (ret <= 0) {
- goto end;
- }
- if (hs->state != SSL_ST_TLS13) {
- hs->state = SSL3_ST_SR_CLNT_HELLO_C;
- }
- break;
-
- case SSL3_ST_SR_CLNT_HELLO_C:
- ret = ssl3_select_parameters(hs);
- if (ret <= 0) {
- goto end;
- }
- hs->state = SSL3_ST_SW_SRVR_HELLO_A;
- break;
-
- case SSL3_ST_SW_SRVR_HELLO_A:
- ret = ssl3_send_server_hello(hs);
- if (ret <= 0) {
- goto end;
- }
- if (ssl->session != NULL) {
- hs->state = SSL3_ST_SW_FINISHED_A;
- } else {
- hs->state = SSL3_ST_SW_CERT_A;
- }
- break;
-
- case SSL3_ST_SW_CERT_A:
- ret = ssl3_send_server_certificate(hs);
- if (ret <= 0) {
- goto end;
- }
- hs->state = SSL3_ST_SW_KEY_EXCH_A;
- break;
-
- case SSL3_ST_SW_KEY_EXCH_A:
- if (hs->server_params_len > 0) {
- ret = ssl3_send_server_key_exchange(hs);
- if (ret <= 0) {
- goto end;
- }
- }
-
- hs->state = SSL3_ST_SW_SRVR_DONE_A;
- break;
-
- case SSL3_ST_SW_SRVR_DONE_A:
- ret = ssl3_send_server_hello_done(hs);
- if (ret <= 0) {
- goto end;
- }
- hs->next_state = SSL3_ST_SR_CERT_A;
- hs->state = SSL3_ST_SW_FLUSH;
- break;
-
- case SSL3_ST_SR_CERT_A:
- if (hs->cert_request) {
- ret = ssl3_get_client_certificate(hs);
- if (ret <= 0) {
- goto end;
- }
- }
- hs->state = SSL3_ST_VERIFY_CLIENT_CERT;
- break;
-
- case SSL3_ST_VERIFY_CLIENT_CERT:
- if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) > 0) {
- switch (ssl_verify_peer_cert(hs)) {
- case ssl_verify_ok:
- break;
- case ssl_verify_invalid:
- ret = -1;
- goto end;
- case ssl_verify_retry:
- ssl->rwstate = SSL_CERTIFICATE_VERIFY;
- ret = -1;
- goto end;
- }
- }
- hs->state = SSL3_ST_SR_KEY_EXCH_A;
- break;
-
- case SSL3_ST_SR_KEY_EXCH_A:
- ret = ssl3_get_client_key_exchange(hs);
- if (ret <= 0) {
- goto end;
- }
- hs->state = SSL3_ST_SR_CERT_VRFY_A;
- break;
-
- case SSL3_ST_SR_CERT_VRFY_A:
- ret = ssl3_get_cert_verify(hs);
- if (ret <= 0) {
- goto end;
- }
-
- hs->state = SSL3_ST_SR_CHANGE;
- break;
-
- case SSL3_ST_SR_CHANGE:
- ret = ssl->method->read_change_cipher_spec(ssl);
- if (ret <= 0) {
- goto end;
- }
-
- if (!tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_SERVER_READ)) {
- ret = -1;
- goto end;
- }
-
- hs->state = SSL3_ST_SR_NEXT_PROTO_A;
- break;
-
- case SSL3_ST_SR_NEXT_PROTO_A:
- if (hs->next_proto_neg_seen) {
- ret = ssl3_get_next_proto(hs);
- if (ret <= 0) {
- goto end;
- }
- }
- hs->state = SSL3_ST_SR_CHANNEL_ID_A;
- break;
-
- case SSL3_ST_SR_CHANNEL_ID_A:
- if (ssl->s3->tlsext_channel_id_valid) {
- ret = ssl3_get_channel_id(hs);
- if (ret <= 0) {
- goto end;
- }
- }
- hs->state = SSL3_ST_SR_FINISHED_A;
- break;
-
- case SSL3_ST_SR_FINISHED_A:
- ret = ssl3_get_finished(hs);
- if (ret <= 0) {
- goto end;
- }
-
- if (ssl->session != NULL) {
- hs->state = SSL_ST_OK;
- } else {
- hs->state = SSL3_ST_SW_FINISHED_A;
- }
-
- /* If this is a full handshake with ChannelID then record the handshake
- * hashes in |hs->new_session| in case we need them to verify a
- * ChannelID signature on a resumption of this session in the future. */
- if (ssl->session == NULL && ssl->s3->tlsext_channel_id_valid) {
- ret = tls1_record_handshake_hashes_for_channel_id(hs);
- if (ret <= 0) {
- goto end;
- }
- }
- break;
-
- case SSL3_ST_SW_FINISHED_A:
- ret = ssl3_send_server_finished(hs);
- if (ret <= 0) {
- goto end;
- }
- hs->state = SSL3_ST_SW_FLUSH;
- if (ssl->session != NULL) {
- hs->next_state = SSL3_ST_SR_CHANGE;
- } else {
- hs->next_state = SSL_ST_OK;
- }
- break;
-
- case SSL3_ST_SW_FLUSH:
- ret = ssl->method->flush_flight(ssl);
- if (ret <= 0) {
- goto end;
- }
-
- hs->state = hs->next_state;
- break;
-
- case SSL_ST_TLS13: {
- int early_return = 0;
- ret = tls13_handshake(hs, &early_return);
- if (ret <= 0) {
- goto end;
- }
-
- if (early_return) {
- ret = 1;
- goto end;
- }
-
- hs->state = SSL_ST_OK;
- break;
- }
-
- case SSL_ST_OK:
- ssl->method->on_handshake_complete(ssl);
-
- /* If we aren't retaining peer certificates then we can discard it
- * now. */
- if (hs->new_session != NULL &&
- ssl->retain_only_sha256_of_client_certs) {
- sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free);
- hs->new_session->certs = NULL;
- ssl->ctx->x509_method->session_clear(hs->new_session.get());
- }
-
- SSL_SESSION_free(ssl->s3->established_session);
- if (ssl->session != NULL) {
- SSL_SESSION_up_ref(ssl->session);
- ssl->s3->established_session = ssl->session;
- } else {
- ssl->s3->established_session = hs->new_session.release();
- ssl->s3->established_session->not_resumable = 0;
- }
-
- ssl->s3->initial_handshake_complete = 1;
- ssl_update_cache(hs, SSL_SESS_CACHE_SERVER);
-
- ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_DONE, 1);
- ret = 1;
- goto end;
-
- default:
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE);
- ret = -1;
- goto end;
- }
-
- if (hs->state != state) {
- ssl_do_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 1);
- }
- }
-
-end:
- ssl_do_info_callback(ssl, SSL_CB_ACCEPT_EXIT, ret);
- return ret;
-}
+enum ssl_server_hs_state_t {
+ state_start_accept = 0,
+ state_read_client_hello,
+ state_select_certificate,
+ state_tls13,
+ state_select_parameters,
+ state_send_server_hello,
+ state_send_server_certificate,
+ state_send_server_key_exchange,
+ state_send_server_hello_done,
+ state_read_client_certificate,
+ state_verify_client_certificate,
+ state_read_client_key_exchange,
+ state_read_client_certificate_verify,
+ state_read_change_cipher_spec,
+ state_process_change_cipher_spec,
+ state_read_next_proto,
+ state_read_channel_id,
+ state_read_client_finished,
+ state_send_server_finished,
+ state_finish_server_handshake,
+ state_done,
+};
int ssl_client_cipher_list_contains_cipher(const SSL_CLIENT_HELLO *client_hello,
uint16_t id) {
@@ -677,36 +422,42 @@
return nullptr;
}
-static int ssl3_read_client_hello(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_start_accept(SSL_HANDSHAKE *hs) {
+ ssl_do_info_callback(hs->ssl, SSL_CB_HANDSHAKE_START, 1);
+ hs->state = state_read_client_hello;
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_read_client_hello(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+
SSLMessage msg;
- int ret = ssl_read_message(ssl, &msg);
- if (ret <= 0) {
- return ret;
+ if (!ssl->method->get_message(ssl, &msg)) {
+ return ssl_hs_read_message;
}
+
if (!ssl_check_message_type(ssl, msg, SSL3_MT_CLIENT_HELLO)) {
- return -1;
+ return ssl_hs_error;
}
SSL_CLIENT_HELLO client_hello;
if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
/* Run the early callback. */
if (ssl->ctx->select_certificate_cb != NULL) {
switch (ssl->ctx->select_certificate_cb(&client_hello)) {
case ssl_select_cert_retry:
- ssl->rwstate = SSL_CERTIFICATE_SELECTION_PENDING;
- return -1;
+ return ssl_hs_certificate_selection_pending;
case ssl_select_cert_error:
/* Connection rejected. */
OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
- return -1;
+ return ssl_hs_error;
default:
/* fallthrough */;
@@ -715,19 +466,19 @@
/* Freeze the version range after the early callback. */
if (!ssl_get_version_range(ssl, &hs->min_version, &hs->max_version)) {
- return -1;
+ return ssl_hs_error;
}
uint8_t alert = SSL_AD_DECODE_ERROR;
if (!negotiate_version(hs, &alert, &client_hello)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
- return -1;
+ return ssl_hs_error;
}
hs->client_version = client_hello.version;
if (client_hello.random_len != SSL3_RANDOM_SIZE) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
OPENSSL_memcpy(ssl->s3->client_random, client_hello.random,
client_hello.random_len);
@@ -740,24 +491,25 @@
client_hello.compression_methods_len != 1)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMPRESSION_LIST);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return -1;
+ return ssl_hs_error;
}
/* TLS extensions. */
if (!ssl_parse_clienthello_tlsext(hs, &client_hello)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
- return -1;
+ return ssl_hs_error;
}
- return 1;
+ hs->state = state_select_certificate;
+ return ssl_hs_ok;
}
-static int ssl3_select_certificate(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_select_certificate(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+
SSLMessage msg;
- int ret = ssl_read_message(ssl, &msg);
- if (ret <= 0) {
- return ret;
+ if (!ssl->method->get_message(ssl, &msg)) {
+ return ssl_hs_read_message;
}
/* Call |cert_cb| to update server certificates if required. */
@@ -766,28 +518,26 @@
if (rv == 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
if (rv < 0) {
- ssl->rwstate = SSL_X509_LOOKUP;
- return -1;
+ return ssl_hs_x509_lookup;
}
}
if (!ssl_on_certificate_selected(hs)) {
- return -1;
+ return ssl_hs_error;
}
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
/* Jump to the TLS 1.3 state machine. */
- hs->state = SSL_ST_TLS13;
- hs->do_tls13_handshake = tls13_server_handshake;
- return 1;
+ hs->state = state_tls13;
+ return ssl_hs_ok;
}
SSL_CLIENT_HELLO client_hello;
if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
- return -1;
+ return ssl_hs_error;
}
/* Negotiate the cipher suite. This must be done after |cert_cb| so the
@@ -797,22 +547,34 @@
if (hs->new_cipher == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
- return -1;
+ return ssl_hs_error;
}
- return 1;
+ hs->state = state_select_parameters;
+ return ssl_hs_ok;
}
-static int ssl3_select_parameters(SSL_HANDSHAKE *hs) {
- SSL *const ssl = hs->ssl;
- SSLMessage msg;
- int ret = ssl_read_message(ssl, &msg);
- if (ret <= 0) {
- return ret;
+static enum ssl_hs_wait_t do_tls13(SSL_HANDSHAKE *hs) {
+ enum ssl_hs_wait_t wait = tls13_server_handshake(hs);
+ if (wait == ssl_hs_ok) {
+ hs->state = state_finish_server_handshake;
+ return ssl_hs_ok;
}
+
+ return wait;
+}
+
+static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+
+ SSLMessage msg;
+ if (!ssl->method->get_message(ssl, &msg)) {
+ return ssl_hs_read_message;
+ }
+
SSL_CLIENT_HELLO client_hello;
if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
- return -1;
+ return ssl_hs_error;
}
/* Determine whether we are doing session resumption. */
@@ -823,13 +585,11 @@
case ssl_session_success:
break;
case ssl_session_error:
- return -1;
+ return ssl_hs_error;
case ssl_session_retry:
- ssl->rwstate = SSL_PENDING_SESSION;
- return -1;
+ return ssl_hs_pending_session;
case ssl_session_ticket_retry:
- ssl->rwstate = SSL_PENDING_TICKET;
- return -1;
+ return ssl_hs_pending_ticket;
}
if (session) {
@@ -838,7 +598,7 @@
* is fatal to the connection. */
OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
- return -1;
+ return ssl_hs_error;
}
if (!ssl_session_is_resumable(hs, session.get()) ||
@@ -858,7 +618,7 @@
hs->ticket_expected = tickets_supported;
ssl_set_session(ssl, NULL);
if (!ssl_get_new_session(hs, 1 /* server */)) {
- return -1;
+ return ssl_hs_error;
}
/* Clear the session ID if we want the session to be single-use. */
@@ -872,7 +632,7 @@
/* 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 -1;
+ return ssl_hs_error;
}
if (ssl->session == NULL) {
@@ -884,7 +644,7 @@
hs->new_session->tlsext_hostname = BUF_strdup(hs->hostname.get());
if (hs->new_session->tlsext_hostname == NULL) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
}
@@ -912,7 +672,7 @@
uint8_t alert = SSL_AD_DECODE_ERROR;
if (!ssl_negotiate_alpn(hs, &alert, &client_hello)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
- return -1;
+ return ssl_hs_error;
}
/* Now that all parameters are known, initialize the handshake hash and hash
@@ -920,7 +680,7 @@
if (!hs->transcript.InitHash(ssl3_protocol_version(ssl), hs->new_cipher) ||
!ssl_hash_message(hs, msg)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
/* Release the handshake buffer if client authentication isn't required. */
@@ -929,10 +689,12 @@
}
ssl->method->next_message(ssl);
- return 1;
+
+ hs->state = state_send_server_hello;
+ return ssl_hs_ok;
}
-static int ssl3_send_server_hello(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
/* We only accept ChannelIDs on connections with ECDHE in order to avoid a
@@ -957,7 +719,7 @@
ssl->s3->server_random[2] = now.tv_sec >> 8;
ssl->s3->server_random[3] = now.tv_sec;
if (!RAND_bytes(ssl->s3->server_random + 4, SSL3_RANDOM_SIZE - 4)) {
- return -1;
+ return ssl_hs_error;
}
/* TODO(davidben): Implement the TLS 1.1 and 1.2 downgrade sentinels once TLS
@@ -981,24 +743,29 @@
!ssl_add_serverhello_tlsext(hs, &body) ||
!ssl_add_message_cbb(ssl, cbb.get())) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
- return 1;
+ if (ssl->session != NULL) {
+ hs->state = state_send_server_finished;
+ } else {
+ hs->state = state_send_server_certificate;
+ }
+ return ssl_hs_ok;
}
-static int ssl3_send_server_certificate(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_send_server_certificate(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
ScopedCBB cbb;
if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
if (!ssl_has_certificate(ssl)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET);
- return -1;
+ return ssl_hs_error;
}
if (!ssl3_output_cert_chain(ssl)) {
- return -1;
+ return ssl_hs_error;
}
if (hs->certificate_status_expected) {
@@ -1012,7 +779,7 @@
CRYPTO_BUFFER_len(ssl->cert->ocsp_response)) ||
!ssl_add_message_cbb(ssl, cbb.get())) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
}
}
@@ -1029,7 +796,7 @@
if (!CBB_init(cbb.get(), SSL3_RANDOM_SIZE * 2 + 128) ||
!CBB_add_bytes(cbb.get(), ssl->s3->client_random, SSL3_RANDOM_SIZE) ||
!CBB_add_bytes(cbb.get(), ssl->s3->server_random, SSL3_RANDOM_SIZE)) {
- return -1;
+ return ssl_hs_error;
}
/* PSK ciphers begin with an identity hint. */
@@ -1039,7 +806,7 @@
if (!CBB_add_u16_length_prefixed(cbb.get(), &child) ||
!CBB_add_bytes(&child, (const uint8_t *)ssl->psk_identity_hint,
len)) {
- return -1;
+ return ssl_hs_error;
}
}
@@ -1049,7 +816,7 @@
if (!tls1_get_shared_group(hs, &group_id)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
- return -1;
+ return ssl_hs_error;
}
hs->new_session->group_id = group_id;
@@ -1060,22 +827,29 @@
!CBB_add_u16(cbb.get(), group_id) ||
!CBB_add_u8_length_prefixed(cbb.get(), &child) ||
!hs->key_share->Offer(&child)) {
- return -1;
+ return ssl_hs_error;
}
} else {
assert(alg_k & SSL_kPSK);
}
if (!CBB_finish(cbb.get(), &hs->server_params, &hs->server_params_len)) {
- return -1;
+ return ssl_hs_error;
}
}
- return 1;
+ hs->state = state_send_server_key_exchange;
+ return ssl_hs_ok;
}
-static int ssl3_send_server_key_exchange(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_send_server_key_exchange(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+
+ if (hs->server_params_len == 0) {
+ hs->state = state_send_server_hello_done;
+ return ssl_hs_ok;
+ }
+
ScopedCBB cbb;
CBB body, child;
if (!ssl->method->init_message(ssl, cbb.get(), &body,
@@ -1084,26 +858,26 @@
hs->server_params_len < 2 * SSL3_RANDOM_SIZE ||
!CBB_add_bytes(&body, hs->server_params + 2 * SSL3_RANDOM_SIZE,
hs->server_params_len - 2 * SSL3_RANDOM_SIZE)) {
- return -1;
+ return ssl_hs_error;
}
/* Add a signature. */
if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
if (!ssl_has_private_key(ssl)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
/* Determine the signature algorithm. */
uint16_t signature_algorithm;
if (!tls1_choose_signature_algorithm(hs, &signature_algorithm)) {
- return -1;
+ return ssl_hs_error;
}
if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
if (!CBB_add_u16(&body, signature_algorithm)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
}
@@ -1112,7 +886,7 @@
uint8_t *ptr;
if (!CBB_add_u16_length_prefixed(&body, &child) ||
!CBB_reserve(&child, &ptr, max_sig_len)) {
- return -1;
+ return ssl_hs_error;
}
size_t sig_len;
@@ -1121,30 +895,31 @@
hs->server_params_len)) {
case ssl_private_key_success:
if (!CBB_did_write(&child, sig_len)) {
- return -1;
+ return ssl_hs_error;
}
break;
case ssl_private_key_failure:
- return -1;
+ return ssl_hs_error;
case ssl_private_key_retry:
- ssl->rwstate = SSL_PRIVATE_KEY_OPERATION;
- return -1;
+ return ssl_hs_private_key_operation;
}
}
if (!ssl_add_message_cbb(ssl, cbb.get())) {
- return -1;
+ return ssl_hs_error;
}
OPENSSL_free(hs->server_params);
hs->server_params = NULL;
hs->server_params_len = 0;
- return 1;
+ hs->state = state_send_server_hello_done;
+ return ssl_hs_ok;
}
-static int ssl3_send_server_hello_done(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_send_server_hello_done(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+
ScopedCBB cbb;
CBB body;
@@ -1162,7 +937,7 @@
!ssl_add_client_CA_list(ssl, &body) ||
!ssl_add_message_cbb(ssl, cbb.get())) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
}
@@ -1170,20 +945,24 @@
SSL3_MT_SERVER_HELLO_DONE) ||
!ssl_add_message_cbb(ssl, cbb.get())) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
+ return ssl_hs_error;
}
- return 1;
+ hs->state = state_read_client_certificate;
+ return ssl_hs_flush;
}
-static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_client_certificate(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
- assert(hs->cert_request);
+
+ if (!hs->cert_request) {
+ hs->state = state_verify_client_certificate;
+ return ssl_hs_ok;
+ }
SSLMessage msg;
- int ret = ssl_read_message(ssl, &msg);
- if (ret <= 0) {
- return ret;
+ if (!ssl->method->get_message(ssl, &msg)) {
+ return ssl_hs_read_message;
}
if (msg.type != SSL3_MT_CERTIFICATE) {
@@ -1194,22 +973,23 @@
if (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
- return -1;
+ return ssl_hs_error;
}
/* OpenSSL returns X509_V_OK when no certificates are received. This is
* classed by them as a bug, but it's assumed by at least NGINX. */
hs->new_session->verify_result = X509_V_OK;
- return 1;
+ hs->state = state_verify_client_certificate;
+ return ssl_hs_ok;
}
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
- return -1;
+ return ssl_hs_error;
}
if (!ssl_hash_message(hs, msg)) {
- return -1;
+ return ssl_hs_error;
}
CBS certificate_msg = msg.body;
@@ -1221,7 +1001,7 @@
: NULL,
&certificate_msg, ssl->ctx->pool)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
- return -1;
+ return ssl_hs_error;
}
sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free);
hs->new_session->certs = chain.release();
@@ -1230,7 +1010,7 @@
!ssl->ctx->x509_method->session_cache_objects(hs->new_session.get())) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) == 0) {
@@ -1242,14 +1022,14 @@
if (ssl->version == SSL3_VERSION) {
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATES_RETURNED);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
- return -1;
+ return ssl_hs_error;
}
if (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
/* Fail for TLS only if we required a certificate */
OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
- return -1;
+ return ssl_hs_error;
}
/* OpenSSL returns X509_V_OK when no certificates are received. This is
@@ -1261,23 +1041,41 @@
}
ssl->method->next_message(ssl);
- return 1;
+ hs->state = state_verify_client_certificate;
+ return ssl_hs_ok;
}
-static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_verify_client_certificate(SSL_HANDSHAKE *hs) {
+ if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) > 0) {
+ switch (ssl_verify_peer_cert(hs)) {
+ case ssl_verify_ok:
+ break;
+ case ssl_verify_invalid:
+ return ssl_hs_error;
+ case ssl_verify_retry:
+ return ssl_hs_certificate_verify;
+ }
+ }
+
+ hs->state = state_read_client_key_exchange;
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_read_client_key_exchange(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+
+ ssl_hs_wait_t ret = ssl_hs_error;
uint8_t *premaster_secret = NULL;
size_t premaster_secret_len = 0;
uint8_t *decrypt_buf = NULL;
SSLMessage msg;
- int ret = ssl_read_message(ssl, &msg);
- if (ret <= 0) {
- return ret;
+ if (!ssl->method->get_message(ssl, &msg)) {
+ return ssl_hs_read_message;
}
if (!ssl_check_message_type(ssl, msg, SSL3_MT_CLIENT_KEY_EXCHANGE)) {
- return -1;
+ return ssl_hs_error;
}
CBS client_key_exchange = msg.body;
@@ -1346,7 +1144,7 @@
case ssl_private_key_failure:
goto err;
case ssl_private_key_retry:
- ssl->rwstate = SSL_PRIVATE_KEY_OPERATION;
+ ret = ssl_hs_private_key_operation;
goto err;
}
@@ -1496,10 +1294,9 @@
}
hs->new_session->extended_master_secret = hs->extended_master_secret;
- OPENSSL_cleanse(premaster_secret, premaster_secret_len);
- OPENSSL_free(premaster_secret);
ssl->method->next_message(ssl);
- return 1;
+ hs->state = state_read_client_certificate_verify;
+ ret = ssl_hs_ok;
err:
if (premaster_secret != NULL) {
@@ -1508,10 +1305,11 @@
}
OPENSSL_free(decrypt_buf);
- return -1;
+ return ret;
+
}
-static int ssl3_get_cert_verify(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_client_certificate_verify(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
/* Only RSA and ECDSA client certificates are supported, so a
@@ -1519,17 +1317,17 @@
* */
if (!hs->peer_pubkey) {
hs->transcript.FreeBuffer();
- return 1;
+ hs->state = state_read_change_cipher_spec;
+ return ssl_hs_ok;
}
SSLMessage msg;
- int ret = ssl_read_message(ssl, &msg);
- if (ret <= 0) {
- return ret;
+ if (!ssl->method->get_message(ssl, &msg)) {
+ return ssl_hs_read_message;
}
if (!ssl_check_message_type(ssl, msg, SSL3_MT_CERTIFICATE_VERIFY)) {
- return -1;
+ return ssl_hs_error;
}
CBS certificate_verify = msg.body, signature;
@@ -1540,19 +1338,19 @@
if (!CBS_get_u16(&certificate_verify, &signature_algorithm)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
uint8_t alert = SSL_AD_DECODE_ERROR;
if (!tls12_check_peer_sigalg(ssl, &alert, signature_algorithm)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
- return -1;
+ return ssl_hs_error;
}
hs->new_session->peer_signature_algorithm = signature_algorithm;
} else if (!tls1_get_legacy_signature_algorithm(&signature_algorithm,
hs->peer_pubkey.get())) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_CERTIFICATE);
- return -1;
+ return ssl_hs_error;
}
/* Parse and verify the signature. */
@@ -1560,7 +1358,7 @@
CBS_len(&certificate_verify) != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
int sig_ok;
@@ -1571,7 +1369,7 @@
size_t digest_len;
if (!hs->transcript.GetSSL3CertVerifyHash(
digest, &digest_len, hs->new_session.get(), signature_algorithm)) {
- return -1;
+ return ssl_hs_error;
}
UniquePtr<EVP_PKEY_CTX> pctx(
@@ -1594,33 +1392,51 @@
if (!sig_ok) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
- return -1;
+ return ssl_hs_error;
}
/* The handshake buffer is no longer necessary, and we may hash the current
* message.*/
hs->transcript.FreeBuffer();
if (!ssl_hash_message(hs, msg)) {
- return -1;
+ return ssl_hs_error;
}
ssl->method->next_message(ssl);
- return 1;
+ hs->state = state_read_change_cipher_spec;
+ return ssl_hs_ok;
}
-/* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It
- * sets the next_proto member in s if found */
-static int ssl3_get_next_proto(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_change_cipher_spec(SSL_HANDSHAKE *hs) {
+ hs->state = state_process_change_cipher_spec;
+ return ssl_hs_read_change_cipher_spec;
+}
+
+static enum ssl_hs_wait_t do_process_change_cipher_spec(SSL_HANDSHAKE *hs) {
+ if (!tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_SERVER_READ)) {
+ return ssl_hs_error;
+ }
+
+ hs->state = state_read_next_proto;
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_read_next_proto(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+
+ if (!hs->next_proto_neg_seen) {
+ hs->state = state_read_channel_id;
+ return ssl_hs_ok;
+ }
+
SSLMessage msg;
- int ret = ssl_read_message(ssl, &msg);
- if (ret <= 0) {
- return ret;
+ if (!ssl->method->get_message(ssl, &msg)) {
+ return ssl_hs_read_message;
}
if (!ssl_check_message_type(ssl, msg, SSL3_MT_NEXT_PROTO) ||
!ssl_hash_message(hs, msg)) {
- return -1;
+ return ssl_hs_error;
}
CBS next_protocol = msg.body, selected_protocol, padding;
@@ -1629,37 +1445,68 @@
CBS_len(&next_protocol) != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return -1;
+ return ssl_hs_error;
}
if (!CBS_stow(&selected_protocol, &ssl->s3->next_proto_negotiated,
&ssl->s3->next_proto_negotiated_len)) {
- return -1;
+ return ssl_hs_error;
}
ssl->method->next_message(ssl);
- return 1;
+ hs->state = state_read_channel_id;
+ return ssl_hs_ok;
}
-/* ssl3_get_channel_id reads and verifies a ClientID handshake message. */
-static int ssl3_get_channel_id(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_channel_id(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+
+ if (!ssl->s3->tlsext_channel_id_valid) {
+ hs->state = state_read_client_finished;
+ return ssl_hs_ok;
+ }
+
SSLMessage msg;
- int ret = ssl_read_message(ssl, &msg);
- if (ret <= 0) {
- return ret;
+ if (!ssl->method->get_message(ssl, &msg)) {
+ return ssl_hs_read_message;
}
if (!ssl_check_message_type(ssl, msg, SSL3_MT_CHANNEL_ID) ||
!tls1_verify_channel_id(hs, msg) ||
!ssl_hash_message(hs, msg)) {
- return -1;
+ return ssl_hs_error;
}
+
ssl->method->next_message(ssl);
- return 1;
+ hs->state = state_read_client_finished;
+ return ssl_hs_ok;
}
-static int ssl3_send_server_finished(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_client_finished(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ enum ssl_hs_wait_t wait = ssl_get_finished(hs);
+ if (wait != ssl_hs_ok) {
+ return wait;
+ }
+
+ if (ssl->session != NULL) {
+ hs->state = state_finish_server_handshake;
+ } else {
+ hs->state = state_send_server_finished;
+ }
+
+ /* If this is a full handshake with ChannelID then record the handshake
+ * hashes in |hs->new_session| in case we need them to verify a
+ * ChannelID signature on a resumption of this session in the future. */
+ if (ssl->session == NULL && ssl->s3->tlsext_channel_id_valid &&
+ !tls1_record_handshake_hashes_for_channel_id(hs)) {
+ return ssl_hs_error;
+ }
+
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_send_server_finished(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
if (hs->ticket_expected) {
@@ -1674,7 +1521,7 @@
* the timeout. */
session_copy = SSL_SESSION_dup(ssl->session, SSL_SESSION_INCLUDE_NONAUTH);
if (!session_copy) {
- return -1;
+ return ssl_hs_error;
}
ssl_session_rebase_time(ssl, session_copy.get());
@@ -1689,16 +1536,186 @@
!CBB_add_u16_length_prefixed(&body, &ticket) ||
!ssl_encrypt_ticket(ssl, &ticket, session) ||
!ssl_add_message_cbb(ssl, cbb.get())) {
- return -1;
+ return ssl_hs_error;
}
}
if (!ssl->method->add_change_cipher_spec(ssl) ||
- !tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_SERVER_WRITE)) {
- return -1;
+ !tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_SERVER_WRITE) ||
+ !ssl3_send_finished(hs)) {
+ return ssl_hs_error;
}
- return ssl3_send_finished(hs);
+ if (ssl->session != NULL) {
+ hs->state = state_read_change_cipher_spec;
+ } else {
+ hs->state = state_finish_server_handshake;
+ }
+ return ssl_hs_flush;
}
-} // namespace bssl
+static enum ssl_hs_wait_t do_finish_server_handshake(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+
+ ssl->method->on_handshake_complete(ssl);
+
+ /* If we aren't retaining peer certificates then we can discard it
+ * now. */
+ if (hs->new_session != NULL && ssl->retain_only_sha256_of_client_certs) {
+ sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free);
+ hs->new_session->certs = NULL;
+ ssl->ctx->x509_method->session_clear(hs->new_session.get());
+ }
+
+ SSL_SESSION_free(ssl->s3->established_session);
+ if (ssl->session != NULL) {
+ SSL_SESSION_up_ref(ssl->session);
+ ssl->s3->established_session = ssl->session;
+ } else {
+ ssl->s3->established_session = hs->new_session.release();
+ ssl->s3->established_session->not_resumable = 0;
+ }
+
+ ssl->s3->initial_handshake_complete = 1;
+ ssl_update_cache(hs, SSL_SESS_CACHE_SERVER);
+
+ hs->state = state_done;
+ return ssl_hs_ok;
+}
+
+enum ssl_hs_wait_t ssl_server_handshake(SSL_HANDSHAKE *hs) {
+ while (hs->state != state_done) {
+ enum ssl_hs_wait_t ret = ssl_hs_error;
+ enum ssl_server_hs_state_t state =
+ static_cast<enum ssl_server_hs_state_t>(hs->state);
+ switch (state) {
+ case state_start_accept:
+ ret = do_start_accept(hs);
+ break;
+ case state_read_client_hello:
+ ret = do_read_client_hello(hs);
+ break;
+ case state_select_certificate:
+ ret = do_select_certificate(hs);
+ break;
+ case state_tls13:
+ ret = do_tls13(hs);
+ break;
+ case state_select_parameters:
+ ret = do_select_parameters(hs);
+ break;
+ case state_send_server_hello:
+ ret = do_send_server_hello(hs);
+ break;
+ case state_send_server_certificate:
+ ret = do_send_server_certificate(hs);
+ break;
+ case state_send_server_key_exchange:
+ ret = do_send_server_key_exchange(hs);
+ break;
+ case state_send_server_hello_done:
+ ret = do_send_server_hello_done(hs);
+ break;
+ case state_read_client_certificate:
+ ret = do_read_client_certificate(hs);
+ break;
+ case state_verify_client_certificate:
+ ret = do_verify_client_certificate(hs);
+ break;
+ case state_read_client_key_exchange:
+ ret = do_read_client_key_exchange(hs);
+ break;
+ case state_read_client_certificate_verify:
+ ret = do_read_client_certificate_verify(hs);
+ break;
+ case state_read_change_cipher_spec:
+ ret = do_read_change_cipher_spec(hs);
+ break;
+ case state_process_change_cipher_spec:
+ ret = do_process_change_cipher_spec(hs);
+ break;
+ case state_read_next_proto:
+ ret = do_read_next_proto(hs);
+ break;
+ case state_read_channel_id:
+ ret = do_read_channel_id(hs);
+ break;
+ case state_read_client_finished:
+ ret = do_read_client_finished(hs);
+ break;
+ case state_send_server_finished:
+ ret = do_send_server_finished(hs);
+ break;
+ case state_finish_server_handshake:
+ ret = do_finish_server_handshake(hs);
+ break;
+ case state_done:
+ ret = ssl_hs_ok;
+ break;
+ }
+
+ if (hs->state != state) {
+ ssl_do_info_callback(hs->ssl, SSL_CB_ACCEPT_LOOP, 1);
+ }
+
+ if (ret != ssl_hs_ok) {
+ return ret;
+ }
+ }
+
+ ssl_do_info_callback(hs->ssl, SSL_CB_HANDSHAKE_DONE, 1);
+ return ssl_hs_ok;
+}
+
+const char *ssl_server_handshake_state(SSL_HANDSHAKE *hs) {
+ enum ssl_server_hs_state_t state =
+ static_cast<enum ssl_server_hs_state_t>(hs->state);
+ switch (state) {
+ case state_start_accept:
+ return "TLS server start_accept";
+ case state_read_client_hello:
+ return "TLS server read_client_hello";
+ case state_select_certificate:
+ return "TLS server select_certificate";
+ case state_tls13:
+ return tls13_server_handshake_state(hs);
+ case state_select_parameters:
+ return "TLS server select_parameters";
+ case state_send_server_hello:
+ return "TLS server send_server_hello";
+ case state_send_server_certificate:
+ return "TLS server send_server_certificate";
+ case state_send_server_key_exchange:
+ return "TLS server send_server_key_exchange";
+ case state_send_server_hello_done:
+ return "TLS server send_server_hello_done";
+ case state_read_client_certificate:
+ return "TLS server read_client_certificate";
+ case state_verify_client_certificate:
+ return "TLS server verify_client_certificate";
+ case state_read_client_key_exchange:
+ return "TLS server read_client_key_exchange";
+ case state_read_client_certificate_verify:
+ return "TLS server read_client_certificate_verify";
+ case state_read_change_cipher_spec:
+ return "TLS server read_change_cipher_spec";
+ case state_process_change_cipher_spec:
+ return "TLS server process_change_cipher_spec";
+ case state_read_next_proto:
+ return "TLS server read_next_proto";
+ case state_read_channel_id:
+ return "TLS server read_channel_id";
+ case state_read_client_finished:
+ return "TLS server read_client_finished";
+ case state_send_server_finished:
+ return "TLS server send_server_finished";
+ case state_finish_server_handshake:
+ return "TLS server finish_server_handshake";
+ case state_done:
+ return "TLS server done";
+ }
+
+ return "TLS server unknown";
+}
+
+}
diff --git a/ssl/internal.h b/ssl/internal.h
index b9c3998..d3efdae 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -844,11 +844,6 @@
* in a handshake message for |ssl|. */
size_t ssl_max_handshake_message_len(const SSL *ssl);
-/* ssl_read_message reads a message for the old |BIO|-based state machine. On
- * success, it returns one and sets |*out| to the current message. Otherwise, it
- * returns <= 0. */
-int ssl_read_message(SSL *ssl, SSLMessage *out);
-
/* dtls_clear_incoming_messages releases all buffered incoming messages. */
void dtls_clear_incoming_messages(SSL *ssl);
@@ -1070,12 +1065,16 @@
enum ssl_hs_wait_t {
ssl_hs_error,
ssl_hs_ok,
+ ssl_hs_read_server_hello,
ssl_hs_read_message,
ssl_hs_flush,
+ ssl_hs_certificate_selection_pending,
ssl_hs_x509_lookup,
ssl_hs_channel_id_lookup,
ssl_hs_private_key_operation,
+ ssl_hs_pending_session,
ssl_hs_pending_ticket,
+ ssl_hs_early_return,
ssl_hs_early_data_rejected,
ssl_hs_read_end_of_early_data,
ssl_hs_read_change_cipher_spec,
@@ -1090,23 +1089,16 @@
/* ssl is a non-owning pointer to the parent |SSL| object. */
SSL *ssl;
- /* do_tls13_handshake runs the TLS 1.3 handshake. On completion, it returns
- * |ssl_hs_ok|. Otherwise, it returns a value corresponding to what operation
- * is needed to progress. */
- enum ssl_hs_wait_t (*do_tls13_handshake)(SSL_HANDSHAKE *hs);
-
- /* wait contains the operation |do_tls13_handshake| is currently blocking on
- * or |ssl_hs_ok| if none. */
+ /* wait contains the operation the handshake is currently blocking on or
+ * |ssl_hs_ok| if none. */
enum ssl_hs_wait_t wait = ssl_hs_ok;
- /* state contains one of the SSL3_ST_* values. */
- int state = SSL_ST_INIT;
-
- /* next_state is used when SSL_ST_FLUSH_DATA is entered */
- int next_state = 0;
+ /* state is the internal state for the TLS 1.2 and below handshake. Its
+ * values depend on |do_handshake| but the starting state is always zero. */
+ int state = 0;
/* tls13_state is the internal state for the TLS 1.3 handshake. Its values
- * depend on |do_tls13_handshake| but the starting state is always zero. */
+ * depend on |do_handshake| but the starting state is always zero. */
int tls13_state = 0;
/* min_version is the minimum accepted protocol version, taking account both
@@ -1326,18 +1318,22 @@
* one. Otherwise, it sends an alert and returns zero. */
int ssl_check_message_type(SSL *ssl, const SSLMessage &msg, int type);
-/* tls13_handshake runs the TLS 1.3 handshake. It returns one on success and <=
- * 0 on error. It sets |out_early_return| to one if we've completed the
- * handshake early. */
-int tls13_handshake(SSL_HANDSHAKE *hs, int *out_early_return);
+/* ssl_run_handshake runs the TLS handshake. It returns one on success and <= 0
+ * on error. It sets |out_early_return| to one if we've completed the handshake
+ * early. */
+int ssl_run_handshake(SSL_HANDSHAKE *hs, int *out_early_return);
-/* The following are implementations of |do_tls13_handshake| for the client and
+/* The following are implementations of |do_handshake| for the client and
* server. */
+enum ssl_hs_wait_t ssl_client_handshake(SSL_HANDSHAKE *hs);
+enum ssl_hs_wait_t ssl_server_handshake(SSL_HANDSHAKE *hs);
enum ssl_hs_wait_t tls13_client_handshake(SSL_HANDSHAKE *hs);
enum ssl_hs_wait_t tls13_server_handshake(SSL_HANDSHAKE *hs);
-/* The following functions return human-readable representations of the TLS 1.3
+/* The following functions return human-readable representations of the TLS
* handshake states for debugging. */
+const char *ssl_client_handshake_state(SSL_HANDSHAKE *hs);
+const char *ssl_server_handshake_state(SSL_HANDSHAKE *hs);
const char *tls13_client_handshake_state(SSL_HANDSHAKE *hs);
const char *tls13_server_handshake_state(SSL_HANDSHAKE *hs);
@@ -1918,7 +1914,10 @@
BIO *rbio; /* used by SSL_read */
BIO *wbio; /* used by SSL_write */
- int (*handshake_func)(SSL_HANDSHAKE *hs);
+ /* do_handshake runs the handshake. On completion, it returns |ssl_hs_ok|.
+ * Otherwise, it returns a value corresponding to what operation is needed to
+ * progress. */
+ enum ssl_hs_wait_t (*do_handshake)(SSL_HANDSHAKE *hs);
BUF_MEM *init_buf; /* buffer used during init */
@@ -2160,7 +2159,7 @@
void ssl_update_cache(SSL_HANDSHAKE *hs, int mode);
-int ssl3_get_finished(SSL_HANDSHAKE *hs);
+enum ssl_hs_wait_t ssl_get_finished(SSL_HANDSHAKE *hs);
int ssl3_send_alert(SSL *ssl, int level, int desc);
bool ssl3_get_message(SSL *ssl, SSLMessage *out);
int ssl3_read_message(SSL *ssl);
@@ -2179,8 +2178,6 @@
int ssl3_new(SSL *ssl);
void ssl3_free(SSL *ssl);
-int ssl3_accept(SSL_HANDSHAKE *hs);
-int ssl3_connect(SSL_HANDSHAKE *hs);
int ssl3_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
int ssl3_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg, size_t *out_len);
diff --git a/ssl/s3_both.cc b/ssl/s3_both.cc
index f51af69..11da692 100644
--- a/ssl/s3_both.cc
+++ b/ssl/s3_both.cc
@@ -132,73 +132,6 @@
namespace bssl {
-SSL_HANDSHAKE::SSL_HANDSHAKE(SSL *ssl_arg)
- : ssl(ssl_arg),
- scts_requested(0),
- needs_psk_binder(0),
- received_hello_retry_request(0),
- received_custom_extension(0),
- accept_psk_mode(0),
- cert_request(0),
- certificate_status_expected(0),
- ocsp_stapling_requested(0),
- should_ack_sni(0),
- in_false_start(0),
- in_early_data(0),
- early_data_offered(0),
- can_early_read(0),
- can_early_write(0),
- next_proto_neg_seen(0),
- ticket_expected(0),
- extended_master_secret(0),
- pending_private_key_op(0) {
-}
-
-SSL_HANDSHAKE::~SSL_HANDSHAKE() {
- OPENSSL_cleanse(secret, sizeof(secret));
- OPENSSL_cleanse(early_traffic_secret, sizeof(early_traffic_secret));
- OPENSSL_cleanse(client_handshake_secret, sizeof(client_handshake_secret));
- OPENSSL_cleanse(server_handshake_secret, sizeof(server_handshake_secret));
- OPENSSL_cleanse(client_traffic_secret_0, sizeof(client_traffic_secret_0));
- OPENSSL_cleanse(server_traffic_secret_0, sizeof(server_traffic_secret_0));
- OPENSSL_free(cookie);
- OPENSSL_free(key_share_bytes);
- OPENSSL_free(ecdh_public_key);
- OPENSSL_free(peer_sigalgs);
- OPENSSL_free(peer_supported_group_list);
- OPENSSL_free(peer_key);
- OPENSSL_free(server_params);
- ssl->ctx->x509_method->hs_flush_cached_ca_names(this);
- OPENSSL_free(certificate_types);
-
- if (key_block != NULL) {
- OPENSSL_cleanse(key_block, key_block_len);
- OPENSSL_free(key_block);
- }
-}
-
-SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl) {
- UniquePtr<SSL_HANDSHAKE> hs = MakeUnique<SSL_HANDSHAKE>(ssl);
- if (!hs ||
- !hs->transcript.Init()) {
- return nullptr;
- }
- return hs.release();
-}
-
-void ssl_handshake_free(SSL_HANDSHAKE *hs) { Delete(hs); }
-
-int ssl_check_message_type(SSL *ssl, const SSLMessage &msg, int type) {
- if (msg.type != type) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
- ERR_add_error_dataf("got type %d, wanted type %d", msg.type, type);
- return 0;
- }
-
- return 1;
-}
-
static int add_record_to_flight(SSL *ssl, uint8_t type, const uint8_t *in,
size_t in_len) {
/* We'll never add a flight while in the process of writing it out. */
@@ -316,17 +249,6 @@
return 1;
}
-int ssl_add_message_cbb(SSL *ssl, CBB *cbb) {
- uint8_t *msg;
- size_t len;
- if (!ssl->method->finish_message(ssl, cbb, &msg, &len) ||
- !ssl->method->add_message(ssl, msg, len)) {
- return 0;
- }
-
- return 1;
-}
-
int ssl3_flush_flight(SSL *ssl) {
if (ssl->s3->pending_flight == NULL) {
return 1;
@@ -396,7 +318,7 @@
if (finished_len > sizeof(ssl->s3->previous_client_finished) ||
finished_len > sizeof(ssl->s3->previous_server_finished)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
+ return 0;
}
if (ssl->server) {
@@ -414,65 +336,12 @@
!CBB_add_bytes(&body, finished, finished_len) ||
!ssl_add_message_cbb(ssl, cbb.get())) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
+ return 0;
}
return 1;
}
-int ssl3_get_finished(SSL_HANDSHAKE *hs) {
- SSL *const ssl = hs->ssl;
- SSLMessage msg;
- int ret = ssl_read_message(ssl, &msg);
- if (ret <= 0) {
- return ret;
- }
-
- if (!ssl_check_message_type(ssl, msg, SSL3_MT_FINISHED)) {
- return -1;
- }
-
- /* Snapshot the finished hash before incorporating the new message. */
- uint8_t finished[EVP_MAX_MD_SIZE];
- size_t finished_len;
- if (!hs->transcript.GetFinishedMAC(finished, &finished_len,
- SSL_get_session(ssl), !ssl->server,
- ssl3_protocol_version(ssl)) ||
- !ssl_hash_message(hs, msg)) {
- return -1;
- }
-
- int finished_ok = CBS_mem_equal(&msg.body, finished, finished_len);
-#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
- finished_ok = 1;
-#endif
- if (!finished_ok) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
- OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED);
- return -1;
- }
-
- /* Copy the Finished so we can use it for renegotiation checks. */
- if (ssl->version != SSL3_VERSION) {
- if (finished_len > sizeof(ssl->s3->previous_client_finished) ||
- finished_len > sizeof(ssl->s3->previous_server_finished)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
- }
-
- if (ssl->server) {
- OPENSSL_memcpy(ssl->s3->previous_client_finished, finished, finished_len);
- ssl->s3->previous_client_finished_len = finished_len;
- } else {
- OPENSSL_memcpy(ssl->s3->previous_server_finished, finished, finished_len);
- ssl->s3->previous_server_finished_len = finished_len;
- }
- }
-
- ssl->method->next_message(ssl);
- return 1;
-}
-
int ssl3_output_cert_chain(SSL *ssl) {
ScopedCBB cbb;
CBB body;
@@ -486,46 +355,6 @@
return 1;
}
-size_t ssl_max_handshake_message_len(const SSL *ssl) {
- /* kMaxMessageLen is the default maximum message size for handshakes which do
- * not accept peer certificate chains. */
- static const size_t kMaxMessageLen = 16384;
-
- if (SSL_in_init(ssl)) {
- if ((!ssl->server || (ssl->verify_mode & SSL_VERIFY_PEER)) &&
- kMaxMessageLen < ssl->max_cert_list) {
- return ssl->max_cert_list;
- }
- return kMaxMessageLen;
- }
-
- if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
- /* In TLS 1.2 and below, the largest acceptable post-handshake message is
- * a HelloRequest. */
- return 0;
- }
-
- if (ssl->server) {
- /* The largest acceptable post-handshake message for a server is a
- * KeyUpdate. We will never initiate post-handshake auth. */
- return 1;
- }
-
- /* Clients must accept NewSessionTicket and CertificateRequest, so allow the
- * default size. */
- return kMaxMessageLen;
-}
-
-int ssl_read_message(SSL *ssl, SSLMessage *out) {
- while (!ssl->method->get_message(ssl, out)) {
- int ret = ssl->method->read_message(ssl);
- if (ret <= 0) {
- return ret;
- }
- }
- return 1;
-}
-
static int extend_handshake_buffer(SSL *ssl, size_t length) {
if (!BUF_MEM_reserve(ssl->init_buf, length)) {
return -1;
@@ -769,15 +598,6 @@
return extend_handshake_buffer(ssl, bytes_needed);
}
-bool ssl_hash_message(SSL_HANDSHAKE *hs, const SSLMessage &msg) {
- /* V2ClientHello messages are pre-hashed. */
- if (msg.is_v2_hello) {
- return true;
- }
-
- return hs->transcript.Update(CBS_data(&msg.raw), CBS_len(&msg.raw));
-}
-
void ssl3_next_message(SSL *ssl) {
SSLMessage msg;
if (!ssl3_get_message(ssl, &msg) ||
@@ -801,154 +621,4 @@
}
}
-int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert,
- const SSL_EXTENSION_TYPE *ext_types,
- size_t num_ext_types, int ignore_unknown) {
- /* Reset everything. */
- for (size_t i = 0; i < num_ext_types; i++) {
- *ext_types[i].out_present = 0;
- CBS_init(ext_types[i].out_data, NULL, 0);
- }
-
- CBS copy = *cbs;
- while (CBS_len(©) != 0) {
- uint16_t type;
- CBS data;
- if (!CBS_get_u16(©, &type) ||
- !CBS_get_u16_length_prefixed(©, &data)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
-
- const SSL_EXTENSION_TYPE *ext_type = NULL;
- for (size_t i = 0; i < num_ext_types; i++) {
- if (type == ext_types[i].type) {
- ext_type = &ext_types[i];
- break;
- }
- }
-
- if (ext_type == NULL) {
- if (ignore_unknown) {
- continue;
- }
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
- *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
- return 0;
- }
-
- /* Duplicate ext_types are forbidden. */
- if (*ext_type->out_present) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
- *out_alert = SSL_AD_ILLEGAL_PARAMETER;
- return 0;
- }
-
- *ext_type->out_present = 1;
- *ext_type->out_data = data;
- }
-
- return 1;
-}
-
-static void set_crypto_buffer(CRYPTO_BUFFER **dest, CRYPTO_BUFFER *src) {
- /* TODO(davidben): Remove this helper once |SSL_SESSION| can use |UniquePtr|
- * and |UniquePtr| has up_ref helpers. */
- CRYPTO_BUFFER_free(*dest);
- *dest = src;
- if (src != nullptr) {
- CRYPTO_BUFFER_up_ref(src);
- }
-}
-
-enum ssl_verify_result_t ssl_verify_peer_cert(SSL_HANDSHAKE *hs) {
- SSL *const ssl = hs->ssl;
- const SSL_SESSION *prev_session = ssl->s3->established_session;
- if (prev_session != NULL) {
- /* If renegotiating, the server must not change the server certificate. See
- * https://mitls.org/pages/attacks/3SHAKE. We never resume on renegotiation,
- * so this check is sufficient to ensure the reported peer certificate never
- * changes on renegotiation. */
- assert(!ssl->server);
- if (sk_CRYPTO_BUFFER_num(prev_session->certs) !=
- sk_CRYPTO_BUFFER_num(hs->new_session->certs)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_SERVER_CERT_CHANGED);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return ssl_verify_invalid;
- }
-
- for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(hs->new_session->certs); i++) {
- const CRYPTO_BUFFER *old_cert =
- sk_CRYPTO_BUFFER_value(prev_session->certs, i);
- const CRYPTO_BUFFER *new_cert =
- sk_CRYPTO_BUFFER_value(hs->new_session->certs, i);
- if (CRYPTO_BUFFER_len(old_cert) != CRYPTO_BUFFER_len(new_cert) ||
- OPENSSL_memcmp(CRYPTO_BUFFER_data(old_cert),
- CRYPTO_BUFFER_data(new_cert),
- CRYPTO_BUFFER_len(old_cert)) != 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_SERVER_CERT_CHANGED);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return ssl_verify_invalid;
- }
- }
-
- /* The certificate is identical, so we may skip re-verifying the
- * certificate. Since we only authenticated the previous one, copy other
- * authentication from the established session and ignore what was newly
- * received. */
- set_crypto_buffer(&hs->new_session->ocsp_response,
- prev_session->ocsp_response);
- set_crypto_buffer(&hs->new_session->signed_cert_timestamp_list,
- prev_session->signed_cert_timestamp_list);
- hs->new_session->verify_result = prev_session->verify_result;
- return ssl_verify_ok;
- }
-
- uint8_t alert = SSL_AD_CERTIFICATE_UNKNOWN;
- enum ssl_verify_result_t ret;
- if (ssl->custom_verify_callback != nullptr) {
- ret = ssl->custom_verify_callback(ssl, &alert);
- switch (ret) {
- case ssl_verify_ok:
- hs->new_session->verify_result = X509_V_OK;
- break;
- case ssl_verify_invalid:
- hs->new_session->verify_result = X509_V_ERR_APPLICATION_VERIFICATION;
- break;
- case ssl_verify_retry:
- break;
- }
- } else {
- ret = ssl->ctx->x509_method->session_verify_cert_chain(
- hs->new_session.get(), ssl, &alert)
- ? ssl_verify_ok
- : ssl_verify_invalid;
- }
-
- if (ret == ssl_verify_invalid) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
- }
-
- return ret;
-}
-
-uint16_t ssl_get_grease_value(const SSL *ssl, enum ssl_grease_index_t index) {
- /* Use the client_random or server_random for entropy. This both avoids
- * calling |RAND_bytes| on a single byte repeatedly and ensures the values are
- * deterministic. This allows the same ClientHello be sent twice for a
- * HelloRetryRequest or the same group be advertised in both supported_groups
- * and key_shares. */
- uint16_t ret = ssl->server ? ssl->s3->server_random[index]
- : ssl->s3->client_random[index];
- /* The first four bytes of server_random are a timestamp prior to TLS 1.3, but
- * servers have no fields to GREASE until TLS 1.3. */
- assert(!ssl->server || ssl3_protocol_version(ssl) >= TLS1_3_VERSION);
- /* This generates a random value of the form 0xωaωa, for all 0 ≤ ω < 16. */
- ret = (ret & 0xf0) | 0x0a;
- ret |= ret << 8;
- return ret;
-}
-
} // namespace bssl
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index 9ecd7df..6305356 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -729,12 +729,12 @@
void SSL_set_connect_state(SSL *ssl) {
ssl->server = 0;
- ssl->handshake_func = ssl3_connect;
+ ssl->do_handshake = ssl_client_handshake;
}
void SSL_set_accept_state(SSL *ssl) {
ssl->server = 1;
- ssl->handshake_func = ssl3_accept;
+ ssl->do_handshake = ssl_server_handshake;
}
void SSL_set0_rbio(SSL *ssl, BIO *rbio) {
@@ -788,7 +788,7 @@
int SSL_do_handshake(SSL *ssl) {
ssl_reset_error_state(ssl);
- if (ssl->handshake_func == NULL) {
+ if (ssl->do_handshake == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_TYPE_NOT_SET);
return -1;
}
@@ -797,20 +797,19 @@
return 1;
}
- if (ssl->s3->hs == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
- }
-
/* Run the handshake. */
- assert(ssl->s3->hs != NULL);
- int ret = ssl->handshake_func(ssl->s3->hs);
+ SSL_HANDSHAKE *hs = ssl->s3->hs;
+
+ int early_return = 0;
+ int ret = ssl_run_handshake(hs, &early_return);
+ ssl_do_info_callback(
+ ssl, ssl->server ? SSL_CB_ACCEPT_EXIT : SSL_CB_CONNECT_EXIT, ret);
if (ret <= 0) {
return ret;
}
/* Destroy the handshake object if the handshake has completely finished. */
- if (!SSL_in_init(ssl)) {
+ if (!early_return) {
ssl_handshake_free(ssl->s3->hs);
ssl->s3->hs = NULL;
}
@@ -819,7 +818,7 @@
}
int SSL_connect(SSL *ssl) {
- if (ssl->handshake_func == NULL) {
+ if (ssl->do_handshake == NULL) {
/* Not properly initialized yet */
SSL_set_connect_state(ssl);
}
@@ -828,7 +827,7 @@
}
int SSL_accept(SSL *ssl) {
- if (ssl->handshake_func == NULL) {
+ if (ssl->do_handshake == NULL) {
/* Not properly initialized yet */
SSL_set_accept_state(ssl);
}
@@ -902,7 +901,7 @@
static int ssl_read_impl(SSL *ssl, void *buf, int num, int peek) {
ssl_reset_error_state(ssl);
- if (ssl->handshake_func == NULL) {
+ if (ssl->do_handshake == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
return -1;
}
@@ -958,7 +957,7 @@
int SSL_write(SSL *ssl, const void *buf, int num) {
ssl_reset_error_state(ssl);
- if (ssl->handshake_func == NULL) {
+ if (ssl->do_handshake == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
return -1;
}
@@ -991,7 +990,7 @@
int SSL_shutdown(SSL *ssl) {
ssl_reset_error_state(ssl);
- if (ssl->handshake_func == NULL) {
+ if (ssl->do_handshake == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
return -1;
}
@@ -2337,8 +2336,7 @@
}
int SSL_in_init(const SSL *ssl) {
- SSL_HANDSHAKE *hs = ssl->s3->hs;
- return hs != NULL && hs->state != SSL_ST_OK;
+ return ssl->s3->hs != NULL;
}
int SSL_in_false_start(const SSL *ssl) {
diff --git a/ssl/ssl_session.cc b/ssl/ssl_session.cc
index 6bacc80..07329d0 100644
--- a/ssl/ssl_session.cc
+++ b/ssl/ssl_session.cc
@@ -1066,7 +1066,7 @@
/* SSL_set_session may only be called before the handshake has started. */
if (ssl->s3->initial_handshake_complete ||
ssl->s3->hs == NULL ||
- ssl->s3->hs->state != SSL_ST_INIT) {
+ ssl->s3->hs->state != 0) {
abort();
}
diff --git a/ssl/ssl_stat.cc b/ssl/ssl_stat.cc
index 31cce4d..37e0324 100644
--- a/ssl/ssl_stat.cc
+++ b/ssl/ssl_stat.cc
@@ -88,217 +88,17 @@
#include "internal.h"
-static int ssl_state(const SSL *ssl) {
- if (ssl->s3->hs == NULL) {
- assert(ssl->s3->initial_handshake_complete);
- return SSL_ST_OK;
- }
-
- return ssl->s3->hs->state;
-}
-
const char *SSL_state_string_long(const SSL *ssl) {
- switch (ssl_state(ssl)) {
- case SSL_ST_ACCEPT:
- return "before accept initialization";
-
- case SSL_ST_CONNECT:
- return "before connect initialization";
-
- case SSL_ST_OK:
- return "SSL negotiation finished successfully";
-
- case SSL_ST_RENEGOTIATE:
- return "SSL renegotiate ciphers";
-
- /* SSLv3 additions */
- case SSL3_ST_CW_CLNT_HELLO_A:
- return "SSLv3 write client hello A";
-
- case SSL3_ST_CR_SRVR_HELLO_A:
- return "SSLv3 read server hello A";
-
- case SSL3_ST_CR_CERT_A:
- return "SSLv3 read server certificate A";
-
- case SSL3_ST_CR_KEY_EXCH_A:
- return "SSLv3 read server key exchange A";
-
- case SSL3_ST_CR_CERT_REQ_A:
- return "SSLv3 read server certificate request A";
-
- case SSL3_ST_CR_SESSION_TICKET_A:
- return "SSLv3 read server session ticket A";
-
- case SSL3_ST_CR_SRVR_DONE_A:
- return "SSLv3 read server done A";
-
- case SSL3_ST_CW_CERT_A:
- return "SSLv3 write client certificate A";
-
- case SSL3_ST_CW_KEY_EXCH_A:
- return "SSLv3 write client key exchange A";
-
- case SSL3_ST_CW_CERT_VRFY_A:
- return "SSLv3 write certificate verify A";
-
- case SSL3_ST_CW_CHANGE:
- return "SSLv3 write change cipher spec";
-
- case SSL3_ST_CW_FINISHED_A:
- case SSL3_ST_SW_FINISHED_A:
- return "SSLv3 write finished A";
-
- case SSL3_ST_CR_CHANGE:
- case SSL3_ST_SR_CHANGE:
- return "SSLv3 read change cipher spec";
-
- case SSL3_ST_CR_FINISHED_A:
- case SSL3_ST_SR_FINISHED_A:
- return "SSLv3 read finished A";
-
- case SSL3_ST_CW_FLUSH:
- case SSL3_ST_SW_FLUSH:
- return "SSLv3 flush data";
-
- case SSL3_ST_SR_CLNT_HELLO_A:
- return "SSLv3 read client hello A";
-
- case SSL3_ST_SR_CLNT_HELLO_B:
- return "SSLv3 read client hello B";
-
- case SSL3_ST_SR_CLNT_HELLO_C:
- return "SSLv3 read client hello C";
-
- case SSL3_ST_SW_SRVR_HELLO_A:
- return "SSLv3 write server hello A";
-
- case SSL3_ST_SW_CERT_A:
- return "SSLv3 write certificate A";
-
- case SSL3_ST_SW_KEY_EXCH_A:
- return "SSLv3 write key exchange A";
-
- case SSL3_ST_SW_SRVR_DONE_A:
- return "SSLv3 write server done A";
-
- case SSL3_ST_SR_CERT_A:
- return "SSLv3 read client certificate A";
-
- case SSL3_ST_SR_KEY_EXCH_A:
- return "SSLv3 read client key exchange A";
-
- case SSL3_ST_SR_CERT_VRFY_A:
- return "SSLv3 read certificate verify A";
-
- /* DTLS */
- case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
- return "DTLS1 read hello verify request A";
-
- case SSL_ST_TLS13:
- return ssl->server ? tls13_server_handshake_state(ssl->s3->hs)
- : tls13_client_handshake_state(ssl->s3->hs);
-
- default:
- return "unknown state";
+ if (ssl->s3->hs == NULL) {
+ return "SSL negotiation finished successfully";
}
+
+ return ssl->server ? ssl_server_handshake_state(ssl->s3->hs)
+ : ssl_client_handshake_state(ssl->s3->hs);
}
const char *SSL_state_string(const SSL *ssl) {
- switch (ssl_state(ssl)) {
- case SSL_ST_ACCEPT:
- return "AINIT ";
-
- case SSL_ST_CONNECT:
- return "CINIT ";
-
- case SSL_ST_OK:
- return "SSLOK ";
-
- /* SSLv3 additions */
- case SSL3_ST_SW_FLUSH:
- case SSL3_ST_CW_FLUSH:
- return "3FLUSH";
-
- case SSL3_ST_CW_CLNT_HELLO_A:
- return "3WCH_A";
-
- case SSL3_ST_CR_SRVR_HELLO_A:
- return "3RSH_A";
-
- case SSL3_ST_CR_CERT_A:
- return "3RSC_A";
-
- case SSL3_ST_CR_KEY_EXCH_A:
- return "3RSKEA";
-
- case SSL3_ST_CR_CERT_REQ_A:
- return "3RCR_A";
-
- case SSL3_ST_CR_SRVR_DONE_A:
- return "3RSD_A";
-
- case SSL3_ST_CW_CERT_A:
- return "3WCC_A";
-
- case SSL3_ST_CW_KEY_EXCH_A:
- return "3WCKEA";
-
- case SSL3_ST_CW_CERT_VRFY_A:
- return "3WCV_A";
-
- case SSL3_ST_CW_CHANGE:
- return "3WCCS_";
-
- case SSL3_ST_SW_FINISHED_A:
- case SSL3_ST_CW_FINISHED_A:
- return "3WFINA";
-
- case SSL3_ST_CR_CHANGE:
- case SSL3_ST_SR_CHANGE:
- return "3RCCS_";
-
- case SSL3_ST_SR_FINISHED_A:
- case SSL3_ST_CR_FINISHED_A:
- return "3RFINA";
-
- case SSL3_ST_SR_CLNT_HELLO_A:
- return "3RCH_A";
-
- case SSL3_ST_SR_CLNT_HELLO_B:
- return "3RCH_B";
-
- case SSL3_ST_SR_CLNT_HELLO_C:
- return "3RCH_C";
-
- case SSL3_ST_SW_SRVR_HELLO_A:
- return "3WSH_A";
-
- case SSL3_ST_SW_CERT_A:
- return "3WSC_A";
-
- case SSL3_ST_SW_KEY_EXCH_A:
- return "3WSKEA";
-
- case SSL3_ST_SW_SRVR_DONE_A:
- return "3WSD_A";
-
- case SSL3_ST_SR_CERT_A:
- return "3RCC_A";
-
- case SSL3_ST_SR_KEY_EXCH_A:
- return "3RCKEA";
-
- case SSL3_ST_SR_CERT_VRFY_A:
- return "3RCV_A";
-
- /* DTLS */
- case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
- return "DRCHVA";
-
- default:
- return "UNKWN ";
- }
+ return "!!!!!!";
}
const char *SSL_alert_type_string_long(int value) {
diff --git a/ssl/ssl_x509.cc b/ssl/ssl_x509.cc
index 98a5b8c..7e9e51f 100644
--- a/ssl/ssl_x509.cc
+++ b/ssl/ssl_x509.cc
@@ -1143,9 +1143,9 @@
/* For historical reasons, this function is used both to query configuration
* state on a server as well as handshake state on a client. However, whether
* |ssl| is a client or server is not known until explicitly configured with
- * |SSL_set_connect_state|. If |handshake_func| is NULL, |ssl| is in an
+ * |SSL_set_connect_state|. If |do_handshake| is NULL, |ssl| is in an
* indeterminate mode and |ssl->server| is unset. */
- if (ssl->handshake_func != NULL && !ssl->server) {
+ if (ssl->do_handshake != NULL && !ssl->server) {
if (ssl->s3->hs != NULL) {
return buffer_names_to_x509(ssl->s3->hs->ca_names.get(),
&ssl->s3->hs->cached_x509_ca_names);
diff --git a/ssl/t1_lib.cc b/ssl/t1_lib.cc
index e50710a..7527a98 100644
--- a/ssl/t1_lib.cc
+++ b/ssl/t1_lib.cc
@@ -3483,7 +3483,7 @@
* handshake hashes that we wish to record are for the original, full
* handshake. */
if (ssl->session != NULL) {
- return -1;
+ return 0;
}
static_assert(
@@ -3493,7 +3493,7 @@
size_t digest_len;
if (!hs->transcript.GetHash(hs->new_session->original_handshake_hash,
&digest_len)) {
- return -1;
+ return 0;
}
static_assert(EVP_MAX_MD_SIZE <= 0xff,
diff --git a/ssl/tls13_both.cc b/ssl/tls13_both.cc
index 6e7260e..509079d 100644
--- a/ssl/tls13_both.cc
+++ b/ssl/tls13_both.cc
@@ -37,101 +37,6 @@
* without being able to return application data. */
static const uint8_t kMaxKeyUpdates = 32;
-int tls13_handshake(SSL_HANDSHAKE *hs, int *out_early_return) {
- SSL *const ssl = hs->ssl;
- for (;;) {
- /* Resolve the operation the handshake was waiting on. */
- switch (hs->wait) {
- case ssl_hs_error:
- OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
- return -1;
-
- case ssl_hs_flush: {
- int ret = ssl->method->flush_flight(ssl);
- if (ret <= 0) {
- return ret;
- }
- break;
- }
-
- case ssl_hs_read_message: {
- int ret = ssl->method->read_message(ssl);
- if (ret <= 0) {
- return ret;
- }
- break;
- }
-
- case ssl_hs_read_change_cipher_spec: {
- int ret = ssl->method->read_change_cipher_spec(ssl);
- if (ret <= 0) {
- return ret;
- }
- break;
- }
-
- case ssl_hs_read_end_of_early_data: {
- if (ssl->s3->hs->can_early_read) {
- /* While we are processing early data, the handshake returns early. */
- *out_early_return = 1;
- return 1;
- }
- hs->wait = ssl_hs_ok;
- break;
- }
-
- case ssl_hs_x509_lookup:
- ssl->rwstate = SSL_X509_LOOKUP;
- hs->wait = ssl_hs_ok;
- return -1;
-
- case ssl_hs_channel_id_lookup:
- ssl->rwstate = SSL_CHANNEL_ID_LOOKUP;
- hs->wait = ssl_hs_ok;
- return -1;
-
- case ssl_hs_private_key_operation:
- ssl->rwstate = SSL_PRIVATE_KEY_OPERATION;
- hs->wait = ssl_hs_ok;
- return -1;
-
- case ssl_hs_pending_ticket:
- ssl->rwstate = SSL_PENDING_TICKET;
- hs->wait = ssl_hs_ok;
- return -1;
-
- case ssl_hs_certificate_verify:
- ssl->rwstate = SSL_CERTIFICATE_VERIFY;
- hs->wait = ssl_hs_ok;
- return -1;
-
- case ssl_hs_early_data_rejected:
- ssl->rwstate = SSL_EARLY_DATA_REJECTED;
- /* Cause |SSL_write| to start failing immediately. */
- hs->can_early_write = 0;
- return -1;
-
- case ssl_hs_ok:
- break;
- }
-
- /* Run the state machine again. */
- hs->wait = hs->do_tls13_handshake(hs);
- if (hs->wait == ssl_hs_error) {
- /* Don't loop around to avoid a stray |SSL_R_SSL_HANDSHAKE_FAILURE| the
- * first time around. */
- return -1;
- }
- if (hs->wait == ssl_hs_ok) {
- /* The handshake has completed. */
- return 1;
- }
-
- /* Otherwise, loop to the beginning and resolve what was blocking the
- * handshake. */
- }
-}
-
int tls13_get_cert_verify_signature_input(
SSL_HANDSHAKE *hs, uint8_t **out, size_t *out_len,
enum ssl_cert_verify_context_t cert_verify_context) {
diff --git a/ssl/tls13_client.cc b/ssl/tls13_client.cc
index 6608404..8221368 100644
--- a/ssl/tls13_client.cc
+++ b/ssl/tls13_client.cc
@@ -733,7 +733,7 @@
break;
}
- if (hs->state != state) {
+ if (hs->tls13_state != state) {
ssl_do_info_callback(hs->ssl, SSL_CB_CONNECT_LOOP, 1);
}
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc
index 894fa87..781d59e 100644
--- a/ssl/tls13_server.cc
+++ b/ssl/tls13_server.cc
@@ -922,7 +922,7 @@
break;
}
- if (hs->state != state) {
+ if (hs->tls13_state != state) {
ssl_do_info_callback(hs->ssl, SSL_CB_ACCEPT_LOOP, 1);
}