Implement Maximum Fragment Length TLS extension.
[openssl.git] / ssl / statem / extensions_srvr.c
index 3da9f556e9453a76361bce0340a7f724d44f7d69..1b56fa1b88d9aac46c66fceaa7aca97d155002af 100644 (file)
@@ -87,10 +87,9 @@ int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, unsigned int context,
     }
 
     /*
-     * Although the server_name extension was intended to be
-     * extensible to new name types, RFC 4366 defined the
-     * syntax inextensibly and OpenSSL 1.0.x parses it as
-     * such.
+     * Although the intent was for server_name to be extensible, RFC 4366
+     * was not clear about it; and so OpenSSL among other implementations,
+     * always and only allows a 'host_name' name types.
      * RFC 6066 corrected the mistake but adding new name types
      * is nevertheless no longer feasible, so act as if no other
      * SNI types can exist, to simplify parsing.
@@ -132,11 +131,48 @@ int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, unsigned int context,
         s->servername_done = s->session->ext.hostname
             && PACKET_equal(&hostname, s->session->ext.hostname,
                             strlen(s->session->ext.hostname));
+
+        if (!s->servername_done && s->session->ext.hostname != NULL)
+            s->ext.early_data_ok = 0;
     }
 
     return 1;
 }
 
+int tls_parse_ctos_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;
+    }
+
+    /* Received |value| should be a valid max-fragment-length code. */
+    if (!IS_MAX_FRAGMENT_LENGTH_EXT_VALID(value)) {
+        *al = SSL_AD_ILLEGAL_PARAMETER;
+        return 0;
+    }
+
+    /*
+     * RFC 6066:  The negotiated length applies for the duration of the session
+     * including session resumptions.
+     * We should receive the same code as in resumed session !
+     */
+    if (s->hit && s->session->ext.max_fragment_len_mode != value) {
+        *al = SSL_AD_ILLEGAL_PARAMETER;
+        return 0;
+    }
+
+    /*
+     * Store it in session, so it'll become binding for us
+     * and we'll include it in a next Server Hello.
+     */
+    s->session->ext.max_fragment_len_mode = value;
+    return 1;
+}
+
 #ifndef OPENSSL_NO_SRP
 int tls_parse_ctos_srp(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
                        size_t chainidx, int *al)
@@ -477,7 +513,8 @@ int tls_parse_ctos_psk_kex_modes(SSL *s, PACKET *pkt, unsigned int context,
     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)
+        else if (mode == TLSEXT_KEX_MODE_KE
+                && (s->options & SSL_OP_ALLOW_NO_DHE_KEX) != 0)
             s->ext.psk_kex_mode |= TLSEXT_KEX_MODE_FLAG_KE;
     }
 #endif
@@ -496,10 +533,9 @@ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
 #ifndef OPENSSL_NO_TLS1_3
     unsigned int group_id;
     PACKET key_share_list, encoded_pt;
-    const unsigned char *clntcurves, *srvrcurves;
-    size_t clnt_num_curves, srvr_num_curves;
-    int group_nid, found = 0;
-    unsigned int curve_flags;
+    const uint16_t *clntgroups, *srvrgroups;
+    size_t clnt_num_groups, srvr_num_groups;
+    int found = 0;
 
     if (s->hit && (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE_DHE) == 0)
         return 1;
@@ -517,20 +553,11 @@ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
         return 0;
     }
 
-    /* Get our list of supported curves */
-    if (!tls1_get_curvelist(s, 0, &srvrcurves, &srvr_num_curves)) {
-        *al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-
-    /* Get the clients list of supported curves. */
-    if (!tls1_get_curvelist(s, 1, &clntcurves, &clnt_num_curves)) {
-        *al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-    if (clnt_num_curves == 0) {
+    /* Get our list of supported groups */
+    tls1_get_supported_groups(s, &srvrgroups, &srvr_num_groups);
+    /* Get the clients list of supported groups. */
+    tls1_get_peer_groups(s, &clntgroups, &clnt_num_groups);
+    if (clnt_num_groups == 0) {
         /*
          * This can only happen if the supported_groups extension was not sent,
          * because we verify that the length is non-zero when we process that
@@ -560,55 +587,25 @@ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
             continue;
 
         /* Check if this share is in supported_groups sent from client */
-        if (!check_in_list(s, group_id, clntcurves, clnt_num_curves, 0)) {
+        if (!check_in_list(s, group_id, clntgroups, clnt_num_groups, 0)) {
             *al = SSL_AD_ILLEGAL_PARAMETER;
             SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_BAD_KEY_SHARE);
             return 0;
         }
 
         /* Check if this share is for a group we can use */
-        if (!check_in_list(s, group_id, srvrcurves, srvr_num_curves, 1)) {
+        if (!check_in_list(s, group_id, srvrgroups, srvr_num_groups, 1)) {
             /* Share not suitable */
             continue;
         }
 
-        group_nid = tls1_ec_curve_id2nid(group_id, &curve_flags);
-
-        if (group_nid == 0) {
+        if ((s->s3->peer_tmp = ssl_generate_param_group(group_id)) == NULL) {
             *al = SSL_AD_INTERNAL_ERROR;
             SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE,
                    SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
             return 0;
         }
 
-        if ((curve_flags & TLS_CURVE_TYPE) == TLS_CURVE_CUSTOM) {
-            /* Can happen for some curves, e.g. X25519 */
-            EVP_PKEY *key = EVP_PKEY_new();
-
-            if (key == NULL || !EVP_PKEY_set_type(key, group_nid)) {
-                *al = SSL_AD_INTERNAL_ERROR;
-                SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_EVP_LIB);
-                EVP_PKEY_free(key);
-                return 0;
-            }
-            s->s3->peer_tmp = key;
-        } else {
-            /* Set up EVP_PKEY with named curve as parameters */
-            EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
-
-            if (pctx == NULL
-                    || EVP_PKEY_paramgen_init(pctx) <= 0
-                    || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx,
-                                                              group_nid) <= 0
-                    || EVP_PKEY_paramgen(pctx, &s->s3->peer_tmp) <= 0) {
-                *al = SSL_AD_INTERNAL_ERROR;
-                SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_EVP_LIB);
-                EVP_PKEY_CTX_free(pctx);
-                return 0;
-            }
-            EVP_PKEY_CTX_free(pctx);
-            pctx = NULL;
-        }
         s->s3->group_id = group_id;
 
         if (!EVP_PKEY_set1_tls_encodedpoint(s->s3->peer_tmp,
@@ -640,14 +637,16 @@ int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, unsigned int context,
         return 0;
     }
 
-    OPENSSL_free(s->session->ext.supportedgroups);
-    s->session->ext.supportedgroups = NULL;
-    s->session->ext.supportedgroups_len = 0;
-    if (!PACKET_memdup(&supported_groups_list,
-                       &s->session->ext.supportedgroups,
-                       &s->session->ext.supportedgroups_len)) {
-        *al = SSL_AD_INTERNAL_ERROR;
-        return 0;
+    if (!s->hit || SSL_IS_TLS13(s)) {
+        OPENSSL_free(s->session->ext.supportedgroups);
+        s->session->ext.supportedgroups = NULL;
+        s->session->ext.supportedgroups_len = 0;
+        if (!tls1_save_u16(&supported_groups_list,
+                           &s->session->ext.supportedgroups,
+                           &s->session->ext.supportedgroups_len)) {
+            *al = SSL_AD_INTERNAL_ERROR;
+            return 0;
+        }
     }
 
     return 1;
@@ -677,6 +676,11 @@ int tls_parse_ctos_early_data(SSL *s, PACKET *pkt, unsigned int context,
         return 0;
     }
 
+    if (s->hello_retry_request) {
+        *al = SSL_AD_ILLEGAL_PARAMETER;
+        return 0;
+    }
+
     return 1;
 }
 
@@ -738,6 +742,8 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
             memcpy(sess->sid_ctx, s->sid_ctx, s->sid_ctx_length);
             sess->sid_ctx_length = s->sid_ctx_length;
             ext = 1;
+            if (id == 0)
+                s->ext.early_data_ok = 1;
         } else {
             uint32_t ticket_age = 0, now, agesec, agems;
             int ret = tls_decrypt_ticket(s, PACKET_data(&identity),
@@ -766,7 +772,8 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
              * Therefore we add 1000ms to our age calculation to adjust for
              * rounding errors.
              */
-            if (sess->timeout >= (long)agesec
+            if (id == 0
+                    && sess->timeout >= (long)agesec
                     && agems / (uint32_t)1000 == agesec
                     && ticket_age <= agems + 1000
                     && ticket_age + TICKET_AGE_ALLOWANCE >= agems + 1000) {
@@ -783,6 +790,7 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
             /* The ciphersuite is not compatible with this session. */
             SSL_SESSION_free(sess);
             sess = NULL;
+            s->ext.early_data_ok = 0;
             continue;
         }
         break;
@@ -870,6 +878,29 @@ EXT_RETURN tls_construct_stoc_server_name(SSL *s, WPACKET *pkt,
     return EXT_RETURN_SENT;
 }
 
+/* Add/include the server's max fragment len extension into ServerHello */
+EXT_RETURN tls_construct_stoc_maxfragmentlen(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx, int *al)
+{
+    if (!USE_MAX_FRAGMENT_LENGTH_EXT(s->session))
+        return EXT_RETURN_NOT_SENT;
+
+    /*-
+     * 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)
+        || !WPACKET_start_sub_packet_u16(pkt)
+        || !WPACKET_put_bytes_u8(pkt, s->session->ext.max_fragment_len_mode)
+        || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_MAXFRAGMENTLEN, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    return EXT_RETURN_SENT;
+}
+
 #ifndef OPENSSL_NO_EC
 EXT_RETURN tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt,
                                             unsigned int context, X509 *x,
@@ -903,7 +934,7 @@ EXT_RETURN tls_construct_stoc_supported_groups(SSL *s, WPACKET *pkt,
                                                unsigned int context, X509 *x,
                                                size_t chainidx, int *al)
 {
-    const unsigned char *groups;
+    const uint16_t *groups;
     size_t numgroups, i, first = 1;
 
     /* s->s3->group_id is non zero if we accepted a key_share */
@@ -911,20 +942,23 @@ EXT_RETURN tls_construct_stoc_supported_groups(SSL *s, WPACKET *pkt,
         return EXT_RETURN_NOT_SENT;
 
     /* Get our list of supported groups */
-    if (!tls1_get_curvelist(s, 0, &groups, &numgroups) || numgroups == 0) {
+    tls1_get_supported_groups(s, &groups, &numgroups);
+    if (numgroups == 0) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS, ERR_R_INTERNAL_ERROR);
         return EXT_RETURN_FAIL;
     }
 
     /* Copy group ID if supported */
-    for (i = 0; i < numgroups; i++, groups += 2) {
-        if (tls_curve_allowed(s, groups, SSL_SECOP_CURVE_SUPPORTED)) {
+    for (i = 0; i < numgroups; i++) {
+        uint16_t group = groups[i];
+
+        if (tls_curve_allowed(s, group, SSL_SECOP_CURVE_SUPPORTED)) {
             if (first) {
                 /*
                  * Check if the client is already using our preferred group. If
                  * so we don't need to add this extension
                  */
-                if (s->s3->group_id == GET_GROUP_ID(groups, 0))
+                if (s->s3->group_id == group)
                     return EXT_RETURN_NOT_SENT;
 
                 /* Add extension header */
@@ -939,7 +973,7 @@ EXT_RETURN tls_construct_stoc_supported_groups(SSL *s, WPACKET *pkt,
 
                 first = 0;
             }
-            if (!WPACKET_put_bytes_u16(pkt, GET_GROUP_ID(groups, 0))) {
+            if (!WPACKET_put_bytes_u16(pkt, group)) {
                     SSLerr(SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS,
                            ERR_R_INTERNAL_ERROR);
                     return EXT_RETURN_FAIL;