/* * Copyright (c) 2019,2020 Linaro Limited * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include "mbedtls/pk.h" #include "mbedtls/x509.h" #include "mbedtls/x509_csr.h" #include "psa_crypto.h" #include "util_app_log.h" #include "util_sformat.h" /** Declare a reference to the application logging interface. */ LOG_MODULE_DECLARE(app, CONFIG_LOG_DEFAULT_LEVEL); /* Formatting details for displaying hex dumps. */ struct sf_hex_tbl_fmt crp_fmt = { .ascii = true, .addr_label = true, .addr = 0 }; struct csr_json_struct { const char *CSR; }; static const struct json_obj_descr csr_json_descr[] = { JSON_OBJ_DESCR_PRIM(struct csr_json_struct, CSR, JSON_TOK_STRING) }; /** * @brief Extracts the public key from the specified persistent key id. * * @param key_id The permanent identifier for the generated key. * @param key Pointer to the buffer where the public key data * will be written. * @param key_buf_size Size of key buffer in bytes. * @param key_len Number of bytes written into key by this function. */ static psa_status_t crp_get_pub_key(psa_key_id_t key_id, uint8_t *key, size_t key_buf_size, size_t *key_len) { psa_status_t status; psa_key_handle_t key_handle; LOG_INF("Retrieving public key for key #%d", key_id); al_dump_log(); /* Now try to re-open the persisted key based on the key ID. */ status = al_psa_status( psa_open_key(key_id, &key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to open persistent key #%d", key_id); goto err; } /* Export the persistent key's public key part. */ status = al_psa_status( psa_export_public_key(key_handle, key, key_buf_size, key_len), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to export public key."); goto err; } /* Display the binary key data for debug purposes. */ sf_hex_tabulate_16(&crp_fmt, key, *key_len); /* Close the key to free up the volatile slot. */ status = al_psa_status( psa_close_key(key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to close persistent key."); goto err; } return status; err: al_dump_log(); return status; } #if CONFIG_PSA_IMPORT_KEY /** * @brief Stores a new persistent secp256r1 key (usage: ecdsa-with-SHA256) * in ITS, associating it with the specified unique key identifier. * * This function will store a new persistent secp256r1 key in internal trusted * storage. Cryptographic operations can then be performed using the key * identifier (key_id) associated with this persistent key. Only the 32-byte * private key needs to be supplied, the public key can be derived using * the supplied private key value. * * @param key_id The permament identifier for the generated key. * @param key_usage The usage policy for the key. * @param key_data Pointer to the 32-byte private key data. */ static psa_status_t crp_imp_key_secp256r1(psa_key_id_t key_id, psa_key_usage_t key_usage, uint8_t *key_data) { psa_status_t status = PSA_SUCCESS; psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_type_t key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); psa_algorithm_t alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256); psa_key_handle_t key_handle; size_t key_len = 32; size_t data_len; uint8_t data_out[65] = { 0 }; /* ECDSA public key = 65 bytes. */ int comp_result; LOG_INF("Persisting SECP256R1 key as #%d", (uint32_t)key_id); al_dump_log(); /* Setup the key's attributes before the creation request. */ psa_set_key_id(&key_attributes, key_id); psa_set_key_usage_flags(&key_attributes, key_usage); psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT); psa_set_key_algorithm(&key_attributes, alg); psa_set_key_type(&key_attributes, key_type); /* Import the private key, creating the persistent key on success */ status = al_psa_status( psa_import_key(&key_attributes, key_data, key_len, &key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to import key."); goto err; } /* Close the key to free up the volatile slot. */ status = al_psa_status( psa_close_key(key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to close persistent key."); goto err; } /* Try to retrieve the public key. */ status = crp_get_pub_key(key_id, data_out, sizeof(data_out), &data_len); /* Export the private key if usage includes PSA_KEY_USAGE_EXPORT. */ if (key_usage & PSA_KEY_USAGE_EXPORT) { /* Re-open the persisted key based on the key ID. */ status = al_psa_status( psa_open_key(key_id, &key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to open persistent key #%d", key_id); goto err; } /* Read the original (private) key data back. */ status = al_psa_status( psa_export_key(key_handle, data_out, sizeof(data_out), &data_len), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to export key."); goto err; } /* Check key len. */ if (data_len != key_len) { LOG_ERR("Unexpected number of bytes in exported key."); goto err; } /* Verify that the exported private key matches input data. */ comp_result = memcmp(data_out, key_data, key_len); if (comp_result != 0) { LOG_ERR("Imported/exported private key mismatch."); goto err; } /* Display the private key. */ LOG_INF("Private key data:"); al_dump_log(); sf_hex_tabulate_16(&crp_fmt, data_out, data_len); /* Close the key to free up the volatile slot. */ status = al_psa_status( psa_close_key(key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to close persistent key."); goto err; } } return status; err: al_dump_log(); return status; } #else /* !CONFIG_PSA_IMPORT_KEY */ /** * @brief Generates a new permanent, persistent prime256v1 (ecdsa-with-SHA256) * key in ITS, associating it with the specified unique key identifier. * * This function will generate a new permanent prime256v1 key in internal trusted * storage. Cryptographic operations can then be performed using the key * identifier (key_id) associated with this persistent key. * * @param key_id The permanent identifier for the generated key. * @param key_usage The usage policy for the key. */ static psa_status_t crp_gen_key_secp256r1(psa_key_id_t key_id, psa_key_usage_t key_usage) { psa_status_t status = PSA_SUCCESS; psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_type_t key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); psa_algorithm_t alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256); psa_key_handle_t key_handle; size_t key_len = 32; size_t data_len; uint8_t data_out[65] = { 0 }; /* ECDSA public key = 65 bytes. */ LOG_INF("Persisting SECP256R1 key as #%d", (uint32_t)key_id); al_dump_log(); /* Setup the key's attributes before the creation request. */ psa_set_key_id(&key_attributes, key_id); psa_set_key_usage_flags(&key_attributes, key_usage); psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT); psa_set_key_algorithm(&key_attributes, alg); psa_set_key_type(&key_attributes, key_type); psa_set_key_bits(&key_attributes, 256); /* Generate the private key, creating the persistent key on success */ status = al_psa_status( psa_generate_key(&key_attributes, &key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to generate key."); goto err; } /* Close the key to free up the volatile slot. */ status = al_psa_status( psa_close_key(key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to close persistent key."); goto err; } /* Try to retrieve the public key. */ status = crp_get_pub_key(key_id, data_out, sizeof(data_out), &data_len); /* Export the private key if usage includes PSA_KEY_USAGE_EXPORT. */ if (key_usage & PSA_KEY_USAGE_EXPORT) { /* Re-open the persisted key based on the key ID. */ status = al_psa_status( psa_open_key(key_id, &key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to open persistent key #%d", key_id); goto err; } /* Read the original (private) key data back. */ status = al_psa_status( psa_export_key(key_handle, data_out, sizeof(data_out), &data_len), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to export key."); goto err; } /* Check key len. */ if (data_len != key_len) { LOG_ERR("Unexpected number of bytes in exported key."); goto err; } /* Display the private key. */ LOG_INF("Private key data:"); al_dump_log(); sf_hex_tabulate_16(&crp_fmt, data_out, data_len); /* Close the key to free up the volatile slot. */ status = al_psa_status( psa_close_key(key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to close persistent key."); goto err; } } return status; err: al_dump_log(); return status; } #endif /* CONFIG_PSA_IMPORT_KEY */ /** * @brief PSA Random number generator wrapper for Mbed TLS */ static int psa_rng_for_mbedtls(void *p_rng, unsigned char *output, size_t output_len) { (void)p_rng; return psa_generate_random(output, output_len); } /** * @brief Generates device certificate signing request (CSR) using Mbed TLS * X.509 and TF-M crypto service. */ void crp_generate_csr(void) { psa_status_t status; psa_key_id_t key_slot = 1; psa_key_handle_t key_handle; unsigned char output_buf[1024]; unsigned char json_encoded_buf[1024]; mbedtls_pk_context pk_key_container; mbedtls_x509write_csr req; struct csr_json_struct csr_json = { .CSR = output_buf }; /* Initialize Mbed TLS structures. */ mbedtls_x509write_csr_init(&req); mbedtls_pk_init(&pk_key_container); memset(output_buf, 0, sizeof(output_buf)); /* Initialize crypto API. */ LOG_INF("Initialising PSA crypto"); al_dump_log(); status = al_psa_status(psa_crypto_init(), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Crypto init failed."); goto err; } LOG_INF("PSA crypto init completed"); al_dump_log(); /* prime256v1 (ecdsa-with-SHA256) private key. */ #if CONFIG_PSA_IMPORT_KEY #if CONFIG_PRIVATE_KEY_STATIC /* This value is based on the private key in user.pem, * which can be viewed viw the following command: * * $ openssl ec -in user.pem -text -noout */ uint8_t priv_key_data[32] = { 0x14, 0xbc, 0xb9, 0x53, 0xa4, 0xee, 0xed, 0x50, 0x09, 0x36, 0x92, 0x07, 0x1d, 0xdb, 0x24, 0x2c, 0xef, 0xf9, 0x57, 0x92, 0x40, 0x4f, 0x49, 0xaa, 0xd0, 0x7c, 0x5b, 0x3f, 0x26, 0xa7, 0x80, 0x48 }; #else /* !CONFIG_PRIVATE_KEY_STATIC */ /* Randomly generate the private key. */ uint8_t priv_key_data[32] = { 0 }; LOG_INF("Generate rnadom data for private key"); al_dump_log(); psa_generate_random(priv_key_data, sizeof(priv_key_data)); LOG_INF("Random data generation for private key completed"); al_dump_log(); #endif /* CONFIG_PRIVATE_KEY_STATIC */ /* Generate persistent prime256v1 (ecdsa-with-SHA256) key w/ID #1. */ /* PSA_KEY_USAGE_EXPORT can be added for debug purposes. */ status = al_psa_status( crp_imp_key_secp256r1(key_slot, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH, priv_key_data), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to create persistent key #%d", key_slot); goto err; } #else /* !CONFIG_PSA_IMPORT_KEY */ /* NOTE: The certificate signing request (CSR) can be generated using * openssl by using following commands: * * Generate a new key: * * $ openssl ecparam -name secp256k1 -genkey -out USER.key * * Generate a certificate signing request, containing the user public key * and required details to be inserted into the user certificate. * openssl req -new -key USER.key -out USER.csr \ * -subj "/O=Linaro/CN=$(uuidgen | tr '[:upper:]' '[:lower:]')" * */ /* Generate persistent prime256v1 (ecdsa-with-SHA256) key w/ID #1. */ /* PSA_KEY_USAGE_EXPORT can be added for debug purposes. */ status = al_psa_status( crp_gen_key_secp256r1(key_slot, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to create persistent key #%d", key_slot); goto err; } #endif /* CONFIG_PSA_IMPORT_KEY */ status = al_psa_status( psa_open_key(key_slot, &key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to open persistent key #%d", key_slot); goto err; } psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_get_key_attributes(key_handle, &attributes); mbedtls_x509write_csr_set_md_alg(&req, MBEDTLS_MD_SHA256); LOG_INF("Adding subject name to CSR"); al_dump_log(); status = mbedtls_x509write_csr_set_subject_name(&req, "O=Linaro,CN=Device Certificate"); if (status != 0) { LOG_ERR("failed! mbedtls_x509write_csr_set_subject_name returned %d", status); goto err; } LOG_INF("Adding subject name to CSR completed"); al_dump_log(); LOG_INF("Adding EC key to PK container"); al_dump_log(); status = mbedtls_pk_setup_opaque(&pk_key_container, key_handle); if (status != 0) { LOG_ERR("failed! mbedtls_pk_setup_opaque returned -0x%04x", (unsigned int) -status); goto err; } LOG_INF("Adding EC key to PK container completed"); al_dump_log(); mbedtls_x509write_csr_set_key(&req, &pk_key_container); LOG_INF("Create device Certificate Signing Request"); al_dump_log(); status = mbedtls_x509write_csr_pem(&req, output_buf, sizeof(output_buf), psa_rng_for_mbedtls, NULL); if (status < 0) { LOG_ERR("failed! mbedtls_x509write_csr_pem returned -0x%04x", (unsigned int) -status); goto err; } LOG_INF("Create device Certificate Signing Request completed"); al_dump_log(); LOG_INF("Certificate Signing Request:\n"); al_dump_log(); printf("%s\n", output_buf); /* * 1.3. Encoding CSR as JSON */ LOG_INF("Encoding CSR as json"); al_dump_log(); status = json_obj_encode_buf(csr_json_descr, ARRAY_SIZE(csr_json_descr), &csr_json, json_encoded_buf, sizeof(json_encoded_buf)); if (status != 0) { LOG_ERR("failed! json_obj_encode_buf returned 0x%04x", status); goto err; } LOG_INF("Encoding CSR as json completed"); al_dump_log(); LOG_INF("Certificate Signing Request in JSON:\n"); al_dump_log(); printf("%s\n", json_encoded_buf); /* Close the key to free up the volatile slot. */ status = al_psa_status( psa_close_key(key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to close persistent key."); goto err; } err: al_dump_log(); mbedtls_x509write_csr_free(&req); mbedtls_pk_free(&pk_key_container); } /** * @brief Calculates the SHA256 hash for the supplied message. * * @param msg Pointer to the buffer to read when generating the hash. * @param msg_len Number of bytes in msg. * @param hash Pointer to the buffer where the hash should be written. * @param hash_buf_size Size of hash in bytes. * @param hash_len Placeholder for the number of hash bytes written. */ static psa_status_t crp_hash_payload(uint8_t *msg, size_t msg_len, uint8_t *hash, size_t hash_buf_size, size_t *hash_len) { psa_status_t status; psa_hash_operation_t hash_handle = psa_hash_operation_init(); psa_algorithm_t alg = PSA_ALG_SHA_256; LOG_INF("Calculating SHA-256 hash of value"); al_dump_log(); /* Display the input message */ sf_hex_tabulate_16(&crp_fmt, msg, msg_len); /* Setup the hash object. */ status = al_psa_status(psa_hash_setup(&hash_handle, alg), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to setup hash op."); goto err; } /* Update object with all the message chunks. */ /* For the moment, the message is passed in a single operation, */ /* but this can be broken up in chunks for larger messages. */ status = al_psa_status(psa_hash_update(&hash_handle, msg, msg_len), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to update hash."); goto err; } /* Finalize the hash calculation. */ status = al_psa_status(psa_hash_finish(&hash_handle, hash, hash_buf_size, hash_len), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to finalize hash op."); goto err; } /* Display the SHA-256 hash for debug purposes */ sf_hex_tabulate_16(&crp_fmt, hash, (size_t)(PSA_HASH_MAX_SIZE)); return status; err: psa_hash_abort(&hash_handle); al_dump_log(); return status; } /** * @brief Signs the supplied hash using the specified persistent key. * * @param key_id The identifier of the key to use when signing. * @param hash Pointer to the buffer where the hash should be written. * @param hash_buf_size Size of hash in bytes. * @param sig Pointer to the buffer to read when generating the sig. * @param sig_buf_size Size of sig buffer in bytes. * @param sig_len Number of bytes written to sig. */ static psa_status_t crp_sign_hash(psa_key_id_t key_id, uint8_t *hash, size_t hash_buf_size, uint8_t *sig, size_t sig_buf_size, size_t *sig_len) { psa_status_t status; psa_key_handle_t key_handle; LOG_INF("Signing SHA-256 hash"); al_dump_log(); /* Try to open the persisted key based on the key ID. */ status = al_psa_status( psa_open_key(key_id, &key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to open persistent key #%d", key_id); goto err; } /* Sign using psa_sign_hash. */ status = al_psa_status( psa_sign_hash(key_handle, PSA_ALG_ECDSA(PSA_ALG_SHA_256), hash, hash_buf_size, sig, sig_buf_size, sig_len), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to sign hash w/persistent key #%d", key_id); goto err; } /* Display the ECDSA signature for debug purposes */ sf_hex_tabulate_16(&crp_fmt, sig, *sig_len); /* You can test this same operation with openssl as follows: * * $ openssl dgst -sha256 -sign */ /* Close the key to free up the volatile slot. */ status = al_psa_status( psa_close_key(key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to close persistent key."); goto err; } return status; err: al_dump_log(); return status; } /** * @brief Verifies the hash signature using the public key associated * with key_id. * * @param key_id The identifier for the persistent key. * @param hash Pointer to the hash data to verify. * @param hash_len Size of the hash buffer in bytes. * @param sig Pointer to the signature buffer. * @param sig_len Size of the signature buffer in bytes. */ static psa_status_t crp_verify_sign(psa_key_id_t key_id, uint8_t *hash, size_t hash_len, uint8_t *sig, size_t sig_len) { psa_status_t status; psa_key_handle_t key_handle; LOG_INF("Verifying signature for SHA-256 hash"); al_dump_log(); /* Try to open the persisted key based on the key ID. */ status = al_psa_status( psa_open_key(key_id, &key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to open persistent key #%d", key_id); goto err; } /* Verify the hash signature. */ status = al_psa_status( psa_verify_hash(key_handle, PSA_ALG_ECDSA(PSA_ALG_SHA_256), hash, hash_len, sig, sig_len), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Signature verification failed!"); goto err; } LOG_INF("Signature verified."); al_dump_log(); /* Close the key to free up the volatile slot. */ status = al_psa_status( psa_close_key(key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to close persistent key."); goto err; } return status; err: al_dump_log(); return status; } /** * @brief Destroys the specified persistent key. * * @param key_id The identifier for the persistent key. */ static psa_status_t crp_dest_key(psa_key_id_t key_id) { psa_status_t status; psa_key_handle_t key_handle; /* Try to open the persisted key based on the key ID. */ status = al_psa_status( psa_open_key(key_id, &key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to open persistent key #%d", key_id); goto err; } /* Destroy the persistent key */ status = al_psa_status( psa_destroy_key(key_handle), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Failed to destroy a persistent key"); goto err; } LOG_INF("Destroyed persistent key #%d", (uint32_t)key_id); al_dump_log(); return status; err: al_dump_log(); return status; } void crp_test(void) { psa_status_t status; uint8_t msg[] = "Please hash and sign this message."; uint8_t hash[PSA_HASH_MAX_SIZE] = { 0 }; size_t hash_len; uint8_t sig[PSA_VENDOR_ECDSA_SIGNATURE_MAX_SIZE] = { 0 }; size_t sig_len; /* secp256r1 private key. */ #if CONFIG_PSA_IMPORT_KEY #if CONFIG_PRIVATE_KEY_STATIC /* This value is based on the private key in user.pem, * which can be viewed viw the following command: * * $ openssl ec -in user.pem -text -noout */ uint8_t priv_key_data[32] = { 0x14, 0xbc, 0xb9, 0x53, 0xa4, 0xee, 0xed, 0x50, 0x09, 0x36, 0x92, 0x07, 0x1d, 0xdb, 0x24, 0x2c, 0xef, 0xf9, 0x57, 0x92, 0x40, 0x4f, 0x49, 0xaa, 0xd0, 0x7c, 0x5b, 0x3f, 0x26, 0xa7, 0x80, 0x48 }; #else /* !CONFIG_PRIVATE_KEY_STATIC */ /* Randomly generate the private key. */ uint8_t priv_key_data[32] = { 0 }; psa_generate_random(priv_key_data, sizeof(priv_key_data)); #endif /* CONFIG_PRIVATE_KEY_STATIC */ #endif /* CONFIG_PSA_IMPORT_KEY */ /* Initialize crypto API. */ status = al_psa_status(psa_crypto_init(), __func__); if (status != PSA_SUCCESS) { LOG_ERR("Crypto init failed."); return; } /* NOTE: The same key generation, SHA256 hash, sign, and verify * operations performed in this file can be also performed with * openssl using the commands described below. * * Generate a new key: * * The curve `prime256v1` is same as `secp256r1` in OpenSSL * (https://github.com/openssl/openssl/blob/master/apps/ecparam.c#L216) * $ openssl ecparam -name prime256v1 -genkey -out user.pem * * Display the public and private keys in hexadecimal format: * * $ openssl ec -in user.pem -text -noout * * Update the private key value in priv_key_data with the hexadecimal * values from "priv:" to be able to compare the PSA API and openssl * output. * * Generate a PEM file with the public key (which will be used to * verify any data signed with the private key): * * $ openssl ec -in user.pem -pubout -out user_pub.pem * * Hash the message with SHA256, and sign it with the private key: * * $ echo "Please hash and sign this message." > message.txt * $ openssl dgst -sha256 -sign user.pem message.txt > signature.der * * Verify the signature using the public key and message file: * * $ openssl dgst -sha256 -verify user_pub.pem \ * -signature signature.der message.txt * * If everything ws OK you should see "Verified OK". */ /* Generate persistent secp256r1 key w/ID #1. */ /* PSA_KEY_USAGE_EXPORT can be added for debug purposes. */ #if CONFIG_PSA_IMPORT_KEY status = crp_imp_key_secp256r1(1, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH, priv_key_data); #else /* !CONFIG_PSA_IMPORT_KEY */ status = crp_gen_key_secp256r1(1, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH); #endif /* Hash some data with the key using SHA256. */ status = crp_hash_payload(msg, strlen(msg), hash, sizeof(hash), &hash_len); /* Sign the hash using key #1. */ status = crp_sign_hash(1, hash, hash_len, sig, sizeof(sig), &sig_len); /* Verify the hash signature using the public key. */ status = crp_verify_sign(1, hash, hash_len, sig, sig_len); /* Destroy the key. */ status = crp_dest_key(1); } /** * @brief Generates random values using the TF-M crypto service. */ void crp_test_rng(void) { psa_status_t status; uint8_t outbuf[256] = { 0 }; struct sf_hex_tbl_fmt fmt = { .ascii = true, .addr_label = true, .addr = 0 }; status = al_psa_status(psa_generate_random(outbuf, 256), __func__); LOG_INF("Generating 256 bytes of random data."); al_dump_log(); sf_hex_tabulate_16(&fmt, outbuf, 256); }