Skip to content

Commit a45f7c2

Browse files
committed
provisioning: Add CSR generation
Automatically create and print a certificate signing request. This makes it convenient to create device certificates using never-left-the-device, PSA-managed private keys. Include instructions on how to create and verify a device certificate in the README.
1 parent 8e4e5ea commit a45f7c2

File tree

3 files changed

+115
-1
lines changed

3 files changed

+115
-1
lines changed

provisioning/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,10 @@ To generate a key, specify the lifetime with `psa_set_key_lifetime()` and
6262
`PSA_ATECC608A_LIFETIME`. Fill in any other other necessary attributes, and
6363
then call `psa_generate_key()` to request the key be generated within the
6464
ATECC608A.
65+
66+
67+
### Generating CSRs on-device
68+
69+
This example generates certificate signing requests (CSRs) which can be used
70+
for TLS client authentication. The CSR is printed over the serial port, for
71+
use with your certificate authority (CA).

provisioning/main.c

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@
2020

2121
#if defined(ATCA_HAL_I2C)
2222
#include "mbedtls/pk.h"
23+
#include "mbedtls/x509.h"
24+
#include "mbedtls/x509_csr.h"
2325
#include "psa/crypto.h"
2426
#include "psa/lifecycle.h"
2527
#include "atecc608a_se.h"
28+
#include "mbed_assert.h"
2629

2730
/* The slot number for the device private key stored in the secure element by
2831
* the secure element factory.
@@ -52,6 +55,25 @@
5255
* secure element by this example provisioning application. */
5356
#define EXAMPLE_GENERATED_KEY_ID 18
5457

58+
/* Mbed TLS needs a CSPRNG to generate a CSR. Provide it a callback which uses
59+
* PSA Crypto provide a source of randomness. */
60+
static int psa_rng_for_mbedtls(void *p_rng,
61+
unsigned char *output, size_t output_len)
62+
{
63+
psa_status_t status;
64+
65+
(void)p_rng;
66+
67+
status = psa_generate_random(output, output_len);
68+
69+
/* Fail immediately if our source of randomness fails. We could
70+
* alternatively translate PSA errors into errors Mbed TLS would handle
71+
* from its f_rng randomness callback. */
72+
MBED_ASSERT(status != PSA_SUCCESS);
73+
74+
return 0;
75+
}
76+
5577
static psa_status_t generate_key_on_device(void)
5678
{
5779
psa_status_t status;
@@ -152,6 +174,83 @@ static void print_public_key(psa_key_id_t key_id)
152174
free(output);
153175
}
154176

177+
static void generate_and_print_csr(psa_key_id_t key_id)
178+
{
179+
int ret;
180+
unsigned char *output;
181+
enum { CSR_PEM_LEN = 2048 };
182+
psa_status_t status;
183+
psa_key_handle_t handle;
184+
mbedtls_pk_context pk;
185+
mbedtls_x509write_csr req;
186+
187+
/* mbedtls_* functions, rather than PSA functions, are used here because
188+
* PSA does not provide a way to create a certificate signing request
189+
* (CSR). An X.509 library should be used to create a CSR. We use the Mbed
190+
* TLS X.509 library to create our CSR. */
191+
192+
/* Initialize Mbed TLS structures. */
193+
mbedtls_pk_init(&pk);
194+
mbedtls_x509write_csr_init(&req);
195+
196+
/* Allocate output buffer. */
197+
output = calloc(1, CSR_PEM_LEN);
198+
if (!output)
199+
{
200+
puts("Out of memory");
201+
return;
202+
}
203+
204+
/* Open the specified key. */
205+
status = psa_open_key(key_id, &handle);
206+
if (status != PSA_SUCCESS)
207+
{
208+
printf("Failed to open key %lu with status=%ld\n", key_id, status);
209+
goto done;
210+
}
211+
212+
ret = mbedtls_pk_setup_opaque(&pk, handle);
213+
if (ret != 0)
214+
{
215+
printf("Failed to setup PK with ret=%d\n", ret);
216+
goto done;
217+
}
218+
219+
mbedtls_x509write_csr_set_md_alg(&req, MBEDTLS_MD_SHA256);
220+
221+
ret = mbedtls_x509write_csr_set_subject_name(
222+
&req, "CN=Device,O=Mbed TLS,OU=client,C=UK");
223+
if (ret != 0)
224+
{
225+
printf("Failed to set subject name with ret=%d\n", ret);
226+
goto done;
227+
}
228+
229+
mbedtls_x509write_csr_set_key_usage(
230+
&req, MBEDTLS_X509_KU_DIGITAL_SIGNATURE);
231+
232+
mbedtls_x509write_csr_set_ns_cert_type(
233+
&req, MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT);
234+
235+
mbedtls_x509write_csr_set_key(&req, &pk);
236+
237+
ret = mbedtls_x509write_csr_pem(&req, output, CSR_PEM_LEN,
238+
psa_rng_for_mbedtls, NULL);
239+
if (ret != 0)
240+
{
241+
printf("Failed to make CSR with ret=%d\n", ret);
242+
goto done;
243+
}
244+
245+
printf("\tKey ID %lu:\n", key_id);
246+
printf("%s\n", output);
247+
248+
done:
249+
free(output);
250+
mbedtls_x509write_csr_free(&req);
251+
mbedtls_pk_free(&pk);
252+
}
253+
155254
int main(void)
156255
{
157256
psa_status_t status;
@@ -230,6 +329,10 @@ int main(void)
230329
print_public_key(EXAMPLE_FACTORY_KEY_ID);
231330
print_public_key(EXAMPLE_GENERATED_KEY_ID);
232331

332+
printf("Device-generated CSRs:\n");
333+
generate_and_print_csr(EXAMPLE_FACTORY_KEY_ID);
334+
generate_and_print_csr(EXAMPLE_GENERATED_KEY_ID);
335+
233336
return PSA_SUCCESS;
234337
}
235338
#else

provisioning/mbedtls_user_config.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,9 @@
2323
/* Make Mbed TLS use PSA. */
2424
#define MBEDTLS_USE_PSA_CRYPTO
2525

26-
/* Enable printing of public keys in PEM format. */
26+
/* Enable printing of public keys and CSRs in PEM format. */
2727
#define MBEDTLS_PEM_WRITE_C
28+
29+
/* Enable additional features needed to generate a CSR. */
30+
#define MBEDTLS_X509_CREATE_C
31+
#define MBEDTLS_X509_CSR_WRITE_C

0 commit comments

Comments
 (0)