Allow a client to send early_data with SNI if the session has no SNI
[openssl.git] / ssl / statem / extensions_clnt.c
index bcbcbac87325b476b49a34ce399b1b31c1d5a37f..0dc1c49734ede1d7345d434a1b4af8a519aa2401 100644 (file)
@@ -57,6 +57,31 @@ EXT_RETURN tls_construct_ctos_server_name(SSL *s, WPACKET *pkt,
     return EXT_RETURN_SENT;
 }
 
+/* Push a Max Fragment Len extension into ClientHello */
+EXT_RETURN tls_construct_ctos_maxfragmentlen(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx, int *al)
+{
+    if (s->ext.max_fragment_len_mode == TLSEXT_max_fragment_length_DISABLED)
+        return EXT_RETURN_NOT_SENT;
+
+    /* Add Max Fragment Length extension if client enabled it. */
+    /*-
+     * 4 bytes for this extension type and extension length
+     * 1 byte for the Max Fragment Length code value.
+     */
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_max_fragment_length)
+            /* Sub-packet for Max Fragment Length extension (1 byte) */
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_put_bytes_u8(pkt, s->ext.max_fragment_len_mode)
+            || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_MAXFRAGMENTLEN, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
 #ifndef OPENSSL_NO_SRP
 EXT_RETURN tls_construct_ctos_srp(SSL *s, WPACKET *pkt, unsigned int context,
                                   X509 *x, size_t chainidx, int *al)
@@ -139,8 +164,8 @@ EXT_RETURN tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
                                                unsigned int context, X509 *x,
                                                size_t chainidx, int *al)
 {
-    const unsigned char *pcurves = NULL, *pcurvestmp;
-    size_t num_curves = 0, i;
+    const uint16_t *pgroups = NULL;
+    size_t num_groups = 0, i;
 
     if (!use_ecc(s))
         return EXT_RETURN_NOT_SENT;
@@ -149,12 +174,7 @@ EXT_RETURN tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
      * Add TLS extension supported_groups to the ClientHello message
      */
     /* TODO(TLS1.3): Add support for DHE groups */
-    if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
-               ERR_R_INTERNAL_ERROR);
-        return EXT_RETURN_FAIL;
-    }
-    pcurvestmp = pcurves;
+    tls1_get_supported_groups(s, &pgroups, &num_groups);
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_groups)
                /* Sub-packet for supported_groups extension */
@@ -165,10 +185,11 @@ EXT_RETURN tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
         return EXT_RETURN_FAIL;
     }
     /* Copy curve ID if supported */
-    for (i = 0; i < num_curves; i++, pcurvestmp += 2) {
-        if (tls_curve_allowed(s, pcurvestmp, SSL_SECOP_CURVE_SUPPORTED)) {
-            if (!WPACKET_put_bytes_u8(pkt, pcurvestmp[0])
-                || !WPACKET_put_bytes_u8(pkt, pcurvestmp[1])) {
+    for (i = 0; i < num_groups; i++) {
+        uint16_t ctmp = pgroups[i];
+
+        if (tls_curve_allowed(s, ctmp, SSL_SECOP_CURVE_SUPPORTED)) {
+            if (!WPACKET_put_bytes_u16(pkt, ctmp)) {
                     SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
                            ERR_R_INTERNAL_ERROR);
                     return EXT_RETURN_FAIL;
@@ -549,7 +570,7 @@ static int add_key_share(SSL *s, WPACKET *pkt, unsigned int curve_id)
          */
         key_share_key = s->s3->tmp.pkey;
     } else {
-        key_share_key = ssl_generate_pkey_curve(curve_id);
+        key_share_key = ssl_generate_pkey_group(curve_id);
         if (key_share_key == NULL) {
             SSLerr(SSL_F_ADD_KEY_SHARE, ERR_R_EVP_LIB);
             return 0;
@@ -594,9 +615,9 @@ EXT_RETURN tls_construct_ctos_key_share(SSL *s, WPACKET *pkt,
                                         size_t chainidx, int *al)
 {
 #ifndef OPENSSL_NO_TLS1_3
-    size_t i, num_curves = 0;
-    const unsigned char *pcurves = NULL;
-    unsigned int curve_id = 0;
+    size_t i, num_groups = 0;
+    const uint16_t *pgroups = NULL;
+    uint16_t curve_id = 0;
 
     /* key_share extension */
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
@@ -608,10 +629,7 @@ EXT_RETURN tls_construct_ctos_key_share(SSL *s, WPACKET *pkt,
         return EXT_RETURN_FAIL;
     }
 
-    if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
-        return EXT_RETURN_FAIL;
-    }
+    tls1_get_supported_groups(s, &pgroups, &num_groups);
 
     /*
      * TODO(TLS1.3): Make the number of key_shares sent configurable. For
@@ -620,12 +638,12 @@ EXT_RETURN tls_construct_ctos_key_share(SSL *s, WPACKET *pkt,
     if (s->s3->group_id != 0) {
         curve_id = s->s3->group_id;
     } else {
-        for (i = 0; i < num_curves; i++, pcurves += 2) {
+        for (i = 0; i < num_groups; i++) {
 
-            if (!tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED))
+            if (!tls_curve_allowed(s, pgroups[i], SSL_SECOP_CURVE_SUPPORTED))
                 continue;
 
-            curve_id = bytestogroup(pcurves);
+            curve_id = pgroups[i];
             break;
         }
     }
@@ -679,7 +697,7 @@ EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt,
                                          unsigned int context, X509 *x,
                                          size_t chainidx, int *al)
 {
-    const unsigned char *id;
+    const unsigned char *id = NULL;
     size_t idlen = 0;
     SSL_SESSION *psksess = NULL;
     SSL_SESSION *edsess = NULL;
@@ -718,13 +736,14 @@ EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt,
     edsess = s->session->ext.max_early_data != 0 ? s->session : psksess;
     s->max_early_data = edsess->ext.max_early_data;
 
-    if ((s->ext.hostname == NULL && edsess->ext.hostname != NULL)
-            || (s->ext.hostname != NULL
-                && (edsess->ext.hostname == NULL
-                    || strcmp(s->ext.hostname, edsess->ext.hostname) != 0))) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA,
-               SSL_R_INCONSISTENT_EARLY_DATA_SNI);
-        return EXT_RETURN_FAIL;
+    if (edsess->ext.hostname != NULL) {
+        if (s->ext.hostname == NULL
+                || (s->ext.hostname != NULL
+                    && strcmp(s->ext.hostname, edsess->ext.hostname) != 0)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA,
+                   SSL_R_INCONSISTENT_EARLY_DATA_SNI);
+            return EXT_RETURN_FAIL;
+        }
     }
 
     if ((s->ext.alpn == NULL && edsess->ext.alpn_selected != NULL)) {
@@ -843,7 +862,7 @@ EXT_RETURN tls_construct_ctos_padding(SSL *s, WPACKET *pkt,
          * 1 byte long so as not to have an empty extension last (WebSphere 7.x,
          * 8.x are intolerant of that condition)
          */
-        if (hlen >= 4)
+        if (hlen > 4)
             hlen -= 4;
         else
             hlen = 1;
@@ -851,7 +870,7 @@ EXT_RETURN tls_construct_ctos_padding(SSL *s, WPACKET *pkt,
         if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_padding)
                 || !WPACKET_sub_allocate_bytes_u16(pkt, hlen, &padbytes)) {
             SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PADDING, ERR_R_INTERNAL_ERROR);
-            return 0;
+            return EXT_RETURN_FAIL;
         }
         memset(padbytes, 0, hlen);
     }
@@ -1052,7 +1071,7 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
  err:
     return ret;
 #else
-    return 1;
+    return EXT_RETURN_NOT_SENT;
 #endif
 }
 
@@ -1122,6 +1141,43 @@ int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
     return 1;
 }
 
+/* Parse the server's max fragment len extension packet */
+int tls_parse_stoc_maxfragmentlen(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al)
+{
+    unsigned int value;
+
+    if (PACKET_remaining(pkt) != 1 || !PACKET_get_1(pkt, &value)) {
+        *al = TLS1_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    /* |value| should contains a valid max-fragment-length code. */
+    if (!IS_MAX_FRAGMENT_LENGTH_EXT_VALID(value)) {
+        *al = SSL_AD_ILLEGAL_PARAMETER;
+        return 0;
+    }
+
+    /* Must be the same value as client-configured one who was sent to server */
+    /*-
+     * RFC 6066: if a client receives a maximum fragment length negotiation
+     * response that differs from the length it requested, ...
+     * It must abort with SSL_AD_ILLEGAL_PARAMETER alert
+     */
+    if (value != s->ext.max_fragment_len_mode) {
+        *al = SSL_AD_ILLEGAL_PARAMETER;
+        return 0;
+    }
+
+    /*
+     * Maximum Fragment Length Negotiation succeeded.
+     * The negotiated Maximum Fragment Length is binding now.
+     */
+    s->session->ext.max_fragment_len_mode = value;
+
+    return 1;
+}
+
 int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, unsigned int context,
                                X509 *x, size_t chainidx, int *al)
 {
@@ -1261,7 +1317,7 @@ int tls_parse_stoc_sct(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
         OPENSSL_free(s->ext.scts);
         s->ext.scts = NULL;
 
-        s->ext.scts_len = size;
+        s->ext.scts_len = (uint16_t)size;
         if (size > 0) {
             s->ext.scts = OPENSSL_malloc(size);
             if (s->ext.scts == NULL
@@ -1401,10 +1457,10 @@ int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
     }
     s->s3->alpn_selected_len = len;
 
-    if (s->session->ext.alpn_selected != NULL
-            && (s->session->ext.alpn_selected_len != len
-                || memcmp(s->session->ext.alpn_selected, s->s3->alpn_selected,
-                          len) != 0)) {
+    if (s->session->ext.alpn_selected == NULL
+            || s->session->ext.alpn_selected_len != len
+            || memcmp(s->session->ext.alpn_selected, s->s3->alpn_selected, len)
+               != 0) {
         /* ALPN not consistent with the old session so cannot use early_data */
         s->ext.early_data_ok = 0;
     }
@@ -1521,8 +1577,8 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
     }
 
     if ((context & SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST) != 0) {
-        unsigned const char *pcurves = NULL;
-        size_t i, num_curves;
+        const uint16_t *pgroups = NULL;
+        size_t i, num_groups;
 
         if (PACKET_remaining(pkt) != 0) {
             *al = SSL_AD_DECODE_ERROR;
@@ -1541,16 +1597,13 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
         }
 
         /* Validate the selected group is one we support */
-        if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
-            SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-        for (i = 0; i < num_curves; i++, pcurves += 2) {
-            if (group_id == bytestogroup(pcurves))
+        tls1_get_supported_groups(s, &pgroups, &num_groups);
+        for (i = 0; i < num_groups; i++) {
+            if (group_id == pgroups[i])
                 break;
         }
-        if (i >= num_curves
-                || !tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED)) {
+        if (i >= num_groups
+                || !tls_curve_allowed(s, group_id, SSL_SECOP_CURVE_SUPPORTED)) {
             *al = SSL_AD_ILLEGAL_PARAMETER;
             SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_BAD_KEY_SHARE);
             return 0;