Merge pull request #4864 from hanno-arm/upstream_sig_alg_identifers

TLS 1.3 MVP: Upstream TLS 1.3 SignatureAlgorithm identifiers and configuration API
diff --git a/.travis.yml b/.travis.yml
index 48faa48..39ae19c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,6 +14,8 @@
           - graphviz
           - gcc-arm-none-eabi
           - libnewlib-arm-none-eabi
+          - gcc-arm-linux-gnueabi
+          - libc6-dev-armel-cross
       language: python # Needed to get pip for Python 3
       python: 3.5 # version from Ubuntu 16.04
       install:
@@ -22,7 +24,7 @@
         - tests/scripts/all.sh -k 'check_*'
         - tests/scripts/all.sh -k test_default_out_of_box
         - tests/scripts/all.sh -k test_ref_configs
-        - tests/scripts/all.sh -k build_arm_none_eabi_gcc_arm5vte build_arm_none_eabi_gcc_m0plus
+        - tests/scripts/all.sh -k build_arm_linux_gnueabi_gcc_arm5vte build_arm_none_eabi_gcc_m0plus
 
     - name: full configuration
       script:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cf74af5..210aba4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -330,7 +330,7 @@
     DESTINATION "cmake"
     FILE "MbedTLSTargets.cmake")
 
-if(CMAKE_VERSION VERSION_GREATER 3.14)
+if(CMAKE_VERSION VERSION_GREATER 3.15 OR CMAKE_VERSION VERSION_EQUAL 3.15)
     # Do not export the package by default
     cmake_policy(SET CMP0090 NEW)
 
diff --git a/ChangeLog.d/tls_ext_cid-config.txt b/ChangeLog.d/tls_ext_cid-config.txt
new file mode 100644
index 0000000..b7b1e72
--- /dev/null
+++ b/ChangeLog.d/tls_ext_cid-config.txt
@@ -0,0 +1,3 @@
+Features
+   * The identifier of the CID TLS extension can be configured by defining
+     MBEDTLS_TLS_EXT_CID at compile time.
diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h
index a60db7e..d470c00 100644
--- a/include/mbedtls/mbedtls_config.h
+++ b/include/mbedtls/mbedtls_config.h
@@ -3194,6 +3194,17 @@
 //#define MBEDTLS_PSK_MAX_LEN               32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */
 //#define MBEDTLS_SSL_COOKIE_TIMEOUT        60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */
 
+/** \def MBEDTLS_TLS_EXT_CID
+ *
+ * At the time of writing, the CID extension has not been assigned its
+ * final value. Set this configuration option to make Mbed TLS use a
+ * different value.
+ *
+ * A future minor revision of Mbed TLS may change the default value of
+ * this option to match evolving standards and usage.
+ */
+//#define MBEDTLS_TLS_EXT_CID                        254
+
 /**
  * Complete list of ciphersuites to use, in order of preference.
  *
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index f537e86..f08fc89 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -460,8 +460,14 @@
 
 /* The value of the CID extension is still TBD as of
  * draft-ietf-tls-dtls-connection-id-05
- * (https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05) */
+ * (https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05).
+ *
+ * A future minor revision of Mbed TLS may change the default value of
+ * this option to match evolving standards and usage.
+ */
+#if !defined(MBEDTLS_TLS_EXT_CID)
 #define MBEDTLS_TLS_EXT_CID                        254 /* TBD */
+#endif
 
 #define MBEDTLS_TLS_EXT_ECJPAKE_KKPP               256 /* experimental */
 
@@ -572,10 +578,11 @@
  * \param buf      Buffer to write the received data to
  * \param len      Length of the receive buffer
  *
- * \return         The callback must return the number of bytes received,
- *                 or a non-zero error code.
- *                 If performing non-blocking I/O, \c MBEDTLS_ERR_SSL_WANT_READ
+ * \returns        If data has been received, the positive number of bytes received.
+ * \returns        \c 0 if the connection has been closed.
+ * \returns        If performing non-blocking I/O, \c MBEDTLS_ERR_SSL_WANT_READ
  *                 must be returned when the operation would block.
+ * \returns        Another negative error code on other kinds of failures.
  *
  * \note           The callback may receive fewer bytes than the length of the
  *                 buffer. It must always return the number of bytes actually
@@ -1367,10 +1374,24 @@
     /*
      * Record layer transformations
      */
-    mbedtls_ssl_transform *MBEDTLS_PRIVATE(transform_in);        /*!<  current transform params (in)   */
-    mbedtls_ssl_transform *MBEDTLS_PRIVATE(transform_out);       /*!<  current transform params (in)   */
-    mbedtls_ssl_transform *MBEDTLS_PRIVATE(transform);           /*!<  negotiated transform params     */
-    mbedtls_ssl_transform *MBEDTLS_PRIVATE(transform_negotiate); /*!<  transform params in negotiation */
+    mbedtls_ssl_transform *MBEDTLS_PRIVATE(transform_in);        /*!<  current transform params (in)
+                                                                  *    This is always a reference,
+                                                                  *    never an owning pointer.        */
+    mbedtls_ssl_transform *MBEDTLS_PRIVATE(transform_out);       /*!<  current transform params (out)
+                                                                  *    This is always a reference,
+                                                                  *    never an owning pointer.        */
+    mbedtls_ssl_transform *MBEDTLS_PRIVATE(transform);           /*!<  negotiated transform params
+                                                                  *    This pointer owns the transform
+                                                                  *    it references.                  */
+    mbedtls_ssl_transform *MBEDTLS_PRIVATE(transform_negotiate); /*!<  transform params in negotiation
+                                                                  *    This pointer owns the transform
+                                                                  *    it references.                  */
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)
+    /*! The application data transform in TLS 1.3.
+     *  This pointer owns the transform it references. */
+    mbedtls_ssl_transform *MBEDTLS_PRIVATE(transform_application);
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */
 
     /*
      * Timers
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index e0a1c24..59c5460 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -4210,23 +4210,8 @@
 {
     int ret = 0;
 
-    if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER || ssl->handshake == NULL )
-        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
-
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "client state: %d", ssl->state ) );
 
-    if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 )
-        return( ret );
-
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
-        ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING )
-    {
-        if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
-            return( ret );
-    }
-#endif /* MBEDTLS_SSL_PROTO_DTLS */
-
     /* Change state now, so that it is right in mbedtls_ssl_read_record(), used
      * by DTLS for dropping out-of-sequence ChangeCipherSpec records */
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
diff --git a/library/ssl_misc.h b/library/ssl_misc.h
index c8e2f4c..b4f841a 100644
--- a/library/ssl_misc.h
+++ b/library/ssl_misc.h
@@ -562,6 +562,13 @@
     uint16_t mtu;                       /*!<  Handshake mtu, used to fragment outgoing messages */
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)
+    /*! TLS 1.3 transforms for 0-RTT and encrypted handshake messages.
+     *  Those pointers own the transforms they reference. */
+    mbedtls_ssl_transform *transform_handshake;
+    mbedtls_ssl_transform *transform_earlydata;
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */
+
     /*
      * Checksum contexts
      */
@@ -740,7 +747,8 @@
 
 #if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
     /* We need the Hello random bytes in order to re-derive keys from the
-     * Master Secret and other session info, see ssl_populate_transform() */
+     * Master Secret and other session info,
+     * see ssl_tls12_populate_transform() */
     unsigned char randbytes[64]; /*!< ServerHello.random+ClientHello.random */
 #endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
 };
@@ -975,7 +983,13 @@
                              unsigned update_hs_digest );
 int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want );
 
-int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl );
+int mbedtls_ssl_write_handshake_msg_ext( mbedtls_ssl_context *ssl,
+                                         int update_checksum );
+static inline int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl )
+{
+    return( mbedtls_ssl_write_handshake_msg_ext( ssl, 1 /* update checksum */ ) );
+}
+
 int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush );
 int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl );
 
diff --git a/library/ssl_msg.c b/library/ssl_msg.c
index 76cc2b1..a03f192 100644
--- a/library/ssl_msg.c
+++ b/library/ssl_msg.c
@@ -384,7 +384,8 @@
 static void ssl_extract_add_data_from_record( unsigned char* add_data,
                                               size_t *add_data_len,
                                               mbedtls_record *rec,
-                                              unsigned minor_ver )
+                                              unsigned minor_ver,
+                                              size_t taglen )
 {
     /* Quoting RFC 5246 (TLS 1.2):
      *
@@ -403,15 +404,37 @@
      *
      * For TLS 1.3, the record sequence number is dropped from the AAD
      * and encoded within the nonce of the AEAD operation instead.
+     * Moreover, the additional data involves the length of the TLS
+     * ciphertext, not the TLS plaintext as in earlier versions.
+     * Quoting RFC 8446 (TLS 1.3):
+     *
+     *      additional_data = TLSCiphertext.opaque_type ||
+     *                        TLSCiphertext.legacy_record_version ||
+     *                        TLSCiphertext.length
+     *
+     * We pass the tag length to this function in order to compute the
+     * ciphertext length from the inner plaintext length rec->data_len via
+     *
+     *     TLSCiphertext.length = TLSInnerPlaintext.length + taglen.
+     *
      */
 
     unsigned char *cur = add_data;
+    size_t ad_len_field = rec->data_len;
 
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)
-    if( minor_ver != MBEDTLS_SSL_MINOR_VERSION_4 )
+    if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 )
+    {
+        /* In TLS 1.3, the AAD contains the length of the TLSCiphertext,
+         * which differs from the length of the TLSInnerPlaintext
+         * by the length of the authentication tag. */
+        ad_len_field += taglen;
+    }
+    else
 #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */
     {
         ((void) minor_ver);
+        ((void) taglen);
         memcpy( cur, rec->ctr, sizeof( rec->ctr ) );
         cur += sizeof( rec->ctr );
     }
@@ -431,15 +454,15 @@
         *cur = rec->cid_len;
         cur++;
 
-        cur[0] = ( rec->data_len >> 8 ) & 0xFF;
-        cur[1] = ( rec->data_len >> 0 ) & 0xFF;
+        cur[0] = ( ad_len_field >> 8 ) & 0xFF;
+        cur[1] = ( ad_len_field >> 0 ) & 0xFF;
         cur += 2;
     }
     else
 #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
     {
-        cur[0] = ( rec->data_len >> 8 ) & 0xFF;
-        cur[1] = ( rec->data_len >> 0 ) & 0xFF;
+        cur[0] = ( ad_len_field >> 8 ) & 0xFF;
+        cur[1] = ( ad_len_field >> 0 ) & 0xFF;
         cur += 2;
     }
 
@@ -646,7 +669,8 @@
         unsigned char mac[MBEDTLS_SSL_MAC_ADD];
 
         ssl_extract_add_data_from_record( add_data, &add_data_len, rec,
-                                          transform->minor_ver );
+                                          transform->minor_ver,
+                                          transform->taglen );
 
         mbedtls_md_hmac_update( &transform->md_ctx_enc, add_data,
                                 add_data_len );
@@ -743,7 +767,8 @@
          * This depends on the TLS version.
          */
         ssl_extract_add_data_from_record( add_data, &add_data_len, rec,
-                                          transform->minor_ver );
+                                          transform->minor_ver,
+                                          transform->taglen );
 
         MBEDTLS_SSL_DEBUG_BUF( 4, "IV used (internal)",
                                iv, transform->ivlen );
@@ -897,7 +922,8 @@
             }
 
             ssl_extract_add_data_from_record( add_data, &add_data_len,
-                                              rec, transform->minor_ver );
+                                              rec, transform->minor_ver,
+                                              transform->taglen );
 
             MBEDTLS_SSL_DEBUG_MSG( 3, ( "using encrypt then mac" ) );
             MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", add_data,
@@ -1304,7 +1330,8 @@
          * This depends on the TLS version.
          */
         ssl_extract_add_data_from_record( add_data, &add_data_len, rec,
-                                          transform->minor_ver );
+                                          transform->minor_ver,
+                                          transform->taglen );
         MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD",
                                add_data, add_data_len );
 
@@ -1414,7 +1441,8 @@
              * Further, we still know that data_len > minlen */
             rec->data_len -= transform->maclen;
             ssl_extract_add_data_from_record( add_data, &add_data_len, rec,
-                                              transform->minor_ver );
+                                              transform->minor_ver,
+                                              transform->taglen );
 
             /* Calculate expected MAC. */
             MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", add_data,
@@ -1606,7 +1634,8 @@
          */
         rec->data_len -= transform->maclen;
         ssl_extract_add_data_from_record( add_data, &add_data_len, rec,
-                                          transform->minor_ver );
+                                          transform->minor_ver,
+                                          transform->taglen );
 
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
         /*
@@ -2360,7 +2389,8 @@
  *      (including handshake headers but excluding record headers)
  *   - ssl->out_msg: the record contents (handshake headers + content)
  */
-int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl )
+int mbedtls_ssl_write_handshake_msg_ext( mbedtls_ssl_context *ssl,
+                                         int update_checksum )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     const size_t hs_len = ssl->out_msglen - 4;
@@ -2469,7 +2499,7 @@
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
         /* Update running hashes of handshake messages seen */
-        if( hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST )
+        if( hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST && update_checksum != 0 )
             ssl->handshake->update_checksum( ssl, ssl->out_msg, ssl->out_msglen );
     }
 
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index d82ec04..3d67393 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -4258,23 +4258,8 @@
 {
     int ret = 0;
 
-    if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER || ssl->handshake == NULL )
-        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
-
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "server state: %d", ssl->state ) );
 
-    if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 )
-        return( ret );
-
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
-        ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING )
-    {
-        if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
-            return( ret );
-    }
-#endif /* MBEDTLS_SSL_PROTO_DTLS */
-
     switch( ssl->state )
     {
         case MBEDTLS_SSL_HELLO_REQUEST:
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 909a32a..f8cad4a 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -664,14 +664,14 @@
  *        - MBEDTLS_SSL_EXPORT_KEYS: ssl->conf->{f,p}_export_keys
  *        - MBEDTLS_DEBUG_C: ssl->conf->{f,p}_dbg
  */
-static int ssl_populate_transform( mbedtls_ssl_transform *transform,
+static int ssl_tls12_populate_transform( mbedtls_ssl_transform *transform,
                                    int ciphersuite,
                                    const unsigned char master[48],
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
-#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) && \
+    defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
                                    int encrypt_then_mac,
-#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
+#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC &&
+          MBEDTLS_SSL_SOME_SUITES_USE_MAC */
                                    ssl_tls_prf_t tls_prf,
                                    const unsigned char randbytes[64],
                                    int minor_ver,
@@ -713,6 +713,15 @@
     memcpy( transform->randbytes, randbytes, sizeof( transform->randbytes ) );
 #endif
 
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)
+    if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 )
+    {
+        /* At the moment, we keep TLS <= 1.2 and TLS 1.3 transform
+         * generation separate. This should never happen. */
+        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+    }
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */
+
     /*
      * Get various info structures
      */
@@ -805,19 +814,10 @@
          *   sequence number).
          */
         transform->ivlen = 12;
-#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)
-        if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 )
-        {
+        if( cipher_info->mode == MBEDTLS_MODE_CHACHAPOLY )
             transform->fixed_ivlen = 12;
-        }
         else
-#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */
-        {
-            if( cipher_info->mode == MBEDTLS_MODE_CHACHAPOLY )
-                transform->fixed_ivlen = 12;
-            else
-                transform->fixed_ivlen = 4;
-        }
+            transform->fixed_ivlen = 4;
 
         /* Minimum length of encrypted record */
         explicit_ivlen = transform->ivlen - transform->fixed_ivlen;
@@ -1327,22 +1327,22 @@
     }
 
     /* Populate transform structure */
-    ret = ssl_populate_transform( ssl->transform_negotiate,
-                                  ssl->session_negotiate->ciphersuite,
-                                  ssl->session_negotiate->master,
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
-#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
-                                  ssl->session_negotiate->encrypt_then_mac,
-#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
-                                  ssl->handshake->tls_prf,
-                                  ssl->handshake->randbytes,
-                                  ssl->minor_ver,
-                                  ssl->conf->endpoint,
-                                  ssl );
+    ret = ssl_tls12_populate_transform( ssl->transform_negotiate,
+                                        ssl->session_negotiate->ciphersuite,
+                                        ssl->session_negotiate->master,
+#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) && \
+    defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+                                        ssl->session_negotiate->encrypt_then_mac,
+#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC &&
+          MBEDTLS_SSL_SOME_SUITES_USE_MAC */
+                                        ssl->handshake->tls_prf,
+                                        ssl->handshake->randbytes,
+                                        ssl->minor_ver,
+                                        ssl->conf->endpoint,
+                                        ssl );
     if( ret != 0 )
     {
-        MBEDTLS_SSL_DEBUG_RET( 1, "ssl_populate_transform", ret );
+        MBEDTLS_SSL_DEBUG_RET( 1, "ssl_tls12_populate_transform", ret );
         return( ret );
     }
 
@@ -3280,9 +3280,9 @@
  * If partial is non-zero, keep data in the input buffer and client ID.
  * (Use when a DTLS client reconnects from the same port.)
  */
-int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial )
+static void ssl_session_reset_msg_layer( mbedtls_ssl_context *ssl,
+                                         int partial )
 {
-    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
 #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
     size_t in_buf_len = ssl->in_buf_len;
     size_t out_buf_len = ssl->out_buf_len;
@@ -3291,16 +3291,65 @@
     size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN;
 #endif
 
-#if !defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) ||     \
-    !defined(MBEDTLS_SSL_SRV_C)
-    ((void) partial);
+#if !defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) || !defined(MBEDTLS_SSL_SRV_C)
+    partial = 0;
 #endif
 
-    ssl->state = MBEDTLS_SSL_HELLO_REQUEST;
-
     /* Cancel any possibly running timer */
     mbedtls_ssl_set_timer( ssl, 0 );
 
+    mbedtls_ssl_reset_in_out_pointers( ssl );
+
+    /* Reset incoming message parsing */
+    ssl->in_offt    = NULL;
+    ssl->nb_zero    = 0;
+    ssl->in_msgtype = 0;
+    ssl->in_msglen  = 0;
+    ssl->in_hslen   = 0;
+    ssl->keep_current_message = 0;
+    ssl->transform_in  = NULL;
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+    ssl->next_record_offset = 0;
+    ssl->in_epoch = 0;
+#endif
+
+    /* Keep current datagram if partial == 1 */
+    if( partial == 0 )
+    {
+        ssl->in_left = 0;
+        memset( ssl->in_buf, 0, in_buf_len );
+    }
+
+    /* Reset outgoing message writing */
+    ssl->out_msgtype = 0;
+    ssl->out_msglen  = 0;
+    ssl->out_left    = 0;
+    memset( ssl->out_buf, 0, out_buf_len );
+    memset( ssl->cur_out_ctr, 0, sizeof( ssl->cur_out_ctr ) );
+    ssl->transform_out = NULL;
+
+#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
+    mbedtls_ssl_dtls_replay_reset( ssl );
+#endif
+
+    if( ssl->transform )
+    {
+        mbedtls_ssl_transform_free( ssl->transform );
+        mbedtls_free( ssl->transform );
+        ssl->transform = NULL;
+    }
+}
+
+int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+    ssl->state = MBEDTLS_SSL_HELLO_REQUEST;
+
+    ssl_session_reset_msg_layer( ssl, partial );
+
+    /* Reset renegotiation state */
 #if defined(MBEDTLS_SSL_RENEGOTIATION)
     ssl->renego_status = MBEDTLS_SSL_INITIAL_HANDSHAKE;
     ssl->renego_records_seen = 0;
@@ -3311,53 +3360,8 @@
 #endif
     ssl->secure_renegotiation = MBEDTLS_SSL_LEGACY_RENEGOTIATION;
 
-    ssl->in_offt = NULL;
-    mbedtls_ssl_reset_in_out_pointers( ssl );
-
-    ssl->in_msgtype = 0;
-    ssl->in_msglen = 0;
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
-    ssl->next_record_offset = 0;
-    ssl->in_epoch = 0;
-#endif
-#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
-    mbedtls_ssl_dtls_replay_reset( ssl );
-#endif
-
-    ssl->in_hslen = 0;
-    ssl->nb_zero = 0;
-
-    ssl->keep_current_message = 0;
-
-    ssl->out_msgtype = 0;
-    ssl->out_msglen = 0;
-    ssl->out_left = 0;
-
-    memset( ssl->cur_out_ctr, 0, sizeof( ssl->cur_out_ctr ) );
-
-    ssl->transform_in = NULL;
-    ssl->transform_out = NULL;
-
-    ssl->session_in = NULL;
+    ssl->session_in  = NULL;
     ssl->session_out = NULL;
-
-    memset( ssl->out_buf, 0, out_buf_len );
-
-#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C)
-    if( partial == 0 )
-#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */
-    {
-        ssl->in_left = 0;
-        memset( ssl->in_buf, 0, in_buf_len );
-    }
-
-    if( ssl->transform )
-    {
-        mbedtls_ssl_transform_free( ssl->transform );
-        mbedtls_free( ssl->transform );
-        ssl->transform = NULL;
-    }
-
     if( ssl->session )
     {
         mbedtls_ssl_session_free( ssl->session );
@@ -5135,12 +5139,40 @@
 /*
  * Perform a single step of the SSL handshake
  */
+static int ssl_prepare_handshake_step( mbedtls_ssl_context *ssl )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+    if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 )
+        return( ret );
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+        ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING )
+    {
+        if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
+            return( ret );
+    }
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
+    return( ret );
+}
+
 int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl )
 {
-    int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
 
-    if( ssl == NULL || ssl->conf == NULL )
+    if( ssl            == NULL                       ||
+        ssl->conf      == NULL                       ||
+        ssl->handshake == NULL                       ||
+        ssl->state     == MBEDTLS_SSL_HANDSHAKE_OVER )
+    {
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    }
+
+    ret = ssl_prepare_handshake_step( ssl );
+    if( ret != 0 )
+        return( ret );
 
 #if defined(MBEDTLS_SSL_CLI_C)
     if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT )
@@ -5472,6 +5504,13 @@
     handle_buffer_resizing( ssl, 1, mbedtls_ssl_get_input_buflen( ssl ),
                                     mbedtls_ssl_get_output_buflen( ssl ) );
 #endif
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)
+    mbedtls_free( handshake->transform_earlydata );
+    mbedtls_free( handshake->transform_handshake );
+    handshake->transform_earlydata = NULL;
+    handshake->transform_handshake = NULL;
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */
 }
 
 void mbedtls_ssl_session_free( mbedtls_ssl_session *session )
@@ -5932,14 +5971,14 @@
     if( (size_t)( end - p ) < sizeof( ssl->transform->randbytes ) )
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
 
-    ret = ssl_populate_transform( ssl->transform,
+    ret = ssl_tls12_populate_transform( ssl->transform,
                   ssl->session->ciphersuite,
                   ssl->session->master,
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
-#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) && \
+    defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
                   ssl->session->encrypt_then_mac,
-#endif
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
+#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC &&
+          MBEDTLS_SSL_SOME_SUITES_USE_MAC */
                   ssl_tls12prf_from_cs( ssl->session->ciphersuite ),
                   p, /* currently pointing to randbytes */
                   MBEDTLS_SSL_MINOR_VERSION_3, /* (D)TLS 1.2 is forced */
@@ -6170,6 +6209,11 @@
         mbedtls_free( ssl->session_negotiate );
     }
 
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)
+    mbedtls_ssl_transform_free( ssl->transform_application );
+    mbedtls_free( ssl->transform_application );
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */
+
     if( ssl->session )
     {
         mbedtls_ssl_session_free( ssl->session );
diff --git a/library/ssl_tls13_keys.c b/library/ssl_tls13_keys.c
index f1c8a12..902f99e 100644
--- a/library/ssl_tls13_keys.c
+++ b/library/ssl_tls13_keys.c
@@ -699,4 +699,125 @@
     return( ret );
 }
 
+int mbedtls_ssl_tls13_populate_transform( mbedtls_ssl_transform *transform,
+                                          int endpoint,
+                                          int ciphersuite,
+                                          mbedtls_ssl_key_set const *traffic_keys,
+                                          mbedtls_ssl_context *ssl /* DEBUG ONLY */ )
+{
+    int ret;
+    mbedtls_cipher_info_t const *cipher_info;
+    const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
+    unsigned char const *key_enc;
+    unsigned char const *iv_enc;
+    unsigned char const *key_dec;
+    unsigned char const *iv_dec;
+
+#if !defined(MBEDTLS_DEBUG_C)
+    ssl = NULL; /* make sure we don't use it except for those cases */
+    (void) ssl;
+#endif
+
+    ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuite );
+    if( ciphersuite_info == NULL )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "ciphersuite info for %d not found",
+                                    ciphersuite ) );
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    }
+
+    cipher_info = mbedtls_cipher_info_from_type( ciphersuite_info->cipher );
+    if( cipher_info == NULL )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "cipher info for %u not found",
+                                    ciphersuite_info->cipher ) );
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    }
+
+    /*
+     * Setup cipher contexts in target transform
+     */
+
+    if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_enc,
+                                      cipher_info ) ) != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret );
+        return( ret );
+    }
+
+    if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_dec,
+                                      cipher_info ) ) != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret );
+        return( ret );
+    }
+
+#if defined(MBEDTLS_SSL_SRV_C)
+    if( endpoint == MBEDTLS_SSL_IS_SERVER )
+    {
+        key_enc = traffic_keys->server_write_key;
+        key_dec = traffic_keys->client_write_key;
+        iv_enc = traffic_keys->server_write_iv;
+        iv_dec = traffic_keys->client_write_iv;
+    }
+    else
+#endif /* MBEDTLS_SSL_SRV_C */
+#if defined(MBEDTLS_SSL_CLI_C)
+    if( endpoint == MBEDTLS_SSL_IS_CLIENT )
+    {
+        key_enc = traffic_keys->client_write_key;
+        key_dec = traffic_keys->server_write_key;
+        iv_enc = traffic_keys->client_write_iv;
+        iv_dec = traffic_keys->server_write_iv;
+    }
+    else
+#endif /* MBEDTLS_SSL_CLI_C */
+    {
+        /* should not happen */
+        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+    }
+
+    memcpy( transform->iv_enc, iv_enc, traffic_keys->iv_len );
+    memcpy( transform->iv_dec, iv_dec, traffic_keys->iv_len );
+
+    if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_enc,
+                                       key_enc, cipher_info->key_bitlen,
+                                       MBEDTLS_ENCRYPT ) ) != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret );
+        return( ret );
+    }
+
+    if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_dec,
+                                       key_dec, cipher_info->key_bitlen,
+                                       MBEDTLS_DECRYPT ) ) != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret );
+        return( ret );
+    }
+
+    /*
+     * Setup other fields in SSL transform
+     */
+
+    if( ( ciphersuite_info->flags & MBEDTLS_CIPHERSUITE_SHORT_TAG ) != 0 )
+        transform->taglen  = 8;
+    else
+        transform->taglen  = 16;
+
+    transform->ivlen       = traffic_keys->iv_len;
+    transform->maclen      = 0;
+    transform->fixed_ivlen = transform->ivlen;
+    transform->minor_ver   = MBEDTLS_SSL_MINOR_VERSION_4;
+
+    /* We add the true record content type (1 Byte) to the plaintext and
+     * then pad to the configured granularity. The mimimum length of the
+     * type-extended and padded plaintext is therefore the padding
+     * granularity. */
+    transform->minlen =
+        transform->taglen + MBEDTLS_SSL_CID_TLS1_3_PADDING_GRANULARITY;
+
+    return( 0 );
+}
+
 #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */
diff --git a/library/ssl_tls13_keys.h b/library/ssl_tls13_keys.h
index 3b96998..ca892b1 100644
--- a/library/ssl_tls13_keys.h
+++ b/library/ssl_tls13_keys.h
@@ -498,4 +498,37 @@
                                unsigned char const *transcript,
                                unsigned char *result );
 
+/**
+ * \bref Setup an SSL transform structure representing the
+ *       record protection mechanism used by TLS 1.3
+ *
+ * \param transform    The SSL transform structure to be created. This must have
+ *                     been initialized through mbedtls_ssl_transform_init() and
+ *                     not used in any other way prior to calling this function.
+ *                     In particular, this function does not clean up the
+ *                     transform structure prior to installing the new keys.
+ * \param endpoint     Indicates whether the transform is for the client
+ *                     (value #MBEDTLS_SSL_IS_CLIENT) or the server
+ *                     (value #MBEDTLS_SSL_IS_SERVER).
+ * \param ciphersuite  The numerical identifier for the ciphersuite to use.
+ *                     This must be one of the identifiers listed in
+ *                     ssl_ciphersuites.h.
+ * \param traffic_keys The key material to use. No reference is stored in
+ *                     the SSL transform being generated, and the caller
+ *                     should destroy the key material afterwards.
+ * \param ssl          (Debug-only) The SSL context to use for debug output
+ *                     in case of failure. This parameter is only needed if
+ *                     #MBEDTLS_DEBUG_C is set, and is ignored otherwise.
+ *
+ * \return             \c 0 on success. In this case, \p transform is ready to
+ *                     be used with mbedtls_ssl_transform_decrypt() and
+ *                     mbedtls_ssl_transform_encrypt().
+ * \return             A negative error code on failure.
+ */
+int mbedtls_ssl_tls13_populate_transform( mbedtls_ssl_transform *transform,
+                                          int endpoint,
+                                          int ciphersuite,
+                                          mbedtls_ssl_key_set const *traffic_keys,
+                                          mbedtls_ssl_context *ssl );
+
 #endif /* MBEDTLS_SSL_TLS1_3_KEYS_H */
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index f8e43c8..af05dd9 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -161,6 +161,7 @@
     : ${ARMC5_BIN_DIR:=/usr/bin}
     : ${ARMC6_BIN_DIR:=/usr/bin}
     : ${ARM_NONE_EABI_GCC_PREFIX:=arm-none-eabi-}
+    : ${ARM_LINUX_GNUEABI_GCC_PREFIX:=arm-linux-gnueabi-}
 
     # if MAKEFLAGS is not set add the -j option to speed up invocations of make
     if [ -z "${MAKEFLAGS+set}" ]; then
@@ -230,6 +231,9 @@
      --arm-none-eabi-gcc-prefix=<string>
                         Prefix for a cross-compiler for arm-none-eabi
                         (default: "${ARM_NONE_EABI_GCC_PREFIX}")
+     --arm-linux-gnueabi-gcc-prefix=<string>
+                        Prefix for a cross-compiler for arm-linux-gnueabi
+                        (default: "${ARM_LINUX_GNUEABI_GCC_PREFIX}")
      --armcc            Run ARM Compiler builds (on by default).
      --except           Exclude the COMPONENTs listed on the command line,
                         instead of running only those.
@@ -387,6 +391,7 @@
         case "$1" in
             --append-outcome) append_outcome=1;;
             --arm-none-eabi-gcc-prefix) shift; ARM_NONE_EABI_GCC_PREFIX="$1";;
+            --arm-linux-gnueabi-gcc-prefix) shift; ARM_LINUX_GNUEABI_GCC_PREFIX="$1";;
             --armcc) no_armcc=;;
             --armc5-bin-dir) shift; ARMC5_BIN_DIR="$1";;
             --armc6-bin-dir) shift; ARMC6_BIN_DIR="$1";;
@@ -2369,14 +2374,29 @@
     ${ARM_NONE_EABI_GCC_PREFIX}size library/*.o
 }
 
-component_build_arm_none_eabi_gcc_arm5vte () {
-    msg "build: ${ARM_NONE_EABI_GCC_PREFIX}gcc -march=arm5vte" # ~ 10s
+component_build_arm_linux_gnueabi_gcc_arm5vte () {
+    msg "build: ${ARM_LINUX_GNUEABI_GCC_PREFIX}gcc -march=arm5vte" # ~ 10s
     scripts/config.py baremetal
     # Build for a target platform that's close to what Debian uses
     # for its "armel" distribution (https://wiki.debian.org/ArmEabiPort).
     # See https://github.com/ARMmbed/mbedtls/pull/2169 and comments.
-    # It would be better to build with arm-linux-gnueabi-gcc but
-    # we don't have that on our CI at this time.
+    # Build everything including programs, see for example
+    # https://github.com/ARMmbed/mbedtls/pull/3449#issuecomment-675313720
+    make CC="${ARM_LINUX_GNUEABI_GCC_PREFIX}gcc" AR="${ARM_LINUX_GNUEABI_GCC_PREFIX}ar" CFLAGS='-Werror -Wall -Wextra -march=armv5te -O1' LDFLAGS='-march=armv5te'
+
+    msg "size: ${ARM_LINUX_GNUEABI_GCC_PREFIX}gcc -march=armv5te -O1"
+    ${ARM_LINUX_GNUEABI_GCC_PREFIX}size library/*.o
+}
+support_build_arm_linux_gnueabi_gcc_arm5vte () {
+    type ${ARM_LINUX_GNUEABI_GCC_PREFIX}gcc >/dev/null 2>&1
+}
+
+component_build_arm_none_eabi_gcc_arm5vte () {
+    msg "build: ${ARM_NONE_EABI_GCC_PREFIX}gcc -march=arm5vte" # ~ 10s
+    scripts/config.py baremetal
+    # This is an imperfect substitute for
+    # component_build_arm_linux_gnueabi_gcc_arm5vte
+    # in case the gcc-arm-linux-gnueabi toolchain is not available
     make CC="${ARM_NONE_EABI_GCC_PREFIX}gcc" AR="${ARM_NONE_EABI_GCC_PREFIX}ar" CFLAGS='-std=c99 -Werror -Wall -Wextra -march=armv5te -O1' LDFLAGS='-march=armv5te' SHELL='sh -x' lib
 
     msg "size: ${ARM_NONE_EABI_GCC_PREFIX}gcc -march=armv5te -O1"
@@ -2437,11 +2457,22 @@
 }
 
 component_test_tls13_experimental () {
-    msg "build: default config with MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL enabled"
+    msg "build: default config with MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL enabled, without padding"
     scripts/config.pl set MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL
+    scripts/config.pl set MBEDTLS_SSL_CID_TLS1_3_PADDING_GRANULARITY 1
     CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
     make
-    msg "test: default config with MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL enabled"
+    msg "test: default config with MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL enabled, without padding"
+    make test
+}
+
+component_test_tls13_experimental_with_padding () {
+    msg "build: default config with MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL enabled, with padding"
+    scripts/config.pl set MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL
+    scripts/config.pl set MBEDTLS_SSL_CID_TLS1_3_PADDING_GRANULARITY 16
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
+    msg "test: default config with MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL enabled, with padding"
     make test
 }
 
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 01265ae..9ee6b76 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -77,6 +77,14 @@
     O_LEGACY_CLI=false
 fi
 
+if [ -n "${OPENSSL_NEXT:-}" ]; then
+    O_NEXT_SRV="$OPENSSL_NEXT s_server -www -cert data_files/server5.crt -key data_files/server5.key"
+    O_NEXT_CLI="echo 'GET / HTTP/1.0' | $OPENSSL_NEXT s_client"
+else
+    O_NEXT_SRV=false
+    O_NEXT_CLI=false
+fi
+
 if [ -n "${GNUTLS_NEXT_SERV:-}" ]; then
     G_NEXT_SRV="$GNUTLS_NEXT_SERV --x509certfile data_files/server5.crt --x509keyfile data_files/server5.key"
 else
@@ -346,6 +354,57 @@
     fi
 }
 
+requires_openssl_next() {
+    if [ -z "${OPENSSL_NEXT_AVAILABLE:-}" ]; then
+        if which "${OPENSSL_NEXT:-}" >/dev/null 2>&1; then
+            OPENSSL_NEXT_AVAILABLE="YES"
+        else
+            OPENSSL_NEXT_AVAILABLE="NO"
+        fi
+    fi
+    if [ "$OPENSSL_NEXT_AVAILABLE" = "NO" ]; then
+        SKIP_NEXT="YES"
+    fi
+}
+
+# skip next test if tls1_3 is not available
+requires_openssl_tls1_3() {
+    requires_openssl_next
+    if [ "$OPENSSL_NEXT_AVAILABLE" = "NO" ]; then
+        OPENSSL_TLS1_3_AVAILABLE="NO"
+    fi
+    if [ -z "${OPENSSL_TLS1_3_AVAILABLE:-}" ]; then
+        if $OPENSSL_NEXT s_client -help 2>&1 | grep tls1_3 >/dev/null
+        then
+            OPENSSL_TLS1_3_AVAILABLE="YES"
+        else
+            OPENSSL_TLS1_3_AVAILABLE="NO"
+        fi
+    fi
+    if [ "$OPENSSL_TLS1_3_AVAILABLE" = "NO" ]; then
+        SKIP_NEXT="YES"
+    fi
+}
+
+# skip next test if tls1_3 is not available
+requires_gnutls_tls1_3() {
+    requires_gnutls_next
+    if [ "$GNUTLS_NEXT_AVAILABLE" = "NO" ]; then
+        GNUTLS_TLS1_3_AVAILABLE="NO"
+    fi
+    if [ -z "${GNUTLS_TLS1_3_AVAILABLE:-}" ]; then
+        if $GNUTLS_NEXT_CLI -l 2>&1 | grep VERS-TLS1.3 >/dev/null
+        then
+            GNUTLS_TLS1_3_AVAILABLE="YES"
+        else
+            GNUTLS_TLS1_3_AVAILABLE="NO"
+        fi
+    fi
+    if [ "$GNUTLS_TLS1_3_AVAILABLE" = "NO" ]; then
+        SKIP_NEXT="YES"
+    fi
+}
+
 # skip next test if IPv6 isn't available on this host
 requires_ipv6() {
     if [ -z "${HAS_IPV6:-}" ]; then
@@ -8487,6 +8546,24 @@
             -c "EAP-TLS IV is:" \
             -s "EAP-TLS IV is:"
 
+# openssl feature tests: check if tls1.3 exists.
+requires_openssl_tls1_3
+run_test    "TLS1.3: Test openssl tls1_3 feature" \
+            "$O_NEXT_SRV -tls1_3 -msg" \
+            "$O_NEXT_CLI -tls1_3 -msg" \
+            0 \
+            -c "TLS 1.3" \
+            -s "TLS 1.3"
+
+# gnutls feature tests: check if tls1.3 exists.
+requires_gnutls_tls1_3
+run_test    "TLS1.3: Test gnutls tls1_3 feature" \
+            "$G_NEXT_SRV --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3" \
+            "$G_NEXT_CLI localhost --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3 -V" \
+            0 \
+            -s "Version: TLS1.3" \
+            -c "Version: TLS1.3"
+
 # TLS1.3 test cases
 # TODO: remove or rewrite this test case if #4832 is resolved.
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data
index 5d92469..25eefb3 100644
--- a/tests/suites/test_suite_ssl.data
+++ b/tests/suites/test_suite_ssl.data
@@ -6021,6 +6021,62 @@
 # Vector from RFC 8448
 ssl_tls1_3_derive_handshake_secrets:MBEDTLS_MD_SHA256:"005cb112fd8eb4ccc623bb88a07c64b3ede1605363fc7d0df8c7ce4ff0fb4ae6":"f736cb34fe25e701551bee6fd24c1cc7102a7daf9405cb15d97aafe16f757d03":"2faac08f851d35fea3604fcb4de82dc62c9b164a70974d0462e27f1ab278700f":"fe927ae271312e8bf0275b581c54eef020450dc4ecffaa05a1a35d27518e7803"
 
+SSL TLS 1.3 Record Encryption, tls13.ulfheim.net Example #1
+# - Server App Key: 0b6d22c8ff68097ea871c672073773bf
+# - Server App IV:  1b13dd9f8d8f17091d34b349
+# - Client App Key: 49134b95328f279f0183860589ac6707
+# - Client App IV:  bc4dd5f7b98acff85466261d
+# - App data payload: 70696e67
+# - Complete record:  1703030015c74061535eb12f5f25a781957874742ab7fb305dd5
+# - Padding used: No (== granularity 1)
+ssl_tls1_3_record_protection:MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:MBEDTLS_SSL_IS_CLIENT:0:1:"0b6d22c8ff68097ea871c672073773bf":"1b13dd9f8d8f17091d34b349":"49134b95328f279f0183860589ac6707":"bc4dd5f7b98acff85466261d":"70696e67":"c74061535eb12f5f25a781957874742ab7fb305dd5"
+
+SSL TLS 1.3 Record Encryption, tls13.ulfheim.net Example #2
+# - Server App Key: 0b6d22c8ff68097ea871c672073773bf
+# - Server App IV:  1b13dd9f8d8f17091d34b349
+# - Client App Key: 49134b95328f279f0183860589ac6707
+# - Client App IV:  bc4dd5f7b98acff85466261d
+# - App data payload: 706f6e67
+# - Complete record:  1703030015370e5f168afa7fb16b663ecdfca3dbb81931a90ca7
+# - Padding used: No (== granularity 1)
+ssl_tls1_3_record_protection:MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:MBEDTLS_SSL_IS_SERVER:1:1:"0b6d22c8ff68097ea871c672073773bf":"1b13dd9f8d8f17091d34b349":"49134b95328f279f0183860589ac6707":"bc4dd5f7b98acff85466261d":"706f6e67":"370e5f168afa7fb16b663ecdfca3dbb81931a90ca7"
+
+SSL TLS 1.3 Record Encryption RFC 8448 Example #1
+# Application Data record sent by Client in 1-RTT example of RFC 8448, Section 3
+# - Server App Key: 9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac 92 e3 56
+# - Server App IV:  cf 78 2b 88 dd 83 54 9a ad f1 e9 84
+# - Client App Key: 17 42 2d da 59 6e d5 d9 ac d8 90 e3 c6 3f 50 51
+# - Client App IV:  5b 78 92 3d ee 08 57 90 33 e5 23 d9
+# - App data payload: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
+#                     10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
+#                     20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
+#                     30 31
+# - Complete record:  17 03 03 00 43 a2 3f 70 54 b6 2c 94 d0 af fa fe
+#                     82 28 ba 55 cb ef ac ea 42 f9 14 aa 66 bc ab 3f
+#                     2b 98 19 a8 a5 b4 6b 39 5b d5 4a 9a 20 44 1e 2b
+#                     62 97 4e 1f 5a 62 92 a2 97 70 14 bd 1e 3d ea e6
+#                     3a ee bb 21 69 49 15 e4
+# - Padding used: No (== granularity 1)
+ssl_tls1_3_record_protection:MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:MBEDTLS_SSL_IS_CLIENT:0:1:"9f02283b6c9c07efc26bb9f2ac92e356":"cf782b88dd83549aadf1e984":"17422dda596ed5d9acd890e3c63f5051":"5b78923dee08579033e523d9":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031":"a23f7054b62c94d0affafe8228ba55cbefacea42f914aa66bcab3f2b9819a8a5b46b395bd54a9a20441e2b62974e1f5a6292a2977014bd1e3deae63aeebb21694915e4"
+
+SSL TLS 1.3 Record Encryption RFC 8448 Example #2
+# Application Data record sent by Server in 1-RTT example of RFC 8448, Section 3
+# - Server App Key: 9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac 92 e3 56
+# - Server App IV:  cf 78 2b 88 dd 83 54 9a ad f1 e9 84
+# - Client App Key: 17 42 2d da 59 6e d5 d9 ac d8 90 e3 c6 3f 50 51
+# - Client App IV:  5b 78 92 3d ee 08 57 90 33 e5 23 d9
+# - App data payload: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
+#                     10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
+#                     20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
+#                     30 31
+# - Complete record:  17 03 03 00 43 2e 93 7e 11 ef 4a c7 40 e5 38 ad
+#                     36 00 5f c4 a4 69 32 fc 32 25 d0 5f 82 aa 1b 36
+#                     e3 0e fa f9 7d 90 e6 df fc 60 2d cb 50 1a 59 a8
+#                     fc c4 9c 4b f2 e5 f0 a2 1c 00 47 c2 ab f3 32 54
+#                     0d d0 32 e1 67 c2 95 5d
+# - Padding used: No (== granularity 1)
+ssl_tls1_3_record_protection:MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:MBEDTLS_SSL_IS_SERVER:1:1:"9f02283b6c9c07efc26bb9f2ac92e356":"cf782b88dd83549aadf1e984":"17422dda596ed5d9acd890e3c63f5051":"5b78923dee08579033e523d9":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031":"2e937e11ef4ac740e538ad36005fc4a46932fc3225d05f82aa1b36e30efaf97d90e6dffc602dcb501a59a8fcc49c4bf2e5f0a21c0047c2abf332540dd032e167c2955d"
+
 SSL TLS 1.3 Key schedule: Application secrets derivation helper
 # Vector from RFC 8448
 ssl_tls1_3_derive_application_secrets:MBEDTLS_MD_SHA256:"e2d32d4ed66dd37897a0e80c84107503ce58bf8aad4cb55a5002d77ecb890ece":"b0aeffc46a2cfe33114e6fd7d51f9f04b1ca3c497dab08934a774a9d9ad7dbf3":"2abbf2b8e381d23dbebe1dd2a7d16a8bf484cb4950d23fb7fb7fa8547062d9a1":"cc21f1bf8feb7dd5fa505bd9c4b468a9984d554a993dc49e6d285598fb672691":"3fd93d4ffddc98e64b14dd107aedf8ee4add23f4510f58a4592d0b201bee56b4"
diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function
index 72b0cdb..69d2e00 100644
--- a/tests/suites/test_suite_ssl.function
+++ b/tests/suites/test_suite_ssl.function
@@ -3945,6 +3945,104 @@
 /* END_CASE */
 
 /* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */
+void ssl_tls1_3_record_protection( int ciphersuite,
+                                   int endpoint,
+                                   int ctr,
+                                   int padding_used,
+                                   data_t *server_write_key,
+                                   data_t *server_write_iv,
+                                   data_t *client_write_key,
+                                   data_t *client_write_iv,
+                                   data_t *plaintext,
+                                   data_t *ciphertext )
+{
+    mbedtls_ssl_key_set keys;
+    mbedtls_ssl_transform transform_send;
+    mbedtls_ssl_transform transform_recv;
+    mbedtls_record rec;
+    unsigned char *buf = NULL;
+    size_t buf_len;
+    int other_endpoint;
+
+    TEST_ASSERT( endpoint == MBEDTLS_SSL_IS_CLIENT ||
+                 endpoint == MBEDTLS_SSL_IS_SERVER );
+
+    if( endpoint == MBEDTLS_SSL_IS_SERVER )
+        other_endpoint = MBEDTLS_SSL_IS_CLIENT;
+    if( endpoint == MBEDTLS_SSL_IS_CLIENT )
+        other_endpoint = MBEDTLS_SSL_IS_SERVER;
+
+    TEST_ASSERT( server_write_key->len == client_write_key->len );
+    TEST_ASSERT( server_write_iv->len  == client_write_iv->len  );
+
+    memcpy( keys.client_write_key,
+            client_write_key->x, client_write_key->len );
+    memcpy( keys.client_write_iv,
+            client_write_iv->x, client_write_iv->len );
+    memcpy( keys.server_write_key,
+            server_write_key->x, server_write_key->len );
+    memcpy( keys.server_write_iv,
+            server_write_iv->x, server_write_iv->len );
+
+    keys.key_len = server_write_key->len;
+    keys.iv_len  = server_write_iv->len;
+
+    mbedtls_ssl_transform_init( &transform_recv );
+    mbedtls_ssl_transform_init( &transform_send );
+
+    TEST_ASSERT( mbedtls_ssl_tls13_populate_transform(
+                     &transform_send, endpoint,
+                     ciphersuite, &keys, NULL ) == 0 );
+    TEST_ASSERT( mbedtls_ssl_tls13_populate_transform(
+                     &transform_recv, other_endpoint,
+                     ciphersuite, &keys, NULL ) == 0 );
+
+    /* Make sure we have enough space in the buffer even if
+     * we use more padding than the KAT. */
+    buf_len = ciphertext->len + MBEDTLS_SSL_CID_TLS1_3_PADDING_GRANULARITY;
+    ASSERT_ALLOC( buf, buf_len );
+    rec.type   = MBEDTLS_SSL_MSG_APPLICATION_DATA;
+
+    /* TLS 1.3 uses the version identifier from TLS 1.2 on the wire. */
+    mbedtls_ssl_write_version( MBEDTLS_SSL_MAJOR_VERSION_3,
+                               MBEDTLS_SSL_MINOR_VERSION_3,
+                               MBEDTLS_SSL_TRANSPORT_STREAM,
+                               rec.ver );
+
+    /* Copy plaintext into record structure */
+    rec.buf = buf;
+    rec.buf_len = buf_len;
+    rec.data_offset = 0;
+    TEST_ASSERT( plaintext->len <= ciphertext->len );
+    memcpy( rec.buf + rec.data_offset, plaintext->x, plaintext->len );
+    rec.data_len = plaintext->len;
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+    rec.cid_len = 0;
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+    memset( &rec.ctr[0], 0, 8 );
+    rec.ctr[7] = ctr;
+
+    TEST_ASSERT( mbedtls_ssl_encrypt_buf( NULL, &transform_send, &rec,
+                                          NULL, NULL ) == 0 );
+
+    if( padding_used == MBEDTLS_SSL_CID_TLS1_3_PADDING_GRANULARITY )
+    {
+        ASSERT_COMPARE( rec.buf + rec.data_offset, rec.data_len,
+                        ciphertext->x, ciphertext->len );
+    }
+
+    TEST_ASSERT( mbedtls_ssl_decrypt_buf( NULL, &transform_recv, &rec ) == 0 );
+    ASSERT_COMPARE( rec.buf + rec.data_offset, rec.data_len,
+                    plaintext->x, plaintext->len );
+
+    mbedtls_free( buf );
+    mbedtls_ssl_transform_free( &transform_send );
+    mbedtls_ssl_transform_free( &transform_recv );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */
 void ssl_tls1_3_key_evolution( int hash_alg,
                                data_t *secret,
                                data_t *input,