TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
attest_asymmetric_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 "attest_key.h"
10 #include <stdint.h>
11 #include <stddef.h>
12 #include "tfm_plat_defs.h"
13 #include "tfm_plat_crypto_keys.h"
14 #include "tfm_plat_device_id.h"
15 #include "t_cose_standard_constants.h"
16 #include "q_useful_buf.h"
17 #include "qcbor.h"
18 #include "tfm_memory_utils.h"
19 
20 #define ECC_P256_PUBLIC_KEY_SIZE PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(256)
21 
30 #define ECC_P256_COORD_SIZE PSA_BITS_TO_BYTES(256) /* 256 bits -> 32 bytes */
31 
32 /* 0 is defined as an invalid handle in the PSA spec, so it is used here to
33  * indicate that the key isn't loaded.
34  */
35 #define ATTEST_KEY_HANDLE_NOT_LOADED 0
36 
41 static psa_key_handle_t attestation_key_handle = ATTEST_KEY_HANDLE_NOT_LOADED;
42 
47 static uint8_t attestation_public_key[ECC_P256_PUBLIC_KEY_SIZE]; /* 65bytes */
48 static size_t attestation_public_key_len = 0;
49 static psa_ecc_family_t attestation_key_curve;
50 
51 #ifdef INCLUDE_COSE_KEY_ID
52 static uint8_t attestation_key_id[PSA_HASH_SIZE(PSA_ALG_SHA_256)]; /* 32bytes */
53 #endif
54 
55 /* Instance ID for asymmetric IAK */
56 static uint8_t instance_id_buf[INSTANCE_ID_MAX_SIZE];
57 static size_t instance_id_len = 0U;
58 
61 {
62  enum tfm_plat_err_t plat_res;
63  psa_ecc_family_t psa_curve;
64  struct ecc_key_t attest_key = {0};
65  uint8_t key_buf[3 * ECC_P256_COORD_SIZE]; /* priv + x_coord + y_coord */
67  psa_status_t crypto_res;
68  psa_key_attributes_t key_attributes = psa_key_attributes_init();
69 
70  if (attestation_key_handle != ATTEST_KEY_HANDLE_NOT_LOADED) {
72  }
73 
74  /* Get the initial attestation key */
75  plat_res = tfm_plat_get_initial_attest_key(key_buf, sizeof(key_buf),
76  &attest_key, &psa_curve);
77 
78  /* Check the availability of the private key */
79  if (plat_res != TFM_PLAT_ERR_SUCCESS || attest_key.priv_key == NULL) {
81  }
82 
83  /* Setup the key policy for private key */
84  psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_SIGN);
85  psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
86  psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(psa_curve));
87 
88  /* Register private key to Crypto service */
89  crypto_res = psa_import_key(&key_attributes,
90  attest_key.priv_key,
91  attest_key.priv_key_size,
92  &key_handle);
93 
94 
95  if (crypto_res != PSA_SUCCESS) {
97  }
98 
99  attestation_key_handle = key_handle;
100 
101  /* If the public key length is 0 then it hasn't been loaded */
102  if (attestation_public_key_len == 0) {
103  crypto_res = psa_export_public_key(key_handle, attestation_public_key,
105  &attestation_public_key_len);
106  if (crypto_res != PSA_SUCCESS) {
107  return PSA_ATTEST_ERR_GENERAL;
108  }
109 
110  attestation_key_curve = psa_curve;
111  }
112 
113  return PSA_ATTEST_ERR_SUCCESS;
114 }
115 
116 enum psa_attest_err_t
118 {
119  psa_status_t crypto_res;
120 
121  if (attestation_key_handle == ATTEST_KEY_HANDLE_NOT_LOADED) {
122  return PSA_ATTEST_ERR_GENERAL;
123  }
124 
125  crypto_res = psa_destroy_key(attestation_key_handle);
126  if (crypto_res != PSA_SUCCESS) {
127  return PSA_ATTEST_ERR_GENERAL;
128  }
129 
130  attestation_key_handle = ATTEST_KEY_HANDLE_NOT_LOADED;
131 
132  return PSA_ATTEST_ERR_SUCCESS;
133 }
134 
135 enum psa_attest_err_t
137 {
138  if (attestation_key_handle == ATTEST_KEY_HANDLE_NOT_LOADED) {
139  return PSA_ATTEST_ERR_GENERAL;
140  }
141 
142  *handle = attestation_key_handle;
143 
144  return PSA_ATTEST_ERR_SUCCESS;
145 }
146 
147 enum psa_attest_err_t
149  size_t *public_key_len,
150  psa_ecc_family_t *public_key_curve)
151 {
152 
153  /* If the public key length is 0 then it hasn't been loaded */
154  if (attestation_public_key_len == 0) {
155  return PSA_ATTEST_ERR_GENERAL;
156  }
157 
158  *public_key = attestation_public_key;
159  *public_key_len = attestation_public_key_len;
160  *public_key_curve = attestation_key_curve;
161 
162  return PSA_ATTEST_ERR_SUCCESS;
163 }
164 
170 static enum psa_attest_err_t attest_calc_instance_id(void)
171 {
172  psa_status_t crypto_res;
173  enum psa_attest_err_t attest_res;
174  uint8_t *public_key;
175  size_t key_len;
176  psa_ecc_family_t psa_curve;
178 
179  attest_res = attest_get_initial_attestation_public_key(&public_key,
180  &key_len,
181  &psa_curve);
182  if (attest_res != PSA_ATTEST_ERR_SUCCESS) {
184  }
185 
186  crypto_res = psa_hash_setup(&hash, PSA_ALG_SHA_256);
187  if (crypto_res != PSA_SUCCESS) {
189  }
190 
191  crypto_res = psa_hash_update(&hash, public_key, key_len);
192  if (crypto_res != PSA_SUCCESS) {
194  }
195 
196  /* The hash starts from the second byte, leaving the first free. */
197  crypto_res = psa_hash_finish(&hash, instance_id_buf + 1,
198  INSTANCE_ID_MAX_SIZE - 1,
199  &instance_id_len);
200  if (crypto_res != PSA_SUCCESS) {
202  }
203 
204  /* Add UEID type byte 0x01 */
205  instance_id_buf[0] = 0x01;
206  instance_id_len = instance_id_len + 1;
207 
208  return PSA_ATTEST_ERR_SUCCESS;
209 }
210 
211 enum psa_attest_err_t
212 attest_get_instance_id(struct q_useful_buf_c *id_buf)
213 {
214  if (instance_id_len == 0U) {
215  if (attest_calc_instance_id() != PSA_ATTEST_ERR_SUCCESS) {
217  }
218  }
219 
220  if (id_buf == NULL) {
221  return PSA_ATTEST_ERR_GENERAL;
222  }
223 
224  id_buf->ptr = instance_id_buf;
225  id_buf->len = instance_id_len;
226 
227  return PSA_ATTEST_ERR_SUCCESS;
228 }
229 
230 #ifdef INCLUDE_COSE_KEY_ID
231 
232 #define MAX_ENCODED_COSE_KEY_SIZE \
233  1 + /* 1 byte to encode map */ \
234  2 + /* 2 bytes to encode key type */ \
235  2 + /* 2 bytes to encode curve */ \
236  2 * /* the X and Y coordinates at 32 bytes each */ \
237  (ECC_P256_COORD_SIZE + 1 + 2)
238 
248 static inline int32_t
249 attest_map_psa_ecc_curve_to_cose_ecc_curve(psa_ecc_family_t psa_curve)
250 {
251  int32_t cose_curve;
252 
253  /* Note: Mapping is not complete. */
254  switch (psa_curve) {
256  cose_curve = COSE_ELLIPTIC_CURVE_P_256;
257  break;
258  default:
259  /* Initial attestation currently supports only ECDSA P256 signature
260  * therefore the other options are not mapped to save object code
261  */
262  cose_curve = -1;
263  }
264 
265  return cose_curve;
266 }
267 
286 static enum psa_attest_err_t
287 attest_encode_key_to_cose_key(psa_ecc_family_t psa_ecc_curve,
288  struct q_useful_buf_c attest_public_key,
289  struct q_useful_buf buffer_for_cose_key,
290  struct q_useful_buf_c *cose_key)
291 {
292  QCBORError qcbor_result;
293  QCBOREncodeContext cbor_encode_ctx;
294  struct q_useful_buf_c x_coord;
295  struct q_useful_buf_c y_coord;
296  struct q_useful_buf_c encoded_key_id;
297  size_t key_coord_len;
298  int32_t cose_ecc_curve;
299  uint8_t *x_coord_ptr;
300  uint8_t *y_coord_ptr;
301  Q_USEFUL_BUF_MAKE_STACK_UB(buffer_for_x_coord, ECC_P256_COORD_SIZE);
302  Q_USEFUL_BUF_MAKE_STACK_UB(buffer_for_y_coord, ECC_P256_COORD_SIZE);
303 
304  /* Key is made up of a 0x4 byte and two coordinates
305  * 0x04 || X_COORD || Y_COORD
306  */
307  key_coord_len = (attest_public_key.len - 1) / 2;
308  x_coord_ptr = ((uint8_t *)attest_public_key.ptr) + 1;
309  y_coord_ptr = ((uint8_t *)attest_public_key.ptr) + 1 + key_coord_len;
310 
311  /* Place they key parts into the x and y buffers. Stars at index 1 to skip
312  * the 0x4 byte.
313  */
314  x_coord = q_useful_buf_copy_ptr(buffer_for_x_coord,
315  x_coord_ptr,
316  key_coord_len);
317 
318  y_coord = q_useful_buf_copy_ptr(buffer_for_y_coord,
319  y_coord_ptr,
320  key_coord_len);
321 
322  if (q_useful_buf_c_is_null(x_coord) || q_useful_buf_c_is_null(y_coord)) {
323  return PSA_ATTEST_ERR_GENERAL;
324  }
325 
326  cose_ecc_curve = attest_map_psa_ecc_curve_to_cose_ecc_curve(psa_ecc_curve);
327  if (cose_ecc_curve == -1) {
328  return PSA_ATTEST_ERR_GENERAL;
329  }
330 
331  /* Encode it into a COSE_Key structure */
332  QCBOREncode_Init(&cbor_encode_ctx, buffer_for_cose_key);
333  QCBOREncode_OpenMap(&cbor_encode_ctx);
334  QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx,
335  COSE_KEY_COMMON_KTY,
336  COSE_KEY_TYPE_EC2);
337  QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx,
338  COSE_KEY_PARAM_CRV,
339  cose_ecc_curve);
340  QCBOREncode_AddBytesToMapN(&cbor_encode_ctx,
341  COSE_KEY_PARAM_X_COORDINATE,
342  x_coord);
343  QCBOREncode_AddBytesToMapN(&cbor_encode_ctx,
344  COSE_KEY_PARAM_Y_COORDINATE,
345  y_coord);
346  QCBOREncode_CloseMap(&cbor_encode_ctx);
347 
348  qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &encoded_key_id);
349  if (qcbor_result != QCBOR_SUCCESS) {
350  /* Mainly means that the COSE_Key was too big for buffer_for_cose_key */
351  return PSA_ATTEST_ERR_GENERAL;
352  }
353 
354  /* Finish up and return */
355  *cose_key = encoded_key_id;
356 
357  return PSA_ATTEST_ERR_SUCCESS;
358 }
359 
375 enum psa_attest_err_t
376 attest_get_cose_key_id(psa_ecc_family_t psa_ecc_curve,
377  struct q_useful_buf_c attest_public_key,
378  struct q_useful_buf buffer_for_attest_key_id,
379  struct q_useful_buf_c *attest_key_id)
380 {
381  enum psa_attest_err_t attest_res;
382  psa_status_t crypto_res;
383  struct q_useful_buf_c cose_key;
385  Q_USEFUL_BUF_MAKE_STACK_UB(buffer_for_cose_key, MAX_ENCODED_COSE_KEY_SIZE);
386 
387  /* Encode the attestation public key to COSE_Key structure */
388  attest_res = attest_encode_key_to_cose_key(psa_ecc_curve,
389  attest_public_key,
390  buffer_for_cose_key,
391  &cose_key);
392  if(attest_res != PSA_ATTEST_ERR_SUCCESS) {
393  return attest_res;
394  }
395 
396  crypto_res = psa_hash_setup(&hash, PSA_ALG_SHA_256);
397  if (crypto_res != PSA_SUCCESS) {
398  return PSA_ATTEST_ERR_GENERAL;
399  }
400 
401  crypto_res = psa_hash_update(&hash, cose_key.ptr, cose_key.len);
402  if (crypto_res != PSA_SUCCESS) {
403  return PSA_ATTEST_ERR_GENERAL;
404  }
405 
406  crypto_res = psa_hash_finish(&hash,
407  buffer_for_attest_key_id.ptr,
408  buffer_for_attest_key_id.len,
409  &buffer_for_attest_key_id.len);
410  if (crypto_res != PSA_SUCCESS) {
411  return PSA_ATTEST_ERR_GENERAL;
412  }
413 
414  attest_key_id->ptr = buffer_for_attest_key_id.ptr;
415  attest_key_id->len = buffer_for_attest_key_id.len;
416 
417  return PSA_ATTEST_ERR_SUCCESS;
418 }
419 
420 enum psa_attest_err_t
421 attest_get_initial_attestation_key_id(struct q_useful_buf_c *attest_key_id)
422 {
423  enum psa_attest_err_t attest_res;
424  static uint8_t attest_key_id_calculated;
425  struct q_useful_buf_c buffer_for_attest_public_key;
426  struct q_useful_buf buffer_for_attest_key_id;
427 
428  buffer_for_attest_key_id.ptr = attestation_key_id;
429  buffer_for_attest_key_id.len = PSA_HASH_SIZE(PSA_ALG_SHA_256);
430 
431  /* Needs to calculate only once */
432  if (attest_key_id_calculated == 0) {
433  buffer_for_attest_public_key.ptr = attestation_public_key;
434  buffer_for_attest_public_key.len = attestation_public_key_len;
435 
436  attest_res = attest_get_cose_key_id(attestation_key_curve,
437  buffer_for_attest_public_key,
438  buffer_for_attest_key_id,
439  attest_key_id);
440  if (attest_res != PSA_ATTEST_ERR_SUCCESS) {
441  return attest_res;
442  }
443  attest_key_id_calculated = 1;
444  } else {
445  attest_key_id->ptr = (const void *)buffer_for_attest_key_id.ptr;
446  attest_key_id->len = buffer_for_attest_key_id.len;
447  }
448 
449  return PSA_ATTEST_ERR_SUCCESS;
450 }
451 #endif /* INCLUDE_COSE_KEY_ID */
enum psa_attest_err_t attest_register_initial_attestation_key()
Register the initial attestation private key to Crypto service. Loads the public key if the key has n...
#define PSA_HASH_SIZE(alg)
Definition: crypto_sizes.h:53
#define psa_hash_setup
Definition: crypto_spe.h:89
#define PSA_SUCCESS
Definition: crypto_values.h:35
#define ECC_P256_PUBLIC_KEY_SIZE
psa_attest_err_t
Initial attestation service error types.
Definition: attest.h:25
enum psa_attest_err_t attest_unregister_initial_attestation_key()
Unregister the initial attestation private key from Crypto service to do not occupy key slot...
#define psa_hash_finish
Definition: crypto_spe.h:93
enum psa_attest_err_t attest_get_initial_attestation_public_key(uint8_t **public_key, size_t *public_key_len, psa_ecc_family_t *public_key_curve)
Get the public key derived from the initial attestation private key.
#define PSA_ALG_SHA_256
#define ATTEST_KEY_HANDLE_NOT_LOADED
#define psa_import_key
Definition: crypto_spe.h:57
#define psa_hash_update
Definition: crypto_spe.h:91
#define PSA_ECC_CURVE_SECP256R1
#define PSA_KEY_TYPE_ECC_KEY_PAIR(curve)
#define PSA_KEY_USAGE_SIGN
Definition: crypto_compat.h:69
#define psa_export_public_key
Definition: crypto_spe.h:67
enum psa_attest_err_t attest_get_signing_key_handle(psa_key_handle_t *handle)
Get the handle of the key for signing token In asymmetric key algorithm based initial attestation...
#define ECC_P256_COORD_SIZE
_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_ALG_ECDSA(hash_alg)
#define psa_destroy_key
Definition: crypto_spe.h:59
enum psa_attest_err_t attest_get_instance_id(struct q_useful_buf_c *id_buf)
Get the buffer of Instance ID data.
uint8_t psa_ecc_family_t
Definition: crypto_types.h:69
int32_t psa_status_t
Function return status.
Definition: crypto_types.h:43