| Gilles Peskine | 514a8fd | 2020-11-13 17:41:53 +0100 | [diff] [blame] | 1 | /** \file psa_crypto_helpers.c | 
|  | 2 | * | 
|  | 3 | * \brief Helper functions to test PSA crypto functionality. | 
|  | 4 | */ | 
|  | 5 |  | 
|  | 6 | /* | 
|  | 7 | *  Copyright The Mbed TLS Contributors | 
| Dave Rodgman | 16799db | 2023-11-02 19:47:20 +0000 | [diff] [blame] | 8 | *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later | 
| Gilles Peskine | 514a8fd | 2020-11-13 17:41:53 +0100 | [diff] [blame] | 9 | */ | 
|  | 10 |  | 
|  | 11 | #include <test/helpers.h> | 
|  | 12 | #include <test/macros.h> | 
| Przemyslaw Stekiel | 53de262 | 2021-11-03 09:35:35 +0100 | [diff] [blame] | 13 | #include <psa_crypto_slot_management.h> | 
| Gilles Peskine | d4008d5 | 2020-11-24 17:34:30 +0100 | [diff] [blame] | 14 | #include <test/psa_crypto_helpers.h> | 
| Gilles Peskine | 514a8fd | 2020-11-13 17:41:53 +0100 | [diff] [blame] | 15 |  | 
|  | 16 | #if defined(MBEDTLS_PSA_CRYPTO_C) | 
|  | 17 |  | 
|  | 18 | #include <psa/crypto.h> | 
|  | 19 |  | 
| Gilles Peskine | 313ffb8 | 2021-02-14 12:51:14 +0100 | [diff] [blame] | 20 | #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) | 
|  | 21 |  | 
|  | 22 | #include <psa_crypto_storage.h> | 
|  | 23 |  | 
|  | 24 | static mbedtls_svc_key_id_t key_ids_used_in_test[9]; | 
|  | 25 | static size_t num_key_ids_used; | 
|  | 26 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 27 | int mbedtls_test_uses_key_id(mbedtls_svc_key_id_t key_id) | 
| Gilles Peskine | 313ffb8 | 2021-02-14 12:51:14 +0100 | [diff] [blame] | 28 | { | 
|  | 29 | size_t i; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 30 | if (MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key_id) > | 
|  | 31 | PSA_MAX_PERSISTENT_KEY_IDENTIFIER) { | 
| Gilles Peskine | 313ffb8 | 2021-02-14 12:51:14 +0100 | [diff] [blame] | 32 | /* Don't touch key id values that designate non-key files. */ | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 33 | return 1; | 
| Gilles Peskine | 313ffb8 | 2021-02-14 12:51:14 +0100 | [diff] [blame] | 34 | } | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 35 | for (i = 0; i < num_key_ids_used; i++) { | 
|  | 36 | if (mbedtls_svc_key_id_equal(key_id, key_ids_used_in_test[i])) { | 
|  | 37 | return 1; | 
|  | 38 | } | 
| Gilles Peskine | 313ffb8 | 2021-02-14 12:51:14 +0100 | [diff] [blame] | 39 | } | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 40 | if (num_key_ids_used == ARRAY_LENGTH(key_ids_used_in_test)) { | 
|  | 41 | return 0; | 
|  | 42 | } | 
| Gilles Peskine | 313ffb8 | 2021-02-14 12:51:14 +0100 | [diff] [blame] | 43 | key_ids_used_in_test[num_key_ids_used] = key_id; | 
|  | 44 | ++num_key_ids_used; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 45 | return 1; | 
| Gilles Peskine | 313ffb8 | 2021-02-14 12:51:14 +0100 | [diff] [blame] | 46 | } | 
|  | 47 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 48 | void mbedtls_test_psa_purge_key_storage(void) | 
| Gilles Peskine | 313ffb8 | 2021-02-14 12:51:14 +0100 | [diff] [blame] | 49 | { | 
|  | 50 | size_t i; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 51 | for (i = 0; i < num_key_ids_used; i++) { | 
|  | 52 | psa_destroy_persistent_key(key_ids_used_in_test[i]); | 
|  | 53 | } | 
| Gilles Peskine | 313ffb8 | 2021-02-14 12:51:14 +0100 | [diff] [blame] | 54 | num_key_ids_used = 0; | 
|  | 55 | } | 
| Gilles Peskine | aae718c | 2021-02-14 13:46:39 +0100 | [diff] [blame] | 56 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 57 | void mbedtls_test_psa_purge_key_cache(void) | 
| Gilles Peskine | aae718c | 2021-02-14 13:46:39 +0100 | [diff] [blame] | 58 | { | 
|  | 59 | size_t i; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 60 | for (i = 0; i < num_key_ids_used; i++) { | 
|  | 61 | psa_purge_key(key_ids_used_in_test[i]); | 
|  | 62 | } | 
| Gilles Peskine | aae718c | 2021-02-14 13:46:39 +0100 | [diff] [blame] | 63 | } | 
|  | 64 |  | 
| Gilles Peskine | 313ffb8 | 2021-02-14 12:51:14 +0100 | [diff] [blame] | 65 | #endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */ | 
|  | 66 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 67 | const char *mbedtls_test_helper_is_psa_leaking(void) | 
| Gilles Peskine | d4008d5 | 2020-11-24 17:34:30 +0100 | [diff] [blame] | 68 | { | 
|  | 69 | mbedtls_psa_stats_t stats; | 
|  | 70 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 71 | mbedtls_psa_get_stats(&stats); | 
| Gilles Peskine | d4008d5 | 2020-11-24 17:34:30 +0100 | [diff] [blame] | 72 |  | 
| Valerio Setti | 7448367 | 2023-11-24 08:36:12 +0100 | [diff] [blame] | 73 | #if defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_AES_C) && \ | 
|  | 74 | !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) | 
|  | 75 | /* When AES_C is not defined and PSA does not have an external RNG, | 
|  | 76 | * then CTR_DRBG uses PSA to perform AES-ECB. In this scenario 1 key | 
|  | 77 | * slot is used internally from PSA to hold the AES key and it should | 
|  | 78 | * not be taken into account when evaluating remaining open slots. */ | 
|  | 79 | if (stats.volatile_slots > 1) { | 
|  | 80 | return "A volatile slot has not been closed properly."; | 
|  | 81 | } | 
|  | 82 | #else | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 83 | if (stats.volatile_slots != 0) { | 
|  | 84 | return "A volatile slot has not been closed properly."; | 
|  | 85 | } | 
| Valerio Setti | 7448367 | 2023-11-24 08:36:12 +0100 | [diff] [blame] | 86 | #endif | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 87 | if (stats.persistent_slots != 0) { | 
|  | 88 | return "A persistent slot has not been closed properly."; | 
|  | 89 | } | 
|  | 90 | if (stats.external_slots != 0) { | 
|  | 91 | return "An external slot has not been closed properly."; | 
|  | 92 | } | 
|  | 93 | if (stats.half_filled_slots != 0) { | 
|  | 94 | return "A half-filled slot has not been cleared properly."; | 
|  | 95 | } | 
|  | 96 | if (stats.locked_slots != 0) { | 
|  | 97 | return "Some slots are still marked as locked."; | 
|  | 98 | } | 
| Gilles Peskine | d4008d5 | 2020-11-24 17:34:30 +0100 | [diff] [blame] | 99 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 100 | return NULL; | 
| Gilles Peskine | d4008d5 | 2020-11-24 17:34:30 +0100 | [diff] [blame] | 101 | } | 
|  | 102 |  | 
|  | 103 | #if defined(RECORD_PSA_STATUS_COVERAGE_LOG) | 
|  | 104 | /** Name of the file where return statuses are logged by #RECORD_STATUS. */ | 
|  | 105 | #define STATUS_LOG_FILE_NAME "statuses.log" | 
|  | 106 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 107 | psa_status_t mbedtls_test_record_status(psa_status_t status, | 
|  | 108 | const char *func, | 
|  | 109 | const char *file, int line, | 
|  | 110 | const char *expr) | 
| Gilles Peskine | d4008d5 | 2020-11-24 17:34:30 +0100 | [diff] [blame] | 111 | { | 
|  | 112 | /* We open the log file on first use. | 
|  | 113 | * We never close the log file, so the record_status feature is not | 
|  | 114 | * compatible with resource leak detectors such as Asan. | 
|  | 115 | */ | 
|  | 116 | static FILE *log; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 117 | if (log == NULL) { | 
|  | 118 | log = fopen(STATUS_LOG_FILE_NAME, "a"); | 
|  | 119 | } | 
|  | 120 | fprintf(log, "%d:%s:%s:%d:%s\n", (int) status, func, file, line, expr); | 
|  | 121 | return status; | 
| Gilles Peskine | d4008d5 | 2020-11-24 17:34:30 +0100 | [diff] [blame] | 122 | } | 
|  | 123 | #endif /* defined(RECORD_PSA_STATUS_COVERAGE_LOG) */ | 
|  | 124 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 125 | psa_key_usage_t mbedtls_test_update_key_usage_flags(psa_key_usage_t usage_flags) | 
| gabor-mezei-arm | 4ff7303 | 2021-05-13 12:05:01 +0200 | [diff] [blame] | 126 | { | 
|  | 127 | psa_key_usage_t updated_usage = usage_flags; | 
|  | 128 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 129 | if (usage_flags & PSA_KEY_USAGE_SIGN_HASH) { | 
| gabor-mezei-arm | 4ff7303 | 2021-05-13 12:05:01 +0200 | [diff] [blame] | 130 | updated_usage |= PSA_KEY_USAGE_SIGN_MESSAGE; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 131 | } | 
| gabor-mezei-arm | 4ff7303 | 2021-05-13 12:05:01 +0200 | [diff] [blame] | 132 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 133 | if (usage_flags & PSA_KEY_USAGE_VERIFY_HASH) { | 
| gabor-mezei-arm | 4ff7303 | 2021-05-13 12:05:01 +0200 | [diff] [blame] | 134 | updated_usage |= PSA_KEY_USAGE_VERIFY_MESSAGE; | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 135 | } | 
| gabor-mezei-arm | 4ff7303 | 2021-05-13 12:05:01 +0200 | [diff] [blame] | 136 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 137 | return updated_usage; | 
| gabor-mezei-arm | 4ff7303 | 2021-05-13 12:05:01 +0200 | [diff] [blame] | 138 | } | 
|  | 139 |  | 
| Yanray Wang | e64b405 | 2022-10-28 18:12:01 +0800 | [diff] [blame] | 140 | int mbedtls_test_fail_if_psa_leaking(int line_no, const char *filename) | 
|  | 141 | { | 
|  | 142 | const char *msg = mbedtls_test_helper_is_psa_leaking(); | 
|  | 143 | if (msg == NULL) { | 
|  | 144 | return 0; | 
|  | 145 | } else { | 
|  | 146 | mbedtls_test_fail(msg, line_no, filename); | 
|  | 147 | return 1; | 
|  | 148 | } | 
|  | 149 | } | 
|  | 150 |  | 
| Kusumit Ghoderao | 7c61ffc | 2023-09-05 19:29:47 +0530 | [diff] [blame] | 151 | uint64_t mbedtls_test_parse_binary_string(data_t *bin_string) | 
| Kusumit Ghoderao | ac7a04a | 2023-08-18 13:47:47 +0530 | [diff] [blame] | 152 | { | 
|  | 153 | uint64_t result = 0; | 
|  | 154 | TEST_LE_U(bin_string->len, 8); | 
|  | 155 | for (size_t i = 0; i < bin_string->len; i++) { | 
|  | 156 | result = result << 8 | bin_string->x[i]; | 
|  | 157 | } | 
|  | 158 | exit: | 
|  | 159 | return result; /* returns 0 if len > 8 */ | 
|  | 160 | } | 
|  | 161 |  | 
| Gilles Peskine | a08def9 | 2023-04-28 21:01:49 +0200 | [diff] [blame] | 162 | #if defined(MBEDTLS_PSA_INJECT_ENTROPY) | 
|  | 163 |  | 
|  | 164 | #include <mbedtls/entropy.h> | 
|  | 165 | #include <psa_crypto_its.h> | 
|  | 166 |  | 
|  | 167 | int mbedtls_test_inject_entropy_seed_read(unsigned char *buf, size_t len) | 
|  | 168 | { | 
|  | 169 | size_t actual_len = 0; | 
|  | 170 | psa_status_t status = psa_its_get(PSA_CRYPTO_ITS_RANDOM_SEED_UID, | 
|  | 171 | 0, len, buf, &actual_len); | 
|  | 172 | if (status != 0) { | 
|  | 173 | return MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; | 
|  | 174 | } | 
|  | 175 | if (actual_len != len) { | 
|  | 176 | return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; | 
|  | 177 | } | 
|  | 178 | return 0; | 
|  | 179 | } | 
|  | 180 |  | 
|  | 181 | int mbedtls_test_inject_entropy_seed_write(unsigned char *buf, size_t len) | 
|  | 182 | { | 
|  | 183 | psa_status_t status = psa_its_set(PSA_CRYPTO_ITS_RANDOM_SEED_UID, | 
|  | 184 | len, buf, 0); | 
|  | 185 | if (status != 0) { | 
|  | 186 | return MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; | 
|  | 187 | } | 
|  | 188 | return 0; | 
|  | 189 | } | 
|  | 190 |  | 
| Gilles Peskine | c2d16b2 | 2023-04-28 23:39:45 +0200 | [diff] [blame] | 191 | int mbedtls_test_inject_entropy_restore(void) | 
|  | 192 | { | 
|  | 193 | unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; | 
|  | 194 | for (size_t i = 0; i < sizeof(buf); i++) { | 
|  | 195 | buf[i] = (unsigned char) i; | 
|  | 196 | } | 
|  | 197 | psa_status_t status = mbedtls_psa_inject_entropy(buf, sizeof(buf)); | 
|  | 198 | /* It's ok if the file was just created, or if it already exists. */ | 
|  | 199 | if (status != PSA_SUCCESS && status != PSA_ERROR_NOT_PERMITTED) { | 
|  | 200 | return status; | 
|  | 201 | } | 
|  | 202 | return PSA_SUCCESS; | 
|  | 203 | } | 
|  | 204 |  | 
| Gilles Peskine | a08def9 | 2023-04-28 21:01:49 +0200 | [diff] [blame] | 205 | #endif /* MBEDTLS_PSA_INJECT_ENTROPY */ | 
|  | 206 |  | 
| Gilles Peskine | 514a8fd | 2020-11-13 17:41:53 +0100 | [diff] [blame] | 207 | #endif /* MBEDTLS_PSA_CRYPTO_C */ |