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/include/openssl/ssl.h b/include/openssl/ssl.h index 4463c8d..269bc8b 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h
@@ -3303,7 +3303,6 @@ #define SSL_ST_INIT (SSL_ST_CONNECT | SSL_ST_ACCEPT) #define SSL_ST_OK 0x03 #define SSL_ST_RENEGOTIATE (0x04 | SSL_ST_INIT) -#define SSL_ST_TLS13 (0x05 | SSL_ST_INIT) // SSL_CB_* are possible values for the |type| parameter in the info // callback and the bitmasks that make them up. @@ -3817,6 +3816,10 @@ // instead. OPENSSL_EXPORT const char *SSL_alert_desc_string(int value); +// SSL_state_string returns "!!!!!!". Use |SSL_state_string_long| for a more +// intelligible string. +OPENSSL_EXPORT const char *SSL_state_string(const SSL *ssl); + // SSL_TXT_* expand to strings. #define SSL_TXT_MEDIUM "MEDIUM" #define SSL_TXT_HIGH "HIGH" @@ -3869,11 +3872,6 @@ #define SSL_get_state(ssl) SSL_state(ssl) -// SSL_state_string returns the current state of the handshake state machine as -// a six-letter string. Use |SSL_state_string_long| for a more intelligible -// string. -OPENSSL_EXPORT const char *SSL_state_string(const SSL *ssl); - // SSL_set_shutdown causes |ssl| to behave as if the shutdown bitmask (see // |SSL_get_shutdown|) were |mode|. This may be used to skip sending or // receiving close_notify in |SSL_shutdown| by causing the implementation to
diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h index 60eb7fc..343ea34 100644 --- a/include/openssl/ssl3.h +++ b/include/openssl/ssl3.h
@@ -296,66 +296,6 @@ #define SSL3_CT_RSA_SIGN 1 -// SSLv3 -// client -// extra state -#define SSL3_ST_CW_FLUSH (0x100 | SSL_ST_CONNECT) -#define SSL3_ST_FALSE_START (0x101 | SSL_ST_CONNECT) -#define SSL3_ST_VERIFY_SERVER_CERT (0x102 | SSL_ST_CONNECT) -#define SSL3_ST_FINISH_CLIENT_HANDSHAKE (0x103 | SSL_ST_CONNECT) -#define SSL3_ST_WRITE_EARLY_DATA (0x104 | SSL_ST_CONNECT) -// write to server -#define SSL3_ST_CW_CLNT_HELLO_A (0x110 | SSL_ST_CONNECT) -// read from server -#define SSL3_ST_CR_SRVR_HELLO_A (0x120 | SSL_ST_CONNECT) -#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A (0x126 | SSL_ST_CONNECT) -#define SSL3_ST_CR_CERT_A (0x130 | SSL_ST_CONNECT) -#define SSL3_ST_CR_KEY_EXCH_A (0x140 | SSL_ST_CONNECT) -#define SSL3_ST_CR_CERT_REQ_A (0x150 | SSL_ST_CONNECT) -#define SSL3_ST_CR_SRVR_DONE_A (0x160 | SSL_ST_CONNECT) -// write to server -#define SSL3_ST_CW_CERT_A (0x170 | SSL_ST_CONNECT) -#define SSL3_ST_CW_KEY_EXCH_A (0x180 | SSL_ST_CONNECT) -#define SSL3_ST_CW_CERT_VRFY_A (0x190 | SSL_ST_CONNECT) -#define SSL3_ST_CW_CHANGE (0x1A0 | SSL_ST_CONNECT) -#define SSL3_ST_CW_NEXT_PROTO_A (0x200 | SSL_ST_CONNECT) -#define SSL3_ST_CW_CHANNEL_ID_A (0x220 | SSL_ST_CONNECT) -#define SSL3_ST_CW_FINISHED_A (0x1B0 | SSL_ST_CONNECT) -// read from server -#define SSL3_ST_CR_CHANGE (0x1C0 | SSL_ST_CONNECT) -#define SSL3_ST_CR_FINISHED_A (0x1D0 | SSL_ST_CONNECT) -#define SSL3_ST_CR_SESSION_TICKET_A (0x1E0 | SSL_ST_CONNECT) -#define SSL3_ST_CR_CERT_STATUS_A (0x1F0 | SSL_ST_CONNECT) - -// SSL3_ST_CR_SRVR_HELLO_B is a legacy alias for |SSL3_ST_CR_SRVR_HELLO_A| used -// by some consumers which check |SSL_state|. -#define SSL3_ST_CR_SRVR_HELLO_B SSL3_ST_CR_SRVR_HELLO_A - -// server -// extra state -#define SSL3_ST_SW_FLUSH (0x100 | SSL_ST_ACCEPT) -#define SSL3_ST_VERIFY_CLIENT_CERT (0x101 | SSL_ST_ACCEPT) -// read from client -#define SSL3_ST_SR_CLNT_HELLO_A (0x110 | SSL_ST_ACCEPT) -#define SSL3_ST_SR_CLNT_HELLO_B (0x111 | SSL_ST_ACCEPT) -#define SSL3_ST_SR_CLNT_HELLO_C (0x112 | SSL_ST_ACCEPT) -// write to client -#define SSL3_ST_SW_SRVR_HELLO_A (0x130 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_CERT_A (0x140 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_KEY_EXCH_A (0x150 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_SRVR_DONE_A (0x170 | SSL_ST_ACCEPT) -// read from client -#define SSL3_ST_SR_CERT_A (0x180 | SSL_ST_ACCEPT) -#define SSL3_ST_SR_KEY_EXCH_A (0x190 | SSL_ST_ACCEPT) -#define SSL3_ST_SR_CERT_VRFY_A (0x1A0 | SSL_ST_ACCEPT) -#define SSL3_ST_SR_CHANGE (0x1B0 | SSL_ST_ACCEPT) -#define SSL3_ST_SR_NEXT_PROTO_A (0x210 | SSL_ST_ACCEPT) -#define SSL3_ST_SR_CHANNEL_ID_A (0x230 | SSL_ST_ACCEPT) -#define SSL3_ST_SR_FINISHED_A (0x1C0 | SSL_ST_ACCEPT) - -// write to client -#define SSL3_ST_SW_FINISHED_A (0x1E0 | SSL_ST_ACCEPT) - #define SSL3_MT_HELLO_REQUEST 0 #define SSL3_MT_CLIENT_HELLO 1 #define SSL3_MT_SERVER_HELLO 2
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); }