TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
attest_symmetric_key.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
3  * Copyright (c) 2018-2019, Laurence Lundblade.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  */
8 
9 #include <stddef.h>
10 #include <stdint.h>
11 
12 #include "attest_key.h"
13 #include "tfm_plat_crypto_keys.h"
14 #include "psa/crypto.h"
15 #include "tfm_memory_utils.h"
16 
17 /* Only support HMAC as MAC algorithm in COSE_Mac0 so far */
18 #define SYMMETRIC_IAK_MAX_SIZE PSA_MAC_MAX_SIZE
19 
20 /* Hash algorithm for calculating Instance ID */
21 #define INSTANCE_ID_HASH_ALG PSA_ALG_SHA_256
22 
23 /* Length of kid buffer */
24 #define KID_BUF_LEN 32
25 
26 /* Symmetric IAK handle */
27 static psa_key_handle_t symmetric_iak_handle = 0;
28 
29 /* Instance ID for symmetric IAK */
30 static uint8_t instance_id_buf[PSA_HASH_SIZE(INSTANCE_ID_HASH_ALG) + 1];
31 static size_t instance_id_len = 0;
32 
33 #ifdef INCLUDE_COSE_KEY_ID
34 /* kid buffer */
35 static uint8_t kid_buf[KID_BUF_LEN];
36 /* Actual kid length */
37 static size_t kid_len = 0;
38 #endif
39 
40 static psa_status_t destroy_iak(psa_key_handle_t *iak_handle)
41 {
42  psa_status_t res;
43 
44  res = psa_destroy_key(*iak_handle);
45 
46  *iak_handle = 0;
47  return res;
48 }
49 
61 static psa_status_t symmetric_iak_hash(const uint8_t *iak_buf,
62  size_t iak_len,
63  uint8_t *hash_buf,
64  size_t hash_size,
65  size_t *hash_len)
66 {
68  psa_status_t status;
69 
70  if (!iak_buf || !hash_buf || !hash_len) {
72  }
73 
74  status = psa_hash_setup(&hash_op, INSTANCE_ID_HASH_ALG);
75  if (status != PSA_SUCCESS) {
76  return status;
77  }
78 
79  status = psa_hash_update(&hash_op, iak_buf, iak_len);
80  if (status != PSA_SUCCESS) {
81  return status;
82  }
83 
84  status = psa_hash_finish(&hash_op, hash_buf, hash_size, hash_len);
85 
86  return status;
87 }
88 
89 /*
90  * Hash a symmetric Initial Attestation Key (IAK) twice to get the Instance ID.
91  *
92  * \note Please note that this function will corrupt the original IAK data in
93  * iak_buf.
94  * It can save a 32-byte buffer to put the intermediate data of the first
95  * hash into iak_buf.
96  */
97 static psa_status_t calc_instance_id(uint8_t *iak_buf, size_t iak_len)
98 {
99  psa_status_t status;
100  /* Leave the first byte for UEID type byte */
101  uint8_t *id_ptr = instance_id_buf + 1;
102  size_t id_len = sizeof(instance_id_buf) - 1;
103 
104  if (!iak_buf) {
105  return PSA_ATTEST_ERR_GENERAL;
106  }
107 
108  status = symmetric_iak_hash(iak_buf, iak_len, id_ptr, id_len,
109  &instance_id_len);
110  if (status != PSA_SUCCESS) {
111  instance_id_len = 0;
112  return status;
113  }
114 
115  /*
116  * instance_id_len = SHA-256 block size < key_len <= key_buf size
117  * It should be safe to directly copy without boundary check.
118  */
119  tfm_memcpy(iak_buf, id_ptr, instance_id_len);
120 
121  status = symmetric_iak_hash(iak_buf, instance_id_len, id_ptr, id_len,
122  &instance_id_len);
123  if (status == PSA_SUCCESS) {
124  /* Add UEID type byte 0x01 */
125  instance_id_buf[0] = 0x01;
126  instance_id_len++;
127  } else {
128  instance_id_len = 0;
129  }
130 
131  return status;
132 }
133 
135 {
136  uint8_t key_buf[SYMMETRIC_IAK_MAX_SIZE];
137  psa_algorithm_t key_alg;
138  psa_key_handle_t key_handle;
139  size_t key_len;
140  enum tfm_plat_err_t plat_res;
141  psa_status_t psa_res;
143 
144  if (symmetric_iak_handle) {
145  return PSA_ATTEST_ERR_GENERAL;
146  }
147 
148  /* Get the symmetric initial attestation key for HMAC operation */
149  plat_res = tfm_plat_get_symmetric_iak(key_buf, sizeof(key_buf),
150  &key_len, &key_alg);
151  /* In case the buffer size was not checked, although unlikely */
152  if (sizeof(key_buf) < key_len) {
153  /*
154  * Something critical following key_buf may be overwritten.
155  * Directly jump into fatal error handling.
156  *
157  * TODO: Should be replaced by a call to psa_panic() when it
158  * becomes available.
159  */
160  while (1) {
161  ;
162  }
163  }
164  if (plat_res != TFM_PLAT_ERR_SUCCESS) {
165  return PSA_ATTEST_ERR_GENERAL;
166  }
167 
168  /*
169  * Verify if HMAC algorithm is valid.
170  * According to COSE (RFC 8152), only SHA-256, SHA-384 and SHA-512 are
171  * supported in HMAC.
172  */
173  if ((key_alg != PSA_ALG_HMAC(PSA_ALG_SHA_256)) &&
174  (key_alg != PSA_ALG_HMAC(PSA_ALG_SHA_384)) &&
175  (key_alg != PSA_ALG_HMAC(PSA_ALG_SHA_512))) {
176  return PSA_ATTEST_ERR_GENERAL;
177  }
178 
179  /* Setup the key attributes */
180  psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_SIGN);
181  psa_set_key_algorithm(&key_attributes, key_alg);
182  psa_set_key_type(&key_attributes, PSA_KEY_TYPE_HMAC);
183 
184  /* Register the symmetric key to Crypto service */
185  psa_res = psa_import_key(&key_attributes, key_buf, key_len, &key_handle);
186  if (psa_res != PSA_SUCCESS) {
187  return PSA_ATTEST_ERR_GENERAL;
188  }
189 
190  symmetric_iak_handle = key_handle;
191 
192  /*
193  * Calculate the Instance ID.
194  * Since Instance ID is generated from symmetric IAK, achieve it now to
195  * protect critical IAK raw data from being repeatedly fetched.
196  * IAK in key_buf will be corrupted. Therefore, this step must be called
197  * at the end.
198  */
199  psa_res = calc_instance_id(key_buf, key_len);
200  if (psa_res != PSA_SUCCESS) {
201  destroy_iak(&symmetric_iak_handle);
202  return PSA_ATTEST_ERR_GENERAL;
203  }
204 
205  return PSA_ATTEST_ERR_SUCCESS;
206 }
207 
209 {
210  if (!symmetric_iak_handle) {
211  return PSA_ATTEST_ERR_GENERAL;
212  }
213 
214  destroy_iak(&symmetric_iak_handle);
215 
216  /* Invalidate the Instance ID as well */
217  instance_id_len = 0;
218 
219 #ifdef INCLUDE_COSE_KEY_ID
220  /* Invalidate the corresponding kid as well */
221  kid_len = 0;
222 #endif
223 
224  return PSA_ATTEST_ERR_SUCCESS;
225 }
226 
227 enum psa_attest_err_t
229 {
230  if (!symmetric_iak_handle) {
231  return PSA_ATTEST_ERR_GENERAL;
232  }
233 
234  *key_handle = symmetric_iak_handle;
235 
236  return PSA_ATTEST_ERR_SUCCESS;
237 }
238 
239 enum psa_attest_err_t
240 attest_get_instance_id(struct q_useful_buf_c *id_buf)
241 {
242  if (!id_buf) {
243  return PSA_ATTEST_ERR_GENERAL;
244  }
245 
246  if (!instance_id_len) {
248  }
249 
250  id_buf->ptr = instance_id_buf;
251  id_buf->len = instance_id_len;
252 
253  return PSA_ATTEST_ERR_SUCCESS;
254 }
255 
256 #ifdef INCLUDE_COSE_KEY_ID
257 enum psa_attest_err_t
258 attest_get_initial_attestation_key_id(struct q_useful_buf_c *attest_key_id)
259 {
260  enum tfm_plat_err_t plat_res;
261 
262  if (!attest_key_id) {
263  return PSA_ATTEST_ERR_GENERAL;
264  }
265 
266  /* The kid has not been fetched previously */
267  if (!kid_len) {
268  plat_res = tfm_plat_get_symmetric_iak_id(kid_buf,
269  sizeof(kid_buf),
270  &kid_len);
271  /* In case the buffer size was not checked, although unlikely */
272  if (sizeof(kid_buf) < kid_len) {
273  /*
274  * Something critical following kid_buf may be overwritten.
275  * Directly jump into fatal error handling.
276  *
277  * TODO: Should be replaced by a call to psa_panic() when it
278  * becomes available.
279  */
280  while (1) {
281  ;
282  }
283  }
284 
285  if (plat_res != TFM_PLAT_ERR_SUCCESS) {
286  return PSA_ATTEST_ERR_GENERAL;
287  }
288  }
289 
290  attest_key_id->ptr = (const void *)&kid_buf;
291  attest_key_id->len = kid_len;
292 
293  return PSA_ATTEST_ERR_SUCCESS;
294 }
295 #endif /* INCLUDE_COSE_KEY_ID */
#define PSA_HASH_SIZE(alg)
Definition: crypto_sizes.h:53
#define INSTANCE_ID_HASH_ALG
#define psa_hash_setup
Definition: crypto_spe.h:89
#define PSA_SUCCESS
Definition: crypto_values.h:35
Platform Security Architecture cryptography module.
psa_attest_err_t
Initial attestation service error types.
Definition: attest.h:25
enum psa_attest_err_t attest_register_initial_attestation_key(void)
Register the initial attestation private key to Crypto service. Loads the public key if the key has n...
#define PSA_ALG_HMAC(hash_alg)
#define psa_hash_finish
Definition: crypto_spe.h:93
#define PSA_ALG_SHA_256
#define PSA_KEY_ATTRIBUTES_INIT
Definition: crypto.h:113
#define PSA_ALG_SHA_512
enum psa_attest_err_t attest_get_instance_id(struct q_useful_buf_c *id_buf)
Get the buffer of Instance ID data.
#define psa_import_key
Definition: crypto_spe.h:57
#define PSA_ALG_SHA_384
enum psa_attest_err_t attest_get_signing_key_handle(psa_key_handle_t *key_handle)
Get the handle of the key for signing token In asymmetric key algorithm based initial attestation...
#define psa_hash_update
Definition: crypto_spe.h:91
#define PSA_ERROR_INVALID_ARGUMENT
uint32_t psa_algorithm_t
Encoding of a cryptographic algorithm.
Definition: crypto_types.h:90
#define PSA_KEY_USAGE_SIGN
Definition: crypto_compat.h:69
enum psa_attest_err_t attest_unregister_initial_attestation_key(void)
Unregister the initial attestation private key from Crypto service to do not occupy key slot...
_unsigned_integral_type_ psa_key_handle_t
Key handle.
Definition: crypto.h:35
#define psa_hash_operation_init
Definition: crypto_spe.h:87
#define PSA_KEY_TYPE_HMAC
__STATIC_INLINE void * tfm_memcpy(void *dest, const void *src, size_t num)
#define psa_destroy_key
Definition: crypto_spe.h:59
int32_t psa_status_t
Function return status.
Definition: crypto_types.h:43
#define SYMMETRIC_IAK_MAX_SIZE
#define KID_BUF_LEN