diff options
author | Bob Beck <beck@cvs.openbsd.org> | 2019-11-26 23:46:19 +0000 |
---|---|---|
committer | Bob Beck <beck@cvs.openbsd.org> | 2019-11-26 23:46:19 +0000 |
commit | bdb313460a13ae266f5e2b907c2a5a19e875c1c1 (patch) | |
tree | 6bbac0b5be599cffd0fc3820cd37441a3bfbac61 /lib | |
parent | de43e991a9bd8ae79d59331adaf837496ac10c9f (diff) |
Add support for TLS 1.3 post handshake messages and key updating.
tested against openssl 1.1's server.
ok jsing@ tb@
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libssl/tls13_internal.h | 19 | ||||
-rw-r--r-- | lib/libssl/tls13_lib.c | 150 | ||||
-rw-r--r-- | lib/libssl/tls13_record_layer.c | 68 |
3 files changed, 217 insertions, 20 deletions
diff --git a/lib/libssl/tls13_internal.h b/lib/libssl/tls13_internal.h index 859030747f4..b33e4818af8 100644 --- a/lib/libssl/tls13_internal.h +++ b/lib/libssl/tls13_internal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tls13_internal.h,v 1.35 2019/11/20 16:21:20 beck Exp $ */ +/* $OpenBSD: tls13_internal.h,v 1.36 2019/11/26 23:46:18 beck Exp $ */ /* * Copyright (c) 2018 Bob Beck <beck@openbsd.org> * Copyright (c) 2018 Theo Buehler <tb@openbsd.org> @@ -38,8 +38,8 @@ __BEGIN_HIDDEN_DECLS #define TLS13_IO_USE_LEGACY -4 typedef void (*tls13_alert_cb)(uint8_t _alert_desc, void *_cb_arg); -typedef int (*tls13_post_handshake_recv_cb)(void *_cb_arg, CBS *cbs); -typedef int (*tls13_post_handshake_sent_cb)(void *_cb_arg); +typedef ssize_t (*tls13_phh_recv_cb)(void *_cb_arg, CBS *cbs); +typedef void (*tls13_phh_sent_cb)(void *_cb_arg); typedef ssize_t (*tls13_read_cb)(void *_buf, size_t _buflen, void *_cb_arg); typedef ssize_t (*tls13_write_cb)(const void *_buf, size_t _buflen, void *_cb_arg); @@ -111,8 +111,8 @@ struct tls13_record_layer; struct tls13_record_layer *tls13_record_layer_new(tls13_read_cb wire_read, tls13_write_cb wire_write, tls13_alert_cb alert_cb, - tls13_post_handshake_recv_cb post_handshake_recv_cb, - tls13_post_handshake_sent_cb post_handshake_sent_cb, void *cb_arg); + tls13_phh_recv_cb phh_recv_cb, + tls13_phh_sent_cb phh_sent_cb, void *cb_arg); void tls13_record_layer_free(struct tls13_record_layer *rl); void tls13_record_layer_set_aead(struct tls13_record_layer *rl, const EVP_AEAD *aead); @@ -172,7 +172,16 @@ struct tls13_ctx { struct tls13_record_layer *rl; struct tls13_handshake_msg *hs_msg; + uint8_t key_update_request; + int phh_count; + time_t phh_last_seen; }; +#ifndef TLS13_PHH_LIMIT_TIME +#define TLS13_PHH_LIMIT_TIME 3600 +#endif +#ifndef TLS13_PHH_LIMIT +#define TLS13_PHH_LIMIT 100 +#endif struct tls13_ctx *tls13_ctx_new(int mode); void tls13_ctx_free(struct tls13_ctx *ctx); diff --git a/lib/libssl/tls13_lib.c b/lib/libssl/tls13_lib.c index 61ca3d46821..6876528f50d 100644 --- a/lib/libssl/tls13_lib.c +++ b/lib/libssl/tls13_lib.c @@ -1,6 +1,7 @@ -/* $OpenBSD: tls13_lib.c,v 1.12 2019/11/17 00:10:47 beck Exp $ */ +/* $OpenBSD: tls13_lib.c,v 1.13 2019/11/26 23:46:18 beck Exp $ */ /* * Copyright (c) 2018, 2019 Joel Sing <jsing@openbsd.org> + * Copyright (c) 2019 Bob Beck <beck@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 @@ -90,6 +91,149 @@ tls13_alert_received_cb(uint8_t alert_desc, void *arg) SSL_CTX_remove_session(s->ctx, s->session); } +static int +tls13_phh_update_local_traffic_secret(struct tls13_ctx *ctx) +{ + struct tls13_secrets *secrets = ctx->hs->secrets; + + if (ctx->mode == TLS13_HS_CLIENT) + return (tls13_update_client_traffic_secret(secrets) && + tls13_record_layer_set_write_traffic_key(ctx->rl, + &secrets->client_application_traffic)); + return (tls13_update_server_traffic_secret(secrets) && + tls13_record_layer_set_read_traffic_key(ctx->rl, + &secrets->server_application_traffic)); +} + +static int +tls13_phh_update_peer_traffic_secret(struct tls13_ctx *ctx) +{ + struct tls13_secrets *secrets = ctx->hs->secrets; + + if (ctx->mode == TLS13_HS_CLIENT) + return (tls13_update_server_traffic_secret(secrets) && + tls13_record_layer_set_read_traffic_key(ctx->rl, + &secrets->server_application_traffic)); + return (tls13_update_client_traffic_secret(secrets) && + tls13_record_layer_set_write_traffic_key(ctx->rl, + &secrets->client_application_traffic)); +} + +/* + * XXX arbitrarily chosen limit of 100 post handshake handshake + * messages in an hour - to avoid a hostile peer from constantly + * requesting certificates or key renegotiaitons, etc. + */ +static int +tls13_phh_limit_check(struct tls13_ctx *ctx) +{ + time_t now = time(NULL); + + if (ctx->phh_last_seen > now - TLS13_PHH_LIMIT_TIME) { + if (ctx->phh_count > TLS13_PHH_LIMIT) + return 0; + } else + ctx->phh_count = 0; + ctx->phh_count++; + ctx->phh_last_seen = now; + return 1; +} + +static ssize_t +tls13_key_update_recv(struct tls13_ctx *ctx, CBS *cbs) +{ + ssize_t ret = TLS13_IO_FAILURE; + + if (!CBS_get_u8(cbs, &ctx->key_update_request)) + goto err; + if (CBS_len(cbs) != 0) + goto err; + + if (!tls13_phh_update_peer_traffic_secret(ctx)) + goto err; + + if (ctx->key_update_request) { + CBB cbb; + CBS cbs; /* XXX */ + + free(ctx->hs_msg); + ctx->hs_msg = tls13_handshake_msg_new(); + if (!tls13_handshake_msg_start(ctx->hs_msg, &cbb, TLS13_MT_KEY_UPDATE)) + goto err; + if (!CBB_add_u8(&cbb, 0)) + goto err; + if (!tls13_handshake_msg_finish(ctx->hs_msg)) + goto err; + tls13_handshake_msg_data(ctx->hs_msg, &cbs); + ret = tls13_record_layer_phh(ctx->rl, &cbs); + + tls13_handshake_msg_free(ctx->hs_msg); + ctx->hs_msg = NULL; + } else + ret = TLS13_IO_SUCCESS; + + return ret; + err: + ctx->key_update_request = 0; + /* XXX alert */ + return TLS13_IO_FAILURE; +} + +static void +tls13_phh_done_cb(void *cb_arg) +{ + struct tls13_ctx *ctx = cb_arg; + + if (ctx->key_update_request) { + tls13_phh_update_local_traffic_secret(ctx); + ctx->key_update_request = 0; + } +} + +static ssize_t +tls13_phh_received_cb(void *cb_arg, CBS *cbs) +{ + ssize_t ret = TLS13_IO_FAILURE; + struct tls13_ctx *ctx = cb_arg; + CBS phh_cbs; + + if (!tls13_phh_limit_check(ctx)) + return tls13_send_alert(ctx->rl, SSL3_AD_UNEXPECTED_MESSAGE); + + if ((ctx->hs_msg == NULL) && + ((ctx->hs_msg = tls13_handshake_msg_new()) == NULL)) + return TLS13_IO_FAILURE; + + if (!tls13_handshake_msg_set_buffer(ctx->hs_msg, cbs)) + return TLS13_IO_FAILURE; + + if ((ret = tls13_handshake_msg_recv(ctx->hs_msg, ctx->rl)) + != TLS13_IO_SUCCESS) + return ret; + + if (!tls13_handshake_msg_content(ctx->hs_msg, &phh_cbs)) + return TLS13_IO_FAILURE; + + switch(tls13_handshake_msg_type(ctx->hs_msg)) { + case TLS13_MT_KEY_UPDATE: + ret = tls13_key_update_recv(ctx, &phh_cbs); + break; + case TLS13_MT_NEW_SESSION_TICKET: + /* XXX do nothing for now and ignore this */ + break; + case TLS13_MT_CERTIFICATE_REQUEST: + /* XXX add support if we choose to advertise this */ + /* FALLTHROUGH */ + default: + ret = TLS13_IO_FAILURE; /* XXX send alert */ + break; + } + + tls13_handshake_msg_free(ctx->hs_msg); + ctx->hs_msg = NULL; + return ret; +} + struct tls13_ctx * tls13_ctx_new(int mode) { @@ -101,8 +245,8 @@ tls13_ctx_new(int mode) ctx->mode = mode; if ((ctx->rl = tls13_record_layer_new(tls13_legacy_wire_read_cb, - tls13_legacy_wire_write_cb, tls13_alert_received_cb, NULL, NULL, - ctx)) == NULL) + tls13_legacy_wire_write_cb, tls13_alert_received_cb, + tls13_phh_received_cb, tls13_phh_done_cb, ctx)) == NULL) goto err; return ctx; diff --git a/lib/libssl/tls13_record_layer.c b/lib/libssl/tls13_record_layer.c index 188f56e0b48..feaca531811 100644 --- a/lib/libssl/tls13_record_layer.c +++ b/lib/libssl/tls13_record_layer.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls13_record_layer.c,v 1.15 2019/11/18 02:44:20 jsing Exp $ */ +/* $OpenBSD: tls13_record_layer.c,v 1.16 2019/11/26 23:46:18 beck Exp $ */ /* * Copyright (c) 2018, 2019 Joel Sing <jsing@openbsd.org> * @@ -30,6 +30,7 @@ static ssize_t tls13_record_layer_write_record(struct tls13_record_layer *rl, struct tls13_record_layer { int change_cipher_spec_seen; int handshake_completed; + int phh; /* * Read and/or write channels are closed due to an alert being @@ -76,8 +77,8 @@ struct tls13_record_layer { /* Record callbacks. */ tls13_alert_cb alert_cb; - tls13_post_handshake_recv_cb post_handshake_recv_cb; - tls13_post_handshake_sent_cb post_handshake_sent_cb; + tls13_phh_recv_cb phh_recv_cb; + tls13_phh_sent_cb phh_sent_cb; /* Wire read/write callbacks. */ tls13_read_cb wire_read; @@ -112,8 +113,8 @@ tls13_record_layer_wrec_free(struct tls13_record_layer *rl) struct tls13_record_layer * tls13_record_layer_new(tls13_read_cb wire_read, tls13_write_cb wire_write, tls13_alert_cb alert_cb, - tls13_post_handshake_recv_cb post_handshake_recv_cb, - tls13_post_handshake_sent_cb post_handshake_sent_cb, + tls13_phh_recv_cb phh_recv_cb, + tls13_phh_sent_cb phh_sent_cb, void *cb_arg) { struct tls13_record_layer *rl; @@ -124,8 +125,8 @@ tls13_record_layer_new(tls13_read_cb wire_read, tls13_write_cb wire_write, rl->wire_read = wire_read; rl->wire_write = wire_write; rl->alert_cb = alert_cb; - rl->post_handshake_recv_cb = post_handshake_recv_cb; - rl->post_handshake_sent_cb = post_handshake_sent_cb; + rl->phh_recv_cb = phh_recv_cb; + rl->phh_sent_cb = phh_sent_cb; rl->cb_arg = cb_arg; return rl; @@ -304,6 +305,8 @@ tls13_record_layer_send_phh(struct tls13_record_layer *rl) CBS_init(&rl->phh_cbs, rl->phh_data, rl->phh_len); + rl->phh_sent_cb(rl->cb_arg); + return TLS13_IO_SUCCESS; } @@ -812,6 +815,16 @@ tls13_record_layer_read(struct tls13_record_layer *rl, uint8_t content_type, /* XXX - need to check record version. */ } + + /* + * If we are in post handshake handshake mode, we may not see + * any record type that isn't a handshake until we are done. + */ + if (rl->phh && rl->rbuf_content_type != SSL3_RT_HANDSHAKE) { + /* XXX send unexpected message alert */ + return TLS13_IO_FAILURE; + } + if (rl->rbuf_content_type != content_type) { /* * Handshake content can appear as post-handshake messages (yup, @@ -821,15 +834,46 @@ tls13_record_layer_read(struct tls13_record_layer *rl, uint8_t content_type, */ if (rl->rbuf_content_type == SSL3_RT_HANDSHAKE) { if (rl->handshake_completed) { - if (rl->post_handshake_recv_cb != NULL) - rl->post_handshake_recv_cb( + rl->phh = 1; + ret = TLS13_IO_FAILURE; + + /* + * The post handshake handshake + * receive callback is allowed to + * return: + * + * TLS13_IO_WANT_POLLIN -> + * I need more handshake data. + * + * TLS13_IO_WANT_POLLOUT -> I got the + * whole handshake message, and have + * enqueued a response + * + * TLS13_IO_SUCCESS -> I got the whole handshake, + * nothing more to do + * + * TLS13_IO_FAILURE -> something broke. + */ + if (rl->phh_recv_cb != NULL) { + ret = rl->phh_recv_cb( rl->cb_arg, &rl->rbuf_cbs); + } + tls13_record_layer_rbuf_free(rl); + + if (ret == TLS13_IO_WANT_POLLIN) + return ret; + /* - * XXX if handshake or alert queued - * return POLLOUT + * leave post handshake handshake mode + * if we do not need more handshake data */ - return TLS13_IO_WANT_POLLIN; + rl->phh = 0; + + if (ret == TLS13_IO_SUCCESS) + return TLS13_IO_WANT_POLLIN; + + return ret; } } |