File
Blob: firmware/platform/certificate.c
| 1 | #include <string.h> |
| 2 | #include <time.h> |
| 3 | #include "radio_bridge.h" |
| 4 | #include "esp_random.h" |
| 5 | #include "mbedtls/ctr_drbg.h" |
| 6 | #include "mbedtls/pk.h" |
| 7 | #include "mbedtls/platform_util.h" |
| 8 | #include "mbedtls/x509_crt.h" |
| 9 | |
| 10 | static int entropy(void *context, unsigned char *out, size_t length) |
| 11 | { |
| 12 | (void)context; |
| 13 | /* Wi-Fi is running before this call, enabling ESP-IDF's hardware entropy source. */ |
| 14 | esp_fill_random(out, length); |
| 15 | return 0; |
| 16 | } |
| 17 | |
| 18 | int32_t radio_certificate_generate(uint8_t *cert, size_t cert_capacity, size_t *cert_length, |
| 19 | uint8_t *key, size_t key_capacity, size_t *key_length) |
| 20 | { |
| 21 | if (!cert || !key || !cert_length || !key_length) |
| 22 | return -1; |
| 23 | *cert_length = *key_length = 0; |
| 24 | time_t now = time(NULL), before = now - 60, after = now + 30 * 24 * 60 * 60; |
| 25 | struct tm tm; |
| 26 | char start[15], end[15]; |
| 27 | if (now < 1700000000 || !gmtime_r(&before, &tm) || |
| 28 | strftime(start, sizeof(start), "%Y%m%d%H%M%S", &tm) != 14 || !gmtime_r(&after, &tm) || |
| 29 | strftime(end, sizeof(end), "%Y%m%d%H%M%S", &tm) != 14) |
| 30 | return -1; |
| 31 | mbedtls_ctr_drbg_context rng; |
| 32 | mbedtls_pk_context pk; |
| 33 | mbedtls_x509write_cert crt; |
| 34 | mbedtls_ctr_drbg_init(&rng); |
| 35 | mbedtls_pk_init(&pk); |
| 36 | mbedtls_x509write_crt_init(&crt); |
| 37 | const unsigned char purpose[] = "pocket-radio-dtls"; |
| 38 | int result = mbedtls_ctr_drbg_seed(&rng, entropy, NULL, purpose, sizeof(purpose) - 1); |
| 39 | if (result != 0) |
| 40 | goto done; |
| 41 | result = mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)); |
| 42 | if (result != 0) |
| 43 | goto done; |
| 44 | result = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(pk), |
| 45 | mbedtls_ctr_drbg_random, &rng); |
| 46 | if (result != 0) |
| 47 | goto done; |
| 48 | mbedtls_x509write_crt_set_version(&crt, MBEDTLS_X509_CRT_VERSION_3); |
| 49 | mbedtls_x509write_crt_set_md_alg(&crt, MBEDTLS_MD_SHA256); |
| 50 | mbedtls_x509write_crt_set_subject_key(&crt, &pk); |
| 51 | mbedtls_x509write_crt_set_issuer_key(&crt, &pk); |
| 52 | unsigned char serial[16]; |
| 53 | esp_fill_random(serial, sizeof(serial)); |
| 54 | serial[0] = (serial[0] & 0x7f) | 1; |
| 55 | if ((result = mbedtls_x509write_crt_set_serial_raw(&crt, serial, sizeof(serial))) != 0 || |
| 56 | (result = mbedtls_x509write_crt_set_subject_name(&crt, "CN=Pocket Radio")) != 0 || |
| 57 | (result = mbedtls_x509write_crt_set_issuer_name(&crt, "CN=Pocket Radio")) != 0 || |
| 58 | (result = mbedtls_x509write_crt_set_validity(&crt, start, end)) != 0) |
| 59 | goto done; |
| 60 | result = mbedtls_x509write_crt_der(&crt, cert, cert_capacity, mbedtls_ctr_drbg_random, &rng); |
| 61 | if (result < 0) |
| 62 | goto done; |
| 63 | *cert_length = (size_t)result; |
| 64 | memmove(cert, cert + cert_capacity - *cert_length, *cert_length); |
| 65 | result = mbedtls_pk_write_key_der(&pk, key, key_capacity); |
| 66 | if (result < 0) |
| 67 | goto done; |
| 68 | *key_length = (size_t)result; |
| 69 | memmove(key, key + key_capacity - *key_length, *key_length); |
| 70 | mbedtls_platform_zeroize(key + *key_length, key_capacity - *key_length); |
| 71 | result = 0; |
| 72 | done: |
| 73 | mbedtls_x509write_crt_free(&crt); |
| 74 | mbedtls_pk_free(&pk); |
| 75 | mbedtls_ctr_drbg_free(&rng); |
| 76 | if (result != 0) { |
| 77 | mbedtls_platform_zeroize(key, key_capacity); |
| 78 | *cert_length = *key_length = 0; |
| 79 | } |
| 80 | return result; |
| 81 | } |