1 /*
2 * Copyright (c) 2017-2022, Arm Limited. All rights reserved.
3 * Copyright (c) 2024 Cypress Semiconductor Corporation (an Infineon company)
4 * or an affiliate of Cypress Semiconductor Corporation. All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 *
8 */
9
10 #include "ps_crypto_interface.h"
11
12 #include <stdbool.h>
13 #include <string.h>
14
15 #include "config_tfm.h"
16 #include "tfm_crypto_defs.h"
17 #include "psa/crypto.h"
18
19 #define PS_KEY_LEN_BYTES 16
20
21 #ifndef PS_CRYPTO_AEAD_ALG
22 #define PS_CRYPTO_AEAD_ALG PSA_ALG_GCM
23 #endif
24
25 /* The PSA key type used by this implementation */
26 #define PS_KEY_TYPE PSA_KEY_TYPE_AES
27 /* The PSA key usage required by this implementation */
28 #define PS_KEY_USAGE (PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT)
29
30 /* The PSA algorithm used by this implementation */
31 #define PS_CRYPTO_ALG \
32 PSA_ALG_AEAD_WITH_SHORTENED_TAG(PS_CRYPTO_AEAD_ALG, PS_TAG_LEN_BYTES)
33
34 /* Length of the label used to derive a crypto key */
35 #if PS_AES_KEY_USAGE_LIMIT == 0
36 #define LABEL_LEN (sizeof(int32_t) + sizeof(psa_storage_uid_t))
37 #else
38 #define LABEL_LEN (sizeof(int32_t) + sizeof(psa_storage_uid_t) + sizeof(uint32_t))
39 #endif
40
41 /*
42 * \brief Check whether the PS AEAD algorithm is a valid one
43 *
44 * Triggers a compilation error if the input algorithm is not a valid AEAD
45 * algorithm. The compilation error should be
46 * "error: 'PS_ERROR_NOT_AEAD_ALG' declared as an array with a negative size"
47 */
48 typedef char PS_ERROR_NOT_AEAD_ALG[(PSA_ALG_IS_AEAD(PS_CRYPTO_ALG)) ? 1 : -1];
49
50 static uint8_t ps_crypto_iv_buf[PS_IV_LEN_BYTES];
51
fill_key_label(const union ps_crypto_t * crypto,uint8_t * label)52 static void fill_key_label(const union ps_crypto_t *crypto,
53 uint8_t *label)
54 {
55 psa_storage_uid_t uid = crypto->ref.uid;
56 int32_t client_id = crypto->ref.client_id;
57 #if PS_AES_KEY_USAGE_LIMIT != 0
58 uint32_t gen = crypto->ref.key_gen_nr;
59 #endif
60
61 memcpy(label, &client_id, sizeof(client_id));
62 memcpy(label + sizeof(client_id), &uid, sizeof(uid));
63 #if PS_AES_KEY_USAGE_LIMIT != 0
64 memcpy(label + sizeof(client_id) + sizeof(uid), &gen, sizeof(gen));
65 #endif
66 }
67
ps_crypto_setkey(psa_key_id_t * ps_key,const uint8_t * key_label,size_t key_label_len)68 static psa_status_t ps_crypto_setkey(psa_key_id_t *ps_key,
69 const uint8_t *key_label,
70 size_t key_label_len)
71 {
72 psa_status_t status;
73 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
74 psa_key_derivation_operation_t op = PSA_KEY_DERIVATION_OPERATION_INIT;
75
76 if (key_label_len == 0 || key_label == NULL) {
77 return PSA_ERROR_INVALID_ARGUMENT;
78 }
79
80 /* Set the key attributes for the storage key */
81 psa_set_key_usage_flags(&attributes, PS_KEY_USAGE);
82 psa_set_key_algorithm(&attributes, PS_CRYPTO_ALG);
83 psa_set_key_type(&attributes, PS_KEY_TYPE);
84 psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(PS_KEY_LEN_BYTES));
85
86 status = psa_key_derivation_setup(&op, PSA_ALG_HKDF(PSA_ALG_SHA_256));
87 if (status != PSA_SUCCESS) {
88 return status;
89 }
90
91 /* Set up a key derivation operation with HUK */
92 status = psa_key_derivation_input_key(&op, PSA_KEY_DERIVATION_INPUT_SECRET,
93 TFM_BUILTIN_KEY_ID_HUK);
94 if (status != PSA_SUCCESS) {
95 goto err_release_op;
96 }
97
98 /* Supply the PS key label as an input to the key derivation */
99 status = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_INFO,
100 key_label,
101 key_label_len);
102 if (status != PSA_SUCCESS) {
103 goto err_release_op;
104 }
105
106 /* Create the storage key from the key derivation operation */
107 status = psa_key_derivation_output_key(&attributes, &op, ps_key);
108 if (status != PSA_SUCCESS) {
109 goto err_release_op;
110 }
111
112 /* Free resources associated with the key derivation operation */
113 status = psa_key_derivation_abort(&op);
114 if (status != PSA_SUCCESS) {
115 goto err_release_key;
116 }
117
118 return PSA_SUCCESS;
119
120 err_release_key:
121 (void)psa_destroy_key(*ps_key);
122
123 err_release_op:
124 (void)psa_key_derivation_abort(&op);
125
126 return PSA_ERROR_GENERIC_ERROR;
127 }
128
ps_crypto_init(void)129 psa_status_t ps_crypto_init(void)
130 {
131 /* For GCM and CCM it is essential that nonce doesn't get repeated. If there
132 * is no rollback protection, an attacker could try to rollback the storage and
133 * encrypt another plaintext block with same IV/Key pair; this breaks GCM and CCM
134 * usage rules.
135 */
136 const psa_algorithm_t ps_crypto_aead_alg = PS_CRYPTO_AEAD_ALG;
137 #ifndef PS_ROLLBACK_PROTECTION
138 if ((ps_crypto_aead_alg == PSA_ALG_GCM) || (ps_crypto_aead_alg == PSA_ALG_CCM)) {
139 return PSA_ERROR_PROGRAMMER_ERROR;
140 }
141 #else
142 (void)ps_crypto_aead_alg;
143 #endif
144 return PSA_SUCCESS;
145 }
146
ps_crypto_to_blocks(size_t in_len)147 uint32_t ps_crypto_to_blocks(size_t in_len)
148 {
149 /* add one additional block to account for the finish operation */
150 return 1 + (in_len + PSA_BLOCK_CIPHER_BLOCK_LENGTH(PSA_KEY_TYPE_AES) - 1)
151 / PSA_BLOCK_CIPHER_BLOCK_LENGTH(PSA_KEY_TYPE_AES);
152 }
153
ps_crypto_set_iv(const union ps_crypto_t * crypto)154 void ps_crypto_set_iv(const union ps_crypto_t *crypto)
155 {
156 (void)memcpy(ps_crypto_iv_buf, crypto->ref.iv, PS_IV_LEN_BYTES);
157 }
158
ps_crypto_get_iv(union ps_crypto_t * crypto)159 psa_status_t ps_crypto_get_iv(union ps_crypto_t *crypto)
160 {
161 /* IV characteristic is algorithm dependent.
162 * For GCM it is essential that it doesn't get repeated.
163 * A simple increment will suffice.
164 * FIXME:
165 * Since IV is predictable in this case,
166 * If there is no rollback protection, an attacker could
167 * try to rollback the storage and encrypt another plaintext
168 * block with same IV/Key pair; this breaks GCM usage rules.
169 * One potential fix would be to generate IV through RNG
170 */
171
172 /* Logic:
173 * IV is a 12 byte value. Read the old value and increment it by 1.
174 * since there is no standard C support for 12 byte integer mathematics,
175 * the increment need to performed manually. Increment the lower 8byte
176 * as uint64_t value and then if the new value is 0, increment the upper
177 * 4 bytes as uint32_t
178 * Endian order doesn't really matter as objective is not to perform
179 * machine accurate increment operation but to generate a non-repetitive
180 * iv value.
181 */
182
183 uint64_t iv_l;
184 uint32_t iv_h;
185
186 (void)memcpy(&iv_l, ps_crypto_iv_buf, sizeof(iv_l));
187 (void)memcpy(&iv_h, (ps_crypto_iv_buf+sizeof(iv_l)), sizeof(iv_h));
188 iv_l++;
189 /* If overflow, increment the MSBs */
190 if (iv_l == 0) {
191 iv_h++;
192
193 /* If overflow, return error. Different IV should be used. */
194 if (iv_h == 0) {
195 /* Reset iv_l and iv_h to the value before increasement. Otherwise,
196 * iv_l will start from '1' the next time this function is called.
197 */
198 iv_l--;
199 iv_h--;
200 return PSA_ERROR_GENERIC_ERROR;
201 }
202 }
203
204 /* Update the local buffer */
205 (void)memcpy(ps_crypto_iv_buf, &iv_l, sizeof(iv_l));
206 (void)memcpy((ps_crypto_iv_buf + sizeof(iv_l)), &iv_h, sizeof(iv_h));
207 /* Update the caller buffer */
208 (void)memcpy(crypto->ref.iv, ps_crypto_iv_buf, PS_IV_LEN_BYTES);
209
210 return PSA_SUCCESS;
211 }
212
ps_crypto_encrypt_and_tag(union ps_crypto_t * crypto,const uint8_t * add,size_t add_len,const uint8_t * in,size_t in_len,uint8_t * out,size_t out_size,size_t * out_len)213 psa_status_t ps_crypto_encrypt_and_tag(union ps_crypto_t *crypto,
214 const uint8_t *add,
215 size_t add_len,
216 const uint8_t *in,
217 size_t in_len,
218 uint8_t *out,
219 size_t out_size,
220 size_t *out_len)
221 {
222 psa_status_t status;
223 psa_key_id_t ps_key;
224 uint8_t label[LABEL_LEN];
225
226 fill_key_label(crypto, label);
227
228 status = ps_crypto_setkey(&ps_key, label, sizeof(label));
229 if (status != PSA_SUCCESS) {
230 return status;
231 }
232
233 status = psa_aead_encrypt(ps_key, PS_CRYPTO_ALG,
234 crypto->ref.iv, PS_IV_LEN_BYTES,
235 add, add_len,
236 in, in_len,
237 out, out_size, out_len);
238 if (status != PSA_SUCCESS) {
239 (void)psa_destroy_key(ps_key);
240 return PSA_ERROR_GENERIC_ERROR;
241 }
242
243 /* Copy the tag out of the output buffer */
244 *out_len -= PS_TAG_LEN_BYTES;
245 (void)memcpy(crypto->ref.tag, (out + *out_len), PS_TAG_LEN_BYTES);
246
247 /* Destroy the transient key */
248 status = psa_destroy_key(ps_key);
249 if (status != PSA_SUCCESS) {
250 return PSA_ERROR_GENERIC_ERROR;
251 }
252
253 return PSA_SUCCESS;
254 }
255
ps_crypto_auth_and_decrypt(const union ps_crypto_t * crypto,const uint8_t * add,size_t add_len,uint8_t * in,size_t in_len,uint8_t * out,size_t out_size,size_t * out_len)256 psa_status_t ps_crypto_auth_and_decrypt(const union ps_crypto_t *crypto,
257 const uint8_t *add,
258 size_t add_len,
259 uint8_t *in,
260 size_t in_len,
261 uint8_t *out,
262 size_t out_size,
263 size_t *out_len)
264 {
265 psa_status_t status;
266 psa_key_id_t ps_key;
267 uint8_t label[LABEL_LEN];
268
269 fill_key_label(crypto, label);
270
271 /* Copy the tag into the input buffer */
272 (void)memcpy((in + in_len), crypto->ref.tag, PS_TAG_LEN_BYTES);
273 in_len += PS_TAG_LEN_BYTES;
274
275 status = ps_crypto_setkey(&ps_key, label, sizeof(label));
276 if (status != PSA_SUCCESS) {
277 return status;
278 }
279
280 status = psa_aead_decrypt(ps_key, PS_CRYPTO_ALG,
281 crypto->ref.iv, PS_IV_LEN_BYTES,
282 add, add_len,
283 in, in_len,
284 out, out_size, out_len);
285 if (status != PSA_SUCCESS) {
286 (void)psa_destroy_key(ps_key);
287 return PSA_ERROR_INVALID_SIGNATURE;
288 }
289
290 /* Destroy the transient key */
291 status = psa_destroy_key(ps_key);
292 if (status != PSA_SUCCESS) {
293 return PSA_ERROR_GENERIC_ERROR;
294 }
295
296 return PSA_SUCCESS;
297 }
298
ps_crypto_generate_auth_tag(union ps_crypto_t * crypto,const uint8_t * add,uint32_t add_len)299 psa_status_t ps_crypto_generate_auth_tag(union ps_crypto_t *crypto,
300 const uint8_t *add,
301 uint32_t add_len)
302 {
303 psa_status_t status;
304 size_t out_len;
305 psa_key_id_t ps_key;
306 uint8_t label[LABEL_LEN];
307
308 fill_key_label(crypto, label);
309
310 status = ps_crypto_setkey(&ps_key, label, sizeof(label));
311 if (status != PSA_SUCCESS) {
312 return status;
313 }
314
315 status = psa_aead_encrypt(ps_key, PS_CRYPTO_ALG,
316 crypto->ref.iv, PS_IV_LEN_BYTES,
317 add, add_len,
318 0, 0,
319 crypto->ref.tag, PS_TAG_LEN_BYTES, &out_len);
320 if (status != PSA_SUCCESS || out_len != PS_TAG_LEN_BYTES) {
321 (void)psa_destroy_key(ps_key);
322 return PSA_ERROR_GENERIC_ERROR;
323 }
324
325 /* Destroy the transient key */
326 status = psa_destroy_key(ps_key);
327 if (status != PSA_SUCCESS) {
328 return PSA_ERROR_GENERIC_ERROR;
329 }
330
331 return PSA_SUCCESS;
332 }
333
ps_crypto_authenticate(const union ps_crypto_t * crypto,const uint8_t * add,uint32_t add_len)334 psa_status_t ps_crypto_authenticate(const union ps_crypto_t *crypto,
335 const uint8_t *add,
336 uint32_t add_len)
337 {
338 psa_status_t status;
339 size_t out_len;
340 psa_key_id_t ps_key;
341 uint8_t label[LABEL_LEN];
342
343 fill_key_label(crypto, label);
344
345 status = ps_crypto_setkey(&ps_key, label, sizeof(label));
346 if (status != PSA_SUCCESS) {
347 return status;
348 }
349
350 status = psa_aead_decrypt(ps_key, PS_CRYPTO_ALG,
351 crypto->ref.iv, PS_IV_LEN_BYTES,
352 add, add_len,
353 crypto->ref.tag, PS_TAG_LEN_BYTES,
354 0, 0, &out_len);
355 if (status != PSA_SUCCESS || out_len != 0) {
356 (void)psa_destroy_key(ps_key);
357 return PSA_ERROR_INVALID_SIGNATURE;
358 }
359
360 /* Destroy the transient key */
361 status = psa_destroy_key(ps_key);
362 if (status != PSA_SUCCESS) {
363 return PSA_ERROR_GENERIC_ERROR;
364 }
365
366 return PSA_SUCCESS;
367 }
368
369 #ifdef PS_SUPPORT_FORMAT_TRANSITION
ps_crypto_authenticate_transition(const union ps_crypto_t * crypto,const uint8_t * add,uint32_t add_len)370 psa_status_t ps_crypto_authenticate_transition(const union ps_crypto_t *crypto,
371 const uint8_t *add,
372 uint32_t add_len)
373 {
374 psa_status_t status;
375 size_t out_len;
376 /* Fixed object table label used in older version of PS */
377 uint8_t ps_table_key_label[] = "table_key_label";
378 psa_key_id_t ps_key;
379
380 /* Set object table key */
381 status = ps_crypto_setkey(&ps_key, ps_table_key_label, sizeof(ps_table_key_label));
382 if (status != PSA_SUCCESS) {
383 return status;
384 }
385
386 status = psa_aead_decrypt(ps_key, PS_CRYPTO_ALG,
387 crypto->ref.iv, PS_IV_LEN_BYTES,
388 add, add_len,
389 crypto->ref.tag, PS_TAG_LEN_BYTES,
390 0, 0, &out_len);
391 if (status != PSA_SUCCESS || out_len != 0) {
392 (void)psa_destroy_key(ps_key);
393 return PSA_ERROR_INVALID_SIGNATURE;
394 }
395
396 /* Destroy the transient key */
397 status = psa_destroy_key(ps_key);
398 if (status != PSA_SUCCESS) {
399 return PSA_ERROR_GENERIC_ERROR;
400 }
401
402 return PSA_SUCCESS;
403 }
404 #endif /* PS_SUPPORT_FORMAT_TRANSITION */
405