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 8 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 9 */ 10 11#include <test/helpers.h> 12#include <test/macros.h> 13#include <psa_crypto_slot_management.h> 14#include <test/psa_crypto_helpers.h> 15 16#if defined(MBEDTLS_PSA_CRYPTO_C) 17 18#include <psa/crypto.h> 19 20#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) 21 22#include <psa_crypto_storage.h> 23 24static mbedtls_svc_key_id_t key_ids_used_in_test[9]; 25static size_t num_key_ids_used; 26 27int mbedtls_test_uses_key_id(mbedtls_svc_key_id_t key_id) 28{ 29 size_t i; 30 if (MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key_id) > 31 PSA_MAX_PERSISTENT_KEY_IDENTIFIER) { 32 /* Don't touch key id values that designate non-key files. */ 33 return 1; 34 } 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 } 39 } 40 if (num_key_ids_used == ARRAY_LENGTH(key_ids_used_in_test)) { 41 return 0; 42 } 43 key_ids_used_in_test[num_key_ids_used] = key_id; 44 ++num_key_ids_used; 45 return 1; 46} 47 48void mbedtls_test_psa_purge_key_storage(void) 49{ 50 size_t i; 51 for (i = 0; i < num_key_ids_used; i++) { 52 psa_destroy_persistent_key(key_ids_used_in_test[i]); 53 } 54 num_key_ids_used = 0; 55} 56 57void mbedtls_test_psa_purge_key_cache(void) 58{ 59 size_t i; 60 for (i = 0; i < num_key_ids_used; i++) { 61 psa_purge_key(key_ids_used_in_test[i]); 62 } 63} 64 65#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */ 66 67const char *mbedtls_test_helper_is_psa_leaking(void) 68{ 69 mbedtls_psa_stats_t stats; 70 71 mbedtls_psa_get_stats(&stats); 72 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 83 if (stats.volatile_slots != 0) { 84 return "A volatile slot has not been closed properly."; 85 } 86#endif 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 } 99 100 return NULL; 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 107psa_status_t mbedtls_test_record_status(psa_status_t status, 108 const char *func, 109 const char *file, int line, 110 const char *expr) 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; 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; 122} 123#endif /* defined(RECORD_PSA_STATUS_COVERAGE_LOG) */ 124 125psa_key_usage_t mbedtls_test_update_key_usage_flags(psa_key_usage_t usage_flags) 126{ 127 psa_key_usage_t updated_usage = usage_flags; 128 129 if (usage_flags & PSA_KEY_USAGE_SIGN_HASH) { 130 updated_usage |= PSA_KEY_USAGE_SIGN_MESSAGE; 131 } 132 133 if (usage_flags & PSA_KEY_USAGE_VERIFY_HASH) { 134 updated_usage |= PSA_KEY_USAGE_VERIFY_MESSAGE; 135 } 136 137 return updated_usage; 138} 139 140int 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 151uint64_t mbedtls_test_parse_binary_string(data_t *bin_string) 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 } 158exit: 159 return result; /* returns 0 if len > 8 */ 160} 161 162#if defined(MBEDTLS_PSA_INJECT_ENTROPY) 163 164#include <mbedtls/entropy.h> 165#include <psa_crypto_its.h> 166 167int 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 181int 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 191int 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 205#endif /* MBEDTLS_PSA_INJECT_ENTROPY */ 206 207#endif /* MBEDTLS_PSA_CRYPTO_C */ 208