Skip to content

Commit 5ded679

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 5ded679

File tree

7 files changed

+304
-0
lines changed

7 files changed

+304
-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: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Mbed Crypto provisioning example application
2+
3+
Let's say the secure element manufacturer shipped you a secure element with a
4+
device private key already inside. This type of "pre-provisioned" secure
5+
element is what you'll use as a part during the device assembly process. You've
6+
taken this secure element, paired it with a nice Cortex-M microcontroller on a
7+
board to make a device. Now, you'd like to be able to use this key from Mbed
8+
Crypto. How does Mbed Crypto know the key exists? We can tell Mbed Crypto by
9+
running a provisionining application, which is typically separate from the
10+
primary application and may be run as a final device assembly step.
11+
12+
13+
### Adding pre-provisioned keys
14+
15+
Mbed Crypto provides a way to register pre-existing secure element keys:
16+
`mbedtls_psa_register_se_key()`. This function adds the necessary metadata to
17+
persistent storage so that the secure element keys can be used by an
18+
application key ID.
19+
20+
Provide which physical secure element slot the key is in with
21+
`psa_set_key_slot_number()`. This function operates on a key attributes
22+
structure. Complete the filling in of all necessary attributes and then call
23+
`mbedtls_psa_register_se_key()` to notify Mbed Crypto that the key exists,
24+
where the key exists, what format the key is, what the key can be used for, and
25+
so forth.

provisioning/main.c

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
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. Note: If, for example, your SE has a
29+
* pre-provisioned key in slot 0, this can be 0; a key slot is not the same as
30+
* a key ID, and key IDs of 0 are invalid, but key slots of 0 are OK. */
31+
#define EXAMPLE_FACTORY_KEY_SE_SLOT 0
32+
33+
/* The slot number for the device private key which is generated within the
34+
* secure element (never leaving the secure element) by this example
35+
* provisioning application. */
36+
#define EXAMPLE_GENERATED_KEY_SE_SLOT 2
37+
38+
/* The application-specific key ID for the secure element factory-provided
39+
* device private key. This provisioning example application will associate the
40+
* factory-provided key with this key ID for use by other applications. Any
41+
* valid ID can be chosen here; the chosen ID does not need to correlate in any
42+
* way with the physical location of the key (within the secure element). */
43+
#define EXAMPLE_FACTORY_KEY_ID 16
44+
45+
/* The application-specific key ID for the device private key imported into the
46+
* secure element by this example provisioning application. */
47+
#define EXAMPLE_GENERATED_KEY_ID 18
48+
49+
psa_status_t generate_key_on_device(void)
50+
{
51+
psa_status_t status;
52+
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
53+
psa_key_handle_t handle;
54+
55+
/* Set device private key attributes. */
56+
/* Note: It is not necessary to hard-code the physical slot number within
57+
* the secure element. The secure element driver can automatically allocate
58+
* a slot that fits your use case. */
59+
psa_set_key_slot_number(&attributes, EXAMPLE_GENERATED_KEY_SE_SLOT);
60+
psa_set_key_id(&attributes, EXAMPLE_GENERATED_KEY_ID);
61+
psa_set_key_lifetime(&attributes, PSA_ATECC608A_LIFETIME);
62+
psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
63+
psa_set_key_bits(&attributes, 256);
64+
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN);
65+
psa_set_key_type(&attributes,
66+
PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1));
67+
68+
/* Generate the key inside the secure element. */
69+
status = psa_generate_key(&attributes, &handle);
70+
if (status != PSA_SUCCESS) {
71+
return status;
72+
}
73+
74+
return psa_close_key(handle);
75+
}
76+
77+
psa_status_t register_preprovisioned_keys(void)
78+
{
79+
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
80+
81+
/* Set device private key attributes. */
82+
psa_set_key_slot_number(&attributes, EXAMPLE_FACTORY_KEY_SE_SLOT);
83+
psa_set_key_id(&attributes, EXAMPLE_FACTORY_KEY_ID);
84+
psa_set_key_lifetime(&attributes, PSA_ATECC608A_LIFETIME);
85+
psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
86+
psa_set_key_bits(&attributes, 256);
87+
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN);
88+
psa_set_key_type(&attributes,
89+
PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1));
90+
91+
/* Register the factory-created key with Mbed Crypto, so that Mbed Crypto
92+
* knows that the key exists and how to find and access the key. This
93+
* registration only needs doing once, as Mbed Crypto will remember the
94+
* registration even across reboots. */
95+
return mbedtls_psa_register_se_key(&attributes);
96+
}
97+
98+
void print_public_key(psa_key_id_t key_id)
99+
{
100+
enum { OUTPUT_LEN = 256 };
101+
int ret;
102+
psa_status_t status;
103+
unsigned char *output;
104+
psa_key_handle_t handle;
105+
mbedtls_pk_context pk;
106+
107+
printf("\tKey ID %lu:\n", key_id);
108+
109+
/* Open the specified key. */
110+
status = psa_open_key(key_id, &handle);
111+
if (status != PSA_SUCCESS)
112+
{
113+
printf("Failed to open key %lu with status=%ld\n", key_id, status);
114+
return;
115+
}
116+
117+
output = calloc(1, OUTPUT_LEN);
118+
if (!output) {
119+
puts("Out of memory");
120+
return;
121+
}
122+
123+
mbedtls_pk_init(&pk);
124+
ret = mbedtls_pk_setup_opaque(&pk, handle);
125+
if (ret != 0)
126+
{
127+
printf("Failed to setup PK with ret=%d\n", ret);
128+
goto done;
129+
}
130+
131+
ret = mbedtls_pk_write_pubkey_pem(&pk, output, OUTPUT_LEN);
132+
if (ret != 0) {
133+
printf("Failed to print pubkey with ret=%d\n", ret);
134+
goto done;
135+
}
136+
137+
printf("%s\n", output);
138+
139+
done:
140+
mbedtls_pk_free(&pk);
141+
free(output);
142+
}
143+
144+
/* The secure element factory put a device private key pair (not attestation
145+
* key) into a slot in the secure element. We need to tell Mbed Crypto that
146+
* this key pair exists so that it can be used. */
147+
148+
/* Put trusted root CA certificate into persistent storage */
149+
/* When and how should PSA use this? TLS wants for authenticating the server. */
150+
/* Application will have this, not provisioning. */
151+
152+
int main(void)
153+
{
154+
psa_status_t status;
155+
printf("Provisioning device...\n");
156+
157+
printf("\tErasing device... ");
158+
fflush(stdout);
159+
status = mbed_psa_reboot_and_request_new_security_state(PSA_LIFECYCLE_ASSEMBLY_AND_TEST);
160+
if (status != PSA_SUCCESS)
161+
{
162+
printf("failed with status=%ld\n", status);
163+
return status;
164+
}
165+
printf("done.\n");
166+
167+
printf("\tRegistering drivers... ");
168+
fflush(stdout);
169+
status = psa_register_se_driver(PSA_ATECC608A_LIFETIME, &atecc608a_drv_info);
170+
if (status != PSA_SUCCESS)
171+
{
172+
printf("failed with status=%ld\n", status);
173+
return status;
174+
}
175+
printf("done.\n");
176+
177+
printf("\tInitializing PSA Crypto... ");
178+
fflush(stdout);
179+
status = psa_crypto_init();
180+
if (status != PSA_SUCCESS)
181+
{
182+
printf("failed with status=%ld\n", status);
183+
return status;
184+
}
185+
printf("done.\n");
186+
187+
printf("\tRegistering factory-created keys... ");
188+
fflush(stdout);
189+
status = register_preprovisioned_keys();
190+
if (status != PSA_SUCCESS)
191+
{
192+
printf("failed with status=%ld\n", status);
193+
return status;
194+
}
195+
printf("done.\n");
196+
197+
printf("\tGenerating keys within the secure element... ");
198+
fflush(stdout);
199+
status = generate_key_on_device();
200+
if (status != PSA_SUCCESS)
201+
{
202+
printf("\n\t\tfailed with status=%ld\n", status);
203+
return status;
204+
}
205+
printf("done.\n");
206+
207+
printf("Device provisioned\n");
208+
209+
printf("\n---------------------------------------------------------------------\n\n");
210+
printf("Device public keys:\n");
211+
print_public_key(EXAMPLE_FACTORY_KEY_ID);
212+
print_public_key(EXAMPLE_GENERATED_KEY_ID);
213+
214+
return PSA_SUCCESS;
215+
}
216+
#else
217+
int main(void)
218+
{
219+
printf("Not all of the required options are defined:\n"
220+
" - ATCA_HAL_I2C\n");
221+
return 0;
222+
}
223+
#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: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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 APIs, which this example depends on. */
21+
#define MBEDTLS_PSA_CRYPTO_C
22+
23+
/* Enable PSA use of secure elements. */
24+
#define MBEDTLS_PSA_CRYPTO_SE_C
25+
26+
/* Make Mbed TLS use PSA. */
27+
#define MBEDTLS_USE_PSA_CRYPTO
28+
29+
/* Enable pretty-printing of public keys. */
30+
#define MBEDTLS_PEM_WRITE_C

0 commit comments

Comments
 (0)