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