Always access key slots through accessor functions

New functions psa_get_key_slot(), psa_get_empty_key_slot(),
psa_get_key_from_slot() to access a key slot object from a key slot
number. These functions perform all requisite validations:

* psa_get_key_slot() verifies that the key slot number is in range.
* psa_get_empty_key_slot() verifies that the slot is empty.
* psa_get_key_from_slot() verifies that the slot contains a key with
  a suitable policy.

Always use these functions so as to make sure that the requisite
validations are always performed.
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 6dff2f5..f156d0c 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -339,6 +339,72 @@
     }
 }
 
+/* Retrieve a key slot, occupied or not. */
+static psa_status_t psa_get_key_slot( psa_key_slot_t key,
+                                      key_slot_t **p_slot )
+{
+    if( key == 0 || key > PSA_KEY_SLOT_COUNT )
+        return( PSA_ERROR_INVALID_ARGUMENT );
+
+    *p_slot = &global_data.key_slots[key];
+    return( PSA_SUCCESS );
+}
+
+/* Retrieve an empty key slot (slot with no key data, but possibly
+ * with some metadata such as a policy). */
+static psa_status_t psa_get_empty_key_slot( psa_key_slot_t key,
+                                            key_slot_t **p_slot )
+{
+    psa_status_t status;
+    key_slot_t *slot = NULL;
+
+    *p_slot = NULL;
+
+    status = psa_get_key_slot( key, &slot );
+    if( status != PSA_SUCCESS )
+        return( status );
+
+    if( slot->type != PSA_KEY_TYPE_NONE )
+        return( PSA_ERROR_OCCUPIED_SLOT );
+
+    *p_slot = slot;
+    return( status );
+}
+
+/* Retrieve a slot which must contain a key. The key must have allow all
+ * the usage flags set in \p usage. If \p alg is nonzero, the key must
+ * allow operations with this algorithm. */
+static psa_status_t psa_get_key_from_slot( psa_key_slot_t key,
+                                           key_slot_t **p_slot,
+                                           psa_key_usage_t usage,
+                                           psa_algorithm_t alg )
+{
+    psa_status_t status;
+    key_slot_t *slot = NULL;
+
+    *p_slot = NULL;
+
+    status = psa_get_key_slot( key, &slot );
+    if( status != PSA_SUCCESS )
+        return( status );
+    if( slot->type == PSA_KEY_TYPE_NONE )
+        return( PSA_ERROR_EMPTY_SLOT );
+
+    /* Enforce that usage policy for the key slot contains all the flags
+     * required by the usage parameter. There is one exception: public
+     * keys can always be exported, so we treat public key objects as
+     * if they had the export flag. */
+    if( PSA_KEY_TYPE_IS_PUBLIC_KEY( slot->type ) )
+        usage &= ~PSA_KEY_USAGE_EXPORT;
+    if( ( slot->policy.usage & usage ) != usage )
+        return( PSA_ERROR_NOT_PERMITTED );
+    if( alg != 0 && ( alg != slot->policy.alg ) )
+        return( PSA_ERROR_NOT_PERMITTED );
+
+    *p_slot = slot;
+    return( PSA_SUCCESS );
+}
+
 
 
 /****************************************************************/
@@ -481,16 +547,13 @@
                              size_t data_length )
 {
     key_slot_t *slot;
-
-    if( key == 0 || key > PSA_KEY_SLOT_COUNT )
-        return( PSA_ERROR_INVALID_ARGUMENT );
-    slot = &global_data.key_slots[key];
-    if( slot->type != PSA_KEY_TYPE_NONE )
-        return( PSA_ERROR_OCCUPIED_SLOT );
+    psa_status_t status = PSA_SUCCESS;
+    status = psa_get_empty_key_slot( key, &slot );
+    if( status != PSA_SUCCESS )
+        return( status );
 
     if( key_type_is_raw_bytes( type ) )
     {
-        psa_status_t status;
         /* Ensure that a bytes-to-bit conversion won't overflow. */
         if( data_length > SIZE_MAX / 8 )
             return( PSA_ERROR_NOT_SUPPORTED );
@@ -510,7 +573,6 @@
     {
         int ret;
         mbedtls_pk_context pk;
-        psa_status_t status = PSA_SUCCESS;
         mbedtls_pk_init( &pk );
         if( PSA_KEY_TYPE_IS_KEYPAIR( type ) )
             ret = mbedtls_pk_parse_key( &pk, data, data_length, NULL, 0 );
@@ -583,10 +645,12 @@
 psa_status_t psa_destroy_key( psa_key_slot_t key )
 {
     key_slot_t *slot;
+    psa_status_t status;
 
-    if( key == 0 || key > PSA_KEY_SLOT_COUNT )
-        return( PSA_ERROR_INVALID_ARGUMENT );
-    slot = &global_data.key_slots[key];
+    status = psa_get_key_slot( key, &slot );
+    if( status != PSA_SUCCESS )
+        return( status );
+
     if( slot->type == PSA_KEY_TYPE_NONE )
     {
         /* No key material to clean, but do zeroize the slot below to wipe
@@ -629,16 +693,19 @@
                                       size_t *bits )
 {
     key_slot_t *slot;
+    psa_status_t status;
 
-    if( key == 0 || key > PSA_KEY_SLOT_COUNT )
-        return( PSA_ERROR_EMPTY_SLOT );
-    slot = &global_data.key_slots[key];
     if( type != NULL )
-        *type = slot->type;
+        *type = 0;
     if( bits != NULL )
         *bits = 0;
+    status = psa_get_key_slot( key, &slot );
+    if( status != PSA_SUCCESS )
+        return( status );
     if( slot->type == PSA_KEY_TYPE_NONE )
         return( PSA_ERROR_EMPTY_SLOT );
+    if( type != NULL )
+        *type = slot->type;
 
     if( key_type_is_raw_bytes( slot->type ) )
     {
@@ -679,6 +746,13 @@
                                               int export_public_key )
 {
     key_slot_t *slot;
+    psa_status_t status;
+    /* Exporting a public key doesn't require a usage flag. If we're
+     * called by psa_export_public_key(), don't require the EXPORT flag.
+     * If we're called by psa_export_key(), do require the EXPORT flag;
+     * if the key turns out to be public key object, psa_get_key_from_slot()
+     * will ignore this flag. */
+    psa_key_usage_t usage = export_public_key ? 0 : PSA_KEY_USAGE_EXPORT;
 
     /* Set the key to empty now, so that even when there are errors, we always
      * set data_length to a value between 0 and data_size. On error, setting
@@ -686,20 +760,12 @@
      * unlikely to be accepted anywhere. */
     *data_length = 0;
 
-    if( key == 0 || key > PSA_KEY_SLOT_COUNT )
-        return( PSA_ERROR_EMPTY_SLOT );
-    slot = &global_data.key_slots[key];
-    if( slot->type == PSA_KEY_TYPE_NONE )
-        return( PSA_ERROR_EMPTY_SLOT );
-
+    status = psa_get_key_from_slot( key, &slot, usage, 0 );
+    if( status != PSA_SUCCESS )
+        return( status );
     if( export_public_key && ! PSA_KEY_TYPE_IS_ASYMMETRIC( slot->type ) )
         return( PSA_ERROR_INVALID_ARGUMENT );
 
-    if( ! export_public_key &&
-        ! PSA_KEY_TYPE_IS_PUBLIC_KEY( slot->type ) &&
-        ( slot->policy.usage & PSA_KEY_USAGE_EXPORT ) == 0 )
-        return( PSA_ERROR_NOT_PERMITTED );
-
     if( key_type_is_raw_bytes( slot->type ) )
     {
         if( slot->data.raw.bytes > data_size )
@@ -1424,13 +1490,17 @@
     if( status != PSA_SUCCESS )
         return( status );
 
-    slot = &global_data.key_slots[key];
-    if( slot->type == PSA_KEY_TYPE_NONE )
-        return( PSA_ERROR_EMPTY_SLOT );
+    status = psa_get_key_from_slot( key, &slot, 0, alg );
+    if( status != PSA_SUCCESS )
+        return( status );
 
+    /* Since this function is called identically for a sign or verify
+     * operation, we don't know yet whether the operation is permitted.
+     * Store the part of the key policy that we can't check in the
+     * operation structure. psa_mac_finish() or psa_mac_verify() will
+     * check that remaining part. */
     if( ( slot->policy.usage & PSA_KEY_USAGE_SIGN ) != 0 )
         operation->key_usage_sign = 1;
-
     if( ( slot->policy.usage & PSA_KEY_USAGE_VERIFY ) != 0 )
         operation->key_usage_verify = 1;
 
@@ -1919,27 +1989,14 @@
     (void) salt;
     (void) salt_length;
 
-    if( key == 0 || key > PSA_KEY_SLOT_COUNT )
-    {
-        status = PSA_ERROR_EMPTY_SLOT;
+    status = psa_get_key_from_slot( key, &slot, PSA_KEY_USAGE_SIGN, alg );
+    if( status != PSA_SUCCESS )
         goto exit;
-    }
-    slot = &global_data.key_slots[key];
-    if( slot->type == PSA_KEY_TYPE_NONE )
-    {
-        status = PSA_ERROR_EMPTY_SLOT;
-        goto exit;
-    }
     if( ! PSA_KEY_TYPE_IS_KEYPAIR( slot->type ) )
     {
         status = PSA_ERROR_INVALID_ARGUMENT;
         goto exit;
     }
-    if( ! ( slot->policy.usage & PSA_KEY_USAGE_SIGN ) )
-    {
-        status = PSA_ERROR_NOT_PERMITTED;
-        goto exit;
-    }
 
 #if defined(MBEDTLS_RSA_C)
     if( slot->type == PSA_KEY_TYPE_RSA_KEYPAIR )
@@ -1999,17 +2056,14 @@
                                     size_t signature_length )
 {
     key_slot_t *slot;
+    psa_status_t status;
 
     (void) salt;
     (void) salt_length;
 
-    if( key == 0 || key > PSA_KEY_SLOT_COUNT )
-        return( PSA_ERROR_INVALID_ARGUMENT );
-    slot = &global_data.key_slots[key];
-    if( slot->type == PSA_KEY_TYPE_NONE )
-        return( PSA_ERROR_EMPTY_SLOT );
-    if( ! ( slot->policy.usage & PSA_KEY_USAGE_VERIFY ) )
-        return( PSA_ERROR_NOT_PERMITTED );
+    status = psa_get_key_from_slot( key, &slot, PSA_KEY_USAGE_VERIFY, alg );
+    if( status != PSA_SUCCESS )
+        return( status );
 
 #if defined(MBEDTLS_RSA_C)
     if( slot->type == PSA_KEY_TYPE_RSA_KEYPAIR ||
@@ -2054,19 +2108,17 @@
                                      size_t *output_length )
 {
     key_slot_t *slot;
+    psa_status_t status;
+
     (void) salt;
     (void) salt_length;
     *output_length = 0;
 
-    if( key == 0 || key > PSA_KEY_SLOT_COUNT )
-        return( PSA_ERROR_INVALID_ARGUMENT );
-    slot = &global_data.key_slots[key];
-    if( slot->type == PSA_KEY_TYPE_NONE )
-        return( PSA_ERROR_EMPTY_SLOT );
+    status = psa_get_key_from_slot( key, &slot, PSA_KEY_USAGE_ENCRYPT, alg );
+    if( status != PSA_SUCCESS )
+        return( status );
     if( ! PSA_KEY_TYPE_IS_KEYPAIR( slot->type ) )
         return( PSA_ERROR_INVALID_ARGUMENT );
-    if( ! ( slot->policy.usage & PSA_KEY_USAGE_ENCRYPT ) )
-        return( PSA_ERROR_NOT_PERMITTED );
 
 #if defined(MBEDTLS_RSA_C)
     if( slot->type == PSA_KEY_TYPE_RSA_KEYPAIR ||
@@ -2121,19 +2173,17 @@
                                      size_t *output_length )
 {
     key_slot_t *slot;
+    psa_status_t status;
+
     (void) salt;
     (void) salt_length;
     *output_length = 0;
 
-    if( key == 0 || key > PSA_KEY_SLOT_COUNT )
-        return( PSA_ERROR_EMPTY_SLOT );
-    slot = &global_data.key_slots[key];
-    if( slot->type == PSA_KEY_TYPE_NONE )
-        return( PSA_ERROR_EMPTY_SLOT );
+    status = psa_get_key_from_slot( key, &slot, PSA_KEY_USAGE_DECRYPT, alg );
+    if( status != PSA_SUCCESS )
+        return( status );
     if( ! PSA_KEY_TYPE_IS_KEYPAIR( slot->type ) )
         return( PSA_ERROR_INVALID_ARGUMENT );
-    if( ! ( slot->policy.usage & PSA_KEY_USAGE_DECRYPT ) )
-        return( PSA_ERROR_NOT_PERMITTED );
 
 #if defined(MBEDTLS_RSA_C)
     if( slot->type == PSA_KEY_TYPE_RSA_KEYPAIR )
@@ -2216,6 +2266,9 @@
     psa_key_type_t key_type;
     size_t key_bits;
     const mbedtls_cipher_info_t *cipher_info = NULL;
+    psa_key_usage_t usage = ( cipher_operation == MBEDTLS_ENCRYPT ?
+                              PSA_KEY_USAGE_ENCRYPT :
+                              PSA_KEY_USAGE_DECRYPT );
 
     status = psa_cipher_init( operation, alg );
     if( status != PSA_SUCCESS )
@@ -2224,7 +2277,9 @@
     status = psa_get_key_information( key, &key_type, &key_bits );
     if( status != PSA_SUCCESS )
         return( status );
-    slot = &global_data.key_slots[key];
+    status = psa_get_key_from_slot( key, &slot, usage, alg);
+    if( status != PSA_SUCCESS )
+        return( status );
 
     cipher_info = mbedtls_cipher_info_from_psa( alg, key_type, key_bits, NULL );
     if( cipher_info == NULL )
@@ -2525,13 +2580,14 @@
                                  const psa_key_policy_t *policy )
 {
     key_slot_t *slot;
+    psa_status_t status;
 
-    if( key == 0 || key > PSA_KEY_SLOT_COUNT || policy == NULL )
+    if( policy == NULL )
         return( PSA_ERROR_INVALID_ARGUMENT );
 
-    slot = &global_data.key_slots[key];
-    if( slot->type != PSA_KEY_TYPE_NONE )
-        return( PSA_ERROR_OCCUPIED_SLOT );
+    status = psa_get_empty_key_slot( key, &slot );
+    if( status != PSA_SUCCESS )
+        return( status );
 
     if( ( policy->usage & ~( PSA_KEY_USAGE_EXPORT |
                              PSA_KEY_USAGE_ENCRYPT |
@@ -2549,11 +2605,14 @@
                                  psa_key_policy_t *policy )
 {
     key_slot_t *slot;
+    psa_status_t status;
 
-    if( key == 0 || key > PSA_KEY_SLOT_COUNT || policy == NULL )
+    if( policy == NULL )
         return( PSA_ERROR_INVALID_ARGUMENT );
 
-    slot = &global_data.key_slots[key];
+    status = psa_get_key_slot( key, &slot );
+    if( status != PSA_SUCCESS )
+        return( status );
 
     *policy = slot->policy;
 
@@ -2570,11 +2629,11 @@
                                    psa_key_lifetime_t *lifetime )
 {
     key_slot_t *slot;
+    psa_status_t status;
 
-    if( key == 0 || key > PSA_KEY_SLOT_COUNT )
-        return( PSA_ERROR_INVALID_ARGUMENT );
-
-    slot = &global_data.key_slots[key];
+    status = psa_get_key_slot( key, &slot );
+    if( status != PSA_SUCCESS )
+        return( status );
 
     *lifetime = slot->lifetime;
 
@@ -2585,18 +2644,16 @@
                                    psa_key_lifetime_t lifetime )
 {
     key_slot_t *slot;
-
-    if( key == 0 || key > PSA_KEY_SLOT_COUNT )
-        return( PSA_ERROR_INVALID_ARGUMENT );
+    psa_status_t status;
 
     if( lifetime != PSA_KEY_LIFETIME_VOLATILE &&
         lifetime != PSA_KEY_LIFETIME_PERSISTENT &&
         lifetime != PSA_KEY_LIFETIME_WRITE_ONCE)
         return( PSA_ERROR_INVALID_ARGUMENT );
 
-    slot = &global_data.key_slots[key];
-    if( slot->type != PSA_KEY_TYPE_NONE )
-        return( PSA_ERROR_OCCUPIED_SLOT );
+    status = psa_get_empty_key_slot( key, &slot );
+    if( status != PSA_SUCCESS )
+        return( status );
 
     if( lifetime != PSA_KEY_LIFETIME_VOLATILE )
         return( PSA_ERROR_NOT_SUPPORTED );
@@ -2639,18 +2696,15 @@
     status = psa_get_key_information( key, &key_type, &key_bits );
     if( status != PSA_SUCCESS )
         return( status );
-    slot = &global_data.key_slots[key];
-    if( slot->type == PSA_KEY_TYPE_NONE )
-        return( PSA_ERROR_EMPTY_SLOT );
+    status = psa_get_key_from_slot( key, &slot, PSA_KEY_USAGE_ENCRYPT, alg );
+    if( status != PSA_SUCCESS )
+        return( status );
 
     cipher_info = mbedtls_cipher_info_from_psa( alg, key_type,
                                                 key_bits, &cipher_id );
     if( cipher_info == NULL )
         return( PSA_ERROR_NOT_SUPPORTED );
 
-    if( ( slot->policy.usage & PSA_KEY_USAGE_ENCRYPT ) == 0 )
-        return( PSA_ERROR_NOT_PERMITTED );
-
     if( ( key_type & PSA_KEY_TYPE_CATEGORY_MASK ) !=
         PSA_KEY_TYPE_CATEGORY_SYMMETRIC )
         return( PSA_ERROR_INVALID_ARGUMENT );
@@ -2787,18 +2841,15 @@
     status = psa_get_key_information( key, &key_type, &key_bits );
     if( status != PSA_SUCCESS )
         return( status );
-    slot = &global_data.key_slots[key];
-    if( slot->type == PSA_KEY_TYPE_NONE )
-        return( PSA_ERROR_EMPTY_SLOT );
+    status = psa_get_key_from_slot( key, &slot, PSA_KEY_USAGE_DECRYPT, alg );
+    if( status != PSA_SUCCESS )
+        return( status );
 
     cipher_info = mbedtls_cipher_info_from_psa( alg, key_type,
                                                 key_bits, &cipher_id );
     if( cipher_info == NULL )
         return( PSA_ERROR_NOT_SUPPORTED );
 
-    if( !( slot->policy.usage & PSA_KEY_USAGE_DECRYPT ) )
-        return( PSA_ERROR_NOT_PERMITTED );
-
     if( ( key_type & PSA_KEY_TYPE_CATEGORY_MASK ) !=
         PSA_KEY_TYPE_CATEGORY_SYMMETRIC )
         return( PSA_ERROR_INVALID_ARGUMENT );
@@ -2903,19 +2954,18 @@
                                size_t parameters_size )
 {
     key_slot_t *slot;
+    psa_status_t status;
 
-    if( key == 0 || key > PSA_KEY_SLOT_COUNT )
-        return( PSA_ERROR_INVALID_ARGUMENT );
-    slot = &global_data.key_slots[key];
-    if( slot->type != PSA_KEY_TYPE_NONE )
-        return( PSA_ERROR_OCCUPIED_SLOT );
     if( parameters == NULL && parameters_size != 0 )
         return( PSA_ERROR_INVALID_ARGUMENT );
 
+    status = psa_get_empty_key_slot( key, &slot );
+    if( status != PSA_SUCCESS )
+        return( status );
+
     if( key_type_is_raw_bytes( type ) )
     {
-        psa_status_t status = prepare_raw_data_slot( type, bits,
-                                                     &slot->data.raw );
+        status = prepare_raw_data_slot( type, bits, &slot->data.raw );
         if( status != PSA_SUCCESS )
             return( status );
         status = psa_generate_random( slot->data.raw.data,