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     uint16_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         *p_handle = iov->op_handle;
68         status = tfm_crypto_operation_alloc(TFM_CRYPTO_HASH_OPERATION,
69                                             out_vec[0].base,
70                                             (void **)&operation);
71     } else {
72         status = tfm_crypto_operation_lookup(TFM_CRYPTO_HASH_OPERATION,
73                                              iov->op_handle,
74                                              (void **)&operation);
75         if ((sid == TFM_CRYPTO_HASH_FINISH_SID) ||
76             (sid == TFM_CRYPTO_HASH_VERIFY_SID) ||
77             (sid == TFM_CRYPTO_HASH_ABORT_SID)) {
78             /*
79              * finish()/abort() interface put handle in out_vec[0].
80              * Therefore, out_vec[0] shall be specially set to original handle
81              * value. Otherwise, the garbage data in message out_vec[0] may
82              * override the original handle value in client, after lookup fails.
83              */
84             p_handle = out_vec[0].base;
85             *p_handle = iov->op_handle;
86         }
87     }
88     if (status != PSA_SUCCESS) {
89         if (sid == TFM_CRYPTO_HASH_ABORT_SID) {
90             /*
91              * Mbed TLS psa_hash_abort() will return a misleading error code
92              * if it is called with invalid operation content, since it
93              * doesn't validate the operation handle.
94              * It is neither necessary to call tfm_crypto_operation_release()
95              * with an invalid handle.
96              * Therefore return PSA_SUCCESS directly as psa_hash_abort() can
97              * be called multiple times.
98              */
99             return PSA_SUCCESS;
100         }
101         return status;
102     }
103 
104     switch (sid) {
105     case TFM_CRYPTO_HASH_SETUP_SID:
106     {
107         status = psa_hash_setup(operation, iov->alg);
108         if (status != PSA_SUCCESS) {
109             goto release_operation_and_return;
110         }
111     }
112     break;
113     case TFM_CRYPTO_HASH_UPDATE_SID:
114     {
115         const uint8_t *input = in_vec[1].base;
116         size_t input_length = in_vec[1].len;
117 
118         return psa_hash_update(operation, input, input_length);
119     }
120     case TFM_CRYPTO_HASH_FINISH_SID:
121     {
122         uint8_t *hash = out_vec[1].base;
123         size_t hash_size = out_vec[1].len;
124 
125         status = psa_hash_finish(operation, hash, hash_size, &out_vec[1].len);
126         if (status == PSA_SUCCESS) {
127             goto release_operation_and_return;
128         } else {
129             out_vec[1].len = 0;
130         }
131     }
132     break;
133     case TFM_CRYPTO_HASH_VERIFY_SID:
134     {
135         const uint8_t *hash = in_vec[1].base;
136         size_t hash_length = in_vec[1].len;
137 
138         status = psa_hash_verify(operation, hash, hash_length);
139         if (status == PSA_SUCCESS) {
140             goto release_operation_and_return;
141         }
142     }
143     break;
144     case TFM_CRYPTO_HASH_ABORT_SID:
145     {
146         status = psa_hash_abort(operation);
147         goto release_operation_and_return;
148     }
149     case TFM_CRYPTO_HASH_CLONE_SID:
150     {
151         psa_hash_operation_t *target_operation = NULL;
152         p_handle = out_vec[0].base;
153         *p_handle = *((uint32_t *)in_vec[1].base);
154 
155         /* Allocate the target operation context in the secure world */
156         status = tfm_crypto_operation_alloc(TFM_CRYPTO_HASH_OPERATION,
157                                             p_handle,
158                                             (void **)&target_operation);
159         if (status != PSA_SUCCESS) {
160             return status;
161         }
162         status = psa_hash_clone(operation, target_operation);
163         if (status != PSA_SUCCESS) {
164             (void)tfm_crypto_operation_release(p_handle);
165         }
166     }
167     break;
168     default:
169         return PSA_ERROR_NOT_SUPPORTED;
170     }
171 
172     return status;
173 
174 release_operation_and_return:
175     /* Release the operation context, ignore if the release fails. */
176     (void)tfm_crypto_operation_release(p_handle);
177     return status;
178 }
179 #else /* CRYPTO_HASH_MODULE_ENABLED */
tfm_crypto_hash_interface(psa_invec in_vec[],psa_outvec out_vec[])180 psa_status_t tfm_crypto_hash_interface(psa_invec in_vec[],
181                                        psa_outvec out_vec[])
182 {
183     (void)in_vec;
184     (void)out_vec;
185 
186     return PSA_ERROR_NOT_SUPPORTED;
187 }
188 #endif /* CRYPTO_HASH_MODULE_ENABLED */
189 /*!@}*/
190