ADAC: Add PSA Crypto implementation

Signed-off-by: Chris Reed <chris.reed@arm.com>
Signed-off-by: Mathias Brossard <mathias.brossard@arm.com>
Change-Id: If3e96826347feae241d9fcd29d260fbf1bb88644
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d28eed1..0a3ee55 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -49,6 +49,7 @@
 add_subdirectory(${PSA_ADAC_ROOT}/psa-adac/core adac_core)
 add_subdirectory(${PSA_ADAC_ROOT}/psa-adac/sda adac_sda)
 add_subdirectory(${PSA_ADAC_TARGET_PATH} adac_platform)
+add_subdirectory(${PSA_ADAC_ROOT}/psa_crypto)
 
 target_link_libraries(${PROJECT_NAME}
     PUBLIC
diff --git a/psa-adac/core/src/adac_crypto.h b/psa-adac/core/src/adac_crypto.h
deleted file mode 100644
index 7b594d2..0000000
--- a/psa-adac/core/src/adac_crypto.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright (c) 2020 Arm Limited. All rights reserved.
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef PSA_ADAC_CRYPTO_H
-#define PSA_ADAC_CRYPTO_H
-
-#include <psa/crypto.h>
-
-psa_status_t load_rsa_3072_public_key(uint8_t *key, size_t key_size, psa_key_handle_t *handle);
-psa_status_t load_rsa_4096_public_key(uint8_t *key, size_t key_size, psa_key_handle_t *handle);
-psa_status_t load_ecdsa_p256_public_key(uint8_t *key, size_t key_size, psa_key_handle_t *handle);
-psa_status_t load_ecdsa_p521_public_key(uint8_t *key, size_t key_size, psa_key_handle_t *handle);
-
-#endif // PSA_ADAC_CRYPTO_H
diff --git a/psa_crypto/CMakeLists.txt b/psa_crypto/CMakeLists.txt
new file mode 100644
index 0000000..3e70624
--- /dev/null
+++ b/psa_crypto/CMakeLists.txt
@@ -0,0 +1,27 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+add_library(psa_adac_psa_crypto STATIC)
+
+target_sources(psa_adac_psa_crypto
+    PRIVATE
+        adac_crypto_psa.c
+        adac_crypto_psa_hash.c
+        adac_crypto_psa_mac.c
+        adac_crypto_psa_pk.c
+)
+
+target_link_libraries(psa_adac_psa_crypto
+    PRIVATE
+        psa_adac_config
+        tfm_sprt
+)
+
+target_link_libraries(trusted-firmware-m-psa-adac
+    PRIVATE
+        psa_adac_psa_crypto
+)
diff --git a/psa_crypto/adac_crypto_psa.c b/psa_crypto/adac_crypto_psa.c
new file mode 100644
index 0000000..a982230
--- /dev/null
+++ b/psa_crypto/adac_crypto_psa.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "adac_crypto_psa.h"
+#include "psa_adac_debug.h"
+
+psa_status_t psa_adac_crypto_init(void)
+{
+    psa_status_t r = psa_crypto_init();
+    if (r == PSA_SUCCESS) {
+        PSA_ADAC_LOG_INFO("psa-crypto", "PSA Crypto API Initialized\n");
+    } else {
+        PSA_ADAC_LOG_ERR("psa-crypto", "PSA Crypto API Initialization failure => %d\n", r);
+    }
+
+    return r;
+}
+
+psa_status_t psa_adac_generate_challenge(uint8_t *output, size_t output_size)
+{
+    return psa_generate_random(output, output_size);
+}
+
+psa_status_t psa_adac_verify_vendor(uint8_t key_type,
+                                    uint8_t *key,
+                                    size_t key_size,
+                                    psa_algorithm_t hash_algo,
+                                    const uint8_t *inputs[],
+                                    size_t input_sizes[],
+                                    size_t input_count,
+                                    psa_algorithm_t sig_algo,
+                                    uint8_t *sig,
+                                    size_t sig_size)
+{
+    psa_status_t ret = PSA_ERROR_NOT_SUPPORTED;
+#if (defined(PSA_ADAC_CMAC) || defined(PSA_ADAC_HMAC))
+    if ((key_type == CMAC_AES) || (key_type == HMAC_SHA256)) {
+        ret = PSA_SUCCESS;
+#if defined(PSA_ADAC_HMAC)
+        if ((key_type == HMAC_SHA256) &&
+            ((sig_algo != HMAC_SIGN_ALGORITHM) ||
+            (hash_algo != HMAC_HASH_ALGORITHM))) {
+            ret = PSA_ERROR_INVALID_ARGUMENT;
+        }
+#endif /* PSA_ADAC_HMAC */
+#if defined(PSA_ADAC_CMAC)
+        if ((key_type == CMAC_AES) &&
+            ((sig_algo != CMAC_SIGN_ALGORITHM) ||
+            (hash_algo != CMAC_HASH_ALGORITHM))) {
+            ret = PSA_ERROR_INVALID_ARGUMENT;
+        }
+#endif /* PSA_ADAC_CMAC */
+        if (PSA_SUCCESS == ret) {
+            ret = psa_adac_verify_mac(key_type,
+                                      key,
+                                      key_size,
+                                      inputs,
+                                      input_sizes,
+                                      input_count,
+                                      sig_algo,
+                                      sig,
+                                      sig_size);
+        }
+    }
+#endif /* (defined(PSA_ADAC_CMAC) || defined(PSA_ADAC_HMAC)) */
+
+    // TODO: Add support for extra algorithms
+    return ret;
+}
diff --git a/psa_crypto/adac_crypto_psa.h b/psa_crypto/adac_crypto_psa.h
new file mode 100644
index 0000000..f8277a1
--- /dev/null
+++ b/psa_crypto/adac_crypto_psa.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __ADAC_CRYPTO_PSA_H__
+#define __ADAC_CRYPTO_PSA_H__
+
+#include "psa_adac_config.h"
+#include "psa_adac.h"
+#include "psa/crypto.h"
+#include "psa_adac_crypto_api.h"
+#include "psa_adac_cryptosystems.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+psa_status_t psa_adac_verify_vendor(uint8_t key_type,
+                                    uint8_t *key,
+                                    size_t key_size,
+                                    psa_algorithm_t hash_algo,
+                                    const uint8_t *inputs[],
+                                    size_t input_sizes[],
+                                    size_t input_count,
+                                    psa_algorithm_t sig_algo,
+                                    uint8_t *sig,
+                                    size_t sig_size);
+
+psa_status_t psa_adac_verify_mac(uint8_t key_type,
+                                 uint8_t *key,
+                                 size_t key_size,
+                                 const uint8_t *inputs[],
+                                 size_t input_sizes[],
+                                 size_t input_count,
+                                 psa_algorithm_t mac_algo,
+                                 uint8_t *mac,
+                                 size_t mac_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__ADAC_CRYPTO_PSA_H__ */
diff --git a/psa_crypto/adac_crypto_psa_hash.c b/psa_crypto/adac_crypto_psa_hash.c
new file mode 100644
index 0000000..23cc388
--- /dev/null
+++ b/psa_crypto/adac_crypto_psa_hash.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <string.h>
+#include "psa_adac.h"
+#include "psa_adac_crypto_api.h"
+
+psa_status_t psa_adac_hash(psa_algorithm_t alg,
+                           const uint8_t *input,
+                           size_t input_size,
+                           uint8_t *hash,
+                           size_t hash_size,
+                           size_t *hash_length)
+{
+    return psa_adac_hash_multiple(alg, &input, &input_size, 1,
+                                  hash, hash_size, hash_length);
+}
+
+psa_status_t psa_adac_hash_multiple(psa_algorithm_t alg,
+                                    const uint8_t *inputs[],
+                                    size_t input_sizes[],
+                                    size_t input_count,
+                                    uint8_t hash[],
+                                    size_t hash_size,
+                                    size_t *hash_length)
+{
+    psa_status_t status;
+    psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT;
+    if (PSA_ALG_IS_VENDOR_DEFINED(alg) != 0) {
+        // TODO: Add support for extra algorithms
+        status = PSA_ERROR_NOT_SUPPORTED;
+    } else {
+        status = psa_hash_setup(&hash_operation, alg);
+        for (size_t i = 0; (i < input_count) && (status == PSA_SUCCESS); i++) {
+            status = psa_hash_update(&hash_operation, inputs[i], input_sizes[i]);
+
+        }
+        if (PSA_SUCCESS == status) {
+            status = psa_hash_finish(&hash_operation, hash, hash_size, hash_length);
+        } else {
+            /* Free all allocated context in case hashing operation fails */
+            /* Return the failed error status to the callee */
+            (void)psa_hash_abort(&hash_operation);
+        }
+    }
+
+    return status;
+}
+
+psa_status_t psa_adac_hash_verify(psa_algorithm_t alg,
+                                  const uint8_t input[],
+                                  size_t input_size,
+                                  uint8_t hash[],
+                                  size_t hash_size)
+{
+    psa_status_t status;
+    psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT;
+    if (PSA_ALG_IS_VENDOR_DEFINED(alg) != 0) {
+        // TODO: Add support for extra algorithms
+        status = PSA_ERROR_NOT_SUPPORTED;
+    } else {
+        status = psa_hash_setup(&hash_operation, alg);
+        if (PSA_SUCCESS == status) {
+            status = psa_hash_update(&hash_operation, input, input_size);
+        }
+
+        if (PSA_SUCCESS == status) {
+            status = psa_hash_verify(&hash_operation, hash, hash_size);
+        }
+    }
+
+    return status;
+}
+
+static psa_status_t hash_check(const uint8_t *input_a,
+                               size_t len_a,
+                               const uint8_t *input_b,
+                               size_t len_b)
+{
+    int32_t result = 1;
+
+    if (len_a == len_b) {
+        result = memcmp(input_b, input_a, len_a);
+    }
+
+    return (result == 0U) ? PSA_SUCCESS : PSA_ERROR_INVALID_SIGNATURE;
+}
+
+psa_status_t psa_adac_hash_verify_multiple(psa_algorithm_t alg,
+                                           const uint8_t input[],
+                                           size_t input_length,
+                                           uint8_t *hash[],
+                                           size_t hash_size[],
+                                           size_t hash_count)
+{
+    psa_status_t status;
+    psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT;
+    uint8_t computed_hash[PSA_HASH_MAX_SIZE];
+    size_t computed_hash_len;
+
+    if (PSA_ALG_IS_VENDOR_DEFINED(alg) != 0) {
+        // TODO: Add support for extra algorithms
+        status = PSA_ERROR_NOT_SUPPORTED;
+    } else {
+        status = psa_hash_setup(&hash_operation, alg);
+        if (PSA_SUCCESS == status) {
+            status = psa_hash_update(&hash_operation, input, input_length);
+        }
+        if (PSA_SUCCESS == status) {
+            status = psa_hash_finish(&hash_operation, computed_hash,
+                                     sizeof(computed_hash), &computed_hash_len);
+        }
+        if (PSA_SUCCESS == status) {
+            for (size_t i = 0; i < hash_count; i++) {
+                status = hash_check(hash[i], hash_size[i], computed_hash, computed_hash_len);
+                if (status == PSA_SUCCESS) {
+                    break;
+                }
+            }
+        }
+    }
+
+    return status;
+}
diff --git a/psa_crypto/adac_crypto_psa_mac.c b/psa_crypto/adac_crypto_psa_mac.c
new file mode 100644
index 0000000..046fef7
--- /dev/null
+++ b/psa_crypto/adac_crypto_psa_mac.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "adac_crypto_psa.h"
+#include "psa_adac_debug.h"
+
+#if (defined(PSA_ADAC_CMAC) || defined(PSA_ADAC_HMAC))
+
+psa_status_t psa_adac_mac_verify(psa_algorithm_t alg,
+                                 const uint8_t *inputs[],
+                                 size_t input_sizes[],
+                                 size_t input_count,
+                                 const uint8_t key[],
+                                 size_t key_size,
+                                 uint8_t mac[],
+                                 size_t mac_size)
+{
+    psa_status_t ret = PSA_ERROR_NOT_SUPPORTED;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_handle_t handle;
+
+    if (alg == PSA_ALG_CMAC) {
+        if (key_size != 16U) {
+            ret = PSA_ERROR_INVALID_ARGUMENT;
+        } else {
+            ret = PSA_SUCCESS;
+        }
+    }
+
+    if (ret == PSA_SUCCESS) {
+        psa_set_key_usage_flags(&attributes, 0);
+        psa_set_key_algorithm(&attributes, alg);
+        psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH);
+        psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
+        psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
+        psa_set_key_bits(&attributes, 128);
+
+        ret = psa_import_key(&attributes, key, key_size, &handle);
+        if (ret == PSA_SUCCESS) {
+            psa_mac_operation_t operation = psa_mac_operation_init();
+            ret = psa_mac_verify_setup(&operation, handle, alg);
+            for (size_t i = 0; (ret == PSA_SUCCESS) && (i < input_count); i++) {
+                ret = psa_mac_update(&operation, inputs[i], input_sizes[i]);
+            }
+            if (ret == PSA_SUCCESS) {
+                ret = psa_mac_verify_finish(&operation, mac, mac_size);
+            }
+            psa_destroy_key(handle);
+            psa_mac_abort(&operation);
+        }
+    }
+
+    return ret;
+}
+
+psa_status_t psa_adac_derive_hmac(uint8_t *key,
+                                  uint8_t *info,
+                                  size_t size,
+                                  uint8_t *output)
+{
+    psa_algorithm_t alg = PSA_ALG_HKDF(PSA_ALG_SHA_256);
+    psa_key_handle_t handle;
+
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_set_key_usage_flags(&attributes, 0);
+    psa_set_key_algorithm(&attributes, alg);
+    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
+    psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
+    psa_set_key_type(&attributes, PSA_KEY_TYPE_DERIVE);
+    psa_set_key_bits(&attributes, 256);
+
+    psa_status_t ret = psa_import_key(&attributes, key, 32, &handle);
+    if (ret == PSA_SUCCESS) {
+        psa_key_derivation_operation_t operation = psa_key_derivation_operation_init();
+        ret = psa_key_derivation_setup(&operation, alg);
+        if (ret == PSA_SUCCESS) {
+            ret = psa_key_derivation_input_key(&operation, PSA_KEY_DERIVATION_INPUT_SECRET, handle);
+        }
+        if (ret == PSA_SUCCESS) {
+            ret = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_INFO, info, size);
+        }
+        if (ret == PSA_SUCCESS) {
+            ret = psa_key_derivation_output_bytes(&operation, output, 32);
+        }
+        psa_destroy_key(handle);
+        psa_key_derivation_abort(&operation);
+    }
+    return ret;
+}
+
+/*  A key-derivation function can iterates n times until l bits of keying material are generated.
+        For each of the iterations of the PRF, i=1 to n, do:
+        result(0) = 0;
+        K(i) = PRF (Ki, [i] || Label || 0x00 || Context || length);
+        results(i) = result(i-1) || K(i);
+
+        concisely, result(i) = K(i) || k(i-1) || .... || k(0)*/
+
+/* NIST SP800-108 + Inspiration from SCP03 */
+/* Label || 0x00 || [L]_2 || [i]_2 || Context */
+
+psa_status_t psa_adac_derive_cmac(uint8_t *key, uint8_t *context, size_t context_size, uint8_t *output)
+{
+    psa_algorithm_t alg = PSA_ALG_CMAC;
+    psa_key_handle_t handle;
+    size_t l = 0;
+    uint8_t info[16] = {
+            /* Label = 'PSA ADAC 1.0' */
+            0x50, 0x53, 0x41, 0x20, 0x41, 0x44, 0x41, 0x43, 0x20, 0x31, 0x2E, 0x30,
+            /* Separator (0x00) */
+            0x00,
+            /* [L]_2 = 128 (encoded in 16 bit) */
+            0x00, 0x80,
+            /* [i]_2 = 8-bit counter */
+            0x01
+            /* Context = input */
+    };
+
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_set_key_usage_flags(&attributes, 0);
+    psa_set_key_algorithm(&attributes, alg);
+    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);
+    psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
+    psa_set_key_bits(&attributes, 128);
+
+    psa_status_t ret = psa_import_key(&attributes, key, 16, &handle);
+    if (ret == PSA_SUCCESS) {
+        psa_mac_operation_t operation = psa_mac_operation_init();
+        ret = psa_mac_sign_setup(&operation, handle, alg);
+        if (ret == PSA_SUCCESS) {
+            ret = psa_mac_update(&operation, info, sizeof(info));
+        }
+        if (ret == PSA_SUCCESS) {
+            ret = psa_mac_update(&operation, context, context_size);
+        }
+        if (ret == PSA_SUCCESS) {
+            ret = psa_mac_sign_finish(&operation, output, 16, &l);
+            if ((ret == PSA_SUCCESS) && (l != 16U)) {
+                ret = PSA_ERROR_GENERIC_ERROR;
+            }
+        }
+        psa_destroy_key(handle);
+        psa_mac_abort(&operation);
+    }
+
+    return ret;
+}
+
+psa_status_t psa_adac_derive_key(uint8_t *crt,
+                                 size_t crt_size,
+                                 uint8_t key_type,
+                                 uint8_t *key,
+                                 size_t key_size)
+{
+    psa_status_t ret;
+
+    if (key_type == CMAC_AES) {
+#ifdef PSA_ADAC_CMAC
+        if ((key_size == 16U) && (crt_size >= sizeof(certificate_cmac_cmac_t))) {
+            ret = psa_adac_derive_cmac(key, crt, offsetof(certificate_cmac_cmac_t, signature), key);
+            PSA_ADAC_LOG_DUMP("psa_adac_derive_key", "cmac", key, 16);
+        } else {
+            ret = PSA_ERROR_INVALID_ARGUMENT;
+        }
+#else
+        ret = PSA_ERROR_NOT_SUPPORTED;
+#endif /* PSA_ADAC_CMAC */
+    } else if (key_type == HMAC_SHA256) {
+#ifdef PSA_ADAC_HMAC
+        if ((key_size == 32U) && (crt_size >= sizeof(certificate_hmac_hmac_t))) {
+            ret = psa_adac_derive_hmac(key, crt, offsetof(certificate_hmac_hmac_t, signature), key);
+            PSA_ADAC_LOG_DUMP("psa_adac_derive_key", "hmac", key, 32);
+        } else {
+            ret = PSA_ERROR_INVALID_ARGUMENT;
+        }
+#else
+        ret = PSA_ERROR_NOT_SUPPORTED;
+#endif /* PSA_ADAC_HMAC */
+    } else {
+        ret = PSA_ERROR_NOT_SUPPORTED;
+    }
+
+    return ret;
+}
+
+psa_status_t psa_adac_verify_mac(uint8_t key_type,
+                                 uint8_t *key,
+                                 size_t key_size,
+                                 const uint8_t *inputs[],
+                                 size_t input_sizes[],
+                                 size_t input_count,
+                                 psa_algorithm_t mac_algo,
+                                 uint8_t *mac,
+                                 size_t mac_size)
+{
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_handle_t handle = -1;
+    psa_status_t ret = PSA_ERROR_NOT_SUPPORTED;
+    psa_key_type_t type = 0;
+    size_t bits = 0;
+
+#ifdef PSA_ADAC_CMAC
+    if ((key_type == CMAC_AES) && (mac_algo == CMAC_SIGN_ALGORITHM)) {
+        if (key_size != 16U) {
+            ret = PSA_ERROR_INVALID_ARGUMENT;
+        } else {
+            ret = PSA_SUCCESS;
+            type = PSA_KEY_TYPE_AES;
+            bits = 128;
+        }
+    }
+#endif /* PSA_ADAC_CMAC */
+
+#ifdef PSA_ADAC_HMAC
+    if ((key_type == HMAC_SHA256) && (mac_algo == HMAC_SIGN_ALGORITHM)) {
+        if (key_size != 32U) {
+            ret = PSA_ERROR_INVALID_ARGUMENT;
+        } else {
+            ret = PSA_SUCCESS;
+            type = PSA_KEY_TYPE_HMAC;
+            bits = 256;
+        }
+    }
+#endif /* PSA_ADAC_HMAC */
+
+    if (ret == PSA_SUCCESS) {
+        psa_set_key_usage_flags(&attributes, 0);
+        psa_set_key_algorithm(&attributes, mac_algo);
+        psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH);
+        psa_set_key_type(&attributes, type);
+        psa_set_key_bits(&attributes, bits);
+        ret = psa_import_key(&attributes, key, key_size, &handle);
+
+        if (PSA_SUCCESS != ret) {
+            PSA_ADAC_LOG_ERR("self", "Error importing key (%d)\n", ret);
+        } else {
+            psa_mac_operation_t operation = psa_mac_operation_init();
+            ret = psa_mac_verify_setup(&operation, handle, mac_algo);
+            for (size_t i = 0; (ret == PSA_SUCCESS) && (i < input_count); i++) {
+                ret = psa_mac_update(&operation, inputs[i], input_sizes[i]);
+            }
+            if (ret == PSA_SUCCESS) {
+                ret = psa_mac_verify_finish(&operation, mac, mac_size);
+            }
+            if (PSA_SUCCESS != ret) {
+                PSA_ADAC_LOG_ERR("self", "Error during MAC verification (%d)\n", ret);
+            }
+            psa_destroy_key(handle);
+            psa_mac_abort(&operation);
+        }
+    }
+
+    return ret;
+}
+
+#endif /*(defined(PSA_ADAC_CMAC) || defined(PSA_ADAC_HMAC)) */
diff --git a/psa_crypto/adac_crypto_psa_pk.c b/psa_crypto/adac_crypto_psa_pk.c
new file mode 100644
index 0000000..d78d0af
--- /dev/null
+++ b/psa_crypto/adac_crypto_psa_pk.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "adac_crypto_psa.h"
+#include "psa_adac_debug.h"
+#include "psa_adac_config.h"
+
+#include <string.h>
+
+#define PSA_ADAC_RSA3072
+#define PSA_ADAC_RSA4096
+
+#if defined(PSA_ADAC_RSA3072) || defined(PSA_ADAC_RSA4096)
+#define ENCODED_EXPONENT_SIZE 5U
+static const uint8_t encoded_exponent[ENCODED_EXPONENT_SIZE] =
+                                                 {0x02, 0x03, 0x01, 0x00, 0x01};
+#endif
+
+#ifdef PSA_ADAC_RSA3072
+
+#define RSA3072_HEADER_SIZE 8U
+#define RSA3072_KEY_SIZE 384U /* 3072 bits */
+#define RSA3072_ENCODED_PUB_KEY_SIZE (RSA3072_HEADER_SIZE + \
+                                      RSA3072_KEY_SIZE + \
+                                      ENCODED_EXPONENT_SIZE)
+
+/* If MSB of the unsigned modulus is set, then an extra byte (0x00) needs to be
+ * inserted before modulus
+ */
+#define RSA3072_ENCODED_PUB_KEY_MAX_SIZE (RSA3072_ENCODED_PUB_KEY_SIZE + 1U)
+
+static const uint8_t rsa3072_header[RSA3072_HEADER_SIZE] = {
+    0x30,       /* Start of sequence */
+    0x82,       /* Length field indicator */
+    0x01, 0x89, /* 0x189 (hex) or 393 (dec) bytes is length of data to follow */
+    0x02,       /* Integer tag */
+    0x82,       /* Length field indicator */
+    0x01, 0x80  /* 0x180 (hex) or 384 (dec) bytes modulus size */
+};
+
+/* RFC3279 Section 2.3.1  - For rsa public keys, it expects key format as DER
+ * encoding of the representation defined by Algorithms and IDs for
+ * Internet X.509 PKI Certificate & CRL Profile
+ */
+static psa_status_t load_rsa_3072_public_key(uint8_t *key,
+                                             size_t key_size,
+                                             psa_key_handle_t *handle)
+{
+    psa_status_t ret;
+    uint8_t pub_key[RSA3072_ENCODED_PUB_KEY_MAX_SIZE];
+    size_t offset = RSA3072_HEADER_SIZE;
+    size_t pub_size = RSA3072_ENCODED_PUB_KEY_SIZE;
+
+    if (key_size == RSA_3072_PUBLIC_KEY_SIZE) {
+        /* Copy the header */
+        (void) memcpy(pub_key, rsa3072_header, sizeof(rsa3072_header));
+
+        /* If MSB is set, modulus need to be prefixed by 0x00 value */
+        if ((key[0] & (uint8_t) 0x80U) != 0x00U) {
+            /* Insert 0x00 after header */
+            pub_key[offset] = 0x00;
+            /* Increase the lengths by 1 */
+            pub_key[3] = 0x8aU;
+            pub_key[7] = 0x81U;
+            offset += 1UL;
+            pub_size += 1UL;
+        }
+
+        (void) memcpy(&(pub_key[offset]), key, RSA_3072_PUBLIC_KEY_SIZE);
+        offset += RSA_3072_PUBLIC_KEY_SIZE;
+        (void) memcpy(&(pub_key[offset]), encoded_exponent,
+                      sizeof(encoded_exponent));
+
+        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+        psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH);
+        psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_PUBLIC_KEY);
+        psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PSS(PSA_ALG_ANY_HASH));
+        psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
+        psa_set_key_bits(&attributes, 3072);
+
+        ret = psa_import_key(&attributes, pub_key, pub_size, handle);
+    } else {
+        ret = PSA_ERROR_INVALID_ARGUMENT;
+    }
+
+    return ret;
+}
+
+#endif /* PSA_ADAC_RSA3072 */
+
+#ifdef PSA_ADAC_RSA4096
+
+#define RSA4096_HEADER_SIZE 8U
+#define RSA4096_KEY_SIZE 512U /* 4096 bits */
+#define RSA4096_ENCODED_PUB_KEY_SIZE (RSA4096_HEADER_SIZE + \
+                                      RSA4096_KEY_SIZE + \
+                                      ENCODED_EXPONENT_SIZE)
+
+/* If MSB of the unsigned modulus is set, then an extra byte (0x00) needs to be
+ * inserted before modulus
+ */
+#define RSA4096_ENCODED_PUB_KEY_MAX_SIZE (RSA4096_ENCODED_PUB_KEY_SIZE + 1U)
+
+static const uint8_t rsa4096_header[RSA4096_HEADER_SIZE] = {
+    0x30,       /* Start of sequence */
+    0x82,       /* Length field indicator */
+    0x02, 0x09, /* 0x209 (hex) or 521 (dec) bytes is length of data to follow */
+    0x02,       /* Integer tag */
+    0x82,       /* Length field indicator */
+    0x02, 0x00  /* 0x200 (hex) or 512 (dec) bytes modulus size */
+};
+
+/* RFC3279 Section 2.3.1  - For rsa public keys, it expects key format as DER
+ * encoding of the representation defined by Algorithms and IDs for
+ * Internet X.509 PKI Certificate & CRL Profile
+ */
+static psa_status_t load_rsa_4096_public_key(uint8_t *key,
+                                             size_t key_size,
+                                             psa_key_handle_t *handle)
+{
+    psa_status_t ret;
+    uint8_t pub_key[RSA4096_ENCODED_PUB_KEY_MAX_SIZE];
+    size_t offset = RSA4096_HEADER_SIZE;
+    size_t pub_size = RSA4096_ENCODED_PUB_KEY_SIZE;
+
+    if (RSA_4096_PUBLIC_KEY_SIZE == key_size) {
+
+        /* Copy the header */
+        (void) memcpy(pub_key, rsa4096_header, sizeof(rsa4096_header));
+
+        /* If MSB is set, modulus need to be prefixed by 0x00 value */
+        if ((key[0] & (uint8_t) 0x80) != 0x00U) {
+            /* Insert 0x00 after header */
+            pub_key[offset] = 0x00;
+            /* Increase the lengths by 1 */
+            pub_key[3] = 0x0a;
+            pub_key[7] = 0x01;
+            offset += 1UL;
+            pub_size += 1UL;
+        }
+
+        (void) memcpy(&(pub_key[offset]), key, RSA_4096_PUBLIC_KEY_SIZE);
+        offset += RSA_4096_PUBLIC_KEY_SIZE;
+        (void) memcpy(&(pub_key[offset]), encoded_exponent,
+                        sizeof(encoded_exponent));
+
+        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+        psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH);
+        psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_PUBLIC_KEY);
+        psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PSS(PSA_ALG_ANY_HASH));
+        psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
+        psa_set_key_bits(&attributes, 4096);
+
+        ret = psa_import_key(&attributes, pub_key, pub_size, handle);
+    } else {
+        ret = PSA_ERROR_INVALID_ARGUMENT;
+    }
+
+    return ret;
+}
+
+#endif /* PSA_ADAC_RSA4096 */
+
+#ifdef PSA_ADAC_EC_P256
+
+static psa_status_t load_ecdsa_p256_public_key(uint8_t *key,
+                                               size_t key_size,
+                                               psa_key_handle_t *handle)
+{
+    psa_status_t ret;
+    uint8_t pub_key[ECDSA_P256_PUBLIC_KEY_SIZE + 1] = {0x04};
+
+    if (ECDSA_P256_PUBLIC_KEY_SIZE == key_size) {
+
+        (void) memcpy(&(pub_key[1]), key, ECDSA_P256_PUBLIC_KEY_SIZE);
+        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+        psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH);
+        psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
+        psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
+        psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
+        psa_set_key_bits(&attributes, 256);
+
+        ret = psa_import_key(&attributes, pub_key, sizeof(pub_key), handle);
+    } else {
+
+        ret = PSA_ERROR_INVALID_ARGUMENT;
+    }
+
+    return ret;
+}
+
+#endif /* PSA_ADAC_EC_P256 */
+
+#ifdef PSA_ADAC_EC_P521
+
+static psa_status_t load_ecdsa_p521_public_key(uint8_t *key,
+                                               size_t key_size,
+                                               psa_key_handle_t *handle)
+{
+    psa_status_t ret;
+    uint8_t pub_key[ECDSA_P521_PUBLIC_KEY_SIZE + 1] = {0x04};
+
+    if (ECDSA_P521_PUBLIC_KEY_SIZE == key_size) {
+
+        (void) memcpy(&(pub_key[1]), key, ECDSA_P521_PUBLIC_KEY_SIZE);
+        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+        psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH);
+        psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
+        psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_512));
+        psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
+        psa_set_key_bits(&attributes, 521);
+
+        ret = psa_import_key(&attributes, pub_key, sizeof(pub_key), handle);
+    } else {
+        ret = PSA_ERROR_INVALID_ARGUMENT;
+    }
+
+    return ret;
+}
+
+#endif /* PSA_ADAC_EC_P521 */
+
+psa_status_t psa_adac_load_public_key(uint8_t key_type,
+                                      uint8_t *key,
+                                      size_t key_size,
+                                      psa_key_handle_t *handle)
+{
+    psa_status_t ret = PSA_ERROR_NOT_SUPPORTED;
+
+    if (key_type == ECDSA_P256_SHA256) {
+#ifdef PSA_ADAC_EC_P256
+        PSA_ADAC_LOG_TRACE("psa-crypto", "Load EcdsaP256 Public-key\n");
+        ret = load_ecdsa_p256_public_key(key, key_size, handle);
+#endif /* PSA_ADAC_EC_P256 */
+    } else if (key_type == ECDSA_P521_SHA512) {
+#ifdef PSA_ADAC_EC_P521
+        PSA_ADAC_LOG_TRACE("psa-crypto", "Load EcdsaP521 Public-key\n");
+        ret = load_ecdsa_p521_public_key(key, key_size, handle);
+#endif /* PSA_ADAC_EC_P521 */
+    } else if (key_type == RSA_3072_SHA256) {
+#ifdef PSA_ADAC_RSA3072
+        PSA_ADAC_LOG_TRACE("psa-crypto", "Load Rsa3072 Public-key\n");
+        ret = load_rsa_3072_public_key(key, key_size, handle);
+#endif /* PSA_ADAC_RSA3072 */
+    } else if (key_type == RSA_4096_SHA256) {
+#ifdef PSA_ADAC_RSA4096
+        PSA_ADAC_LOG_TRACE("psa-crypto", "Load Rsa4096 Public-key\n");
+        ret = load_rsa_4096_public_key(key, key_size, handle);
+#endif /* PSA_ADAC_RSA4096 */
+    } else {
+        ret = PSA_ERROR_NOT_SUPPORTED;
+    }
+
+    return ret;
+}
+
+psa_status_t psa_adac_verify_signature(uint8_t key_type,
+                                       uint8_t *key,
+                                       size_t key_size,
+                                       psa_algorithm_t hash_algo,
+                                       const uint8_t *inputs[],
+                                       size_t input_sizes[],
+                                       size_t input_count,
+                                       psa_algorithm_t sig_algo,
+                                       uint8_t *sig, size_t sig_size)
+{
+    uint8_t hash[PSA_HASH_MAX_SIZE];
+    size_t hash_size;
+    psa_key_handle_t handle;
+    psa_status_t ret;
+
+    if ((PSA_ALG_IS_VENDOR_DEFINED(sig_algo) != 0) ||
+        (sig_algo == PSA_ALG_HMAC(PSA_ALG_SHA_256)) || (sig_algo == PSA_ALG_CMAC)) {
+        ret = psa_adac_verify_vendor(key_type, key, key_size, hash_algo,
+                                     inputs, input_sizes, input_count,
+                                     sig_algo, sig, sig_size);
+    } else {
+        ret = psa_adac_load_public_key(key_type, key, key_size, &handle);
+        if (PSA_SUCCESS != ret) {
+            PSA_ADAC_LOG_ERR("psa-crypto", "Error loading public key (%d)\n", ret);
+        } else {
+            ret = psa_adac_hash_multiple(hash_algo, inputs, input_sizes, input_count,
+                                         hash, sizeof(hash), &hash_size);
+            if (PSA_SUCCESS != ret) {
+                PSA_ADAC_LOG_ERR("psa-crypto", "Error hashing content (%d)\n", ret);
+            } else {
+                PSA_ADAC_LOG_TRACE("psa-crypto", "Verify signature\n");
+                ret = psa_verify_hash(handle, sig_algo, hash, hash_size, sig, sig_size);
+                PSA_ADAC_LOG_DEBUG("psa-crypto", "Signature verification %s\n",
+                                   (ret == PSA_SUCCESS) ? "successful" : "failed");
+            }
+
+            psa_destroy_key(handle);
+        }
+    }
+
+    return ret;
+}