Merge pull request #109 from gilles-peskine-arm/psa-key_attributes-set_persistent

Individual setters for persistent key attributes
diff --git a/include/psa/crypto.h b/include/psa/crypto.h
index 043db32..8c42e93 100644
--- a/include/psa/crypto.h
+++ b/include/psa/crypto.h
@@ -132,7 +132,8 @@
  * psa_reset_key_attributes() on an attribute structure is optional if
  * the structure has only been modified by the following functions
  * since it was initialized or last reset with psa_reset_key_attributes():
- * - psa_make_key_persistent()
+ * - psa_set_key_id()
+ * - psa_set_key_lifetime()
  * - psa_set_key_type()
  * - psa_set_key_bits()
  * - psa_set_key_usage_flags()
@@ -173,7 +174,9 @@
  *
  * A typical sequence to create a key is as follows:
  * -# Create and initialize an attribute structure.
- * -# If the key is persistent, call psa_make_key_persistent().
+ * -# If the key is persistent, call psa_set_key_id().
+ *    Also call psa_set_key_lifetime() to place the key in a non-default
+ *    location.
  * -# Set the key policy with psa_set_key_usage_flags() and
  *    psa_set_key_algorithm().
  * -# Set the key type with psa_set_key_type(). If the key type requires
@@ -203,30 +206,56 @@
  */
 typedef struct psa_key_attributes_s psa_key_attributes_t;
 
-/** Declare a key as persistent.
+/** Declare a key as persistent and set its key identifier.
  *
- * This function does not access storage, it merely fills the attribute
- * structure with given values. The persistent key will be written to
- * storage when the attribute structure is passed to a key creation
- * function such as psa_import_key(), psa_generate_random_key(),
+ * If the attribute structure currently declares the key as volatile (which
+ * is the default content of an attribute structure), this function sets
+ * the lifetime attribute to #PSA_KEY_LIFETIME_PERSISTENT.
+ *
+ * This function does not access storage, it merely stores the given
+ * value in the structure.
+ * The persistent key will be written to storage when the attribute
+ * structure is passed to a key creation function such as
+ * psa_import_key(), psa_generate_random_key(),
  * psa_generate_derived_key() or psa_copy_key().
  *
- * This function overwrites any identifier and lifetime values
- * previously set in \p attributes.
- *
  * This function may be declared as `static` (i.e. without external
  * linkage). This function may be provided as a function-like macro,
  * but in this case it must evaluate each of its arguments exactly once.
  *
  * \param[out] attributes       The attribute structure to write to.
  * \param id                    The persistent identifier for the key.
+ */
+static void psa_set_key_id(psa_key_attributes_t *attributes,
+                           psa_key_id_t id);
+
+/** Set the location of a persistent key.
+ *
+ * To make a key persistent, you must give it a persistent key identifier
+ * with psa_set_key_id(). By default, a key that has a persistent identifier
+ * is stored in the default storage area identifier by
+ * #PSA_KEY_LIFETIME_PERSISTENT. Call this function to choose a storage
+ * area, or to explicitly declare the key as volatile.
+ *
+ * This function does not access storage, it merely stores the given
+ * value in the structure.
+ * The persistent key will be written to storage when the attribute
+ * structure is passed to a key creation function such as
+ * psa_import_key(), psa_generate_random_key(),
+ * psa_generate_derived_key() or psa_copy_key().
+ *
+ * This function may be declared as `static` (i.e. without external
+ * linkage). This function may be provided as a function-like macro,
+ * but in this case it must evaluate each of its arguments exactly once.
+ *
+ * \param[out] attributes       The attribute structure to write to.
  * \param lifetime              The lifetime for the key.
  *                              If this is #PSA_KEY_LIFETIME_VOLATILE, the
- *                              key will be volatile, and \p id is ignored.
+ *                              key will be volatile, and the key identifier
+ *                              attribute is reset to 0.
  */
-static void psa_make_key_persistent(psa_key_attributes_t *attributes,
-                                    psa_key_id_t id,
-                                    psa_key_lifetime_t lifetime);
+static void psa_set_key_lifetime(psa_key_attributes_t *attributes,
+                                 psa_key_lifetime_t lifetime);
 
 /** Retrieve the key identifier from key attributes.
  *
diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h
index f6bec2c..df76571 100644
--- a/include/psa/crypto_struct.h
+++ b/include/psa/crypto_struct.h
@@ -279,12 +279,12 @@
     return( v );
 }
 
-static inline void psa_make_key_persistent(psa_key_attributes_t *attributes,
-                                           psa_key_id_t id,
-                                           psa_key_lifetime_t lifetime)
+static inline void psa_set_key_id(psa_key_attributes_t *attributes,
+                                  psa_key_id_t id)
 {
     attributes->id = id;
-    attributes->lifetime = lifetime;
+    if( attributes->lifetime == PSA_KEY_LIFETIME_VOLATILE )
+        attributes->lifetime = PSA_KEY_LIFETIME_PERSISTENT;
 }
 
 static inline psa_key_id_t psa_get_key_id(
@@ -293,6 +293,14 @@
     return( attributes->id );
 }
 
+static inline void psa_set_key_lifetime(psa_key_attributes_t *attributes,
+                                        psa_key_lifetime_t lifetime)
+{
+    attributes->lifetime = lifetime;
+    if( lifetime == PSA_KEY_LIFETIME_VOLATILE )
+        attributes->id = 0;
+}
+
 static inline psa_key_lifetime_t psa_get_key_lifetime(
     const psa_key_attributes_t *attributes)
 {
diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h
index d30af41..e67fc60 100644
--- a/include/psa/crypto_values.h
+++ b/include/psa/crypto_values.h
@@ -672,10 +672,8 @@
  * Then you may create and use a key as follows:
  * - Set the key usage field using #PSA_ALG_ANY_HASH, for example:
  *   ```
- *   psa_key_policy_set_usage(&policy,
- *                            PSA_KEY_USAGE_SIGN, //or PSA_KEY_USAGE_VERIFY
- *                            PSA_xxx_SIGNATURE(PSA_ALG_ANY_HASH));
- *   psa_set_key_policy(handle, &policy);
+ *   psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN); // or VERIFY
+ *   psa_set_key_algorithm(&attributes, PSA_xxx_SIGNATURE(PSA_ALG_ANY_HASH));
  *   ```
  * - Import or generate key material.
  * - Call psa_asymmetric_sign() or psa_asymmetric_verify(), passing
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index 752132a..991d91a 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -4,6 +4,21 @@
 PSA key attributes structure
 attributes_set_get:0x6963:PSA_KEY_LIFETIME_PERSISTENT:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_CCM:PSA_KEY_TYPE_AES:128
 
+PSA key attributes: id only
+persistence_attributes:0x1234:-1:-1:0x1234:PSA_KEY_LIFETIME_PERSISTENT
+
+PSA key attributes: lifetime=3 only
+persistence_attributes:-1:3:-1:0:3
+
+PSA key attributes: id then back to volatile
+persistence_attributes:0x1234:PSA_KEY_LIFETIME_VOLATILE:-1:0:PSA_KEY_LIFETIME_VOLATILE
+
+PSA key attributes: id then lifetime
+persistence_attributes:0x1234:3:-1:0x1234:3
+
+PSA key attributes: lifetime then id
+persistence_attributes:0x1234:3:0x1235:0x1235:3
+
 PSA import/export raw: 0 bytes
 import_export:"":PSA_KEY_TYPE_RAW_DATA:0:PSA_KEY_USAGE_EXPORT:0:0:PSA_SUCCESS:1
 
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 75b303b..8b57737 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -1098,7 +1098,7 @@
     size_t length;
     int ok = 0;
 
-    psa_make_key_persistent( &attributes, 0x6964, PSA_KEY_LIFETIME_PERSISTENT );
+    psa_set_key_id( &attributes, 0x6964 );
     psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT );
     psa_set_key_algorithm( &attributes, PSA_ALG_CTR );
     psa_set_key_type( &attributes, PSA_KEY_TYPE_AES );
@@ -1181,7 +1181,8 @@
     TEST_EQUAL( psa_get_key_type( &attributes ), 0 );
     TEST_EQUAL( psa_get_key_bits( &attributes ), 0 );
 
-    psa_make_key_persistent( &attributes, id, lifetime );
+    psa_set_key_id( &attributes, id );
+    psa_set_key_lifetime( &attributes, lifetime );
     psa_set_key_usage_flags( &attributes, usage_flags );
     psa_set_key_algorithm( &attributes, alg );
     psa_set_key_type( &attributes, type );
@@ -1206,6 +1207,29 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void persistence_attributes( int id1_arg, int lifetime_arg, int id2_arg,
+                             int expected_id_arg, int expected_lifetime_arg )
+{
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_id_t id1 = id1_arg;
+    psa_key_lifetime_t lifetime = lifetime_arg;
+    psa_key_id_t id2 = id2_arg;
+    psa_key_id_t expected_id = expected_id_arg;
+    psa_key_lifetime_t expected_lifetime = expected_lifetime_arg;
+
+    if( id1_arg != -1 )
+        psa_set_key_id( &attributes, id1 );
+    if( lifetime_arg != -1 )
+        psa_set_key_lifetime( &attributes, lifetime );
+    if( id2_arg != -1 )
+        psa_set_key_id( &attributes, id2 );
+
+    TEST_EQUAL( psa_get_key_id( &attributes ), expected_id );
+    TEST_EQUAL( psa_get_key_lifetime( &attributes ), expected_lifetime );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void import( data_t *data, int type_arg,
              int attr_bits_arg,
              int expected_status_arg )
@@ -4877,7 +4901,7 @@
 
     PSA_ASSERT( psa_crypto_init() );
 
-    psa_make_key_persistent( &attributes, key_id, PSA_KEY_LIFETIME_PERSISTENT );
+    psa_set_key_id( &attributes, key_id );
     psa_set_key_usage_flags( &attributes, usage_flags );
     psa_set_key_algorithm( &attributes, alg );
     psa_set_key_type( &attributes, type );
diff --git a/tests/suites/test_suite_psa_crypto_persistent_key.function b/tests/suites/test_suite_psa_crypto_persistent_key.function
index 1ebab9c..636f260 100644
--- a/tests/suites/test_suite_psa_crypto_persistent_key.function
+++ b/tests/suites/test_suite_psa_crypto_persistent_key.function
@@ -96,7 +96,7 @@
 
     PSA_ASSERT( psa_crypto_init() );
 
-    psa_make_key_persistent( &attributes, key_id, PSA_KEY_LIFETIME_PERSISTENT );
+    psa_set_key_id( &attributes, key_id );
     psa_set_key_type( &attributes, PSA_KEY_TYPE_RAW_DATA );
 
     TEST_EQUAL( psa_import_key( &attributes, data, data_length, &handle ),
@@ -122,7 +122,7 @@
 
     PSA_ASSERT( psa_crypto_init() );
 
-    psa_make_key_persistent( &attributes, key_id, PSA_KEY_LIFETIME_PERSISTENT );
+    psa_set_key_id( &attributes, key_id );
     psa_set_key_type( &attributes, first_type );
 
     PSA_ASSERT( psa_import_key( &attributes, first_data->x, first_data->len,
@@ -150,7 +150,7 @@
     PSA_ASSERT( psa_crypto_init() );
 
     /* Create another key in the same slot */
-    psa_make_key_persistent( &attributes, key_id, PSA_KEY_LIFETIME_PERSISTENT );
+    psa_set_key_id( &attributes, key_id );
     psa_set_key_type( &attributes, second_type );
     PSA_ASSERT( psa_import_key( &attributes, second_data->x, second_data->len,
                                 &handle ) );
@@ -172,7 +172,7 @@
 
     PSA_ASSERT( psa_crypto_init() );
 
-    psa_make_key_persistent( &attributes, key_id, PSA_KEY_LIFETIME_PERSISTENT );
+    psa_set_key_id( &attributes, key_id );
     psa_set_key_type( &attributes, type );
     TEST_EQUAL( psa_import_key( &attributes, data->x, data->len, &handle ),
                 expected_status );
@@ -224,7 +224,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    psa_make_key_persistent( &attributes, key_id, PSA_KEY_LIFETIME_PERSISTENT );
+    psa_set_key_id( &attributes, key_id );
     psa_set_key_type( &attributes, type );
     psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_EXPORT );
 
diff --git a/tests/suites/test_suite_psa_crypto_slot_management.function b/tests/suites/test_suite_psa_crypto_slot_management.function
index 3e4f0cc..5e594c2 100644
--- a/tests/suites/test_suite_psa_crypto_slot_management.function
+++ b/tests/suites/test_suite_psa_crypto_slot_management.function
@@ -143,7 +143,8 @@
     PSA_ASSERT( psa_crypto_init( ) );
 
     /* Get a handle and import a key. */
-    psa_make_key_persistent( &attributes, id, lifetime );
+    psa_set_key_id( &attributes, id );
+    psa_set_key_lifetime( &attributes, lifetime );
     psa_set_key_type( &attributes, type );
     psa_set_key_usage_flags( &attributes, usage_flags );
     psa_set_key_algorithm( &attributes, alg );
@@ -221,7 +222,8 @@
     PSA_ASSERT( psa_crypto_init( ) );
 
     /* Create a key. */
-    psa_make_key_persistent( &attributes, id, lifetime );
+    psa_set_key_id( &attributes, id );
+    psa_set_key_lifetime( &attributes, lifetime );
     psa_set_key_type( &attributes, type1 );
     psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_EXPORT );
     psa_set_key_algorithm( &attributes, 0 );
@@ -298,7 +300,8 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    psa_make_key_persistent( &attributes, id, lifetime );
+    psa_set_key_id( &attributes, id );
+    psa_set_key_lifetime( &attributes, lifetime );
     psa_set_key_type( &attributes, PSA_KEY_TYPE_RAW_DATA );
     TEST_EQUAL( psa_import_key( &attributes, material, sizeof( material ),
                                 &handle ),
@@ -345,8 +348,10 @@
 
     /* Populate the source slot. */
     if( source_lifetime != PSA_KEY_LIFETIME_VOLATILE )
-        psa_make_key_persistent( &source_attributes,
-                                 source_id, source_lifetime );
+    {
+        psa_set_key_id( &source_attributes, source_id );
+        psa_set_key_lifetime( &source_attributes, source_lifetime );
+    }
     psa_set_key_type( &source_attributes, source_type );
     psa_set_key_usage_flags( &source_attributes, source_usage );
     psa_set_key_algorithm( &source_attributes, source_alg );
@@ -358,8 +363,10 @@
 
     /* Prepare the target slot. */
     if( target_lifetime != PSA_KEY_LIFETIME_VOLATILE )
-        psa_make_key_persistent( &target_attributes,
-                                 target_id, target_lifetime );
+    {
+        psa_set_key_id( &target_attributes, target_id );
+        psa_set_key_lifetime( &target_attributes, target_lifetime );
+    }
     psa_set_key_usage_flags( &target_attributes, target_usage );
     psa_set_key_algorithm( &target_attributes, target_alg );
 
@@ -449,8 +456,10 @@
 
     /* Populate the source slot. */
     if( source_lifetime != PSA_KEY_LIFETIME_VOLATILE )
-        psa_make_key_persistent( &attributes,
-                                 source_id, source_lifetime );
+    {
+        psa_set_key_id( &attributes, source_id );
+        psa_set_key_lifetime( &attributes, source_lifetime );
+    }
     psa_set_key_type( &attributes, source_type );
     psa_set_key_usage_flags( &attributes, source_usage );
     psa_set_key_algorithm( &attributes, source_alg );
@@ -465,7 +474,8 @@
     }
     else
     {
-        psa_make_key_persistent( &attributes1, target_id, target_lifetime );
+        psa_set_key_id( &attributes1, target_id );
+        psa_set_key_lifetime( &attributes1, target_lifetime );
         psa_set_key_type( &attributes1, target_type );
         psa_set_key_usage_flags( &attributes1, target_usage );
         psa_set_key_algorithm( &attributes1, target_alg );
@@ -476,7 +486,8 @@
     PSA_ASSERT( psa_get_key_attributes( target_handle, &attributes1 ) );
 
     /* Make a copy attempt. */
-    psa_make_key_persistent( &attributes, target_id, target_lifetime );
+    psa_set_key_id( &attributes, target_id );
+    psa_set_key_lifetime( &attributes, target_lifetime );
     TEST_EQUAL( psa_copy_key( source_handle,
                               &attributes, &new_handle ),
                 PSA_ERROR_ALREADY_EXISTS );