From b2f7e8c0fe2f4e8d3d14fa30805211daa5456ffa Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 12 Jan 2017 15:28:48 +0000 Subject: [PATCH] Add support for the psk_key_exchange_modes extension This is required for the later addition of resumption support. Reviewed-by: Rich Salz (Merged from https://github.com/openssl/openssl/pull/2259) --- include/openssl/ssl.h | 1 + include/openssl/tls1.h | 1 + ssl/ssl_err.c | 2 ++ ssl/ssl_locl.h | 15 ++++++++++++++ ssl/statem/extensions.c | 15 ++++++++++++++ ssl/statem/extensions_clnt.c | 27 ++++++++++++++++++++++++++ ssl/statem/extensions_srvr.c | 29 ++++++++++++++++++++++++++++ ssl/statem/statem_locl.h | 4 ++++ ssl/t1_trce.c | 15 ++++++++++++++ test/recipes/70-test_tls13messages.t | 2 ++ util/TLSProxy/Message.pm | 1 + 11 files changed, 112 insertions(+) diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index e95fdb4842..708d59b14c 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -2281,6 +2281,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE 470 # define SSL_F_TLS_CONSTRUCT_CTOS_NPN 471 # define SSL_F_TLS_CONSTRUCT_CTOS_PADDING 472 +# define SSL_F_TLS_CONSTRUCT_CTOS_PSK_KEX_MODES 509 # define SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE 473 # define SSL_F_TLS_CONSTRUCT_CTOS_SCT 474 # define SSL_F_TLS_CONSTRUCT_CTOS_SERVER_NAME 475 diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h index 707fb96054..65569bd50d 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -178,6 +178,7 @@ extern "C" { /* As defined for TLS1.3 */ # define TLSEXT_TYPE_key_share 40 # define TLSEXT_TYPE_supported_versions 43 +# define TLSEXT_TYPE_psk_kex_modes 45 /* Temporary extension type */ # define TLSEXT_TYPE_renegotiate 0xff01 diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 099af01371..2d9401af62 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -300,6 +300,8 @@ static ERR_STRING_DATA SSL_str_functs[] = { {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_NPN), "tls_construct_ctos_npn"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_PADDING), "tls_construct_ctos_padding"}, + {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_PSK_KEX_MODES), + "tls_construct_ctos_psk_kex_modes"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE), "tls_construct_ctos_renegotiate"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_SCT), "tls_construct_ctos_sct"}, diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index ef525fe6e1..17b377f507 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1105,6 +1105,9 @@ struct ssl_st { */ unsigned char *npn; size_t npn_len; + + /* The selected PSK key exchange mode */ + int psk_kex_mode; } ext; /*- @@ -1680,6 +1683,7 @@ typedef enum tlsext_index_en { TLSEXT_IDX_signed_certificate_timestamp, TLSEXT_IDX_extended_master_secret, TLSEXT_IDX_supported_versions, + TLSEXT_IDX_psk_kex_modes, TLSEXT_IDX_key_share, TLSEXT_IDX_cryptopro_bug, TLSEXT_IDX_padding @@ -1711,6 +1715,17 @@ typedef enum tlsext_index_en { #define TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512 0xefef #define TLSEXT_SIGALG_gostr34102001_gostr3411 0xeded +/* Known PSK key exchange modes */ +#define TLSEXT_KEX_MODE_KE 0x00 +#define TLSEXT_KEX_MODE_KE_DHE 0x01 + +/* + * Internal representations of key exchange modes + */ +#define TLSEXT_KEX_MODE_FLAG_NONE 0 +#define TLSEXT_KEX_MODE_FLAG_KE 1 +#define TLSEXT_KEX_MODE_FLAG_KE_DHE 2 + #define SIGID_IS_PSS(sigid) ((sigid) == TLSEXT_SIGALG_rsa_pss_sha256 \ || (sigid) == TLSEXT_SIGALG_rsa_pss_sha384 \ || (sigid) == TLSEXT_SIGALG_rsa_pss_sha512) diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index ee5b0d71a3..dc992010ec 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -35,6 +35,7 @@ static int init_srp(SSL *s, unsigned int context); static int init_etm(SSL *s, unsigned int context); static int init_ems(SSL *s, unsigned int context); static int final_ems(SSL *s, unsigned int context, int sent, int *al); +static int init_psk_kex_modes(SSL *s, unsigned int context); #ifndef OPENSSL_NO_SRTP static int init_srtp(SSL *s, unsigned int context); #endif @@ -234,6 +235,13 @@ static const EXTENSION_DEFINITION ext_defs[] = { /* Processed inline as part of version selection */ NULL, NULL, NULL, tls_construct_ctos_supported_versions, NULL }, + { + /* Must be before key_share */ + TLSEXT_TYPE_psk_kex_modes, + EXT_CLIENT_HELLO | EXT_TLS_IMPLEMENTATION_ONLY | EXT_TLS1_3_ONLY, + init_psk_kex_modes, tls_parse_ctos_psk_kex_modes, NULL, NULL, + tls_construct_ctos_psk_kex_modes, NULL + }, { /* * Must be in this list after supported_groups. We need that to have @@ -938,3 +946,10 @@ static int final_sig_algs(SSL *s, unsigned int context, int sent, int *al) return 1; } + +static int init_psk_kex_modes(SSL *s, unsigned int context) +{ + s->ext.psk_kex_mode = TLSEXT_KEX_MODE_FLAG_NONE; + + return 1; +} diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index 1e2cc3f6f7..57f6564678 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -494,6 +494,33 @@ int tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt, X509 *x, return 1; } +/* + * Construct a psk_kex_modes extension. We only have two modes we know about + * at this stage, so we send both. + */ +int tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt, X509 *x, + size_t chainidx, int *al) +{ +#ifndef OPENSSL_NO_TLS1_3 + /* + * TODO(TLS1.3): Do we want this list to be configurable? For now we always + * just send both supported modes + */ + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_psk_kex_modes) + || !WPACKET_start_sub_packet_u16(pkt) + || !WPACKET_start_sub_packet_u8(pkt) + || !WPACKET_put_bytes_u8(pkt, TLSEXT_KEX_MODE_KE_DHE) + || !WPACKET_put_bytes_u8(pkt, TLSEXT_KEX_MODE_KE) + || !WPACKET_close(pkt) + || !WPACKET_close(pkt)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK_KEX_MODES, ERR_R_INTERNAL_ERROR); + return 0; + } +#endif + + return 1; +} + int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx, int *al) { diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 357b3b7105..8ee292818e 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -478,6 +478,35 @@ static int check_in_list(SSL *s, unsigned int group_id, } #endif +/* + * Process a psk_kex_modes extension received in the ClientHello. |pkt| contains + * the raw PACKET data for the extension. Returns 1 on success or 0 on failure. + * If a failure occurs then |*al| is set to an appropriate alert value. + */ +int tls_parse_ctos_psk_kex_modes(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, + int *al) +{ +#ifndef OPENSSL_NO_TLS1_3 + PACKET psk_kex_modes; + unsigned int mode; + + if (!PACKET_as_length_prefixed_1(pkt, &psk_kex_modes) + || PACKET_remaining(&psk_kex_modes) == 0) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + while (PACKET_get_1(&psk_kex_modes, &mode)) { + if (mode == TLSEXT_KEX_MODE_KE_DHE) + s->ext.psk_kex_mode |= TLSEXT_KEX_MODE_FLAG_KE_DHE; + else if (mode == TLSEXT_KEX_MODE_KE) + s->ext.psk_kex_mode |= TLSEXT_KEX_MODE_FLAG_KE; + } +#endif + + return 1; +} + /* * Process a key_share extension received in the ClientHello. |pkt| contains * the raw PACKET data for the extension. Returns 1 on success or 0 on failure. diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h index 51adfc6dce..be3167ce54 100644 --- a/ssl/statem/statem_locl.h +++ b/ssl/statem/statem_locl.h @@ -201,6 +201,8 @@ int tls_parse_ctos_etm(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al); int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al); int tls_parse_ctos_ems(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al); +int tls_parse_ctos_psk_kex_modes(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, + int *al); int tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx, int *al); @@ -285,6 +287,8 @@ int tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx, int *al); int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx, int *al); +int tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt, X509 *x, + size_t chainidx, int *al); int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx, int *al); int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, diff --git a/ssl/t1_trce.c b/ssl/t1_trce.c index b3b6e18b0d..9da8f756d8 100644 --- a/ssl/t1_trce.c +++ b/ssl/t1_trce.c @@ -449,6 +449,7 @@ static ssl_trace_tbl ssl_exts_tbl[] = { {TLSEXT_TYPE_server_authz, "server_authz"}, {TLSEXT_TYPE_cert_type, "cert_type"}, {TLSEXT_TYPE_key_share, "key_share"}, + {TLSEXT_TYPE_psk_kex_modes, "psk_key_exchange_modes"}, {TLSEXT_TYPE_supported_groups, "supported_groups"}, {TLSEXT_TYPE_ec_point_formats, "ec_point_formats"}, {TLSEXT_TYPE_srp, "srp"}, @@ -540,6 +541,11 @@ static ssl_trace_tbl ssl_ctype_tbl[] = { {66, "ecdsa_fixed_ecdh"} }; +static ssl_trace_tbl ssl_psk_kex_modes_tbl[] = { + {TLSEXT_KEX_MODE_KE, "psk_ke"}, + {TLSEXT_KEX_MODE_KE_DHE, "psk_dhe_ke"} +}; + static ssl_trace_tbl ssl_crypto_tbl[] = { {TLS1_RT_CRYPTO_PREMASTER, "Premaster Secret"}, {TLS1_RT_CRYPTO_CLIENT_RANDOM, "Client Random"}, @@ -760,6 +766,15 @@ static int ssl_print_extension(BIO *bio, int indent, int server, int extype, return ssl_trace_list(bio, indent + 2, ext + 1, xlen, 2, ssl_version_tbl); + case TLSEXT_TYPE_psk_kex_modes: + if (extlen < 1) + return 0; + xlen = ext[0]; + if (extlen != xlen + 1) + return 0; + return ssl_trace_list(bio, indent + 2, ext + 1, xlen, 1, + ssl_psk_kex_modes_tbl); + default: BIO_dump_indent(bio, (const char *)ext, extlen, indent + 2); } diff --git a/test/recipes/70-test_tls13messages.t b/test/recipes/70-test_tls13messages.t index d6512b57ad..fb69e7cd0d 100755 --- a/test/recipes/70-test_tls13messages.t +++ b/test/recipes/70-test_tls13messages.t @@ -81,6 +81,8 @@ $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf"); checkhandshake::DEFAULT_EXTENSIONS], [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS, checkhandshake::DEFAULT_EXTENSIONS], + [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK_KEX_MODES, + checkhandshake::DEFAULT_EXTENSIONS], [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_KEY_SHARE, checkhandshake::DEFAULT_EXTENSIONS], diff --git a/util/TLSProxy/Message.pm b/util/TLSProxy/Message.pm index 7cb7b28aec..99c3689ca2 100644 --- a/util/TLSProxy/Message.pm +++ b/util/TLSProxy/Message.pm @@ -75,6 +75,7 @@ use constant { EXT_SESSION_TICKET => 35, EXT_KEY_SHARE => 40, EXT_SUPPORTED_VERSIONS => 43, + EXT_PSK_KEX_MODES => 45, EXT_RENEGOTIATE => 65281, EXT_NPN => 13172, # This extension is an unofficial extension only ever written by OpenSSL -- 2.34.1