summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorBob Beck <beck@cvs.openbsd.org>2019-11-26 23:46:19 +0000
committerBob Beck <beck@cvs.openbsd.org>2019-11-26 23:46:19 +0000
commitbdb313460a13ae266f5e2b907c2a5a19e875c1c1 (patch)
tree6bbac0b5be599cffd0fc3820cd37441a3bfbac61 /lib
parentde43e991a9bd8ae79d59331adaf837496ac10c9f (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.h19
-rw-r--r--lib/libssl/tls13_lib.c150
-rw-r--r--lib/libssl/tls13_record_layer.c68
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;
}
}