1 /*
2  * Copyright (c) 2019,2020 Linaro Limited
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdio.h>
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/logging/log_ctrl.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/data/json.h>
13 
14 #include "mbedtls/pk.h"
15 #include "mbedtls/x509.h"
16 #include "mbedtls/x509_csr.h"
17 
18 #include "psa_crypto.h"
19 #include "util_app_log.h"
20 #include "util_sformat.h"
21 
22 /** Declare a reference to the application logging interface. */
23 LOG_MODULE_DECLARE(app, CONFIG_LOG_DEFAULT_LEVEL);
24 
25 /* Formatting details for displaying hex dumps. */
26 struct sf_hex_tbl_fmt crp_fmt = {
27 	.ascii = true,
28 	.addr_label = true,
29 	.addr = 0
30 };
31 
32 struct csr_json_struct {
33 	const char *CSR;
34 };
35 
36 static const struct json_obj_descr csr_json_descr[] = {
37 	JSON_OBJ_DESCR_PRIM(struct csr_json_struct, CSR, JSON_TOK_STRING)
38 };
39 
40 /**
41  * @brief Extracts the public key from the specified persistent key id.
42  *
43  * @param key_id        The permanent identifier for the generated key.
44  * @param key           Pointer to the buffer where the public key data
45  *                      will be written.
46  * @param key_buf_size  Size of key buffer in bytes.
47  * @param key_len       Number of bytes written into key by this function.
48  */
crp_get_pub_key(psa_key_id_t key_id,uint8_t * key,size_t key_buf_size,size_t * key_len)49 static psa_status_t crp_get_pub_key(psa_key_id_t key_id,
50 				    uint8_t *key, size_t key_buf_size,
51 				    size_t *key_len)
52 {
53 	psa_status_t status;
54 	psa_key_handle_t key_handle;
55 
56 	LOG_INF("Retrieving public key for key #%d", key_id);
57 	al_dump_log();
58 
59 	/* Now try to re-open the persisted key based on the key ID. */
60 	status = al_psa_status(
61 		psa_open_key(key_id, &key_handle),
62 		__func__);
63 	if (status != PSA_SUCCESS) {
64 		LOG_ERR("Failed to open persistent key #%d", key_id);
65 		goto err;
66 	}
67 
68 	/* Export the persistent key's public key part. */
69 	status = al_psa_status(
70 		psa_export_public_key(key_handle, key, key_buf_size, key_len),
71 		__func__);
72 	if (status != PSA_SUCCESS) {
73 		LOG_ERR("Failed to export public key.");
74 		goto err;
75 	}
76 
77 	/* Display the binary key data for debug purposes. */
78 	sf_hex_tabulate_16(&crp_fmt, key, *key_len);
79 
80 	/* Close the key to free up the volatile slot. */
81 	status = al_psa_status(
82 		psa_close_key(key_handle),
83 		__func__);
84 	if (status != PSA_SUCCESS) {
85 		LOG_ERR("Failed to close persistent key.");
86 		goto err;
87 	}
88 
89 	return status;
90 err:
91 	al_dump_log();
92 	return status;
93 }
94 
95 #if CONFIG_PSA_IMPORT_KEY
96 /**
97  * @brief Stores a new persistent secp256r1 key (usage: ecdsa-with-SHA256)
98  *        in ITS, associating it with the specified unique key identifier.
99  *
100  * This function will store a new persistent secp256r1 key in internal trusted
101  * storage. Cryptographic operations can then be performed using the key
102  * identifier (key_id) associated with this persistent key. Only the 32-byte
103  * private key needs to be supplied, the public key can be derived using
104  * the supplied private key value.
105  *
106  * @param key_id        The permament identifier for the generated key.
107  * @param key_usage     The usage policy for the key.
108  * @param key_data      Pointer to the 32-byte private key data.
109  */
crp_imp_key_secp256r1(psa_key_id_t key_id,psa_key_usage_t key_usage,uint8_t * key_data)110 static psa_status_t crp_imp_key_secp256r1(psa_key_id_t key_id,
111 					  psa_key_usage_t key_usage,
112 					  uint8_t *key_data)
113 {
114 	psa_status_t status = PSA_SUCCESS;
115 	psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
116 	psa_key_type_t key_type =
117 		PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
118 	psa_algorithm_t alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256);
119 	psa_key_handle_t key_handle;
120 	size_t key_len = 32;
121 	size_t data_len;
122 	uint8_t data_out[65] = { 0 }; /* ECDSA public key = 65 bytes. */
123 	int comp_result;
124 
125 	LOG_INF("Persisting SECP256R1 key as #%d", (uint32_t)key_id);
126 	al_dump_log();
127 
128 	/* Setup the key's attributes before the creation request. */
129 	psa_set_key_id(&key_attributes, key_id);
130 	psa_set_key_usage_flags(&key_attributes, key_usage);
131 	psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT);
132 	psa_set_key_algorithm(&key_attributes, alg);
133 	psa_set_key_type(&key_attributes, key_type);
134 
135 	/* Import the private key, creating the persistent key on success */
136 	status = al_psa_status(
137 		psa_import_key(&key_attributes, key_data, key_len, &key_handle),
138 		__func__);
139 	if (status != PSA_SUCCESS) {
140 		LOG_ERR("Failed to import key.");
141 		goto err;
142 	}
143 
144 	/* Close the key to free up the volatile slot. */
145 	status = al_psa_status(
146 		psa_close_key(key_handle),
147 		__func__);
148 	if (status != PSA_SUCCESS) {
149 		LOG_ERR("Failed to close persistent key.");
150 		goto err;
151 	}
152 
153 	/* Try to retrieve the public key. */
154 	status = crp_get_pub_key(key_id, data_out, sizeof(data_out), &data_len);
155 
156 	/* Export the private key if usage includes PSA_KEY_USAGE_EXPORT. */
157 	if (key_usage & PSA_KEY_USAGE_EXPORT) {
158 		/* Re-open the persisted key based on the key ID. */
159 		status = al_psa_status(
160 			psa_open_key(key_id, &key_handle),
161 			__func__);
162 		if (status != PSA_SUCCESS) {
163 			LOG_ERR("Failed to open persistent key #%d", key_id);
164 			goto err;
165 		}
166 
167 		/* Read the original (private) key data back. */
168 		status = al_psa_status(
169 			psa_export_key(key_handle, data_out,
170 				       sizeof(data_out), &data_len),
171 			__func__);
172 		if (status != PSA_SUCCESS) {
173 			LOG_ERR("Failed to export key.");
174 			goto err;
175 		}
176 
177 		/* Check key len. */
178 		if (data_len != key_len) {
179 			LOG_ERR("Unexpected number of bytes in exported key.");
180 			goto err;
181 		}
182 
183 		/* Verify that the exported private key matches input data. */
184 		comp_result = memcmp(data_out, key_data, key_len);
185 		if (comp_result != 0) {
186 			LOG_ERR("Imported/exported private key mismatch.");
187 			goto err;
188 		}
189 
190 		/* Display the private key. */
191 		LOG_INF("Private key data:");
192 		al_dump_log();
193 		sf_hex_tabulate_16(&crp_fmt, data_out, data_len);
194 
195 		/* Close the key to free up the volatile slot. */
196 		status = al_psa_status(
197 			psa_close_key(key_handle),
198 			__func__);
199 		if (status != PSA_SUCCESS) {
200 			LOG_ERR("Failed to close persistent key.");
201 			goto err;
202 		}
203 	}
204 
205 	return status;
206 err:
207 	al_dump_log();
208 	return status;
209 }
210 
211 #else /* !CONFIG_PSA_IMPORT_KEY */
212 /**
213  * @brief Generates a new permanent, persistent prime256v1 (ecdsa-with-SHA256)
214  *        key in ITS, associating it with the specified unique key identifier.
215  *
216  * This function will generate a new permanent prime256v1 key in internal trusted
217  * storage. Cryptographic operations can then be performed using the key
218  * identifier (key_id) associated with this persistent key.
219  *
220  * @param key_id        The permanent identifier for the generated key.
221  * @param key_usage     The usage policy for the key.
222  */
crp_gen_key_secp256r1(psa_key_id_t key_id,psa_key_usage_t key_usage)223 static psa_status_t crp_gen_key_secp256r1(psa_key_id_t key_id,
224 					  psa_key_usage_t key_usage)
225 {
226 	psa_status_t status = PSA_SUCCESS;
227 	psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
228 	psa_key_type_t key_type =
229 		PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
230 	psa_algorithm_t alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256);
231 	psa_key_handle_t key_handle;
232 	size_t key_len = 32;
233 	size_t data_len;
234 	uint8_t data_out[65] = { 0 }; /* ECDSA public key = 65 bytes. */
235 
236 	LOG_INF("Persisting SECP256R1 key as #%d", (uint32_t)key_id);
237 	al_dump_log();
238 
239 	/* Setup the key's attributes before the creation request. */
240 	psa_set_key_id(&key_attributes, key_id);
241 	psa_set_key_usage_flags(&key_attributes, key_usage);
242 	psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT);
243 	psa_set_key_algorithm(&key_attributes, alg);
244 	psa_set_key_type(&key_attributes, key_type);
245 	psa_set_key_bits(&key_attributes, 256);
246 
247 	/* Generate the private key, creating the persistent key on success */
248 	status = al_psa_status(
249 		psa_generate_key(&key_attributes, &key_handle),
250 		__func__);
251 	if (status != PSA_SUCCESS) {
252 		LOG_ERR("Failed to generate key.");
253 		goto err;
254 	}
255 
256 	/* Close the key to free up the volatile slot. */
257 	status = al_psa_status(
258 		psa_close_key(key_handle),
259 		__func__);
260 	if (status != PSA_SUCCESS) {
261 		LOG_ERR("Failed to close persistent key.");
262 		goto err;
263 	}
264 
265 	/* Try to retrieve the public key. */
266 	status = crp_get_pub_key(key_id, data_out, sizeof(data_out), &data_len);
267 
268 	/* Export the private key if usage includes PSA_KEY_USAGE_EXPORT. */
269 	if (key_usage & PSA_KEY_USAGE_EXPORT) {
270 		/* Re-open the persisted key based on the key ID. */
271 		status = al_psa_status(
272 			psa_open_key(key_id, &key_handle),
273 			__func__);
274 		if (status != PSA_SUCCESS) {
275 			LOG_ERR("Failed to open persistent key #%d", key_id);
276 			goto err;
277 		}
278 
279 		/* Read the original (private) key data back. */
280 		status = al_psa_status(
281 			psa_export_key(key_handle, data_out,
282 				       sizeof(data_out), &data_len),
283 			__func__);
284 		if (status != PSA_SUCCESS) {
285 			LOG_ERR("Failed to export key.");
286 			goto err;
287 		}
288 
289 		/* Check key len. */
290 		if (data_len != key_len) {
291 			LOG_ERR("Unexpected number of bytes in exported key.");
292 			goto err;
293 		}
294 
295 		/* Display the private key. */
296 		LOG_INF("Private key data:");
297 		al_dump_log();
298 
299 		sf_hex_tabulate_16(&crp_fmt, data_out, data_len);
300 
301 		/* Close the key to free up the volatile slot. */
302 		status = al_psa_status(
303 			psa_close_key(key_handle),
304 			__func__);
305 		if (status != PSA_SUCCESS) {
306 			LOG_ERR("Failed to close persistent key.");
307 			goto err;
308 		}
309 	}
310 
311 	return status;
312 err:
313 	al_dump_log();
314 	return status;
315 }
316 #endif /* CONFIG_PSA_IMPORT_KEY */
317 
318 /**
319  * @brief PSA Random number generator wrapper for Mbed TLS
320  */
psa_rng_for_mbedtls(void * p_rng,unsigned char * output,size_t output_len)321 static int psa_rng_for_mbedtls(void *p_rng,
322 			       unsigned char *output, size_t output_len)
323 {
324 	(void)p_rng;
325 
326 	return psa_generate_random(output, output_len);
327 }
328 
329 /**
330  * @brief Generates device certificate signing request (CSR) using Mbed TLS
331  * X.509 and TF-M crypto service.
332  */
crp_generate_csr(void)333 void crp_generate_csr(void)
334 {
335 	psa_status_t status;
336 	psa_key_id_t key_slot = 1;
337 	psa_key_handle_t key_handle;
338 
339 	unsigned char output_buf[1024];
340 	unsigned char json_encoded_buf[1024];
341 
342 	mbedtls_pk_context pk_key_container;
343 	mbedtls_x509write_csr req;
344 
345 	struct csr_json_struct csr_json = {
346 		.CSR = output_buf
347 	};
348 
349 	/* Initialize Mbed TLS structures. */
350 	mbedtls_x509write_csr_init(&req);
351 	mbedtls_pk_init(&pk_key_container);
352 	memset(output_buf, 0, sizeof(output_buf));
353 
354 	/* Initialize crypto API. */
355 	LOG_INF("Initialising PSA crypto");
356 	al_dump_log();
357 
358 	status = al_psa_status(psa_crypto_init(), __func__);
359 	if (status != PSA_SUCCESS) {
360 		LOG_ERR("Crypto init failed.");
361 		goto err;
362 	}
363 
364 	LOG_INF("PSA crypto init completed");
365 	al_dump_log();
366 
367 	/* prime256v1 (ecdsa-with-SHA256) private key. */
368 #if CONFIG_PSA_IMPORT_KEY
369 #if CONFIG_PRIVATE_KEY_STATIC
370 	/* This value is based on the private key in user.pem,
371 	 * which can be viewed viw the following command:
372 	 *
373 	 *   $ openssl ec -in user.pem -text -noout
374 	 */
375 	uint8_t priv_key_data[32] = {
376 		0x14, 0xbc, 0xb9, 0x53, 0xa4, 0xee, 0xed, 0x50,
377 		0x09, 0x36, 0x92, 0x07, 0x1d, 0xdb, 0x24, 0x2c,
378 		0xef, 0xf9, 0x57, 0x92, 0x40, 0x4f, 0x49, 0xaa,
379 		0xd0, 0x7c, 0x5b, 0x3f, 0x26, 0xa7, 0x80, 0x48
380 	};
381 #else /* !CONFIG_PRIVATE_KEY_STATIC */
382 	/* Randomly generate the private key. */
383 	uint8_t priv_key_data[32] = { 0 };
384 
385 	LOG_INF("Generate rnadom data for private key");
386 	al_dump_log();
387 
388 	psa_generate_random(priv_key_data, sizeof(priv_key_data));
389 	LOG_INF("Random data generation for private key completed");
390 	al_dump_log();
391 
392 #endif /* CONFIG_PRIVATE_KEY_STATIC */
393 
394 	/* Generate persistent prime256v1 (ecdsa-with-SHA256) key w/ID #1. */
395 	/* PSA_KEY_USAGE_EXPORT can be added for debug purposes. */
396 	status = al_psa_status(
397 		crp_imp_key_secp256r1(key_slot,
398 				      PSA_KEY_USAGE_SIGN_HASH |
399 				      PSA_KEY_USAGE_VERIFY_HASH,
400 				      priv_key_data),
401 		__func__);
402 	if (status != PSA_SUCCESS) {
403 		LOG_ERR("Failed to create persistent key #%d", key_slot);
404 		goto err;
405 	}
406 #else /* !CONFIG_PSA_IMPORT_KEY */
407 
408 	/* NOTE: The certificate signing request (CSR) can be generated using
409 	 * openssl by using following commands:
410 	 *
411 	 * Generate a new key:
412 	 *
413 	 *   $ openssl ecparam -name secp256k1 -genkey -out USER.key
414 	 *
415 	 * Generate a certificate signing request, containing the user public key
416 	 * and required details to be inserted into the user certificate.
417 	 * openssl req -new -key USER.key -out USER.csr \
418 	 *   -subj "/O=Linaro/CN=$(uuidgen | tr '[:upper:]' '[:lower:]')"
419 	 *
420 	 */
421 
422 	/* Generate persistent prime256v1 (ecdsa-with-SHA256) key w/ID #1. */
423 	/* PSA_KEY_USAGE_EXPORT can be added for debug purposes. */
424 	status = al_psa_status(
425 		crp_gen_key_secp256r1(key_slot,
426 				      PSA_KEY_USAGE_SIGN_HASH |
427 				      PSA_KEY_USAGE_VERIFY_HASH),
428 		__func__);
429 	if (status != PSA_SUCCESS) {
430 		LOG_ERR("Failed to create persistent key #%d", key_slot);
431 		goto err;
432 	}
433 #endif /* CONFIG_PSA_IMPORT_KEY */
434 
435 	status = al_psa_status(
436 		psa_open_key(key_slot, &key_handle),
437 		__func__);
438 	if (status != PSA_SUCCESS) {
439 		LOG_ERR("Failed to open persistent key #%d", key_slot);
440 		goto err;
441 	}
442 
443 	psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
444 
445 	psa_get_key_attributes(key_handle, &attributes);
446 	mbedtls_x509write_csr_set_md_alg(&req, MBEDTLS_MD_SHA256);
447 
448 	LOG_INF("Adding subject name to CSR");
449 	al_dump_log();
450 
451 	status = mbedtls_x509write_csr_set_subject_name(&req, "O=Linaro,CN=Device Certificate");
452 	if (status != 0) {
453 		LOG_ERR("failed! mbedtls_x509write_csr_set_subject_name returned %d", status);
454 		goto err;
455 	}
456 
457 	LOG_INF("Adding subject name to CSR completed");
458 	al_dump_log();
459 
460 	LOG_INF("Adding EC key to PK container");
461 	al_dump_log();
462 
463 	status = mbedtls_pk_setup_opaque(&pk_key_container, key_handle);
464 	if (status != 0) {
465 		LOG_ERR("failed! mbedtls_pk_setup_opaque returned -0x%04x", (unsigned int) -status);
466 		goto err;
467 	}
468 
469 	LOG_INF("Adding EC key to PK container completed");
470 	al_dump_log();
471 
472 	mbedtls_x509write_csr_set_key(&req, &pk_key_container);
473 
474 	LOG_INF("Create device Certificate Signing Request");
475 	al_dump_log();
476 
477 	status = mbedtls_x509write_csr_pem(&req, output_buf, sizeof(output_buf),
478 					   psa_rng_for_mbedtls, NULL);
479 	if (status < 0) {
480 		LOG_ERR("failed! mbedtls_x509write_csr_pem returned -0x%04x",
481 			(unsigned int) -status);
482 		goto err;
483 	}
484 
485 	LOG_INF("Create device Certificate Signing Request completed");
486 	al_dump_log();
487 
488 	LOG_INF("Certificate Signing Request:\n");
489 	al_dump_log();
490 
491 	printf("%s\n", output_buf);
492 
493 	/*
494 	 * 1.3. Encoding CSR as JSON
495 	 */
496 	LOG_INF("Encoding CSR as json");
497 	al_dump_log();
498 
499 	status = json_obj_encode_buf(csr_json_descr, ARRAY_SIZE(csr_json_descr),
500 				     &csr_json, json_encoded_buf, sizeof(json_encoded_buf));
501 
502 	if (status != 0) {
503 		LOG_ERR("failed! json_obj_encode_buf returned 0x%04x", status);
504 		goto err;
505 	}
506 
507 	LOG_INF("Encoding CSR as json completed");
508 	al_dump_log();
509 
510 	LOG_INF("Certificate Signing Request in JSON:\n");
511 	al_dump_log();
512 
513 	printf("%s\n\n", json_encoded_buf);
514 
515 	/* Close the key to free up the volatile slot. */
516 	status = al_psa_status(
517 		psa_close_key(key_handle),
518 		__func__);
519 	if (status != PSA_SUCCESS) {
520 		LOG_ERR("Failed to close persistent key.");
521 		goto err;
522 	}
523 
524 err:
525 	al_dump_log();
526 	mbedtls_x509write_csr_free(&req);
527 	mbedtls_pk_free(&pk_key_container);
528 }
529 
530 /**
531  * @brief Calculates the SHA256 hash for the supplied message.
532  *
533  * @param msg           Pointer to the buffer to read when generating the hash.
534  * @param msg_len       Number of bytes in msg.
535  * @param hash          Pointer to the buffer where the hash should be written.
536  * @param hash_buf_size Size of hash in bytes.
537  * @param hash_len      Placeholder for the number of hash bytes written.
538  */
crp_hash_payload(uint8_t * msg,size_t msg_len,uint8_t * hash,size_t hash_buf_size,size_t * hash_len)539 static psa_status_t crp_hash_payload(uint8_t *msg, size_t msg_len,
540 				     uint8_t *hash, size_t hash_buf_size,
541 				     size_t *hash_len)
542 {
543 	psa_status_t status;
544 	psa_hash_operation_t hash_handle = psa_hash_operation_init();
545 	psa_algorithm_t alg = PSA_ALG_SHA_256;
546 
547 	LOG_INF("Calculating SHA-256 hash of value");
548 	al_dump_log();
549 
550 	/* Display the input message */
551 	sf_hex_tabulate_16(&crp_fmt, msg, msg_len);
552 
553 	/* Setup the hash object. */
554 	status = al_psa_status(psa_hash_setup(&hash_handle, alg),
555 			       __func__);
556 	if (status != PSA_SUCCESS) {
557 		LOG_ERR("Failed to setup hash op.");
558 		goto err;
559 	}
560 
561 	/* Update object with all the message chunks. */
562 	/* For the moment, the message is passed in a single operation, */
563 	/* but this can be broken up in chunks for larger messages. */
564 	status = al_psa_status(psa_hash_update(&hash_handle, msg, msg_len),
565 			       __func__);
566 	if (status != PSA_SUCCESS) {
567 		LOG_ERR("Failed to update hash.");
568 		goto err;
569 	}
570 
571 	/* Finalize the hash calculation. */
572 	status = al_psa_status(psa_hash_finish(&hash_handle,
573 					       hash, hash_buf_size, hash_len),
574 			       __func__);
575 	if (status != PSA_SUCCESS) {
576 		LOG_ERR("Failed to finalize hash op.");
577 		goto err;
578 	}
579 
580 	/* Display the SHA-256 hash for debug purposes */
581 	sf_hex_tabulate_16(&crp_fmt, hash, (size_t)(PSA_HASH_MAX_SIZE));
582 
583 	return status;
584 err:
585 	psa_hash_abort(&hash_handle);
586 	al_dump_log();
587 	return status;
588 }
589 
590 /**
591  * @brief Signs the supplied hash using the specified persistent key.
592  *
593  * @param key_id        The identifier of the key to use when signing.
594  * @param hash          Pointer to the buffer where the hash should be written.
595  * @param hash_buf_size Size of hash in bytes.
596  * @param sig           Pointer to the buffer to read when generating the sig.
597  * @param sig_buf_size  Size of sig buffer in bytes.
598  * @param sig_len       Number of bytes written to sig.
599  */
crp_sign_hash(psa_key_id_t key_id,uint8_t * hash,size_t hash_buf_size,uint8_t * sig,size_t sig_buf_size,size_t * sig_len)600 static psa_status_t crp_sign_hash(psa_key_id_t key_id,
601 				  uint8_t *hash, size_t hash_buf_size,
602 				  uint8_t *sig, size_t sig_buf_size,
603 				  size_t *sig_len)
604 {
605 	psa_status_t status;
606 	psa_key_handle_t key_handle;
607 
608 	LOG_INF("Signing SHA-256 hash");
609 	al_dump_log();
610 
611 	/* Try to open the persisted key based on the key ID. */
612 	status = al_psa_status(
613 		psa_open_key(key_id, &key_handle),
614 		__func__);
615 	if (status != PSA_SUCCESS) {
616 		LOG_ERR("Failed to open persistent key #%d", key_id);
617 		goto err;
618 	}
619 
620 	/* Sign using psa_sign_hash. */
621 	status = al_psa_status(
622 		psa_sign_hash(key_handle,
623 			      PSA_ALG_ECDSA(PSA_ALG_SHA_256),
624 			      hash, hash_buf_size,
625 			      sig, sig_buf_size, sig_len),
626 		__func__);
627 	if (status != PSA_SUCCESS) {
628 		LOG_ERR("Failed to sign hash w/persistent key #%d", key_id);
629 		goto err;
630 	}
631 
632 	/* Display the ECDSA signature for debug purposes */
633 	sf_hex_tabulate_16(&crp_fmt, sig, *sig_len);
634 
635 	/* You can test this same operation with openssl as follows:
636 	 *
637 	 * $ openssl dgst -sha256 -sign
638 	 */
639 
640 	/* Close the key to free up the volatile slot. */
641 	status = al_psa_status(
642 		psa_close_key(key_handle),
643 		__func__);
644 	if (status != PSA_SUCCESS) {
645 		LOG_ERR("Failed to close persistent key.");
646 		goto err;
647 	}
648 
649 	return status;
650 err:
651 	al_dump_log();
652 	return status;
653 }
654 
655 /**
656  * @brief Verifies the hash signature using the public key associated
657  *        with key_id.
658  *
659  * @param key_id        The identifier for the persistent key.
660  * @param hash          Pointer to the hash data to verify.
661  * @param hash_len      Size of the hash buffer in bytes.
662  * @param sig           Pointer to the signature buffer.
663  * @param sig_len       Size of the signature buffer in bytes.
664  */
crp_verify_sign(psa_key_id_t key_id,uint8_t * hash,size_t hash_len,uint8_t * sig,size_t sig_len)665 static psa_status_t crp_verify_sign(psa_key_id_t key_id,
666 				    uint8_t *hash, size_t hash_len,
667 				    uint8_t *sig, size_t sig_len)
668 {
669 	psa_status_t status;
670 	psa_key_handle_t key_handle;
671 
672 	LOG_INF("Verifying signature for SHA-256 hash");
673 	al_dump_log();
674 
675 	/* Try to open the persisted key based on the key ID. */
676 	status = al_psa_status(
677 		psa_open_key(key_id, &key_handle),
678 		__func__);
679 	if (status != PSA_SUCCESS) {
680 		LOG_ERR("Failed to open persistent key #%d", key_id);
681 		goto err;
682 	}
683 
684 	/* Verify the hash signature. */
685 	status = al_psa_status(
686 		psa_verify_hash(key_handle,
687 				PSA_ALG_ECDSA(PSA_ALG_SHA_256),
688 				hash, hash_len,
689 				sig, sig_len),
690 		__func__);
691 	if (status != PSA_SUCCESS) {
692 		LOG_ERR("Signature verification failed!");
693 		goto err;
694 	}
695 
696 	LOG_INF("Signature verified.");
697 	al_dump_log();
698 
699 	/* Close the key to free up the volatile slot. */
700 	status = al_psa_status(
701 		psa_close_key(key_handle),
702 		__func__);
703 	if (status != PSA_SUCCESS) {
704 		LOG_ERR("Failed to close persistent key.");
705 		goto err;
706 	}
707 
708 	return status;
709 err:
710 	al_dump_log();
711 	return status;
712 }
713 
714 /**
715  * @brief Destroys the specified persistent key.
716  *
717  * @param key_id        The identifier for the persistent key.
718  */
crp_dest_key(psa_key_id_t key_id)719 static psa_status_t crp_dest_key(psa_key_id_t key_id)
720 {
721 	psa_status_t status;
722 	psa_key_handle_t key_handle;
723 
724 	/* Try to open the persisted key based on the key ID. */
725 	status = al_psa_status(
726 		psa_open_key(key_id, &key_handle),
727 		__func__);
728 	if (status != PSA_SUCCESS) {
729 		LOG_ERR("Failed to open persistent key #%d", key_id);
730 		goto err;
731 	}
732 
733 	/* Destroy the persistent key */
734 	status = al_psa_status(
735 		psa_destroy_key(key_handle),
736 		__func__);
737 	if (status != PSA_SUCCESS) {
738 		LOG_ERR("Failed to destroy a persistent key");
739 		goto err;
740 	}
741 
742 	LOG_INF("Destroyed persistent key #%d", (uint32_t)key_id);
743 	al_dump_log();
744 
745 	return status;
746 err:
747 	al_dump_log();
748 	return status;
749 }
750 
crp_test(void)751 void crp_test(void)
752 {
753 	psa_status_t status;
754 	uint8_t msg[] = "Please hash and sign this message.";
755 	uint8_t hash[PSA_HASH_MAX_SIZE] = { 0 };
756 	size_t hash_len;
757 	uint8_t sig[PSA_VENDOR_ECDSA_SIGNATURE_MAX_SIZE] = { 0 };
758 	size_t sig_len;
759 
760 	/* secp256r1 private key. */
761 #if CONFIG_PSA_IMPORT_KEY
762 #if CONFIG_PRIVATE_KEY_STATIC
763 	/* This value is based on the private key in user.pem,
764 	 * which can be viewed viw the following command:
765 	 *
766 	 *   $ openssl ec -in user.pem -text -noout
767 	 */
768 	uint8_t priv_key_data[32] = {
769 		0x14, 0xbc, 0xb9, 0x53, 0xa4, 0xee, 0xed, 0x50,
770 		0x09, 0x36, 0x92, 0x07, 0x1d, 0xdb, 0x24, 0x2c,
771 		0xef, 0xf9, 0x57, 0x92, 0x40, 0x4f, 0x49, 0xaa,
772 		0xd0, 0x7c, 0x5b, 0x3f, 0x26, 0xa7, 0x80, 0x48
773 	};
774 #else /* !CONFIG_PRIVATE_KEY_STATIC */
775 	/* Randomly generate the private key. */
776 	uint8_t priv_key_data[32] = { 0 };
777 
778 	psa_generate_random(priv_key_data, sizeof(priv_key_data));
779 #endif  /* CONFIG_PRIVATE_KEY_STATIC */
780 #endif  /* CONFIG_PSA_IMPORT_KEY */
781 
782 	/* Initialize crypto API. */
783 	status = al_psa_status(psa_crypto_init(), __func__);
784 	if (status != PSA_SUCCESS) {
785 		LOG_ERR("Crypto init failed.");
786 		return;
787 	}
788 
789 	/* NOTE: The same key generation, SHA256 hash, sign, and verify
790 	 * operations performed in this file can be also performed with
791 	 * openssl using the commands described below.
792 	 *
793 	 * Generate a new key:
794 	 *
795 	 *   The curve `prime256v1` is same as `secp256r1` in OpenSSL
796 	 *   (https://github.com/openssl/openssl/blob/master/apps/ecparam.c#L216)
797 	 *   $ openssl ecparam -name prime256v1 -genkey -out user.pem
798 	 *
799 	 * Display the public and private keys in hexadecimal format:
800 	 *
801 	 *   $ openssl ec -in user.pem -text -noout
802 	 *
803 	 * Update the private key value in priv_key_data with the hexadecimal
804 	 * values from "priv:" to be able to compare the PSA API and openssl
805 	 * output.
806 	 *
807 	 * Generate a PEM file with the public key (which will be used to
808 	 * verify any data signed with the private key):
809 	 *
810 	 *   $ openssl ec -in user.pem -pubout -out user_pub.pem
811 	 *
812 	 * Hash the message with SHA256, and sign it with the private key:
813 	 *
814 	 *   $ echo "Please hash and sign this message." > message.txt
815 	 *   $ openssl dgst -sha256 -sign user.pem message.txt > signature.der
816 	 *
817 	 * Verify the signature using the public key and message file:
818 	 *
819 	 *   $ openssl dgst -sha256 -verify user_pub.pem \
820 	 *     -signature signature.der message.txt
821 	 *
822 	 * If everything ws OK you should see "Verified OK".
823 	 */
824 
825 	/* Generate persistent secp256r1 key w/ID #1. */
826 	/* PSA_KEY_USAGE_EXPORT can be added for debug purposes. */
827 #if CONFIG_PSA_IMPORT_KEY
828 	status = crp_imp_key_secp256r1(1,
829 				       PSA_KEY_USAGE_SIGN_HASH |
830 				       PSA_KEY_USAGE_VERIFY_HASH,
831 				       priv_key_data);
832 #else /* !CONFIG_PSA_IMPORT_KEY */
833 	status = crp_gen_key_secp256r1(1,
834 				       PSA_KEY_USAGE_SIGN_HASH |
835 				       PSA_KEY_USAGE_VERIFY_HASH);
836 #endif
837 
838 	/* Hash some data with the key using SHA256. */
839 	status = crp_hash_payload(msg, strlen(msg),
840 				  hash, sizeof(hash), &hash_len);
841 
842 	/* Sign the hash using key #1. */
843 	status = crp_sign_hash(1,
844 			       hash, hash_len,
845 			       sig, sizeof(sig), &sig_len);
846 
847 	/* Verify the hash signature using the public key. */
848 	status = crp_verify_sign(1, hash, hash_len, sig, sig_len);
849 
850 	/* Destroy the key. */
851 	status = crp_dest_key(1);
852 }
853 
854 /**
855  * @brief Generates random values using the TF-M crypto service.
856  */
crp_test_rng(void)857 void crp_test_rng(void)
858 {
859 	psa_status_t status;
860 	uint8_t outbuf[256] = { 0 };
861 	struct sf_hex_tbl_fmt fmt = {
862 		.ascii = true,
863 		.addr_label = true,
864 		.addr = 0
865 	};
866 
867 	status = al_psa_status(psa_generate_random(outbuf, 256), __func__);
868 	LOG_INF("Generating 256 bytes of random data.");
869 	al_dump_log();
870 	sf_hex_tabulate_16(&fmt, outbuf, 256);
871 }
872