1 /*
2 * Copyright (c) 2017-2022, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "ps_crypto_interface.h"
9
10 #include <stdbool.h>
11 #include <string.h>
12
13 #include "config_tfm.h"
14 #include "tfm_crypto_defs.h"
15 #include "psa/crypto.h"
16
17 #ifndef PS_CRYPTO_AEAD_ALG
18 #define PS_CRYPTO_AEAD_ALG PSA_ALG_GCM
19 #endif
20
21 /* The PSA key type used by this implementation */
22 #define PS_KEY_TYPE PSA_KEY_TYPE_AES
23 /* The PSA key usage required by this implementation */
24 #define PS_KEY_USAGE (PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT)
25
26 /* The PSA algorithm used by this implementation */
27 #define PS_CRYPTO_ALG \
28 PSA_ALG_AEAD_WITH_SHORTENED_TAG(PS_CRYPTO_AEAD_ALG, PS_TAG_LEN_BYTES)
29
30 /*
31 * \brief Check whether the PS AEAD algorithm is a valid one
32 *
33 * Triggers a compilation error if the input algorithm is not a valid AEAD
34 * algorithm. The compilation error should be
35 * "error: 'PS_ERROR_NOT_AEAD_ALG' declared as an array with a negative size"
36 */
37 typedef char PS_ERROR_NOT_AEAD_ALG[(PSA_ALG_IS_AEAD(PS_CRYPTO_ALG)) ? 1 : -1];
38
39 static psa_key_id_t ps_key;
40 static uint8_t ps_crypto_iv_buf[PS_IV_LEN_BYTES];
41
ps_crypto_init(void)42 psa_status_t ps_crypto_init(void)
43 {
44 /* For GCM and CCM it is essential that nonce doesn't get repeated. If there
45 * is no rollback protection, an attacker could try to rollback the storage and
46 * encrypt another plaintext block with same IV/Key pair; this breaks GCM and CCM
47 * usage rules.
48 */
49 const psa_algorithm_t ps_crypto_aead_alg = PS_CRYPTO_AEAD_ALG;
50 #ifndef PS_ROLLBACK_PROTECTION
51 if ((ps_crypto_aead_alg == PSA_ALG_GCM) || (ps_crypto_aead_alg == PSA_ALG_CCM)) {
52 return PSA_ERROR_PROGRAMMER_ERROR;
53 }
54 #else
55 (void)ps_crypto_aead_alg;
56 #endif
57 return PSA_SUCCESS;
58 }
59
ps_crypto_setkey(const uint8_t * key_label,size_t key_label_len)60 psa_status_t ps_crypto_setkey(const uint8_t *key_label, size_t key_label_len)
61 {
62 psa_status_t status;
63 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
64 psa_key_derivation_operation_t op = PSA_KEY_DERIVATION_OPERATION_INIT;
65
66 if (key_label_len == 0 || key_label == NULL) {
67 return PSA_ERROR_INVALID_ARGUMENT;
68 }
69
70 /* Set the key attributes for the storage key */
71 psa_set_key_usage_flags(&attributes, PS_KEY_USAGE);
72 psa_set_key_algorithm(&attributes, PS_CRYPTO_ALG);
73 psa_set_key_type(&attributes, PS_KEY_TYPE);
74 psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(PS_KEY_LEN_BYTES));
75
76 status = psa_key_derivation_setup(&op, PSA_ALG_HKDF(PSA_ALG_SHA_256));
77 if (status != PSA_SUCCESS) {
78 return status;
79 }
80
81 /* Set up a key derivation operation with HUK */
82 status = psa_key_derivation_input_key(&op, PSA_KEY_DERIVATION_INPUT_SECRET,
83 TFM_BUILTIN_KEY_ID_HUK);
84 if (status != PSA_SUCCESS) {
85 goto err_release_op;
86 }
87
88 /* Supply the PS key label as an input to the key derivation */
89 status = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_INFO,
90 key_label,
91 key_label_len);
92 if (status != PSA_SUCCESS) {
93 goto err_release_op;
94 }
95
96 /* Create the storage key from the key derivation operation */
97 status = psa_key_derivation_output_key(&attributes, &op, &ps_key);
98 if (status != PSA_SUCCESS) {
99 goto err_release_op;
100 }
101
102 /* Free resources associated with the key derivation operation */
103 status = psa_key_derivation_abort(&op);
104 if (status != PSA_SUCCESS) {
105 goto err_release_key;
106 }
107
108 return PSA_SUCCESS;
109
110 err_release_key:
111 (void)psa_destroy_key(ps_key);
112
113 err_release_op:
114 (void)psa_key_derivation_abort(&op);
115
116 return PSA_ERROR_GENERIC_ERROR;
117 }
118
ps_crypto_destroykey(void)119 psa_status_t ps_crypto_destroykey(void)
120 {
121 psa_status_t status;
122
123 /* Destroy the transient key */
124 status = psa_destroy_key(ps_key);
125 if (status != PSA_SUCCESS) {
126 return PSA_ERROR_GENERIC_ERROR;
127 }
128
129 return PSA_SUCCESS;
130 }
131
ps_crypto_set_iv(const union ps_crypto_t * crypto)132 void ps_crypto_set_iv(const union ps_crypto_t *crypto)
133 {
134 (void)memcpy(ps_crypto_iv_buf, crypto->ref.iv, PS_IV_LEN_BYTES);
135 }
136
ps_crypto_get_iv(union ps_crypto_t * crypto)137 psa_status_t ps_crypto_get_iv(union ps_crypto_t *crypto)
138 {
139 /* IV characteristic is algorithm dependent.
140 * For GCM it is essential that it doesn't get repeated.
141 * A simple increment will suffice.
142 * FIXME:
143 * Since IV is predictable in this case,
144 * If there is no rollback protection, an attacker could
145 * try to rollback the storage and encrypt another plaintext
146 * block with same IV/Key pair; this breaks GCM usage rules.
147 * One potential fix would be to generate IV through RNG
148 */
149
150 /* Logic:
151 * IV is a 12 byte value. Read the old value and increment it by 1.
152 * since there is no standard C support for 12 byte integer mathematics,
153 * the increment need to performed manually. Increment the lower 8byte
154 * as uint64_t value and then if the new value is 0, increment the upper
155 * 4 bytes as uint32_t
156 * Endian order doesn't really matter as objective is not to perform
157 * machine accurate increment operation but to generate a non-repetitive
158 * iv value.
159 */
160
161 uint64_t iv_l;
162 uint32_t iv_h;
163
164 (void)memcpy(&iv_l, ps_crypto_iv_buf, sizeof(iv_l));
165 (void)memcpy(&iv_h, (ps_crypto_iv_buf+sizeof(iv_l)), sizeof(iv_h));
166 iv_l++;
167 /* If overflow, increment the MSBs */
168 if (iv_l == 0) {
169 iv_h++;
170
171 /* If overflow, return error. Different IV should be used. */
172 if (iv_h == 0) {
173 /* Reset iv_l and iv_h to the value before increasement. Otherwise,
174 * iv_l will start from '1' the next time this function is called.
175 */
176 iv_l--;
177 iv_h--;
178 return PSA_ERROR_GENERIC_ERROR;
179 }
180 }
181
182 /* Update the local buffer */
183 (void)memcpy(ps_crypto_iv_buf, &iv_l, sizeof(iv_l));
184 (void)memcpy((ps_crypto_iv_buf + sizeof(iv_l)), &iv_h, sizeof(iv_h));
185 /* Update the caller buffer */
186 (void)memcpy(crypto->ref.iv, ps_crypto_iv_buf, PS_IV_LEN_BYTES);
187
188 return PSA_SUCCESS;
189 }
190
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)191 psa_status_t ps_crypto_encrypt_and_tag(union ps_crypto_t *crypto,
192 const uint8_t *add,
193 size_t add_len,
194 const uint8_t *in,
195 size_t in_len,
196 uint8_t *out,
197 size_t out_size,
198 size_t *out_len)
199 {
200 psa_status_t status;
201
202 status = psa_aead_encrypt(ps_key, PS_CRYPTO_ALG,
203 crypto->ref.iv, PS_IV_LEN_BYTES,
204 add, add_len,
205 in, in_len,
206 out, out_size, out_len);
207 if (status != PSA_SUCCESS) {
208 return PSA_ERROR_GENERIC_ERROR;
209 }
210
211 /* Copy the tag out of the output buffer */
212 *out_len -= PS_TAG_LEN_BYTES;
213 (void)memcpy(crypto->ref.tag, (out + *out_len), PS_TAG_LEN_BYTES);
214
215 return PSA_SUCCESS;
216 }
217
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)218 psa_status_t ps_crypto_auth_and_decrypt(const union ps_crypto_t *crypto,
219 const uint8_t *add,
220 size_t add_len,
221 uint8_t *in,
222 size_t in_len,
223 uint8_t *out,
224 size_t out_size,
225 size_t *out_len)
226 {
227 psa_status_t status;
228
229 /* Copy the tag into the input buffer */
230 (void)memcpy((in + in_len), crypto->ref.tag, PS_TAG_LEN_BYTES);
231 in_len += PS_TAG_LEN_BYTES;
232
233 status = psa_aead_decrypt(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 return PSA_ERROR_INVALID_SIGNATURE;
240 }
241
242 return PSA_SUCCESS;
243 }
244
ps_crypto_generate_auth_tag(union ps_crypto_t * crypto,const uint8_t * add,uint32_t add_len)245 psa_status_t ps_crypto_generate_auth_tag(union ps_crypto_t *crypto,
246 const uint8_t *add,
247 uint32_t add_len)
248 {
249 psa_status_t status;
250 size_t out_len;
251
252 status = psa_aead_encrypt(ps_key, PS_CRYPTO_ALG,
253 crypto->ref.iv, PS_IV_LEN_BYTES,
254 add, add_len,
255 0, 0,
256 crypto->ref.tag, PS_TAG_LEN_BYTES, &out_len);
257 if (status != PSA_SUCCESS || out_len != PS_TAG_LEN_BYTES) {
258 return PSA_ERROR_GENERIC_ERROR;
259 }
260
261 return PSA_SUCCESS;
262 }
263
ps_crypto_authenticate(const union ps_crypto_t * crypto,const uint8_t * add,uint32_t add_len)264 psa_status_t ps_crypto_authenticate(const union ps_crypto_t *crypto,
265 const uint8_t *add,
266 uint32_t add_len)
267 {
268 psa_status_t status;
269 size_t out_len;
270
271 status = psa_aead_decrypt(ps_key, PS_CRYPTO_ALG,
272 crypto->ref.iv, PS_IV_LEN_BYTES,
273 add, add_len,
274 crypto->ref.tag, PS_TAG_LEN_BYTES,
275 0, 0, &out_len);
276 if (status != PSA_SUCCESS || out_len != 0) {
277 return PSA_ERROR_INVALID_SIGNATURE;
278 }
279
280 return PSA_SUCCESS;
281 }
282