Merge branch 'development' into iotssl-2257-chacha-poly-primitives

* development: (182 commits)
  Change the library version to 2.11.0
  Fix version in ChangeLog for fix for #552
  Add ChangeLog entry for clang version fix. Issue #1072
  Compilation warning fixes on 32b platfrom with IAR
  Revert "Turn on MBEDTLS_SSL_ASYNC_PRIVATE by default"
  Fix for missing len var when XTS config'd and CTR not
  ssl_server2: handle mbedtls_x509_dn_gets failure
  Fix harmless use of uninitialized memory in ssl_parse_encrypted_pms
  SSL async tests: add a few test cases for error in decrypt
  Fix memory leak in ssl_server2 with SNI + async callback
  SNI + SSL async callback: make all keys async
  ssl_async_resume: free the operation context on error
  ssl_server2: get op_name from context in ssl_async_resume as well
  Clarify "as directed here" in SSL async callback documentation
  SSL async callbacks documentation: clarify resource cleanup
  Async callback: use mbedtls_pk_check_pair to compare keys
  Rename mbedtls_ssl_async_{get,set}_data for clarity
  Fix copypasta in the async callback documentation
  SSL async callback: cert is not always from mbedtls_ssl_conf_own_cert
  ssl_async_set_key: detect if ctx->slots overflows
  ...
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 6bfb210..3a413ad 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -109,6 +109,10 @@
 #define DFL_KEY_FILE            ""
 #define DFL_CRT_FILE2           ""
 #define DFL_KEY_FILE2           ""
+#define DFL_ASYNC_OPERATIONS    "-"
+#define DFL_ASYNC_PRIVATE_DELAY1 ( -1 )
+#define DFL_ASYNC_PRIVATE_DELAY2 ( -1 )
+#define DFL_ASYNC_PRIVATE_ERROR  ( 0 )
 #define DFL_PSK                 ""
 #define DFL_PSK_IDENTITY        "Client_identity"
 #define DFL_ECJPAKE_PW          NULL
@@ -196,6 +200,18 @@
 #define USAGE_IO ""
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+#define USAGE_SSL_ASYNC \
+    "    async_operations=%%c...   d=decrypt, s=sign (default: -=off)\n" \
+    "    async_private_delay1=%%d  Asynchronous delay for key_file or preloaded key\n" \
+    "    async_private_delay2=%%d  Asynchronous delay for key_file2 and sni\n" \
+    "                              default: -1 (not asynchronous)\n" \
+    "    async_private_error=%%d   Async callback error injection (default=0=none,\n" \
+    "                              1=start, 2=cancel, 3=resume, negative=first time only)"
+#else
+#define USAGE_SSL_ASYNC ""
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
 #define USAGE_PSK                                                   \
     "    psk=%%s              default: \"\" (in hex, without 0x)\n" \
@@ -346,6 +362,7 @@
     "    cert_req_ca_list=%%d default: 1 (send ca list)\n"  \
     "                        options: 1 (send ca list), 0 (don't send)\n" \
     USAGE_IO                                                \
+    USAGE_SSL_ASYNC                                         \
     USAGE_SNI                                               \
     "\n"                                                    \
     USAGE_PSK                                               \
@@ -410,6 +427,10 @@
     const char *key_file;       /* the file with the server key             */
     const char *crt_file2;      /* the file with the 2nd server certificate */
     const char *key_file2;      /* the file with the 2nd server key         */
+    const char *async_operations; /* supported SSL asynchronous operations  */
+    int async_private_delay1;   /* number of times f_async_resume needs to be called for key 1, or -1 for no async */
+    int async_private_delay2;   /* number of times f_async_resume needs to be called for key 2, or -1 for no async */
+    int async_private_error;    /* inject error in async private callback */
     const char *psk;            /* the pre-shared key                       */
     const char *psk_identity;   /* the pre-shared key identity              */
     char *psk_list;             /* list of PSK id/key pairs for callback    */
@@ -841,6 +862,244 @@
 };
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
+/** Return true if \p ret is a status code indicating that there is an
+ * operation in progress on an SSL connection, and false if it indicates
+ * success or a fatal error.
+ *
+ * The possible operations in progress are:
+ *
+ * - A read, when the SSL input buffer does not contain a full message.
+ * - A write, when the SSL output buffer contains some data that has not
+ *   been sent over the network yet.
+ * - An asynchronous callback that has not completed yet. */
+static int mbedtls_status_is_ssl_in_progress( int ret )
+{
+    return( ret == MBEDTLS_ERR_SSL_WANT_READ ||
+            ret == MBEDTLS_ERR_SSL_WANT_WRITE ||
+            ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS );
+}
+
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+typedef struct
+{
+    mbedtls_x509_crt *cert; /*!< Certificate corresponding to the key */
+    mbedtls_pk_context *pk; /*!< Private key */
+    unsigned delay; /*!< Number of resume steps to go through */
+    unsigned pk_owned : 1; /*!< Whether to free the pk object on exit */
+} ssl_async_key_slot_t;
+
+typedef enum {
+    SSL_ASYNC_INJECT_ERROR_NONE = 0, /*!< Let the callbacks succeed */
+    SSL_ASYNC_INJECT_ERROR_START, /*!< Inject error during start */
+    SSL_ASYNC_INJECT_ERROR_CANCEL, /*!< Close the connection after async start */
+    SSL_ASYNC_INJECT_ERROR_RESUME, /*!< Inject error during resume */
+#define SSL_ASYNC_INJECT_ERROR_MAX SSL_ASYNC_INJECT_ERROR_RESUME
+} ssl_async_inject_error_t;
+
+typedef struct
+{
+    ssl_async_key_slot_t slots[4]; /* key, key2, sni1, sni2 */
+    size_t slots_used;
+    ssl_async_inject_error_t inject_error;
+    int (*f_rng)(void *, unsigned char *, size_t);
+    void *p_rng;
+} ssl_async_key_context_t;
+
+int ssl_async_set_key( ssl_async_key_context_t *ctx,
+                       mbedtls_x509_crt *cert,
+                       mbedtls_pk_context *pk,
+                       int pk_take_ownership,
+                       unsigned delay )
+{
+    if( ctx->slots_used >= sizeof( ctx->slots ) / sizeof( *ctx->slots ) )
+        return( -1 );
+    ctx->slots[ctx->slots_used].cert = cert;
+    ctx->slots[ctx->slots_used].pk = pk;
+    ctx->slots[ctx->slots_used].delay = delay;
+    ctx->slots[ctx->slots_used].pk_owned = pk_take_ownership;
+    ++ctx->slots_used;
+    return( 0 );
+}
+
+#define SSL_ASYNC_INPUT_MAX_SIZE 512
+
+typedef enum
+{
+    ASYNC_OP_SIGN,
+    ASYNC_OP_DECRYPT,
+} ssl_async_operation_type_t;
+/* Note that the enum above and the array below need to be kept in sync!
+ * `ssl_async_operation_names[op]` is the name of op for each value `op`
+ * of type `ssl_async_operation_type_t`. */
+static const char *const ssl_async_operation_names[] =
+{
+    "sign",
+    "decrypt",
+};
+
+typedef struct
+{
+    unsigned slot;
+    ssl_async_operation_type_t operation_type;
+    mbedtls_md_type_t md_alg;
+    unsigned char input[SSL_ASYNC_INPUT_MAX_SIZE];
+    size_t input_len;
+    unsigned remaining_delay;
+} ssl_async_operation_context_t;
+
+static int ssl_async_start( mbedtls_ssl_context *ssl,
+                            mbedtls_x509_crt *cert,
+                            ssl_async_operation_type_t op_type,
+                            mbedtls_md_type_t md_alg,
+                            const unsigned char *input,
+                            size_t input_len )
+{
+    ssl_async_key_context_t *config_data =
+        mbedtls_ssl_conf_get_async_config_data( ssl->conf );
+    unsigned slot;
+    ssl_async_operation_context_t *ctx = NULL;
+    const char *op_name = ssl_async_operation_names[op_type];
+
+    {
+        char dn[100];
+        if( mbedtls_x509_dn_gets( dn, sizeof( dn ), &cert->subject ) > 0 )
+            mbedtls_printf( "Async %s callback: looking for DN=%s\n",
+                            op_name, dn );
+    }
+
+    /* Look for a private key that matches the public key in cert.
+     * Since this test code has the private key inside Mbed TLS,
+     * we call mbedtls_pk_check_pair to match a private key with the
+     * public key. */
+    for( slot = 0; slot < config_data->slots_used; slot++ )
+    {
+        if( mbedtls_pk_check_pair( &cert->pk,
+                                   config_data->slots[slot].pk ) == 0 )
+            break;
+    }
+    if( slot == config_data->slots_used )
+    {
+        mbedtls_printf( "Async %s callback: no key matches this certificate.\n",
+                        op_name );
+        return( MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH );
+    }
+    mbedtls_printf( "Async %s callback: using key slot %u, delay=%u.\n",
+                    op_name, slot, config_data->slots[slot].delay );
+
+    if( config_data->inject_error == SSL_ASYNC_INJECT_ERROR_START )
+    {
+        mbedtls_printf( "Async %s callback: injected error\n", op_name );
+        return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
+    }
+
+    if( input_len > SSL_ASYNC_INPUT_MAX_SIZE )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    ctx = mbedtls_calloc( 1, sizeof( *ctx ) );
+    if( ctx == NULL )
+        return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+    ctx->slot = slot;
+    ctx->operation_type = op_type;
+    ctx->md_alg = md_alg;
+    memcpy( ctx->input, input, input_len );
+    ctx->input_len = input_len;
+    ctx->remaining_delay = config_data->slots[slot].delay;
+    mbedtls_ssl_set_async_operation_data( ssl, ctx );
+
+    if( ctx->remaining_delay == 0 )
+        return( 0 );
+    else
+        return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS );
+}
+
+static int ssl_async_sign( mbedtls_ssl_context *ssl,
+                           mbedtls_x509_crt *cert,
+                           mbedtls_md_type_t md_alg,
+                           const unsigned char *hash,
+                           size_t hash_len )
+{
+    return( ssl_async_start( ssl, cert,
+                             ASYNC_OP_SIGN, md_alg,
+                             hash, hash_len ) );
+}
+
+static int ssl_async_decrypt( mbedtls_ssl_context *ssl,
+                              mbedtls_x509_crt *cert,
+                              const unsigned char *input,
+                              size_t input_len )
+{
+    return( ssl_async_start( ssl, cert,
+                             ASYNC_OP_DECRYPT, MBEDTLS_MD_NONE,
+                             input, input_len ) );
+}
+
+static int ssl_async_resume( mbedtls_ssl_context *ssl,
+                             unsigned char *output,
+                             size_t *output_len,
+                             size_t output_size )
+{
+    ssl_async_operation_context_t *ctx = mbedtls_ssl_get_async_operation_data( ssl );
+    ssl_async_key_context_t *config_data =
+        mbedtls_ssl_conf_get_async_config_data( ssl->conf );
+    ssl_async_key_slot_t *key_slot = &config_data->slots[ctx->slot];
+    int ret;
+    const char *op_name;
+
+    if( ctx->remaining_delay > 0 )
+    {
+        --ctx->remaining_delay;
+        mbedtls_printf( "Async resume (slot %u): call %u more times.\n",
+                        ctx->slot, ctx->remaining_delay );
+        return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS );
+    }
+
+    switch( ctx->operation_type )
+    {
+        case ASYNC_OP_DECRYPT:
+            ret = mbedtls_pk_decrypt( key_slot->pk,
+                                      ctx->input, ctx->input_len,
+                                      output, output_len, output_size,
+                                      config_data->f_rng, config_data->p_rng );
+            break;
+        case ASYNC_OP_SIGN:
+            ret = mbedtls_pk_sign( key_slot->pk,
+                                   ctx->md_alg,
+                                   ctx->input, ctx->input_len,
+                                   output, output_len,
+                                   config_data->f_rng, config_data->p_rng );
+            break;
+        default:
+            mbedtls_printf( "Async resume (slot %u): unknown operation type %ld. This shouldn't happen.\n",
+                            ctx->slot, (long) ctx->operation_type );
+            mbedtls_free( ctx );
+            return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
+            break;
+    }
+
+    op_name = ssl_async_operation_names[ctx->operation_type];
+
+    if( config_data->inject_error == SSL_ASYNC_INJECT_ERROR_RESUME )
+    {
+        mbedtls_printf( "Async resume callback: %s done but injected error\n",
+                        op_name );
+        mbedtls_free( ctx );
+        return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
+    }
+
+    mbedtls_printf( "Async resume (slot %u): %s done, status=%d.\n",
+                    ctx->slot, op_name, ret );
+    mbedtls_free( ctx );
+    return( ret );
+}
+
+static void ssl_async_cancel( mbedtls_ssl_context *ssl )
+{
+    ssl_async_operation_context_t *ctx = mbedtls_ssl_get_async_operation_data( ssl );
+    mbedtls_printf( "Async cancel callback.\n" );
+    mbedtls_free( ctx );
+}
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
 /*
  * Wait for an event from the underlying transport or the timer
  * (Used in event-driven IO mode).
@@ -929,7 +1188,10 @@
     mbedtls_x509_crt srvcert2;
     mbedtls_pk_context pkey2;
     int key_cert_init = 0, key_cert_init2 = 0;
-#endif
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+    ssl_async_key_context_t ssl_async_keys;
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
 #if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_FS_IO)
     mbedtls_dhm_context dhm;
 #endif
@@ -975,6 +1237,9 @@
     mbedtls_pk_init( &pkey );
     mbedtls_x509_crt_init( &srvcert2 );
     mbedtls_pk_init( &pkey2 );
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+    memset( &ssl_async_keys, 0, sizeof( ssl_async_keys ) );
+#endif
 #endif
 #if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_FS_IO)
     mbedtls_dhm_init( &dhm );
@@ -1032,6 +1297,10 @@
     opt.key_file            = DFL_KEY_FILE;
     opt.crt_file2           = DFL_CRT_FILE2;
     opt.key_file2           = DFL_KEY_FILE2;
+    opt.async_operations    = DFL_ASYNC_OPERATIONS;
+    opt.async_private_delay1 = DFL_ASYNC_PRIVATE_DELAY1;
+    opt.async_private_delay2 = DFL_ASYNC_PRIVATE_DELAY2;
+    opt.async_private_error = DFL_ASYNC_PRIVATE_ERROR;
     opt.psk                 = DFL_PSK;
     opt.psk_identity        = DFL_PSK_IDENTITY;
     opt.psk_list            = DFL_PSK_LIST;
@@ -1124,6 +1393,25 @@
             opt.key_file2 = q;
         else if( strcmp( p, "dhm_file" ) == 0 )
             opt.dhm_file = q;
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+        else if( strcmp( p, "async_operations" ) == 0 )
+            opt.async_operations = q;
+        else if( strcmp( p, "async_private_delay1" ) == 0 )
+            opt.async_private_delay1 = atoi( q );
+        else if( strcmp( p, "async_private_delay2" ) == 0 )
+            opt.async_private_delay2 = atoi( q );
+        else if( strcmp( p, "async_private_error" ) == 0 )
+        {
+            int n = atoi( q );
+            if( n < -SSL_ASYNC_INJECT_ERROR_MAX ||
+                n > SSL_ASYNC_INJECT_ERROR_MAX )
+            {
+                ret = 2;
+                goto usage;
+            }
+            opt.async_private_error = n;
+        }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
         else if( strcmp( p, "psk" ) == 0 )
             opt.psk = q;
         else if( strcmp( p, "psk_identity" ) == 0 )
@@ -2018,22 +2306,109 @@
         mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );
     }
     if( key_cert_init )
-        if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, &pkey ) ) != 0 )
+    {
+        mbedtls_pk_context *pk = &pkey;
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+        if( opt.async_private_delay1 >= 0 )
+        {
+            ret = ssl_async_set_key( &ssl_async_keys, &srvcert, pk, 0,
+                                     opt.async_private_delay1 );
+            if( ret < 0 )
+            {
+                mbedtls_printf( "  Test error: ssl_async_set_key failed (%d)\n",
+                                ret );
+                goto exit;
+            }
+            pk = NULL;
+        }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+        if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, pk ) ) != 0 )
         {
             mbedtls_printf( " failed\n  ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret );
             goto exit;
         }
+    }
     if( key_cert_init2 )
-        if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert2, &pkey2 ) ) != 0 )
+    {
+        mbedtls_pk_context *pk = &pkey2;
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+        if( opt.async_private_delay2 >= 0 )
+        {
+            ret = ssl_async_set_key( &ssl_async_keys, &srvcert2, pk, 0,
+                                     opt.async_private_delay2 );
+            if( ret < 0 )
+            {
+                mbedtls_printf( "  Test error: ssl_async_set_key failed (%d)\n",
+                                ret );
+                goto exit;
+            }
+            pk = NULL;
+        }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+        if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert2, pk ) ) != 0 )
         {
             mbedtls_printf( " failed\n  ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret );
             goto exit;
         }
-#endif
+    }
+
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+    if( opt.async_operations[0] != '-' )
+    {
+        mbedtls_ssl_async_sign_t *sign = NULL;
+        mbedtls_ssl_async_decrypt_t *decrypt = NULL;
+        const char *r;
+        for( r = opt.async_operations; *r; r++ )
+        {
+            switch( *r )
+            {
+            case 'd':
+                decrypt = ssl_async_decrypt;
+                break;
+            case 's':
+                sign = ssl_async_sign;
+                break;
+            }
+        }
+        ssl_async_keys.inject_error = ( opt.async_private_error < 0 ?
+                                        - opt.async_private_error :
+                                        opt.async_private_error );
+        ssl_async_keys.f_rng = mbedtls_ctr_drbg_random;
+        ssl_async_keys.p_rng = &ctr_drbg;
+        mbedtls_ssl_conf_async_private_cb( &conf,
+                                           sign,
+                                           decrypt,
+                                           ssl_async_resume,
+                                           ssl_async_cancel,
+                                           &ssl_async_keys );
+    }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
 
 #if defined(SNI_OPTION)
     if( opt.sni != NULL )
+    {
         mbedtls_ssl_conf_sni( &conf, sni_callback, sni_info );
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+        if( opt.async_private_delay2 >= 0 )
+        {
+            sni_entry *cur;
+            for( cur = sni_info; cur != NULL; cur = cur->next )
+            {
+                ret = ssl_async_set_key( &ssl_async_keys,
+                                         cur->cert, cur->key, 1,
+                                         opt.async_private_delay2 );
+                if( ret < 0 )
+                {
+                    mbedtls_printf( "  Test error: ssl_async_set_key failed (%d)\n",
+                                    ret );
+                    goto exit;
+                }
+                cur->key = NULL;
+            }
+        }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+    }
 #endif
 
 #if defined(MBEDTLS_ECP_C)
@@ -2205,8 +2580,16 @@
 
     while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 )
     {
-        if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
-            ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+        if( ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS &&
+            ssl_async_keys.inject_error == SSL_ASYNC_INJECT_ERROR_CANCEL )
+        {
+            mbedtls_printf( " cancelling on injected error\n" );
+            break;
+        }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
+        if( ! mbedtls_status_is_ssl_in_progress( ret ) )
             break;
 
         /* For event-driven IO, wait for socket to become available */
@@ -2244,6 +2627,11 @@
         }
 #endif
 
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+        if( opt.async_private_error < 0 )
+            /* Injected error only the first time round, to test reset */
+            ssl_async_keys.inject_error = SSL_ASYNC_INJECT_ERROR_NONE;
+#endif
         goto reset;
     }
     else /* ret == 0 */
@@ -2324,8 +2712,7 @@
             memset( buf, 0, sizeof( buf ) );
             ret = mbedtls_ssl_read( &ssl, buf, len );
 
-            if( ret == MBEDTLS_ERR_SSL_WANT_READ ||
-                ret == MBEDTLS_ERR_SSL_WANT_WRITE )
+            if( mbedtls_status_is_ssl_in_progress( ret ) )
             {
                 if( opt.event == 1 /* level triggered IO */ )
                 {
@@ -2425,7 +2812,7 @@
         len = sizeof( buf ) - 1;
         memset( buf, 0, sizeof( buf ) );
 
-        while( 1 )
+        do
         {
             /* Without the call to `mbedtls_ssl_check_pending`, it might
              * happen that the client sends application data in the same
@@ -2455,10 +2842,8 @@
              * it can happen that the subsequent call to `mbedtls_ssl_read`
              * returns `MBEDTLS_ERR_SSL_WANT_READ`, because the pending messages
              * might be discarded (e.g. because they are retransmissions). */
-            if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
-                ret != MBEDTLS_ERR_SSL_WANT_WRITE )
-                break;
         }
+        while( mbedtls_status_is_ssl_in_progress( ret ) );
 
         if( ret <= 0 )
         {
@@ -2493,8 +2878,7 @@
 
         while( ( ret = mbedtls_ssl_renegotiate( &ssl ) ) != 0 )
         {
-            if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
-                ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+            if( ! mbedtls_status_is_ssl_in_progress( ret ) )
             {
                 mbedtls_printf( " failed\n  ! mbedtls_ssl_renegotiate returned %d\n\n", ret );
                 goto reset;
@@ -2537,8 +2921,7 @@
                     goto reset;
                 }
 
-                if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
-                    ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+                if( ! mbedtls_status_is_ssl_in_progress( ret ) )
                 {
                     mbedtls_printf( " failed\n  ! mbedtls_ssl_write returned %d\n\n", ret );
                     goto reset;
@@ -2562,8 +2945,7 @@
         {
             ret = mbedtls_ssl_write( &ssl, buf, len );
 
-            if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
-                ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+            if( ! mbedtls_status_is_ssl_in_progress( ret ) )
                 break;
 
             /* For event-driven IO, wait for socket to become available */
@@ -2641,6 +3023,17 @@
     mbedtls_x509_crt_free( &srvcert2 );
     mbedtls_pk_free( &pkey2 );
 #endif
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+    for( i = 0; (size_t) i < ssl_async_keys.slots_used; i++ )
+    {
+        if( ssl_async_keys.slots[i].pk_owned )
+        {
+            mbedtls_pk_free( ssl_async_keys.slots[i].pk );
+            mbedtls_free( ssl_async_keys.slots[i].pk );
+            ssl_async_keys.slots[i].pk = NULL;
+        }
+    }
+#endif
 #if defined(SNI_OPTION)
     sni_free( sni_info );
 #endif
diff --git a/programs/test/benchmark.c b/programs/test/benchmark.c
index 61abba1..d577adb 100644
--- a/programs/test/benchmark.c
+++ b/programs/test/benchmark.c
@@ -102,7 +102,7 @@
 #define OPTIONS                                                         \
     "md4, md5, ripemd160, sha1, sha256, sha512,\n"                      \
     "arc4, des3, des, camellia, blowfish, chacha20,\n"                  \
-    "aes_cbc, aes_gcm, aes_ccm, chachapoly,\n"                          \
+    "aes_cbc, aes_gcm, aes_ccm, aes_ctx, chachapoly,\n"                 \
     "aes_cmac, des3_cmac, poly1305\n"                                   \
     "havege, ctr_drbg, hmac_drbg\n"                                     \
     "rsa, dhm, ecdsa, ecdh.\n"
@@ -237,7 +237,7 @@
 typedef struct {
     char md4, md5, ripemd160, sha1, sha256, sha512,
          arc4, des3, des,
-         aes_cbc, aes_gcm, aes_ccm, chachapoly,
+         aes_cbc, aes_gcm, aes_ccm, aes_xts, chachapoly,
          aes_cmac, des3_cmac,
          aria, camellia, blowfish, chacha20,
          poly1305,
@@ -285,6 +285,8 @@
                 todo.des = 1;
             else if( strcmp( argv[i], "aes_cbc" ) == 0 )
                 todo.aes_cbc = 1;
+            else if( strcmp( argv[i], "aes_xts" ) == 0 )
+                todo.aes_xts = 1;
             else if( strcmp( argv[i], "aes_gcm" ) == 0 )
                 todo.aes_gcm = 1;
             else if( strcmp( argv[i], "aes_ccm" ) == 0 )
@@ -438,6 +440,29 @@
         mbedtls_aes_free( &aes );
     }
 #endif
+#if defined(MBEDTLS_CIPHER_MODE_XTS)
+    if( todo.aes_xts )
+    {
+        int keysize;
+        mbedtls_aes_xts_context ctx;
+
+        mbedtls_aes_xts_init( &ctx );
+        for( keysize = 128; keysize <= 256; keysize += 128 )
+        {
+            mbedtls_snprintf( title, sizeof( title ), "AES-XTS-%d", keysize );
+
+            memset( buf, 0, sizeof( buf ) );
+            memset( tmp, 0, sizeof( tmp ) );
+            mbedtls_aes_xts_setkey_enc( &ctx, tmp, keysize * 2 );
+
+            TIME_AND_TSC( title,
+                    mbedtls_aes_crypt_xts( &ctx, MBEDTLS_AES_ENCRYPT, BUFSIZE,
+                                           tmp, buf, buf ) );
+
+            mbedtls_aes_xts_free( &ctx );
+        }
+    }
+#endif
 #if defined(MBEDTLS_GCM_C)
     if( todo.aes_gcm )
     {
diff --git a/programs/test/zeroize.c b/programs/test/zeroize.c
index 252438b..29cc0ac 100644
--- a/programs/test/zeroize.c
+++ b/programs/test/zeroize.c
@@ -66,7 +66,7 @@
     char buf[BUFFER_LEN];
     char *p = buf;
     char *end = p + BUFFER_LEN;
-    char c;
+    int c;
 
     if( argc != 2 )
     {
@@ -83,7 +83,7 @@
     }
 
     while( ( c = fgetc( fp ) ) != EOF && p < end - 1 )
-        *p++ = c;
+        *p++ = (char)c;
     *p = '\0';
 
     if( p - buf != 0 )
diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c
index 9cc582d..12baf72 100644
--- a/programs/x509/cert_write.c
+++ b/programs/x509/cert_write.c
@@ -607,11 +607,7 @@
     //
     if( strlen( opt.issuer_crt ) )
     {
-        if( !mbedtls_pk_can_do( &issuer_crt.pk, MBEDTLS_PK_RSA ) ||
-            mbedtls_mpi_cmp_mpi( &mbedtls_pk_rsa( issuer_crt.pk )->N,
-                         &mbedtls_pk_rsa( *issuer_key )->N ) != 0 ||
-            mbedtls_mpi_cmp_mpi( &mbedtls_pk_rsa( issuer_crt.pk )->E,
-                         &mbedtls_pk_rsa( *issuer_key )->E ) != 0 )
+        if( mbedtls_pk_check_pair( &issuer_crt.pk, issuer_key ) != 0 )
         {
             mbedtls_printf( " failed\n  !  issuer_key does not match "
                             "issuer certificate\n\n" );