Fix HTTPS handshake: trust the actual cert the proxy presents, not Origin CA
The Tools Server hostname turned out to be Cloudflare-proxied, not a
direct connection to nginx -- so the ESP32 (and any browser) sees
Cloudflare's own edge certificate (issued by Google Trust Services),
never the Origin CA cert, which only ever sits on the Cloudflare-to-
origin leg. Confirmed on hardware: ESP_ERR_HTTP_CONNECT.
Tried switching to ESP-IDF's built-in public CA bundle instead
(esp_crt_bundle_attach) as the more general fix, but that also failed
on hardware ("No matching trusted root certificate found") -- the
bundle's copy of the relevant Google root has the same name and public
key as the live one but a different serial/signature (a reissue), and
the bundle does an exact byte-level match, not a semantic one.
Simplest reliable fix: embed the exact certificate the proxy actually
presents (extracted live via openssl s_client, see
firmware/main/certs/tools_server_ca.pem) and trust that directly via
cert_pem, sidestepping bundle-matching semantics entirely. Documented
in firmware/README.md how to re-extract if the proxy's CA ever changes.
This commit is contained in:
@@ -25,12 +25,18 @@ static const char *TAG = "frame_client";
|
||||
|
||||
static EventGroupHandle_t s_sta_event_group;
|
||||
|
||||
/* Cloudflare's Origin CA root certs (RSA + ECC, both concatenated --
|
||||
* mbedtls_x509_crt_parse() chains every cert in a PEM buffer into the
|
||||
* trust store, so either one nginx presents validates), for trusting an
|
||||
* https tools server whose reverse proxy terminates TLS with a
|
||||
* Cloudflare-issued origin certificate. See firmware/main/certs/. */
|
||||
extern const char cloudflare_origin_ca_pem_start[] asm("_binary_cloudflare_origin_ca_pem_start");
|
||||
/* The exact CA certificate the tools server's reverse proxy presents,
|
||||
* embedded verbatim (not sourced from ESP-IDF's built-in root bundle --
|
||||
* that does an exact byte-level match against its compiled-in table,
|
||||
* and a semantically-identical "same name, same public key" root
|
||||
* re-issued under a different serial/signature, as Google did for GTS
|
||||
* Root R4, doesn't match it; confirmed on hardware, see
|
||||
* firmware/main/certs/tools_server_ca.pem for how this was extracted).
|
||||
* If the proxy's CA ever changes, re-extract with:
|
||||
* openssl s_client -connect <host>:443 -showcerts </dev/null
|
||||
* and replace this file with whichever cert in the chain you want as
|
||||
* the trust anchor (typically the root). */
|
||||
extern const char tools_server_ca_pem_start[] asm("_binary_tools_server_ca_pem_start");
|
||||
|
||||
/* Builds a full URL from cfg->toolsserver + a path (no leading slash),
|
||||
* appending cfg->access_token as ?token= if one's set. toolsserver is
|
||||
@@ -237,7 +243,7 @@ static frame_server_config_t fetch_frame_config(const frame_config_t *cfg)
|
||||
.url = url,
|
||||
.method = HTTP_METHOD_GET,
|
||||
.timeout_ms = CONFIG_FRAME_SERVER_CHECK_TIMEOUT_MS,
|
||||
.cert_pem = cloudflare_origin_ca_pem_start,
|
||||
.cert_pem = tools_server_ca_pem_start,
|
||||
};
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
|
||||
@@ -298,7 +304,7 @@ static void fetch_photo_info(const frame_config_t *cfg, char *location_line1, si
|
||||
.url = url,
|
||||
.method = HTTP_METHOD_GET,
|
||||
.timeout_ms = CONFIG_FRAME_SERVER_CHECK_TIMEOUT_MS,
|
||||
.cert_pem = cloudflare_origin_ca_pem_start,
|
||||
.cert_pem = tools_server_ca_pem_start,
|
||||
};
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
|
||||
@@ -358,7 +364,7 @@ static int fetch_face_labels(const frame_config_t *cfg, manage_face_label_t *out
|
||||
.url = url,
|
||||
.method = HTTP_METHOD_GET,
|
||||
.timeout_ms = CONFIG_FRAME_SERVER_CHECK_TIMEOUT_MS,
|
||||
.cert_pem = cloudflare_origin_ca_pem_start,
|
||||
.cert_pem = tools_server_ca_pem_start,
|
||||
};
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
|
||||
@@ -498,7 +504,7 @@ static esp_err_t fetch_and_display(const frame_config_t *cfg, bool force_advance
|
||||
.url = url,
|
||||
.method = force_advance ? HTTP_METHOD_POST : HTTP_METHOD_GET,
|
||||
.timeout_ms = CONFIG_FRAME_FETCH_TIMEOUT_MS,
|
||||
.cert_pem = cloudflare_origin_ca_pem_start,
|
||||
.cert_pem = tools_server_ca_pem_start,
|
||||
};
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user