Merge remote-tracking branch 'psa/pr/85' into feature-psa
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 4a33639..ca461c2 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -409,10 +409,17 @@
     switch( type )
     {
         case PSA_KEY_TYPE_RAW_DATA:
+            if( bits == 0 )
+            {
+                raw->bytes = 0;
+                raw->data = NULL;
+                return( PSA_SUCCESS );
+            }
+            break;
 #if defined(MBEDTLS_MD_C)
         case PSA_KEY_TYPE_HMAC:
-#endif
             break;
+#endif
 #if defined(MBEDTLS_AES_C)
         case PSA_KEY_TYPE_AES:
             if( bits != 128 && bits != 192 && bits != 256 )
@@ -478,7 +485,8 @@
                                         &slot->data.raw );
         if( status != PSA_SUCCESS )
             return( status );
-        memcpy( slot->data.raw.data, data, data_length );
+        if( data_length != 0 )
+            memcpy( slot->data.raw.data, data, data_length );
     }
     else
 #if defined(MBEDTLS_PK_PARSE_C)
@@ -506,7 +514,10 @@
                     mbedtls_rsa_context *rsa = mbedtls_pk_rsa( pk );
                     size_t bits = mbedtls_rsa_get_bitlen( rsa );
                     if( bits > PSA_VENDOR_RSA_MAX_KEY_BITS )
-                        return( PSA_ERROR_NOT_SUPPORTED );
+                    {
+                        status = PSA_ERROR_NOT_SUPPORTED;
+                        break;
+                    }
                     slot->data.rsa = rsa;
                 }
                 else
@@ -679,7 +690,8 @@
     {
         if( slot->data.raw.bytes > data_size )
             return( PSA_ERROR_BUFFER_TOO_SMALL );
-        memcpy( data, slot->data.raw.data, slot->data.raw.bytes );
+        if( slot->data.raw.bytes != 0 )
+            memcpy( data, slot->data.raw.data, slot->data.raw.bytes );
         *data_length = slot->data.raw.bytes;
         return( PSA_SUCCESS );
     }
@@ -710,7 +722,10 @@
                 ret = mbedtls_pk_write_key_der( &pk, data, data_size );
             if( ret < 0 )
             {
-                memset( data, 0, data_size );
+                /* If data_size is 0 then data may be NULL and then the
+                 * call to memset would have undefined behavior. */
+                if( data_size != 0 )
+                    memset( data, 0, data_size );
                 return( mbedtls_to_psa_error( ret ) );
             }
             /* The mbedtls_pk_xxx functions write to the end of the buffer.
@@ -998,8 +1013,11 @@
     /* Fill the output buffer with something that isn't a valid hash
      * (barring an attack on the hash and deliberately-crafted input),
      * in case the caller doesn't check the return status properly. */
-    *hash_length = actual_hash_length;
-    memset( hash, '!', hash_size );
+    *hash_length = hash_size;
+    /* If hash_size is 0 then hash may be NULL and then the
+     * call to memset would have undefined behavior. */
+    if( hash_size != 0 )
+        memset( hash, '!', hash_size );
 
     if( hash_size < actual_hash_length )
         return( PSA_ERROR_BUFFER_TOO_SMALL );
@@ -1050,6 +1068,7 @@
 
     if( ret == 0 )
     {
+        *hash_length = actual_hash_length;
         return( psa_hash_abort( operation ) );
     }
     else
@@ -1491,16 +1510,20 @@
 {
     int ret = 0;
     psa_status_t status = PSA_SUCCESS;
-    if( ! operation->key_set )
-        return( PSA_ERROR_BAD_STATE );
-    if( operation->iv_required && ! operation->iv_set )
-        return( PSA_ERROR_BAD_STATE );
 
     /* Fill the output buffer with something that isn't a valid mac
      * (barring an attack on the mac and deliberately-crafted input),
      * in case the caller doesn't check the return status properly. */
-    *mac_length = operation->mac_size;
-    memset( mac, '!', mac_size );
+    *mac_length = mac_size;
+    /* If mac_size is 0 then mac may be NULL and then the
+     * call to memset would have undefined behavior. */
+    if( mac_size != 0 )
+        memset( mac, '!', mac_size );
+
+    if( ! operation->key_set )
+        return( PSA_ERROR_BAD_STATE );
+    if( operation->iv_required && ! operation->iv_set )
+        return( PSA_ERROR_BAD_STATE );
 
     if( mac_size < operation->mac_size )
         return( PSA_ERROR_BUFFER_TOO_SMALL );
@@ -1562,6 +1585,7 @@
 
     if( ret == 0 && status == PSA_SUCCESS )
     {
+        *mac_length = operation->mac_size;
         return( psa_mac_abort( operation ) );
     }
     else
@@ -1944,8 +1968,10 @@
     if( status == PSA_SUCCESS )
         memset( signature + *signature_length, '!',
                 signature_size - *signature_length );
-    else
+    else if( signature_size != 0 )
         memset( signature, '!', signature_size );
+    /* If signature_size is 0 then we have nothing to do. We must not call
+     * memset because signature may be NULL in this case. */
     return( status );
 }
 
@@ -2410,7 +2436,9 @@
         psa_cipher_abort( operation );
         return( mbedtls_to_psa_error( ret ) );
     }
-    if( output_size >= *output_length )
+    if( *output_length == 0 )
+        /* Nothing to copy. Note that output may be NULL in this case. */ ;
+    else if( output_size >= *output_length )
         memcpy( output, temp_output_buffer, *output_length );
     else
     {
@@ -2684,7 +2712,10 @@
 
     if( ret != 0 )
     {
-        memset( ciphertext, 0, ciphertext_size );
+        /* If ciphertext_size is 0 then ciphertext may be NULL and then the
+         * call to memset would have undefined behavior. */
+        if( ciphertext_size != 0 )
+            memset( ciphertext, 0, ciphertext_size );
         return( mbedtls_to_psa_error( ret ) );
     }
 
@@ -2823,7 +2854,12 @@
     }
 
     if( ret != 0 )
-        memset( plaintext, 0, plaintext_size );
+    {
+        /* If plaintext_size is 0 then plaintext may be NULL and then the
+         * call to memset has undefined behavior. */
+        if( plaintext_size != 0 )
+            memset( plaintext, 0, plaintext_size );
+    }
     else
         *plaintext_length = ciphertext_length - tag_length;
 
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 0d1a25c..1017e88 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -46,7 +46,9 @@
 {
     int ret;
     int len = bits / 8 + 1;
-    if( x >= 1 << bits )
+    if( bits == 0 )
+        return( MBEDTLS_ERR_ASN1_INVALID_DATA );
+    if( bits <= 8 && x >= 1 << ( bits - 1 ) )
         return( MBEDTLS_ERR_ASN1_INVALID_DATA );
     if( *p < start || *p - start < (ssize_t) len )
         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
@@ -343,6 +345,36 @@
 exit:
     return( 0 );
 }
+
+static int exercise_key( psa_key_slot_t slot,
+                         psa_key_usage_t usage,
+                         psa_algorithm_t alg )
+{
+    int ok;
+    if( alg == 0 )
+        ok = 1; /* If no algorihm, do nothing (used for raw data "keys"). */
+    else if( PSA_ALG_IS_MAC( alg ) )
+        ok = exercise_mac_key( slot, usage, alg );
+    else if( PSA_ALG_IS_CIPHER( alg ) )
+        ok = exercise_cipher_key( slot, usage, alg );
+    else if( PSA_ALG_IS_AEAD( alg ) )
+        ok = exercise_aead_key( slot, usage, alg );
+    else if( PSA_ALG_IS_SIGN( alg ) )
+        ok = exercise_signature_key( slot, usage, alg );
+    else if( PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) )
+        ok = exercise_asymmetric_encryption_key( slot, usage, alg );
+    else
+    {
+        char message[40];
+        mbedtls_snprintf( message, sizeof( message ),
+                          "No code to exercise alg=0x%08lx",
+                          (unsigned long) alg );
+        test_fail( message, __LINE__, __FILE__ );
+        ok = 0;
+    }
+    return( ok );
+}
+
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -638,16 +670,8 @@
     TEST_ASSERT( got_bits == bits );
 
     /* Do something with the key according to its type and permitted usage. */
-    if( PSA_ALG_IS_MAC( alg ) )
-        exercise_mac_key( slot, usage, alg );
-    else if( PSA_ALG_IS_CIPHER( alg ) )
-        exercise_cipher_key( slot, usage, alg );
-    else if( PSA_ALG_IS_AEAD( alg ) )
-        exercise_aead_key( slot, usage, alg );
-    else if( PSA_ALG_IS_SIGN( alg ) )
-        exercise_signature_key( slot, usage, alg );
-    else if( PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) )
-        exercise_asymmetric_encryption_key( slot, usage, alg );
+    if( ! exercise_key( slot, usage, alg ) )
+        goto exit;
 
 exit:
     psa_destroy_key( slot );
@@ -2258,16 +2282,8 @@
     }
 
     /* Do something with the key according to its type and permitted usage. */
-    if( PSA_ALG_IS_MAC( alg ) )
-        exercise_mac_key( slot, usage, alg );
-    else if( PSA_ALG_IS_CIPHER( alg ) )
-        exercise_cipher_key( slot, usage, alg );
-    else if( PSA_ALG_IS_AEAD( alg ) )
-        exercise_aead_key( slot, usage, alg );
-    else if( PSA_ALG_IS_SIGN( alg ) )
-        exercise_signature_key( slot, usage, alg );
-    else if( PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) )
-        exercise_asymmetric_encryption_key( slot, usage, alg );
+    if( ! exercise_key( slot, usage, alg ) )
+        goto exit;
 
 exit:
     psa_destroy_key( slot );