Continue the extensions refactor
authorMatt Caswell <matt@openssl.org>
Thu, 24 Nov 2016 18:02:12 +0000 (18:02 +0000)
committerMatt Caswell <matt@openssl.org>
Thu, 8 Dec 2016 17:17:53 +0000 (17:17 +0000)
Add support for construction of extensions

Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
Salz

Reviewed-by: Rich Salz <rsalz@openssl.org>
Reviewed-by: Richard Levitte <levitte@openssl.org>
ssl/statem/extensions.c

index 2aad56b..82f1565 100644 (file)
@@ -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