Merge pull request #294 from ARMmbed/development-restricted

Merge restricted topic branch
diff --git a/ChangeLog b/ChangeLog
index 915c718..584dd65 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,14 @@
 
 = mbed TLS 2.1.1 released 2015-09-16
 
+Security
+   * Add countermeasure against Lenstra's RSA-CRT attack for PKCS#1 v1.5
+     signatures. (Found by Florian Weimer, Red Hat.)
+     https://securityblog.redhat.com/2015/09/02/factoring-rsa-keys-with-tls-perfect-forward-secrecy/
+   * Fix possible client-side NULL pointer dereference (read) when the client
+     tries to continue the handshake after it failed (a misuse of the API).
+     (Found by GDS Labs using afl-fuzz, patch provided by GDS Labs.)
+
 Bugfix
    * Fix warning when using a 64bit platform. (found by embedthis) (#275)
    * Fix off-by-one error in parsing Supported Point Format extension that
diff --git a/library/rsa.c b/library/rsa.c
index f4ab6b2a..3883d09 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -51,6 +51,8 @@
 #else
 #include <stdio.h>
 #define mbedtls_printf printf
+#define mbedtls_calloc calloc
+#define mbedtls_free   free
 #endif
 
 /*
@@ -1005,6 +1007,11 @@
     size_t nb_pad, olen, oid_size = 0;
     unsigned char *p = sig;
     const char *oid = NULL;
+    unsigned char *sig_try = NULL, *verif = NULL;
+    size_t i;
+    unsigned char diff;
+    volatile unsigned char diff_no_optimize;
+    int ret;
 
     if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 )
         return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
@@ -1067,9 +1074,39 @@
         memcpy( p, hash, hashlen );
     }
 
-    return( ( mode == MBEDTLS_RSA_PUBLIC )
-            ? mbedtls_rsa_public(  ctx, sig, sig )
-            : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig ) );
+    if( mode == MBEDTLS_RSA_PUBLIC )
+        return( mbedtls_rsa_public(  ctx, sig, sig ) );
+
+    /*
+     * In order to prevent Lenstra's attack, make the signature in a
+     * temporary buffer and check it before returning it.
+     */
+    sig_try = mbedtls_calloc( 1, ctx->len );
+    verif   = mbedtls_calloc( 1, ctx->len );
+    if( sig_try == NULL || verif == NULL )
+        return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
+
+    MBEDTLS_MPI_CHK( mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig_try ) );
+    MBEDTLS_MPI_CHK( mbedtls_rsa_public( ctx, sig_try, verif ) );
+
+    /* Compare in constant time just in case */
+    for( diff = 0, i = 0; i < ctx->len; i++ )
+        diff |= verif[i] ^ sig[i];
+    diff_no_optimize = diff;
+
+    if( diff_no_optimize != 0 )
+    {
+        ret = MBEDTLS_ERR_RSA_PRIVATE_FAILED;
+        goto cleanup;
+    }
+
+    memcpy( sig, sig_try, ctx->len );
+
+cleanup:
+    mbedtls_free( sig_try );
+    mbedtls_free( verif );
+
+    return( ret );
 }
 #endif /* MBEDTLS_PKCS1_V15 */
 
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index 5a9c432..c82e2e7 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -1771,6 +1771,12 @@
 
     ssl->handshake->pmslen = 48;
 
+    if( ssl->session_negotiate->peer_cert == NULL )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) );
+        return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
+    }
+
     /*
      * Now write it out, encrypted
      */
@@ -1873,6 +1879,12 @@
     int ret;
     const mbedtls_ecp_keypair *peer_key;
 
+    if( ssl->session_negotiate->peer_cert == NULL )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) );
+        return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
+    }
+
     if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk,
                      MBEDTLS_PK_ECKEY ) )
     {
@@ -2182,6 +2194,12 @@
         MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen != 0 ? hashlen :
             (unsigned int) ( mbedtls_md_get_size( mbedtls_md_info_from_type( md_alg ) ) ) );
 
+        if( ssl->session_negotiate->peer_cert == NULL )
+        {
+            MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) );
+            return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
+        }
+
         /*
          * Verify signature
          */