1 /*
2  * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
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
tfm_crypto_hash_interface(psa_invec in_vec[],psa_outvec out_vec[])24 psa_status_t tfm_crypto_hash_interface(psa_invec in_vec[],
25                                        psa_outvec out_vec[])
26 {
27     const struct tfm_crypto_pack_iovec *iov = in_vec[0].base;
28     psa_status_t status = PSA_ERROR_NOT_SUPPORTED;
29     psa_hash_operation_t *operation = NULL;
30     uint32_t *p_handle = NULL;
31     enum tfm_crypto_func_sid_t sid = iov->function_id;
32 
33     if (sid == TFM_CRYPTO_HASH_COMPUTE_SID) {
34 #if CRYPTO_SINGLE_PART_FUNCS_DISABLED
35         return PSA_ERROR_NOT_SUPPORTED;
36 #else
37         const uint8_t *input = in_vec[1].base;
38         size_t input_length = in_vec[1].len;
39         uint8_t *hash = out_vec[0].base;
40         size_t hash_size = out_vec[0].len;
41 
42         status = psa_hash_compute(iov->alg, input, input_length,
43                                   hash, hash_size, &out_vec[0].len);
44         if (status != PSA_SUCCESS) {
45             out_vec[0].len = 0;
46         }
47         return status;
48 #endif
49     }
50 
51     if (sid == TFM_CRYPTO_HASH_COMPARE_SID) {
52 #if CRYPTO_SINGLE_PART_FUNCS_DISABLED
53         return PSA_ERROR_NOT_SUPPORTED;
54 #else
55         const uint8_t *input = in_vec[1].base;
56         size_t input_length = in_vec[1].len;
57         const uint8_t *hash = in_vec[2].base;
58         size_t hash_length = in_vec[2].len;
59 
60         return psa_hash_compare(iov->alg, input, input_length,
61                                 hash, hash_length);
62 #endif
63     }
64 
65     if (sid == TFM_CRYPTO_HASH_SETUP_SID) {
66         p_handle = out_vec[0].base;
67         if ((out_vec[0].base == NULL) || (out_vec[0].len < sizeof(uint32_t))) {
68             return PSA_ERROR_PROGRAMMER_ERROR;
69         }
70         *p_handle = iov->op_handle;
71         status = tfm_crypto_operation_alloc(TFM_CRYPTO_HASH_OPERATION,
72                                             out_vec[0].base,
73                                             (void **)&operation);
74     } else {
75         status = tfm_crypto_operation_lookup(TFM_CRYPTO_HASH_OPERATION,
76                                              iov->op_handle,
77                                              (void **)&operation);
78         if ((sid == TFM_CRYPTO_HASH_FINISH_SID) ||
79             (sid == TFM_CRYPTO_HASH_VERIFY_SID) ||
80             (sid == TFM_CRYPTO_HASH_ABORT_SID)) {
81             /*
82              * finish()/abort() interface put handle in out_vec[0].
83              * Therefore, out_vec[0] shall be specially set to original handle
84              * value. Otherwise, the garbage data in message out_vec[0] may
85              * override the original handle value in client, after lookup fails.
86              */
87             p_handle = out_vec[0].base;
88             if ((out_vec[0].base == NULL) || (out_vec[0].len < sizeof(uint32_t))) {
89                 return PSA_ERROR_PROGRAMMER_ERROR;
90             }
91             *p_handle = iov->op_handle;
92         }
93     }
94     if (status != PSA_SUCCESS) {
95         if (sid == TFM_CRYPTO_HASH_ABORT_SID) {
96             /*
97              * Mbed TLS psa_hash_abort() will return a misleading error code
98              * if it is called with invalid operation content, since it
99              * doesn't validate the operation handle.
100              * It is neither necessary to call tfm_crypto_operation_release()
101              * with an invalid handle.
102              * Therefore return PSA_SUCCESS directly as psa_hash_abort() can
103              * be called multiple times.
104              */
105             return PSA_SUCCESS;
106         }
107         return status;
108     }
109 
110     switch (sid) {
111     case TFM_CRYPTO_HASH_SETUP_SID:
112     {
113         status = psa_hash_setup(operation, iov->alg);
114         if (status != PSA_SUCCESS) {
115             goto release_operation_and_return;
116         }
117     }
118     break;
119     case TFM_CRYPTO_HASH_UPDATE_SID:
120     {
121         const uint8_t *input = in_vec[1].base;
122         size_t input_length = in_vec[1].len;
123 
124         return psa_hash_update(operation, input, input_length);
125     }
126     case TFM_CRYPTO_HASH_FINISH_SID:
127     {
128         uint8_t *hash = out_vec[1].base;
129         size_t hash_size = out_vec[1].len;
130 
131         status = psa_hash_finish(operation, hash, hash_size, &out_vec[1].len);
132         if (status == PSA_SUCCESS) {
133             goto release_operation_and_return;
134         } else {
135             out_vec[1].len = 0;
136         }
137     }
138     break;
139     case TFM_CRYPTO_HASH_VERIFY_SID:
140     {
141         const uint8_t *hash = in_vec[1].base;
142         size_t hash_length = in_vec[1].len;
143 
144         status = psa_hash_verify(operation, hash, hash_length);
145         if (status == PSA_SUCCESS) {
146             goto release_operation_and_return;
147         }
148     }
149     break;
150     case TFM_CRYPTO_HASH_ABORT_SID:
151     {
152         status = psa_hash_abort(operation);
153         goto release_operation_and_return;
154     }
155     case TFM_CRYPTO_HASH_CLONE_SID:
156     {
157         psa_hash_operation_t *target_operation = NULL;
158         p_handle = out_vec[0].base;
159         if ((out_vec[0].base == NULL) || (out_vec[0].len < sizeof(uint32_t)) ||
160             (in_vec[1].base == NULL) || (in_vec[1].len < sizeof(uint32_t))) {
161             return PSA_ERROR_PROGRAMMER_ERROR;
162         }
163         *p_handle = *((uint32_t *)in_vec[1].base);
164 
165         /* Allocate the target operation context in the secure world */
166         status = tfm_crypto_operation_alloc(TFM_CRYPTO_HASH_OPERATION,
167                                             p_handle,
168                                             (void **)&target_operation);
169         if (status != PSA_SUCCESS) {
170             return status;
171         }
172         status = psa_hash_clone(operation, target_operation);
173         if (status != PSA_SUCCESS) {
174             (void)tfm_crypto_operation_release(p_handle);
175         }
176     }
177     break;
178     default:
179         return PSA_ERROR_NOT_SUPPORTED;
180     }
181 
182     return status;
183 
184 release_operation_and_return:
185     /* Release the operation context, ignore if the release fails. */
186     (void)tfm_crypto_operation_release(p_handle);
187     return status;
188 }
189 #else /* CRYPTO_HASH_MODULE_ENABLED */
tfm_crypto_hash_interface(psa_invec in_vec[],psa_outvec out_vec[])190 psa_status_t tfm_crypto_hash_interface(psa_invec in_vec[],
191                                        psa_outvec out_vec[])
192 {
193     (void)in_vec;
194     (void)out_vec;
195 
196     return PSA_ERROR_NOT_SUPPORTED;
197 }
198 #endif /* CRYPTO_HASH_MODULE_ENABLED */
199 /*!@}*/
200