mirror of
https://github.com/cesanta/mongoose.git
synced 2026-11-09 16:21:45 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b6c08acfb | ||
|
|
528be76a23 | ||
|
|
b6ba6a56d9 | ||
|
|
1efc211a51 | ||
|
|
ca5ca3403c | ||
|
|
7a86c401b9 | ||
|
|
52cc8ef1d3 | ||
|
|
b975a8e761 | ||
|
|
2d7e44201d | ||
|
|
b415c23bc5 | ||
|
|
cba6c4f8df | ||
|
|
9d6d064b39 | ||
|
|
fc79fd0be5 | ||
|
|
22a94c0906 | ||
|
|
f347dbf2b5 | ||
|
|
39a3478429 | ||
|
|
7fccc2b75f | ||
|
|
07e580d956 |
No files matched your search
+74
-54
@@ -3913,30 +3913,31 @@ size_t mg_usage(int task, int metric) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static size_t print_mem_stat(mg_pfn_t fn, void *arg, const char *name,
|
||||
size_t free, size_t total) {
|
||||
return mg_xprintf(fn, arg, "{%m:%m,%m:%zu,%m:%zu}", MG_ESC("name"),
|
||||
MG_ESC(name == NULL ? "" : name), MG_ESC("free"), free,
|
||||
MG_ESC("total"), total);
|
||||
}
|
||||
|
||||
size_t mg_print_mem_stats(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
int i, count;
|
||||
size_t heap_total = mg_usage(0, MG_USAGE_HEAP_TOTAL);
|
||||
size_t heap_free = mg_usage(0, MG_USAGE_HEAP_FREE);
|
||||
static size_t print_stacks(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
int i;
|
||||
int count = (int) mg_usage(-1, MG_USAGE_NUM_TASKS);
|
||||
size_t len = mg_xprintf(fn, arg, "[");
|
||||
len += print_mem_stat(fn, arg, "heap", heap_free, heap_total);
|
||||
count = (int) mg_usage(-1, MG_USAGE_NUM_TASKS);
|
||||
for (i = 0; i < count; i++) {
|
||||
const char *name = (const char *) mg_usage(i, MG_USAGE_TASK_NAME);
|
||||
len += mg_xprintf(fn, arg, ",");
|
||||
len += print_mem_stat(fn, arg, name, mg_usage(i, MG_USAGE_STACK_FREE),
|
||||
mg_usage(i, MG_USAGE_STACK_TOTAL));
|
||||
len += mg_xprintf(fn, arg, "%s{%m:%m,%m:%zu,%m:%zu}",
|
||||
i == 0 ? "" : ",", MG_ESC("name"),
|
||||
MG_ESC(name == NULL ? "" : name), MG_ESC("free"),
|
||||
(size_t) mg_usage(i, MG_USAGE_STACK_FREE), MG_ESC("total"),
|
||||
(size_t) mg_usage(i, MG_USAGE_STACK_TOTAL));
|
||||
}
|
||||
(void) ap;
|
||||
return len + mg_xprintf(fn, arg, "]");
|
||||
}
|
||||
|
||||
size_t mg_print_mem_stats(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
size_t heap_total = (size_t) mg_usage(0, MG_USAGE_HEAP_TOTAL);
|
||||
size_t heap_free = (size_t) mg_usage(0, MG_USAGE_HEAP_FREE);
|
||||
(void) ap;
|
||||
return mg_xprintf(fn, arg, "{%m:%zu,%m:%zu,%m:%M}",
|
||||
MG_ESC("heap_total"), heap_total, MG_ESC("heap_free"),
|
||||
heap_free, MG_ESC("stacks"), print_stacks);
|
||||
}
|
||||
|
||||
#if MG_ARCH == MG_ARCH_ESP32
|
||||
// reusable for other platforms, currently ESP32-only
|
||||
struct mg_health_coredump {
|
||||
@@ -4391,6 +4392,12 @@ static bool mg_http_parse_headers(const char *s, const char *end,
|
||||
// MG_INFO(("--HH [%.*s] [%.*s]", (int) k.len, k.buf, (int) v.len, v.buf));
|
||||
h[i].name = k, h[i].value = v; // Success. Assign values
|
||||
}
|
||||
if (i == max_hdrs &&
|
||||
!(s < end &&
|
||||
(s[0] == '\n' ||
|
||||
(s[0] == '\r' && s + 1 < end && s[1] == '\n')))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -10239,6 +10246,7 @@ static struct mg_connection *getpeer(struct mg_mgr *mgr, struct pkt *pkt,
|
||||
if (!c->is_udp && pkt->tcp && c->loc.port == pkt->tcp->dport &&
|
||||
((lsn && c->is_listening && !(c->loc.is_ip6 ^ (pkt->ip6 != NULL))) ||
|
||||
(!lsn && !c->is_listening && c->rem.port == pkt->tcp->sport &&
|
||||
!(c->loc.is_ip6 ^ (pkt->ip6 != NULL)) && // IP or IPv6 to same dest
|
||||
((!c->loc.is_ip6 && c->rem.addr.ip4 == pkt->ip->src)
|
||||
#if MG_ENABLE_IPV6
|
||||
|| (c->loc.is_ip6 && MG_IP6MATCH(c->rem.addr.ip6, pkt->ip6->src))
|
||||
@@ -19040,7 +19048,7 @@ static int mg_tls_server_recv_hello(struct mg_connection *c) {
|
||||
if (!is_retry || rio->buf[0] != MG_TLS_CHANGE_CIPHER) break;
|
||||
mg_tls_drop_record(c); // compatibility mode CCS before 2nd ClientHello
|
||||
}
|
||||
if (rio->buf[0] != MG_TLS_HANDSHAKE || rio->buf[5] != MG_TLS_CLIENT_HELLO) {
|
||||
if (rio->buf[0] != MG_TLS_HANDSHAKE || rio->len < 6 || rio->buf[5] != MG_TLS_CLIENT_HELLO) {
|
||||
mg_error(c, "not a client hello packet");
|
||||
return -1;
|
||||
}
|
||||
@@ -19070,17 +19078,21 @@ static int mg_tls_server_recv_hello(struct mg_connection *c) {
|
||||
uint16_t k;
|
||||
uint16_t key_exchange_len;
|
||||
uint8_t *key_exchange;
|
||||
uint16_t n = MG_LOAD_BE16(ext + j + 2);
|
||||
uint16_t n;
|
||||
if ((ext_len - j) < 4) goto fail;
|
||||
n = MG_LOAD_BE16(ext + j + 2);
|
||||
if (((uint32_t) n + j + 4) > ext_len) goto fail;
|
||||
if (MG_LOAD_BE16(ext + j) != 0x0033) { // not a key share extension, ignore
|
||||
j += (uint16_t) (n + 4);
|
||||
continue;
|
||||
}
|
||||
if (n < 2) goto fail;
|
||||
key_exchange_len = MG_LOAD_BE16(ext + j + 4);
|
||||
key_exchange = ext + j + 6;
|
||||
if ((key_exchange + key_exchange_len) > ((uint8_t *) rio->buf + rio->len))
|
||||
if (key_exchange_len > n - 2)
|
||||
goto fail;
|
||||
for (k = 0; k < key_exchange_len;) {
|
||||
if ((key_exchange_len - k) < 4) goto fail;
|
||||
uint16_t m = MG_LOAD_BE16(key_exchange + k + 2);
|
||||
uint16_t group = MG_LOAD_BE16(key_exchange + k);
|
||||
if (((uint32_t) m + k + 4) > key_exchange_len) goto fail;
|
||||
@@ -20071,41 +20083,39 @@ static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mg_tls_verify_cert_signature(const struct mg_tls_cert *cert,
|
||||
static void unpadlen(uint8_t *sig, struct mg_der_tlv *a, struct mg_der_tlv *b,
|
||||
uint32_t n) {
|
||||
if (a->len > n) a->value += (a->len - n), a->len = n;
|
||||
if (b->len > n) b->value += (b->len - n), b->len = n;
|
||||
memset(sig, 0, n - a->len); // short encoding
|
||||
memmove(sig + (n - a->len), a->value, a->len);
|
||||
memset(sig + n, 0, n - b->len);
|
||||
memmove(sig + n + (n - b->len), b->value, b->len);
|
||||
}
|
||||
|
||||
static bool mg_tls_verify_cert_signature(const struct mg_tls_cert *cert,
|
||||
const struct mg_tls_cert *issuer) {
|
||||
if (issuer->is_ec_pubkey) {
|
||||
uint8_t sig[128];
|
||||
struct mg_der_tlv seq = {0, 0, 0}, a = {0, 0, 0}, b = {0, 0, 0};
|
||||
mg_der_parse((uint8_t *) cert->sig.buf, cert->sig.len, &seq);
|
||||
mg_der_next(&seq, &a);
|
||||
mg_der_next(&seq, &b);
|
||||
if (a.len == 0 || b.len == 0) {
|
||||
if (mg_der_parse((uint8_t *) cert->sig.buf, cert->sig.len, &seq) <= 0 ||
|
||||
seq.type != 0x30 || mg_der_next(&seq, &a) <= 0 || a.type != 0x02 ||
|
||||
mg_der_next(&seq, &b) <= 0 || b.type != 0x02 || a.len == 0 ||
|
||||
b.len == 0 || seq.len != 0) {
|
||||
MG_ERROR(("cert verification error"));
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
if (issuer->pubkey.len == 64) {
|
||||
const uint32_t N = 32;
|
||||
if (a.len > N) a.value += (a.len - N), a.len = N; // padding
|
||||
if (b.len > N) b.value += (b.len - N), b.len = N;
|
||||
memset(sig, 0, N - a.len); // short encoding
|
||||
memmove(sig + (N - a.len), a.value, a.len);
|
||||
memset(sig + N, 0, N - b.len);
|
||||
memmove(sig + N + (N - b.len), b.value, b.len);
|
||||
unpadlen(sig, &a, &b, 32);
|
||||
return mg_p256_verify((uint8_t *) issuer->pubkey.buf, cert->tbshash,
|
||||
cert->tbshashsz, sig);
|
||||
cert->tbshashsz, sig) == 1;
|
||||
} else if (issuer->pubkey.len == 96) {
|
||||
const uint32_t N = 48;
|
||||
if (a.len > N) a.value += (a.len - N), a.len = N; // padding
|
||||
if (b.len > N) b.value += (b.len - N), b.len = N;
|
||||
memset(sig, 0, N - a.len); // short encoding
|
||||
memmove(sig + (N - a.len), a.value, a.len);
|
||||
memset(sig + N, 0, N - b.len);
|
||||
memmove(sig + N + (N - b.len), b.value, b.len);
|
||||
unpadlen(sig, &a, &b, 48);
|
||||
return mg_p384_verify((uint8_t *) issuer->pubkey.buf, cert->tbshash,
|
||||
cert->tbshashsz, sig);
|
||||
cert->tbshashsz, sig) == 1;
|
||||
} else {
|
||||
MG_ERROR(("unsupported public key length: %d", issuer->pubkey.len));
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
const uint8_t *n;
|
||||
@@ -20117,14 +20127,16 @@ static int mg_tls_verify_cert_signature(const struct mg_tls_cert *cert,
|
||||
mg_der_next(&seq, &modulus) <= 0 || modulus.type != 2 ||
|
||||
modulus.len == 0 || mg_der_next(&seq, &exponent) <= 0 ||
|
||||
exponent.type != 2 || exponent.len == 0) {
|
||||
return -1;
|
||||
MG_ERROR(("failed to parse RSA issuer public key"));
|
||||
return false;
|
||||
}
|
||||
n = modulus.value, nlen = mg_rsa_trim_len(&n, modulus.len);
|
||||
if (nlen > sizeof(sig2) || cert->tbshashsz > nlen ||
|
||||
mg_rsa_mod_pow(modulus.value, modulus.len, exponent.value,
|
||||
exponent.len, (uint8_t *) cert->sig.buf, cert->sig.len,
|
||||
sig2, nlen) != 0) {
|
||||
return 0;
|
||||
MG_ERROR(("failed to process RSA cert sig"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return mg_rsa_pkcs_verify(sig2, nlen, cert->tbshash, cert->tbshashsz);
|
||||
@@ -30137,7 +30149,7 @@ uint64_t mg_timegm(unsigned int year, unsigned int month, unsigned int day,
|
||||
const uint64_t day_secs = 86400;
|
||||
const uint64_t year_secs = 31536000;
|
||||
unsigned int y, ly;
|
||||
if (year < 1970) return 0;
|
||||
if (year < 1970 || month == 0 || month > 12) return 0;
|
||||
y = year - 1900;
|
||||
ly = month > 2 ? y + 1 : y;
|
||||
return (uint64_t) sec + 60 * min + 3600 * hour +
|
||||
@@ -30502,12 +30514,14 @@ static uint32_t be32(const uint8_t *p) {
|
||||
(((uint32_t) p[1]) << 16) | (((uint32_t) p[0]) << 24);
|
||||
}
|
||||
|
||||
static size_t ws_process(uint8_t *buf, size_t len, struct ws_msg *msg) {
|
||||
static size_t ws_process(uint8_t *buf, size_t len, struct ws_msg *msg,
|
||||
bool *masked) {
|
||||
size_t i, n = 0, mask_len = 0;
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
if (len >= 2) {
|
||||
n = buf[1] & 0x7f; // Frame length
|
||||
mask_len = buf[1] & 128 ? 4 : 0; // last bit is a mask bit
|
||||
*masked = (buf[1] & 0x80) != 0; // b7 Mask, b6:0 Frame length
|
||||
n = buf[1] & 0x7f;
|
||||
mask_len = *masked ? 4 : 0;
|
||||
msg->flags = buf[0];
|
||||
if (n < 126 && len >= mask_len) {
|
||||
msg->data_len = n;
|
||||
@@ -30516,14 +30530,14 @@ static size_t ws_process(uint8_t *buf, size_t len, struct ws_msg *msg) {
|
||||
msg->header_len = 4 + mask_len;
|
||||
msg->data_len = (((size_t) buf[2]) << 8) | buf[3];
|
||||
} else if (len >= 10 + mask_len) {
|
||||
// Sanity check and protect the boundary check below: data_len should not
|
||||
// be larger than 1 GB, so it fits in 32-bits
|
||||
uint32_t hi = be32(buf + 2), lo = be32(buf + 6);
|
||||
if (hi != 0 || lo > 1024U * 1024U * 1024U) return 0;
|
||||
msg->data_len = (size_t) lo;
|
||||
msg->header_len = 10 + mask_len;
|
||||
msg->data_len =
|
||||
(size_t) (((uint64_t) be32(buf + 2) << 32) + be32(buf + 6));
|
||||
}
|
||||
}
|
||||
// Sanity check, and integer overflow protection for the boundary check below
|
||||
// data_len should not be larger than 1 Gb
|
||||
if (msg->data_len > 1024 * 1024 * 1024) return 0;
|
||||
if (msg->header_len + msg->data_len > len) return 0;
|
||||
if (mask_len > 0) {
|
||||
uint8_t *p = buf + msg->header_len, *m = p - mask_len;
|
||||
@@ -30604,17 +30618,23 @@ static bool mg_ws_client_handshake(struct mg_connection *c) {
|
||||
|
||||
static void mg_ws_cb(struct mg_connection *c, int ev, void *ev_data) {
|
||||
struct ws_msg msg;
|
||||
bool msk; // is this frame masked ?
|
||||
size_t ofs = (size_t) c->pfn_data;
|
||||
|
||||
// assert(ofs < c->recv.len);
|
||||
if (ev == MG_EV_READ) {
|
||||
if (c->is_client && !c->is_websocket && mg_ws_client_handshake(c)) return;
|
||||
|
||||
while (ws_process(c->recv.buf + ofs, c->recv.len - ofs, &msg) > 0) {
|
||||
while (ws_process(c->recv.buf + ofs, c->recv.len - ofs, &msg, &msk) > 0) {
|
||||
char *s = (char *) c->recv.buf + ofs + msg.header_len;
|
||||
struct mg_ws_message m;
|
||||
size_t len;
|
||||
uint8_t final, op;
|
||||
if (msk == c->is_client) {
|
||||
mg_error(c, c->is_client ? "masked WS server frame"
|
||||
: "unmasked WS client frame");
|
||||
return;
|
||||
}
|
||||
m.data.buf = s, m.data.len = msg.data_len, m.flags = msg.flags;
|
||||
len = msg.header_len + msg.data_len;
|
||||
final = msg.flags & 128;
|
||||
|
||||
+3
-3
@@ -4516,8 +4516,8 @@ size_t mg_usage(int task, int metric);
|
||||
|
||||
#define MG_HEALTH_INIT() mg_health_init()
|
||||
extern size_t mg_print_crash_record(mg_pfn_t, void *, va_list *);
|
||||
// JSON memory statistics via mg_usage(), suitable for %M: an array of
|
||||
// {name, free, total} entries, starting with "heap", then task stacks
|
||||
// JSON memory statistics via mg_usage(), suitable for %M: heap_total, heap_free,
|
||||
// and a stacks array of {name, free, total}
|
||||
// A zero total means unknown
|
||||
extern size_t mg_print_mem_stats(mg_pfn_t, void *, va_list *);
|
||||
extern void mg_health_init(void);
|
||||
@@ -4540,7 +4540,7 @@ static inline size_t mg_print_crash_record(mg_pfn_t fn, void *arg,
|
||||
}
|
||||
static inline size_t mg_print_mem_stats(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
(void) ap;
|
||||
return mg_xprintf(fn, arg, "[]");
|
||||
return mg_xprintf(fn, arg, "{}");
|
||||
}
|
||||
static inline bool mg_health_coredump_begin(size_t *size) {
|
||||
(void) size;
|
||||
|
||||
+17
-16
@@ -58,30 +58,31 @@ size_t mg_usage(int task, int metric) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static size_t print_mem_stat(mg_pfn_t fn, void *arg, const char *name,
|
||||
size_t free, size_t total) {
|
||||
return mg_xprintf(fn, arg, "{%m:%m,%m:%zu,%m:%zu}", MG_ESC("name"),
|
||||
MG_ESC(name == NULL ? "" : name), MG_ESC("free"), free,
|
||||
MG_ESC("total"), total);
|
||||
}
|
||||
|
||||
size_t mg_print_mem_stats(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
int i, count;
|
||||
size_t heap_total = mg_usage(0, MG_USAGE_HEAP_TOTAL);
|
||||
size_t heap_free = mg_usage(0, MG_USAGE_HEAP_FREE);
|
||||
static size_t print_stacks(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
int i;
|
||||
int count = (int) mg_usage(-1, MG_USAGE_NUM_TASKS);
|
||||
size_t len = mg_xprintf(fn, arg, "[");
|
||||
len += print_mem_stat(fn, arg, "heap", heap_free, heap_total);
|
||||
count = (int) mg_usage(-1, MG_USAGE_NUM_TASKS);
|
||||
for (i = 0; i < count; i++) {
|
||||
const char *name = (const char *) mg_usage(i, MG_USAGE_TASK_NAME);
|
||||
len += mg_xprintf(fn, arg, ",");
|
||||
len += print_mem_stat(fn, arg, name, mg_usage(i, MG_USAGE_STACK_FREE),
|
||||
mg_usage(i, MG_USAGE_STACK_TOTAL));
|
||||
len += mg_xprintf(fn, arg, "%s{%m:%m,%m:%zu,%m:%zu}",
|
||||
i == 0 ? "" : ",", MG_ESC("name"),
|
||||
MG_ESC(name == NULL ? "" : name), MG_ESC("free"),
|
||||
(size_t) mg_usage(i, MG_USAGE_STACK_FREE), MG_ESC("total"),
|
||||
(size_t) mg_usage(i, MG_USAGE_STACK_TOTAL));
|
||||
}
|
||||
(void) ap;
|
||||
return len + mg_xprintf(fn, arg, "]");
|
||||
}
|
||||
|
||||
size_t mg_print_mem_stats(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
size_t heap_total = (size_t) mg_usage(0, MG_USAGE_HEAP_TOTAL);
|
||||
size_t heap_free = (size_t) mg_usage(0, MG_USAGE_HEAP_FREE);
|
||||
(void) ap;
|
||||
return mg_xprintf(fn, arg, "{%m:%zu,%m:%zu,%m:%M}",
|
||||
MG_ESC("heap_total"), heap_total, MG_ESC("heap_free"),
|
||||
heap_free, MG_ESC("stacks"), print_stacks);
|
||||
}
|
||||
|
||||
#if MG_ARCH == MG_ARCH_ESP32
|
||||
// reusable for other platforms, currently ESP32-only
|
||||
struct mg_health_coredump {
|
||||
|
||||
+3
-3
@@ -139,8 +139,8 @@ size_t mg_usage(int task, int metric);
|
||||
|
||||
#define MG_HEALTH_INIT() mg_health_init()
|
||||
extern size_t mg_print_crash_record(mg_pfn_t, void *, va_list *);
|
||||
// JSON memory statistics via mg_usage(), suitable for %M: an array of
|
||||
// {name, free, total} entries, starting with "heap", then task stacks
|
||||
// JSON memory statistics via mg_usage(), suitable for %M: heap_total, heap_free,
|
||||
// and a stacks array of {name, free, total}
|
||||
// A zero total means unknown
|
||||
extern size_t mg_print_mem_stats(mg_pfn_t, void *, va_list *);
|
||||
extern void mg_health_init(void);
|
||||
@@ -163,7 +163,7 @@ static inline size_t mg_print_crash_record(mg_pfn_t fn, void *arg,
|
||||
}
|
||||
static inline size_t mg_print_mem_stats(mg_pfn_t fn, void *arg, va_list *ap) {
|
||||
(void) ap;
|
||||
return mg_xprintf(fn, arg, "[]");
|
||||
return mg_xprintf(fn, arg, "{}");
|
||||
}
|
||||
static inline bool mg_health_coredump_begin(size_t *size) {
|
||||
(void) size;
|
||||
|
||||
@@ -265,6 +265,12 @@ static bool mg_http_parse_headers(const char *s, const char *end,
|
||||
// MG_INFO(("--HH [%.*s] [%.*s]", (int) k.len, k.buf, (int) v.len, v.buf));
|
||||
h[i].name = k, h[i].value = v; // Success. Assign values
|
||||
}
|
||||
if (i == max_hdrs &&
|
||||
!(s < end &&
|
||||
(s[0] == '\n' ||
|
||||
(s[0] == '\r' && s + 1 < end && s[1] == '\n')))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -602,6 +602,7 @@ static struct mg_connection *getpeer(struct mg_mgr *mgr, struct pkt *pkt,
|
||||
if (!c->is_udp && pkt->tcp && c->loc.port == pkt->tcp->dport &&
|
||||
((lsn && c->is_listening && !(c->loc.is_ip6 ^ (pkt->ip6 != NULL))) ||
|
||||
(!lsn && !c->is_listening && c->rem.port == pkt->tcp->sport &&
|
||||
!(c->loc.is_ip6 ^ (pkt->ip6 != NULL)) && // IP or IPv6 to same dest
|
||||
((!c->loc.is_ip6 && c->rem.addr.ip4 == pkt->ip->src)
|
||||
#if MG_ENABLE_IPV6
|
||||
|| (c->loc.is_ip6 && MG_IP6MATCH(c->rem.addr.ip6, pkt->ip6->src))
|
||||
|
||||
+32
-28
@@ -681,7 +681,7 @@ static int mg_tls_server_recv_hello(struct mg_connection *c) {
|
||||
if (!is_retry || rio->buf[0] != MG_TLS_CHANGE_CIPHER) break;
|
||||
mg_tls_drop_record(c); // compatibility mode CCS before 2nd ClientHello
|
||||
}
|
||||
if (rio->buf[0] != MG_TLS_HANDSHAKE || rio->buf[5] != MG_TLS_CLIENT_HELLO) {
|
||||
if (rio->buf[0] != MG_TLS_HANDSHAKE || rio->len < 6 || rio->buf[5] != MG_TLS_CLIENT_HELLO) {
|
||||
mg_error(c, "not a client hello packet");
|
||||
return -1;
|
||||
}
|
||||
@@ -711,17 +711,21 @@ static int mg_tls_server_recv_hello(struct mg_connection *c) {
|
||||
uint16_t k;
|
||||
uint16_t key_exchange_len;
|
||||
uint8_t *key_exchange;
|
||||
uint16_t n = MG_LOAD_BE16(ext + j + 2);
|
||||
uint16_t n;
|
||||
if ((ext_len - j) < 4) goto fail;
|
||||
n = MG_LOAD_BE16(ext + j + 2);
|
||||
if (((uint32_t) n + j + 4) > ext_len) goto fail;
|
||||
if (MG_LOAD_BE16(ext + j) != 0x0033) { // not a key share extension, ignore
|
||||
j += (uint16_t) (n + 4);
|
||||
continue;
|
||||
}
|
||||
if (n < 2) goto fail;
|
||||
key_exchange_len = MG_LOAD_BE16(ext + j + 4);
|
||||
key_exchange = ext + j + 6;
|
||||
if ((key_exchange + key_exchange_len) > ((uint8_t *) rio->buf + rio->len))
|
||||
if (key_exchange_len > n - 2)
|
||||
goto fail;
|
||||
for (k = 0; k < key_exchange_len;) {
|
||||
if ((key_exchange_len - k) < 4) goto fail;
|
||||
uint16_t m = MG_LOAD_BE16(key_exchange + k + 2);
|
||||
uint16_t group = MG_LOAD_BE16(key_exchange + k);
|
||||
if (((uint32_t) m + k + 4) > key_exchange_len) goto fail;
|
||||
@@ -1712,41 +1716,39 @@ static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mg_tls_verify_cert_signature(const struct mg_tls_cert *cert,
|
||||
static void unpadlen(uint8_t *sig, struct mg_der_tlv *a, struct mg_der_tlv *b,
|
||||
uint32_t n) {
|
||||
if (a->len > n) a->value += (a->len - n), a->len = n;
|
||||
if (b->len > n) b->value += (b->len - n), b->len = n;
|
||||
memset(sig, 0, n - a->len); // short encoding
|
||||
memmove(sig + (n - a->len), a->value, a->len);
|
||||
memset(sig + n, 0, n - b->len);
|
||||
memmove(sig + n + (n - b->len), b->value, b->len);
|
||||
}
|
||||
|
||||
static bool mg_tls_verify_cert_signature(const struct mg_tls_cert *cert,
|
||||
const struct mg_tls_cert *issuer) {
|
||||
if (issuer->is_ec_pubkey) {
|
||||
uint8_t sig[128];
|
||||
struct mg_der_tlv seq = {0, 0, 0}, a = {0, 0, 0}, b = {0, 0, 0};
|
||||
mg_der_parse((uint8_t *) cert->sig.buf, cert->sig.len, &seq);
|
||||
mg_der_next(&seq, &a);
|
||||
mg_der_next(&seq, &b);
|
||||
if (a.len == 0 || b.len == 0) {
|
||||
if (mg_der_parse((uint8_t *) cert->sig.buf, cert->sig.len, &seq) <= 0 ||
|
||||
seq.type != 0x30 || mg_der_next(&seq, &a) <= 0 || a.type != 0x02 ||
|
||||
mg_der_next(&seq, &b) <= 0 || b.type != 0x02 || a.len == 0 ||
|
||||
b.len == 0 || seq.len != 0) {
|
||||
MG_ERROR(("cert verification error"));
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
if (issuer->pubkey.len == 64) {
|
||||
const uint32_t N = 32;
|
||||
if (a.len > N) a.value += (a.len - N), a.len = N; // padding
|
||||
if (b.len > N) b.value += (b.len - N), b.len = N;
|
||||
memset(sig, 0, N - a.len); // short encoding
|
||||
memmove(sig + (N - a.len), a.value, a.len);
|
||||
memset(sig + N, 0, N - b.len);
|
||||
memmove(sig + N + (N - b.len), b.value, b.len);
|
||||
unpadlen(sig, &a, &b, 32);
|
||||
return mg_p256_verify((uint8_t *) issuer->pubkey.buf, cert->tbshash,
|
||||
cert->tbshashsz, sig);
|
||||
cert->tbshashsz, sig) == 1;
|
||||
} else if (issuer->pubkey.len == 96) {
|
||||
const uint32_t N = 48;
|
||||
if (a.len > N) a.value += (a.len - N), a.len = N; // padding
|
||||
if (b.len > N) b.value += (b.len - N), b.len = N;
|
||||
memset(sig, 0, N - a.len); // short encoding
|
||||
memmove(sig + (N - a.len), a.value, a.len);
|
||||
memset(sig + N, 0, N - b.len);
|
||||
memmove(sig + N + (N - b.len), b.value, b.len);
|
||||
unpadlen(sig, &a, &b, 48);
|
||||
return mg_p384_verify((uint8_t *) issuer->pubkey.buf, cert->tbshash,
|
||||
cert->tbshashsz, sig);
|
||||
cert->tbshashsz, sig) == 1;
|
||||
} else {
|
||||
MG_ERROR(("unsupported public key length: %d", issuer->pubkey.len));
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
const uint8_t *n;
|
||||
@@ -1758,14 +1760,16 @@ static int mg_tls_verify_cert_signature(const struct mg_tls_cert *cert,
|
||||
mg_der_next(&seq, &modulus) <= 0 || modulus.type != 2 ||
|
||||
modulus.len == 0 || mg_der_next(&seq, &exponent) <= 0 ||
|
||||
exponent.type != 2 || exponent.len == 0) {
|
||||
return -1;
|
||||
MG_ERROR(("failed to parse RSA issuer public key"));
|
||||
return false;
|
||||
}
|
||||
n = modulus.value, nlen = mg_rsa_trim_len(&n, modulus.len);
|
||||
if (nlen > sizeof(sig2) || cert->tbshashsz > nlen ||
|
||||
mg_rsa_mod_pow(modulus.value, modulus.len, exponent.value,
|
||||
exponent.len, (uint8_t *) cert->sig.buf, cert->sig.len,
|
||||
sig2, nlen) != 0) {
|
||||
return 0;
|
||||
MG_ERROR(("failed to process RSA cert sig"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return mg_rsa_pkcs_verify(sig2, nlen, cert->tbshash, cert->tbshashsz);
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ uint64_t mg_timegm(unsigned int year, unsigned int month, unsigned int day,
|
||||
const uint64_t day_secs = 86400;
|
||||
const uint64_t year_secs = 31536000;
|
||||
unsigned int y, ly;
|
||||
if (year < 1970) return 0;
|
||||
if (year < 1970 || month == 0 || month > 12) return 0;
|
||||
y = year - 1900;
|
||||
ly = month > 2 ? y + 1 : y;
|
||||
return (uint64_t) sec + 60 * min + 3600 * hour +
|
||||
|
||||
@@ -63,12 +63,14 @@ static uint32_t be32(const uint8_t *p) {
|
||||
(((uint32_t) p[1]) << 16) | (((uint32_t) p[0]) << 24);
|
||||
}
|
||||
|
||||
static size_t ws_process(uint8_t *buf, size_t len, struct ws_msg *msg) {
|
||||
static size_t ws_process(uint8_t *buf, size_t len, struct ws_msg *msg,
|
||||
bool *masked) {
|
||||
size_t i, n = 0, mask_len = 0;
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
if (len >= 2) {
|
||||
n = buf[1] & 0x7f; // Frame length
|
||||
mask_len = buf[1] & 128 ? 4 : 0; // last bit is a mask bit
|
||||
*masked = (buf[1] & 0x80) != 0; // b7 Mask, b6:0 Frame length
|
||||
n = buf[1] & 0x7f;
|
||||
mask_len = *masked ? 4 : 0;
|
||||
msg->flags = buf[0];
|
||||
if (n < 126 && len >= mask_len) {
|
||||
msg->data_len = n;
|
||||
@@ -77,14 +79,14 @@ static size_t ws_process(uint8_t *buf, size_t len, struct ws_msg *msg) {
|
||||
msg->header_len = 4 + mask_len;
|
||||
msg->data_len = (((size_t) buf[2]) << 8) | buf[3];
|
||||
} else if (len >= 10 + mask_len) {
|
||||
// Sanity check and protect the boundary check below: data_len should not
|
||||
// be larger than 1 GB, so it fits in 32-bits
|
||||
uint32_t hi = be32(buf + 2), lo = be32(buf + 6);
|
||||
if (hi != 0 || lo > 1024U * 1024U * 1024U) return 0;
|
||||
msg->data_len = (size_t) lo;
|
||||
msg->header_len = 10 + mask_len;
|
||||
msg->data_len =
|
||||
(size_t) (((uint64_t) be32(buf + 2) << 32) + be32(buf + 6));
|
||||
}
|
||||
}
|
||||
// Sanity check, and integer overflow protection for the boundary check below
|
||||
// data_len should not be larger than 1 Gb
|
||||
if (msg->data_len > 1024 * 1024 * 1024) return 0;
|
||||
if (msg->header_len + msg->data_len > len) return 0;
|
||||
if (mask_len > 0) {
|
||||
uint8_t *p = buf + msg->header_len, *m = p - mask_len;
|
||||
@@ -165,17 +167,23 @@ static bool mg_ws_client_handshake(struct mg_connection *c) {
|
||||
|
||||
static void mg_ws_cb(struct mg_connection *c, int ev, void *ev_data) {
|
||||
struct ws_msg msg;
|
||||
bool msk; // is this frame masked ?
|
||||
size_t ofs = (size_t) c->pfn_data;
|
||||
|
||||
// assert(ofs < c->recv.len);
|
||||
if (ev == MG_EV_READ) {
|
||||
if (c->is_client && !c->is_websocket && mg_ws_client_handshake(c)) return;
|
||||
|
||||
while (ws_process(c->recv.buf + ofs, c->recv.len - ofs, &msg) > 0) {
|
||||
while (ws_process(c->recv.buf + ofs, c->recv.len - ofs, &msg, &msk) > 0) {
|
||||
char *s = (char *) c->recv.buf + ofs + msg.header_len;
|
||||
struct mg_ws_message m;
|
||||
size_t len;
|
||||
uint8_t final, op;
|
||||
if (msk == c->is_client) {
|
||||
mg_error(c, c->is_client ? "masked WS server frame"
|
||||
: "unmasked WS client frame");
|
||||
return;
|
||||
}
|
||||
m.data.buf = s, m.data.len = msg.data_len, m.flags = msg.flags;
|
||||
len = msg.header_len + msg.data_len;
|
||||
final = msg.flags & 128;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
SRCS = mongoose.c unit_test.c packed_fs.c
|
||||
HDRS = $(wildcard ../src/*.h) $(wildcard ../src/drivers/*.h)
|
||||
DEFS ?= -DMG_MAX_HTTP_HEADERS=7 -DMG_ENABLE_LINES -DMG_ENABLE_SSI=1 -DMG_ENABLE_ASSERT=1 -DMG_ENABLE_IPV6=$(IPV6) -DMG_ENABLE_MDASH=$(MDASH)
|
||||
DEFS ?= -DMG_ENABLE_LINES -DMG_ENABLE_SSI=1 -DMG_ENABLE_ASSERT=1 -DMG_ENABLE_IPV6=$(IPV6) -DMG_ENABLE_MDASH=$(MDASH)
|
||||
WARN ?= -pedantic -W -Wall -Werror -Wshadow -Wdouble-promotion -fno-common -Wconversion -Wundef
|
||||
OPTS ?= -O3 -g3
|
||||
INCS ?= -Isrc -I.
|
||||
|
||||
+30
-2
@@ -1987,13 +1987,41 @@ static void test_http_parse(void) {
|
||||
}
|
||||
|
||||
{
|
||||
const char *s = "a b HTTP/1.0\na:1\nb:2\nc:3\nd:4\ne:5\nf:6\ng:7\nh:8\n\n";
|
||||
const char *s = "a b HTTP/1.0\na:1\nb:2\nc:3\nd:4\ne:5\nf:6\ng:7\n\n";
|
||||
ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
|
||||
ASSERT((v = mg_http_get_header(&req, "e")) != NULL);
|
||||
ASSERT(vcmp(*v, "5"));
|
||||
ASSERT((v = mg_http_get_header(&req, "g")) != NULL);
|
||||
ASSERT(vcmp(*v, "7"));
|
||||
ASSERT((v = mg_http_get_header(&req, "h")) == NULL); // MG_MAX_HTTP_HEADERS
|
||||
|
||||
{
|
||||
char headers[MG_MAX_HTTP_HEADERS * 10 + 32];
|
||||
size_t i, len = 0;
|
||||
len += (size_t) mg_snprintf(headers + len, sizeof(headers) - len,
|
||||
"a b HTTP/1.0\n");
|
||||
for (i = 0; i <= MG_MAX_HTTP_HEADERS; i++) {
|
||||
len += (size_t) mg_snprintf(headers + len, sizeof(headers) - len,
|
||||
"h%u:1\n", (unsigned) i);
|
||||
}
|
||||
len += (size_t) mg_snprintf(headers + len, sizeof(headers) - len, "\n");
|
||||
ASSERT(mg_http_parse(headers, len, &req) == -1); // MG_MAX_HTTP_HEADERS
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
char headers[MG_MAX_HTTP_HEADERS * 10 + 128];
|
||||
size_t i, len = 0;
|
||||
len += (size_t) mg_snprintf(headers + len, sizeof(headers) - len,
|
||||
"GET /public HTTP/1.1\r\n");
|
||||
for (i = 0; i < MG_MAX_HTTP_HEADERS; i++) {
|
||||
len += (size_t) mg_snprintf(headers + len, sizeof(headers) - len,
|
||||
"h%u:1\r\n", (unsigned) i);
|
||||
}
|
||||
len += (size_t) mg_snprintf(headers + len, sizeof(headers) - len,
|
||||
"Content-Length: 43\r\n\r\n"
|
||||
"POST /admin HTTP/1.1\r\n"
|
||||
"Content-Length: 0\r\n\r\n");
|
||||
ASSERT(mg_http_parse(headers, len, &req) == -1);
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user