diff options
author | Joel Sing <jsing@cvs.openbsd.org> | 2019-11-17 17:20:17 +0000 |
---|---|---|
committer | Joel Sing <jsing@cvs.openbsd.org> | 2019-11-17 17:20:17 +0000 |
commit | 1a9ef7e80acbe5dc8e9b18365db17c530ffae2e3 (patch) | |
tree | d0a380921ea74f4ebb9b70354bd10ec8e4d91f49 /lib/libssl | |
parent | 31509ae9391ef32a4bf9fe756ad7ed196670ea2b (diff) |
Provide framework for sending alerts and post-handshake handshake messages.
Discussed at length with beck@
ok beck@ tb@
Diffstat (limited to 'lib/libssl')
-rw-r--r-- | lib/libssl/tls13_internal.h | 6 | ||||
-rw-r--r-- | lib/libssl/tls13_record_layer.c | 183 |
2 files changed, 174 insertions, 15 deletions
diff --git a/lib/libssl/tls13_internal.h b/lib/libssl/tls13_internal.h index 9ab72f4f3a7..05e108952a3 100644 --- a/lib/libssl/tls13_internal.h +++ b/lib/libssl/tls13_internal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tls13_internal.h,v 1.30 2019/11/17 06:35:30 jsing Exp $ */ +/* $OpenBSD: tls13_internal.h,v 1.31 2019/11/17 17:20:16 jsing Exp $ */ /* * Copyright (c) 2018 Bob Beck <beck@openbsd.org> * Copyright (c) 2018 Theo Buehler <tb@openbsd.org> @@ -120,6 +120,10 @@ int tls13_record_layer_set_read_traffic_key(struct tls13_record_layer *rl, struct tls13_secret *read_key); int tls13_record_layer_set_write_traffic_key(struct tls13_record_layer *rl, struct tls13_secret *write_key); +ssize_t tls13_record_layer_alert(struct tls13_record_layer *rl, + uint8_t alert_level, uint8_t alert_desc); +ssize_t tls13_record_layer_phh(struct tls13_record_layer *rl, uint8_t *data, + size_t len); ssize_t tls13_read_handshake_data(struct tls13_record_layer *rl, uint8_t *buf, size_t n); ssize_t tls13_write_handshake_data(struct tls13_record_layer *rl, const uint8_t *buf, diff --git a/lib/libssl/tls13_record_layer.c b/lib/libssl/tls13_record_layer.c index ff26b09d46d..8208ae508c5 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.10 2019/11/17 00:10:47 beck Exp $ */ +/* $OpenBSD: tls13_record_layer.c,v 1.11 2019/11/17 17:20:16 jsing Exp $ */ /* * Copyright (c) 2018, 2019 Joel Sing <jsing@openbsd.org> * @@ -22,6 +22,11 @@ #include "tls13_internal.h" #include "tls13_record.h" +static ssize_t tls13_record_layer_write_chunk(struct tls13_record_layer *rl, + uint8_t content_type, const uint8_t *buf, size_t n); +static ssize_t tls13_record_layer_write_record(struct tls13_record_layer *rl, + uint8_t content_type, const uint8_t *content, size_t content_len); + struct tls13_record_layer { int change_cipher_spec_seen; int handshake_completed; @@ -36,7 +41,20 @@ struct tls13_record_layer { int write_closed; struct tls13_record *rrec; + struct tls13_record *wrec; + uint8_t wrec_content_type; + size_t wrec_appdata_len; + size_t wrec_content_len; + + /* Pending alert messages. */ + uint8_t *alert_data; + size_t alert_len; + + /* Pending post-handshake handshake messages. */ + CBS phh_cbs; + uint8_t *phh_data; + size_t phh_len; /* Buffer containing plaintext from opened records. */ uint8_t rbuf_content_type; @@ -232,7 +250,7 @@ tls13_record_layer_process_alert(struct tls13_record_layer *rl) } else if (alert_level == SSL3_AL_FATAL) { rl->read_closed = 1; rl->write_closed = 1; - ret = TLS13_IO_EOF; + ret = TLS13_IO_FAILURE; /* XXX - ALERT? */ } else { /* XXX - decode error alert. */ return TLS13_IO_FAILURE; @@ -244,12 +262,112 @@ tls13_record_layer_process_alert(struct tls13_record_layer *rl) return ret; } -int -tls13_record_layer_send_alert(struct tls13_record_layer *rl, +static ssize_t +tls13_record_layer_send_alert(struct tls13_record_layer *rl) +{ + ssize_t ret; + + /* This has to fit into a single record, per RFC 8446 section 5.1. */ + if ((ret = tls13_record_layer_write_record(rl, SSL3_RT_ALERT, + rl->alert_data, rl->alert_len)) != rl->alert_len) + return ret; + + freezero(rl->alert_data, rl->alert_len); + rl->alert_data = NULL; + rl->alert_len = 0; + + /* XXX - only close write channel when sending close notify. */ + rl->read_closed = 1; + rl->write_closed = 1; + + /* XXX - we may want a TLS13_IO_ALERT (or handle as errors). */ + return TLS13_IO_FAILURE; +} + +static ssize_t +tls13_record_layer_send_phh(struct tls13_record_layer *rl) +{ + ssize_t ret; + + /* Push out pending post-handshake handshake messages. */ + if ((ret = tls13_record_layer_write_chunk(rl, SSL3_RT_HANDSHAKE, + CBS_data(&rl->phh_cbs), CBS_len(&rl->phh_cbs))) < 0) + return ret; + if (!CBS_skip(&rl->phh_cbs, ret)) + return TLS13_IO_FAILURE; + if (CBS_len(&rl->phh_cbs) != 0) + return TLS13_IO_WANT_POLLOUT; + + freezero(rl->phh_data, rl->phh_len); + rl->phh_data = NULL; + rl->phh_len = 0; + + CBS_init(&rl->phh_cbs, rl->phh_data, rl->phh_len); + + return TLS13_IO_SUCCESS; +} + +static ssize_t +tls13_record_layer_send_pending(struct tls13_record_layer *rl) +{ + /* + * If an alert is pending, then it needs to be sent. However, + * if we're already part of the way through sending post-handshake + * handshake messages, then we need to finish that first... + */ + + if (rl->phh_data != NULL && CBS_len(&rl->phh_cbs) != rl->phh_len) + return tls13_record_layer_send_phh(rl); + + if (rl->alert_data != NULL) + return tls13_record_layer_send_alert(rl); + + if (rl->phh_data != NULL) + return tls13_record_layer_send_phh(rl); + + return TLS13_IO_SUCCESS; +} + +ssize_t +tls13_record_layer_alert(struct tls13_record_layer *rl, uint8_t alert_level, uint8_t alert_desc) { - /* XXX - implement. */ - return -1; + CBB cbb; + + if (rl->alert_data != NULL) + return TLS13_IO_FAILURE; + + if (!CBB_init(&cbb, 0)) + goto err; + + if (!CBB_add_u8(&cbb, alert_level)) + goto err; + if (!CBB_add_u8(&cbb, alert_desc)) + goto err; + if (!CBB_finish(&cbb, &rl->alert_data, &rl->alert_len)) + goto err; + + return tls13_record_layer_send_pending(rl); + + err: + CBB_cleanup(&cbb); + + return TLS13_IO_FAILURE; +} + +ssize_t +tls13_record_layer_phh(struct tls13_record_layer *rl, uint8_t *data, + size_t len) +{ + if (rl->phh_data != NULL) + return TLS13_IO_FAILURE; + + rl->phh_data = data; + rl->phh_len = len; + + CBS_init(&rl->phh_cbs, rl->phh_data, rl->phh_len); + + return tls13_record_layer_send_pending(rl); } static int @@ -546,6 +664,9 @@ tls13_record_layer_seal_record_protected(struct tls13_record_layer *rl, if (!tls13_record_set_data(rl->wrec, data, data_len)) goto err; + rl->wrec_content_len = content_len; + rl->wrec_content_type = content_type; + data = NULL; data_len = 0; @@ -673,12 +794,12 @@ tls13_record_layer_read(struct tls13_record_layer *rl, uint8_t content_type, { ssize_t ret; + if ((ret = tls13_record_layer_send_pending(rl)) != TLS13_IO_SUCCESS) + return ret; + if (rl->read_closed) return TLS13_IO_EOF; - /* XXX - loop here with record and byte limits. */ - /* XXX - send alert... */ - /* If necessary, pull up the next record. */ if (CBS_len(&rl->rbuf_cbs) == 0) { if ((ret = tls13_record_layer_read_record(rl)) <= 0) @@ -737,16 +858,38 @@ tls13_record_layer_write_record(struct tls13_record_layer *rl, if (rl->write_closed) return TLS13_IO_EOF; + /* + * If we pushed out application data while handling other messages, + * we need to return content length on the next call. + */ + if (content_type == SSL3_RT_APPLICATION_DATA && + rl->wrec_appdata_len != 0) { + ret = rl->wrec_appdata_len; + rl->wrec_appdata_len = 0; + return ret; + } + /* See if there is an existing record and attempt to push it out... */ if (rl->wrec != NULL) { if ((ret = tls13_record_send(rl->wrec, rl->wire_write, rl->cb_arg)) <= 0) return ret; - tls13_record_layer_wrec_free(rl); - /* XXX - could be pushing out different data... */ - return content_len; + if (rl->wrec_content_type == content_type) { + ret = rl->wrec_content_len; + rl->wrec_content_len = 0; + rl->wrec_content_type = 0; + return ret; + } + + /* + * The only partial record type should be application data. + * All other cases are handled to completion. + */ + if (rl->wrec_content_type != SSL3_RT_APPLICATION_DATA) + return TLS13_IO_FAILURE; + rl->wrec_appdata_len = rl->wrec_content_len; } if (content_len > TLS13_RECORD_MAX_PLAINTEXT_LEN) @@ -767,8 +910,8 @@ tls13_record_layer_write_record(struct tls13_record_layer *rl, } static ssize_t -tls13_record_layer_write(struct tls13_record_layer *rl, uint8_t content_type, - const uint8_t *buf, size_t n) +tls13_record_layer_write_chunk(struct tls13_record_layer *rl, + uint8_t content_type, const uint8_t *buf, size_t n) { if (n > TLS13_RECORD_MAX_PLAINTEXT_LEN) n = TLS13_RECORD_MAX_PLAINTEXT_LEN; @@ -776,6 +919,18 @@ tls13_record_layer_write(struct tls13_record_layer *rl, uint8_t content_type, return tls13_record_layer_write_record(rl, content_type, buf, n); } +static ssize_t +tls13_record_layer_write(struct tls13_record_layer *rl, uint8_t content_type, + const uint8_t *buf, size_t n) +{ + ssize_t ret; + + if ((ret = tls13_record_layer_send_pending(rl)) != TLS13_IO_SUCCESS) + return ret; + + return tls13_record_layer_write_chunk(rl, content_type, buf, n); +} + ssize_t tls13_read_handshake_data(struct tls13_record_layer *rl, uint8_t *buf, size_t n) { |