/* $OpenBSD: tls13_handshake.c,v 1.73 2024/02/03 19:57:14 tb Exp $ */ /* * Copyright (c) 2018-2021 Theo Buehler * Copyright (c) 2019 Joel Sing * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include "ssl_local.h" #include "tls13_handshake.h" #include "tls13_internal.h" /* Based on RFC 8446 and inspired by s2n's TLS 1.2 state machine. */ struct tls13_handshake_action { uint8_t handshake_type; uint8_t sender; uint8_t handshake_complete; uint8_t send_preserve_transcript_hash; uint8_t recv_preserve_transcript_hash; int (*send)(struct tls13_ctx *ctx, CBB *cbb); int (*sent)(struct tls13_ctx *ctx); int (*recv)(struct tls13_ctx *ctx, CBS *cbs); }; static enum tls13_message_type tls13_handshake_active_state(struct tls13_ctx *ctx); static const struct tls13_handshake_action * tls13_handshake_active_action(struct tls13_ctx *ctx); static int tls13_handshake_advance_state_machine(struct tls13_ctx *ctx); static int tls13_handshake_send_action(struct tls13_ctx *ctx, const struct tls13_handshake_action *action); static int tls13_handshake_recv_action(struct tls13_ctx *ctx, const struct tls13_handshake_action *action); static int tls13_handshake_set_legacy_state(struct tls13_ctx *ctx); static int tls13_handshake_legacy_info_callback(struct tls13_ctx *ctx); static const struct tls13_handshake_action state_machine[] = { [CLIENT_HELLO] = { .handshake_type = TLS13_MT_CLIENT_HELLO, .sender = TLS13_HS_CLIENT, .send = tls13_client_hello_send, .sent = tls13_client_hello_sent, .recv = tls13_client_hello_recv, }, [CLIENT_HELLO_RETRY] = { .handshake_type = TLS13_MT_CLIENT_HELLO, .sender = TLS13_HS_CLIENT, .send = tls13_client_hello_retry_send, .recv = tls13_client_hello_retry_recv, }, [CLIENT_END_OF_EARLY_DATA] = { .handshake_type = TLS13_MT_END_OF_EARLY_DATA, .sender = TLS13_HS_CLIENT, .send = tls13_client_end_of_early_data_send, .recv = tls13_client_end_of_early_data_recv, }, [CLIENT_CERTIFICATE] = { .handshake_type = TLS13_MT_CERTIFICATE, .sender = TLS13_HS_CLIENT, .send_preserve_transcript_hash = 1, .send = tls13_client_certificate_send, .recv = tls13_client_certificate_recv, }, [CLIENT_CERTIFICATE_VERIFY] = { .handshake_type = TLS13_MT_CERTIFICATE_VERIFY, .sender = TLS13_HS_CLIENT, .recv_preserve_transcript_hash = 1, .send = tls13_client_certificate_verify_send, .recv = tls13_client_certificate_verify_recv, }, [CLIENT_FINISHED] = { .handshake_type = TLS13_MT_FINISHED, .sender = TLS13_HS_CLIENT, .recv_preserve_transcript_hash = 1, .send = tls13_client_finished_send, .sent = tls13_client_finished_sent, .recv = tls13_client_finished_recv, }, [SERVER_HELLO] = { .handshake_type = TLS13_MT_SERVER_HELLO, .sender = TLS13_HS_SERVER, .send = tls13_server_hello_send, .sent = tls13_server_hello_sent, .recv = tls13_server_hello_recv, }, [SERVER_HELLO_RETRY_REQUEST] = { .handshake_type = TLS13_MT_SERVER_HELLO, .sender = TLS13_HS_SERVER, .send = tls13_server_hello_retry_request_send, .recv = tls13_server_hello_retry_request_recv, .sent = tls13_server_hello_retry_request_sent, }, [SERVER_ENCRYPTED_EXTENSIONS] = { .handshake_type = TLS13_MT_ENCRYPTED_EXTENSIONS, .sender = TLS13_HS_SERVER, .send = tls13_server_encrypted_extensions_send, .recv = tls13_server_encrypted_extensions_recv, }, [SERVER_CERTIFICATE] = { .handshake_type = TLS13_MT_CERTIFICATE, .sender = TLS13_HS_SERVER, .send_preserve_transcript_hash = 1, .send = tls13_server_certificate_send, .recv = tls13_server_certificate_recv, }, [SERVER_CERTIFICATE_REQUEST] = { .handshake_type = TLS13_MT_CERTIFICATE_REQUEST, .sender = TLS13_HS_SERVER, .send = tls13_server_certificate_request_send, .recv = tls13_server_certificate_request_recv, }, [SERVER_CERTIFICATE_VERIFY] = { .handshake_type = TLS13_MT_CERTIFICATE_VERIFY, .sender = TLS13_HS_SERVER, .recv_preserve_transcript_hash = 1, .send = tls13_server_certificate_verify_send, .recv = tls13_server_certificate_verify_recv, }, [SERVER_FINISHED] = { .handshake_type = TLS13_MT_FINISHED, .sender = TLS13_HS_SERVER, .recv_preserve_transcript_hash = 1, .send_preserve_transcript_hash = 1, .send = tls13_server_finished_send, .sent = tls13_server_finished_sent, .recv = tls13_server_finished_recv, }, [APPLICATION_DATA] = { .handshake_complete = 1, }, }; const enum tls13_message_type handshakes[][TLS13_NUM_MESSAGE_TYPES] = { [INITIAL] = { CLIENT_HELLO, SERVER_HELLO_RETRY_REQUEST, CLIENT_HELLO_RETRY, SERVER_HELLO, }, [NEGOTIATED] = { CLIENT_HELLO, SERVER_HELLO_RETRY_REQUEST, CLIENT_HELLO_RETRY, SERVER_HELLO, SERVER_ENCRYPTED_EXTENSIONS, SERVER_CERTIFICATE_REQUEST, SERVER_CERTIFICATE, SERVER_CERTIFICATE_VERIFY, SERVER_FINISHED, CLIENT_CERTIFICATE, CLIENT_FINISHED, APPLICATION_DATA, }, [NEGOTIATED | WITHOUT_HRR] = { CLIENT_HELLO, SERVER_HELLO, SERVER_ENCRYPTED_EXTENSIONS, SERVER_CERTIFICATE_REQUEST, SERVER_CERTIFICATE, SERVER_CERTIFICATE_VERIFY, SERVER_FINISHED, CLIENT_CERTIFICATE, CLIENT_FINISHED, APPLICATION_DATA, }, [NEGOTIATED | WITHOUT_CR] = { CLIENT_HELLO, SERVER_HELLO_RETRY_REQUEST, CLIENT_HELLO_RETRY, SERVER_HELLO, SERVER_ENCRYPTED_EXTENSIONS, SERVER_CERTIFICATE, SERVER_CERTIFICATE_VERIFY, SERVER_FINISHED, CLIENT_FINISHED, APPLICATION_DATA, }, [NEGOTIATED | WITHOUT_HRR | WITHOUT_CR] = { CLIENT_HELLO, SERVER_HELLO, SERVER_ENCRYPTED_EXTENSIONS, SERVER_CERTIFICATE, SERVER_CERTIFICATE_VERIFY, SERVER_FINISHED, CLIENT_FINISHED, APPLICATION_DATA, }, [NEGOTIATED | WITH_PSK] = { CLIENT_HELLO, SERVER_HELLO_RETRY_REQUEST, CLIENT_HELLO_RETRY, SERVER_HELLO, SERVER_ENCRYPTED_EXTENSIONS, SERVER_FINISHED, CLIENT_FINISHED, APPLICATION_DATA, }, [NEGOTIATED | WITHOUT_HRR | WITH_PSK] = { CLIENT_HELLO, SERVER_HELLO, SERVER_ENCRYPTED_EXTENSIONS, SERVER_FINISHED, CLIENT_FINISHED, APPLICATION_DATA, }, [NEGOTIATED | WITH_CCV] = { CLIENT_HELLO, SERVER_HELLO_RETRY_REQUEST, CLIENT_HELLO_RETRY, SERVER_HELLO, SERVER_ENCRYPTED_EXTENSIONS, SERVER_CERTIFICATE_REQUEST, SERVER_CERTIFICATE, SERVER_CERTIFICATE_VERIFY, SERVER_FINISHED, CLIENT_CERTIFICATE, CLIENT_CERTIFICATE_VERIFY, CLIENT_FINISHED, APPLICATION_DATA, }, [NEGOTIATED | WITHOUT_HRR | WITH_CCV] = { CLIENT_HELLO, SERVER_HELLO, SERVER_ENCRYPTED_EXTENSIONS, SERVER_CERTIFICATE_REQUEST, SERVER_CERTIFICATE, SERVER_CERTIFICATE_VERIFY, SERVER_FINISHED, CLIENT_CERTIFICATE, CLIENT_CERTIFICATE_VERIFY, CLIENT_FINISHED, APPLICATION_DATA, }, }; const size_t handshake_count = sizeof(handshakes) / sizeof(handshakes[0]); #ifndef TLS13_DEBUG #define DEBUGF(...) #else #define DEBUGF(...) fprintf(stderr, __VA_ARGS__) static const char * tls13_handshake_mode_name(uint8_t mode) { switch (mode) { case TLS13_HS_CLIENT: return "Client"; case TLS13_HS_SERVER: return "Server"; } return "Unknown"; } static const char * tls13_handshake_message_name(uint8_t msg_type) { switch (msg_type) { case TLS13_MT_CLIENT_HELLO: return "ClientHello"; case TLS13_MT_SERVER_HELLO: return "ServerHello"; case TLS13_MT_NEW_SESSION_TICKET: return "NewSessionTicket"; case TLS13_MT_END_OF_EARLY_DATA: return "EndOfEarlyData"; case TLS13_MT_ENCRYPTED_EXTENSIONS: return "EncryptedExtensions"; case TLS13_MT_CERTIFICATE: return "Certificate"; case TLS13_MT_CERTIFICATE_REQUEST: return "CertificateRequest"; case TLS13_MT_CERTIFICATE_VERIFY: return "CertificateVerify"; case TLS13_MT_FINISHED: return "Finished"; } return "Unknown"; } #endif static enum tls13_message_type tls13_handshake_active_state(struct tls13_ctx *ctx) { struct tls13_handshake_stage hs = ctx->handshake_stage; if (hs.hs_type >= handshake_count) return INVALID; if (hs.message_number >= TLS13_NUM_MESSAGE_TYPES) return INVALID; return handshakes[hs.hs_type][hs.message_number]; } static const struct tls13_handshake_action * tls13_handshake_active_action(struct tls13_ctx *ctx) { enum tls13_message_type mt = tls13_handshake_active_state(ctx); if (mt == INVALID) return NULL; return &state_machine[mt]; } static int tls13_handshake_advance_state_machine(struct tls13_ctx *ctx) { if (++ctx->handshake_stage.message_number >= TLS13_NUM_MESSAGE_TYPES) return 0; return 1; } static int tls13_handshake_end_of_flight(struct tls13_ctx *ctx, const struct tls13_handshake_action *previous) { const struct tls13_handshake_action *current; if ((current = tls13_handshake_active_action(ctx)) == NULL) return 1; return current->sender != previous->sender; } int tls13_handshake_msg_record(struct tls13_ctx *ctx) { CBS cbs; tls13_handshake_msg_data(ctx->hs_msg, &cbs); return tls1_transcript_record(ctx->ssl, CBS_data(&cbs), CBS_len(&cbs)); } int tls13_handshake_perform(struct tls13_ctx *ctx) { const struct tls13_handshake_action *action; int sending; int ret; if (!ctx->handshake_started) { /* * Set legacy state to connect/accept and call info callback * to signal that the handshake started. */ if (!tls13_handshake_set_legacy_state(ctx)) return TLS13_IO_FAILURE; if (!tls13_handshake_legacy_info_callback(ctx)) return TLS13_IO_FAILURE; ctx->handshake_started = 1; /* Set legacy state for initial ClientHello read or write. */ if (!tls13_handshake_set_legacy_state(ctx)) return TLS13_IO_FAILURE; } for (;;) { if ((action = tls13_handshake_active_action(ctx)) == NULL) return TLS13_IO_FAILURE; if (ctx->need_flush) { if ((ret = tls13_record_layer_flush(ctx->rl)) != TLS13_IO_SUCCESS) return ret; ctx->need_flush = 0; } if (action->handshake_complete) { ctx->handshake_completed = 1; tls13_record_layer_handshake_completed(ctx->rl); if (!tls13_handshake_set_legacy_state(ctx)) return TLS13_IO_FAILURE; if (!tls13_handshake_legacy_info_callback(ctx)) return TLS13_IO_FAILURE; return TLS13_IO_SUCCESS; } sending = action->sender == ctx->mode; DEBUGF("%s %s %s\n", tls13_handshake_mode_name(ctx->mode), sending ? "sending" : "receiving", tls13_handshake_message_name(action->handshake_type)); if (ctx->alert != 0) return tls13_send_alert(ctx->rl, ctx->alert); if (sending) ret = tls13_handshake_send_action(ctx, action); else ret = tls13_handshake_recv_action(ctx, action); if (ctx->alert != 0) return tls13_send_alert(ctx->rl, ctx->alert); if (ret <= 0) { DEBUGF("%s %s returned %d\n", tls13_handshake_mode_name(ctx->mode), (action->sender == ctx->mode) ? "send" : "recv", ret); return ret; } if (!tls13_handshake_legacy_info_callback(ctx)) return TLS13_IO_FAILURE; if (!tls13_handshake_advance_state_machine(ctx)) return TLS13_IO_FAILURE; if (sending) ctx->need_flush = tls13_handshake_end_of_flight(ctx, action); if (!tls13_handshake_set_legacy_state(ctx)) return TLS13_IO_FAILURE; } } static int tls13_handshake_send_action(struct tls13_ctx *ctx, const struct tls13_handshake_action *action) { ssize_t ret; CBB cbb; if (ctx->send_dummy_ccs) { if ((ret = tls13_send_dummy_ccs(ctx->rl)) != TLS13_IO_SUCCESS) return ret; ctx->send_dummy_ccs = 0; if (ctx->send_dummy_ccs_after) { ctx->send_dummy_ccs_after = 0; return TLS13_IO_SUCCESS; } } /* If we have no handshake message, we need to build one. */ if (ctx->hs_msg == NULL) { if ((ctx->hs_msg = tls13_handshake_msg_new()) == NULL) return TLS13_IO_FAILURE; if (!tls13_handshake_msg_start(ctx->hs_msg, &cbb, action->handshake_type)) return TLS13_IO_FAILURE; if (!action->send(ctx, &cbb)) return TLS13_IO_FAILURE; if (!tls13_handshake_msg_finish(ctx->hs_msg)) return TLS13_IO_FAILURE; } if ((ret = tls13_handshake_msg_send(ctx->hs_msg, ctx->rl)) <= 0) return ret; if (!tls13_handshake_msg_record(ctx)) return TLS13_IO_FAILURE; if (action->send_preserve_transcript_hash) { if (!tls1_transcript_hash_value(ctx->ssl, ctx->hs->tls13.transcript_hash, sizeof(ctx->hs->tls13.transcript_hash), &ctx->hs->tls13.transcript_hash_len)) return TLS13_IO_FAILURE; } if (ctx->handshake_message_sent_cb != NULL) ctx->handshake_message_sent_cb(ctx); tls13_handshake_msg_free(ctx->hs_msg); ctx->hs_msg = NULL; if (action->sent != NULL && !action->sent(ctx)) return TLS13_IO_FAILURE; if (ctx->send_dummy_ccs_after) { ctx->send_dummy_ccs = 1; if ((ret = tls13_send_dummy_ccs(ctx->rl)) != TLS13_IO_SUCCESS) return ret; ctx->send_dummy_ccs = 0; ctx->send_dummy_ccs_after = 0; } return TLS13_IO_SUCCESS; } static int tls13_handshake_recv_action(struct tls13_ctx *ctx, const struct tls13_handshake_action *action) { uint8_t msg_type; ssize_t ret; CBS cbs; if (ctx->hs_msg == NULL) { if ((ctx->hs_msg = tls13_handshake_msg_new()) == NULL) return TLS13_IO_FAILURE; } if ((ret = tls13_handshake_msg_recv(ctx->hs_msg, ctx->rl)) <= 0) return ret; if (action->recv_preserve_transcript_hash) { if (!tls1_transcript_hash_value(ctx->ssl, ctx->hs->tls13.transcript_hash, sizeof(ctx->hs->tls13.transcript_hash), &ctx->hs->tls13.transcript_hash_len)) return TLS13_IO_FAILURE; } if (!tls13_handshake_msg_record(ctx)) return TLS13_IO_FAILURE; if (ctx->handshake_message_recv_cb != NULL) ctx->handshake_message_recv_cb(ctx); /* * In TLSv1.3 there is no way to know if you're going to receive a * certificate request message or not, hence we have to special case it * here. The receive handler also knows how to deal with this situation. */ msg_type = tls13_handshake_msg_type(ctx->hs_msg); if (msg_type != action->handshake_type && (msg_type != TLS13_MT_CERTIFICATE || action->handshake_type != TLS13_MT_CERTIFICATE_REQUEST)) return tls13_send_alert(ctx->rl, TLS13_ALERT_UNEXPECTED_MESSAGE); if (!tls13_handshake_msg_content(ctx->hs_msg, &cbs)) return TLS13_IO_FAILURE; ret = TLS13_IO_FAILURE; if (!action->recv(ctx, &cbs)) goto err; if (CBS_len(&cbs) != 0) { tls13_set_errorx(ctx, TLS13_ERR_TRAILING_DATA, 0, "trailing data in handshake message", NULL); ctx->alert = TLS13_ALERT_DECODE_ERROR; goto err; } ret = TLS13_IO_SUCCESS; if (ctx->ssl->method->version < TLS1_3_VERSION) ret = TLS13_IO_USE_LEGACY; err: tls13_handshake_msg_free(ctx->hs_msg); ctx->hs_msg = NULL; return ret; } struct tls13_handshake_legacy_state { int recv; int send; }; static const struct tls13_handshake_legacy_state legacy_states[] = { [CLIENT_HELLO] = { .recv = SSL3_ST_SR_CLNT_HELLO_A, .send = SSL3_ST_CW_CLNT_HELLO_A, }, [SERVER_HELLO_RETRY_REQUEST] = { .recv = SSL3_ST_CR_SRVR_HELLO_A, .send = SSL3_ST_SW_SRVR_HELLO_A, }, [CLIENT_HELLO_RETRY] = { .recv = SSL3_ST_SR_CLNT_HELLO_A, .send = SSL3_ST_CW_CLNT_HELLO_A, }, [SERVER_HELLO] = { .recv = SSL3_ST_CR_SRVR_HELLO_A, .send = SSL3_ST_SW_SRVR_HELLO_A, }, [SERVER_ENCRYPTED_EXTENSIONS] = { .send = 0, .recv = 0, }, [SERVER_CERTIFICATE_REQUEST] = { .recv = SSL3_ST_CR_CERT_REQ_A, .send = SSL3_ST_SW_CERT_REQ_A, }, [SERVER_CERTIFICATE] = { .recv = SSL3_ST_CR_CERT_A, .send = SSL3_ST_SW_CERT_A, }, [SERVER_CERTIFICATE_VERIFY] = { .send = 0, .recv = 0, }, [SERVER_FINISHED] = { .recv = SSL3_ST_CR_FINISHED_A, .send = SSL3_ST_SW_FINISHED_A, }, [CLIENT_END_OF_EARLY_DATA] = { .send = 0, .recv = 0, }, [CLIENT_CERTIFICATE] = { .recv = SSL3_ST_SR_CERT_VRFY_A, .send = SSL3_ST_CW_CERT_VRFY_B, }, [CLIENT_CERTIFICATE_VERIFY] = { .send = 0, .recv = 0, }, [CLIENT_FINISHED] = { .recv = SSL3_ST_SR_FINISHED_A, .send = SSL3_ST_CW_FINISHED_A, }, [APPLICATION_DATA] = { .recv = 0, .send = 0, }, }; CTASSERT(sizeof(state_machine) / sizeof(state_machine[0]) == sizeof(legacy_states) / sizeof(legacy_states[0])); static int tls13_handshake_legacy_state(struct tls13_ctx *ctx, int *out_state) { const struct tls13_handshake_action *action; enum tls13_message_type mt; *out_state = 0; if (!ctx->handshake_started) { if (ctx->mode == TLS13_HS_CLIENT) *out_state = SSL_ST_CONNECT; else *out_state = SSL_ST_ACCEPT; return 1; } if (ctx->handshake_completed) { *out_state = SSL_ST_OK; return 1; } if ((mt = tls13_handshake_active_state(ctx)) == INVALID) return 0; if ((action = tls13_handshake_active_action(ctx)) == NULL) return 0; if (action->sender == ctx->mode) *out_state = legacy_states[mt].send; else *out_state = legacy_states[mt].recv; return 1; } static int tls13_handshake_info_position(struct tls13_ctx *ctx) { if (!ctx->handshake_started) return TLS13_INFO_HANDSHAKE_STARTED; if (ctx->handshake_completed) return TLS13_INFO_HANDSHAKE_COMPLETED; if (ctx->mode == TLS13_HS_CLIENT) return TLS13_INFO_CONNECT_LOOP; else return TLS13_INFO_ACCEPT_LOOP; } static int tls13_handshake_legacy_info_callback(struct tls13_ctx *ctx) { int state, where; if (!tls13_handshake_legacy_state(ctx, &state)) return 0; /* Do nothing if there's no corresponding legacy state. */ if (state == 0) return 1; if (ctx->info_cb != NULL) { where = tls13_handshake_info_position(ctx); ctx->info_cb(ctx, where, 1); } return 1; } static int tls13_handshake_set_legacy_state(struct tls13_ctx *ctx) { int state; if (!tls13_handshake_legacy_state(ctx, &state)) return 0; /* Do nothing if there's no corresponding legacy state. */ if (state == 0) return 1; ctx->hs->state = state; return 1; }