Test slot_number attribute

Test the behavior of the getter/setter functions.

Test that psa_get_key_slot_number() reports a slot number for a key in
a secure element, and doesn't report a slot number for a key that is
not in a secure element.

Test that psa_get_key_slot_number() reports the correct slot number
for a key in a secure element.
diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h
index 5359b58..130ce75 100644
--- a/include/psa/crypto_extra.h
+++ b/include/psa/crypto_extra.h
@@ -163,6 +163,18 @@
     attributes->slot_number = slot_number;
 }
 
+/** Remove the slot number attribute from a key attribute structure.
+ *
+ * This function undoes the action of psa_set_key_slot_number().
+ *
+ * \param[out] attributes       The attribute structure to write to.
+ */
+static inline void psa_clear_key_slot_number(
+    psa_key_attributes_t *attributes )
+{
+    attributes->core.flags &= ~MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER;
+}
+
 #endif /* MBEDTLS_PSA_CRYPTO_SE_C */
 
 /**@}*/
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index b049840..4118d2f 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -19,6 +19,9 @@
 PSA key attributes: lifetime then id
 persistence_attributes:0x1234:3:0x1235:0x1235:3
 
+PSA key attributes: slot number
+slot_number_attribute:
+
 PSA import/export raw: 0 bytes
 import_export:"":PSA_KEY_TYPE_RAW_DATA:PSA_KEY_USAGE_EXPORT:0:0:0:PSA_SUCCESS:1
 
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 0eb6172..3225bef 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -1113,6 +1113,23 @@
     return( ok );
 }
 
+/* Assert that a key isn't reported as having a slot number. */
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+#define ASSERT_NO_SLOT_NUMBER( attributes )                             \
+    do                                                                  \
+    {                                                                   \
+        psa_key_slot_number_t ASSERT_NO_SLOT_NUMBER_slot_number;        \
+        TEST_EQUAL( psa_get_key_slot_number(                            \
+                        attributes,                                     \
+                        &ASSERT_NO_SLOT_NUMBER_slot_number ),           \
+                    PSA_ERROR_INVALID_ARGUMENT );                       \
+    }                                                                   \
+    while( 0 )
+#else /* MBEDTLS_PSA_CRYPTO_SE_C */
+#define ASSERT_NO_SLOT_NUMBER( attributes )     \
+    ( (void) 0 )
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+
 /* An overapproximation of the amount of storage needed for a key of the
  * given type and with the given content. The API doesn't make it easy
  * to find a good value for the size. The current implementation doesn't
@@ -1214,6 +1231,46 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_SE_C */
+void slot_number_attribute( )
+{
+    psa_key_slot_number_t slot_number = 0xdeadbeef;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+    /* Initially, there is no slot number. */
+    TEST_EQUAL( psa_get_key_slot_number( &attributes, &slot_number ),
+                PSA_ERROR_INVALID_ARGUMENT );
+
+    /* Test setting a slot number. */
+    psa_set_key_slot_number( &attributes, 0 );
+    PSA_ASSERT( psa_get_key_slot_number( &attributes, &slot_number ) );
+    TEST_EQUAL( slot_number, 0 );
+
+    /* Test changing the slot number. */
+    psa_set_key_slot_number( &attributes, 42 );
+    PSA_ASSERT( psa_get_key_slot_number( &attributes, &slot_number ) );
+    TEST_EQUAL( slot_number, 42 );
+
+    /* Test clearing the slot number. */
+    psa_clear_key_slot_number( &attributes );
+    TEST_EQUAL( psa_get_key_slot_number( &attributes, &slot_number ),
+                PSA_ERROR_INVALID_ARGUMENT );
+
+    /* Clearing again should have no effect. */
+    psa_clear_key_slot_number( &attributes );
+    TEST_EQUAL( psa_get_key_slot_number( &attributes, &slot_number ),
+                PSA_ERROR_INVALID_ARGUMENT );
+
+    /* Test that reset clears the slot number. */
+    psa_set_key_slot_number( &attributes, 42 );
+    PSA_ASSERT( psa_get_key_slot_number( &attributes, &slot_number ) );
+    TEST_EQUAL( slot_number, 42 );
+    psa_reset_key_attributes( &attributes );
+    TEST_EQUAL( psa_get_key_slot_number( &attributes, &slot_number ),
+                PSA_ERROR_INVALID_ARGUMENT );
+}
+/* END_CASE */
+
 /* BEGIN_CASE */
 void import_with_policy( int type_arg,
                          int usage_arg, int alg_arg,
@@ -1246,6 +1303,7 @@
     TEST_EQUAL( psa_get_key_type( &got_attributes ), type );
     TEST_EQUAL( psa_get_key_usage_flags( &got_attributes ), usage );
     TEST_EQUAL( psa_get_key_algorithm( &got_attributes ), alg );
+    ASSERT_NO_SLOT_NUMBER( &got_attributes );
 
     PSA_ASSERT( psa_destroy_key( handle ) );
     test_operations_on_invalid_handle( handle );
@@ -1284,6 +1342,7 @@
     TEST_EQUAL( psa_get_key_type( &got_attributes ), type );
     if( attr_bits != 0 )
         TEST_EQUAL( attr_bits, psa_get_key_bits( &got_attributes ) );
+    ASSERT_NO_SLOT_NUMBER( &got_attributes );
 
     PSA_ASSERT( psa_destroy_key( handle ) );
     test_operations_on_invalid_handle( handle );
@@ -1328,6 +1387,7 @@
         TEST_EQUAL( psa_get_key_type( &attributes ), type );
         TEST_EQUAL( psa_get_key_bits( &attributes ),
                     PSA_BYTES_TO_BITS( byte_size ) );
+        ASSERT_NO_SLOT_NUMBER( &attributes );
         memset( buffer, 0, byte_size + 1 );
         PSA_ASSERT( psa_export_key( handle, buffer, byte_size, &n ) );
         for( n = 0; n < byte_size; n++ )
@@ -1420,6 +1480,7 @@
     PSA_ASSERT( psa_get_key_attributes( handle, &got_attributes ) );
     TEST_EQUAL( psa_get_key_type( &got_attributes ), type );
     TEST_EQUAL( psa_get_key_bits( &got_attributes ), (size_t) expected_bits );
+    ASSERT_NO_SLOT_NUMBER( &got_attributes );
 
     /* Export the key */
     status = psa_export_key( handle,
diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal.function b/tests/suites/test_suite_psa_crypto_se_driver_hal.function
index 6ac19a6..9a57464 100644
--- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function
+++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function
@@ -212,6 +212,31 @@
                     psa_get_key_bits( reference_attributes ) );
     }
 
+    {
+        psa_key_slot_number_t actual_slot_number = 0xdeadbeef;
+        psa_key_slot_number_t desired_slot_number = 0xb90cc011;
+        psa_key_lifetime_t lifetime =
+            psa_get_key_lifetime( &actual_attributes );
+        psa_status_t status = psa_get_key_slot_number( &actual_attributes,
+                                                       &actual_slot_number );
+        if( lifetime < MIN_DRIVER_LIFETIME )
+        {
+            /* The key is not in a secure element. */
+            TEST_EQUAL( status, PSA_ERROR_INVALID_ARGUMENT );
+        }
+        else
+        {
+            /* The key is in a secure element. If it had been created
+             * in a specific slot, check that it is reported there. */
+            PSA_ASSERT( status );
+            status = psa_get_key_slot_number( reference_attributes,
+                                              &desired_slot_number );
+            if( status == PSA_SUCCESS )
+            {
+                TEST_EQUAL( desired_slot_number, actual_slot_number );
+            }
+        }
+    }
     ok = 1;
 
 exit:
@@ -485,11 +510,14 @@
     /* Test that the key was created in the expected slot. */
     TEST_ASSERT( ram_slots[min_slot].type == PSA_KEY_TYPE_RAW_DATA );
 
-    /* Test the key attributes and the key data. */
+    /* Test the key attributes, including the reported slot number. */
     psa_set_key_bits( &attributes,
                       PSA_BYTES_TO_BITS( sizeof( key_material ) ) );
+    psa_set_key_slot_number( &attributes, min_slot );
     if( ! check_key_attributes( handle, &attributes ) )
         goto exit;
+
+    /* Test the key data. */
     PSA_ASSERT( psa_export_key( handle,
                                 exported, sizeof( exported ),
                                 &exported_length ) );