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.
160 lines
7.4 KiB
C
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");
|
|
}
|