#include "crypto.h" #include "system.h" #include "constants.h" #include "storage.h" #include "dev_name.h" #include #include #include #include #include #include #include #include #include #include #include "esp_log.h" #define ECPARAMS MBEDTLS_ECP_DP_SECP256R1 static const char *TAG = "crypto"; static const char *pers = "ecdsa"; static void seed_ctr_drbg_context(mbedtls_entropy_context *entropy, mbedtls_ctr_drbg_context *ctr_drbg) { int ret; mbedtls_entropy_init(entropy); mbedtls_ctr_drbg_init(ctr_drbg); ESP_LOGI(TAG, "Seed Mbedtls"); if ((ret = mbedtls_ctr_drbg_seed(ctr_drbg, mbedtls_entropy_func, entropy, (const unsigned char *)pers, strlen(pers))) != 0) { ESP_LOGE(TAG, " failed\n ! mbedtls_ctr_drbg_seed returned %d", ret); reboot(); } } bool crypto_gen_priv_key() { // Check if a private key has already been defined for this device if (storage_get_priv_key(NULL) > 0) return false; int ret = 1; mbedtls_pk_context key; mbedtls_pk_init(&key); mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; seed_ctr_drbg_context(&entropy, &ctr_drbg); ESP_LOGI(TAG, "PK info from type"); if ((ret = mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY))) != 0) { ESP_LOGE(TAG, " failed\n ! mbedtls_pk_setup returned -0x%04x", (unsigned int)-ret); reboot(); } // Generate private key ESP_LOGI(TAG, "Generate private key"); ret = mbedtls_ecp_gen_key(ECPARAMS, mbedtls_pk_ec(key), mbedtls_ctr_drbg_random, &ctr_drbg); if (ret != 0) { ESP_LOGE(TAG, " failed\n ! mbedtls_ecp_gen_key returned -0x%04x", (unsigned int)-ret); reboot(); } // Export private key ESP_LOGI(TAG, "Export private key"); unsigned char *key_buff = malloc(PRV_KEY_DER_MAX_BYTES); if ((ret = mbedtls_pk_write_key_der(&key, key_buff, PRV_KEY_DER_MAX_BYTES)) < 1) { ESP_LOGE(TAG, " failed\n ! mbedtls_pk_write_key_der returned -0x%04x", (unsigned int)-ret); reboot(); } storage_set_priv_key(key_buff + PRV_KEY_DER_MAX_BYTES - ret, ret); free(key_buff); mbedtls_pk_free(&key); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); return true; } void crypto_print_priv_key() { int ret; unsigned char *key_buff = malloc(PRV_KEY_DER_MAX_BYTES); size_t key_len = storage_get_priv_key(key_buff); assert(key_len > 0); mbedtls_pk_context key; mbedtls_pk_init(&key); mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; seed_ctr_drbg_context(&entropy, &ctr_drbg); ESP_LOGI(TAG, "Parse private key (len = %d)", key_len); if ((ret = mbedtls_pk_parse_key(&key, key_buff, key_len, NULL, 0, mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) { ESP_LOGE(TAG, " failed\n ! mbedtls_pk_parse_key returned -0x%04x", (unsigned int)-ret); reboot(); } free(key_buff); ESP_LOGI(TAG, "Show private key"); unsigned char *out = malloc(16000); memset(out, 0, 16000); if ((ret = mbedtls_pk_write_key_pem(&key, out, 16000)) != 0) { ESP_LOGE(TAG, " failed\n ! mbedtls_pk_write_key_pem returned -0x%04x", (unsigned int)-ret); reboot(); } ESP_LOGI(TAG, "%s", out); free(out); mbedtls_pk_free(&key); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); } /** * Get secret point value of our private key */ static bool crypto_get_priv_key_mpi(mbedtls_mpi *dst) { int ret; unsigned char *key_buff = malloc(PRV_KEY_DER_MAX_BYTES); size_t key_len = storage_get_priv_key(key_buff); assert(key_len > 0); mbedtls_pk_context key; mbedtls_pk_init(&key); mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; seed_ctr_drbg_context(&entropy, &ctr_drbg); ESP_LOGI(TAG, "Parse private key (len = %d)", key_len); if ((ret = mbedtls_pk_parse_key(&key, key_buff, key_len, NULL, 0, mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) { ESP_LOGE(TAG, " failed\n ! mbedtls_pk_parse_key returned -0x%04x", (unsigned int)-ret); reboot(); } free(key_buff); ESP_LOGI(TAG, "Extract private key"); mbedtls_ecp_keypair *kp = mbedtls_pk_ec(key); mbedtls_mpi_init(dst); mbedtls_mpi_copy(dst, &kp->private_d); mbedtls_pk_free(&key); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); return true; } char *crypto_get_csr() { int ret; unsigned char *key_buff = malloc(PRV_KEY_DER_MAX_BYTES); size_t key_len = storage_get_priv_key(key_buff); assert(key_len > 0); mbedtls_pk_context key; mbedtls_pk_init(&key); mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; seed_ctr_drbg_context(&entropy, &ctr_drbg); ESP_LOGI(TAG, "Parse private key (len = %d)", key_len); if ((ret = mbedtls_pk_parse_key(&key, key_buff, key_len, NULL, 0, mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) { ESP_LOGE(TAG, " failed\n ! mbedtls_pk_parse_key returned -0x%04x", (unsigned int)-ret); reboot(); } free(key_buff); // Create CSR mbedtls_x509write_csr req; mbedtls_x509write_csr_init(&req); mbedtls_x509write_csr_set_md_alg(&req, MBEDTLS_MD_SHA256); char subj[DEV_NAME_LEN + 4]; char *n = dev_name(); sprintf(subj, "CN=%s", n); free(n); if ((ret = mbedtls_x509write_csr_set_subject_name(&req, subj)) != 0) { ESP_LOGE(TAG, " failed\n ! mbedtls_x509write_csr_set_subject_name returned %d", ret); reboot(); } ESP_LOGI(TAG, "Sign CSR with private key"); mbedtls_x509write_csr_set_key(&req, &key); char *csr = malloc(4096); if ((ret = mbedtls_x509write_csr_pem(&req, (u_char *)csr, 4096, mbedtls_ctr_drbg_random, &ctr_drbg)) < 0) { ESP_LOGE(TAG, " failed\n ! mbedtls_x509write_csr_pem returned %d", ret); reboot(); } mbedtls_x509write_csr_free(&req); mbedtls_pk_free(&key); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); return csr; } char *crypto_encode_base64_safe_url(const char *src, size_t srclen) { size_t olen = 0; mbedtls_base64_encode(NULL, 0, &olen, (unsigned char *)src, srclen); if (olen < 1) { ESP_LOGE(TAG, "Failed to determine base64 buffer size!"); return NULL; } char *out = calloc(1, olen); if (!out) { ESP_LOGE(TAG, "Failed to allocate memory for destination buffer!"); return NULL; } if (mbedtls_base64_encode((unsigned char *)out, olen, &olen, (unsigned char *)src, srclen) != 0) { ESP_LOGE(TAG, "Failed to perfom base64 encoding!"); free(out); return NULL; } // Convert base64 encoding to base64URL for (size_t i = 0; i < olen; i++) { switch (out[i]) { case '+': out[i] = '-'; break; case '/': out[i] = '_'; break; case '=': out[i] = '\0'; break; } } return out; } #define HASH_LEN 32 char *crypto_sign_sha256_payload(const char *src, const size_t src_len, size_t *dstlen) { int ret; uint8_t r_be[32] = {0}; uint8_t s_be[32] = {0}; // Load private key mbedtls_mpi key_mpi; if (!crypto_get_priv_key_mpi(&key_mpi)) { ESP_LOGE(TAG, "Failed to load private key MPI!"); return NULL; } mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; seed_ctr_drbg_context(&entropy, &ctr_drbg); mbedtls_mpi r, s; mbedtls_mpi_init(&r); mbedtls_mpi_init(&s); mbedtls_ecdsa_context ecdsa_context; mbedtls_ecdsa_init(&ecdsa_context); mbedtls_ecp_group_load(&ecdsa_context.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP256R1); // Compute sha256 uint8_t sha256_out[HASH_LEN] = {0}; mbedtls_sha256((unsigned char *)src, src_len, sha256_out, 0); // Compute signature ret = mbedtls_ecdsa_sign(&ecdsa_context.MBEDTLS_PRIVATE(grp), &r, &s, &key_mpi, sha256_out, HASH_LEN, mbedtls_ctr_drbg_random, &ctr_drbg); // Extract R & S (as per RFC 7518) mbedtls_mpi_write_binary(&r, r_be, 32); mbedtls_mpi_write_binary(&s, s_be, 32); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); mbedtls_mpi_free(&r); mbedtls_mpi_free(&s); mbedtls_mpi_free(&key_mpi); mbedtls_ecdsa_free(&ecdsa_context); if (ret != 0) { ESP_LOGE(TAG, "Failed to perfom base64 encoding!"); return NULL; } // Prepare output char *out = calloc(1, 64); if (!out) { ESP_LOGE(TAG, "Failed to allocate memory to store signature!"); return NULL; } memcpy(out, &r_be, 32); memcpy(out + 32, &s_be, 32); *dstlen = 64; return out; }