102 lines
3.6 KiB
C
102 lines
3.6 KiB
C
/* SPDX-License-Identifier: GPL-3.0-only */
|
|
/* Persistent HTTPS identity; authentication belongs to the user database. */
|
|
|
|
#pragma once
|
|
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include "esp_err.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#define WEB_SECURITY_NVS_NAMESPACE "web_sec"
|
|
#define WEB_SECURITY_NVS_BLOB_KEY "material"
|
|
|
|
|
|
#define WEB_SECURITY_PRIVATE_KEY_DER_CAPACITY 256U
|
|
#define WEB_SECURITY_CERTIFICATE_DER_CAPACITY 1024U
|
|
#define WEB_SECURITY_SHA256_LENGTH 32U
|
|
#define WEB_SECURITY_COMMON_NAME_CAPACITY 32U
|
|
#define WEB_SECURITY_DNS_NAME_CAPACITY 40U
|
|
|
|
#define WEB_SECURITY_CERT_NOT_BEFORE "20250101000000"
|
|
#define WEB_SECURITY_CERT_NOT_AFTER "20491231235959"
|
|
|
|
typedef enum {
|
|
WEB_SECURITY_LOAD_STORED = 0,
|
|
WEB_SECURITY_LOAD_GENERATED_MISSING = 1,
|
|
WEB_SECURITY_LOAD_MIGRATED_V1 = 2,
|
|
} web_security_load_result_t;
|
|
|
|
|
|
typedef struct {
|
|
uint32_t material_generation;
|
|
uint8_t sha256_fingerprint[WEB_SECURITY_SHA256_LENGTH];
|
|
char common_name[WEB_SECURITY_COMMON_NAME_CAPACITY];
|
|
char dns_name[WEB_SECURITY_DNS_NAME_CAPACITY];
|
|
uint8_t ipv4_address[4];
|
|
char not_before[sizeof(WEB_SECURITY_CERT_NOT_BEFORE)];
|
|
char not_after[sizeof(WEB_SECURITY_CERT_NOT_AFTER)];
|
|
} web_security_certificate_metadata_t;
|
|
|
|
/*
|
|
* NVS must already be initialized. Missing TLS material is generated and saved.
|
|
* Valid v1 material is migrated to certificate-only v2 before publication,
|
|
* preserving exact TLS identity and generation. Replacement is logical NVS
|
|
* deletion of legacy fields, not secure flash erasure. Migration failure never
|
|
* triggers regeneration or fallback overwrite;
|
|
* an existing wrong-version blob returns ESP_ERR_INVALID_VERSION, while any
|
|
* malformed or cryptographically inconsistent blob returns
|
|
* ESP_ERR_INVALID_RESPONSE and is never overwritten. Call before radio startup
|
|
* so secure_random_init() can seed from the pre-radio entropy source.
|
|
*/
|
|
esp_err_t web_security_init(web_security_load_result_t *load_result);
|
|
|
|
/*
|
|
* Query with both outputs NULL/capacities zero. Certificate and key are copied
|
|
* under one lock so a concurrent rotation can never produce a mismatched pair.
|
|
*/
|
|
esp_err_t web_security_copy_tls_material(
|
|
uint8_t *certificate, size_t certificate_capacity,
|
|
size_t *certificate_length,
|
|
uint8_t *private_key, size_t private_key_capacity,
|
|
size_t *private_key_length);
|
|
|
|
|
|
esp_err_t web_security_get_certificate_metadata(
|
|
web_security_certificate_metadata_t *metadata);
|
|
|
|
typedef struct {
|
|
uint32_t generation;
|
|
uint8_t fingerprint[WEB_SECURITY_SHA256_LENGTH];
|
|
bool busy;
|
|
} web_security_identity_snapshot_t;
|
|
|
|
/* Zero-wait public metadata only; never returns DER or private material. */
|
|
esp_err_t web_security_get_identity_snapshot(web_security_identity_snapshot_t *snapshot);
|
|
|
|
/* Internal owner transaction shared with canonical mutations. Tokens never reuse.
|
|
* Reserve before crypto; retain through service restart. No lock stays held.
|
|
* Zero expected_generation selects canonical CLI semantics; reset permits recovery.
|
|
* Only the reserving owner may replace once and release its token. */
|
|
esp_err_t web_security_reserve_identity(uint32_t expected_generation, bool reset, uint32_t *token);
|
|
esp_err_t web_security_replace_reserved(uint32_t token);
|
|
void web_security_release_identity(uint32_t token);
|
|
|
|
/* Mutations become visible only after a complete blob has committed to NVS. */
|
|
|
|
esp_err_t web_security_rotate_certificate(void);
|
|
|
|
/* TLS ONLY: explicitly replaces missing, valid, or incompatible material.
|
|
* Generation increments from live state, or starts at one if unavailable.
|
|
* No user database mutation. */
|
|
esp_err_t web_security_reset_all(void);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|