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 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 
mbedtls_test_record_status(psa_status_t status,const char * func,const char * file,int line,const char * expr)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)
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 
mbedtls_test_update_key_usage_flags(psa_key_usage_t usage_flags)125 psa_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 
mbedtls_test_fail_if_psa_leaking(int line_no,const char * filename)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 
mbedtls_test_parse_binary_string(data_t * bin_string)151 uint64_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     }
158 exit:
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 
mbedtls_test_inject_entropy_seed_read(unsigned char * buf,size_t len)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 
mbedtls_test_inject_entropy_seed_write(unsigned char * buf,size_t len)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 
mbedtls_test_inject_entropy_restore(void)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 
205 #endif /* MBEDTLS_PSA_INJECT_ENTROPY */
206 
207 #endif /* MBEDTLS_PSA_CRYPTO_C */
208