mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-21 11:30:01 +00:00
OTA: strenghten checks and introduce HTTPS support
This commit is contained in:
1 parent
9f16806a22
commit
2696c1ff94
4 files changed
+86
-12
No files matched your search
+28
@@ -10591,6 +10591,7 @@ void mg_tcpip_mapip(struct mg_connection *c, struct mg_addr *ip) {
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef MG_OTA_MAX_URL_LEN
|
||||
#define MG_OTA_MAX_URL_LEN 256
|
||||
#endif
|
||||
@@ -10611,6 +10612,17 @@ static struct mg_ota_state {
|
||||
|
||||
static void s_firmware_fn(struct mg_connection *c, int ev, void *ev_data);
|
||||
|
||||
static bool s_tls_init(struct mg_connection *c, const char *url) {
|
||||
struct mg_tls_opts opts = {
|
||||
.ca = mg_str(MG_OTA_TLS_CA), .name = mg_url_host(url)};
|
||||
if (opts.ca.len == 0) {
|
||||
mg_error(c, "MG_OTA_TLS_CA is not configured");
|
||||
} else {
|
||||
mg_tls_init(c, &opts);
|
||||
}
|
||||
return c->is_tls_hs != 0 && !c->is_closing;
|
||||
}
|
||||
|
||||
#if MG_ENABLE_CUSTOM_DEVICE_ID
|
||||
#else
|
||||
void mg_ota_device_id(char *buf, size_t len) {
|
||||
@@ -10643,6 +10655,11 @@ void mg_ota_device_id(char *buf, size_t len) {
|
||||
|
||||
static void s_version_fn(struct mg_connection *c, int ev, void *ev_data) {
|
||||
uint64_t expiration = *(uint64_t *) c->data;
|
||||
if (s_ota == NULL) {
|
||||
c->fn = NULL;
|
||||
c->is_closing = 1;
|
||||
return;
|
||||
}
|
||||
if (ev == MG_EV_POLL) {
|
||||
if (mg_millis() > expiration) mg_error(c, "Metadata timeout");
|
||||
} else if (ev == MG_EV_CONNECT) {
|
||||
@@ -10650,6 +10667,9 @@ static void s_version_fn(struct mg_connection *c, int ev, void *ev_data) {
|
||||
struct mg_str host = mg_url_host(s_ota->json_url);
|
||||
const char *uri = mg_url_uri(s_ota->json_url);
|
||||
const char *sep = strchr(uri, '?') == NULL ? "?" : "&";
|
||||
if (mg_url_is_ssl(s_ota->json_url)) {
|
||||
if (!s_tls_init(c, s_ota->json_url)) return;
|
||||
}
|
||||
mg_ota_device_id(id, sizeof(id));
|
||||
id[sizeof(id) - 1] = '\0';
|
||||
mg_printf(
|
||||
@@ -10715,10 +10735,18 @@ static void status_fn_2(struct mg_connection *c, const char *errmsg) {
|
||||
|
||||
static void s_firmware_fn(struct mg_connection *c, int ev, void *ev_data) {
|
||||
uint64_t expiration = *(uint64_t *) c->data;
|
||||
if (s_ota == NULL) {
|
||||
c->fn = NULL;
|
||||
c->is_closing = 1;
|
||||
return;
|
||||
}
|
||||
if (ev == MG_EV_POLL) {
|
||||
if (mg_millis() > expiration) mg_error(c, "OTA timeout");
|
||||
} else if (ev == MG_EV_CONNECT) {
|
||||
struct mg_str host = mg_url_host(s_ota->url);
|
||||
if (mg_url_is_ssl(s_ota->url)) {
|
||||
if (!s_tls_init(c, s_ota->url)) return;
|
||||
}
|
||||
mg_printf(c,
|
||||
"GET %s HTTP/1.1\r\n"
|
||||
"Host: %.*s\r\n"
|
||||
|
||||
+15
-6
@@ -4628,7 +4628,7 @@ extern void mg_mqtt_poll(struct mg_mgr *);
|
||||
//
|
||||
// This is a low-level OTA API, not intended to be called directly by users.
|
||||
// Users are provided with a higher-level API:
|
||||
// - defining MG_OTA_URL enables HTTP pull-based updates
|
||||
// - defining MG_OTA_URL enables HTTP or HTTPS pull-based updates
|
||||
// - mg_http_start_ota() enables push-based updates
|
||||
//
|
||||
// However, it is possible to use the mg_ota_* API directly. Below is the
|
||||
@@ -4775,8 +4775,10 @@ enum {
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Pull-based OTA over HTTP. Fetches metadata_url, which must return a JSON
|
||||
// object like: { "version": "1.2.3", "url": "FIRMWARE_URL", "size": 324645 }
|
||||
// Pull-based OTA over HTTP or HTTPS. If it's HTTPS, MG_OTA_TLS_CA
|
||||
// needs to be defined. Fetches metadata_url, which must
|
||||
// return a JSON object like:
|
||||
// { "version": "1.2.3", "url": "FIRMWARE_URL", "size": 324645 }
|
||||
// If the server version differs from MG_OTA_FIRMWARE_VERSION, downloads
|
||||
// FIRMWARE_URL and performs the OTA update. fn is called on every outcome:
|
||||
// NULL on successful flash, "Same version" when already up to date, or an
|
||||
@@ -4786,12 +4788,18 @@ void mg_ota_url_check(struct mg_mgr *mgr, const char *metadata_url,
|
||||
void (*fn)(const char *error_message));
|
||||
|
||||
// Firmware info URL for mg_ota_poll() which calls mg_ota_url_check().
|
||||
// Example: "http://mongoose.ws/ota/u/0/ota.json". See http://mongoose.ws/ota/
|
||||
// Example: "http://mongoose.ws/ota/u/0/ota.json". See http://mongoose.ws/ota/
|
||||
// Settable in mongoose_config.h
|
||||
#ifndef MG_OTA_URL
|
||||
#define MG_OTA_URL NULL
|
||||
#endif
|
||||
|
||||
// PEM or DER CA certificate used to authenticate an HTTPS OTA server. Set to
|
||||
// NULL to use HTTP. Set in mongoose_config.h.
|
||||
#ifndef MG_OTA_TLS_CA
|
||||
#define MG_OTA_TLS_CA NULL
|
||||
#endif
|
||||
|
||||
// OTA status callback function for mg_ota_poll()
|
||||
#ifndef MG_OTA_STATUS_FN
|
||||
#define MG_OTA_STATUS_FN NULL
|
||||
@@ -4821,8 +4829,9 @@ void mg_ota_url_check(struct mg_mgr *mgr, const char *metadata_url,
|
||||
// E.g. on STM32, uses the 96-bit MCU UID converted to a hex string.
|
||||
void mg_ota_device_id(char *buf, size_t len);
|
||||
|
||||
// Checks for a firmware update over HTTP. Called automatically by mg_mgr_poll()
|
||||
// when MG_OTA_URL is set in mongoose_config.h. Do not call directly.
|
||||
// Checks for a firmware update over HTTP or HTTPS. Called automatically by
|
||||
// mg_mgr_poll() when MG_OTA_URL is set in mongoose_config.h. Do not call
|
||||
// directly.
|
||||
void mg_ota_poll(struct mg_mgr *);
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "json.h"
|
||||
#include "log.h"
|
||||
#include "printf.h"
|
||||
#include "tls.h"
|
||||
#include "url.h"
|
||||
#include "util.h"
|
||||
|
||||
@@ -26,6 +27,17 @@ static struct mg_ota_state {
|
||||
|
||||
static void s_firmware_fn(struct mg_connection *c, int ev, void *ev_data);
|
||||
|
||||
static bool s_tls_init(struct mg_connection *c, const char *url) {
|
||||
struct mg_tls_opts opts = {
|
||||
.ca = mg_str(MG_OTA_TLS_CA), .name = mg_url_host(url)};
|
||||
if (opts.ca.len == 0) {
|
||||
mg_error(c, "MG_OTA_TLS_CA is not configured");
|
||||
} else {
|
||||
mg_tls_init(c, &opts);
|
||||
}
|
||||
return c->is_tls_hs != 0 && !c->is_closing;
|
||||
}
|
||||
|
||||
#if MG_ENABLE_CUSTOM_DEVICE_ID
|
||||
#else
|
||||
void mg_ota_device_id(char *buf, size_t len) {
|
||||
@@ -58,6 +70,11 @@ void mg_ota_device_id(char *buf, size_t len) {
|
||||
|
||||
static void s_version_fn(struct mg_connection *c, int ev, void *ev_data) {
|
||||
uint64_t expiration = *(uint64_t *) c->data;
|
||||
if (s_ota == NULL) {
|
||||
c->fn = NULL;
|
||||
c->is_closing = 1;
|
||||
return;
|
||||
}
|
||||
if (ev == MG_EV_POLL) {
|
||||
if (mg_millis() > expiration) mg_error(c, "Metadata timeout");
|
||||
} else if (ev == MG_EV_CONNECT) {
|
||||
@@ -65,6 +82,9 @@ static void s_version_fn(struct mg_connection *c, int ev, void *ev_data) {
|
||||
struct mg_str host = mg_url_host(s_ota->json_url);
|
||||
const char *uri = mg_url_uri(s_ota->json_url);
|
||||
const char *sep = strchr(uri, '?') == NULL ? "?" : "&";
|
||||
if (mg_url_is_ssl(s_ota->json_url)) {
|
||||
if (!s_tls_init(c, s_ota->json_url)) return;
|
||||
}
|
||||
mg_ota_device_id(id, sizeof(id));
|
||||
id[sizeof(id) - 1] = '\0';
|
||||
mg_printf(
|
||||
@@ -130,10 +150,18 @@ static void status_fn_2(struct mg_connection *c, const char *errmsg) {
|
||||
|
||||
static void s_firmware_fn(struct mg_connection *c, int ev, void *ev_data) {
|
||||
uint64_t expiration = *(uint64_t *) c->data;
|
||||
if (s_ota == NULL) {
|
||||
c->fn = NULL;
|
||||
c->is_closing = 1;
|
||||
return;
|
||||
}
|
||||
if (ev == MG_EV_POLL) {
|
||||
if (mg_millis() > expiration) mg_error(c, "OTA timeout");
|
||||
} else if (ev == MG_EV_CONNECT) {
|
||||
struct mg_str host = mg_url_host(s_ota->url);
|
||||
if (mg_url_is_ssl(s_ota->url)) {
|
||||
if (!s_tls_init(c, s_ota->url)) return;
|
||||
}
|
||||
mg_printf(c,
|
||||
"GET %s HTTP/1.1\r\n"
|
||||
"Host: %.*s\r\n"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// This is a low-level OTA API, not intended to be called directly by users.
|
||||
// Users are provided with a higher-level API:
|
||||
// - defining MG_OTA_URL enables HTTP pull-based updates
|
||||
// - defining MG_OTA_URL enables HTTP or HTTPS pull-based updates
|
||||
// - mg_http_start_ota() enables push-based updates
|
||||
//
|
||||
// However, it is possible to use the mg_ota_* API directly. Below is the
|
||||
@@ -149,8 +149,10 @@ enum {
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Pull-based OTA over HTTP. Fetches metadata_url, which must return a JSON
|
||||
// object like: { "version": "1.2.3", "url": "FIRMWARE_URL", "size": 324645 }
|
||||
// Pull-based OTA over HTTP or HTTPS. If it's HTTPS, MG_OTA_TLS_CA
|
||||
// needs to be defined. Fetches metadata_url, which must
|
||||
// return a JSON object like:
|
||||
// { "version": "1.2.3", "url": "FIRMWARE_URL", "size": 324645 }
|
||||
// If the server version differs from MG_OTA_FIRMWARE_VERSION, downloads
|
||||
// FIRMWARE_URL and performs the OTA update. fn is called on every outcome:
|
||||
// NULL on successful flash, "Same version" when already up to date, or an
|
||||
@@ -160,12 +162,18 @@ void mg_ota_url_check(struct mg_mgr *mgr, const char *metadata_url,
|
||||
void (*fn)(const char *error_message));
|
||||
|
||||
// Firmware info URL for mg_ota_poll() which calls mg_ota_url_check().
|
||||
// Example: "http://mongoose.ws/ota/u/0/ota.json". See http://mongoose.ws/ota/
|
||||
// Example: "http://mongoose.ws/ota/u/0/ota.json". See http://mongoose.ws/ota/
|
||||
// Settable in mongoose_config.h
|
||||
#ifndef MG_OTA_URL
|
||||
#define MG_OTA_URL NULL
|
||||
#endif
|
||||
|
||||
// PEM or DER CA certificate used to authenticate an HTTPS OTA server. Set to
|
||||
// NULL to use HTTP. Set in mongoose_config.h.
|
||||
#ifndef MG_OTA_TLS_CA
|
||||
#define MG_OTA_TLS_CA NULL
|
||||
#endif
|
||||
|
||||
// OTA status callback function for mg_ota_poll()
|
||||
#ifndef MG_OTA_STATUS_FN
|
||||
#define MG_OTA_STATUS_FN NULL
|
||||
@@ -195,6 +203,7 @@ void mg_ota_url_check(struct mg_mgr *mgr, const char *metadata_url,
|
||||
// E.g. on STM32, uses the 96-bit MCU UID converted to a hex string.
|
||||
void mg_ota_device_id(char *buf, size_t len);
|
||||
|
||||
// Checks for a firmware update over HTTP. Called automatically by mg_mgr_poll()
|
||||
// when MG_OTA_URL is set in mongoose_config.h. Do not call directly.
|
||||
// Checks for a firmware update over HTTP or HTTPS. Called automatically by
|
||||
// mg_mgr_poll() when MG_OTA_URL is set in mongoose_config.h. Do not call
|
||||
// directly.
|
||||
void mg_ota_poll(struct mg_mgr *);
|
||||
Reference in new issue
Block a user