1 /*
2  * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "ps_encrypted_object.h"
9 
10 #include <stddef.h>
11 #include <string.h>
12 
13 #include "crypto/ps_crypto_interface.h"
14 #include "psa/internal_trusted_storage.h"
15 #include "ps_object_defs.h"
16 #include "ps_utils.h"
17 
18 /* Gets the size of data to encrypt */
19 #define PS_ENCRYPT_SIZE(plaintext_size) \
20     ((plaintext_size) + PS_OBJECT_HEADER_SIZE - sizeof(union ps_crypto_t))
21 
22 #define PS_OBJECT_START_POSITION  0
23 
24 /* Buffer to store the maximum encrypted object */
25 /* FIXME: Do partial encrypt/decrypt to reduce the size of internal buffer */
26 #define PS_MAX_ENCRYPTED_OBJ_SIZE PS_ENCRYPT_SIZE(PS_MAX_OBJECT_DATA_SIZE)
27 
28 /* FIXME: add the tag length to the crypto buffer size to account for the tag
29  * being appended to the ciphertext by the crypto layer.
30  */
31 #define PS_TAG_IV_LEN_MAX   ((PS_TAG_LEN_BYTES > PS_IV_LEN_BYTES) ? \
32                              PS_TAG_LEN_BYTES : PS_IV_LEN_BYTES)
33 #define PS_CRYPTO_BUF_LEN (PS_MAX_ENCRYPTED_OBJ_SIZE + PS_TAG_IV_LEN_MAX)
34 
fill_key_label(struct ps_object_t * obj,uint8_t * label)35 static psa_status_t fill_key_label(struct ps_object_t *obj, uint8_t *label)
36 {
37     psa_storage_uid_t uid = obj->header.crypto.ref.uid;
38     int32_t client_id = obj->header.crypto.ref.client_id;
39 
40     memcpy(label, &client_id, sizeof(client_id));
41     memcpy(label + sizeof(client_id), &uid, sizeof(uid));
42 
43     return PSA_SUCCESS;
44 }
45 
46 /**
47  * \brief Performs authenticated decryption on object data, with the header as
48  *        the associated data.
49  *
50  * \param[in]  fid       File ID
51  * \param[in]  cur_size  Size of the object data to decrypt
52  * \param[in,out] obj    Pointer to the object structure to authenticate and
53  *                       fill in with the decrypted data. The tag of the object
54  *                       is the one stored in the object table for the given
55  *                       File ID.
56  *
57  * \return Returns error code as specified in \ref psa_status_t
58  */
ps_object_auth_decrypt(uint32_t fid,uint32_t cur_size,struct ps_object_t * obj)59 static psa_status_t ps_object_auth_decrypt(uint32_t fid,
60                                            uint32_t cur_size,
61                                            struct ps_object_t *obj)
62 {
63     psa_status_t err;
64     uint8_t *p_obj_data = (uint8_t *)&obj->header.info;
65     size_t out_len;
66     uint8_t label[sizeof(int32_t) + sizeof(psa_storage_uid_t)];
67 
68     err = fill_key_label(obj, label);
69     if (err != PSA_SUCCESS) {
70         return err;
71     }
72 
73     err = ps_crypto_setkey(label, sizeof(label));
74     if (err != PSA_SUCCESS) {
75         return err;
76     }
77 
78     /* Use File ID as a part of the associated data to authenticate
79      * the object in the FS. The tag will be stored in the object table and
80      * not as a part of the object's data stored in the FS.
81      */
82 
83     err = ps_crypto_auth_and_decrypt(&obj->header.crypto,
84                                      (const uint8_t *)&fid,
85                                      sizeof(fid),
86                                      p_obj_data,
87                                      cur_size,
88                                      p_obj_data,
89                                      sizeof(*obj) - sizeof(obj->header.crypto),
90                                      &out_len);
91     if (err != PSA_SUCCESS || out_len != cur_size) {
92         (void)ps_crypto_destroykey();
93         return PSA_ERROR_GENERIC_ERROR;
94     }
95 
96     return ps_crypto_destroykey();
97 }
98 
99 /**
100  * \brief Performs authenticated encryption on object data, with the header as
101  *        the associated data.
102  *
103  * \param[in]  fid       File ID
104  * \param[in]  cur_size  Size of the object data to encrypt
105  * \param[out] obj       Pointer to the object structure to authenticate and
106  *                       fill in with the encrypted data.
107  *
108  * \return Returns error code as specified in \ref psa_status_t
109  */
ps_object_auth_encrypt(uint32_t fid,uint32_t cur_size,struct ps_object_t * obj)110 static psa_status_t ps_object_auth_encrypt(uint32_t fid,
111                                            uint32_t cur_size,
112                                            struct ps_object_t *obj)
113 {
114     psa_status_t err;
115     uint8_t *p_obj_data = (uint8_t *)&obj->header.info;
116     size_t out_len;
117     uint8_t label[sizeof(int32_t) + sizeof(psa_storage_uid_t)];
118 
119     err = fill_key_label(obj, label);
120     if (err != PSA_SUCCESS) {
121         return err;
122     }
123 
124     err = ps_crypto_setkey(label, sizeof(label));
125     if (err != PSA_SUCCESS) {
126         return err;
127     }
128 
129     /* Get a new IV for each encryption */
130     err = ps_crypto_get_iv(&obj->header.crypto);
131     if (err != PSA_SUCCESS) {
132         return err;
133     }
134 
135     /* Use File ID as a part of the associated data to authenticate
136      * the object in the FS. The tag will be stored in the object table and
137      * not as a part of the object's data stored in the FS.
138      */
139 
140     err = ps_crypto_encrypt_and_tag(&obj->header.crypto,
141                                     (const uint8_t *)&fid,
142                                     sizeof(fid),
143                                     p_obj_data,
144                                     cur_size,
145                                     (uint8_t *)&obj->header.info,
146                                     PS_CRYPTO_BUF_LEN,
147                                     &out_len);
148     if (err != PSA_SUCCESS || out_len != cur_size) {
149         (void)ps_crypto_destroykey();
150         return PSA_ERROR_GENERIC_ERROR;
151     }
152 
153     return ps_crypto_destroykey();
154 }
155 
ps_encrypted_object_read(uint32_t fid,struct ps_object_t * obj)156 psa_status_t ps_encrypted_object_read(uint32_t fid, struct ps_object_t *obj)
157 {
158     psa_status_t err;
159     uint32_t decrypt_size;
160     size_t data_length;
161 
162     /* Read the encrypted object from the persistent area. The data stored via
163      * ITS interface of this `fid` is the encrypted object together with the
164      * `IV`.
165      * In the psa_its_get, the buffer size is not checked. Check the buffer size
166      * here.
167      */
168     err = psa_its_get(fid, PS_OBJECT_START_POSITION,
169                       PS_MAX_ENCRYPTED_OBJ_SIZE + PS_IV_LEN_BYTES,
170                       (void *)obj->header.crypto.ref.iv,
171                       &data_length);
172     if (err != PSA_SUCCESS) {
173         return err;
174     }
175 
176     /* Get the decrypt size. IV is also stored by ITS service. It is at the end
177      * of the read out data. Toolchains may add padding byte after iv array in
178      * crypto.ref structure. Separate the copies of header.info and iv array to
179      * skip the padding byte.
180      */
181     decrypt_size = data_length - sizeof(obj->header.crypto.ref.iv);
182 
183     /* Decrypt the object data */
184     err = ps_object_auth_decrypt(fid, decrypt_size, obj);
185     if (err != PSA_SUCCESS) {
186         return err;
187     }
188 
189     return PSA_SUCCESS;
190 }
191 
ps_encrypted_object_write(uint32_t fid,struct ps_object_t * obj)192 psa_status_t ps_encrypted_object_write(uint32_t fid, struct ps_object_t *obj)
193 {
194     psa_status_t err;
195     uint32_t wrt_size;
196 
197     wrt_size = PS_ENCRYPT_SIZE(obj->header.info.current_size);
198 
199     /* Authenticate and encrypt the object */
200     err = ps_object_auth_encrypt(fid, wrt_size, obj);
201     if (err != PSA_SUCCESS) {
202         return err;
203     }
204 
205     /* The IV will also be stored. The encrypted data is stored in ps_crypto_buf
206      * now. Append the value of the 'iv' to the end of the encrypted data.
207      * Toolchains may add padding byte after iv array in crypto.ref structure.
208      * The padding byte shall not be written into the storage area.
209      */
210     wrt_size += sizeof(obj->header.crypto.ref.iv);
211 
212     /* Write the encrypted object to the persistent area. The tag values is not
213      * copied as it is stored in the object table.
214      */
215     return psa_its_set(fid, wrt_size, (const void *)obj->header.crypto.ref.iv,
216                        PSA_STORAGE_FLAG_NONE);
217 }
218