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