From 5f1bde4564ba31b04e48f9092e1605799b21645f Mon Sep 17 00:00:00 2001 From: jsing Date: Mon, 7 Nov 2022 11:58:45 +0000 Subject: [PATCH] Rewrite TLSv1.2 key exporter. Replace the grotty TLSv1.2 key exporter with a cleaner version that uses CBB and CBS. ok tb@ --- lib/libssl/ssl_lib.c | 21 +++--- lib/libssl/ssl_locl.h | 5 +- lib/libssl/t1_enc.c | 82 +-------------------- lib/libssl/tls12_internal.h | 29 ++++++++ lib/libssl/tls12_key_schedule.c | 122 +++++++++++++++++++++++++++++++- 5 files changed, 163 insertions(+), 96 deletions(-) create mode 100644 lib/libssl/tls12_internal.h diff --git a/lib/libssl/ssl_lib.c b/lib/libssl/ssl_lib.c index 4b5f119a88a..c9c63e9d3f6 100644 --- a/lib/libssl/ssl_lib.c +++ b/lib/libssl/ssl_lib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_lib.c,v 1.306 2022/10/02 16:36:41 jsing Exp $ */ +/* $OpenBSD: ssl_lib.c,v 1.307 2022/11/07 11:58:45 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -163,6 +163,7 @@ #include "ssl_locl.h" #include "ssl_sigalgs.h" #include "ssl_tlsext.h" +#include "tls12_internal.h" const char *SSL_version_str = OPENSSL_VERSION_TEXT; @@ -1867,21 +1868,21 @@ SSL_set_psk_use_session_callback(SSL *s, SSL_psk_use_session_cb_func cb) } int -SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen, - const char *label, size_t llen, const unsigned char *p, size_t plen, - int use_context) +SSL_export_keying_material(SSL *s, unsigned char *out, size_t out_len, + const char *label, size_t label_len, const unsigned char *context, + size_t context_len, int use_context) { if (s->tls13 != NULL && s->version == TLS1_3_VERSION) { if (!use_context) { - p = NULL; - plen = 0; + context = NULL; + context_len = 0; } - return tls13_exporter(s->tls13, label, llen, p, plen, - out, olen); + return tls13_exporter(s->tls13, label, label_len, context, + context_len, out, out_len); } - return (tls1_export_keying_material(s, out, olen, label, llen, p, plen, - use_context)); + return tls12_exporter(s, label, label_len, context, context_len, + use_context, out, out_len); } static unsigned long diff --git a/lib/libssl/ssl_locl.h b/lib/libssl/ssl_locl.h index 42ae4290748..64cf6a60f9f 100644 --- a/lib/libssl/ssl_locl.h +++ b/lib/libssl/ssl_locl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_locl.h,v 1.429 2022/10/20 15:22:51 tb Exp $ */ +/* $OpenBSD: ssl_locl.h,v 1.430 2022/11/07 11:58:45 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -1463,9 +1463,6 @@ int tls1_change_read_cipher_state(SSL *s); int tls1_change_write_cipher_state(SSL *s); int tls1_setup_key_block(SSL *s); int tls1_generate_key_block(SSL *s, uint8_t *key_block, size_t key_block_len); -int tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen, - const char *label, size_t llen, const unsigned char *p, size_t plen, - int use_context); int ssl_ok(SSL *s); int tls12_derive_finished(SSL *s); diff --git a/lib/libssl/t1_enc.c b/lib/libssl/t1_enc.c index 66a7aea2f50..dc627c5a8bb 100644 --- a/lib/libssl/t1_enc.c +++ b/lib/libssl/t1_enc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: t1_enc.c,v 1.155 2022/10/02 16:36:41 jsing Exp $ */ +/* $OpenBSD: t1_enc.c,v 1.156 2022/11/07 11:58:45 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -413,83 +413,3 @@ tls1_setup_key_block(SSL *s) return (ret); } - -int -tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen, - const char *label, size_t llen, const unsigned char *context, - size_t contextlen, int use_context) -{ - unsigned char *val = NULL; - size_t vallen, currentvalpos; - int rv; - - if (!SSL_is_init_finished(s)) { - SSLerror(s, SSL_R_BAD_STATE); - return 0; - } - - /* construct PRF arguments - * we construct the PRF argument ourself rather than passing separate - * values into the TLS PRF to ensure that the concatenation of values - * does not create a prohibited label. - */ - vallen = llen + SSL3_RANDOM_SIZE * 2; - if (use_context) { - vallen += 2 + contextlen; - } - - val = malloc(vallen); - if (val == NULL) - goto err2; - currentvalpos = 0; - memcpy(val + currentvalpos, (unsigned char *) label, llen); - currentvalpos += llen; - memcpy(val + currentvalpos, s->s3->client_random, SSL3_RANDOM_SIZE); - currentvalpos += SSL3_RANDOM_SIZE; - memcpy(val + currentvalpos, s->s3->server_random, SSL3_RANDOM_SIZE); - currentvalpos += SSL3_RANDOM_SIZE; - - if (use_context) { - val[currentvalpos] = (contextlen >> 8) & 0xff; - currentvalpos++; - val[currentvalpos] = contextlen & 0xff; - currentvalpos++; - if ((contextlen > 0) || (context != NULL)) { - memcpy(val + currentvalpos, context, contextlen); - } - } - - /* disallow prohibited labels - * note that SSL3_RANDOM_SIZE > max(prohibited label len) = - * 15, so size of val > max(prohibited label len) = 15 and the - * comparisons won't have buffer overflow - */ - if (memcmp(val, TLS_MD_CLIENT_FINISH_CONST, - TLS_MD_CLIENT_FINISH_CONST_SIZE) == 0) - goto err1; - if (memcmp(val, TLS_MD_SERVER_FINISH_CONST, - TLS_MD_SERVER_FINISH_CONST_SIZE) == 0) - goto err1; - if (memcmp(val, TLS_MD_MASTER_SECRET_CONST, - TLS_MD_MASTER_SECRET_CONST_SIZE) == 0) - goto err1; - if (memcmp(val, TLS_MD_KEY_EXPANSION_CONST, - TLS_MD_KEY_EXPANSION_CONST_SIZE) == 0) - goto err1; - - rv = tls1_PRF(s, s->session->master_key, s->session->master_key_length, - val, vallen, NULL, 0, NULL, 0, NULL, 0, NULL, 0, out, olen); - - goto ret; - err1: - SSLerror(s, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL); - rv = 0; - goto ret; - err2: - SSLerror(s, ERR_R_MALLOC_FAILURE); - rv = 0; - ret: - free(val); - - return (rv); -} diff --git a/lib/libssl/tls12_internal.h b/lib/libssl/tls12_internal.h new file mode 100644 index 00000000000..d416b2e3f11 --- /dev/null +++ b/lib/libssl/tls12_internal.h @@ -0,0 +1,29 @@ +/* $OpenBSD: tls12_internal.h,v 1.1 2022/11/07 11:58:45 jsing Exp $ */ +/* + * Copyright (c) 2022 Joel Sing + * + * Permission to use, copy, modify, and/or 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. + */ + +#ifndef HEADER_TLS12_INTERNAL_H +#define HEADER_TLS12_INTERNAL_H + +__BEGIN_HIDDEN_DECLS + +int tls12_exporter(SSL *s, const uint8_t *label, size_t label_len, + const uint8_t *context_value, size_t context_value_len, int use_context, + uint8_t *out, size_t out_len); + +__END_HIDDEN_DECLS + +#endif diff --git a/lib/libssl/tls12_key_schedule.c b/lib/libssl/tls12_key_schedule.c index c206460d959..e603e2c2227 100644 --- a/lib/libssl/tls12_key_schedule.c +++ b/lib/libssl/tls12_key_schedule.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls12_key_schedule.c,v 1.1 2021/05/05 10:05:27 jsing Exp $ */ +/* $OpenBSD: tls12_key_schedule.c,v 1.2 2022/11/07 11:58:45 jsing Exp $ */ /* * Copyright (c) 2021 Joel Sing * @@ -21,6 +21,7 @@ #include "bytestring.h" #include "ssl_locl.h" +#include "tls12_internal.h" struct tls12_key_block { CBS client_write_mac_key; @@ -173,3 +174,122 @@ tls12_key_block_generate(struct tls12_key_block *kb, SSL *s, return 0; } + +struct tls12_reserved_label { + const char *label; + size_t label_len; +}; + +/* + * RFC 5705 section 6. + */ +static const struct tls12_reserved_label tls12_reserved_labels[] = { + { + .label = TLS_MD_CLIENT_FINISH_CONST, + .label_len = TLS_MD_CLIENT_FINISH_CONST_SIZE, + }, + { + .label = TLS_MD_SERVER_FINISH_CONST, + .label_len = TLS_MD_SERVER_FINISH_CONST_SIZE, + }, + { + .label = TLS_MD_MASTER_SECRET_CONST, + .label_len = TLS_MD_MASTER_SECRET_CONST_SIZE, + }, + { + .label = TLS_MD_KEY_EXPANSION_CONST, + .label_len = TLS_MD_KEY_EXPANSION_CONST_SIZE, + }, + { + .label = NULL, + .label_len = 0, + }, +}; + +int +tls12_exporter(SSL *s, const uint8_t *label, size_t label_len, + const uint8_t *context_value, size_t context_value_len, int use_context, + uint8_t *out, size_t out_len) +{ + uint8_t *data = NULL; + size_t data_len = 0; + CBB cbb, context; + CBS seed; + size_t i; + int ret = 0; + + /* + * RFC 5705 - Key Material Exporters for TLS. + */ + + memset(&cbb, 0, sizeof(cbb)); + + if (!SSL_is_init_finished(s)) { + SSLerror(s, SSL_R_BAD_STATE); + goto err; + } + + if (s->s3->hs.negotiated_tls_version >= TLS1_3_VERSION) + goto err; + + /* + * Due to exceptional design choices, we need to build a concatenation + * of the label and the seed value, before checking for reserved + * labels. This prevents a reserved label from being split across the + * label and the seed (that includes the client random), which are + * concatenated by the PRF. + */ + if (!CBB_init(&cbb, 0)) + goto err; + if (!CBB_add_bytes(&cbb, label, label_len)) + goto err; + if (!CBB_add_bytes(&cbb, s->s3->client_random, SSL3_RANDOM_SIZE)) + goto err; + if (!CBB_add_bytes(&cbb, s->s3->server_random, SSL3_RANDOM_SIZE)) + goto err; + if (use_context) { + if (!CBB_add_u16_length_prefixed(&cbb, &context)) + goto err; + if (context_value_len > 0) { + if (!CBB_add_bytes(&context, context_value, + context_value_len)) + goto err; + } + } + if (!CBB_finish(&cbb, &data, &data_len)) + goto err; + + /* + * Ensure that the block (label + seed) does not start with a reserved + * label - in an ideal world we would ensure that the label has an + * explicitly permitted prefix instead, but of course this also got + * messed up by the standards. + */ + for (i = 0; tls12_reserved_labels[i].label != NULL; i++) { + /* XXX - consider adding/using CBS_has_prefix(). */ + if (tls12_reserved_labels[i].label_len > data_len) + goto err; + if (memcmp(data, tls12_reserved_labels[i].label, + tls12_reserved_labels[i].label_len) == 0) { + SSLerror(s, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL); + goto err; + } + } + + CBS_init(&seed, data, data_len); + if (!CBS_skip(&seed, label_len)) + goto err; + + if (!tls1_PRF(s, s->session->master_key, s->session->master_key_length, + label, label_len, CBS_data(&seed), CBS_len(&seed), NULL, 0, NULL, 0, + NULL, 0, out, out_len)) + goto err; + + ret = 1; + + err: + freezero(data, data_len); + CBB_cleanup(&cbb); + + return ret; +} -- 2.20.1