Skip to content

Commit 699f547

Browse files
committed
Add a device provisioning example
Add a device provisioning example that works with two different types of secure element keys: - Keys already stored in the secure element (in physical slot 0 in our example), placed there by the secure element vendor or another secure facility before coming to the assembly house. - Keys generated within the secure element during assembly (into physical slot 2 in our example) The provisiong example fulfils the need post-device-assembly to notify Mbed Crypto about which keys are present where, so that applications can use those keys. Mbed Crypto will remember this information across reboots, so after provisioning, another application can be flashed onto the device which can use these keys.
1 parent f8de46c commit 699f547

File tree

7 files changed

+359
-0
lines changed

7 files changed

+359
-0
lines changed

provisioning/.mbedignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
mbed-os/features/frameworks/unity/
2+

provisioning/README.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Mbed Crypto factory device provisioning example
2+
3+
This example demonstrates how to install keys into a device during a
4+
hypothetical board assembly stage. Your device comprises a microcontroller, a
5+
secure element (e.g. ATECC608A), and a PCB to connect and hold everything
6+
together. When this README refers to "device", we mean the entire board
7+
assembly, not just the microcontroller or the secure element.
8+
9+
Let's say the secure element manufacturer shipped you a secure element with a
10+
device private key already inside. This type of "pre-provisioned" secure
11+
element is what you'll use as a part during the device assembly process. You've
12+
taken this secure element, paired it with a nice Cortex-M microcontroller on a
13+
board to make a device. Now, you'd like to be able to use this key from Mbed
14+
Crypto. How does Mbed Crypto know the key exists? We can tell Mbed Crypto by
15+
running a factory device provisionining application, which is typically
16+
separate from the primary application and may be run as a final device assembly
17+
step.
18+
19+
20+
### Installing keys during factory device provisioning
21+
22+
Mbed Crypto provides three ways to install secure element keys into your
23+
device.
24+
25+
- Register a pre-existing secure element key
26+
- Generate a new key within a secure element
27+
- Import a pre-existing key to a secure element (not all secure elements
28+
support this method)
29+
30+
This example demonstrates the first two methods.
31+
32+
33+
#### Register a pre-existing secure element key
34+
35+
For registering keys already present within a secure element, Mbed Crypto
36+
provides a function to inform Mbed Crypto about the existence of the key:
37+
`mbedtls_psa_register_se_key()`. This function adds the necessary metadata to
38+
persistent storage so that the secure element keys can be used by an
39+
application.
40+
41+
With `psa_set_key_slot_number()`, you can specify which physical secure element
42+
slot the key is in. This function operates on a key attributes structure. Fill
43+
in any other necessary attributes and then call `mbedtls_psa_register_se_key()`
44+
to notify Mbed Crypto that the key exists, where the key exists, what format
45+
the key is, what the key can be used for, and so forth.
46+
47+
48+
#### Generate a new key within a secure element
49+
50+
For generating a new key, Mbed Crypto provides `psa_generate_key()`. The
51+
physical location in which to generate the key is specified by the key's
52+
attributes before the key is created: specifically, the lifetime and
53+
optionally, for keys within a secure element, the physical secure element slot
54+
number.
55+
56+
For generated keys, unlike pre-existing secure element keys, calling
57+
`psa_set_key_slot_number()` is not required. The driver will select a valid and
58+
available key slot for the key you wish to generated based on the key
59+
attributes you've requested during creation time.
60+
61+
To generate a key, specify the lifetime with `psa_set_key_lifetime()` and
62+
`PSA_ATECC608A_LIFETIME`. Fill in any other other necessary attributes, and
63+
then call `psa_generate_key()` to request the key be generated within the
64+
ATECC608A.

provisioning/main.c

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
/*
2+
* Copyright (c) 2019, Arm Limited and affiliates
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include <stdio.h>
19+
#include <stdlib.h>
20+
21+
#if defined(ATCA_HAL_I2C)
22+
#include "mbedtls/pk.h"
23+
#include "psa/crypto.h"
24+
#include "psa/lifecycle.h"
25+
#include "atecc608a_se.h"
26+
27+
/* The slot number for the device private key stored in the secure element by
28+
* the secure element factory.
29+
*
30+
* ATECC608A secure elements with pre-provisioned keys often have that
31+
* key present in slot 0, so we use 0 here for our example.
32+
*
33+
* Note that unlike most numerical values in the PSA Crypto API, 0 is a valid
34+
* value for a slot number. Like many other secure elements, the ATECC608A
35+
* numbers its slots from 0.
36+
*/
37+
#define EXAMPLE_FACTORY_KEY_SE_SLOT 0
38+
39+
/* The slot number for the device private key which is generated within the
40+
* secure element (never leaving the secure element) by this example
41+
* provisioning application. */
42+
#define EXAMPLE_GENERATED_KEY_SE_SLOT 2
43+
44+
/* The application-specific key ID for the secure element factory-provided
45+
* device private key. This provisioning example application will associate the
46+
* factory-provided key with this key ID for use by other applications. Any
47+
* valid ID can be chosen here; the chosen ID does not need to correlate in any
48+
* way with the physical location of the key (within the secure element). */
49+
#define EXAMPLE_FACTORY_KEY_ID 16
50+
51+
/* The application-specific key ID for the device private key imported into the
52+
* secure element by this example provisioning application. */
53+
#define EXAMPLE_GENERATED_KEY_ID 18
54+
55+
static psa_status_t generate_key_on_device(void)
56+
{
57+
psa_status_t status;
58+
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
59+
psa_key_handle_t handle;
60+
61+
/* Set device private key attributes. */
62+
/* Note that it is not necessary to specify the physical slot number within
63+
* the secure element. The secure element driver can automatically allocate
64+
* a slot that fits the use case the key attributes request. */
65+
psa_set_key_id(&attributes, EXAMPLE_GENERATED_KEY_ID);
66+
psa_set_key_lifetime(&attributes, PSA_ATECC608A_LIFETIME);
67+
psa_set_key_slot_number(&attributes, EXAMPLE_GENERATED_KEY_SE_SLOT);
68+
psa_set_key_type(&attributes,
69+
PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1));
70+
psa_set_key_bits(&attributes, 256);
71+
psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
72+
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN);
73+
74+
/* Generate the key inside the secure element. */
75+
status = psa_generate_key(&attributes, &handle);
76+
if (status != PSA_SUCCESS) {
77+
return status;
78+
}
79+
80+
return psa_close_key(handle);
81+
}
82+
83+
static psa_status_t register_preprovisioned_keys(void)
84+
{
85+
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
86+
87+
/* Set device private key attributes. */
88+
psa_set_key_id(&attributes, EXAMPLE_FACTORY_KEY_ID);
89+
psa_set_key_lifetime(&attributes, PSA_ATECC608A_LIFETIME);
90+
psa_set_key_slot_number(&attributes, EXAMPLE_FACTORY_KEY_SE_SLOT);
91+
psa_set_key_type(&attributes,
92+
PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1));
93+
psa_set_key_bits(&attributes, 256);
94+
psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
95+
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN);
96+
97+
/* Register the factory-created key with Mbed Crypto, so that Mbed Crypto
98+
* knows that the key exists and how to find and access the key. This
99+
* registration only needs doing once, as Mbed Crypto will remember the
100+
* registration even across reboots. */
101+
return mbedtls_psa_register_se_key(&attributes);
102+
}
103+
104+
static void print_public_key(psa_key_id_t key_id)
105+
{
106+
enum { PUBKEY_PEM_LEN = 256 };
107+
int ret;
108+
psa_status_t status;
109+
unsigned char *output;
110+
psa_key_handle_t handle;
111+
mbedtls_pk_context pk;
112+
113+
printf("\tKey ID %lu:\n", key_id);
114+
115+
/* Open the specified key. */
116+
status = psa_open_key(key_id, &handle);
117+
if (status != PSA_SUCCESS)
118+
{
119+
printf("Failed to open key %lu with status=%ld\n", key_id, status);
120+
return;
121+
}
122+
123+
output = calloc(1, PUBKEY_PEM_LEN);
124+
if (!output) {
125+
puts("Out of memory");
126+
return;
127+
}
128+
129+
/* mbedtls_* functions, rather than PSA functions, are used here because
130+
* PSA currently lacks a way to format the key in the desired format. Mbed
131+
* Crypto's PK module can transform PSA keys to our desired key format, so
132+
* we employ Mbed Crypto's PK module here. */
133+
134+
mbedtls_pk_init(&pk);
135+
ret = mbedtls_pk_setup_opaque(&pk, handle);
136+
if (ret != 0)
137+
{
138+
printf("Failed to setup PK with ret=%d\n", ret);
139+
goto done;
140+
}
141+
142+
ret = mbedtls_pk_write_pubkey_pem(&pk, output, PUBKEY_PEM_LEN);
143+
if (ret != 0) {
144+
printf("Failed to print pubkey with ret=%d\n", ret);
145+
goto done;
146+
}
147+
148+
printf("%s\n", output);
149+
150+
done:
151+
mbedtls_pk_free(&pk);
152+
free(output);
153+
}
154+
155+
int main(void)
156+
{
157+
psa_status_t status;
158+
printf("Provisioning device...\n");
159+
160+
/* Erase secure storage (PSA ITS and PSA PS) to give Mbed Crypto a blank
161+
* slate to provision the device from. Any keys it used to know about will
162+
* be forgotten. Any keys stored in PSA ITS will be erased. All metadata
163+
* stored in PSA ITS about keys stored in secure elements will be erased.
164+
*
165+
* Note that the device may reboot as a part of this erase step, depending
166+
* on how mbed_psa_reboot_and_request_new_security_state() is implemented.
167+
* Currently, the function does not reboot in a manner such that this
168+
* function would be executed again and again in a loop.
169+
*/
170+
printf("\tErasing secure storage... ");
171+
fflush(stdout);
172+
status = mbed_psa_reboot_and_request_new_security_state(PSA_LIFECYCLE_ASSEMBLY_AND_TEST);
173+
if (status != PSA_SUCCESS)
174+
{
175+
printf("failed with status=%ld\n", status);
176+
return status;
177+
}
178+
printf("done.\n");
179+
180+
printf("\tRegistering drivers... ");
181+
fflush(stdout);
182+
status = psa_register_se_driver(PSA_ATECC608A_LIFETIME, &atecc608a_drv_info);
183+
if (status != PSA_SUCCESS)
184+
{
185+
printf("failed with status=%ld\n", status);
186+
return status;
187+
}
188+
printf("done.\n");
189+
190+
printf("\tInitializing PSA Crypto... ");
191+
fflush(stdout);
192+
status = psa_crypto_init();
193+
if (status != PSA_SUCCESS)
194+
{
195+
printf("failed with status=%ld\n", status);
196+
return status;
197+
}
198+
printf("done.\n");
199+
200+
/* The secure element factory put a device private key pair into a slot in
201+
* the secure element. We need to tell Mbed Crypto that this key pair
202+
* exists so that it can be used. */
203+
printf("\tRegistering factory-created keys... ");
204+
fflush(stdout);
205+
status = register_preprovisioned_keys();
206+
if (status != PSA_SUCCESS)
207+
{
208+
printf("failed with status=%ld\n", status);
209+
return status;
210+
}
211+
printf("done.\n");
212+
213+
/* We also want to generate our own key entirely within the secure element
214+
* during the factory device provisioning stage in device assembly. Ask
215+
* Mbed Crypto to generate this key for us. */
216+
printf("\tGenerating keys within the secure element... ");
217+
fflush(stdout);
218+
status = generate_key_on_device();
219+
if (status != PSA_SUCCESS)
220+
{
221+
printf("\n\t\tfailed with status=%ld\n", status);
222+
return status;
223+
}
224+
printf("done.\n");
225+
226+
printf("Device provisioned\n");
227+
228+
printf("\n---------------------------------------------------------------------\n\n");
229+
printf("Device public keys:\n");
230+
print_public_key(EXAMPLE_FACTORY_KEY_ID);
231+
print_public_key(EXAMPLE_GENERATED_KEY_ID);
232+
233+
return PSA_SUCCESS;
234+
}
235+
#else
236+
int main(void)
237+
{
238+
printf("Not all of the required options are defined:\n"
239+
" - ATCA_HAL_I2C\n");
240+
return 0;
241+
}
242+
#endif

provisioning/mbed-os-atecc608a.lib

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
https://github.com/ARMmbed/mbed-os-atecc608a/#754d0e42acc15f67310c7b3c773cd5b9484b924e

provisioning/mbed-os.lib

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
https://github.com/ARMmbed/mbed-os/

provisioning/mbed_app.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"target_overrides": {
3+
"*": {
4+
"platform.stdio-baud-rate": 9600,
5+
"platform.stdio-convert-newlines": true,
6+
"target.OUTPUT_EXT": "hex",
7+
"mbed-trace.enable": 0
8+
},
9+
"NRF52_DK": {
10+
"cryptoauthlib.i2c_sda": "P0_26",
11+
"cryptoauthlib.i2c_scl": "P0_27"
12+
},
13+
"SAML21J18A": {
14+
"cryptoauthlib.i2c_sda": "PA08",
15+
"cryptoauthlib.i2c_scl": "PA09"
16+
}
17+
},
18+
"macros": [
19+
"ATCAPRINTF",
20+
"MBEDTLS_USER_CONFIG_FILE=\"mbedtls_user_config.h\""
21+
]
22+
}

provisioning/mbedtls_user_config.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (C) 2006-2019, Arm Limited, All Rights Reserved
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
6+
* not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
* This file is part of Mbed TLS (https://tls.mbed.org)
18+
*/
19+
20+
/* Enable PSA use of secure elements. */
21+
#define MBEDTLS_PSA_CRYPTO_SE_C
22+
23+
/* Make Mbed TLS use the PSA Crypto API. */
24+
#define MBEDTLS_USE_PSA_CRYPTO
25+
26+
/* Enable printing of public keys in PEM format. */
27+
#define MBEDTLS_PEM_WRITE_C

0 commit comments

Comments
 (0)