Crypto: Align implementation to pass PSA API compliance

-- Enable the option to specify maximum supported key
   length and maximum number of key slots at build time
   for the key module
-- Enable the option to specify internal buffer size
   for scratch allocation at build time for the
   engine module
-- Make sure that MD-2 and MD-4 hashes are enabled and
   supported by the back end as they are tested by the
   PSA API compliance tests
-- Other alignment needed to pass PSA API compliance
   tests, as changes in return codes, more error
   checking, and documentation update when needed

Change-Id: I4bb78b06de2fa01580c4cbd361c946d32c614240
Signed-off-by: Jamie Fox <jamie.fox@arm.com>
Co-Authored-by: Antonio de Angelis <antonio.deangelis@arm.com>
diff --git a/secure_fw/services/crypto/crypto_cipher.c b/secure_fw/services/crypto/crypto_cipher.c
index 84b5b78..a88f4a8 100644
--- a/secure_fw/services/crypto/crypto_cipher.c
+++ b/secure_fw/services/crypto/crypto_cipher.c
@@ -18,13 +18,23 @@
 #include "tfm_crypto_api.h"
 #include "crypto_utils.h"
 
+/**
+ * \def CRYPTO_CIPHER_MAX_KEY_LENGTH
+ *
+ * \brief Specifies the maximum key length supported by the
+ *        Cipher operations in this implementation
+ */
+#ifndef CRYPTO_CIPHER_MAX_KEY_LENGTH
+#define CRYPTO_CIPHER_MAX_KEY_LENGTH (32)
+#endif
+
 static enum tfm_crypto_err_t tfm_crypto_cipher_setup(
                                            psa_cipher_operation_t *operation,
                                            psa_key_slot_t key,
                                            psa_algorithm_t alg,
                                            enum engine_cipher_mode_t c_mode)
 {
-    uint8_t key_data[TFM_CRYPTO_MAX_KEY_LENGTH];
+    uint8_t key_data[CRYPTO_CIPHER_MAX_KEY_LENGTH];
     size_t key_size;
     psa_key_type_t key_type = PSA_KEY_TYPE_NONE;
     psa_status_t status = PSA_SUCCESS;
@@ -48,6 +58,16 @@
     /* Access the key module to retrieve key related information */
     err = tfm_crypto_get_key_information(key, &key_type, &key_size);
     if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+        return err;
+    }
+
+    /* Check if it's a raw data key type */
+    if (key_type == PSA_KEY_TYPE_RAW_DATA) {
+        return TFM_CRYPTO_ERR_PSA_ERROR_NOT_PERMITTED;
+    }
+
+    /* Check compatibility between key and algorithm */
+    if ((key_type == PSA_KEY_TYPE_ARC4) && (alg != PSA_ALG_ARC4)) {
         return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
     }
 
@@ -101,7 +121,7 @@
                              usage,
                              alg,
                              key_data,
-                             TFM_CRYPTO_MAX_KEY_LENGTH,
+                             CRYPTO_CIPHER_MAX_KEY_LENGTH,
                              &key_size);
     if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
         /* Release the operation context */
@@ -260,6 +280,9 @@
         return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
     }
 
+    /* Initialise the output length to zero */
+    *output_length = 0;
+
     /* Look up the corresponding operation context */
     err = tfm_crypto_operation_lookup(TFM_CRYPTO_CIPHER_OPERATION,
                                       operation->handle,
@@ -278,8 +301,6 @@
         /* This call is used to set the IV on the object */
         err = tfm_crypto_cipher_set_iv(operation, input, input_length);
 
-        *output_length = 0;
-
         return err;
     }
 
@@ -288,6 +309,13 @@
         return TFM_CRYPTO_ERR_PSA_ERROR_BAD_STATE;
     }
 
+    /* FIXME: The implementation currently expects to work only on blocks
+     *        of input data whose length is equal to the block size
+     */
+    if (input_length > output_size) {
+        return TFM_CRYPTO_ERR_PSA_ERROR_BUFFER_TOO_SMALL;
+    }
+
     /* Update the cipher output with the input chunk on the engine */
     status = tfm_crypto_engine_cipher_update(&(ctx->engine_ctx),
                                              input,
@@ -339,6 +367,13 @@
         return err;
     }
 
+    /* Check that the output buffer is large enough for up to one block size of
+     * output data.
+     */
+    if (output_size < ctx->block_size) {
+        return TFM_CRYPTO_ERR_PSA_ERROR_BUFFER_TOO_SMALL;
+    }
+
     /* Finalise the operation on the crypto engine */
     status = tfm_crypto_engine_cipher_finish(&(ctx->engine_ctx),
                                              output,