psa: Disentangle public export and export code

Disentangle public export and export code to be
able to move the call to export and public
export operations to the driver wrapper.

Signed-off-by: Ronald Cron <ronald.cron@arm.com>
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index faccca6..e047489 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -1498,58 +1498,114 @@
 static psa_status_t psa_export_key_internal( const psa_key_slot_t *slot,
                                              uint8_t *data,
                                              size_t data_size,
-                                             size_t *data_length,
-                                             int export_public_key )
+                                             size_t *data_length )
 {
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
     const psa_drv_se_t *drv;
     psa_drv_se_context_t *drv_context;
 #endif /* MBEDTLS_PSA_CRYPTO_SE_C */
 
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+    if( psa_get_se_driver( slot->attr.lifetime, &drv, &drv_context ) )
+    {
+        if( ( drv->key_management == NULL   ) ||
+            ( drv->key_management->p_export == NULL ) )
+            return( PSA_ERROR_NOT_SUPPORTED );
+
+        return( drv->key_management->p_export(
+                     drv_context, psa_key_slot_get_slot_number( slot ),
+                     data, data_size, data_length ) );
+    }
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+
+    if( key_type_is_raw_bytes( slot->attr.type ) ||
+        PSA_KEY_TYPE_IS_RSA( slot->attr.type )   ||
+        PSA_KEY_TYPE_IS_ECC( slot->attr.type )      )
+    {
+        return( psa_export_key_buffer_internal(
+                    slot, data, data_size, data_length ) );
+    }
+    else
+    {
+        /* This shouldn't happen in the reference implementation, but
+           it is valid for a special-purpose implementation to omit
+           support for exporting certain key types. */
+        return( PSA_ERROR_NOT_SUPPORTED );
+    }
+}
+
+psa_status_t psa_export_key( mbedtls_svc_key_id_t key,
+                             uint8_t *data,
+                             size_t data_size,
+                             size_t *data_length )
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
+    psa_key_slot_t *slot;
+
+    /* 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
+     * the key to empty is a good choice because an empty key representation is
+     * unlikely to be accepted anywhere. */
     *data_length = 0;
 
-    if( export_public_key && ! PSA_KEY_TYPE_IS_ASYMMETRIC( slot->attr.type ) )
-        return( PSA_ERROR_INVALID_ARGUMENT );
+    /* Export requires the EXPORT flag. There is an exception for public keys,
+     * which don't require any flag, but
+     * psa_get_and_lock_key_slot_with_policy() takes care of this.
+     */
+    status = psa_get_and_lock_key_slot_with_policy( key, &slot,
+                                                    PSA_KEY_USAGE_EXPORT, 0 );
+    if( status != PSA_SUCCESS )
+        return( status );
 
     /* Reject a zero-length output buffer now, since this can never be a
      * valid key representation. This way we know that data must be a valid
      * pointer and we can do things like memset(data, ..., data_size). */
     if( data_size == 0 )
-        return( PSA_ERROR_BUFFER_TOO_SMALL );
+    {
+         status = PSA_ERROR_BUFFER_TOO_SMALL;
+         goto exit;
+    }
+
+    status = psa_export_key_internal( slot, data, data_size, data_length );
+
+exit:
+    unlock_status = psa_unlock_key_slot( slot );
+
+    return( ( status == PSA_SUCCESS ) ? unlock_status : status );
+}
+
+static psa_status_t psa_export_public_key_internal( const psa_key_slot_t *slot,
+                                                    uint8_t *data,
+                                                    size_t data_size,
+                                                    size_t *data_length )
+{
+#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
+    const psa_drv_se_t *drv;
+    psa_drv_se_context_t *drv_context;
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
 
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
     if( psa_get_se_driver( slot->attr.lifetime, &drv, &drv_context ) )
     {
-        psa_drv_se_export_key_t method;
-        if( drv->key_management == NULL )
+        if( ( drv->key_management == NULL ) ||
+            ( drv->key_management->p_export_public == NULL ) )
             return( PSA_ERROR_NOT_SUPPORTED );
-        method = ( export_public_key ?
-                   drv->key_management->p_export_public :
-                   drv->key_management->p_export );
-        if( method == NULL )
-            return( PSA_ERROR_NOT_SUPPORTED );
-        return( method( drv_context,
-                        psa_key_slot_get_slot_number( slot ),
-                        data, data_size, data_length ) );
-    }
-#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
 
-    if( key_type_is_raw_bytes( slot->attr.type ) )
-    {
-        return( psa_export_key_buffer_internal( slot, data, data_size, data_length ) );
+        return( drv->key_management->p_export_public(
+                    drv_context, psa_key_slot_get_slot_number( slot ),
+                    data, data_size, data_length ) );
     }
-    else if( PSA_KEY_TYPE_IS_RSA( slot->attr.type ) ||
+    else
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
+    if( PSA_KEY_TYPE_IS_RSA( slot->attr.type ) ||
              PSA_KEY_TYPE_IS_ECC( slot->attr.type ) )
     {
         if( PSA_KEY_TYPE_IS_PUBLIC_KEY( slot->attr.type ) )
         {
             /* Exporting public -> public */
-            return( psa_export_key_buffer_internal( slot, data, data_size, data_length ) );
-        }
-        else if( !export_public_key )
-        {
-            /* Exporting private -> private */
-            return( psa_export_key_buffer_internal( slot, data, data_size, data_length ) );
+            return( psa_export_key_buffer_internal(
+                        slot, data, data_size, data_length ) );
         }
 
         /* Need to export the public part of a private key,
@@ -1631,37 +1687,6 @@
         return( PSA_ERROR_NOT_SUPPORTED );
     }
 }
-
-psa_status_t psa_export_key( mbedtls_svc_key_id_t key,
-                             uint8_t *data,
-                             size_t data_size,
-                             size_t *data_length )
-{
-    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
-    psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
-    psa_key_slot_t *slot;
-
-    /* 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
-     * the key to empty is a good choice because an empty key representation is
-     * unlikely to be accepted anywhere. */
-    *data_length = 0;
-
-    /* Export requires the EXPORT flag. There is an exception for public keys,
-     * which don't require any flag, but
-     * psa_get_and_lock_key_slot_with_policy() takes care of this.
-     */
-    status = psa_get_and_lock_key_slot_with_policy( key, &slot,
-                                                    PSA_KEY_USAGE_EXPORT, 0 );
-    if( status != PSA_SUCCESS )
-        return( status );
-
-    status = psa_export_key_internal( slot, data, data_size, data_length, 0 );
-    unlock_status = psa_unlock_key_slot( slot );
-
-    return( ( status == PSA_SUCCESS ) ? unlock_status : status );
-}
-
 psa_status_t psa_export_public_key( mbedtls_svc_key_id_t key,
                                     uint8_t *data,
                                     size_t data_size,
@@ -1682,7 +1707,25 @@
     if( status != PSA_SUCCESS )
         return( status );
 
-    status = psa_export_key_internal( slot, data, data_size, data_length, 1 );
+    if( ! PSA_KEY_TYPE_IS_ASYMMETRIC( slot->attr.type ) )
+    {
+         status = PSA_ERROR_INVALID_ARGUMENT;
+         goto exit;
+    }
+
+    /* Reject a zero-length output buffer now, since this can never be a
+     * valid key representation. This way we know that data must be a valid
+     * pointer and we can do things like memset(data, ..., data_size). */
+    if( data_size == 0 )
+    {
+         status = PSA_ERROR_BUFFER_TOO_SMALL;
+         goto exit;
+    }
+
+    status = psa_export_public_key_internal(
+                 slot, data, data_size, data_length );
+
+exit:
     unlock_status = psa_unlock_key_slot( slot );
 
     return( ( status == PSA_SUCCESS ) ? unlock_status : status );