1 /*
2  * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include "config_tfm.h"
12 #include "tfm_mbedcrypto_include.h"
13 
14 #include "tfm_crypto_api.h"
15 #include "tfm_crypto_defs.h"
16 
17 /*!
18  * \addtogroup tfm_crypto_api_shim_layer
19  *
20  */
21 
22 /*!@{*/
23 #if CRYPTO_HASH_MODULE_ENABLED
24 /**
25  * \brief Check whether PSA is capable of handling the specified hash algorithm.
26  *
27  * \note  As service initialization is performed during TF-M boot up, so there is no need
28  *        to check whether psa_crypto_init has already been called.
29  *
30  * \param[in] alg The hash algorithm.
31  *
32  * \return 1 if the PSA can handle \p alg, 0 otherwise.
33  */
tfm_crypto_can_do_hash(psa_algorithm_t alg)34 static int tfm_crypto_can_do_hash(psa_algorithm_t alg)
35 {
36     switch (alg) {
37 #if defined(PSA_WANT_ALG_MD5)
38     case PSA_ALG_MD5:
39         return 1;
40 #endif
41 #if defined(PSA_WANT_ALG_RIPEMD160)
42     case PSA_ALG_RIPEMD160:
43         return 1;
44 #endif
45 #if defined(PSA_WANT_ALG_SHA_1)
46     case PSA_ALG_SHA_1:
47         return 1;
48 #endif
49 #if defined(PSA_WANT_ALG_SHA_224)
50     case PSA_ALG_SHA_224:
51         return 1;
52 #endif
53 #if defined(PSA_WANT_ALG_SHA_256)
54     case PSA_ALG_SHA_256:
55         return 1;
56 #endif
57 #if defined(PSA_WANT_ALG_SHA_384)
58     case PSA_ALG_SHA_384:
59         return 1;
60 #endif
61 #if defined(PSA_WANT_ALG_SHA_512)
62     case PSA_ALG_SHA_512:
63         return 1;
64 #endif
65 #if defined(PSA_WANT_ALG_SHA3_224)
66     case PSA_ALG_SHA3_224:
67         return 1;
68 #endif
69 #if defined(PSA_WANT_ALG_SHA3_256)
70     case PSA_ALG_SHA3_256:
71         return 1;
72 #endif
73 #if defined(PSA_WANT_ALG_SHA3_384)
74     case PSA_ALG_SHA3_384:
75         return 1;
76 #endif
77 #if defined(PSA_WANT_ALG_SHA3_512)
78     case PSA_ALG_SHA3_512:
79         return 1;
80 #endif
81     default:
82         return 0;
83     }
84 }
85 
tfm_crypto_hash_interface(psa_invec in_vec[],psa_outvec out_vec[])86 psa_status_t tfm_crypto_hash_interface(psa_invec in_vec[],
87                                        psa_outvec out_vec[])
88 {
89     const struct tfm_crypto_pack_iovec *iov = in_vec[0].base;
90     psa_status_t status = PSA_ERROR_NOT_SUPPORTED;
91     psa_hash_operation_t *operation = NULL;
92     uint32_t *p_handle = NULL;
93     enum tfm_crypto_func_sid_t sid = (enum tfm_crypto_func_sid_t)iov->function_id;
94 
95     if (sid == TFM_CRYPTO_CAN_DO_HASH_SID)
96     {
97         int *p_result = out_vec[0].base;
98         if ((out_vec[0].base == NULL) || (out_vec[0].len < sizeof(int))) {
99             return PSA_ERROR_PROGRAMMER_ERROR;
100         }
101 
102         *p_result = tfm_crypto_can_do_hash(iov->alg);
103         return PSA_SUCCESS;
104     }
105 
106     if (sid == TFM_CRYPTO_HASH_COMPUTE_SID) {
107 #if CRYPTO_SINGLE_PART_FUNCS_DISABLED
108         return PSA_ERROR_NOT_SUPPORTED;
109 #else
110         const uint8_t *input = in_vec[1].base;
111         size_t input_length = in_vec[1].len;
112         uint8_t *hash = out_vec[0].base;
113         size_t hash_size = out_vec[0].len;
114 
115         status = psa_hash_compute(iov->alg, input, input_length,
116                                   hash, hash_size, &out_vec[0].len);
117         if (status != PSA_SUCCESS) {
118             out_vec[0].len = 0;
119         }
120         return status;
121 #endif
122     }
123 
124     if (sid == TFM_CRYPTO_HASH_COMPARE_SID) {
125 #if CRYPTO_SINGLE_PART_FUNCS_DISABLED
126         return PSA_ERROR_NOT_SUPPORTED;
127 #else
128         const uint8_t *input = in_vec[1].base;
129         size_t input_length = in_vec[1].len;
130         const uint8_t *hash = in_vec[2].base;
131         size_t hash_length = in_vec[2].len;
132 
133         return psa_hash_compare(iov->alg, input, input_length,
134                                 hash, hash_length);
135 #endif
136     }
137 
138     if (sid == TFM_CRYPTO_HASH_SETUP_SID) {
139         p_handle = out_vec[0].base;
140         if ((out_vec[0].base == NULL) || (out_vec[0].len < sizeof(uint32_t))) {
141             return PSA_ERROR_PROGRAMMER_ERROR;
142         }
143         *p_handle = iov->op_handle;
144         status = tfm_crypto_operation_alloc(TFM_CRYPTO_HASH_OPERATION,
145                                             out_vec[0].base,
146                                             (void **)&operation);
147     } else {
148         status = tfm_crypto_operation_lookup(TFM_CRYPTO_HASH_OPERATION,
149                                              iov->op_handle,
150                                              (void **)&operation);
151         if ((sid == TFM_CRYPTO_HASH_FINISH_SID) ||
152             (sid == TFM_CRYPTO_HASH_VERIFY_SID) ||
153             (sid == TFM_CRYPTO_HASH_ABORT_SID)) {
154             /*
155              * finish()/abort() interface put handle in out_vec[0].
156              * Therefore, out_vec[0] shall be specially set to original handle
157              * value. Otherwise, the garbage data in message out_vec[0] may
158              * override the original handle value in client, after lookup fails.
159              */
160             p_handle = out_vec[0].base;
161             if ((out_vec[0].base == NULL) || (out_vec[0].len < sizeof(uint32_t))) {
162                 return PSA_ERROR_PROGRAMMER_ERROR;
163             }
164             *p_handle = iov->op_handle;
165         }
166     }
167     if (status != PSA_SUCCESS) {
168         if (sid == TFM_CRYPTO_HASH_ABORT_SID) {
169             /*
170              * Mbed TLS psa_hash_abort() will return a misleading error code
171              * if it is called with invalid operation content, since it
172              * doesn't validate the operation handle.
173              * It is neither necessary to call tfm_crypto_operation_release()
174              * with an invalid handle.
175              * Therefore return PSA_SUCCESS directly as psa_hash_abort() can
176              * be called multiple times.
177              */
178             return PSA_SUCCESS;
179         }
180         return status;
181     }
182 
183     switch (sid) {
184     case TFM_CRYPTO_HASH_SETUP_SID:
185     {
186         status = psa_hash_setup(operation, iov->alg);
187         if (status != PSA_SUCCESS) {
188             goto release_operation_and_return;
189         }
190     }
191     break;
192     case TFM_CRYPTO_HASH_UPDATE_SID:
193     {
194         const uint8_t *input = in_vec[1].base;
195         size_t input_length = in_vec[1].len;
196 
197         return psa_hash_update(operation, input, input_length);
198     }
199     case TFM_CRYPTO_HASH_FINISH_SID:
200     {
201         uint8_t *hash = out_vec[1].base;
202         size_t hash_size = out_vec[1].len;
203 
204         status = psa_hash_finish(operation, hash, hash_size, &out_vec[1].len);
205         if (status == PSA_SUCCESS) {
206             goto release_operation_and_return;
207         } else {
208             out_vec[1].len = 0;
209         }
210     }
211     break;
212     case TFM_CRYPTO_HASH_VERIFY_SID:
213     {
214         const uint8_t *hash = in_vec[1].base;
215         size_t hash_length = in_vec[1].len;
216 
217         status = psa_hash_verify(operation, hash, hash_length);
218         if (status == PSA_SUCCESS) {
219             goto release_operation_and_return;
220         }
221     }
222     break;
223     case TFM_CRYPTO_HASH_ABORT_SID:
224     {
225         status = psa_hash_abort(operation);
226         goto release_operation_and_return;
227     }
228     case TFM_CRYPTO_HASH_CLONE_SID:
229     {
230         psa_hash_operation_t *target_operation = NULL;
231         p_handle = out_vec[0].base;
232         if ((out_vec[0].base == NULL) || (out_vec[0].len < sizeof(uint32_t)) ||
233             (in_vec[1].base == NULL) || (in_vec[1].len < sizeof(uint32_t))) {
234             return PSA_ERROR_PROGRAMMER_ERROR;
235         }
236         *p_handle = *((uint32_t *)in_vec[1].base);
237 
238         /* Allocate the target operation context in the secure world */
239         status = tfm_crypto_operation_alloc(TFM_CRYPTO_HASH_OPERATION,
240                                             p_handle,
241                                             (void **)&target_operation);
242         if (status != PSA_SUCCESS) {
243             return status;
244         }
245         status = psa_hash_clone(operation, target_operation);
246         if (status != PSA_SUCCESS) {
247             (void)tfm_crypto_operation_release(p_handle);
248         }
249     }
250     break;
251     default:
252         return PSA_ERROR_NOT_SUPPORTED;
253     }
254 
255     return status;
256 
257 release_operation_and_return:
258     /* Release the operation context, ignore if the release fails. */
259     (void)tfm_crypto_operation_release(p_handle);
260     return status;
261 }
262 #else /* CRYPTO_HASH_MODULE_ENABLED */
tfm_crypto_hash_interface(psa_invec in_vec[],psa_outvec out_vec[])263 psa_status_t tfm_crypto_hash_interface(psa_invec in_vec[],
264                                        psa_outvec out_vec[])
265 {
266     (void)in_vec;
267     (void)out_vec;
268 
269     return PSA_ERROR_NOT_SUPPORTED;
270 }
271 #endif /* CRYPTO_HASH_MODULE_ENABLED */
272 /*!@}*/
273