From 224135e96a16deaf9de787398d91c1b8212ab8ed Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 24 Nov 2016 18:02:12 +0000 Subject: [PATCH] Continue the extensions refactor Add support for construction of extensions Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich Salz Reviewed-by: Rich Salz Reviewed-by: Richard Levitte --- ssl/statem/extensions.c | 143 +++++++++++++++++++++++++++++++++++----- 1 file changed, 128 insertions(+), 15 deletions(-) diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index 2aad56b135..82f1565a95 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -40,6 +40,8 @@ typedef struct { unsigned int type; int (*server_parse)(SSL *s, PACKET *pkt, int *al); int (*client_parse)(SSL *s, PACKET *pkt, int *al); + int (*server_construct)(SSL *s, WPACKET *pkt, int *al); + int (*client_construct)(SSL *s, WPACKET *pkt, int *al); unsigned int context; } EXTENSION_DEFINITION; @@ -48,6 +50,8 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_renegotiate, tls_parse_clienthello_renegotiate, NULL, + NULL, + NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_SSL3_ALLOWED | EXT_TLS1_2_AND_BELOW_ONLY }, @@ -55,6 +59,8 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_server_name, tls_parse_clienthello_server_name, NULL, + NULL, + NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_3_ENCRYPTED_EXTENSIONS }, @@ -63,6 +69,8 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_srp, tls_parse_clienthello_srp, NULL, + NULL, + NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY }, #endif @@ -71,12 +79,16 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_ec_point_formats, tls_parse_clienthello_ec_pt_formats, NULL, + NULL, + NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_AND_BELOW_ONLY }, { TLSEXT_TYPE_supported_groups, tls_parse_clienthello_supported_groups, NULL, + NULL, + NULL, EXT_CLIENT_HELLO | EXT_TLS1_3_ENCRYPTED_EXTENSIONS }, #endif @@ -84,18 +96,24 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_session_ticket, tls_parse_clienthello_session_ticket, NULL, + NULL, + NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY }, { TLSEXT_TYPE_signature_algorithms, tls_parse_clienthello_sig_algs, NULL, + NULL, + NULL, EXT_CLIENT_HELLO }, { TLSEXT_TYPE_status_request, tls_parse_clienthello_status_request, NULL, + NULL, + NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_3_CERTIFICATE }, #ifndef OPENSSL_NO_NEXTPROTONEG @@ -103,6 +121,8 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_next_proto_neg, tls_parse_clienthello_npn, NULL, + NULL, + NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY }, #endif @@ -110,6 +130,8 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_application_layer_protocol_negotiation, tls_parse_clienthello_alpn, NULL, + NULL, + NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_3_ENCRYPTED_EXTENSIONS }, @@ -117,6 +139,8 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_use_srtp, tls_parse_clienthello_use_srtp, NULL, + NULL, + NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_3_ENCRYPTED_EXTENSIONS | EXT_DTLS_ONLY }, @@ -124,6 +148,8 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_encrypt_then_mac, tls_parse_clienthello_etm, NULL, + NULL, + NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY }, { @@ -135,6 +161,8 @@ static const EXTENSION_DEFINITION ext_defs[] = { */ NULL, NULL, + NULL, + NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_3_CERTIFICATE }, { @@ -148,6 +176,8 @@ static const EXTENSION_DEFINITION ext_defs[] = { /* Processed inline as part of version selection */ NULL, NULL, + NULL, + NULL, EXT_CLIENT_HELLO | EXT_TLS_IMPLEMENTATION_ONLY }, { @@ -155,12 +185,16 @@ static const EXTENSION_DEFINITION ext_defs[] = { /* We send this, but don't read it */ NULL, NULL, + NULL, + NULL, EXT_CLIENT_HELLO }, { TLSEXT_TYPE_key_share, tls_parse_clienthello_key_share, NULL, + NULL, + NULL, EXT_CLIENT_HELLO | EXT_TLS1_3_SERVER_HELLO | EXT_TLS1_3_HELLO_RETRY_REQUEST | EXT_TLS_IMPLEMENTATION_ONLY | EXT_TLS1_3_ONLY @@ -354,15 +388,33 @@ int tls_parse_all_extensions(SSL *s, RAW_EXTENSION *exts, size_t numexts, currext->parsed = 1; parser = NULL; - if (find_extension_definition(s, currext->type, &extdef)) + if (find_extension_definition(s, currext->type, &extdef)) { parser = s->server ? extdef->server_parse : extdef->client_parse; + /* Check if extension is defined for our protocol. If not, skip */ + if ((SSL_IS_DTLS(s) + && (extdef->context & EXT_TLS_IMPLEMENTATION_ONLY) != 0) + || (s->version == SSL3_VERSION + && (extdef->context & EXT_SSL3_ALLOWED) == 0) + || (SSL_IS_TLS13(s) + && (extdef->context & EXT_TLS1_2_AND_BELOW_ONLY) != 0) + || (!SSL_IS_TLS13(s) + && (extdef->context & EXT_TLS1_3_ONLY) != 0)) + continue; + } + if (parser == NULL) { /* * Could be a custom extension. We only allow this if it is a non - * resumed session on the server side + * resumed session on the server side. + * + * TODO(TLS1.3): We only allow old style <=TLS1.2 custom extensions. + * We're going to need a new mechanism for TLS1.3 to specify which + * messages to add the custom extensions to. */ if ((!s->hit || !s->server) + && (context + & (EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO)) != 0 && custom_ext_parse(s, s->server, currext->type, PACKET_data(&currext->data), PACKET_remaining(&currext->data), @@ -372,19 +424,6 @@ int tls_parse_all_extensions(SSL *s, RAW_EXTENSION *exts, size_t numexts, continue; } - /* Check if this extension is defined for our protocol. If not, skip */ - if ((SSL_IS_DTLS(s) - && (extdef->context & EXT_TLS_IMPLEMENTATION_ONLY) != 0) - || (s->version == SSL3_VERSION - && (extdef->context & EXT_SSL3_ALLOWED) == 0) - || (SSL_IS_TLS13(s) - && (extdef->context & EXT_TLS1_2_AND_BELOW_ONLY) != 0) - || (!SSL_IS_TLS13(s) - && (extdef->context & EXT_TLS1_3_ONLY) != 0) - || (s->server && extdef->server_parse == NULL) - || (!s->server && extdef->client_parse == NULL)) - continue; - if (!parser(s, &currext->data, al)) return 0; } @@ -409,6 +448,80 @@ int tls_parse_extension(SSL *s, int type, RAW_EXTENSION *exts, size_t numexts, return tls_parse_all_extensions(s, ext, 1, al); } +int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context, + int *al) +{ + size_t loop; + int addcustom = 0; + + if (!WPACKET_start_sub_packet_u16(pkt) + /* + * If extensions are of zero length then we don't even add the + * extensions length bytes to a ClientHello + */ + || ((context & EXT_CLIENT_HELLO) != 0 + && !WPACKET_set_flags(pkt, + WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH))) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_CONSTRUCT_EXTENSIONS, ERR_R_INTERNAL_ERROR); + return 0; + } + + for (loop = 0; loop < OSSL_NELEM(ext_defs); loop++) { + /* Skip if not relevant for our context */ + if ((ext_defs[loop].context & context) == 0) + continue; + + construct = s->server ? extdef->server_construct + : extdef->client_construct; + + /* Check if this extension is defined for our protocol. If not, skip */ + if ((SSL_IS_DTLS(s) + && (extdef->context & EXT_TLS_IMPLEMENTATION_ONLY) != 0) + || (s->version == SSL3_VERSION + && (extdef->context & EXT_SSL3_ALLOWED) == 0) + || (SSL_IS_TLS13(s) + && (extdef->context & EXT_TLS1_2_AND_BELOW_ONLY) != 0) + || (!SSL_IS_TLS13(s) + && ((extdef->context & EXT_TLS1_3_ONLY) != 0 + || (context & EXT_CLIENT_HELLO) != 0)) + || construct == NULL) + continue; + + if (!construct(s, pkt, al)) + return 0; + } + + + /* Add custom extensions */ + if ((context & EXT_CLIENT_HELLO) != 0) { + custom_ext_init(&s->cert->cli_ext); + addcustom = 1; + } else if (context & (EXT_TLS1_2_SERVER_HELLO) { + /* + * We already initialised the custom extensions during ClientHello + * parsing. + * + * TODO(TLS1.3): We're going to need a new custom extension mechanism + * for TLS1.3, so that custom extensions can specify which of the + * multiple message they wish to add themselves to. + */ + addcustom = 1; + } + if (addcustom && !custom_ext_add(s, s->server, pkt, al)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (!WPACKET_close(pkt)) { + *sl = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_CONSTRUCT_EXTENSIONS, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} + /* * Parse the client's renegotiation binding and abort if it's not right -- 2.34.1