Add the ability to send the supported_versions extension
[openssl.git] / ssl / t1_lib.c
index e8357afe0da51c7f055ee455d957dddbb64822d0..515b4e33af5c698789abe19fe64d501f5ab05a87 100644 (file)
@@ -1371,6 +1371,40 @@ int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al)
         return 0;
     }
 
+
+    /* TODO(TLS1.3): Should we add this extension for versions < TLS1.3? */
+    if (!SSL_IS_DTLS(s) && s->version >= TLS1_3_VERSION) {
+        int min_version, max_version, reason, currv;
+        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_versions)
+                || !WPACKET_start_sub_packet_u16(pkt)
+                || !WPACKET_start_sub_packet_u8(pkt)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        reason = ssl_get_client_min_max_version(s, &min_version, &max_version);
+        if (reason != 0) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, reason);
+            return 0;
+        }
+        for (currv = max_version; currv >= min_version; currv--) {
+            /* TODO(TLS1.3): Remove this first if clause prior to release!! */
+            if (currv == TLS1_3_VERSION) {
+                if (!WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT)) {
+                    SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT,
+                           ERR_R_INTERNAL_ERROR);
+                    return 0;
+                }
+            } else if (!WPACKET_put_bytes_u16(pkt, currv)) {
+                SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        }
+        if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+
     /*
      * Add padding to workaround bugs in F5 terminators. See
      * https://tools.ietf.org/html/draft-agl-tls-padding-03 NB: because this
@@ -1690,7 +1724,7 @@ static int tls1_alpn_handle_client_hello_late(SSL *s, int *al)
 #ifndef OPENSSL_NO_EC
 /*-
  * ssl_check_for_safari attempts to fingerprint Safari using OS X
- * SecureTransport using the TLS extension block in |pkt|.
+ * SecureTransport using the TLS extension block in |hello|.
  * Safari, since 10.6, sends exactly these extensions, in this order:
  *   SNI,
  *   elliptic_curves
@@ -1701,7 +1735,7 @@ static int tls1_alpn_handle_client_hello_late(SSL *s, int *al)
  * Sadly we cannot differentiate 10.6, 10.7 and 10.8.4 (which work), from
  * 10.8..10.8.3 (which don't work).
  */
-static void ssl_check_for_safari(SSL *s, CLIENTHELLO_MSG *hello)
+static void ssl_check_for_safari(SSL *s, const CLIENTHELLO_MSG *hello)
 {
     unsigned int type;
     PACKET sni, tmppkt;
@@ -1753,14 +1787,15 @@ static void ssl_check_for_safari(SSL *s, CLIENTHELLO_MSG *hello)
 #endif                          /* !OPENSSL_NO_EC */
 
 /*
- * Parse ClientHello extensions and stash extension info in various parts of
- * the SSL object. Verify that there are no duplicate extensions.
+ * Loop through all remaining ClientHello extensions that we collected earlier
+ * and haven't already processed. For each one parse it and update the SSL
+ * object as required.
  *
  * Behaviour upon resumption is extension-specific. If the extension has no
  * effect during resumption, it is parsed (to verify its format) but otherwise
  * ignored.
  *
- * Consumes the entire packet in |pkt|. Returns 1 on success and 0 on failure.
+ * Returns 1 on success and 0 on failure.
  * Upon failure, sets |al| to the appropriate alert.
  */
 static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
@@ -1809,15 +1844,17 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
      * resumption.
      */
     for (loop = 0; loop < hello->num_extensions; loop++) {
+        RAW_EXTENSION *currext = &hello->pre_proc_exts[loop];
+
         if (s->tlsext_debug_cb)
-            s->tlsext_debug_cb(s, 0, hello->pre_proc_exts[loop].type,
-                               PACKET_data(&hello->pre_proc_exts[loop].data),
-                               PACKET_remaining(&hello->pre_proc_exts[loop].data),
+            s->tlsext_debug_cb(s, 0, currext->type,
+                               PACKET_data(&currext->data),
+                               PACKET_remaining(&currext->data),
                                s->tlsext_debug_arg);
 
-        if (hello->pre_proc_exts[loop].type == TLSEXT_TYPE_renegotiate) {
+        if (currext->type == TLSEXT_TYPE_renegotiate) {
             if (!ssl_parse_clienthello_renegotiate_ext(s,
-                    &hello->pre_proc_exts[loop].data, al))
+                    &currext->data, al))
                 return 0;
             renegotiate_seen = 1;
         } else if (s->version == SSL3_VERSION) {
@@ -1847,12 +1884,11 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
  *
  */
 
-        else if (hello->pre_proc_exts[loop].type == TLSEXT_TYPE_server_name) {
+        else if (currext->type == TLSEXT_TYPE_server_name) {
             unsigned int servname_type;
             PACKET sni, hostname;
 
-            if (!PACKET_as_length_prefixed_2(&hello->pre_proc_exts[loop].data,
-                                             &sni)
+            if (!PACKET_as_length_prefixed_2(&currext->data, &sni)
                 /* ServerNameList must be at least 1 byte long. */
                 || PACKET_remaining(&sni) == 0) {
                 return 0;
@@ -1904,11 +1940,10 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
             }
         }
 #ifndef OPENSSL_NO_SRP
-        else if (hello->pre_proc_exts[loop].type == TLSEXT_TYPE_srp) {
+        else if (currext->type == TLSEXT_TYPE_srp) {
             PACKET srp_I;
 
-            if (!PACKET_as_length_prefixed_1(&hello->pre_proc_exts[loop].data,
-                                             &srp_I))
+            if (!PACKET_as_length_prefixed_1(&currext->data, &srp_I))
                 return 0;
 
             if (PACKET_contains_zero_byte(&srp_I))
@@ -1926,11 +1961,10 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
 #endif
 
 #ifndef OPENSSL_NO_EC
-        else if (hello->pre_proc_exts[loop].type
-                 == TLSEXT_TYPE_ec_point_formats) {
+        else if (currext->type == TLSEXT_TYPE_ec_point_formats) {
             PACKET ec_point_format_list;
 
-            if (!PACKET_as_length_prefixed_1(&hello->pre_proc_exts[loop].data,
+            if (!PACKET_as_length_prefixed_1(&currext->data,
                                              &ec_point_format_list)
                 || PACKET_remaining(&ec_point_format_list) == 0) {
                 return 0;
@@ -1945,12 +1979,11 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
                     return 0;
                 }
             }
-        } else if (hello->pre_proc_exts[loop].type
-                   == TLSEXT_TYPE_elliptic_curves) {
+        } else if (currext->type == TLSEXT_TYPE_elliptic_curves) {
             PACKET elliptic_curve_list;
 
             /* Each NamedCurve is 2 bytes and we must have at least 1. */
-            if (!PACKET_as_length_prefixed_2(&hello->pre_proc_exts[loop].data,
+            if (!PACKET_as_length_prefixed_2(&currext->data,
                                              &elliptic_curve_list)
                 || PACKET_remaining(&elliptic_curve_list) == 0
                 || (PACKET_remaining(&elliptic_curve_list) % 2) != 0) {
@@ -1968,21 +2001,19 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
             }
         }
 #endif                          /* OPENSSL_NO_EC */
-        else if (hello->pre_proc_exts[loop].type
-                 == TLSEXT_TYPE_session_ticket) {
+        else if (currext->type == TLSEXT_TYPE_session_ticket) {
             if (s->tls_session_ticket_ext_cb &&
                 !s->tls_session_ticket_ext_cb(s,
-                    PACKET_data(&hello->pre_proc_exts[loop].data),
-                    PACKET_remaining(&hello->pre_proc_exts[loop].data),
+                    PACKET_data(&currext->data),
+                    PACKET_remaining(&currext->data),
                     s->tls_session_ticket_ext_cb_arg)) {
                 *al = TLS1_AD_INTERNAL_ERROR;
                 return 0;
             }
-        } else if (hello->pre_proc_exts[loop].type
-                   == TLSEXT_TYPE_signature_algorithms) {
+        } else if (currext->type == TLSEXT_TYPE_signature_algorithms) {
             PACKET supported_sig_algs;
 
-            if (!PACKET_as_length_prefixed_2(&hello->pre_proc_exts[loop].data,
+            if (!PACKET_as_length_prefixed_2(&currext->data,
                                              &supported_sig_algs)
                 || (PACKET_remaining(&supported_sig_algs) % 2) != 0
                 || PACKET_remaining(&supported_sig_algs) == 0) {
@@ -1995,9 +2026,8 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
                     return 0;
                 }
             }
-        } else if (hello->pre_proc_exts[loop].type
-                   == TLSEXT_TYPE_status_request) {
-            if (!PACKET_get_1(&hello->pre_proc_exts[loop].data,
+        } else if (currext->type == TLSEXT_TYPE_status_request) {
+            if (!PACKET_get_1(&currext->data,
                               (unsigned int *)&s->tlsext_status_type)) {
                 return 0;
             }
@@ -2006,7 +2036,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
                 const unsigned char *ext_data;
                 PACKET responder_id_list, exts;
                 if (!PACKET_get_length_prefixed_2
-                    (&hello->pre_proc_exts[loop].data, &responder_id_list))
+                    (&currext->data, &responder_id_list))
                     return 0;
 
                 /*
@@ -2057,7 +2087,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
 
                 /* Read in request_extensions */
                 if (!PACKET_as_length_prefixed_2(
-                        &hello->pre_proc_exts[loop].data, &exts))
+                        &currext->data, &exts))
                     return 0;
 
                 if (PACKET_remaining(&exts) > 0) {
@@ -2082,12 +2112,11 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
             }
         }
 #ifndef OPENSSL_NO_HEARTBEATS
-        else if (SSL_IS_DTLS(s)
-                 && hello->pre_proc_exts[loop].type == TLSEXT_TYPE_heartbeat) {
+        else if (SSL_IS_DTLS(s) && currext->type == TLSEXT_TYPE_heartbeat) {
             unsigned int hbtype;
 
-            if (!PACKET_get_1(&hello->pre_proc_exts[loop].data, &hbtype)
-                || PACKET_remaining(&hello->pre_proc_exts[loop].data)) {
+            if (!PACKET_get_1(&currext->data, &hbtype)
+                || PACKET_remaining(&currext->data)) {
                 *al = SSL_AD_DECODE_ERROR;
                 return 0;
             }
@@ -2106,7 +2135,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
         }
 #endif
 #ifndef OPENSSL_NO_NEXTPROTONEG
-        else if (hello->pre_proc_exts[loop].type == TLSEXT_TYPE_next_proto_neg
+        else if (currext->type == TLSEXT_TYPE_next_proto_neg
                  && s->s3->tmp.finish_md_len == 0) {
             /*-
              * We shouldn't accept this extension on a
@@ -2129,24 +2158,24 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
         }
 #endif
 
-        else if (hello->pre_proc_exts[loop].type
+        else if (currext->type
                      == TLSEXT_TYPE_application_layer_protocol_negotiation
                  && s->s3->tmp.finish_md_len == 0) {
             if (!tls1_alpn_handle_client_hello(s,
-                    &hello->pre_proc_exts[loop].data, al))
+                    &currext->data, al))
                 return 0;
         }
 
         /* session ticket processed earlier */
 #ifndef OPENSSL_NO_SRTP
         else if (SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s)
-                 && hello->pre_proc_exts[loop].type == TLSEXT_TYPE_use_srtp) {
+                 && currext->type == TLSEXT_TYPE_use_srtp) {
             if (ssl_parse_clienthello_use_srtp_ext(s,
-                    &hello->pre_proc_exts[loop].data, al))
+                    &currext->data, al))
                 return 0;
         }
 #endif
-        else if (hello->pre_proc_exts[loop].type == TLSEXT_TYPE_encrypt_then_mac
+        else if (currext->type == TLSEXT_TYPE_encrypt_then_mac
                  && !(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC))
             s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC;
         /*
@@ -2162,9 +2191,9 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
          * ServerHello may be later returned.
          */
         else if (!s->hit) {
-            if (custom_ext_parse(s, 1, hello->pre_proc_exts[loop].type,
-                    PACKET_data(&hello->pre_proc_exts[loop].data),
-                    PACKET_remaining(&hello->pre_proc_exts[loop].data), al) <= 0)
+            if (custom_ext_parse(s, 1, currext->type,
+                    PACKET_data(&currext->data),
+                    PACKET_remaining(&currext->data), al) <= 0)
                 return 0;
         }
     }
@@ -2787,6 +2816,16 @@ int ssl_parse_serverhello_tlsext(SSL *s, PACKET *pkt)
     return 1;
 }
 
+/*
+ * Given a list of extensions that we collected earlier, find one of a given
+ * type and return it.
+ *
+ * |exts| is the set of extensions previously collected.
+ * |numexts| is the number of extensions that we have.
+ * |type| the type of the extension that we are looking for.
+ *
+ * Returns a pointer to the found RAW_EXTENSION data, or NULL if not found.
+ */
 static RAW_EXTENSION *get_extension_by_type(RAW_EXTENSION *exts, size_t numexts,
                                             unsigned int type)
 {
@@ -2894,10 +2933,13 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
 }
 
 /*
- * Sets the extended master secret flag is set if the extension is present
- * in the ClientHello
+ * Sets the extended master secret flag if the extension is present in the
+ * ClientHello
+ * Returns:
+ *  1 on success
+ *  0 on error
  */
-int tls_check_client_ems_support(SSL *s, CLIENTHELLO_MSG *hello)
+int tls_check_client_ems_support(SSL *s, const CLIENTHELLO_MSG *hello)
 {
     RAW_EXTENSION *emsext;