Edit

IABSD.fr/src/lib/libssl/tls13_handshake.c

Branch :

  • Show log

    Commit

  • Author : tb
    Date : 2020-07-30 16:23:17
    Hash : 08d6ed5e
    Message : Add minimal info callback support for TLSv1.3 As abieber@ found the hard way, some python frameworks (twisted, synapse) thought it a great idea to use the info callback mechanism (designed to get state information about SSL objects) to modify state information such as setting and verifying the SNI. The switch of TLS_method() to default to TLSv1.3 broke these contraptions. Further bits of the info callback mechanism will likely metastasize throughout the TLSv1.3 stack if we need them, so we only do what's really necessary now. Lots of debugging, crucial hint and testing by abieber input & ok jsing

  • lib/libssl/tls13_handshake.c
  • /*	$OpenBSD: tls13_handshake.c,v 1.64 2020/07/30 16:23:17 tb Exp $	*/
    /*
     * Copyright (c) 2018-2019 Theo Buehler <tb@openbsd.org>
     * Copyright (c) 2019 Joel Sing <jsing@openbsd.org>
     *
     * 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 <stddef.h>
    
    #include "ssl_locl.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 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";
    	case TLS13_MT_KEY_UPDATE:
    		return "KeyUpdate";
    	}
    	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;
    }
    
    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 ret;
    
    	if (!ctx->handshake_started) {
    		ctx->handshake_started = 1;
    		if (ctx->info_cb != NULL)
    			ctx->info_cb(ctx, TLS13_INFO_HANDSHAKE_STARTED, 1);
    	}
    
    	for (;;) {
    		if ((action = tls13_handshake_active_action(ctx)) == NULL)
    			return TLS13_IO_FAILURE;
    
    		if (action->handshake_complete) {
    			ctx->handshake_completed = 1;
    			tls13_record_layer_handshake_completed(ctx->rl);
    			if (ctx->info_cb != NULL)
    				ctx->info_cb(ctx,
    				    TLS13_INFO_HANDSHAKE_COMPLETED, 1);
    			return TLS13_IO_SUCCESS;
    		}
    
    		DEBUGF("%s %s %s\n", tls13_handshake_mode_name(ctx->mode),
    		    (action->sender == ctx->mode) ? "sending" : "receiving",
    		    tls13_handshake_message_name(action->handshake_type));
    
    		if (ctx->alert)
    			return tls13_send_alert(ctx->rl, ctx->alert);
    
    		if (action->sender == ctx->mode)
    			ret = tls13_handshake_send_action(ctx, action);
    		else
    			ret = tls13_handshake_recv_action(ctx, action);
    
    		if (ctx->alert)
    			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_advance_state_machine(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->transcript_hash, sizeof(ctx->hs->transcript_hash),
    		    &ctx->hs->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->transcript_hash, sizeof(ctx->hs->transcript_hash),
    		    &ctx->hs->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)) {
    		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;
    		} else {
    			ret = TLS13_IO_SUCCESS;
    		}
    	}
    
    	tls13_handshake_msg_free(ctx->hs_msg);
    	ctx->hs_msg = NULL;
    
    	if (ctx->ssl->method->internal->version < TLS1_3_VERSION)
    		return TLS13_IO_USE_LEGACY;
    
    	return ret;
    }