From 0bd76fc4e9005b314101b808715176995cdf33a5 Mon Sep 17 00:00:00 2001 From: Alexander K Date: Thu, 24 Jan 2019 21:49:48 +0300 Subject: [PATCH] Fix #1146: ttls_update_checksum() can be called for chunk of ClientHello, while we still don't know the cipher suite. So calculate two checksums in parallel and copy SHA256 contex if necessary when ClientHello sets xfrm.ciphersuite_info. The rest of the patch, besides ttls_update_checksum() changes, is coding style adjustments. --- tls/ciphersuites.c | 14 +++++------ tls/ciphersuites.h | 62 +++++++++++++++++++++------------------------- tls/tls_cli.c | 14 +++++------ tls/tls_internal.h | 55 ++++++++++++++++++++++------------------ tls/tls_srv.c | 23 +++++++---------- tls/ttls.c | 56 ++++++++++++++++++++++++++++++++++------- tls/ttls.h | 2 +- 7 files changed, 130 insertions(+), 96 deletions(-) diff --git a/tls/ciphersuites.c b/tls/ciphersuites.c index 6507970a92..97b8f5a883 100644 --- a/tls/ciphersuites.c +++ b/tls/ciphersuites.c @@ -76,7 +76,7 @@ static const int ciphersuite_preference[] = { 0 }; -static const ttls_ciphersuite_t ciphersuite_definitions[] = +static const TlsCiphersuite ciphersuite_definitions[] = { { TTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256", @@ -259,10 +259,10 @@ static const ttls_ciphersuite_t ciphersuite_definitions[] = 0, 0, 0, 0, 0 } }; -const ttls_ciphersuite_t * +const TlsCiphersuite * ttls_ciphersuite_from_id(int ciphersuite) { - const ttls_ciphersuite_t *cur = ciphersuite_definitions; + const TlsCiphersuite *cur = ciphersuite_definitions; while (cur->id) { if (cur->id == ciphersuite) @@ -276,7 +276,7 @@ ttls_ciphersuite_from_id(int ciphersuite) const char * ttls_get_ciphersuite_name(const int ciphersuite_id) { - const ttls_ciphersuite_t *cur; + const TlsCiphersuite *cur; if (!(cur = ttls_ciphersuite_from_id(ciphersuite_id))) return("unknown"); @@ -285,7 +285,7 @@ ttls_get_ciphersuite_name(const int ciphersuite_id) } ttls_pk_type_t -ttls_get_ciphersuite_sig_pk_alg(const ttls_ciphersuite_t *info) +ttls_get_ciphersuite_sig_pk_alg(const TlsCiphersuite *info) { switch (info->key_exchange) { case TTLS_KEY_EXCHANGE_RSA: @@ -307,7 +307,7 @@ ttls_get_ciphersuite_sig_pk_alg(const ttls_ciphersuite_t *info) } ttls_pk_type_t -ttls_get_ciphersuite_sig_alg(const ttls_ciphersuite_t *info) +ttls_get_ciphersuite_sig_alg(const TlsCiphersuite *info) { switch (info->key_exchange) { case TTLS_KEY_EXCHANGE_RSA: @@ -324,7 +324,7 @@ ttls_get_ciphersuite_sig_alg(const ttls_ciphersuite_t *info) } int -ttls_ciphersuite_uses_ec(const ttls_ciphersuite_t *info) +ttls_ciphersuite_uses_ec(const TlsCiphersuite *info) { switch (info->key_exchange) { case TTLS_KEY_EXCHANGE_ECDHE_RSA: diff --git a/tls/ciphersuites.h b/tls/ciphersuites.h index abd034c03b..c5c04cbfa7 100644 --- a/tls/ciphersuites.h +++ b/tls/ciphersuites.h @@ -95,43 +95,37 @@ typedef enum { /* Key exchanges allowing client certificate requests */ //#define TTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED -typedef struct ttls_ciphersuite_t ttls_ciphersuite_t; - /* Weak ciphersuite flag */ #define TTLS_CIPHERSUITE_WEAK 0x01 /* Short authentication tag, eg for CCM_8 */ #define TTLS_CIPHERSUITE_SHORT_TAG 0x02 /** - * \brief This structure is used for storing ciphersuite information + * This structure is used for storing ciphersuite information. */ -struct ttls_ciphersuite_t -{ - int id; - const char * name; - - ttls_cipher_type_t cipher; - ttls_md_type_t mac; - ttls_key_exchange_type_t key_exchange; - - int min_major_ver; - int min_minor_ver; - int max_major_ver; - int max_minor_ver; - - unsigned char flags; -}; - -const ttls_ciphersuite_t *ttls_ciphersuite_from_id(int ciphersuite_id); - -ttls_pk_type_t ttls_get_ciphersuite_sig_pk_alg(const ttls_ciphersuite_t *info); -ttls_pk_type_t ttls_get_ciphersuite_sig_alg(const ttls_ciphersuite_t *info); - -int ttls_ciphersuite_uses_ec(const ttls_ciphersuite_t *info); -int ttls_ciphersuite_uses_psk(const ttls_ciphersuite_t *info); +typedef struct { + int id; + const char *name; + ttls_cipher_type_t cipher; + ttls_md_type_t mac; + ttls_key_exchange_type_t key_exchange; + int min_major_ver; + int min_minor_ver; + int max_major_ver; + int max_minor_ver; + unsigned char flags; +} TlsCiphersuite; + +const TlsCiphersuite *ttls_ciphersuite_from_id(int ciphersuite_id); + +ttls_pk_type_t ttls_get_ciphersuite_sig_pk_alg(const TlsCiphersuite *info); +ttls_pk_type_t ttls_get_ciphersuite_sig_alg(const TlsCiphersuite *info); + +int ttls_ciphersuite_uses_ec(const TlsCiphersuite *info); +int ttls_ciphersuite_uses_psk(const TlsCiphersuite *info); static inline int -ttls_ciphersuite_has_pfs(const ttls_ciphersuite_t *info) +ttls_ciphersuite_has_pfs(const TlsCiphersuite *info) { switch (info->key_exchange) { case TTLS_KEY_EXCHANGE_DHE_RSA: @@ -146,7 +140,7 @@ ttls_ciphersuite_has_pfs(const ttls_ciphersuite_t *info) } static inline int -ttls_ciphersuite_no_pfs(const ttls_ciphersuite_t *info) +ttls_ciphersuite_no_pfs(const TlsCiphersuite *info) { switch (info->key_exchange) { case TTLS_KEY_EXCHANGE_ECDH_RSA: @@ -161,7 +155,7 @@ ttls_ciphersuite_no_pfs(const ttls_ciphersuite_t *info) } static inline int -ttls_ciphersuite_uses_ecdh(const ttls_ciphersuite_t *info) +ttls_ciphersuite_uses_ecdh(const TlsCiphersuite *info) { switch (info->key_exchange) { case TTLS_KEY_EXCHANGE_ECDH_RSA: @@ -173,7 +167,7 @@ ttls_ciphersuite_uses_ecdh(const ttls_ciphersuite_t *info) } static inline int -ttls_ciphersuite_cert_req_allowed(const ttls_ciphersuite_t *info) +ttls_ciphersuite_cert_req_allowed(const TlsCiphersuite *info) { switch (info->key_exchange) { case TTLS_KEY_EXCHANGE_RSA: @@ -189,7 +183,7 @@ ttls_ciphersuite_cert_req_allowed(const ttls_ciphersuite_t *info) } static inline int -ttls_ciphersuite_uses_dhe(const ttls_ciphersuite_t *info) +ttls_ciphersuite_uses_dhe(const TlsCiphersuite *info) { switch (info->key_exchange) { case TTLS_KEY_EXCHANGE_DHE_RSA: @@ -201,7 +195,7 @@ ttls_ciphersuite_uses_dhe(const ttls_ciphersuite_t *info) } static inline int -ttls_ciphersuite_uses_ecdhe(const ttls_ciphersuite_t *info) +ttls_ciphersuite_uses_ecdhe(const TlsCiphersuite *info) { switch (info->key_exchange) { case TTLS_KEY_EXCHANGE_ECDHE_ECDSA: @@ -214,7 +208,7 @@ ttls_ciphersuite_uses_ecdhe(const ttls_ciphersuite_t *info) } static inline int -ttls_ciphersuite_uses_server_signature(const ttls_ciphersuite_t *info) +ttls_ciphersuite_uses_server_signature(const TlsCiphersuite *info) { switch (info->key_exchange) { case TTLS_KEY_EXCHANGE_DHE_RSA: diff --git a/tls/tls_cli.c b/tls/tls_cli.c index 2e0ff4a545..ccfc919829 100644 --- a/tls/tls_cli.c +++ b/tls/tls_cli.c @@ -448,7 +448,7 @@ static int ssl_write_client_hello(ttls_context *ssl) unsigned char *p, *q; unsigned char offer_compress; const int *ciphersuites; - const ttls_ciphersuite_t *ciphersuite_info; + const TlsCiphersuite *ciphersuite_info; T_DBG2("=> write client hello\n"); @@ -828,7 +828,7 @@ static int ssl_parse_server_hello(ttls_context *ssl) unsigned char *buf, *ext; unsigned char comp; int handshake_failure = 0; - const ttls_ciphersuite_t *suite_info; + const TlsCiphersuite *suite_info; T_DBG2("=> parse server hello\n"); @@ -1374,7 +1374,7 @@ static int ssl_get_ecdh_params_from_cert(ttls_context *ssl) static int ssl_parse_server_key_exchange(ttls_context *ssl) { int ret; - const ttls_ciphersuite_t *ciphersuite_info = + const TlsCiphersuite *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; unsigned char *p = NULL, *end = NULL; @@ -1591,7 +1591,7 @@ static int ssl_parse_server_key_exchange(ttls_context *ssl) #if ! defined(TTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED) static int ssl_parse_certificate_request(ttls_context *ssl) { - const ttls_ciphersuite_t *ciphersuite_info = + const TlsCiphersuite *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; T_DBG2("=> parse certificate request\n"); @@ -1613,7 +1613,7 @@ static int ssl_parse_certificate_request(ttls_context *ssl) unsigned char *buf; size_t n = 0; size_t cert_type_len = 0, dn_len = 0; - const ttls_ciphersuite_t *ciphersuite_info = + const TlsCiphersuite *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; T_DBG2("=> parse certificate request\n"); @@ -1769,7 +1769,7 @@ static int ssl_write_client_key_exchange(ttls_context *ssl) { int ret; size_t i, n; - const ttls_ciphersuite_t *ciphersuite_info = + const TlsCiphersuite *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; T_DBG2("=> write client key exchange\n"); @@ -1862,7 +1862,7 @@ static int ssl_write_client_key_exchange(ttls_context *ssl) static int ssl_write_certificate_verify(ttls_context *ssl) { - const ttls_ciphersuite_t *ciphersuite_info = + const TlsCiphersuite *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; int ret; diff --git a/tls/tls_internal.h b/tls/tls_internal.h index 04b1766e5d..00d3f111c0 100644 --- a/tls/tls_internal.h +++ b/tls/tls_internal.h @@ -102,7 +102,7 @@ struct ttls_sig_hash_set_t * This structure contains the parameters only needed during handshake. * * @hash_algs - set of suitable sig-hash pairs; - * @fin_sha{256,512} - checksum contexts; + * @sni_authmode - authmode from SNI callback; * @point_form - TLS extension flags (for extensions with outgoing ServerHello * content that need it (e.g. for RENEGOTIATION_INFO the server * already knows because of state of the renegotiation flag, so @@ -111,6 +111,14 @@ struct ttls_sig_hash_set_t * @new_session_ticket - use NewSessionTicket? * @resume - session resume indicator; * @cli_exts - client extension presence; + * @pmslen - premaster length; + * @key_cert - chosen key/cert pair (server); + * @sni_key_cert - key/cert list from SNI; + * @sni_ca_chain - trusted CAs from SNI callback; + * @sni_ca_crt - trusted CAs CRLs from SNI; + * @dhm_ctx - DHM key exchange; + * @ecdh_ctx - ECDH key exchange; + * @fin_sha{256,512} - checksum contexts; * @curves - supported elliptic curves; * @randbytes - random bytes; * @finished - temporal buffer for chunks of Finished message, @@ -120,36 +128,35 @@ struct ttls_sig_hash_set_t */ typedef struct tls_handshake_t { ttls_sig_hash_set_t hash_algs; + int sni_authmode; -#if defined(TTLS_DHM_C) - ttls_dhm_context dhm_ctx; /*!< DHM key exchange */ -#endif - ttls_ecdh_context ecdh_ctx; /*!< ECDH key exchange */ - ttls_key_cert *key_cert; /*!< chosen key/cert pair (server) */ - int sni_authmode; /*!< authmode from SNI callback */ - ttls_key_cert *sni_key_cert; /*!< key/cert list from SNI */ - ttls_x509_crt *sni_ca_chain; /*!< trusted CAs from SNI callback */ - ttls_x509_crl *sni_ca_crl; /*!< trusted CAs CRLs from SNI */ + unsigned char point_form : 1, + extended_ms : 1, + new_session_ticket : 1, + resume : 1, + cli_exts : 1, + curves_ext : 1; - union { - struct shash_desc desc; /* common for both the contexts */ - ttls_sha256_context fin_sha256; - ttls_sha512_context fin_sha512; - }; + size_t pmslen; + ttls_key_cert *key_cert; + ttls_key_cert *sni_key_cert; + ttls_x509_crt *sni_ca_chain; + ttls_x509_crl *sni_ca_crl; void (*calc_verify)(ttls_context *, unsigned char *); void (*calc_finished)(ttls_context *, unsigned char *, int); int (*tls_prf)(const unsigned char *, size_t, const char *, size_t, const unsigned char *, size_t, unsigned char *, size_t); - size_t pmslen; /*!< premaster length*/ - unsigned char point_form:1, - extended_ms:1, - new_session_ticket:1, - resume:1, - cli_exts:1, - curves_ext:1; - +#if defined(TTLS_DHM_C) + ttls_dhm_context dhm_ctx; +#endif + ttls_ecdh_context ecdh_ctx; + union { + struct shash_desc desc; /* common for both the contexts */ + ttls_sha256_context fin_sha256; + ttls_sha512_context fin_sha512; + }; const ttls_ecp_curve_info *curves[TTLS_ECP_DP_MAX]; union { unsigned char randbytes[64]; @@ -268,7 +275,7 @@ ttls_own_cert(TlsCtx *tls) * Return 0 if everything is OK, -1 if not. */ int ttls_check_cert_usage(const ttls_x509_crt *cert, - const ttls_ciphersuite_t *ciphersuite, + const TlsCiphersuite *ciphersuite, int cert_endpoint, uint32_t *flags); diff --git a/tls/tls_srv.c b/tls/tls_srv.c index 58cef94074..d99ed81e40 100644 --- a/tls/tls_srv.c +++ b/tls/tls_srv.c @@ -4,7 +4,7 @@ * TLS server-side finite state machine. * * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved - * Copyright (C) 2015-2018 Tempesta Technologies, Inc. + * Copyright (C) 2015-2019 Tempesta Technologies, Inc. * SPDX-License-Identifier: GPL-2.0 * * This program is free software; you can redistribute it and/or modify @@ -405,7 +405,7 @@ ttls_check_key_curve(ttls_pk_context *pk, const ttls_ecp_curve_info **curves) * @return 0 on success and -1 on failure. */ static int -ttls_pick_cert(TlsCtx *tls, const ttls_ciphersuite_t *ci) +ttls_pick_cert(TlsCtx *tls, const TlsCiphersuite *ci) { ttls_key_cert *cur, *list; ttls_pk_type_t pk_alg = ttls_get_ciphersuite_sig_pk_alg(ci); @@ -473,9 +473,9 @@ ttls_pick_cert(TlsCtx *tls, const ttls_ciphersuite_t *ci) * Sets @ci only if the suite matches. */ static int -ttls_ciphersuite_match(TlsCtx *tls, int suite_id, const ttls_ciphersuite_t **ci) +ttls_ciphersuite_match(TlsCtx *tls, int suite_id, const TlsCiphersuite **ci) { - const ttls_ciphersuite_t *suite_info; + const TlsCiphersuite *suite_info; ttls_pk_type_t sig_type; suite_info = ttls_ciphersuite_from_id(suite_id); @@ -534,7 +534,7 @@ ttls_choose_ciphersuite(TlsCtx *tls, const unsigned char *csp) unsigned short ciph_len = ntohs(*(short *)csp); int r, i, got_common_suite = 0; const int *ciphersuites = tls->conf->ciphersuite_list[tls->minor]; - const ttls_ciphersuite_t *ci = NULL; + const TlsCiphersuite *ci = NULL; const unsigned char *cs; for (i = 0; ciphersuites[i] != 0; i++) @@ -1038,11 +1038,6 @@ ttls_parse_client_hello(TlsCtx *tls, unsigned char *buf, size_t len, */ r = ttls_choose_ciphersuite(tls, &tls->hs->tmp[TTLS_HS_TMP_STORE_SZ]); - /* - * This is, after ttls_choose_ciphersuite() call, the earliest time - * when we know which hash function to use and now we can start to - * compute the handshake session checksum. - */ if (!r) ttls_update_checksum(tls, buf - hh_len, p - buf + hh_len); @@ -1296,7 +1291,7 @@ ttls_write_server_key_exchange(TlsCtx *tls, struct sg_table *sgt, { int r; size_t len, n = 0, dig_signed_len = 0; - const ttls_ciphersuite_t *ci = tls->xfrm.ciphersuite_info; + const TlsCiphersuite *ci = tls->xfrm.ciphersuite_info; TlsIOCtx *io = &tls->io_out; unsigned char *dig_signed, *p, *hdr = *in_buf; @@ -1785,7 +1780,7 @@ ttls_parse_client_key_exchange(TlsCtx *tls, unsigned char *buf, size_t len, size_t hh_len, unsigned int *read) { int r; - const ttls_ciphersuite_t *ci = tls->xfrm.ciphersuite_info; + const TlsCiphersuite *ci = tls->xfrm.ciphersuite_info; unsigned char *p, *end; TlsIOCtx *io = &tls->io_in; @@ -2108,7 +2103,7 @@ ttls_handshake_server_hello(TlsCtx *tls) T_FSM_JMP(TTLS_SERVER_HELLO_DONE); } T_FSM_STATE(TTLS_SERVER_HELLO_DONE) { - const ttls_ciphersuite_t *ci = tls->xfrm.ciphersuite_info; + const TlsCiphersuite *ci = tls->xfrm.ciphersuite_info; if ((r = ttls_write_server_hello_done(tls, &sgt, &p))) return r; @@ -2258,7 +2253,7 @@ ttls_handshake_server_step(TlsCtx *tls, unsigned char *buf, size_t len, return T_OK; } T_FSM_STATE(TTLS_CLIENT_KEY_EXCHANGE) { - const ttls_ciphersuite_t *ci = tls->xfrm.ciphersuite_info; + const TlsCiphersuite *ci = tls->xfrm.ciphersuite_info; r = ttls_parse_client_key_exchange(tls, buf, len, hh_len, read); if (r) diff --git a/tls/ttls.c b/tls/ttls.c index a10fab29f6..4551c3ac98 100644 --- a/tls/ttls.c +++ b/tls/ttls.c @@ -4,7 +4,7 @@ * Main TLS shared functions for the server and client. * * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved - * Copyright (C) 2015-2018 Tempesta Technologies, Inc. + * Copyright (C) 2015-2019 Tempesta Technologies, Inc. * SPDX-License-Identifier: GPL-2.0 * * This program is free software; you can redistribute it and/or modify @@ -38,7 +38,7 @@ MODULE_AUTHOR("Tempesta Technologies, Inc"); MODULE_DESCRIPTION("Tempesta TLS"); -MODULE_VERSION("0.2.0"); +MODULE_VERSION("0.2.1"); MODULE_LICENSE("GPL"); typedef struct { @@ -359,7 +359,9 @@ ttls_update_checksum(TlsCtx *tls, const unsigned char *buf, size_t len) { int r; TlsHandshake *hs = tls->hs; - const ttls_ciphersuite_t *ci = tls->xfrm.ciphersuite_info; + const TlsCiphersuite *ci = tls->xfrm.ciphersuite_info; + ttls_sha256_context *sha256 = (ttls_sha256_context *)&hs->ecdh_ctx; + ttls_md_type_t mac; if (unlikely(!len)) return; @@ -367,10 +369,47 @@ ttls_update_checksum(TlsCtx *tls, const unsigned char *buf, size_t len) /* * Initialize the hash context on first call to avoid double * hash calculation. + * + * We may find empty ciphersuite_info here only if we process a part of + * ClientHello message, when we hadn't read the extension yet. If so, + * then do a trick: compute both the checksums for the chunk and use + * hs->ecdh_ctx to store SHA256 checksum data. */ - BUG_ON(!ci); + if (unlikely(IS_ERR_OR_NULL(ci))) { + WARN_ON_ONCE(tls->state >= TTLS_SERVER_HELLO); + BUILD_BUG_ON(sizeof(ttls_ecdh_context) + < sizeof(ttls_sha256_context)); + + if (!ci) { + if (WARN_ON_ONCE(ttls_sha256_init_start(sha256))) + return; + tls->xfrm.ciphersuite_info = ERR_PTR(0xdead); + } + r = crypto_shash_update((struct shash_desc *)sha256, buf, len); + if (WARN_ON_ONCE(r)) + return; + mac = TTLS_MD_SHA384; + } else { + mac = ci->mac; + /* + * This is, after ttls_choose_ciphersuite() call but still at + * ClientHello state, the earliest time when we know which hash + * function to use. If the hash context is initialized, then + * there were ClientHello chunks and probably we need to copy + * the hash context. + */ + if (unlikely(tls->state < TTLS_SERVER_HELLO && hs->desc.tfm + && mac == TTLS_MD_SHA256)) + { + crypto_free_shash(hs->desc.tfm); + memcpy_fast(&tls->hs->fin_sha256, sha256, + sizeof(*sha256)); + bzero_fast(&hs->ecdh_ctx, sizeof(ttls_ecdh_context)); + } + + } if (unlikely(!hs->desc.tfm)) { - if (ci->mac == TTLS_MD_SHA384) + if (mac == TTLS_MD_SHA384) r = ttls_sha384_init_start(&hs->fin_sha512); else r = ttls_sha256_init_start(&hs->fin_sha256); @@ -379,11 +418,10 @@ ttls_update_checksum(TlsCtx *tls, const unsigned char *buf, size_t len) } T_DBG2("update checksum on buf %pK len=%ld, hash=%d\n", - buf, len, ci->mac); + buf, len, mac); T_DBG3_BUF("hash buf ", buf, len); - r = crypto_shash_update(&tls->hs->desc, buf, len); - WARN_ON_ONCE(r); + WARN_ON_ONCE(crypto_shash_update(&tls->hs->desc, buf, len)); } static void @@ -2614,7 +2652,7 @@ ttls_set_default_sig_hash(TlsCtx *tls) int ttls_check_cert_usage(const ttls_x509_crt *cert, - const ttls_ciphersuite_t *ciphersuite, int cert_endpoint, + const TlsCiphersuite *ciphersuite, int cert_endpoint, uint32_t *flags) { int r = 0; diff --git a/tls/ttls.h b/tls/ttls.h index b3d9536e90..ec533a208b 100644 --- a/tls/ttls.h +++ b/tls/ttls.h @@ -319,7 +319,7 @@ typedef struct { * @iv_dec - IV for decryption; */ typedef struct { - const ttls_ciphersuite_t *ciphersuite_info; + const TlsCiphersuite *ciphersuite_info; TlsMdCtx md_ctx_enc; TlsMdCtx md_ctx_dec; TlsCipherCtx cipher_ctx_enc;