Files
ESP32_Serial_Swiss_Army_Knife/tests/sdk_security_overrides/https.c
T
Commander1024 cdc9c7335a Add Phase 9C security hardening
Generate exact-hash SDK source overrides without modifying dependencies.
Harden
SSH allocation and algorithm policy, tighten web authentication cleanup,
and add
focused host contract tests and documentation.
2026-09-15 22:12:57 +02:00

160 lines
7.4 KiB
C

/* SPDX-License-Identifier: GPL-3.0-only */
#include "alloc.h"
typedef void *httpd_handle_t;
typedef int (*httpd_open_func_t)(httpd_handle_t, int);
typedef void esp_https_server_user_cb(void *);
typedef struct { unsigned char secret[37]; } esp_tls_t;
typedef void *esp_tls_error_handle_t;
typedef struct { int last_error, esp_tls_error_code, esp_tls_flags; } esp_https_server_last_error_t;
typedef struct { int user_cb_state; esp_tls_t *tls; } esp_https_server_user_cb_arg_t;
typedef struct {
const unsigned char *cacert_buf, *servercert_buf, *serverkey_buf;
unsigned cacert_bytes, servercert_bytes, serverkey_bytes;
void *userdata; const char **alpn_protos;
unsigned tls_handshake_timeout_ms; bool use_secure_element;
} esp_tls_cfg_server_t;
typedef struct {
void *global_transport_ctx, *global_user_ctx;
void (*global_transport_ctx_free_fn)(void *), (*global_user_ctx_free_fn)(void *);
httpd_open_func_t open_fn;
int server_port, ctrl_port;
} httpd_config_t;
struct httpd_ssl_config {
httpd_config_t httpd;
bool session_tickets, use_secure_element, use_ecdsa_peripheral;
const unsigned char *cacert_pem, *servercert, *prvtkey_pem;
unsigned cacert_len, servercert_len, prvtkey_len, tls_handshake_timeout_ms;
void *ssl_userdata; const char **alpn_protos;
esp_https_server_user_cb *user_cb;
int transport_mode, port_secure, port_insecure;
};
struct httpd_data {
httpd_config_t config; int msg_fd;
struct { int status; } hd_td;
void *transport;
void (*close_fn)(void *);
};
struct httpd_ctrl_data { int hc_msg; };
#define HTTPD_SSL_TRANSPORT_SECURE 1
#define HTTPD_SSL_USER_CB_SESS_CLOSE 2
#define HTTPD_SSL_USER_CB_SESS_CREATE 3
#define HTTPS_SERVER_EVENT_ERROR 4
#define HTTPS_SERVER_EVENT_ON_CONNECTED 5
#define HTTPS_SERVER_EVENT_DISCONNECTED 6
#define HTTPS_SERVER_EVENT_START 7
#define HTTPS_SERVER_EVENT_STOP 8
#define HTTP_SERVER_EVENT_STOP 9
#define HTTPD_CTRL_SHUTDOWN 10
#define THREAD_STOPPED 11
static bool start_failure, stop_failure, handshake_failure;
static unsigned deletes, creates, closes;
static struct httpd_data *active;
static void http_dispatch_event_to_event_loop(int id, const void *v, size_t n) {}
static void esp_http_server_dispatch_event(int id, const void *v, size_t n) {}
static int esp_tls_cfg_server_session_tickets_init(esp_tls_cfg_server_t *cfg) { return 0; }
static void esp_tls_cfg_server_session_tickets_free(esp_tls_cfg_server_t *cfg) {}
static esp_tls_t *esp_tls_init(void) {
esp_tls_t *tls = calloc(1, sizeof(*tls));
if (tls) { memset(tls, 0xb6, sizeof(*tls)); mark_secret(tls); }
return tls;
}
static int esp_tls_server_session_create(esp_tls_cfg_server_t *cfg, int fd, esp_tls_t *tls) {
return handshake_failure ? -1 : 0;
}
static void esp_tls_server_session_delete(esp_tls_t *tls) {
assert(tls); ++deletes; memset(tls, 0, sizeof(*tls)); free(tls);
}
static int esp_tls_get_error_handle(esp_tls_t *tls, esp_tls_error_handle_t *e) { return -1; }
static int esp_tls_get_and_clear_last_error(esp_tls_error_handle_t e, int *a, int *b) { return 0; }
static void *httpd_get_global_transport_ctx(httpd_handle_t h) { return ((struct httpd_data *)h)->config.global_transport_ctx; }
static void httpd_sess_set_transport_ctx(httpd_handle_t h, int fd, void *ctx, void (*fn)(void *)) {
struct httpd_data *hd = h; assert(!hd->transport); hd->transport = ctx; hd->close_fn = fn;
}
static int httpd_ssl_send(void) { return 0; }
static int httpd_ssl_recv(void) { return 0; }
static int httpd_ssl_pending(void) { return 0; }
static void httpd_sess_set_send_override(httpd_handle_t h, int fd, int (*fn)(void)) {}
static void httpd_sess_set_recv_override(httpd_handle_t h, int fd, int (*fn)(void)) {}
static void httpd_sess_set_pending_override(httpd_handle_t h, int fd, int (*fn)(void)) {}
static int httpd_start(httpd_handle_t *h, httpd_config_t *cfg) {
if (start_failure) return ESP_FAIL;
struct httpd_data *hd = calloc(1, sizeof(*hd));
if (!hd) return ESP_ERR_NO_MEM;
hd->config = *cfg; *h = hd; active = hd; return ESP_OK;
}
static int cs_send_to_ctrl_sock(int fd, int port, void *msg, size_t n) { return stop_failure ? -1 : 0; }
static void httpd_os_thread_sleep(int ms) {
if (active->transport) {
active->close_fn(active->transport);
active->transport = NULL;
}
active->hd_td.status = THREAD_STOPPED;
}
static void httpd_delete(struct httpd_data *hd) { assert(!hd->transport); free(hd); active = NULL; }
static void user_callback(void *arg) {
esp_https_server_user_cb_arg_t *a = arg;
if (a->user_cb_state == HTTPD_SSL_USER_CB_SESS_CREATE) ++creates;
if (a->user_cb_state == HTTPD_SSL_USER_CB_SESS_CLOSE) ++closes;
}
/* SDK_FUNCTIONS */
static struct httpd_ssl_config config(void) {
static unsigned char ca[13], cert[19], key[23];
memset(ca, 1, sizeof(ca)); memset(cert, 2, sizeof(cert)); memset(key, 3, sizeof(key));
return (struct httpd_ssl_config){.transport_mode=HTTPD_SSL_TRANSPORT_SECURE,
.cacert_pem=ca, .cacert_len=sizeof(ca), .servercert=cert, .servercert_len=sizeof(cert),
.prvtkey_pem=key, .prvtkey_len=sizeof(key), .user_cb=user_callback};
}
int main(void) {
secret_size = 23;
for (unsigned fail = 1; fail <= 6; ++fail) {
struct httpd_ssl_config cfg = config(); httpd_handle_t h = NULL;
calls = 0; fail_at = fail;
assert(httpd_ssl_start(&h, &cfg) != ESP_OK);
assert(!h && live == 0);
}
fail_at = 0;
struct httpd_ssl_config cfg = config(); httpd_handle_t h = NULL;
start_failure = true;
unsigned wipes = wiped_frees;
assert(httpd_ssl_start(&h, &cfg) != ESP_OK && live == 0);
assert(wiped_frees == wipes + 1);
assert(!cfg.httpd.global_transport_ctx && !cfg.httpd.global_transport_ctx_free_fn);
assert(!cfg.httpd.open_fn); /* no stale HTTPS wrapper on a retry */
start_failure = false;
assert(httpd_ssl_start(&h, &cfg) == ESP_OK);
assert(httpd_ssl_stop(h) == ESP_OK && live == 0);
h = NULL;
for (unsigned missing = 0; missing < 2; ++missing) {
cfg = config();
if (missing) cfg.prvtkey_pem = NULL; else cfg.servercert = NULL;
assert(httpd_ssl_start(&h, &cfg) != ESP_OK && live == 0);
}
cfg = config();
assert(httpd_ssl_start(&h, &cfg) == ESP_OK);
unsigned baseline = live;
for (unsigned fail = 1; fail <= 2; ++fail) {
calls = 0; fail_at = fail; unsigned before = deletes;
assert(httpd_ssl_open(h, 42) == ESP_ERR_NO_MEM);
assert(live == baseline && !active->transport);
assert(deletes == before + (fail == 2));
}
fail_at = 0; handshake_failure = true;
unsigned before = deletes;
assert(httpd_ssl_open(h, 42) != ESP_OK && live == baseline);
assert(deletes == before + 1);
handshake_failure = false;
assert(httpd_ssl_open(h, 42) == ESP_OK && creates == 1);
void *retained = active->transport; unsigned retained_live = live;
stop_failure = true; before = deletes; wipes = wiped_frees;
assert(httpd_ssl_stop(h) != ESP_OK);
assert(active->transport == retained && live == retained_live);
assert(deletes == before && wiped_frees == wipes && closes == 0);
stop_failure = false;
assert(httpd_ssl_stop(h) == ESP_OK && live == 0 && closes == 1);
assert(deletes == before + 1 && wiped_frees == wipes + 2);
assert(httpd_ssl_stop(NULL) == ESP_ERR_INVALID_ARG);
cfg = config(); cfg.transport_mode = 0; start_failure = true;
assert(httpd_ssl_start(&h, &cfg) != ESP_OK && live == 0);
puts("HTTPS allocation/handshake/start/stop ownership and wipe matrix PASS");
}