1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

acme: adaptations through plat for esp32

This commit is contained in:
Andy Green 2017-11-26 09:22:42 +08:00
parent d7b6c04aaf
commit d58d749b30
21 changed files with 830 additions and 274 deletions

View file

@ -19,12 +19,12 @@ endif
build:
cd $(COMPONENT_BUILD_DIR) ; \
echo "doing lws cmake" ; \
cmake $(COMPONENT_PATH) -DLWS_C_FLAGS="$(CFLAGS) " \
cmake $(COMPONENT_PATH) -DLWS_C_FLAGS="$(CFLAGS) -DNDEBUG=1" \
-DIDF_PATH=$(IDF_PATH) \
-DCROSS_PATH=$(CROSS_PATH) \
-DBUILD_DIR_BASE=$(BUILD_DIR_BASE) \
-DCMAKE_TOOLCHAIN_FILE=$(COMPONENT_PATH)/contrib/cross-esp32.cmake \
-DCMAKE_BUILD_TYPE=DEBUG \
-DCMAKE_BUILD_TYPE=RELEASE \
-DLWS_MBEDTLS_INCLUDE_DIRS="${IDF_PATH}/components/openssl/include;${IDF_PATH}/components/mbedtls/include;${IDF_PATH}/components/mbedtls/port/include" \
-DLWS_WITH_STATS=0 \
-DLWS_WITH_HTTP2=1 \

View file

@ -52,8 +52,8 @@ static void *_realloc(void *ptr, size_t size, const char *reason)
{
if (size) {
#if defined(LWS_WITH_ESP32)
lwsl_notice("%s: size %lu: %s\n", __func__,
(unsigned long)size, reason);
lwsl_notice("%s: size %lu: %s (free heap %d)\n", __func__,
(unsigned long)size, reason, (unsigned int)esp_get_free_heap_size() - (int)size);
#else
lwsl_debug("%s: size %lu: %s\n", __func__,
(unsigned long)size, reason);

View file

@ -838,12 +838,12 @@ lws_create_vhost(struct lws_context *context,
vh->log_fd = (int)LWS_INVALID_FILE;
#endif
if (lws_context_init_server_ssl(info, vh))
goto bail;
goto bail1;
if (lws_context_init_client_ssl(info, vh))
goto bail;
goto bail1;
if (lws_context_init_server(info, vh)) {
lwsl_err("init server failed\n");
goto bail;
goto bail1;
}
while (1) {
@ -858,12 +858,19 @@ lws_create_vhost(struct lws_context *context,
if (context->protocol_init_done)
if (lws_protocol_init(context))
goto bail;
goto bail1;
return vh;
bail1:
lws_vhost_destroy(vh);
return NULL;
#ifdef LWS_WITH_ACCESS_LOG
bail:
lws_free(vh);
#endif
return NULL;
}

View file

@ -1496,7 +1496,7 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
h2n->inside += n;
h2n->count += n - 1;
lwsl_notice("%s: count %d len %d\n", __func__, (int)h2n->count, (int)h2n->length);
// lwsl_notice("%s: count %d len %d\n", __func__, (int)h2n->count, (int)h2n->length);
break;

View file

@ -571,6 +571,8 @@ struct lws_esp32 {
char access_pw[16];
char hostname[32];
char mac[20];
char le_dns[64];
char le_email[64];
mdns_server_t *mdns;
char region;
char inet;
@ -584,6 +586,8 @@ struct lws_esp32 {
struct lws_group_member *first;
int extant_group_members;
char acme;
volatile char button_is_down;
};
@ -836,6 +840,45 @@ struct lws_ssl_info {
int ret;
};
enum lws_cert_update_state {
LWS_CUS_IDLE,
LWS_CUS_STARTING,
LWS_CUS_SUCCESS,
LWS_CUS_FAILED,
LWS_CUS_CREATE_KEYS,
LWS_CUS_REG,
LWS_CUS_AUTH,
LWS_CUS_CHALLENGE,
LWS_CUS_CREATE_REQ,
LWS_CUS_REQ,
LWS_CUS_CONFIRM,
LWS_CUS_ISSUE,
};
enum {
LWS_TLS_REQ_ELEMENT_COUNTRY,
LWS_TLS_REQ_ELEMENT_STATE,
LWS_TLS_REQ_ELEMENT_LOCALITY,
LWS_TLS_REQ_ELEMENT_ORGANIZATION,
LWS_TLS_REQ_ELEMENT_COMMON_NAME,
LWS_TLS_REQ_ELEMENT_EMAIL,
LWS_TLS_REQ_ELEMENT_COUNT,
LWS_TLS_SET_DIR_URL = LWS_TLS_REQ_ELEMENT_COUNT,
LWS_TLS_SET_AUTH_PATH,
LWS_TLS_SET_CERT_PATH,
LWS_TLS_SET_KEY_PATH,
LWS_TLS_TOTAL_COUNT
};
struct lws_acme_cert_aging_args {
struct lws_vhost *vh;
const char *element_overrides[LWS_TLS_TOTAL_COUNT]; /* NULL = use pvo */
};
/*
* NOTE: These public enums are part of the abi. If you want to add one,
* add it at where specified so existing users are unaffected.
@ -1352,14 +1395,25 @@ enum lws_callback_reasons {
/**< When a vhost TLS cert has its expiry checked, this callback
* is broadcast to every protocol of every vhost in case the
* protocol wants to take some action with this information.
* \p in is the lws_vhost and \p len is the number of days left
* before it expires, as a (ssize_t) */
* \p in is a pointer to a struct lws_acme_cert_aging_args,
* and \p len is the number of days left before it expires, as
* a (ssize_t). In the struct lws_acme_cert_aging_args, vh
* points to the vhost the cert aging information applies to,
* and element_overrides[] is an optional way to update information
* from the pvos... NULL in an index means use the information from
* from the pvo for the cert renewal, non-NULL in the array index
* means use that pointer instead for the index. */
LWS_CALLBACK_TIMER = 73,
/**< When the time elapsed after a call to lws_set_timer(wsi, secs)
* is up, the wsi will get one of these callbacks. The deadline
* can be continuously extended into the future by later calls
* to lws_set_timer() before the deadline expires, or cancelled by
* lws_set_timer(wsi, -1); */
LWS_CALLBACK_VHOST_CERT_UPDATE = 74,
/**< When a vhost TLS cert is being updated, progress is
* reported to the vhost in question here, including completion
* and failure. in points to optional JSON, and len represents the
* connection state using enum lws_cert_update_state */
/****** add new things just above ---^ ******/
@ -5492,6 +5546,17 @@ lws_is_ssl(struct lws *wsi);
LWS_VISIBLE LWS_EXTERN int
lws_is_cgi(struct lws *wsi);
struct lws_wifi_scan { /* generic wlan scan item */
struct lws_wifi_scan *next;
char ssid[32];
int32_t rssi; /* divide by .count to get db */
uint8_t bssid[6];
uint8_t count;
uint8_t channel;
uint8_t authmode;
};
#if defined(LWS_OPENSSL_SUPPORT) && !defined(LWS_WITH_MBEDTLS)
/**
* lws_get_ssl() - Return wsi's SSL context structure
@ -5601,23 +5666,6 @@ LWS_VISIBLE LWS_EXTERN int
lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
const char *san_b);
enum {
LWS_TLS_REQ_ELEMENT_COUNTRY,
LWS_TLS_REQ_ELEMENT_STATE,
LWS_TLS_REQ_ELEMENT_LOCALITY,
LWS_TLS_REQ_ELEMENT_ORGANIZATION,
LWS_TLS_REQ_ELEMENT_COMMON_NAME,
LWS_TLS_REQ_ELEMENT_EMAIL,
LWS_TLS_REQ_ELEMENT_COUNT,
LWS_TLS_SET_DIR_URL = LWS_TLS_REQ_ELEMENT_COUNT,
LWS_TLS_SET_AUTH_PATH,
LWS_TLS_SET_CERT_PATH,
LWS_TLS_SET_KEY_PATH,
LWS_TLS_TOTAL_COUNT
};
/**
* lws_tls_acme_sni_csr_create() - creates a CSR and related private key PEM
*
@ -6614,31 +6662,31 @@ struct lejp_ctx {
/* arrays */
struct _lejp_stack st[LEJP_MAX_DEPTH];
unsigned short i[LEJP_MAX_INDEX_DEPTH]; /* index array */
unsigned short wild[LEJP_MAX_INDEX_DEPTH]; /* index array */
uint16_t i[LEJP_MAX_INDEX_DEPTH]; /* index array */
uint16_t wild[LEJP_MAX_INDEX_DEPTH]; /* index array */
char path[LEJP_MAX_PATH];
char buf[LEJP_STRING_CHUNK];
/* int */
unsigned int line;
uint32_t line;
/* short */
unsigned short uni;
uint16_t uni;
/* char */
unsigned char npos;
unsigned char dcount;
unsigned char f;
unsigned char sp; /* stack head */
unsigned char ipos; /* index stack depth */
unsigned char ppos;
unsigned char count_paths;
unsigned char path_match;
unsigned char path_match_len;
unsigned char wildcount;
uint8_t npos;
uint8_t dcount;
uint8_t f;
uint8_t sp; /* stack head */
uint8_t ipos; /* index stack depth */
uint8_t ppos;
uint8_t count_paths;
uint8_t path_match;
uint8_t path_match_len;
uint8_t wildcount;
};
LWS_VISIBLE LWS_EXTERN void

View file

@ -110,7 +110,7 @@ lws_poll_listen_fd(struct lws_pollfd *fd)
LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
{
printf("%d: %s", level, line);
lwsl_emit_stderr(level, line);
}
LWS_VISIBLE LWS_EXTERN int
@ -709,7 +709,7 @@ static const char *gapss_str[] = {
};
static romfs_t lws_esp32_romfs;
static TimerHandle_t leds_timer, scan_timer, debounce_timer
static TimerHandle_t leds_timer, scan_timer, debounce_timer, association_timer
#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
, mdns_timer
#endif
@ -811,6 +811,28 @@ static void lws_esp32_scan_timer_cb(TimerHandle_t th)
lwsl_err("scan start failed %d\n", n);
}
static void lws_esp32_assoc_timer_cb(TimerHandle_t th)
{
int n;
xTimerStop(association_timer, 0);
if (gapss == LWS_GAPSS_STAT_HAPPY) {
lwsl_debug("%s: saw we were happy\n", __func__);
return;
}
lwsl_notice("%s: forcing rescan\n", __func__);
lws_gapss_to(LWS_GAPSS_SCAN);
scan_ongoing = 0;
n = esp_wifi_scan_start(&scan_config, false);
if (n != ESP_OK)
lwsl_err("scan start failed %d\n", n);
}
#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
void __attribute__(( weak ))
@ -1018,7 +1040,7 @@ end_scan()
goto passthru;
if (gapss != LWS_GAPSS_SCAN) {
lwsl_notice("ignoring scan as gapss %s\n", gapss_str[gapss]);
lwsl_info("ignoring scan as gapss %s\n", gapss_str[gapss]);
goto passthru;
}
@ -1029,14 +1051,14 @@ end_scan()
!lws_esp32.ssid[3][0])
goto passthru;
lwsl_notice("checking %d scan records\n", count_ap_records);
lwsl_info("checking %d scan records\n", count_ap_records);
for (n = 0; n < 4; n++) {
if (!lws_esp32.ssid[(n + try_slot + 1) & 3][0])
continue;
lwsl_notice("looking for %s\n",
lwsl_debug("looking for %s\n",
lws_esp32.ssid[(n + try_slot + 1) & 3]);
/* this ssid appears in scan results? */
@ -1053,7 +1075,7 @@ end_scan()
hit:
m = (n + try_slot + 1) & 3;
try_slot = m;
lwsl_notice("Attempting connection with slot %d: %s:\n", m,
lwsl_info("Attempting connection with slot %d: %s:\n", m,
lws_esp32.ssid[m]);
/* set the ssid we last tried to connect to */
strncpy(lws_esp32.active_ssid, lws_esp32.ssid[m],
@ -1068,6 +1090,8 @@ hit:
tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA,
(const char *)&config.ap.ssid[7]);
lws_gapss_to(LWS_GAPSS_STAT);
xTimerStop(association_timer, 0);
xTimerStart(association_timer, 0);
esp_wifi_set_config(WIFI_IF_STA, &sta_config);
esp_wifi_connect();
@ -1484,6 +1508,8 @@ lws_esp32_wlan_config(void)
};
int n;
lwsl_debug("%s\n", __func__);
ledc_timer_config(&ledc_timer);
lws_set_genled(LWSESP32_GENLED__INIT);
@ -1496,6 +1522,8 @@ lws_esp32_wlan_config(void)
(TimerCallbackFunction_t)lws_esp32_scan_timer_cb);
debounce_timer = xTimerCreate("lws_db", pdMS_TO_TICKS(100), 0, NULL,
(TimerCallbackFunction_t)lws_esp32_debounce_timer_cb);
association_timer = xTimerCreate("lws_assoc", pdMS_TO_TICKS(10000), 0, NULL,
(TimerCallbackFunction_t)lws_esp32_assoc_timer_cb);
#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
mdns_timer = xTimerCreate("lws_mdns", pdMS_TO_TICKS(5000), 0, NULL,
@ -1667,13 +1695,13 @@ lws_esp32_set_creation_defaults(struct lws_context_creation_info *info)
info->vhost_name = "default";
info->port = 443;
info->fd_limit_per_thread = 30;
info->max_http_header_pool = 16;
info->max_http_header_data = 512;
info->pt_serv_buf_size = 2048;
info->fd_limit_per_thread = 16;
info->max_http_header_pool = 5;
info->max_http_header_data = 1024;
info->pt_serv_buf_size = 4096;
info->keepalive_timeout = 30;
info->timeout_secs = 30;
info->simultaneous_ssl_restriction = 4;
info->simultaneous_ssl_restriction = 2;
info->options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
}
@ -1851,6 +1879,22 @@ fail:
return -1;
}
void
lws_esp32_update_acme_info(void)
{
int n;
n = lws_plat_read_file("acme-email", lws_esp32.le_email,
sizeof(lws_esp32.le_email) - 1);
if (n >= 0)
lws_esp32.le_email[n] = '\0';
n = lws_plat_read_file("acme-cn", lws_esp32.le_dns,
sizeof(lws_esp32.le_dns) - 1);
if (n >= 0)
lws_esp32.le_dns[n] = '\0';
}
struct lws_context *
lws_esp32_init(struct lws_context_creation_info *info, struct lws_vhost **pvh)
{
@ -1893,6 +1937,8 @@ lws_esp32_init(struct lws_context_creation_info *info, struct lws_vhost **pvh)
return NULL;
}
lws_esp32_update_acme_info();
lws_esp32_selfsigned(vhost);
wsi.context = vhost->context;
wsi.vhost = vhost;
@ -1960,16 +2006,16 @@ lws_plat_write_file(const char *filename, void *buf, int len)
if (nvs_open("lws-station", NVS_READWRITE, &nvh)) {
lwsl_notice("%s: failed to open nvs\n", __func__);
return 1;
return -1;
}
n = nvs_set_blob(nvh, filename, buf, len);
if (n)
if (n >= 0)
nvs_commit(nvh);
nvs_close(nvh);
lwsl_notice("%s: wrote %s\n", __func__, filename);
lwsl_notice("%s: wrote %s (%d)\n", __func__, filename, n);
return n;
}
@ -1985,7 +2031,7 @@ lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
if (is_key)
name = vhost->key_path;
return lws_plat_write_file(name, buf, len);
return lws_plat_write_file(name, buf, len) < 0;
}
LWS_VISIBLE int

View file

@ -1000,6 +1000,7 @@ struct lws_vhost {
unsigned int created_vhost_protocols:1;
unsigned int being_destroyed:1;
unsigned int skipped_certs:1;
unsigned int acme_challenge:1;
unsigned char default_protocol_index;
unsigned char raw_protocol_index;

View file

@ -2540,10 +2540,13 @@ try_pollout:
case LWSCM_SERVER_LISTENER:
#if LWS_POSIX
/* pollin means a client has connected to us then */
/* pollin means a client has connected to us then
* pollout is a hack on esp32 for background accepts signalling
* they completed
* */
do {
if (!(pollfd->revents & LWS_POLLIN) ||
if (!(pollfd->revents & (LWS_POLLIN |LWS_POLLOUT)) ||
!(pollfd->events & LWS_POLLIN))
break;

View file

@ -88,9 +88,10 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
lws_tls_server_client_cert_verify_config(vhost);
vhost->protocols[0].callback(&wsi,
LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
vhost->ssl_ctx, vhost, 0);
if (vhost->protocols[0].callback(&wsi,
LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
vhost->ssl_ctx, vhost, 0))
return -1;
}
if (vhost->use_ssl)
@ -142,6 +143,11 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
context->simultaneous_ssl_restriction)
/* that was the last allowed SSL connection */
lws_gate_accepts(context, 0);
//lwsl_notice("%s: ssl restr %d, simul %d\n", __func__,
// context->simultaneous_ssl_restriction,
// context->simultaneous_ssl);
#if defined(LWS_WITH_STATS)
context->updated = 1;
#endif

View file

@ -1000,7 +1000,7 @@ completed:
if (user_callback_handle_rxflow(wsi->protocol->callback,
wsi, LWS_CALLBACK_COMPLETED_CLIENT_HTTP,
wsi->user_space, NULL, 0)) {
lwsl_debug("Completed call returned -1\n");
lwsl_debug("%s: Completed call returned nonzero (mode %d)\n", __func__, wsi->mode);
return -1;
}

View file

@ -213,6 +213,7 @@ lws_tls_server_vhost_backend_init(struct lws_context_creation_info *info,
const SSL_METHOD *method = TLS_server_method();
uint8_t *p;
lws_filepos_t flen;
int n;
vhost->ssl_ctx = SSL_CTX_new(method); /* create context */
if (!vhost->ssl_ctx) {
@ -243,10 +244,13 @@ lws_tls_server_vhost_backend_init(struct lws_context_creation_info *info,
free(p);
}
return lws_tls_server_certs_load(vhost, wsi,
info->ssl_cert_filepath,
info->ssl_private_key_filepath,
NULL, 0, NULL, 0);
n = lws_tls_server_certs_load(vhost, wsi, info->ssl_cert_filepath,
info->ssl_private_key_filepath, NULL,
0, NULL, 0);
if (n)
return n;
return 0;
}
int
@ -284,9 +288,17 @@ enum lws_ssl_capable_status
lws_tls_server_accept(struct lws *wsi)
{
union lws_tls_cert_info_results ir;
int m, n = SSL_accept(wsi->ssl);
int m, n;
n = SSL_accept(wsi->ssl);
if (n == 1) {
if (strstr(wsi->vhost->name, ".invalid")) {
lwsl_notice("%s: vhost has .invalid, rejecting accept\n", __func__);
return LWS_SSL_CAPABLE_ERROR;
}
n = lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_COMMON_NAME, &ir,
sizeof(ir.ns.name));
if (!n)
@ -298,6 +310,8 @@ lws_tls_server_accept(struct lws *wsi)
}
m = SSL_get_error(wsi->ssl, n);
lwsl_debug("%s: %p: accept SSL_get_error %d errno %d\n", __func__,
wsi, m, errno);
// mbedtls wrapper only
if (m == SSL_ERROR_SYSCALL && errno == 11)
@ -439,7 +453,7 @@ lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
uint8_t digest[32];
struct lws_genhash_ctx hash_ctx;
int pkey_asn1_len = 3 * 1024;
int n, keybits = lws_plat_recommended_rsa_bits(), adj;
int n, m, keybits = lws_plat_recommended_rsa_bits(), adj;
if (!buf)
return 1;
@ -522,35 +536,35 @@ lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
if (!pkey_asn1)
goto bail2;
n = lws_genrsa_render_pkey_asn1(&ctx, 1, pkey_asn1, pkey_asn1_len);
if (n < 0) {
m = lws_genrsa_render_pkey_asn1(&ctx, 1, pkey_asn1, pkey_asn1_len);
if (m < 0) {
lws_free(pkey_asn1);
goto bail2;
}
lwsl_debug("private key\n");
lwsl_hexdump_level(LLL_DEBUG, pkey_asn1, n);
/* and to use our generated private key */
n = SSL_CTX_use_PrivateKey_ASN1(0, vhost->ssl_ctx, pkey_asn1, n);
lws_free(pkey_asn1);
// lwsl_hexdump_level(LLL_DEBUG, buf, lws_ptr_diff(p, buf));
n = SSL_CTX_use_certificate_ASN1(vhost->ssl_ctx,
lws_ptr_diff(p, buf), buf);
if (n != 1) {
lwsl_notice("%s: SSL_CTX_use_PrivateKey_ASN1 failed\n",
__func__);
lws_free(pkey_asn1);
lwsl_err("%s: generated cert failed to load 0x%x\n",
__func__, -n);
} else {
//lwsl_debug("private key\n");
//lwsl_hexdump_level(LLL_DEBUG, pkey_asn1, n);
/* and to use our generated private key */
n = SSL_CTX_use_PrivateKey_ASN1(0, vhost->ssl_ctx, pkey_asn1, m);
lws_free(pkey_asn1);
if (n != 1) {
lwsl_err("%s: SSL_CTX_use_PrivateKey_ASN1 failed\n",
__func__);
}
}
lws_genrsa_destroy(&ctx);
lws_jwk_destroy_genrsa_elements(&el);
if (n == 1) {
lwsl_hexdump_level(LLL_DEBUG, buf, lws_ptr_diff(p, buf));
n = SSL_CTX_use_certificate_ASN1(vhost->ssl_ctx,
lws_ptr_diff(p, buf), buf);
if (n != 1)
lwsl_notice("%s: generated cert failed to load 0x%x\n",
__func__, -n);
}
lws_free(buf);
return n != 1;
@ -579,6 +593,8 @@ _rngf(void *context, unsigned char *buf, size_t len)
return -1;
}
static const char *x5[] = { "C", "ST", "L", "O", "CN" };
/*
* CSR is output formatted as b64url(DER)
* Private key is output as a PEM in memory
@ -589,9 +605,9 @@ lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
size_t *privkey_len)
{
mbedtls_x509write_csr csr;
char subject[200];
mbedtls_pk_context mpk;
int buf_size = 4096, n;
char subject[200], *p = subject, *end = p + sizeof(subject) - 1;
uint8_t *buf = malloc(buf_size); /* malloc because given to user code */
if (!buf)
@ -615,13 +631,14 @@ lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
/* subject must be formatted like "C=TW,O=warmcat,CN=myserver" */
lws_snprintf(subject, sizeof(subject) - 1,
"C=%s,ST=%s,L=%s,O=%s,CN=%s",
elements[LWS_TLS_REQ_ELEMENT_COUNTRY],
elements[LWS_TLS_REQ_ELEMENT_STATE],
elements[LWS_TLS_REQ_ELEMENT_LOCALITY],
elements[LWS_TLS_REQ_ELEMENT_ORGANIZATION],
elements[LWS_TLS_REQ_ELEMENT_COMMON_NAME]);
for (n = 0; n < ARRAY_SIZE(x5); n++) {
if (p != subject)
*p++ = ',';
if (elements[n])
p += lws_snprintf(p, end - p, "%s=%s", x5[n],
elements[n]);
}
if (mbedtls_x509write_csr_set_subject_name(&csr, subject))
goto fail1;

View file

@ -257,11 +257,16 @@ lws_ssl_close(struct lws *wsi)
SSL_free(wsi->ssl);
wsi->ssl = NULL;
if (wsi->context->simultaneous_ssl_restriction &&
if (!(wsi->mode & LWSCM_FLAG_IMPLIES_CALLBACK_CLOSED_CLIENT_HTTP) &&
wsi->context->simultaneous_ssl_restriction &&
wsi->context->simultaneous_ssl-- ==
wsi->context->simultaneous_ssl_restriction)
/* we made space and can do an accept */
lws_gate_accepts(wsi->context, 1);
//lwsl_notice("%s: ssl restr %d, simul %d\n", __func__,
// wsi->context->simultaneous_ssl_restriction,
// wsi->context->simultaneous_ssl);
#if defined(LWS_WITH_STATS)
wsi->context->updated = 1;
#endif

View file

@ -25,6 +25,8 @@
#include "mbedtls/error.h"
#include "mbedtls/certs.h"
#include <libwebsockets.h>
#define X509_INFO_STRING_LENGTH 8192
struct ssl_pm
@ -64,7 +66,7 @@ unsigned int max_content_len;
/*********************************************************************************************/
/************************************ SSL arch interface *************************************/
#ifdef CONFIG_OPENSSL_LOWLEVEL_DEBUG
//#ifdef CONFIG_OPENSSL_LOWLEVEL_DEBUG
/* mbedtls debug level */
#define MBEDTLS_DEBUG_LEVEL 4
@ -81,13 +83,13 @@ static void ssl_platform_debug(void *ctx, int level,
This is a bit wasteful because the macros are compiled in with
the full _FILE_ path in each case.
*/
char *file_sep = rindex(file, '/');
if(file_sep)
file = file_sep + 1;
// char *file_sep = rindex(file, '/');
// if(file_sep)
// file = file_sep + 1;
SSL_DEBUG(SSL_DEBUG_ON, "%s:%d %s", file, line, str);
printf("%s:%d %s", file, line, str);
}
#endif
//#endif
/**
* @brief create SSL low-level object
@ -163,12 +165,12 @@ int ssl_pm_new(SSL *ssl)
mbedtls_ssl_conf_rng(&ssl_pm->conf, mbedtls_ctr_drbg_random, &ssl_pm->ctr_drbg);
#ifdef CONFIG_OPENSSL_LOWLEVEL_DEBUG
mbedtls_debug_set_threshold(MBEDTLS_DEBUG_LEVEL);
//#ifdef CONFIG_OPENSSL_LOWLEVEL_DEBUG
// mbedtls_debug_set_threshold(MBEDTLS_DEBUG_LEVEL);
// mbedtls_ssl_conf_dbg(&ssl_pm->conf, ssl_platform_debug, NULL);
//#else
mbedtls_ssl_conf_dbg(&ssl_pm->conf, ssl_platform_debug, NULL);
#else
mbedtls_ssl_conf_dbg(&ssl_pm->conf, NULL, NULL);
#endif
//#endif
ret = mbedtls_ssl_setup(&ssl_pm->ssl, &ssl_pm->conf);
if (ret) {
@ -265,7 +267,7 @@ static int mbedtls_handshake( mbedtls_ssl_context *ssl )
while (ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER) {
ret = mbedtls_ssl_handshake_step(ssl);
SSL_DEBUG(SSL_PLATFORM_DEBUG_LEVEL, "ssl ret %d state %d", ret, ssl->state);
lwsl_notice("%s: ssl ret -%x state %d\n", __func__, -ret, ssl->state);
if (ret != 0)
break;
@ -274,14 +276,23 @@ static int mbedtls_handshake( mbedtls_ssl_context *ssl )
return ret;
}
#include <errno.h>
int ssl_pm_handshake(SSL *ssl)
{
int ret;
struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
lwsl_notice("%s\n", __func__);
ssl->err = 0;
errno = 0;
ret = ssl_pm_reload_crt(ssl);
if (ret)
if (ret) {
printf("%s: cert reload failed\n", __func__);
return 0;
}
if (ssl_pm->ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER) {
ssl_speed_up_enter();
@ -302,6 +313,7 @@ int ssl_pm_handshake(SSL *ssl)
* <0 = death
*/
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
ssl->err = ret;
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_handshake() return -0x%x", -ret);
return 0; /* OpenSSL: did not complete but may be retried */
}
@ -313,6 +325,14 @@ int ssl_pm_handshake(SSL *ssl)
return 1; /* openssl successful */
}
if (errno == 11) {
ssl->err = ret == MBEDTLS_ERR_SSL_WANT_READ;
return 0;
}
printf("%s: mbedtls_ssl_handshake() returned -0x%x\n", __func__, -ret);
/* it's had it */
ssl->err = SSL_ERROR_SYSCALL;
@ -377,7 +397,7 @@ int ssl_pm_read(SSL *ssl, void *buffer, int len)
ret = mbedtls_ssl_read(&ssl_pm->ssl, buffer, len);
if (ret < 0) {
//printf("%s: mbedtls_ssl_read says -0x%x\n", __func__, -ret);
// lwsl_notice("%s: mbedtls_ssl_read says -0x%x\n", __func__, -ret);
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_read() return -0x%x", -ret);
if (ret == MBEDTLS_ERR_NET_CONN_RESET ||
ret <= MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE) /* fatal errors */

View file

@ -282,7 +282,7 @@ check_key:
lwsl_err("%s: no extra certs\n", __func__);
#endif
if (!x) {
lwsl_err("%s: x is NULL\n", __func__);
//lwsl_err("%s: x is NULL\n", __func__);
goto post_ecdh;
}
/* Get the public key from certificate */

View file

@ -401,6 +401,11 @@ lws_ssl_close(struct lws *wsi)
wsi->context->simultaneous_ssl_restriction)
/* we made space and can do an accept */
lws_gate_accepts(wsi->context, 1);
// lwsl_notice("%s: ssl restr %d, simul %d\n", __func__,
// wsi->context->simultaneous_ssl_restriction,
// wsi->context->simultaneous_ssl);
#if defined(LWS_WITH_STATS)
wsi->context->updated = 1;
#endif

View file

@ -225,6 +225,7 @@ lws_tls_check_cert_lifetime(struct lws_vhost *v)
{
union lws_tls_cert_info_results ir;
time_t now = (time_t)lws_now_secs(), life = 0;
struct lws_acme_cert_aging_args caa;
int n;
if (v->ssl_ctx && !v->skipped_certs) {
@ -242,7 +243,9 @@ lws_tls_check_cert_lifetime(struct lws_vhost *v)
} else
lwsl_notice(" vhost %s: no cert\n", v->name);
lws_broadcast(v->context, LWS_CALLBACK_VHOST_CERT_AGING, v,
memset(&caa, 0, sizeof(caa));
caa.vh = v;
lws_broadcast(v->context, LWS_CALLBACK_VHOST_CERT_AGING, (void *)&caa,
(size_t)(ssize_t)life);
return 0;
@ -446,7 +449,7 @@ lws_gate_accepts(struct lws_context *context, int on)
{
struct lws_vhost *v = context->vhost_list;
lwsl_info("gating accepts %d\n", on);
lwsl_notice("%s: on = %d\n", __func__, on);
context->ssl_gate_accepts = !on;
#if defined(LWS_WITH_STATS)
context->updated = 1;
@ -456,7 +459,7 @@ lws_gate_accepts(struct lws_context *context, int on)
if (v->use_ssl && v->lserv_wsi &&
lws_change_pollfd(v->lserv_wsi, (LWS_POLLIN) * !on,
(LWS_POLLIN) * on))
lwsl_info("Unable to set accept POLLIN %d\n", on);
lwsl_notice("Unable to set accept POLLIN %d\n", on);
v = v->vhost_next;
}

View file

@ -56,6 +56,7 @@ struct acme_connection {
char replay_nonce[64];
char chall_token[64];
char challenge_uri[256];
char detail[64];
char status[16];
char san_a[100];
char san_b[100];
@ -105,6 +106,7 @@ struct per_vhost_data__lws_acme_client {
char *pvo_data;
char *pvop[LWS_TLS_TOTAL_COUNT];
const char *pvop_active[LWS_TLS_TOTAL_COUNT];
int count_live_pss;
char *dest;
int pos;
@ -191,6 +193,7 @@ static const char * const jauthz_tok[] = {
"challenges[].status",
"challenges[].uri",
"challenges[].token",
"detail"
};
enum enum_jauthz_tok {
JAAZ_ID_TYPE,
@ -201,6 +204,7 @@ enum enum_jauthz_tok {
JAAZ_CHALLENGES_STATUS,
JAAZ_CHALLENGES_URI,
JAAZ_CHALLENGES_TOKEN,
JAAZ_DETAIL,
};
static signed char
cb_authz(struct lejp_ctx *ctx, char reason)
@ -226,6 +230,9 @@ cb_authz(struct lejp_ctx *ctx, char reason)
break;
case JAAZ_EXPIRES:
break;
case JAAZ_DETAIL:
lws_snprintf(s->detail, sizeof(s->detail), "%s", ctx->buf);
break;
case JAAZ_CHALLENGES_TYPE:
if (s->is_sni_02)
break;
@ -263,12 +270,14 @@ static const char * const jchac_tok[] = {
"status",
"uri",
"token",
"error.detail"
};
enum enum_jchac_tok {
JCAC_TYPE,
JCAC_STATUS,
JCAC_URI,
JCAC_TOKEN,
JCAC_DETAIL,
};
static signed char
cb_chac(struct lejp_ctx *ctx, char reason)
@ -300,6 +309,9 @@ cb_chac(struct lejp_ctx *ctx, char reason)
sizeof(s->chall_token) - 1);
s->yes |= 1;
break;
case JCAC_DETAIL:
lws_snprintf(s->detail, sizeof(s->detail), "%s", ctx->buf);
break;
}
return 0;
@ -328,6 +340,14 @@ cb_chac(struct lejp_ctx *ctx, char reason)
* (ie, just use new-cert instead of new-order, use the directory for links)
*/
static int
lws_acme_report_status(struct lws_vhost *v, int state, const char *json)
{
lws_callback_vhost_protocols_vhost(v, LWS_CALLBACK_VHOST_CERT_UPDATE,
(void *)json, state);
return 0;
}
/*
* Notice: trashes i and url
@ -339,6 +359,7 @@ lws_acme_client_connect(struct lws_context *context, struct lws_vhost *vh,
{
const char *prot, *p;
char path[200], _url[256];
struct lws *wsi;
memset(i, 0, sizeof(*i));
i->port = 443;
@ -364,13 +385,21 @@ lws_acme_client_connect(struct lws_context *context, struct lws_vhost *vh,
i->pwsi = pwsi;
i->protocol = "lws-acme-client";
return lws_client_connect_via_info(i);
wsi = lws_client_connect_via_info(i);
if (!wsi) {
lws_snprintf(path, sizeof(path) - 1,
"Unable to connect to %s", url);
lwsl_notice("%s: %s\n", __func__, path);
lws_acme_report_status(vh, LWS_CUS_FAILED, path);
}
return wsi;
}
static void
lws_acme_finished(struct per_vhost_data__lws_acme_client *vhd)
{
lwsl_notice("finishing up jws stuff\n");
lwsl_debug("%s\n", __func__);
if (vhd->ac) {
if (vhd->ac->vhost)
@ -384,6 +413,9 @@ lws_acme_finished(struct per_vhost_data__lws_acme_client *vhd)
lws_jwk_destroy(&vhd->jwk);
vhd->ac = NULL;
#if defined(LWS_WITH_ESP32)
lws_esp32.acme = 0; /* enable scanning */
#endif
}
static const char * const pvo_names[] = {
@ -399,6 +431,113 @@ static const char * const pvo_names[] = {
"key-path",
};
static int
lws_acme_load_create_auth_keys(struct per_vhost_data__lws_acme_client *vhd,
int bits)
{
int n;
if (!lws_jwk_load(&vhd->jwk, vhd->pvop[LWS_TLS_SET_AUTH_PATH]))
return 0;
strcpy(vhd->jwk.keytype, "RSA");
lwsl_notice("Generating ACME %d-bit keypair... "
"will take a little while\n", bits);
n = lws_genrsa_new_keypair(vhd->context, &vhd->rsactx, &vhd->jwk.el,
bits);
if (n) {
lwsl_notice("failed to create keypair\n");
return 1;
}
lwsl_notice("...keypair generated\n");
if (lws_jwk_save(&vhd->jwk,
vhd->pvop[LWS_TLS_SET_AUTH_PATH])) {
lwsl_notice("unable to save %s\n",
vhd->pvop[LWS_TLS_SET_AUTH_PATH]);
return 1;
}
return 0;
}
static int
lws_acme_start_acquisition(struct per_vhost_data__lws_acme_client *vhd,
struct lws_vhost *v)
{
char buf[128];
/* ...and we were given enough info to do the update? */
if (!vhd->pvop[LWS_TLS_REQ_ELEMENT_COMMON_NAME])
return -1;
/*
* ...well... we should try to do something about it then...
*/
lwsl_notice("%s: ACME cert needs creating / updating: "
"vhost %s\n", __func__, lws_get_vhost_name(vhd->vhost));
vhd->ac = malloc(sizeof(*vhd->ac));
memset(vhd->ac, 0, sizeof(*vhd->ac));
/*
* So if we don't have it, the first job is get the directory.
*
* If we already have the directory, jump straight into trying
* to register our key.
*
* We always try to register the keys... if it's not the first
* time, we will get a JSON body in the (legal, nonfatal)
* response like this
*
* {
* "type": "urn:acme:error:malformed",
* "detail": "Registration key is already in use",
* "status": 409
* }
*/
if (!vhd->ac->urls[0][0]) {
vhd->ac->state = ACME_STATE_DIRECTORY;
lws_snprintf(buf, sizeof(buf) - 1, "%s",
vhd->pvop_active[LWS_TLS_SET_DIR_URL]);
} else {
vhd->ac->state = ACME_STATE_NEW_REG;
lws_snprintf(buf, sizeof(buf) - 1, "%s",
vhd->ac->urls[JAD_NEW_REG_URL]);
}
vhd->ac->real_vh_port = lws_get_vhost_port(vhd->vhost);
vhd->ac->real_vh_name = lws_get_vhost_name(vhd->vhost);
vhd->ac->real_vh_iface = lws_get_vhost_iface(vhd->vhost);
lws_acme_report_status(vhd->vhost, LWS_CUS_STARTING, NULL);
#if defined(LWS_WITH_ESP32)
lws_acme_report_status(vhd->vhost, LWS_CUS_CREATE_KEYS,
"Generating keys, please wait");
if (lws_acme_load_create_auth_keys(vhd, 2048))
goto bail;
lws_acme_report_status(vhd->vhost, LWS_CUS_CREATE_KEYS,
"Auth keys created");
#endif
if (lws_acme_client_connect(vhd->context, vhd->vhost,
&vhd->ac->cwsi, &vhd->ac->i, buf, "GET"))
return 0;
#if defined(LWS_WITH_ESP32)
bail:
#endif
free(vhd->ac);
vhd->ac = NULL;
return 1;
}
static int
callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
@ -408,10 +547,11 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
lws_protocol_vh_priv_get(lws_get_vhost(wsi),
lws_get_protocol(wsi));
char buf[LWS_PRE + 2536], *start = buf + LWS_PRE, *p = start,
*end = buf + sizeof(buf) - 1, digest[32];
unsigned char **pp = (unsigned char **)in, *pend = in + len;
const char *content_type = "application/jose+json";
*end = buf + sizeof(buf) - 1, digest[32], *failreason = NULL;
unsigned char **pp, *pend;
const char *content_type;
const struct lws_protocol_vhost_options *pvo;
struct lws_acme_cert_aging_args *caa;
struct acme_connection *ac = NULL;
struct lws_genhash_ctx hctx;
struct lws *cwsi;
@ -420,7 +560,7 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
if (vhd)
ac = vhd->ac;
switch (reason) {
switch ((int)reason) {
case LWS_CALLBACK_PROTOCOL_INIT:
vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
lws_get_protocol(wsi),
@ -461,8 +601,9 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
pvo_names[m]);
n |= 1;
} else
lwsl_info(" %s: %s\n", pvo_names[m],
vhd->pvop[m]);
if (vhd->pvop[m])
lwsl_info(" %s: %s\n", pvo_names[m],
vhd->pvop[m]);
if (n) {
free(vhd->pvo_data);
vhd->pvo_data = NULL;
@ -470,30 +611,14 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
return -1;
}
#if !defined(LWS_WITH_ESP32)
/*
* load (or create) the registration keypair while we
* still have root
*/
if (lws_jwk_load(&vhd->jwk,
vhd->pvop[LWS_TLS_SET_AUTH_PATH])) {
strcpy(vhd->jwk.keytype, "RSA");
n = lws_genrsa_new_keypair(lws_get_context(wsi),
&vhd->rsactx, &vhd->jwk.el,
4096);
if (n) {
lwsl_notice("failed to create keypair\n");
if (lws_acme_load_create_auth_keys(vhd, 4096))
return 1;
return 1;
}
if (lws_jwk_save(&vhd->jwk,
vhd->pvop[LWS_TLS_SET_AUTH_PATH])) {
lwsl_notice("unable to save %s\n",
vhd->pvop[LWS_TLS_SET_AUTH_PATH]);
return 1;
}
}
/*
* in case we do an update, open the update files while we
* still have root
@ -514,6 +639,7 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
lwsl_err("unable to create update key file %s\n", buf);
return -1;
}
#endif
break;
case LWS_CALLBACK_PROTOCOL_DESTROY:
@ -528,6 +654,8 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
case LWS_CALLBACK_VHOST_CERT_AGING:
if (!vhd)
break;
caa = (struct lws_acme_cert_aging_args *)in;
/*
* Somebody is telling us about a cert some vhost is using.
*
@ -536,64 +664,23 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
*/
if ((int)(ssize_t)len > 14)
break;
/*
* ...is this a vhost we were configured on?
*/
if (vhd->vhost != (struct lws_vhost *)in)
break;
if (vhd->vhost != caa->vh)
return 1;
/* ...and we were given enough info to do the update? */
for (n = 0; n < (int)ARRAY_SIZE(vhd->pvop);n++)
if (caa->element_overrides[n])
vhd->pvop_active[n] = caa->element_overrides[n];
else
vhd->pvop_active[n] = vhd->pvop[n];
if (!vhd->pvop[LWS_TLS_REQ_ELEMENT_COUNTRY])
break;
lwsl_notice("starting acme acquisition on %s: %s\n",
lws_get_vhost_name(caa->vh), vhd->pvop_active[LWS_TLS_SET_DIR_URL]);
/*
* ...well... we should try to do something about it then...
*/
lwsl_notice("%s: ACME cert needs updating: "
"vhost %s: %dd left\n", __func__,
lws_get_vhost_name(in), (int)(ssize_t)len);
vhd->ac = ac = malloc(sizeof(*vhd->ac));
memset(ac, 0, sizeof(*ac));
/*
* So if we don't have it, the first job is get the directory.
*
* If we already have the directory, jump straight into trying
* to register our key.
*
* We always try to register the keys... if it's not the first
* time, we will get a JSON body in the (legal, nonfatal)
* response like this
*
* {
* "type": "urn:acme:error:malformed",
* "detail": "Registration key is already in use",
* "status": 409
* }
*/
if (!ac->urls[0][0]) {
ac->state = ACME_STATE_DIRECTORY;
lws_snprintf(buf, sizeof(buf) - 1, "%s",
vhd->pvop[LWS_TLS_SET_DIR_URL]);
} else {
ac->state = ACME_STATE_NEW_REG;
lws_snprintf(buf, sizeof(buf) - 1, "%s",
ac->urls[JAD_NEW_REG_URL]);
}
ac->real_vh_port = lws_get_vhost_port((struct lws_vhost *)in);
ac->real_vh_name = lws_get_vhost_name((struct lws_vhost *)in);
ac->real_vh_iface = lws_get_vhost_iface((struct lws_vhost *)in);
cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
&ac->cwsi, &ac->i, buf, "GET");
if (!cwsi) {
lwsl_notice("%s: acme connect failed\n", __func__);
free(vhd->ac);
vhd->ac = NULL;
}
lws_acme_start_acquisition(vhd, caa->vh);
break;
/*
@ -605,11 +692,15 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
break;
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
lwsl_notice("%s: CLIENT_CONNECTION_ERROR\n", __func__);
lwsl_notice("%s: CLIENT_CONNECTION_ERROR: %p\n", __func__, wsi);
break;
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
lwsl_notice("%s: CLOSED_CLIENT_HTTP\n", __func__);
lwsl_notice("%s: CLOSED_CLIENT_HTTP: %p\n", __func__, wsi);
break;
case LWS_CALLBACK_CLOSED:
lwsl_notice("%s: CLOSED: %p\n", __func__, wsi);
break;
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
@ -625,7 +716,7 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
WSI_TOKEN_REPLAY_NONCE) < 0) {
lwsl_notice("%s: nonce too large\n", __func__);
return -1;
goto failed;
}
switch (ac->state) {
@ -687,8 +778,10 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
"\"mailto:%s\""
"],\"agreement\":\"%s\""
"}",
vhd->pvop[LWS_TLS_REQ_ELEMENT_EMAIL],
vhd->pvop_active[LWS_TLS_REQ_ELEMENT_EMAIL],
ac->urls[JAD_TOS_URL]);
puts(start);
pkt_add_hdrs:
ac->len = lws_jws_create_packet(&vhd->jwk,
start, p - start,
@ -701,23 +794,33 @@ pkt_add_hdrs:
lwsl_notice("lws_jws_create_packet failed\n");
goto failed;
}
pp = (unsigned char **)in;
pend = (*pp) + len;
ac->pos = 0;
content_type = "application/jose+json";
if (ac->state == ACME_STATE_POLLING_CSR)
content_type = "application/pkix-cert";
if (lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_CONTENT_TYPE,
(uint8_t *)content_type, 21, pp, pend))
(uint8_t *)content_type, 21, pp, pend)) {
lwsl_notice("could not add content type\n");
goto failed;
}
n = sprintf(buf, "%d", ac->len);
if (lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_CONTENT_LENGTH,
(uint8_t *)buf, n, pp, pend))
(uint8_t *)buf, n, pp, pend)) {
lwsl_notice("could not add content length\n");
goto failed;
}
lws_client_http_body_pending(wsi, 1);
lws_callback_on_writable(wsi);
lwsl_notice("prepare to send ACME_STATE_NEW_REG\n");
break;
case ACME_STATE_NEW_AUTH:
p += lws_snprintf(p, end - p,
@ -727,7 +830,7 @@ pkt_add_hdrs:
"\"type\":\"http-01\","
"\"value\":\"%s\""
"}"
"}", ac->real_vh_name);
"}", vhd->pvop_active[LWS_TLS_REQ_ELEMENT_COMMON_NAME]);
goto pkt_add_hdrs;
case ACME_STATE_ACCEPT_CHALL:
@ -842,8 +945,7 @@ pkt_add_hdrs:
"{\"resource\":\"new-cert\","
"\"csr\":\"");
n = lws_tls_acme_sni_csr_create(vhd->context,
(const char **)
vhd->pvop,
&vhd->pvop_active[0],
(uint8_t *)p, end - p,
&ac->alloc_privkey_pem,
&ac->len_privkey_pem);
@ -948,15 +1050,18 @@ pkt_add_hdrs:
* not complete for some reason...
*/
ac->state = ACME_STATE_NEW_REG;
lws_acme_report_status(vhd->vhost, LWS_CUS_REG, NULL);
strcpy(buf, ac->urls[JAD_NEW_REG_URL]);
cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
&ac->cwsi, &ac->i, buf,
"POST");
if (!cwsi)
if (!cwsi) {
lwsl_notice("%s: failed to connect to acme\n",
__func__);
break;
goto failed;
}
return -1; /* close the completed client connection */
case ACME_STATE_NEW_REG:
if ((ac->resp >= 200 && ac->resp < 299) ||
@ -967,6 +1072,8 @@ pkt_add_hdrs:
* Move on to requesting a cert auth.
*/
ac->state = ACME_STATE_NEW_AUTH;
lws_acme_report_status(vhd->vhost, LWS_CUS_AUTH,
NULL);
strcpy(buf, ac->urls[JAD_NEW_AUTHZ_URL]);
cwsi = lws_acme_client_connect(vhd->context,
@ -975,16 +1082,32 @@ pkt_add_hdrs:
if (!cwsi)
lwsl_notice("%s: failed to connect\n",
__func__);
break;
return -1; /* close the completed client connection */
} else {
lwsl_notice("new-reg replied %d\n", ac->resp);
goto failed;
}
break;
return -1; /* close the completed client connection */
case ACME_STATE_NEW_AUTH:
lejp_destruct(&ac->jctx);
lwsl_notice("chall: %s\n", ac->chall_token);
if (ac->resp / 100 == 4) {
lws_snprintf(buf, sizeof(buf),
"Auth failed: %s", ac->detail);
failreason = buf;
lwsl_notice("auth failed\n");
goto failed;
}
lwsl_notice("chall: %s (%d)\n", ac->chall_token, ac->resp);
if (!ac->chall_token[0]) {
lwsl_notice("no challenge\n");
goto failed;
}
ac->state = ACME_STATE_ACCEPT_CHALL;
lws_acme_report_status(vhd->vhost, LWS_CUS_CHALLENGE,
NULL);
/* tls-sni-01 ... what a mess.
* The stuff in
@ -1141,7 +1264,6 @@ pkt_add_hdrs:
* server know we are ready to roll...
*/
ac->state = ACME_STATE_ACCEPT_CHALL;
ac->goes_around = 0;
cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
&ac->cwsi, &ac->i,
@ -1152,7 +1274,7 @@ pkt_add_hdrs:
__func__);
goto failed;
}
break;
return -1; /* close the completed client connection */
case ACME_STATE_ACCEPT_CHALL:
/*
@ -1176,23 +1298,18 @@ pkt_add_hdrs:
__func__, ac->challenge_uri);
poll_again:
ac->state = ACME_STATE_POLLING;
lws_acme_report_status(vhd->vhost, LWS_CUS_CHALLENGE, NULL);
if (ac->goes_around++ == 10) {
if (ac->goes_around++ == 20) {
lwsl_notice("%s: too many chall retries\n",
__func__);
goto failed;
}
cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
&ac->cwsi, &ac->i,
ac->challenge_uri,
"GET");
if (!cwsi) {
lwsl_notice("%s: failed to connect\n",
__func__);
goto failed;
}
break;
lws_timed_callback_vh_protocol(vhd->vhost, vhd->protocol,
LWS_CALLBACK_USER + 0xac33, ac->goes_around == 1 ? 10 : 2);
return -1; /* close the completed client connection */
case ACME_STATE_POLLING:
@ -1205,13 +1322,16 @@ poll_again:
if (!strcmp(ac->status, "invalid")) {
lwsl_notice("%s: polling failed\n", __func__);
lws_snprintf(buf, sizeof(buf),
"Challenge Invalid: %s", ac->detail);
failreason = buf;
goto failed;
}
lwsl_notice("Authorization accepted\n");
lwsl_notice("Challenge passed\n");
/*
* our authorization was validated... so delete the
* The challenge was validated... so delete the
* temp SNI vhost now its job is done
*/
if (ac->vhost)
@ -1225,6 +1345,7 @@ poll_again:
* server to request the actual certs.
*/
ac->state = ACME_STATE_POLLING_CSR;
lws_acme_report_status(vhd->vhost, LWS_CUS_REQ, NULL);
ac->goes_around = 0;
strcpy(buf, ac->urls[JAD_NEW_CERT_URL]);
@ -1237,7 +1358,7 @@ poll_again:
goto failed;
}
break;
return -1; /* close the completed client connection */
case ACME_STATE_POLLING_CSR:
/*
@ -1273,6 +1394,10 @@ poll_again:
int max;
lwsl_notice("The cert was sent..\n");
lws_acme_report_status(vhd->vhost,
LWS_CUS_ISSUE, NULL);
/*
* That means we have the issued cert DER in
* ac->buf, length in ac->cpos; and the key in
@ -1334,7 +1459,7 @@ poll_again:
lws_ptr_diff(p, start));
free(start);
if (n) {
lwsl_err("unable to write ACME cert!\n");
lwsl_err("unable to write ACME cert! %d\n", n);
goto failed;
}
/*
@ -1356,15 +1481,15 @@ poll_again:
lwsl_notice("%s: Updated certs written for %s "
"to %s.upd and %s.upd\n", __func__,
vhd->pvop[LWS_TLS_REQ_ELEMENT_COMMON_NAME],
vhd->pvop[LWS_TLS_SET_CERT_PATH],
vhd->pvop[LWS_TLS_SET_KEY_PATH]);
vhd->pvop_active[LWS_TLS_REQ_ELEMENT_COMMON_NAME],
vhd->pvop_active[LWS_TLS_SET_CERT_PATH],
vhd->pvop_active[LWS_TLS_SET_KEY_PATH]);
/* notify lws there was a cert update */
if (lws_tls_cert_updated(vhd->context,
vhd->pvop[LWS_TLS_SET_CERT_PATH],
vhd->pvop[LWS_TLS_SET_KEY_PATH],
vhd->pvop_active[LWS_TLS_SET_CERT_PATH],
vhd->pvop_active[LWS_TLS_SET_KEY_PATH],
ac->buf, ac->cpos,
ac->alloc_privkey_pem,
ac->len_privkey_pem)) {
@ -1372,10 +1497,14 @@ poll_again:
}
lws_acme_finished(vhd);
lws_acme_report_status(vhd->vhost,
LWS_CUS_SUCCESS, NULL);
return 0;
}
lws_acme_report_status(vhd->vhost, LWS_CUS_CONFIRM, NULL);
/* he is preparing the cert, go again with a GET */
if (ac->goes_around++ == 30) {
@ -1395,13 +1524,24 @@ poll_again:
goto failed;
}
break;
return -1; /* close the completed client connection */
default:
break;
}
break;
case LWS_CALLBACK_USER + 0xac33:
cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
&ac->cwsi, &ac->i,
ac->challenge_uri,
"GET");
if (!cwsi) {
lwsl_notice("%s: failed to connect\n", __func__);
goto failed;
}
break;
case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS:
/*
* This goes to vhost->protocols[0], but for our temp certs
@ -1414,9 +1554,17 @@ poll_again:
lwsl_debug("LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS\n");
ac = (struct acme_connection *)lws_get_vhost_user(
(struct lws_vhost *)in);
lws_acme_report_status((struct lws_vhost *)in,
LWS_CUS_CREATE_REQ,
"creating challenge cert");
if (lws_tls_acme_sni_cert_create((struct lws_vhost *)in,
ac->san_a, ac->san_b))
ac->san_a, ac->san_b)) {
lwsl_err("%s: creating the sni test cert failed\n", __func__);
return -1;
}
break;
default:
@ -1427,6 +1575,7 @@ poll_again:
failed:
lwsl_err("%s: failed out\n", __func__);
lws_acme_report_status(vhd->vhost, LWS_CUS_FAILED, failreason);
lws_acme_finished(vhd);
return -1;

View file

@ -72,7 +72,8 @@ lwsgs_handler_confirm(struct per_vhost_data__gs *vhd, struct lws *wsi,
a.event = LWSGSE_CREATED;
a.username = u.username;
a.email = u.email;
lws_callback_vhost_protocols(wsi, LWS_CALLBACK_GS_EVENT, &a, 0);
lws_callback_vhost_protocols_vhost(lws_get_vhost(wsi),
LWS_CALLBACK_GS_EVENT, &a, 0);
lws_snprintf(pss->onward, sizeof(pss->onward),
"%s/post-verify-ok.html", vhd->email_confirm_url);
@ -325,7 +326,8 @@ lwsgs_handler_change_password(struct per_vhost_data__gs *vhd, struct lws *wsi,
a.event = LWSGSE_DELETED;
a.username = u.username;
a.email = "";
lws_callback_vhost_protocols(wsi, LWS_CALLBACK_GS_EVENT, &a, 0);
lws_callback_vhost_protocols_vhost(lws_get_vhost(wsi),
LWS_CALLBACK_GS_EVENT, &a, 0);
lws_snprintf(s, sizeof(s) - 1,
"delete from users where username='%s';"

View file

@ -213,7 +213,7 @@ callback_messageboard(struct lws *wsi, enum lws_callback_reasons reason,
break;
case LWS_CALLBACK_PROTOCOL_DESTROY:
if (vhd->pdb)
if (vhd && vhd->pdb)
sqlite3_close(vhd->pdb);
goto passthru;

View file

@ -33,6 +33,7 @@ struct per_session_data__esplws_ota {
esp_ota_handle_t otahandle;
const esp_partition_t *part;
long file_length;
long last_rep;
nvs_handle nvh;
TimerHandle_t reboot_timer;
};
@ -117,6 +118,7 @@ ota_file_upload_cb(void *data, const char *name, const char *filename,
}
pss->file_length = 0;
pss->last_rep = -1;
break;
case LWS_UFS_FINAL_CONTENT:
@ -126,9 +128,11 @@ ota_file_upload_cb(void *data, const char *name, const char *filename,
return 1;
}
lwsl_notice("writing 0x%lx... 0x%lx\n",
pss->part->address + pss->file_length,
pss->part->address + pss->file_length + len);
if ((pss->file_length & ~0xffff) != (pss->last_rep & ~0xffff)) {
lwsl_notice("writing 0x%lx...\n",
pss->part->address + pss->file_length);
pss->last_rep = pss->file_length;
}
if (esp_ota_write(pss->otahandle, buf, len) != ESP_OK) {
lwsl_err("OTA: Failed to write\n");
return 1;

View file

@ -56,6 +56,8 @@ struct per_session_data__esplws_scan {
unsigned char changed_partway:1;
};
#define max_aps 12
struct per_vhost_data__esplws_scan {
wifi_ap_record_t ap_records[10];
TimerHandle_t timer, reboot_timer;
@ -63,6 +65,7 @@ struct per_vhost_data__esplws_scan {
struct lws_context *context;
struct lws_vhost *vhost;
const struct lws_protocols *protocol;
struct lws_wifi_scan *known_aps_list;
const esp_partition_t *part;
esp_ota_handle_t otahandle;
@ -75,6 +78,9 @@ struct per_vhost_data__esplws_scan {
char json[2048];
int json_len;
int acme_state;
char acme_msg[256];
uint16_t count_ap_records;
char count_live_pss;
unsigned char scan_ongoing:1;
@ -117,6 +123,9 @@ static const char * const param_names[] = {
"pri",
"serial",
"opts",
"group",
"role",
"updsettings",
};
enum enum_param_names {
@ -125,6 +134,9 @@ enum enum_param_names {
EPN_PRI,
EPN_SERIAL,
EPN_OPTS,
EPN_GROUP,
EPN_ROLE,
EPN_UPDSETTINGS,
};
@ -159,6 +171,9 @@ scan_start(struct per_vhost_data__esplws_scan *vhd)
if (vhd->scan_ongoing)
return;
if (lws_esp32.acme)
return;
vhd->scan_ongoing = 1;
lws_esp32.scan_consumer = scan_finished;
lws_esp32.scan_consumer_arg = vhd;
@ -167,10 +182,17 @@ scan_start(struct per_vhost_data__esplws_scan *vhd)
lwsl_err("scan start failed %d\n", n);
}
static char scan_defer;
static void timer_cb(TimerHandle_t t)
{
struct per_vhost_data__esplws_scan *vhd = pvTimerGetTimerID(t);
if (!lws_esp32.inet && (scan_defer & 1)) {
/* if connected in AP mode, wait twice as long between scans */
return;
}
scan_start(vhd);
}
@ -214,11 +236,101 @@ client_connection(struct per_vhost_data__esplws_scan *vhd, const char *file)
return 0; /* ongoing */
}
static int
lws_wifi_scan_rssi(struct lws_wifi_scan *p)
{
if (!p->count)
return -127;
return p->rssi / p->count;
}
/*
* Insert new lws_wifi_scan into linkedlist in rssi-sorted order, trimming the
* list if needed to keep it at or below max_aps entries.
*/
static int
lws_wifi_scan_insert_trim(struct lws_wifi_scan **list, struct lws_wifi_scan *ns)
{
int count = 0, ins = 1, worst;
struct lws_wifi_scan *newlist, **pworst, *pp1;
lws_start_foreach_llp(struct lws_wifi_scan **, pp, *list) {
/* try to find existing match */
if (!strcmp((*pp)->ssid, ns->ssid) &&
!memcmp((*pp)->bssid, ns->bssid, 6)) {
if ((*pp)->count > 127) {
(*pp)->count /= 2;
(*pp)->rssi /= 2;
}
(*pp)->rssi += ns->rssi;
(*pp)->count++;
ins = 0;
break;
}
} lws_end_foreach_llp(pp, next);
if (ins) {
lws_start_foreach_llp(struct lws_wifi_scan **, pp, *list) {
/* trim any excess guys */
if (count++ >= max_aps - 1) {
pp1 = *pp;
*pp = (*pp)->next;
free(pp1);
continue; /* stay where we are */
}
} lws_end_foreach_llp(pp, next);
/* we are inserting... so alloc a copy of him */
pp1 = malloc(sizeof(*pp1));
if (!pp1)
return -1;
memcpy(pp1, ns, sizeof(*pp1));
pp1->next = *list;
*list = pp1;
}
/* sort the list ... worst first, but added at the newlist head */
newlist = NULL;
/* while anybody left on the old list */
while (*list) {
worst = 0;
pworst = NULL;
/* who is the worst guy still left on the old list? */
lws_start_foreach_llp(struct lws_wifi_scan **, pp, *list) {
if (lws_wifi_scan_rssi(*pp) <= worst) {
worst = lws_wifi_scan_rssi(*pp);
pworst = pp;
}
} lws_end_foreach_llp(pp, next);
if (pworst) {
/* move the worst to the head of the new list */
pp1 = *pworst;
*pworst = (*pworst)->next;
pp1->next = newlist;
newlist = pp1;
}
}
*list = newlist;
return 0;
}
static void
scan_finished(uint16_t count, wifi_ap_record_t *recs, void *v)
{
struct per_vhost_data__esplws_scan *vhd = v;
struct per_session_data__esplws_scan *p = vhd->live_pss_list;
struct lws_wifi_scan lws;
wifi_ap_record_t *r;
int m;
lwsl_notice("%s: count %d\n", __func__, count);
@ -232,13 +344,31 @@ scan_finished(uint16_t count, wifi_ap_record_t *recs, void *v)
memcpy(vhd->ap_records, recs, vhd->count_ap_records * sizeof(*recs));
while (p) {
if (p->scan_state != SCAN_STATE_INITIAL && p->scan_state != SCAN_STATE_NONE)
if (p->scan_state != SCAN_STATE_INITIAL &&
p->scan_state != SCAN_STATE_NONE)
p->changed_partway = 1;
else
p->scan_state = SCAN_STATE_INITIAL;
p = p->next;
}
/* convert to generic, cumulative scan results */
for (m = 0; m < vhd->count_ap_records; m++) {
r = &vhd->ap_records[m];
lws.authmode = r->authmode;
lws.channel = r->primary;
lws.rssi = r->rssi;
lws.count = 1;
memcpy(&lws.bssid, r->bssid, 6);
strncpy(lws.ssid, (const char *)r->ssid, sizeof(lws.ssid) - 1);
lws.ssid[sizeof(lws.ssid) - 1] = '\0';
lws_wifi_scan_insert_trim(&vhd->known_aps_list, &lws);
}
lws_callback_on_writable_all_protocol(vhd->context, vhd->protocol);
if (lws_esp32.inet && !vhd->cwsi && !vhd->checked_updates)
@ -320,9 +450,8 @@ callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
unsigned char *start = pss->buffer + LWS_PRE - 1, *p = start,
*end = pss->buffer + sizeof(pss->buffer) - 1;
union lws_tls_cert_info_results ir;
struct lws_wifi_scan *lwscan;
char subject[64];
const char *pp;
wifi_ap_record_t *r;
int n, m;
nvs_handle nvh;
size_t s;
@ -341,7 +470,7 @@ callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
(TimerCallbackFunction_t)timer_cb);
vhd->scan_ongoing = 0;
strcpy(vhd->json, " { }");
scan_start(vhd);
// scan_start(vhd);
break;
case LWS_CALLBACK_PROTOCOL_DESTROY:
@ -354,17 +483,17 @@ callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
case LWS_CALLBACK_ESTABLISHED:
lwsl_notice("%s: ESTABLISHED\n", __func__);
if (!vhd->live_pss_list) {
scan_start(vhd);
// scan_start(vhd);
xTimerStart(vhd->timer, 0);
}
vhd->count_live_pss++;
pss->next = vhd->live_pss_list;
vhd->live_pss_list = pss;
/* if we have scan results, update them. Otherwise wait */
if (vhd->count_ap_records) {
// if (vhd->count_ap_records) {
pss->scan_state = SCAN_STATE_INITIAL;
lws_callback_on_writable(wsi);
}
// }
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
@ -481,6 +610,10 @@ callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
" \"unixtime\":\"%llu\",\n"
" \"certissuer\":\"%s\",\n"
" \"certsubject\":\"%s\",\n"
" \"le_dns\":\"%s\",\n"
" \"le_email\":\"%s\",\n"
" \"acme_state\":\"%d\",\n"
" \"acme_msg\":\"%s\",\n"
" \"button\":\"%d\",\n"
" \"group\":\"%s\",\n"
" \"role\":\"%s\",\n",
@ -499,6 +632,10 @@ callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
vhd->cert_remaining_days,
(unsigned long long)t.tv_sec,
ir.ns.name, subject,
lws_esp32.le_dns,
lws_esp32.le_email,
vhd->acme_state,
vhd->acme_msg,
((volatile struct lws_esp32 *)(&lws_esp32))->button_is_down,
group, role);
p += snprintf((char *)p, end - p,
@ -561,6 +698,7 @@ callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
ssid, pp, use);
}
nvs_close(nvh);
pss->ap_record = 0;
p += snprintf((char *)p, end - p,
"], \"aps\":[\n");
@ -570,27 +708,36 @@ callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
break;
case SCAN_STATE_LIST:
lwscan = vhd->known_aps_list;
n = pss->ap_record;
while (lwscan && n--)
lwscan = lwscan->next;
for (m = 0; m < 6; m++) {
n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
if (pss->ap_record >= vhd->count_ap_records)
if (!lwscan)
goto scan_state_final;
if (pss->subsequent)
*p++ = ',';
pss->subsequent = 1;
pss->ap_record++;
r = &vhd->ap_records[(int)pss->ap_record++];
p += snprintf((char *)p, end - p,
"{\"ssid\":\"%s\",\n"
"\"bssid\":\"%02X:%02X:%02X:%02X:%02X:%02X\",\n"
"\"rssi\":\"%d\",\n"
"\"chan\":\"%d\",\n"
"\"auth\":\"%d\"}\n",
r->ssid,
r->bssid[0], r->bssid[1], r->bssid[2],
r->bssid[3], r->bssid[4], r->bssid[5],
r->rssi, r->primary, r->authmode);
if (pss->ap_record >= vhd->count_ap_records)
lwscan->ssid,
lwscan->bssid[0], lwscan->bssid[1], lwscan->bssid[2],
lwscan->bssid[3], lwscan->bssid[4], lwscan->bssid[5],
lws_wifi_scan_rssi(lwscan),
lwscan->channel, lwscan->authmode);
lwscan = lwscan->next;
if (!lwscan)
pss->scan_state = SCAN_STATE_FINAL;
}
break;
@ -600,6 +747,7 @@ scan_state_final:
n = LWS_WRITE_CONTINUATION;
p += sprintf((char *)p, "]\n}\n");
if (pss->changed_partway) {
pss->changed_partway = 0;
pss->subsequent = 0;
pss->scan_state = SCAN_STATE_INITIAL;
} else {
@ -622,6 +770,17 @@ issue:
break;
case LWS_CALLBACK_VHOST_CERT_UPDATE:
lwsl_notice("LWS_CALLBACK_VHOST_CERT_UPDATE: %d\n", (int)len);
vhd->acme_state = (int)len;
if (in) {
strncpy(vhd->acme_msg, in, sizeof(vhd->acme_msg) - 1);
vhd->acme_msg[sizeof(vhd->acme_msg) - 1] = '\0';
lwsl_notice("acme_msg: %s\n", (char *)in);
}
lws_callback_on_writable_all_protocol_vhost(vhd->vhost, vhd->protocol);
break;
case LWS_CALLBACK_RECEIVE:
{
const char *sect = "\"app\": {", *b;
@ -644,6 +803,10 @@ issue:
if (strstr((const char *)in, "\"reset\""))
goto sched_reset;
if (!strncmp((const char *)in, "{\"job\":\"start-le\"", 17))
goto start_le;
if (nvs_open("lws-station", NVS_READWRITE, &nvh) != ESP_OK) {
lwsl_err("Unable to open nvs\n");
break;
@ -662,16 +825,6 @@ issue:
if (n == 8 && lws_esp32_get_reboot_type() != LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON)
continue;
//lwsl_notice("%s: %s '%s'\n", __func__, store_json[n].nvs, p);
if (n == 9) {
strncpy(lws_esp32.group, p, sizeof(lws_esp32.group) - 1);
lws_esp32.group[sizeof(lws_esp32.group) - 1] = '\0';
}
if (n == 10) {
strncpy(lws_esp32.role, p, sizeof(lws_esp32.role) - 1);
lws_esp32.role[sizeof(lws_esp32.role) - 1] = '\0';
}
if (lws_nvs_set_str(nvh, store_json[n].nvs, p) != ESP_OK) {
lwsl_err("Unable to store %s in nvm\n", store_json[n].nvs);
goto bail_nvs;
@ -767,6 +920,75 @@ auton:
vhd->autonomous_update = 0;
break;
start_le:
lws_esp32.acme = 1; /* hold off scanning */
puts(in);
/*
* {"job":"start-le","cn":"home.warmcat.com",
* "email":"andy@warmcat.com", "staging":"true"}
*/
if (nvs_open("lws-station", NVS_READWRITE, &nvh) != ESP_OK) {
lwsl_err("Unable to open nvs\n");
break;
}
n = 0;
b = strstr(in, ",\"cn\":\"");
if (b) {
b += 7;
while (*b && *b != '\"' && n < sizeof(lws_esp32.le_dns) - 1)
lws_esp32.le_dns[n++] = *b++;
}
lws_esp32.le_dns[n] = '\0';
lws_nvs_set_str(nvh, "acme-cn", lws_esp32.le_dns);
n = 0;
b = strstr(in, ",\"email\":\"");
if (b) {
b += 10;
while (*b && *b != '\"' && n < sizeof(lws_esp32.le_email) - 1)
lws_esp32.le_email[n++] = *b++;
}
lws_esp32.le_email[n] = '\0';
lws_nvs_set_str(nvh, "acme-email", lws_esp32.le_email);
nvs_commit(nvh);
nvs_close(nvh);
n = 1;
b = strstr(in, ",\"staging\":\"");
if (b)
lwsl_notice("staging: %s\n", b);
if (b && b[12] == 'f')
n = 0;
lwsl_notice("cn: %s, email: %s, staging: %d\n", lws_esp32.le_dns, lws_esp32.le_email, n);
{
struct lws_acme_cert_aging_args caa;
memset(&caa, 0, sizeof(caa));
caa.vh = vhd->vhost;
caa.element_overrides[LWS_TLS_REQ_ELEMENT_COMMON_NAME] = lws_esp32.le_dns;
caa.element_overrides[LWS_TLS_REQ_ELEMENT_EMAIL] = lws_esp32.le_email;
if (n)
caa.element_overrides[LWS_TLS_SET_DIR_URL] =
"https://acme-staging.api.letsencrypt.org/directory"; /* staging */
else
caa.element_overrides[LWS_TLS_SET_DIR_URL] =
"https://acme-v01.api.letsencrypt.org/directory"; /* real */
lws_callback_vhost_protocols_vhost(vhd->vhost,
LWS_CALLBACK_VHOST_CERT_AGING,
(void *)&caa, 0);
}
break;
}
case LWS_CALLBACK_CLOSED:
@ -802,7 +1024,7 @@ auton:
pss->filename[0] = '\0';
pss->file_length = 0;
}
//puts((const char *)in);
/* let it parse the POST data */
if (lws_spa_process(pss->spa, in, len))
return -1;
@ -813,6 +1035,14 @@ auton:
/* call to inform no more payload data coming */
lws_spa_finalize(pss->spa);
for (n = 0; n < ARRAY_SIZE(param_names); n++)
if (lws_spa_get_string(pss->spa, n))
lwsl_notice(" Param %s: %s\n", param_names[n],
lws_spa_get_string(pss->spa, n));
else
lwsl_notice(" Param %s: (none)\n",
param_names[n]);
if (nvs_open("lws-station", NVS_READWRITE, &nvh) != ESP_OK) {
lwsl_err("Unable to open nvs\n");
break;
@ -838,15 +1068,29 @@ auton:
nvs_commit(nvh);
}
}
if (lws_spa_get_string(pss->spa, EPN_GROUP)) {
if (lws_nvs_set_str(nvh, "group", lws_spa_get_string(pss->spa, EPN_GROUP)) != ESP_OK) {
lwsl_err("Unable to store group in nvm\n");
goto bail_nvs;
}
nvs_commit(nvh);
}
if (lws_spa_get_string(pss->spa, EPN_ROLE)) {
if (lws_nvs_set_str(nvh, "role", lws_spa_get_string(pss->spa, EPN_ROLE)) != ESP_OK) {
lwsl_err("Unable to store group in nvm\n");
goto bail_nvs;
}
nvs_commit(nvh);
}
nvs_close(nvh);
pp = lws_spa_get_string(pss->spa, EPN_SERIAL);
if (!pp)
pp = "unknown";
pss->result_len = snprintf(pss->result + LWS_PRE, sizeof(pss->result) - LWS_PRE - 1,
"<html>Rebooting after storing certs...<br>connect to AP '<b>config-%s-%s</b>' and continue here: "
"<a href=\"https://192.168.4.1\">https://192.168.4.1</a></html>",
lws_esp32.model, pp);
"<html>OK</html>");
if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
goto bail;
@ -860,11 +1104,7 @@ auton:
goto bail;
n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
if (n < 0)
goto bail;
lws_callback_on_writable(wsi);
break;
goto bail;
case LWS_CALLBACK_HTTP_WRITEABLE:
lwsl_debug("LWS_CALLBACK_HTTP_WRITEABLE: sending %d\n",