File
Blob: firmware/platform/crypto_ec.c
| 1 | #include "radio_bridge.h" |
| 2 | #include "esp_err.h" |
| 3 | #include "esp_random.h" |
| 4 | #include "mbedtls/ecdh.h" |
| 5 | #include "mbedtls/platform_util.h" |
| 6 | #include "mbedtls/md.h" |
| 7 | #include "mbedtls/pk.h" |
| 8 | #include "mbedtls/x509_crt.h" |
| 9 | |
| 10 | static int curve_bits(const mbedtls_pk_context *key) |
| 11 | { |
| 12 | if (!mbedtls_pk_can_do(key, MBEDTLS_PK_ECDSA)) |
| 13 | return 0; |
| 14 | mbedtls_ecp_group_id id = mbedtls_pk_ec(*key)->MBEDTLS_PRIVATE(grp).id; |
| 15 | if (id == MBEDTLS_ECP_DP_SECP256R1) |
| 16 | return 256; |
| 17 | if (id == MBEDTLS_ECP_DP_SECP384R1) |
| 18 | return 384; |
| 19 | return 0; |
| 20 | } |
| 21 | |
| 22 | static int crypto_random(void *context, unsigned char *bytes, size_t length) |
| 23 | { |
| 24 | (void)context; |
| 25 | /* Board initialization starts Wi-Fi, enabling the hardware entropy source. */ |
| 26 | esp_fill_random(bytes, length); |
| 27 | return 0; |
| 28 | } |
| 29 | |
| 30 | static int load_key(mbedtls_pk_context *key, const uint8_t *der, size_t length) |
| 31 | { |
| 32 | if (!length || length > 4096) |
| 33 | return ESP_ERR_INVALID_SIZE; |
| 34 | int result = mbedtls_pk_parse_key(key, der, length, NULL, 0, crypto_random, NULL); |
| 35 | if (!result && !curve_bits(key)) |
| 36 | result = ESP_ERR_INVALID_ARG; |
| 37 | if (!result) { |
| 38 | mbedtls_ecp_keypair *ec = mbedtls_pk_ec(*key); |
| 39 | result = mbedtls_ecp_check_privkey(&ec->MBEDTLS_PRIVATE(grp), &ec->MBEDTLS_PRIVATE(d)); |
| 40 | } |
| 41 | return result; |
| 42 | } |
| 43 | |
| 44 | int32_t radio_crypto_key_info(const uint8_t *der, size_t length, int32_t *bits) |
| 45 | { |
| 46 | *bits = 0; |
| 47 | mbedtls_pk_context key; |
| 48 | mbedtls_pk_init(&key); |
| 49 | int result = load_key(&key, der, length); |
| 50 | if (!result) |
| 51 | *bits = curve_bits(&key); |
| 52 | mbedtls_pk_free(&key); |
| 53 | return result; |
| 54 | } |
| 55 | |
| 56 | int32_t radio_crypto_sign(const uint8_t *der, size_t key_length, const uint8_t *data, |
| 57 | size_t data_length, int32_t hash_bits, uint8_t *output, size_t capacity, |
| 58 | size_t *used) |
| 59 | { |
| 60 | *used = 0; |
| 61 | if (data_length > 65536 || (hash_bits != 256 && hash_bits != 384)) |
| 62 | return ESP_ERR_INVALID_SIZE; |
| 63 | mbedtls_pk_context key; |
| 64 | mbedtls_pk_init(&key); |
| 65 | uint8_t hash[64] = {0}; |
| 66 | mbedtls_md_type_t type = hash_bits == 256 ? MBEDTLS_MD_SHA256 : MBEDTLS_MD_SHA384; |
| 67 | int result = load_key(&key, der, key_length); |
| 68 | if (!result) |
| 69 | result = mbedtls_md(mbedtls_md_info_from_type(type), data, data_length, hash); |
| 70 | if (!result) |
| 71 | result = mbedtls_pk_sign(&key, type, hash, hash_bits / 8, output, capacity, used, |
| 72 | crypto_random, NULL); |
| 73 | mbedtls_pk_free(&key); |
| 74 | if (result) { |
| 75 | *used = 0; |
| 76 | mbedtls_platform_zeroize(output, capacity); |
| 77 | } |
| 78 | mbedtls_platform_zeroize(hash, sizeof(hash)); |
| 79 | return result; |
| 80 | } |
| 81 | |
| 82 | int32_t radio_crypto_p256_keygen(uint8_t secret[32], uint8_t public_key[65]) |
| 83 | { |
| 84 | mbedtls_ecp_keypair key; |
| 85 | mbedtls_ecp_keypair_init(&key); |
| 86 | int result = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, &key, crypto_random, NULL); |
| 87 | size_t used = 0; |
| 88 | if (!result) |
| 89 | result = mbedtls_mpi_write_binary(&key.MBEDTLS_PRIVATE(d), secret, 32); |
| 90 | if (!result) |
| 91 | result = mbedtls_ecp_point_write_binary(&key.MBEDTLS_PRIVATE(grp), &key.MBEDTLS_PRIVATE(Q), |
| 92 | MBEDTLS_ECP_PF_UNCOMPRESSED, &used, public_key, 65); |
| 93 | if (!result && used != 65) |
| 94 | result = ESP_ERR_INVALID_SIZE; |
| 95 | mbedtls_ecp_keypair_free(&key); |
| 96 | if (result) { |
| 97 | mbedtls_platform_zeroize(secret, 32); |
| 98 | mbedtls_platform_zeroize(public_key, 65); |
| 99 | } |
| 100 | return result; |
| 101 | } |
| 102 | |
| 103 | int32_t radio_crypto_p256_shared(const uint8_t secret[32], const uint8_t public_key[65], |
| 104 | uint8_t shared[32]) |
| 105 | { |
| 106 | mbedtls_ecp_group group; |
| 107 | mbedtls_ecp_point peer; |
| 108 | mbedtls_mpi scalar, value; |
| 109 | mbedtls_ecp_group_init(&group); |
| 110 | mbedtls_ecp_point_init(&peer); |
| 111 | mbedtls_mpi_init(&scalar); |
| 112 | mbedtls_mpi_init(&value); |
| 113 | int result = mbedtls_ecp_group_load(&group, MBEDTLS_ECP_DP_SECP256R1); |
| 114 | if (!result) |
| 115 | result = mbedtls_mpi_read_binary(&scalar, secret, 32); |
| 116 | if (!result) |
| 117 | result = mbedtls_ecp_check_privkey(&group, &scalar); |
| 118 | if (!result) |
| 119 | result = mbedtls_ecp_point_read_binary(&group, &peer, public_key, 65); |
| 120 | if (!result) |
| 121 | result = mbedtls_ecp_check_pubkey(&group, &peer); |
| 122 | if (!result) |
| 123 | result = mbedtls_ecdh_compute_shared(&group, &value, &peer, &scalar, crypto_random, NULL); |
| 124 | if (!result) |
| 125 | result = mbedtls_mpi_write_binary(&value, shared, 32); |
| 126 | mbedtls_mpi_free(&value); |
| 127 | mbedtls_mpi_free(&scalar); |
| 128 | mbedtls_ecp_point_free(&peer); |
| 129 | mbedtls_ecp_group_free(&group); |
| 130 | if (result) |
| 131 | mbedtls_platform_zeroize(shared, 32); |
| 132 | return result; |
| 133 | } |
| 134 | |
| 135 | int32_t radio_crypto_verify_ec(const uint8_t *certificate, size_t certificate_length, |
| 136 | const uint8_t *data, size_t data_length, const uint8_t *signature, |
| 137 | size_t signature_length, int32_t hash_bits) |
| 138 | { |
| 139 | if (certificate_length > 65536 || data_length > 65536 || signature_length > 128 || |
| 140 | (hash_bits != 256 && hash_bits != 384)) |
| 141 | return ESP_ERR_INVALID_SIZE; |
| 142 | mbedtls_x509_crt parsed; |
| 143 | mbedtls_x509_crt_init(&parsed); |
| 144 | uint8_t hash[64] = {0}; |
| 145 | mbedtls_md_type_t type = hash_bits == 256 ? MBEDTLS_MD_SHA256 : MBEDTLS_MD_SHA384; |
| 146 | int result = mbedtls_x509_crt_parse_der(&parsed, certificate, certificate_length); |
| 147 | if (!result && !curve_bits(&parsed.pk)) |
| 148 | result = ESP_ERR_INVALID_ARG; |
| 149 | if (!result) |
| 150 | result = mbedtls_md(mbedtls_md_info_from_type(type), data, data_length, hash); |
| 151 | if (!result) |
| 152 | result = |
| 153 | mbedtls_pk_verify(&parsed.pk, type, hash, hash_bits / 8, signature, signature_length); |
| 154 | mbedtls_x509_crt_free(&parsed); |
| 155 | return result; |
| 156 | } |