TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ps_crypto_interface.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-2020, 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 
12 #include "tfm_crypto_defs.h"
13 #include "psa/crypto.h"
14 #include "tfm_memory_utils.h"
15 
16 #ifndef PS_CRYPTO_AEAD_ALG
17 #define PS_CRYPTO_AEAD_ALG PSA_ALG_GCM
18 #endif
19 
20 /* The PSA key type used by this implementation */
21 #define PS_KEY_TYPE PSA_KEY_TYPE_AES
22 /* The PSA key usage required by this implementation */
23 #define PS_KEY_USAGE (PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT)
24 
25 /* The PSA algorithm used by this implementation */
26 #define PS_CRYPTO_ALG \
27  PSA_ALG_AEAD_WITH_TAG_LENGTH(PS_CRYPTO_AEAD_ALG, PS_TAG_LEN_BYTES)
28 
29 /*
30  * \brief Check whether the PS AEAD algorithm is a valid one
31  *
32  * Triggers a compilation error if the input algorithm is not a valid AEAD
33  * algorithm. The compilation error should be
34  * "error: 'PS_ERROR_NOT_AEAD_ALG' declared as an array with a negative size"
35  */
37 
38 static const uint8_t ps_key_label[] = "storage_key";
39 static psa_key_handle_t ps_key_handle;
40 static uint8_t ps_crypto_iv_buf[PS_IV_LEN_BYTES];
41 
43 {
44  /* Currently, no initialisation is required. This may change if key
45  * handling is changed.
46  */
47  return PSA_SUCCESS;
48 }
49 
51 {
52  psa_status_t status;
55 
56  /* Set the key attributes for the storage key */
57  psa_set_key_usage_flags(&attributes, PS_KEY_USAGE);
58  psa_set_key_algorithm(&attributes, PS_CRYPTO_ALG);
59  psa_set_key_type(&attributes, PS_KEY_TYPE);
60  psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(PS_KEY_LEN_BYTES));
61 
62  /* Set up a key derivation operation with HUK derivation as the alg */
64  if (status != PSA_SUCCESS) {
65  return status;
66  }
67 
68  /* Supply the PS key label as an input to the key derivation */
70  ps_key_label,
71  sizeof(ps_key_label));
72  if (status != PSA_SUCCESS) {
73  goto err_release_op;
74  }
75 
76  /* Create the storage key from the key derivation operation */
77  status = psa_key_derivation_output_key(&attributes, &op, &ps_key_handle);
78  if (status != PSA_SUCCESS) {
79  goto err_release_op;
80  }
81 
82  /* Free resources associated with the key derivation operation */
83  status = psa_key_derivation_abort(&op);
84  if (status != PSA_SUCCESS) {
85  goto err_release_key;
86  }
87 
88  return PSA_SUCCESS;
89 
90 err_release_key:
91  (void)psa_destroy_key(ps_key_handle);
92 
93 err_release_op:
94  (void)psa_key_derivation_abort(&op);
95 
97 }
98 
100 {
101  psa_status_t status;
102 
103  /* Destroy the transient key */
104  status = psa_destroy_key(ps_key_handle);
105  if (status != PSA_SUCCESS) {
107  }
108 
109  return PSA_SUCCESS;
110 }
111 
112 void ps_crypto_set_iv(const union ps_crypto_t *crypto)
113 {
114  (void)tfm_memcpy(ps_crypto_iv_buf, crypto->ref.iv, PS_IV_LEN_BYTES);
115 }
116 
117 void ps_crypto_get_iv(union ps_crypto_t *crypto)
118 {
119  /* IV characteristic is algorithm dependent.
120  * For GCM it is essential that it doesn't get repeated.
121  * A simple increment will suffice.
122  * FIXME:
123  * Since IV is predictable in this case,
124  * If there is no rollback protection, an attacker could
125  * try to rollback the storage and encrypt another plaintext
126  * block with same IV/Key pair; this breaks GCM usage rules.
127  * One potential fix would be to generate IV through RNG
128  */
129 
130  /* Logic:
131  * IV is a 12 byte value. Read the old value and increment it by 1.
132  * since there is no standard C support for 12 byte integer mathematics,
133  * the increment need to performed manually. Increment the lower 8byte
134  * as uint64_t value and then if the new value is 0, increment the upper
135  * 4 bytes as uint32_t
136  * Endian order doesn't really matter as objective is not to perform
137  * machine accurate increment operation but to generate a non-repetitive
138  * iv value.
139  */
140 
141  uint64_t iv_l;
142  uint32_t iv_h;
143 
144  (void)tfm_memcpy(&iv_l, ps_crypto_iv_buf, sizeof(iv_l));
145  (void)tfm_memcpy(&iv_h, (ps_crypto_iv_buf+sizeof(iv_l)), sizeof(iv_h));
146  iv_l++;
147  /* If overflow, increment the MSBs */
148  if (iv_l == 0) {
149  iv_h++;
150  }
151 
152  /* Update the local buffer */
153  (void)tfm_memcpy(ps_crypto_iv_buf, &iv_l, sizeof(iv_l));
154  (void)tfm_memcpy((ps_crypto_iv_buf + sizeof(iv_l)), &iv_h, sizeof(iv_h));
155  /* Update the caller buffer */
156  (void)tfm_memcpy(crypto->ref.iv, ps_crypto_iv_buf, PS_IV_LEN_BYTES);
157 }
158 
160  const uint8_t *add,
161  size_t add_len,
162  const uint8_t *in,
163  size_t in_len,
164  uint8_t *out,
165  size_t out_size,
166  size_t *out_len)
167 {
168  psa_status_t status;
169 
170  status = psa_aead_encrypt(ps_key_handle, PS_CRYPTO_ALG,
171  crypto->ref.iv, PS_IV_LEN_BYTES,
172  add, add_len,
173  in, in_len,
174  out, out_size, out_len);
175  if (status != PSA_SUCCESS) {
177  }
178 
179  /* Copy the tag out of the output buffer */
180  *out_len -= PS_TAG_LEN_BYTES;
181  (void)tfm_memcpy(crypto->ref.tag, (out + *out_len), PS_TAG_LEN_BYTES);
182 
183  return PSA_SUCCESS;
184 }
185 
187  const uint8_t *add,
188  size_t add_len,
189  uint8_t *in,
190  size_t in_len,
191  uint8_t *out,
192  size_t out_size,
193  size_t *out_len)
194 {
195  psa_status_t status;
196 
197  /* Copy the tag into the input buffer */
198  (void)tfm_memcpy((in + in_len), crypto->ref.tag, PS_TAG_LEN_BYTES);
199  in_len += PS_TAG_LEN_BYTES;
200 
201  status = psa_aead_decrypt(ps_key_handle, PS_CRYPTO_ALG,
202  crypto->ref.iv, PS_IV_LEN_BYTES,
203  add, add_len,
204  in, in_len,
205  out, out_size, out_len);
206  if (status != PSA_SUCCESS) {
208  }
209 
210  return PSA_SUCCESS;
211 }
212 
214  const uint8_t *add,
215  uint32_t add_len)
216 {
217  psa_status_t status;
218  size_t out_len;
219 
220  status = psa_aead_encrypt(ps_key_handle, PS_CRYPTO_ALG,
221  crypto->ref.iv, PS_IV_LEN_BYTES,
222  add, add_len,
223  0, 0,
224  crypto->ref.tag, PS_TAG_LEN_BYTES, &out_len);
225  if (status != PSA_SUCCESS || out_len != PS_TAG_LEN_BYTES) {
227  }
228 
229  return PSA_SUCCESS;
230 }
231 
233  const uint8_t *add,
234  uint32_t add_len)
235 {
236  psa_status_t status;
237  size_t out_len;
238 
239  status = psa_aead_decrypt(ps_key_handle, PS_CRYPTO_ALG,
240  crypto->ref.iv, PS_IV_LEN_BYTES,
241  add, add_len,
242  crypto->ref.tag, PS_TAG_LEN_BYTES,
243  0, 0, &out_len);
244  if (status != PSA_SUCCESS || out_len != 0) {
246  }
247 
248  return PSA_SUCCESS;
249 }
#define PSA_ERROR_INVALID_SIGNATURE
void ps_crypto_set_iv(const union ps_crypto_t *crypto)
Provides current IV value to crypto layer.
#define PS_KEY_USAGE
#define PS_CRYPTO_ALG
#define PSA_SUCCESS
Definition: crypto_values.h:35
#define psa_aead_encrypt
Definition: crypto_spe.h:49
Platform Security Architecture cryptography module.
#define PS_TAG_LEN_BYTES
psa_status_t ps_crypto_setkey(void)
Sets the key to use for crypto operations for the current client.
psa_status_t 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)
Encrypts and tags the given plaintext data.
#define PSA_KEY_DERIVATION_INPUT_LABEL
#define PSA_KEY_ATTRIBUTES_INIT
Definition: crypto.h:113
struct ps_crypto_t::@9 ref
psa_status_t ps_crypto_init(void)
Initializes the crypto engine.
#define psa_key_derivation_output_key
Definition: crypto_spe.h:37
#define PSA_ERROR_GENERIC_ERROR
Definition: crypto_values.h:43
#define PSA_BYTES_TO_BITS(bytes)
Definition: crypto_sizes.h:34
#define psa_key_derivation_input_bytes
Definition: crypto_spe.h:31
#define PS_KEY_TYPE
#define PS_KEY_LEN_BYTES
psa_status_t ps_crypto_generate_auth_tag(union ps_crypto_t *crypto, const uint8_t *add, uint32_t add_len)
Generates authentication tag for given data.
psa_status_t 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)
Decrypts and authenticates the given encrypted data.
#define psa_key_derivation_setup
Definition: crypto_spe.h:39
#define PSA_KEY_DERIVATION_OPERATION_INIT
Definition: crypto.h:3106
char PS_ERROR_NOT_AEAD_ALG[(PSA_ALG_IS_AEAD(PSA_ALG_AEAD_WITH_TAG_LENGTH(PSA_ALG_GCM, 16)))?1:-1]
psa_status_t ps_crypto_authenticate(const union ps_crypto_t *crypto, const uint8_t *add, uint32_t add_len)
Authenticate given data against the tag.
_unsigned_integral_type_ psa_key_handle_t
Key handle.
Definition: crypto.h:35
#define psa_key_derivation_abort
Definition: crypto_spe.h:41
__STATIC_INLINE void * tfm_memcpy(void *dest, const void *src, size_t num)
#define PS_IV_LEN_BYTES
#define psa_destroy_key
Definition: crypto_spe.h:59
psa_status_t ps_crypto_destroykey(void)
Destroys the transient key used for crypto operations.
#define TFM_CRYPTO_ALG_HUK_DERIVATION
The algorithm identifier that refers to key derivation from the hardware unique key.
void ps_crypto_get_iv(union ps_crypto_t *crypto)
Gets a new IV value into the crypto union.
#define PSA_ALG_IS_AEAD(alg)
uint8_t iv[12]
int32_t psa_status_t
Function return status.
Definition: crypto_types.h:43
uint8_t tag[16]
#define psa_aead_decrypt
Definition: crypto_spe.h:51