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
35 static uint8_t ps_crypto_buf[PS_CRYPTO_BUF_LEN];
36
fill_key_label(struct ps_object_t * obj,size_t * length)37 static psa_status_t fill_key_label(struct ps_object_t *obj, size_t *length)
38 {
39 psa_storage_uid_t uid = obj->header.crypto.ref.uid;
40 int32_t client_id = obj->header.crypto.ref.client_id;
41
42 if (PS_CRYPTO_BUF_LEN < (sizeof(client_id) + sizeof(uid))) {
43 return PSA_ERROR_BUFFER_TOO_SMALL;
44 }
45
46 memcpy(ps_crypto_buf, &client_id, sizeof(client_id));
47 memcpy(ps_crypto_buf + sizeof(client_id), &uid, sizeof(uid));
48
49 *length = sizeof(client_id) + sizeof(uid);
50
51 return PSA_SUCCESS;
52 }
53
54 /**
55 * \brief Performs authenticated decryption on object data, with the header as
56 * the associated data.
57 *
58 * \param[in] fid File ID
59 * \param[in] cur_size Size of the object data to decrypt
60 * \param[in,out] obj Pointer to the object structure to authenticate and
61 * fill in with the decrypted data. The tag of the object
62 * is the one stored in the object table for the given
63 * File ID.
64 *
65 * \return Returns error code as specified in \ref psa_status_t
66 */
ps_object_auth_decrypt(uint32_t fid,uint32_t cur_size,struct ps_object_t * obj)67 static psa_status_t ps_object_auth_decrypt(uint32_t fid,
68 uint32_t cur_size,
69 struct ps_object_t *obj)
70 {
71 psa_status_t err;
72 uint8_t *p_obj_data = (uint8_t *)&obj->header.info;
73 size_t out_len, label_length;
74
75 err = fill_key_label(obj, &label_length);
76 if (err != PSA_SUCCESS) {
77 return err;
78 }
79
80 err = ps_crypto_setkey(ps_crypto_buf, label_length);
81 if (err != PSA_SUCCESS) {
82 return err;
83 }
84
85 (void)memcpy(ps_crypto_buf, p_obj_data, cur_size);
86
87 /* Use File ID as a part of the associated data to authenticate
88 * the object in the FS. The tag will be stored in the object table and
89 * not as a part of the object's data stored in the FS.
90 */
91
92 err = ps_crypto_auth_and_decrypt(&obj->header.crypto,
93 (const uint8_t *)&fid,
94 sizeof(fid),
95 ps_crypto_buf,
96 cur_size,
97 p_obj_data,
98 sizeof(*obj) - sizeof(obj->header.crypto),
99 &out_len);
100 if (err != PSA_SUCCESS || out_len != cur_size) {
101 (void)ps_crypto_destroykey();
102 return PSA_ERROR_GENERIC_ERROR;
103 }
104
105 return ps_crypto_destroykey();
106 }
107
108 /**
109 * \brief Performs authenticated encryption on object data, with the header as
110 * the associated data.
111 *
112 * \param[in] fid File ID
113 * \param[in] cur_size Size of the object data to encrypt
114 * \param[out] obj Pointer to the object structure to authenticate and
115 * fill in with the encrypted data.
116 *
117 * \return Returns error code as specified in \ref psa_status_t
118 */
ps_object_auth_encrypt(uint32_t fid,uint32_t cur_size,struct ps_object_t * obj)119 static psa_status_t ps_object_auth_encrypt(uint32_t fid,
120 uint32_t cur_size,
121 struct ps_object_t *obj)
122 {
123 psa_status_t err;
124 uint8_t *p_obj_data = (uint8_t *)&obj->header.info;
125 size_t out_len, label_length;
126
127 err = fill_key_label(obj, &label_length);
128 if (err != PSA_SUCCESS) {
129 return err;
130 }
131
132 err = ps_crypto_setkey(ps_crypto_buf, label_length);
133 if (err != PSA_SUCCESS) {
134 return err;
135 }
136
137 /* Get a new IV for each encryption */
138 err = ps_crypto_get_iv(&obj->header.crypto);
139 if (err != PSA_SUCCESS) {
140 return err;
141 }
142
143 /* Use File ID as a part of the associated data to authenticate
144 * the object in the FS. The tag will be stored in the object table and
145 * not as a part of the object's data stored in the FS.
146 */
147
148 err = ps_crypto_encrypt_and_tag(&obj->header.crypto,
149 (const uint8_t *)&fid,
150 sizeof(fid),
151 p_obj_data,
152 cur_size,
153 ps_crypto_buf,
154 sizeof(ps_crypto_buf),
155 &out_len);
156 if (err != PSA_SUCCESS || out_len != cur_size) {
157 (void)ps_crypto_destroykey();
158 return PSA_ERROR_GENERIC_ERROR;
159 }
160
161 (void)memcpy(p_obj_data, ps_crypto_buf, cur_size);
162
163 return ps_crypto_destroykey();
164 }
165
ps_encrypted_object_read(uint32_t fid,struct ps_object_t * obj)166 psa_status_t ps_encrypted_object_read(uint32_t fid, struct ps_object_t *obj)
167 {
168 psa_status_t err;
169 uint32_t decrypt_size;
170 size_t data_length;
171
172 /* Read the encrypted object from the persistent area. The data stored via
173 * ITS interface of this `fid` is the encrypted object together with the
174 * `IV`.
175 * In the psa_its_get, the buffer size is not checked. Check the buffer size
176 * here.
177 */
178 if (sizeof(ps_crypto_buf) < PS_MAX_ENCRYPTED_OBJ_SIZE + PS_IV_LEN_BYTES) {
179 return PSA_ERROR_GENERIC_ERROR;
180 }
181 err = psa_its_get(fid, PS_OBJECT_START_POSITION,
182 PS_MAX_ENCRYPTED_OBJ_SIZE + PS_IV_LEN_BYTES,
183 (void *)ps_crypto_buf,
184 &data_length);
185 if (err != PSA_SUCCESS) {
186 return err;
187 }
188
189 /* Get the decrypt size. IV is also stored by ITS service. It is at the end
190 * of the read out data. Toolchains may add padding byte after iv array in
191 * crypto.ref structure. Separate the copies of header.info and iv array to
192 * skip the padding byte.
193 */
194 decrypt_size = data_length - sizeof(obj->header.crypto.ref.iv);
195 memcpy(&obj->header.info, ps_crypto_buf, decrypt_size);
196 memcpy(obj->header.crypto.ref.iv,
197 ps_crypto_buf + decrypt_size,
198 sizeof(obj->header.crypto.ref.iv));
199
200 /* Decrypt the object data */
201 err = ps_object_auth_decrypt(fid, decrypt_size, obj);
202 if (err != PSA_SUCCESS) {
203 return err;
204 }
205
206 return PSA_SUCCESS;
207 }
208
ps_encrypted_object_write(uint32_t fid,struct ps_object_t * obj)209 psa_status_t ps_encrypted_object_write(uint32_t fid, struct ps_object_t *obj)
210 {
211 psa_status_t err;
212 uint32_t wrt_size;
213
214 wrt_size = PS_ENCRYPT_SIZE(obj->header.info.current_size);
215
216 /* Authenticate and encrypt the object */
217 err = ps_object_auth_encrypt(fid, wrt_size, obj);
218 if (err != PSA_SUCCESS) {
219 return err;
220 }
221
222 /* The IV will also be stored. The encrypted data is stored in ps_crypto_buf
223 * now. Append the value of the 'iv' to the end of the encrypted data.
224 * Toolchains may add padding byte after iv array in crypto.ref structure.
225 * The padding byte shall not be written into the storage area.
226 */
227 (void)memcpy(ps_crypto_buf + wrt_size,
228 obj->header.crypto.ref.iv,
229 sizeof(obj->header.crypto.ref.iv));
230 wrt_size += sizeof(obj->header.crypto.ref.iv);
231
232 /* Write the encrypted object to the persistent area. The tag values is not
233 * copied as it is stored in the object table.
234 */
235 return psa_its_set(fid, wrt_size, (const void *)ps_crypto_buf,
236 PSA_STORAGE_FLAG_NONE);
237 }
238