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
24 static mbedtls_svc_key_id_t key_ids_used_in_test[9];
25 static size_t num_key_ids_used;
26
mbedtls_test_uses_key_id(mbedtls_svc_key_id_t key_id)27 int 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
mbedtls_test_psa_purge_key_storage(void)48 void 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
mbedtls_test_psa_purge_key_cache(void)57 void 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
mbedtls_test_helper_is_psa_leaking(void)67 const 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 (stats.volatile_slots != 0) {
74 return "A volatile slot has not been closed properly.";
75 }
76 if (stats.persistent_slots != 0) {
77 return "A persistent slot has not been closed properly.";
78 }
79 if (stats.external_slots != 0) {
80 return "An external slot has not been closed properly.";
81 }
82 if (stats.half_filled_slots != 0) {
83 return "A half-filled slot has not been cleared properly.";
84 }
85 if (stats.locked_slots != 0) {
86 return "Some slots are still marked as locked.";
87 }
88
89 return NULL;
90 }
91
92 #if defined(RECORD_PSA_STATUS_COVERAGE_LOG)
93 /** Name of the file where return statuses are logged by #RECORD_STATUS. */
94 #define STATUS_LOG_FILE_NAME "statuses.log"
95
mbedtls_test_record_status(psa_status_t status,const char * func,const char * file,int line,const char * expr)96 psa_status_t mbedtls_test_record_status(psa_status_t status,
97 const char *func,
98 const char *file, int line,
99 const char *expr)
100 {
101 /* We open the log file on first use.
102 * We never close the log file, so the record_status feature is not
103 * compatible with resource leak detectors such as Asan.
104 */
105 static FILE *log;
106 if (log == NULL) {
107 log = fopen(STATUS_LOG_FILE_NAME, "a");
108 }
109 fprintf(log, "%d:%s:%s:%d:%s\n", (int) status, func, file, line, expr);
110 return status;
111 }
112 #endif /* defined(RECORD_PSA_STATUS_COVERAGE_LOG) */
113
mbedtls_test_update_key_usage_flags(psa_key_usage_t usage_flags)114 psa_key_usage_t mbedtls_test_update_key_usage_flags(psa_key_usage_t usage_flags)
115 {
116 psa_key_usage_t updated_usage = usage_flags;
117
118 if (usage_flags & PSA_KEY_USAGE_SIGN_HASH) {
119 updated_usage |= PSA_KEY_USAGE_SIGN_MESSAGE;
120 }
121
122 if (usage_flags & PSA_KEY_USAGE_VERIFY_HASH) {
123 updated_usage |= PSA_KEY_USAGE_VERIFY_MESSAGE;
124 }
125
126 return updated_usage;
127 }
128
mbedtls_test_fail_if_psa_leaking(int line_no,const char * filename)129 int mbedtls_test_fail_if_psa_leaking(int line_no, const char *filename)
130 {
131 const char *msg = mbedtls_test_helper_is_psa_leaking();
132 if (msg == NULL) {
133 return 0;
134 } else {
135 mbedtls_test_fail(msg, line_no, filename);
136 return 1;
137 }
138 }
139
mbedtls_test_parse_binary_string(data_t * bin_string)140 uint64_t mbedtls_test_parse_binary_string(data_t *bin_string)
141 {
142 uint64_t result = 0;
143 TEST_LE_U(bin_string->len, 8);
144 for (size_t i = 0; i < bin_string->len; i++) {
145 result = result << 8 | bin_string->x[i];
146 }
147 exit:
148 return result; /* returns 0 if len > 8 */
149 }
150
151 #if defined(MBEDTLS_PSA_INJECT_ENTROPY)
152
153 #include <mbedtls/entropy.h>
154 #include <psa_crypto_its.h>
155
mbedtls_test_inject_entropy_seed_read(unsigned char * buf,size_t len)156 int mbedtls_test_inject_entropy_seed_read(unsigned char *buf, size_t len)
157 {
158 size_t actual_len = 0;
159 psa_status_t status = psa_its_get(PSA_CRYPTO_ITS_RANDOM_SEED_UID,
160 0, len, buf, &actual_len);
161 if (status != 0) {
162 return MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
163 }
164 if (actual_len != len) {
165 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
166 }
167 return 0;
168 }
169
mbedtls_test_inject_entropy_seed_write(unsigned char * buf,size_t len)170 int mbedtls_test_inject_entropy_seed_write(unsigned char *buf, size_t len)
171 {
172 psa_status_t status = psa_its_set(PSA_CRYPTO_ITS_RANDOM_SEED_UID,
173 len, buf, 0);
174 if (status != 0) {
175 return MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
176 }
177 return 0;
178 }
179
mbedtls_test_inject_entropy_restore(void)180 int mbedtls_test_inject_entropy_restore(void)
181 {
182 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
183 for (size_t i = 0; i < sizeof(buf); i++) {
184 buf[i] = (unsigned char) i;
185 }
186 psa_status_t status = mbedtls_psa_inject_entropy(buf, sizeof(buf));
187 /* It's ok if the file was just created, or if it already exists. */
188 if (status != PSA_SUCCESS && status != PSA_ERROR_NOT_PERMITTED) {
189 return status;
190 }
191 return PSA_SUCCESS;
192 }
193
194 #endif /* MBEDTLS_PSA_INJECT_ENTROPY */
195
196 #endif /* MBEDTLS_PSA_CRYPTO_C */
197