mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-12 10:13:29 +00:00
patch
This commit is contained in:
+224
-119
@@ -408,6 +408,7 @@ void mg_resolve(struct mg_connection *c, const char *url) {
|
||||
}
|
||||
}
|
||||
|
||||
// Response header length is 10 bytes
|
||||
static const uint8_t mdns_answer[] = {
|
||||
0, 1, // 2 bytes - record type, A
|
||||
0, 1, // 2 bytes - address class, INET
|
||||
@@ -415,6 +416,7 @@ static const uint8_t mdns_answer[] = {
|
||||
0, 4 // 2 bytes - address length
|
||||
};
|
||||
|
||||
// A name length is name->len + '.local' + 2 = name->len + 8
|
||||
static uint8_t *build_name(struct mg_str *name, uint8_t *p) {
|
||||
*p++ = (uint8_t) name->len; // label 1
|
||||
memcpy(p, name->buf, name->len), p += name->len;
|
||||
@@ -426,6 +428,7 @@ static uint8_t *build_name(struct mg_str *name, uint8_t *p) {
|
||||
|
||||
void mg_getlocaddr(struct mg_connection *, struct mg_addr *, struct mg_addr *);
|
||||
|
||||
// An A record length is 10 + 4 = 14 bytes
|
||||
static uint8_t *build_a_record(struct mg_connection *c, uint8_t *p,
|
||||
struct mg_addr *addr) {
|
||||
memcpy(p, mdns_answer, sizeof(mdns_answer)), p += sizeof(mdns_answer);
|
||||
@@ -447,6 +450,7 @@ static uint8_t *build_a_record(struct mg_connection *c, uint8_t *p,
|
||||
return p;
|
||||
}
|
||||
|
||||
// A srv name length is r->srvcproto.len + '.local' + 2 = r->srvcproto.len + 8
|
||||
static uint8_t *build_srv_name(uint8_t *p, struct mg_dnssd_record *r) {
|
||||
*p++ = (uint8_t) r->srvcproto.len - 5; // label 1, up to '._tcp'
|
||||
memcpy(p, r->srvcproto.buf, r->srvcproto.len), p += r->srvcproto.len;
|
||||
@@ -467,6 +471,7 @@ static uint8_t *build_mysrv_name(struct mg_str *name, uint8_t *p,
|
||||
}
|
||||
#endif
|
||||
|
||||
// A PTR record length is 10 + name->len + 3 = name->len + 13
|
||||
static uint8_t *build_ptr_record(struct mg_str *name, uint8_t *p, uint16_t o) {
|
||||
uint16_t offset = mg_htons(o);
|
||||
memcpy(p, mdns_answer, sizeof(mdns_answer));
|
||||
@@ -481,6 +486,7 @@ static uint8_t *build_ptr_record(struct mg_str *name, uint8_t *p, uint16_t o) {
|
||||
return p;
|
||||
}
|
||||
|
||||
// An SRV record length is 10 + name->len + 9 = name->len + 19
|
||||
static uint8_t *build_srv_record(struct mg_str *name, uint8_t *p,
|
||||
struct mg_dnssd_record *r, uint16_t o) {
|
||||
uint16_t port = mg_htons(r->port);
|
||||
@@ -501,6 +507,7 @@ static uint8_t *build_srv_record(struct mg_str *name, uint8_t *p,
|
||||
return p;
|
||||
}
|
||||
|
||||
// A TXT record length is r->txt.len (txt contents) + 10
|
||||
static uint8_t *build_txt_record(uint8_t *p, struct mg_dnssd_record *r) {
|
||||
uint16_t len = mg_htons((uint16_t) r->txt.len);
|
||||
memcpy(p, mdns_answer, sizeof(mdns_answer));
|
||||
@@ -511,6 +518,8 @@ static uint8_t *build_txt_record(uint8_t *p, struct mg_dnssd_record *r) {
|
||||
return p;
|
||||
}
|
||||
|
||||
// Each additional record has a 2-byte field pointing to the name label
|
||||
|
||||
// RFC-6762 16: case-insensitivity --> RFC-1034, 1035
|
||||
|
||||
static void handle_mdns_query(struct mg_connection *c) {
|
||||
@@ -599,6 +608,10 @@ static void handle_mdns_query(struct mg_connection *c) {
|
||||
uint8_t *o = p, *aux;
|
||||
uint16_t offset;
|
||||
if (respname->buf == NULL || respname->len == 0) return;
|
||||
if ((sizeof(*h) + req.r->srvcproto.len + 8 + respname->len + 13 + 2 +
|
||||
respname->len + 19 + 2 + req.r->txt.len + 10 + 2 + 14) >
|
||||
sizeof(buf)) // srv name + PTR + 2 + SRV + 2 + TXT + 2 + A
|
||||
return;
|
||||
h->num_other_prs = mg_htons(3); // 3 additional records
|
||||
p = build_srv_name(p, req.r);
|
||||
aux = build_ptr_record(respname, p, (uint16_t) (o - buf));
|
||||
@@ -619,12 +632,18 @@ static void handle_mdns_query(struct mg_connection *c) {
|
||||
*p |= 0xC0, p += 2;
|
||||
p = build_a_record(c, p, req.addr);
|
||||
} else if (rr.atype == MG_DNS_RTYPE_TXT) {
|
||||
if ((sizeof(*h) + req.r->srvcproto.len + 8 + req.r->txt.len + 10) >
|
||||
sizeof(buf)) // srv name + TXT
|
||||
return;
|
||||
p = build_srv_name(p, req.r);
|
||||
p = build_txt_record(p, req.r);
|
||||
} else if (rr.atype == MG_DNS_RTYPE_SRV) { // serve SRV + A
|
||||
uint8_t *o, *aux;
|
||||
uint16_t offset;
|
||||
if (respname->buf == NULL || respname->len == 0) return;
|
||||
if ((sizeof(*h) + req.r->srvcproto.len + 8 + respname->len + 19 + 2 +
|
||||
14) > sizeof(buf)) // srv name + SRV + 2 + A
|
||||
return;
|
||||
h->num_other_prs = mg_htons(1); // 1 additional record
|
||||
p = build_srv_name(p, req.r);
|
||||
o = p - 7; // point to '.local' label (\x05local\x00)
|
||||
@@ -638,6 +657,8 @@ static void handle_mdns_query(struct mg_connection *c) {
|
||||
} else { // A requested
|
||||
// RFC-6762 6: 0 Auth, 0 Additional RRs
|
||||
if (respname->buf == NULL || respname->len == 0) return;
|
||||
if ((sizeof(*h) + respname->len + 8 + 14) > sizeof(buf)) // name + A
|
||||
return;
|
||||
p = build_name(respname, p);
|
||||
p = build_a_record(c, p, req.addr);
|
||||
}
|
||||
@@ -1941,6 +1962,8 @@ static const char *skiptorn(const char *s, const char *end, struct mg_str *v) {
|
||||
static bool mg_http_parse_headers(const char *s, const char *end,
|
||||
struct mg_http_header *h, size_t max_hdrs) {
|
||||
size_t i, n;
|
||||
int cl_count = 0, te_count = 0, auth_count = 0;
|
||||
int conn_count = 0, cookie_count = 0;
|
||||
for (i = 0; i < max_hdrs; i++) {
|
||||
struct mg_str k = {NULL, 0}, v = {NULL, 0};
|
||||
if (s >= end) return false;
|
||||
@@ -1956,6 +1979,13 @@ static bool mg_http_parse_headers(const char *s, const char *end,
|
||||
while (v.len > 0 && (v.buf[v.len - 1] == ' ' || v.buf[v.len - 1] == '\t')) {
|
||||
v.len--; // Trim spaces
|
||||
}
|
||||
// detect duplicated headers -> discard
|
||||
if (((mg_strcasecmp(k, mg_str("Content-Length")) == 0) && (++cl_count > 1)) ||
|
||||
((mg_strcasecmp(k, mg_str("Transfer-Encoding")) == 0) && (++te_count > 1)) ||
|
||||
((mg_strcasecmp(k, mg_str("Authorization")) == 0) && (++auth_count > 1)) ||
|
||||
((mg_strcasecmp(k, mg_str("Cookie")) == 0) && (++cookie_count > 1)) ||
|
||||
((mg_strcasecmp(k, mg_str("Connection")) == 0) && (++conn_count > 1)))
|
||||
return false;
|
||||
// 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
|
||||
}
|
||||
@@ -1990,6 +2020,8 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
|
||||
// If we're given a version, check that it is HTTP/x.x
|
||||
version_prefix_valid =
|
||||
hm->proto.len > 5 && (mg_ncasecmp(hm->proto.buf, "HTTP/", 5) == 0);
|
||||
if (!is_response && !version_prefix_valid)
|
||||
return -1; // no version detected in request
|
||||
if (!is_response && hm->proto.len > 0 &&
|
||||
(!version_prefix_valid || hm->proto.len != 8 ||
|
||||
(hm->proto.buf[5] < '0' || hm->proto.buf[5] > '9') ||
|
||||
@@ -2739,7 +2771,11 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) {
|
||||
hm.message.len = c->recv.len - ofs; // and closes now, deliver MSG
|
||||
hm.body.len = hm.message.len - (size_t) (hm.body.buf - hm.message.buf);
|
||||
}
|
||||
if ((te = mg_http_get_header(&hm, "Transfer-Encoding")) != NULL) {
|
||||
bool is_http_1_0 =
|
||||
hm.proto.len > 8 && mg_ncasecmp(hm.proto.buf, "HTTP/1.0", 8) == 0;
|
||||
// HTTP/1.0 does not use "Transfer-Encoding: chunked"
|
||||
if (!is_http_1_0 &&
|
||||
(te = mg_http_get_header(&hm, "Transfer-Encoding")) != NULL) {
|
||||
if (mg_strcasecmp(*te, mg_str("chunked")) == 0) {
|
||||
is_chunked = true;
|
||||
} else {
|
||||
@@ -2963,15 +2999,28 @@ static double mg_atod(const char *p, int len, int *numlen) {
|
||||
|
||||
// Exponential
|
||||
if (i < len && (p[i] == 'e' || p[i] == 'E')) {
|
||||
int j, exp = 0, minus = 0;
|
||||
int exp = 0, minus = 0;
|
||||
i++;
|
||||
if (i < len && p[i] == '-') minus = 1, i++;
|
||||
if (i < len && p[i] == '+') i++;
|
||||
while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308)
|
||||
exp = exp * 10 + (p[i++] - '0');
|
||||
if (minus) exp = -exp;
|
||||
for (j = 0; j < exp; j++) d *= 10.0;
|
||||
for (j = 0; j < -exp; j++) d /= 10.0;
|
||||
// use fast exponentiation
|
||||
// https://en.wikipedia.org/wiki/Exponentiation_by_squaring
|
||||
if (exp != 0) {
|
||||
double x = 10, y = 1;
|
||||
if (exp > 308) exp = 308;
|
||||
if (minus) x = 0.1;
|
||||
while (exp > 1) {
|
||||
if (exp & 1) {
|
||||
y *= x;
|
||||
--exp;
|
||||
}
|
||||
x *= x;
|
||||
exp >>= 1;
|
||||
}
|
||||
d *= x * y;
|
||||
}
|
||||
}
|
||||
|
||||
if (numlen != NULL) *numlen = i;
|
||||
@@ -5462,9 +5511,13 @@ static struct mg_connection *getpeer(struct mg_mgr *mgr, struct pkt *pkt,
|
||||
!(c->loc.is_ip6 ^ (pkt->ip6 != NULL))) // IP or IPv6 to same dest
|
||||
break;
|
||||
if (!c->is_udp && pkt->tcp && c->loc.port == pkt->tcp->dport &&
|
||||
!(c->loc.is_ip6 ^ (pkt->ip6 != NULL)) &&
|
||||
lsn == (bool) c->is_listening &&
|
||||
(lsn || c->rem.port == pkt->tcp->sport))
|
||||
((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 && c->rem.addr.ip4 == pkt->ip->src)
|
||||
#if MG_ENABLE_IPV6
|
||||
|| (c->loc.is_ip6 && MG_IP6MATCH(c->rem.addr.ip6, pkt->ip6->src))
|
||||
#endif
|
||||
)))) // validate addr for established (not listening) conns
|
||||
break;
|
||||
}
|
||||
return c;
|
||||
@@ -6408,7 +6461,7 @@ static void backlog_poll(struct mg_mgr *mgr) {
|
||||
}
|
||||
|
||||
// process options (MSS)
|
||||
static void handle_opt(struct connstate *s, struct tcp *tcp, bool ip6) {
|
||||
static bool handle_opt(struct connstate *s, struct tcp *tcp, bool ip6) {
|
||||
uint8_t *opts = (uint8_t *) (tcp + 1);
|
||||
int len = 4 * ((int) (tcp->off >> 4) - ((int) sizeof(*tcp) / 4));
|
||||
s->dmss = ip6 ? 1220 : 536; // assume default, RFC-9293 3.7.1
|
||||
@@ -6416,6 +6469,7 @@ static void handle_opt(struct connstate *s, struct tcp *tcp, bool ip6) {
|
||||
uint8_t kind = opts[0], optlen = 1;
|
||||
if (kind != 1) { // No-Operation
|
||||
if (kind == 0) break; // End of Option List
|
||||
if (len < 2 || opts[1] == 0) return false; // Malformed options
|
||||
optlen = opts[1];
|
||||
if (kind == 2 && optlen == 4) // set received MSS
|
||||
s->dmss = (uint16_t) (((uint16_t) opts[2] << 8) + opts[3]);
|
||||
@@ -6424,6 +6478,7 @@ static void handle_opt(struct connstate *s, struct tcp *tcp, bool ip6) {
|
||||
opts += optlen;
|
||||
len -= optlen;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
|
||||
@@ -6438,7 +6493,7 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
|
||||
// - check clients (Group 1) and established connections (Group 3)
|
||||
if (c != NULL && c->is_connecting && pkt->tcp->flags == (TH_SYN | TH_ACK)) {
|
||||
// client got a server connection accept
|
||||
handle_opt(s, pkt->tcp, pkt->ip6 != NULL); // process options (MSS)
|
||||
if (!handle_opt(s, pkt->tcp, pkt->ip6 != NULL)) return; // process options (MSS)
|
||||
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1;
|
||||
tx_tcp_ctrlresp(ifp, pkt, TH_ACK, pkt->tcp->ack);
|
||||
c->is_connecting = 0; // Client connected
|
||||
@@ -6449,8 +6504,9 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
|
||||
} else if (c != NULL && c->is_connecting && pkt->tcp->flags != TH_ACK) {
|
||||
mg_error(c, "connection refused");
|
||||
} else if (c != NULL && pkt->tcp->flags & TH_RST) {
|
||||
// TODO(): validate RST is within window (and optional with proper ACK)
|
||||
mg_error(c, "peer RST"); // RFC-1122 4.2.2.13
|
||||
uint32_t seqno = mg_ntohl(pkt->tcp->seq);
|
||||
if (seqno >= s->ack && seqno < (s->ack + MG_TCPIP_WIN)) // RFC-9293 3.5.3
|
||||
mg_error(c, "peer RST"); // RFC-1122 4.2.2.13
|
||||
} else if (c != NULL) {
|
||||
// process segment
|
||||
s->tmiss = 0; // Reset missed keep-alive counter
|
||||
@@ -6472,7 +6528,7 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
|
||||
int key;
|
||||
uint32_t isn;
|
||||
if (pkt->tcp->sport != 0) {
|
||||
handle_opt(&cs, pkt->tcp, pkt->ip6 != NULL); // process options (MSS)
|
||||
if (!handle_opt(&cs, pkt->tcp, pkt->ip6 != NULL)) return; // process options (MSS)
|
||||
key = backlog_insert(c, pkt->tcp->sport,
|
||||
cs.dmss); // backlog options (MSS)
|
||||
if (key < 0) return; // no room in backlog, discard SYN, client retries
|
||||
@@ -11365,7 +11421,9 @@ bool mg_match(struct mg_str s, struct mg_str p, struct mg_str *caps) {
|
||||
} else if (i < p.len && (p.buf[i] == '*' || p.buf[i] == '#')) {
|
||||
if (caps && !caps->buf) caps->len = 0, caps->buf = &s.buf[j]; // Init cap
|
||||
ni = i++, nj = j + 1;
|
||||
} else if (nj > 0 && nj <= s.len && ((ni < p.len && p.buf[ni] == '#') || s.buf[j] != '/')) {
|
||||
} else if (nj > 0 && nj <= s.len &&
|
||||
((ni < p.len && p.buf[ni] == '#') ||
|
||||
(j < s.len && s.buf[j] != '/'))) {
|
||||
i = ni, j = nj;
|
||||
if (caps && caps->buf == NULL && caps->len == 0) {
|
||||
caps--, caps->len = 0; // Restart previous cap
|
||||
@@ -11446,8 +11504,7 @@ bool mg_str_to_num(struct mg_str str, int base, void *val, size_t val_len) {
|
||||
i++, ndigits++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
default: return false;
|
||||
}
|
||||
if (ndigits == 0) return false;
|
||||
if (i != str.len) return false;
|
||||
@@ -11557,45 +11614,47 @@ static void aes_init_keygen_tables(void);
|
||||
/******************************************************************************
|
||||
* AES_SETKEY : called to expand the key for encryption or decryption
|
||||
******************************************************************************/
|
||||
static int aes_setkey(aes_context *ctx, // pointer to context
|
||||
int mode, // 1 or 0 for Encrypt/Decrypt
|
||||
const unsigned char *key, // AES input key
|
||||
unsigned int keysize); // size in bytes (must be 16, 24, 32 for
|
||||
// 128, 192 or 256-bit keys respectively)
|
||||
// returns 0 for success
|
||||
static int aes_setkey(
|
||||
aes_context *ctx, // pointer to context
|
||||
int mode, // 1 or 0 for Encrypt/Decrypt
|
||||
const unsigned char *key, // AES input key
|
||||
unsigned int keysize); // size in bytes (must be 16, 24, 32 for
|
||||
// 128, 192 or 256-bit keys respectively)
|
||||
// returns 0 for success
|
||||
|
||||
/******************************************************************************
|
||||
* AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data
|
||||
******************************************************************************/
|
||||
static int aes_cipher(aes_context *ctx, // pointer to context
|
||||
const unsigned char input[16], // 128-bit block to en/decipher
|
||||
unsigned char output[16]); // 128-bit output result block
|
||||
// returns 0 for success
|
||||
static int aes_cipher(
|
||||
aes_context *ctx, // pointer to context
|
||||
const unsigned char input[16], // 128-bit block to en/decipher
|
||||
unsigned char output[16]); // 128-bit output result block
|
||||
// returns 0 for success
|
||||
|
||||
/******************************************************************************
|
||||
* GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
int mode; // cipher direction: encrypt/decrypt
|
||||
uint64_t len; // cipher data length processed so far
|
||||
uint64_t add_len; // total add data length
|
||||
uint64_t HL[16]; // precalculated lo-half HTable
|
||||
uint64_t HH[16]; // precalculated hi-half HTable
|
||||
int mode; // cipher direction: encrypt/decrypt
|
||||
uint64_t len; // cipher data length processed so far
|
||||
uint64_t add_len; // total add data length
|
||||
uint64_t HL[16]; // precalculated lo-half HTable
|
||||
uint64_t HH[16]; // precalculated hi-half HTable
|
||||
unsigned char base_ectr[16]; // first counter-mode cipher output for tag
|
||||
unsigned char y[16]; // the current cipher-input IV|Counter value
|
||||
unsigned char buf[16]; // buf working value
|
||||
aes_context aes_ctx; // cipher context used
|
||||
aes_context aes_ctx; // cipher context used
|
||||
} gcm_context;
|
||||
|
||||
/******************************************************************************
|
||||
* GCM_SETKEY : sets the GCM (and AES) keying material for use
|
||||
******************************************************************************/
|
||||
static int gcm_setkey(
|
||||
gcm_context *ctx, // caller-provided context ptr
|
||||
gcm_context *ctx, // caller-provided context ptr
|
||||
const unsigned char *key, // pointer to cipher key
|
||||
const unsigned int keysize // size in bytes (must be 16, 24, 32 for
|
||||
// 128, 192 or 256-bit keys respectively)
|
||||
); // returns 0 for success
|
||||
// 128, 192 or 256-bit keys respectively)
|
||||
); // returns 0 for success
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
@@ -11615,17 +11674,17 @@ static int gcm_setkey(
|
||||
*
|
||||
******************************************************************************/
|
||||
static int gcm_crypt_and_tag(
|
||||
gcm_context *ctx, // gcm context with key already setup
|
||||
int mode, // cipher direction: MG_ENCRYPT (1) or MG_DECRYPT (0)
|
||||
gcm_context *ctx, // gcm context with key already setup
|
||||
int mode, // cipher direction: MG_ENCRYPT (1) or MG_DECRYPT (0)
|
||||
const unsigned char *iv, // pointer to the 12-byte initialization vector
|
||||
size_t iv_len, // byte length if the IV. should always be 12
|
||||
size_t iv_len, // byte length if the IV. should always be 12
|
||||
const unsigned char *add, // pointer to the non-ciphered additional data
|
||||
size_t add_len, // byte length of the additional AEAD data
|
||||
size_t add_len, // byte length of the additional AEAD data
|
||||
const unsigned char *input, // pointer to the cipher data source
|
||||
unsigned char *output, // pointer to the cipher data destination
|
||||
size_t length, // byte length of the cipher data
|
||||
size_t length, // byte length of the cipher data
|
||||
unsigned char *tag, // pointer to the tag to be generated
|
||||
size_t tag_len); // byte length of the tag to be generated
|
||||
size_t tag_len); // byte length of the tag to be generated
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
@@ -11636,12 +11695,12 @@ static int gcm_crypt_and_tag(
|
||||
*
|
||||
******************************************************************************/
|
||||
static int gcm_start(
|
||||
gcm_context *ctx, // pointer to user-provided GCM context
|
||||
int mode, // MG_ENCRYPT (1) or MG_DECRYPT (0)
|
||||
gcm_context *ctx, // pointer to user-provided GCM context
|
||||
int mode, // MG_ENCRYPT (1) or MG_DECRYPT (0)
|
||||
const unsigned char *iv, // pointer to initialization vector
|
||||
size_t iv_len, // IV length in bytes (should == 12)
|
||||
size_t iv_len, // IV length in bytes (should == 12)
|
||||
const unsigned char *add, // pointer to additional AEAD data (NULL if none)
|
||||
size_t add_len); // length of additional AEAD data (bytes)
|
||||
size_t add_len); // length of additional AEAD data (bytes)
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
@@ -11657,7 +11716,7 @@ static int gcm_start(
|
||||
static int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
size_t length, // length, in bytes, of data to process
|
||||
const unsigned char *input, // pointer to source data
|
||||
unsigned char *output); // pointer to destination data
|
||||
unsigned char *output); // pointer to destination data
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
@@ -11668,9 +11727,9 @@ static int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
*
|
||||
******************************************************************************/
|
||||
static int gcm_finish(
|
||||
gcm_context *ctx, // pointer to user-provided GCM context
|
||||
unsigned char *tag, // ptr to tag buffer - NULL if tag_len = 0
|
||||
size_t tag_len); // length, in bytes, of the tag-receiving buf
|
||||
gcm_context *ctx, // pointer to user-provided GCM context
|
||||
unsigned char *tag, // ptr to tag buffer - NULL if tag_len = 0
|
||||
size_t tag_len); // length, in bytes, of the tag-receiving buf
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
@@ -11721,15 +11780,15 @@ static int aes_tables_inited = 0; // run-once flag for performing key
|
||||
* decryption is typically disabled by setting AES_DECRYPTION to 0 in aes.h.
|
||||
*/
|
||||
// We always need our forward tables
|
||||
static unsigned char FSb[256]; // Forward substitution box (FSb)
|
||||
static uint32_t FT0[256]; // Forward key schedule assembly tables
|
||||
static unsigned char FSb[256]; // Forward substitution box (FSb)
|
||||
static uint32_t FT0[256]; // Forward key schedule assembly tables
|
||||
static uint32_t FT1[256];
|
||||
static uint32_t FT2[256];
|
||||
static uint32_t FT3[256];
|
||||
|
||||
#if AES_DECRYPTION // We ONLY need reverse for decryption
|
||||
static unsigned char RSb[256]; // Reverse substitution box (RSb)
|
||||
static uint32_t RT0[256]; // Reverse key schedule assembly tables
|
||||
#if AES_DECRYPTION // We ONLY need reverse for decryption
|
||||
static unsigned char RSb[256]; // Reverse substitution box (RSb)
|
||||
static uint32_t RT0[256]; // Reverse key schedule assembly tables
|
||||
static uint32_t RT1[256];
|
||||
static uint32_t RT2[256];
|
||||
static uint32_t RT3[256];
|
||||
@@ -11747,8 +11806,8 @@ static uint32_t RCON[10]; // AES round constants
|
||||
((uint32_t) (b)[(i) + 2] << 16) | ((uint32_t) (b)[(i) + 3] << 24); \
|
||||
}
|
||||
|
||||
#define PUT_UINT32_LE(n, b, i) \
|
||||
{ \
|
||||
#define PUT_UINT32_LE(n, b, i) \
|
||||
{ \
|
||||
(b)[(i)] = (unsigned char) ((n)); \
|
||||
(b)[(i) + 1] = (unsigned char) ((n) >> 8); \
|
||||
(b)[(i) + 2] = (unsigned char) ((n) >> 16); \
|
||||
@@ -11893,7 +11952,7 @@ void aes_init_keygen_tables(void) {
|
||||
******************************************************************************/
|
||||
static int aes_set_encryption_key(aes_context *ctx, const unsigned char *key,
|
||||
unsigned int keysize) {
|
||||
unsigned int i; // general purpose iteration local
|
||||
unsigned int i; // general purpose iteration local
|
||||
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
|
||||
|
||||
for (i = 0; i < (keysize >> 2); i++) {
|
||||
@@ -12228,8 +12287,8 @@ static const uint64_t last4[16] = {
|
||||
((uint32_t) (b)[(i) + 2] << 8) | ((uint32_t) (b)[(i) + 3]); \
|
||||
}
|
||||
|
||||
#define PUT_UINT32_BE(n, b, i) \
|
||||
{ \
|
||||
#define PUT_UINT32_BE(n, b, i) \
|
||||
{ \
|
||||
(b)[(i)] = (unsigned char) ((n) >> 24); \
|
||||
(b)[(i) + 1] = (unsigned char) ((n) >> 16); \
|
||||
(b)[(i) + 2] = (unsigned char) ((n) >> 8); \
|
||||
@@ -12262,9 +12321,10 @@ int mg_gcm_initialize(void) {
|
||||
* 'x' and 'output' are seen as elements of GCM's GF(2^128) Galois field.
|
||||
*
|
||||
******************************************************************************/
|
||||
static void gcm_mult(gcm_context *ctx, // pointer to established context
|
||||
const unsigned char x[16], // pointer to 128-bit input vector
|
||||
unsigned char output[16]) // pointer to 128-bit output vector
|
||||
static void gcm_mult(
|
||||
gcm_context *ctx, // pointer to established context
|
||||
const unsigned char x[16], // pointer to 128-bit input vector
|
||||
unsigned char output[16]) // pointer to 128-bit output vector
|
||||
{
|
||||
int i;
|
||||
unsigned char lo, hi, rem;
|
||||
@@ -12309,10 +12369,10 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context
|
||||
*
|
||||
******************************************************************************/
|
||||
static int gcm_setkey(
|
||||
gcm_context *ctx, // pointer to caller-provided gcm context
|
||||
gcm_context *ctx, // pointer to caller-provided gcm context
|
||||
const unsigned char *key, // pointer to the AES encryption key
|
||||
const unsigned int keysize) // size in bytes (must be 16, 24, 32 for
|
||||
// 128, 192 or 256-bit keys respectively)
|
||||
// 128, 192 or 256-bit keys respectively)
|
||||
{
|
||||
int ret, i, j;
|
||||
uint64_t hi, lo;
|
||||
@@ -12381,18 +12441,19 @@ static int gcm_setkey(
|
||||
* mode, and preprocesses the initialization vector and additional AEAD data.
|
||||
*
|
||||
******************************************************************************/
|
||||
int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
int mode, // GCM_ENCRYPT or GCM_DECRYPT
|
||||
const unsigned char *iv, // pointer to initialization vector
|
||||
size_t iv_len, // IV length in bytes (should == 12)
|
||||
const unsigned char *add, // ptr to additional AEAD data (NULL if none)
|
||||
size_t add_len) // length of additional AEAD data (bytes)
|
||||
int gcm_start(
|
||||
gcm_context *ctx, // pointer to user-provided GCM context
|
||||
int mode, // GCM_ENCRYPT or GCM_DECRYPT
|
||||
const unsigned char *iv, // pointer to initialization vector
|
||||
size_t iv_len, // IV length in bytes (should == 12)
|
||||
const unsigned char *add, // ptr to additional AEAD data (NULL if none)
|
||||
size_t add_len) // length of additional AEAD data (bytes)
|
||||
{
|
||||
int ret; // our error return if the AES encrypt fails
|
||||
int ret; // our error return if the AES encrypt fails
|
||||
unsigned char work_buf[16]; // XOR source built from provided IV if len != 16
|
||||
const unsigned char *p; // general purpose array pointer
|
||||
size_t use_len; // byte count to process, up to 16 bytes
|
||||
size_t i; // local loop iterator
|
||||
size_t use_len; // byte count to process, up to 16 bytes
|
||||
size_t i; // local loop iterator
|
||||
|
||||
// since the context might be reused under the same key
|
||||
// we zero the working buffers for this next new process
|
||||
@@ -12449,15 +12510,15 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
* have a partial block length of < 128 bits.)
|
||||
*
|
||||
******************************************************************************/
|
||||
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
size_t length, // length, in bytes, of data to process
|
||||
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
size_t length, // length, in bytes, of data to process
|
||||
const unsigned char *input, // pointer to source data
|
||||
unsigned char *output) // pointer to destination data
|
||||
{
|
||||
int ret; // our error return if the AES encrypt fails
|
||||
int ret; // our error return if the AES encrypt fails
|
||||
unsigned char ectr[16]; // counter-mode cipher output for XORing
|
||||
size_t use_len; // byte count to process, up to 16 bytes
|
||||
size_t i; // local loop iterator
|
||||
size_t use_len; // byte count to process, up to 16 bytes
|
||||
size_t i; // local loop iterator
|
||||
|
||||
ctx->len += length; // bump the GCM context's running length count
|
||||
|
||||
@@ -12513,9 +12574,9 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
* It performs the final GHASH to produce the resulting authentication TAG.
|
||||
*
|
||||
******************************************************************************/
|
||||
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
unsigned char *tag, // pointer to buffer which receives the tag
|
||||
size_t tag_len) // length, in bytes, of the tag-receiving buf
|
||||
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
unsigned char *tag, // pointer to buffer which receives the tag
|
||||
size_t tag_len) // length, in bytes, of the tag-receiving buf
|
||||
{
|
||||
unsigned char work_buf[16];
|
||||
uint64_t orig_len = ctx->len * 8;
|
||||
@@ -12557,22 +12618,22 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
*
|
||||
******************************************************************************/
|
||||
int gcm_crypt_and_tag(
|
||||
gcm_context *ctx, // gcm context with key already setup
|
||||
int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT
|
||||
gcm_context *ctx, // gcm context with key already setup
|
||||
int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT
|
||||
const unsigned char *iv, // pointer to the 12-byte initialization vector
|
||||
size_t iv_len, // byte length if the IV. should always be 12
|
||||
size_t iv_len, // byte length if the IV. should always be 12
|
||||
const unsigned char *add, // pointer to the non-ciphered additional data
|
||||
size_t add_len, // byte length of the additional AEAD data
|
||||
size_t add_len, // byte length of the additional AEAD data
|
||||
const unsigned char *input, // pointer to the cipher data source
|
||||
unsigned char *output, // pointer to the cipher data destination
|
||||
size_t length, // byte length of the cipher data
|
||||
size_t length, // byte length of the cipher data
|
||||
unsigned char *tag, // pointer to the tag to be generated
|
||||
size_t tag_len) // byte length of the tag to be generated
|
||||
{ /*
|
||||
assuming that the caller has already invoked gcm_setkey to
|
||||
prepare the gcm context with the keying material, we simply
|
||||
invoke each of the three GCM sub-functions in turn...
|
||||
*/
|
||||
size_t tag_len) // byte length of the tag to be generated
|
||||
{ /*
|
||||
assuming that the caller has already invoked gcm_setkey to
|
||||
prepare the gcm context with the keying material, we simply
|
||||
invoke each of the three GCM sub-functions in turn...
|
||||
*/
|
||||
gcm_start(ctx, mode, iv, iv_len, add, add_len);
|
||||
gcm_update(ctx, length, input, output);
|
||||
gcm_finish(ctx, tag, tag_len);
|
||||
@@ -12622,20 +12683,28 @@ int mg_aes_gcm_encrypt(unsigned char *output, //
|
||||
int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
|
||||
size_t input_length, const unsigned char *key,
|
||||
const size_t key_len, const unsigned char *iv,
|
||||
const size_t iv_len) {
|
||||
const size_t iv_len, unsigned char *aead,
|
||||
size_t aead_len, const unsigned char *tag,
|
||||
const size_t tag_len) {
|
||||
int ret = 0; // our return value
|
||||
gcm_context ctx; // includes the AES context structure
|
||||
unsigned char computed_tag[16];
|
||||
size_t i;
|
||||
int diff = 0;
|
||||
|
||||
size_t tag_len = 0;
|
||||
unsigned char *tag_buf = NULL;
|
||||
if (tag_len > sizeof(computed_tag)) return -1;
|
||||
|
||||
gcm_setkey(&ctx, key, (unsigned int) key_len);
|
||||
|
||||
ret = gcm_crypt_and_tag(&ctx, MG_DECRYPT, iv, iv_len, NULL, 0, input, output,
|
||||
input_length, tag_buf, tag_len);
|
||||
ret = gcm_crypt_and_tag(&ctx, MG_DECRYPT, iv, iv_len, aead, aead_len, input,
|
||||
output, input_length, computed_tag, tag_len);
|
||||
|
||||
gcm_zero_ctx(&ctx);
|
||||
|
||||
// compare tags
|
||||
for (i = 0; i < tag_len; i++) diff |= computed_tag[i] ^ tag[i];
|
||||
if (diff != 0) ret = -1;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
#endif
|
||||
@@ -13201,14 +13270,19 @@ static int mg_tls_recv_record(struct mg_connection *c) {
|
||||
nonce[11] ^= (uint8_t) ((seq) & 255U);
|
||||
#if MG_ENABLE_CHACHA20
|
||||
{
|
||||
uint8_t associated_data[5] = {MG_TLS_APP_DATA, 0x03, 0x03,
|
||||
(uint8_t) ((msgsz >> 8) & 0xff),
|
||||
(uint8_t) (msgsz & 0xff)};
|
||||
uint8_t *dec = (uint8_t *) mg_calloc(1, msgsz);
|
||||
size_t n;
|
||||
if (dec == NULL) {
|
||||
mg_error(c, "TLS OOM");
|
||||
return -1;
|
||||
}
|
||||
n = mg_chacha20_poly1305_decrypt(dec, key, nonce, msg, msgsz);
|
||||
n = mg_chacha20_poly1305_decrypt(dec, key, nonce, associated_data,
|
||||
sizeof(associated_data), msg, msgsz);
|
||||
if (n == (size_t) -1) {
|
||||
mg_free(dec);
|
||||
mg_error(c, "decryption error");
|
||||
return -1;
|
||||
}
|
||||
@@ -13216,8 +13290,18 @@ static int mg_tls_recv_record(struct mg_connection *c) {
|
||||
mg_free(dec);
|
||||
}
|
||||
#else
|
||||
mg_gcm_initialize();
|
||||
mg_aes_gcm_decrypt(msg, msg, msgsz - 16, key, 16, nonce, sizeof(nonce));
|
||||
{
|
||||
uint8_t associated_data[5] = {MG_TLS_APP_DATA, 0x03, 0x03,
|
||||
(uint8_t) ((msgsz >> 8) & 0xff),
|
||||
(uint8_t) (msgsz & 0xff)};
|
||||
mg_gcm_initialize();
|
||||
if (mg_aes_gcm_decrypt(msg, msg, msgsz - 16, key, 16, nonce, sizeof(nonce),
|
||||
associated_data, sizeof(associated_data),
|
||||
msg + msgsz - 16, 16) != 0) {
|
||||
mg_error(c, "GCM tag verify failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
r = msgsz - 16 - 1;
|
||||
@@ -14143,7 +14227,7 @@ static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz,
|
||||
if (mg_match(mg_str(server_name), mg_str_n((char *) name.value, name.len),
|
||||
NULL))
|
||||
return 1; // and matches the host name
|
||||
} // TODO(): add IPv6 comparison, more items ?
|
||||
} // TODO(): add IPv6 comparison, more items ?
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -14171,7 +14255,7 @@ static int mg_tls_verify_cert_signature(const struct mg_tls_cert *cert,
|
||||
mg_uecc_secp256r1());
|
||||
} else if (issuer->pubkey.len == 96) {
|
||||
MG_VERBOSE(("ignore secp386 for now"));
|
||||
return 1;
|
||||
return 0;
|
||||
} else {
|
||||
MG_ERROR(("unsupported public key length: %d", issuer->pubkey.len));
|
||||
return 0;
|
||||
@@ -14288,6 +14372,14 @@ static int mg_tls_recv_cert(struct mg_connection *c, bool is_client) {
|
||||
mg_error(c, "failed to verify hostname");
|
||||
return -1;
|
||||
}
|
||||
if (ci->pubkey.len > sizeof(tls->pubkey)) {
|
||||
mg_error(c, "invalid certificate length");
|
||||
return -1;
|
||||
}
|
||||
if (ci->pubkey.len > sizeof(tls->pubkey)) {
|
||||
mg_error(c, "peer public key too large");
|
||||
return -1;
|
||||
}
|
||||
memmove(tls->pubkey, ci->pubkey.buf, ci->pubkey.len);
|
||||
tls->pubkeysz = ci->pubkey.len;
|
||||
} else {
|
||||
@@ -14635,7 +14727,7 @@ static int mg_rsa_parse_der_int(const uint8_t **p, const uint8_t *end,
|
||||
*p = value_end;
|
||||
|
||||
MG_VERBOSE(("DER INT: parsed %u bytes (skipped zero=%d)", len,
|
||||
(size_t)(value_end - value_start) != (size_t) len ? 1 : 0));
|
||||
(size_t) (value_end - value_start) != (size_t) len ? 1 : 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -15145,7 +15237,7 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
|
||||
if (!mg_tls_encrypt(c, (const uint8_t *) buf, len, MG_TLS_APP_DATA))
|
||||
return 0; // returning 0 means an OOM condition (iobuf couldn't resize),
|
||||
// yet this is so far recoverable, let the caller decide
|
||||
} // else, resend outstanding encrypted data in tls->send
|
||||
} // else, resend outstanding encrypted data in tls->send
|
||||
while (tls->send.len > 0 &&
|
||||
(n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) {
|
||||
mg_iobuf_del(&tls->send, 0, (size_t) n);
|
||||
@@ -15292,7 +15384,8 @@ static PORTABLE_8439_DECL void poly1305_finish(poly1305_context *ctx,
|
||||
defined(__AVR__)
|
||||
#define __HAVE_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
// DO NOT test for LITTLE_ENDIAN, as it is defined as 1234 when including sys/types.h in GCC
|
||||
// DO NOT test for LITTLE_ENDIAN, as it is defined as 1234 when including
|
||||
// sys/types.h in GCC
|
||||
|
||||
#ifndef TEST_SLOW_PATH
|
||||
#if defined(__HAVE_LITTLE_ENDIAN)
|
||||
@@ -15388,7 +15481,7 @@ static void core_block(const uint32_t *restrict start,
|
||||
TIMES16(__FIN)
|
||||
}
|
||||
|
||||
#define U8(x) ((uint8_t) ((x) &0xFF))
|
||||
#define U8(x) ((uint8_t) ((x) & 0xFF))
|
||||
|
||||
#ifdef FAST_PATH
|
||||
#define xor32_le(dst, src, pad) \
|
||||
@@ -15713,7 +15806,7 @@ static unsigned short U8TO16(const unsigned char *p) {
|
||||
/* store a 16 bit unsigned integer as two 8 bit unsigned integers in little
|
||||
* endian */
|
||||
static void U16TO8(unsigned char *p, unsigned short v) {
|
||||
p[0] = (v) &0xff;
|
||||
p[0] = (v) & 0xff;
|
||||
p[1] = (v >> 8) & 0xff;
|
||||
}
|
||||
|
||||
@@ -15724,7 +15817,7 @@ static void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
|
||||
|
||||
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
|
||||
t0 = U8TO16(&key[0]);
|
||||
st->r[0] = (t0) &0x1fff;
|
||||
st->r[0] = (t0) & 0x1fff;
|
||||
t1 = U8TO16(&key[2]);
|
||||
st->r[1] = ((t0 >> 13) | (t1 << 3)) & 0x1fff;
|
||||
t2 = U8TO16(&key[4]);
|
||||
@@ -15764,7 +15857,7 @@ static void poly1305_blocks(poly1305_state_internal_t *st,
|
||||
|
||||
/* h += m[i] */
|
||||
t0 = U8TO16(&m[0]);
|
||||
st->h[0] += (t0) &0x1fff;
|
||||
st->h[0] += (t0) & 0x1fff;
|
||||
t1 = U8TO16(&m[2]);
|
||||
st->h[1] += ((t0 >> 13) | (t1 << 3)) & 0x1fff;
|
||||
t2 = U8TO16(&m[4]);
|
||||
@@ -15926,7 +16019,7 @@ static unsigned long U8TO32(const unsigned char *p) {
|
||||
/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little
|
||||
* endian */
|
||||
static void U32TO8(unsigned char *p, unsigned long v) {
|
||||
p[0] = (unsigned char) ((v) &0xff);
|
||||
p[0] = (unsigned char) ((v) & 0xff);
|
||||
p[1] = (unsigned char) ((v >> 8) & 0xff);
|
||||
p[2] = (unsigned char) ((v >> 16) & 0xff);
|
||||
p[3] = (unsigned char) ((v >> 24) & 0xff);
|
||||
@@ -16190,8 +16283,8 @@ typedef unsigned uint128_t __attribute__((mode(TI)));
|
||||
#define MUL128(out, x, y) out = ((uint128_t) x * y)
|
||||
#define ADD(out, in) out += in
|
||||
#define ADDLO(out, in) out += in
|
||||
#define SHR(in, shift) (uint64_t)(in >> (shift))
|
||||
#define LO(in) (uint64_t)(in)
|
||||
#define SHR(in, shift) (uint64_t) (in >> (shift))
|
||||
#define LO(in) (uint64_t) (in)
|
||||
|
||||
#define POLY1305_NOINLINE __attribute__((noinline))
|
||||
#endif
|
||||
@@ -16220,7 +16313,7 @@ static uint64_t U8TO64(const unsigned char *p) {
|
||||
/* store a 64 bit unsigned integer as eight 8 bit unsigned integers in little
|
||||
* endian */
|
||||
static void U64TO8(unsigned char *p, uint64_t v) {
|
||||
p[0] = (unsigned char) ((v) &0xff);
|
||||
p[0] = (unsigned char) ((v) & 0xff);
|
||||
p[1] = (unsigned char) ((v >> 8) & 0xff);
|
||||
p[2] = (unsigned char) ((v >> 16) & 0xff);
|
||||
p[3] = (unsigned char) ((v >> 24) & 0xff);
|
||||
@@ -16238,7 +16331,7 @@ static void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
|
||||
t0 = U8TO64(&key[0]);
|
||||
t1 = U8TO64(&key[8]);
|
||||
|
||||
st->r[0] = (t0) &0xffc0fffffff;
|
||||
st->r[0] = (t0) & 0xffc0fffffff;
|
||||
st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
|
||||
st->r[2] = ((t1 >> 24)) & 0x00ffffffc0f;
|
||||
|
||||
@@ -16282,7 +16375,7 @@ static void poly1305_blocks(poly1305_state_internal_t *st,
|
||||
t0 = U8TO64(&m[0]);
|
||||
t1 = U8TO64(&m[8]);
|
||||
|
||||
h0 += ((t0) &0xfffffffffff);
|
||||
h0 += ((t0) & 0xfffffffffff);
|
||||
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
|
||||
h2 += (((t1 >> 24)) & 0x3ffffffffff) | hibit;
|
||||
|
||||
@@ -16389,7 +16482,7 @@ static POLY1305_NOINLINE void poly1305_finish(poly1305_context *ctx,
|
||||
t0 = st->pad[0];
|
||||
t1 = st->pad[1];
|
||||
|
||||
h0 += ((t0) &0xfffffffffff);
|
||||
h0 += ((t0) & 0xfffffffffff);
|
||||
c = (h0 >> 44);
|
||||
h0 &= 0xfffffffffff;
|
||||
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c;
|
||||
@@ -16466,7 +16559,7 @@ static PORTABLE_8439_DECL void pad_if_needed(poly1305_context *ctx,
|
||||
}
|
||||
}
|
||||
|
||||
#define __u8(v) ((uint8_t) ((v) &0xFF))
|
||||
#define __u8(v) ((uint8_t) ((v) & 0xFF))
|
||||
|
||||
// TODO: make this depending on the unaligned/native read size possible
|
||||
static PORTABLE_8439_DECL void write_64bit_int(poly1305_context *ctx,
|
||||
@@ -16539,14 +16632,26 @@ PORTABLE_8439_DECL size_t mg_chacha20_poly1305_encrypt(
|
||||
|
||||
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
|
||||
uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
|
||||
const uint8_t nonce[RFC_8439_NONCE_SIZE],
|
||||
const uint8_t *restrict cipher_text, size_t cipher_text_size) {
|
||||
const uint8_t nonce[RFC_8439_NONCE_SIZE], const uint8_t *restrict ad,
|
||||
size_t ad_size, const uint8_t *restrict cipher_text,
|
||||
size_t cipher_text_size) {
|
||||
// first we calculate the mac and see if it lines up, only then do we decrypt
|
||||
size_t actual_size = cipher_text_size - RFC_8439_TAG_SIZE;
|
||||
uint8_t computed_mac[RFC_8439_TAG_SIZE];
|
||||
int diff = 0;
|
||||
size_t i;
|
||||
if (MG_OVERLAPPING(plain_text, actual_size, cipher_text, cipher_text_size)) {
|
||||
return (size_t) -1;
|
||||
}
|
||||
|
||||
poly1305_calculate_mac(computed_mac, cipher_text, actual_size, key, nonce, ad,
|
||||
ad_size);
|
||||
|
||||
// compare tags
|
||||
for (i = 0; i < RFC_8439_TAG_SIZE; i++)
|
||||
diff |= computed_mac[i] ^ cipher_text[actual_size + i];
|
||||
if (diff != 0) return (size_t) -1;
|
||||
|
||||
chacha20_xor_stream(plain_text, cipher_text, actual_size, key, nonce, 1);
|
||||
return actual_size;
|
||||
}
|
||||
|
||||
+4
-1
@@ -1961,7 +1961,9 @@ int mg_aes_gcm_encrypt(unsigned char *output, const unsigned char *input,
|
||||
int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
|
||||
size_t input_length, const unsigned char *key,
|
||||
const size_t key_len, const unsigned char *iv,
|
||||
const size_t iv_len);
|
||||
const size_t iv_len, unsigned char *aead,
|
||||
size_t aead_len, const unsigned char *tag,
|
||||
const size_t tag_len);
|
||||
|
||||
#endif /* TLS_AES128_H */
|
||||
|
||||
@@ -2727,6 +2729,7 @@ PORTABLE_8439_DECL size_t mg_chacha20_poly1305_encrypt(
|
||||
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
|
||||
uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
|
||||
const uint8_t nonce[RFC_8439_NONCE_SIZE],
|
||||
const uint8_t *restrict ad, size_t ad_size,
|
||||
const uint8_t *restrict cipher_text, size_t cipher_text_size);
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
||||
@@ -287,6 +287,7 @@ void mg_resolve(struct mg_connection *c, const char *url) {
|
||||
}
|
||||
}
|
||||
|
||||
// Response header length is 10 bytes
|
||||
static const uint8_t mdns_answer[] = {
|
||||
0, 1, // 2 bytes - record type, A
|
||||
0, 1, // 2 bytes - address class, INET
|
||||
@@ -294,6 +295,7 @@ static const uint8_t mdns_answer[] = {
|
||||
0, 4 // 2 bytes - address length
|
||||
};
|
||||
|
||||
// A name length is name->len + '.local' + 2 = name->len + 8
|
||||
static uint8_t *build_name(struct mg_str *name, uint8_t *p) {
|
||||
*p++ = (uint8_t) name->len; // label 1
|
||||
memcpy(p, name->buf, name->len), p += name->len;
|
||||
@@ -305,6 +307,7 @@ static uint8_t *build_name(struct mg_str *name, uint8_t *p) {
|
||||
|
||||
void mg_getlocaddr(struct mg_connection *, struct mg_addr *, struct mg_addr *);
|
||||
|
||||
// An A record length is 10 + 4 = 14 bytes
|
||||
static uint8_t *build_a_record(struct mg_connection *c, uint8_t *p,
|
||||
struct mg_addr *addr) {
|
||||
memcpy(p, mdns_answer, sizeof(mdns_answer)), p += sizeof(mdns_answer);
|
||||
@@ -326,6 +329,7 @@ static uint8_t *build_a_record(struct mg_connection *c, uint8_t *p,
|
||||
return p;
|
||||
}
|
||||
|
||||
// A srv name length is r->srvcproto.len + '.local' + 2 = r->srvcproto.len + 8
|
||||
static uint8_t *build_srv_name(uint8_t *p, struct mg_dnssd_record *r) {
|
||||
*p++ = (uint8_t) r->srvcproto.len - 5; // label 1, up to '._tcp'
|
||||
memcpy(p, r->srvcproto.buf, r->srvcproto.len), p += r->srvcproto.len;
|
||||
@@ -346,6 +350,7 @@ static uint8_t *build_mysrv_name(struct mg_str *name, uint8_t *p,
|
||||
}
|
||||
#endif
|
||||
|
||||
// A PTR record length is 10 + name->len + 3 = name->len + 13
|
||||
static uint8_t *build_ptr_record(struct mg_str *name, uint8_t *p, uint16_t o) {
|
||||
uint16_t offset = mg_htons(o);
|
||||
memcpy(p, mdns_answer, sizeof(mdns_answer));
|
||||
@@ -360,6 +365,7 @@ static uint8_t *build_ptr_record(struct mg_str *name, uint8_t *p, uint16_t o) {
|
||||
return p;
|
||||
}
|
||||
|
||||
// An SRV record length is 10 + name->len + 9 = name->len + 19
|
||||
static uint8_t *build_srv_record(struct mg_str *name, uint8_t *p,
|
||||
struct mg_dnssd_record *r, uint16_t o) {
|
||||
uint16_t port = mg_htons(r->port);
|
||||
@@ -380,6 +386,7 @@ static uint8_t *build_srv_record(struct mg_str *name, uint8_t *p,
|
||||
return p;
|
||||
}
|
||||
|
||||
// A TXT record length is r->txt.len (txt contents) + 10
|
||||
static uint8_t *build_txt_record(uint8_t *p, struct mg_dnssd_record *r) {
|
||||
uint16_t len = mg_htons((uint16_t) r->txt.len);
|
||||
memcpy(p, mdns_answer, sizeof(mdns_answer));
|
||||
@@ -390,6 +397,8 @@ static uint8_t *build_txt_record(uint8_t *p, struct mg_dnssd_record *r) {
|
||||
return p;
|
||||
}
|
||||
|
||||
// Each additional record has a 2-byte field pointing to the name label
|
||||
|
||||
// RFC-6762 16: case-insensitivity --> RFC-1034, 1035
|
||||
|
||||
static void handle_mdns_query(struct mg_connection *c) {
|
||||
@@ -478,6 +487,10 @@ static void handle_mdns_query(struct mg_connection *c) {
|
||||
uint8_t *o = p, *aux;
|
||||
uint16_t offset;
|
||||
if (respname->buf == NULL || respname->len == 0) return;
|
||||
if ((sizeof(*h) + req.r->srvcproto.len + 8 + respname->len + 13 + 2 +
|
||||
respname->len + 19 + 2 + req.r->txt.len + 10 + 2 + 14) >
|
||||
sizeof(buf)) // srv name + PTR + 2 + SRV + 2 + TXT + 2 + A
|
||||
return;
|
||||
h->num_other_prs = mg_htons(3); // 3 additional records
|
||||
p = build_srv_name(p, req.r);
|
||||
aux = build_ptr_record(respname, p, (uint16_t) (o - buf));
|
||||
@@ -498,12 +511,18 @@ static void handle_mdns_query(struct mg_connection *c) {
|
||||
*p |= 0xC0, p += 2;
|
||||
p = build_a_record(c, p, req.addr);
|
||||
} else if (rr.atype == MG_DNS_RTYPE_TXT) {
|
||||
if ((sizeof(*h) + req.r->srvcproto.len + 8 + req.r->txt.len + 10) >
|
||||
sizeof(buf)) // srv name + TXT
|
||||
return;
|
||||
p = build_srv_name(p, req.r);
|
||||
p = build_txt_record(p, req.r);
|
||||
} else if (rr.atype == MG_DNS_RTYPE_SRV) { // serve SRV + A
|
||||
uint8_t *o, *aux;
|
||||
uint16_t offset;
|
||||
if (respname->buf == NULL || respname->len == 0) return;
|
||||
if ((sizeof(*h) + req.r->srvcproto.len + 8 + respname->len + 19 + 2 +
|
||||
14) > sizeof(buf)) // srv name + SRV + 2 + A
|
||||
return;
|
||||
h->num_other_prs = mg_htons(1); // 1 additional record
|
||||
p = build_srv_name(p, req.r);
|
||||
o = p - 7; // point to '.local' label (\x05local\x00)
|
||||
@@ -517,6 +536,8 @@ static void handle_mdns_query(struct mg_connection *c) {
|
||||
} else { // A requested
|
||||
// RFC-6762 6: 0 Auth, 0 Additional RRs
|
||||
if (respname->buf == NULL || respname->len == 0) return;
|
||||
if ((sizeof(*h) + respname->len + 8 + 14) > sizeof(buf)) // name + A
|
||||
return;
|
||||
p = build_name(respname, p);
|
||||
p = build_a_record(c, p, req.addr);
|
||||
}
|
||||
|
||||
+16
-1
@@ -237,6 +237,8 @@ static const char *skiptorn(const char *s, const char *end, struct mg_str *v) {
|
||||
static bool mg_http_parse_headers(const char *s, const char *end,
|
||||
struct mg_http_header *h, size_t max_hdrs) {
|
||||
size_t i, n;
|
||||
int cl_count = 0, te_count = 0, auth_count = 0;
|
||||
int conn_count = 0, cookie_count = 0;
|
||||
for (i = 0; i < max_hdrs; i++) {
|
||||
struct mg_str k = {NULL, 0}, v = {NULL, 0};
|
||||
if (s >= end) return false;
|
||||
@@ -252,6 +254,13 @@ static bool mg_http_parse_headers(const char *s, const char *end,
|
||||
while (v.len > 0 && (v.buf[v.len - 1] == ' ' || v.buf[v.len - 1] == '\t')) {
|
||||
v.len--; // Trim spaces
|
||||
}
|
||||
// detect duplicated headers -> discard
|
||||
if (((mg_strcasecmp(k, mg_str("Content-Length")) == 0) && (++cl_count > 1)) ||
|
||||
((mg_strcasecmp(k, mg_str("Transfer-Encoding")) == 0) && (++te_count > 1)) ||
|
||||
((mg_strcasecmp(k, mg_str("Authorization")) == 0) && (++auth_count > 1)) ||
|
||||
((mg_strcasecmp(k, mg_str("Cookie")) == 0) && (++cookie_count > 1)) ||
|
||||
((mg_strcasecmp(k, mg_str("Connection")) == 0) && (++conn_count > 1)))
|
||||
return false;
|
||||
// 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
|
||||
}
|
||||
@@ -286,6 +295,8 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
|
||||
// If we're given a version, check that it is HTTP/x.x
|
||||
version_prefix_valid =
|
||||
hm->proto.len > 5 && (mg_ncasecmp(hm->proto.buf, "HTTP/", 5) == 0);
|
||||
if (!is_response && !version_prefix_valid)
|
||||
return -1; // no version detected in request
|
||||
if (!is_response && hm->proto.len > 0 &&
|
||||
(!version_prefix_valid || hm->proto.len != 8 ||
|
||||
(hm->proto.buf[5] < '0' || hm->proto.buf[5] > '9') ||
|
||||
@@ -1035,7 +1046,11 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) {
|
||||
hm.message.len = c->recv.len - ofs; // and closes now, deliver MSG
|
||||
hm.body.len = hm.message.len - (size_t) (hm.body.buf - hm.message.buf);
|
||||
}
|
||||
if ((te = mg_http_get_header(&hm, "Transfer-Encoding")) != NULL) {
|
||||
bool is_http_1_0 =
|
||||
hm.proto.len > 8 && mg_ncasecmp(hm.proto.buf, "HTTP/1.0", 8) == 0;
|
||||
// HTTP/1.0 does not use "Transfer-Encoding: chunked"
|
||||
if (!is_http_1_0 &&
|
||||
(te = mg_http_get_header(&hm, "Transfer-Encoding")) != NULL) {
|
||||
if (mg_strcasecmp(*te, mg_str("chunked")) == 0) {
|
||||
is_chunked = true;
|
||||
} else {
|
||||
|
||||
+17
-4
@@ -60,15 +60,28 @@ static double mg_atod(const char *p, int len, int *numlen) {
|
||||
|
||||
// Exponential
|
||||
if (i < len && (p[i] == 'e' || p[i] == 'E')) {
|
||||
int j, exp = 0, minus = 0;
|
||||
int exp = 0, minus = 0;
|
||||
i++;
|
||||
if (i < len && p[i] == '-') minus = 1, i++;
|
||||
if (i < len && p[i] == '+') i++;
|
||||
while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308)
|
||||
exp = exp * 10 + (p[i++] - '0');
|
||||
if (minus) exp = -exp;
|
||||
for (j = 0; j < exp; j++) d *= 10.0;
|
||||
for (j = 0; j < -exp; j++) d /= 10.0;
|
||||
// use fast exponentiation
|
||||
// https://en.wikipedia.org/wiki/Exponentiation_by_squaring
|
||||
if (exp != 0) {
|
||||
double x = 10, y = 1;
|
||||
if (exp > 308) exp = 308;
|
||||
if (minus) x = 0.1;
|
||||
while (exp > 1) {
|
||||
if (exp & 1) {
|
||||
y *= x;
|
||||
--exp;
|
||||
}
|
||||
x *= x;
|
||||
exp >>= 1;
|
||||
}
|
||||
d *= x * y;
|
||||
}
|
||||
}
|
||||
|
||||
if (numlen != NULL) *numlen = i;
|
||||
|
||||
+15
-8
@@ -551,9 +551,13 @@ static struct mg_connection *getpeer(struct mg_mgr *mgr, struct pkt *pkt,
|
||||
!(c->loc.is_ip6 ^ (pkt->ip6 != NULL))) // IP or IPv6 to same dest
|
||||
break;
|
||||
if (!c->is_udp && pkt->tcp && c->loc.port == pkt->tcp->dport &&
|
||||
!(c->loc.is_ip6 ^ (pkt->ip6 != NULL)) &&
|
||||
lsn == (bool) c->is_listening &&
|
||||
(lsn || c->rem.port == pkt->tcp->sport))
|
||||
((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 && c->rem.addr.ip4 == pkt->ip->src)
|
||||
#if MG_ENABLE_IPV6
|
||||
|| (c->loc.is_ip6 && MG_IP6MATCH(c->rem.addr.ip6, pkt->ip6->src))
|
||||
#endif
|
||||
)))) // validate addr for established (not listening) conns
|
||||
break;
|
||||
}
|
||||
return c;
|
||||
@@ -1497,7 +1501,7 @@ static void backlog_poll(struct mg_mgr *mgr) {
|
||||
}
|
||||
|
||||
// process options (MSS)
|
||||
static void handle_opt(struct connstate *s, struct tcp *tcp, bool ip6) {
|
||||
static bool handle_opt(struct connstate *s, struct tcp *tcp, bool ip6) {
|
||||
uint8_t *opts = (uint8_t *) (tcp + 1);
|
||||
int len = 4 * ((int) (tcp->off >> 4) - ((int) sizeof(*tcp) / 4));
|
||||
s->dmss = ip6 ? 1220 : 536; // assume default, RFC-9293 3.7.1
|
||||
@@ -1505,6 +1509,7 @@ static void handle_opt(struct connstate *s, struct tcp *tcp, bool ip6) {
|
||||
uint8_t kind = opts[0], optlen = 1;
|
||||
if (kind != 1) { // No-Operation
|
||||
if (kind == 0) break; // End of Option List
|
||||
if (len < 2 || opts[1] == 0) return false; // Malformed options
|
||||
optlen = opts[1];
|
||||
if (kind == 2 && optlen == 4) // set received MSS
|
||||
s->dmss = (uint16_t) (((uint16_t) opts[2] << 8) + opts[3]);
|
||||
@@ -1513,6 +1518,7 @@ static void handle_opt(struct connstate *s, struct tcp *tcp, bool ip6) {
|
||||
opts += optlen;
|
||||
len -= optlen;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
|
||||
@@ -1527,7 +1533,7 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
|
||||
// - check clients (Group 1) and established connections (Group 3)
|
||||
if (c != NULL && c->is_connecting && pkt->tcp->flags == (TH_SYN | TH_ACK)) {
|
||||
// client got a server connection accept
|
||||
handle_opt(s, pkt->tcp, pkt->ip6 != NULL); // process options (MSS)
|
||||
if (!handle_opt(s, pkt->tcp, pkt->ip6 != NULL)) return; // process options (MSS)
|
||||
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1;
|
||||
tx_tcp_ctrlresp(ifp, pkt, TH_ACK, pkt->tcp->ack);
|
||||
c->is_connecting = 0; // Client connected
|
||||
@@ -1538,8 +1544,9 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
|
||||
} else if (c != NULL && c->is_connecting && pkt->tcp->flags != TH_ACK) {
|
||||
mg_error(c, "connection refused");
|
||||
} else if (c != NULL && pkt->tcp->flags & TH_RST) {
|
||||
// TODO(): validate RST is within window (and optional with proper ACK)
|
||||
mg_error(c, "peer RST"); // RFC-1122 4.2.2.13
|
||||
uint32_t seqno = mg_ntohl(pkt->tcp->seq);
|
||||
if (seqno >= s->ack && seqno < (s->ack + MG_TCPIP_WIN)) // RFC-9293 3.5.3
|
||||
mg_error(c, "peer RST"); // RFC-1122 4.2.2.13
|
||||
} else if (c != NULL) {
|
||||
// process segment
|
||||
s->tmiss = 0; // Reset missed keep-alive counter
|
||||
@@ -1561,7 +1568,7 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
|
||||
int key;
|
||||
uint32_t isn;
|
||||
if (pkt->tcp->sport != 0) {
|
||||
handle_opt(&cs, pkt->tcp, pkt->ip6 != NULL); // process options (MSS)
|
||||
if (!handle_opt(&cs, pkt->tcp, pkt->ip6 != NULL)) return; // process options (MSS)
|
||||
key = backlog_insert(c, pkt->tcp->sport,
|
||||
cs.dmss); // backlog options (MSS)
|
||||
if (key < 0) return; // no room in backlog, discard SYN, client retries
|
||||
|
||||
@@ -87,7 +87,9 @@ bool mg_match(struct mg_str s, struct mg_str p, struct mg_str *caps) {
|
||||
} else if (i < p.len && (p.buf[i] == '*' || p.buf[i] == '#')) {
|
||||
if (caps && !caps->buf) caps->len = 0, caps->buf = &s.buf[j]; // Init cap
|
||||
ni = i++, nj = j + 1;
|
||||
} else if (nj > 0 && nj <= s.len && ((ni < p.len && p.buf[ni] == '#') || s.buf[j] != '/')) {
|
||||
} else if (nj > 0 && nj <= s.len &&
|
||||
((ni < p.len && p.buf[ni] == '#') ||
|
||||
(j < s.len && s.buf[j] != '/'))) {
|
||||
i = ni, j = nj;
|
||||
if (caps && caps->buf == NULL && caps->len == 0) {
|
||||
caps--, caps->len = 0; // Restart previous cap
|
||||
@@ -168,8 +170,7 @@ bool mg_str_to_num(struct mg_str str, int base, void *val, size_t val_len) {
|
||||
i++, ndigits++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
default: return false;
|
||||
}
|
||||
if (ndigits == 0) return false;
|
||||
if (i != str.len) return false;
|
||||
|
||||
+93
-81
@@ -40,45 +40,47 @@ static void aes_init_keygen_tables(void);
|
||||
/******************************************************************************
|
||||
* AES_SETKEY : called to expand the key for encryption or decryption
|
||||
******************************************************************************/
|
||||
static int aes_setkey(aes_context *ctx, // pointer to context
|
||||
int mode, // 1 or 0 for Encrypt/Decrypt
|
||||
const unsigned char *key, // AES input key
|
||||
unsigned int keysize); // size in bytes (must be 16, 24, 32 for
|
||||
// 128, 192 or 256-bit keys respectively)
|
||||
// returns 0 for success
|
||||
static int aes_setkey(
|
||||
aes_context *ctx, // pointer to context
|
||||
int mode, // 1 or 0 for Encrypt/Decrypt
|
||||
const unsigned char *key, // AES input key
|
||||
unsigned int keysize); // size in bytes (must be 16, 24, 32 for
|
||||
// 128, 192 or 256-bit keys respectively)
|
||||
// returns 0 for success
|
||||
|
||||
/******************************************************************************
|
||||
* AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data
|
||||
******************************************************************************/
|
||||
static int aes_cipher(aes_context *ctx, // pointer to context
|
||||
const unsigned char input[16], // 128-bit block to en/decipher
|
||||
unsigned char output[16]); // 128-bit output result block
|
||||
// returns 0 for success
|
||||
static int aes_cipher(
|
||||
aes_context *ctx, // pointer to context
|
||||
const unsigned char input[16], // 128-bit block to en/decipher
|
||||
unsigned char output[16]); // 128-bit output result block
|
||||
// returns 0 for success
|
||||
|
||||
/******************************************************************************
|
||||
* GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
int mode; // cipher direction: encrypt/decrypt
|
||||
uint64_t len; // cipher data length processed so far
|
||||
uint64_t add_len; // total add data length
|
||||
uint64_t HL[16]; // precalculated lo-half HTable
|
||||
uint64_t HH[16]; // precalculated hi-half HTable
|
||||
int mode; // cipher direction: encrypt/decrypt
|
||||
uint64_t len; // cipher data length processed so far
|
||||
uint64_t add_len; // total add data length
|
||||
uint64_t HL[16]; // precalculated lo-half HTable
|
||||
uint64_t HH[16]; // precalculated hi-half HTable
|
||||
unsigned char base_ectr[16]; // first counter-mode cipher output for tag
|
||||
unsigned char y[16]; // the current cipher-input IV|Counter value
|
||||
unsigned char buf[16]; // buf working value
|
||||
aes_context aes_ctx; // cipher context used
|
||||
aes_context aes_ctx; // cipher context used
|
||||
} gcm_context;
|
||||
|
||||
/******************************************************************************
|
||||
* GCM_SETKEY : sets the GCM (and AES) keying material for use
|
||||
******************************************************************************/
|
||||
static int gcm_setkey(
|
||||
gcm_context *ctx, // caller-provided context ptr
|
||||
gcm_context *ctx, // caller-provided context ptr
|
||||
const unsigned char *key, // pointer to cipher key
|
||||
const unsigned int keysize // size in bytes (must be 16, 24, 32 for
|
||||
// 128, 192 or 256-bit keys respectively)
|
||||
); // returns 0 for success
|
||||
// 128, 192 or 256-bit keys respectively)
|
||||
); // returns 0 for success
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
@@ -98,17 +100,17 @@ static int gcm_setkey(
|
||||
*
|
||||
******************************************************************************/
|
||||
static int gcm_crypt_and_tag(
|
||||
gcm_context *ctx, // gcm context with key already setup
|
||||
int mode, // cipher direction: MG_ENCRYPT (1) or MG_DECRYPT (0)
|
||||
gcm_context *ctx, // gcm context with key already setup
|
||||
int mode, // cipher direction: MG_ENCRYPT (1) or MG_DECRYPT (0)
|
||||
const unsigned char *iv, // pointer to the 12-byte initialization vector
|
||||
size_t iv_len, // byte length if the IV. should always be 12
|
||||
size_t iv_len, // byte length if the IV. should always be 12
|
||||
const unsigned char *add, // pointer to the non-ciphered additional data
|
||||
size_t add_len, // byte length of the additional AEAD data
|
||||
size_t add_len, // byte length of the additional AEAD data
|
||||
const unsigned char *input, // pointer to the cipher data source
|
||||
unsigned char *output, // pointer to the cipher data destination
|
||||
size_t length, // byte length of the cipher data
|
||||
size_t length, // byte length of the cipher data
|
||||
unsigned char *tag, // pointer to the tag to be generated
|
||||
size_t tag_len); // byte length of the tag to be generated
|
||||
size_t tag_len); // byte length of the tag to be generated
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
@@ -119,12 +121,12 @@ static int gcm_crypt_and_tag(
|
||||
*
|
||||
******************************************************************************/
|
||||
static int gcm_start(
|
||||
gcm_context *ctx, // pointer to user-provided GCM context
|
||||
int mode, // MG_ENCRYPT (1) or MG_DECRYPT (0)
|
||||
gcm_context *ctx, // pointer to user-provided GCM context
|
||||
int mode, // MG_ENCRYPT (1) or MG_DECRYPT (0)
|
||||
const unsigned char *iv, // pointer to initialization vector
|
||||
size_t iv_len, // IV length in bytes (should == 12)
|
||||
size_t iv_len, // IV length in bytes (should == 12)
|
||||
const unsigned char *add, // pointer to additional AEAD data (NULL if none)
|
||||
size_t add_len); // length of additional AEAD data (bytes)
|
||||
size_t add_len); // length of additional AEAD data (bytes)
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
@@ -140,7 +142,7 @@ static int gcm_start(
|
||||
static int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
size_t length, // length, in bytes, of data to process
|
||||
const unsigned char *input, // pointer to source data
|
||||
unsigned char *output); // pointer to destination data
|
||||
unsigned char *output); // pointer to destination data
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
@@ -151,9 +153,9 @@ static int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
*
|
||||
******************************************************************************/
|
||||
static int gcm_finish(
|
||||
gcm_context *ctx, // pointer to user-provided GCM context
|
||||
unsigned char *tag, // ptr to tag buffer - NULL if tag_len = 0
|
||||
size_t tag_len); // length, in bytes, of the tag-receiving buf
|
||||
gcm_context *ctx, // pointer to user-provided GCM context
|
||||
unsigned char *tag, // ptr to tag buffer - NULL if tag_len = 0
|
||||
size_t tag_len); // length, in bytes, of the tag-receiving buf
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
@@ -204,15 +206,15 @@ static int aes_tables_inited = 0; // run-once flag for performing key
|
||||
* decryption is typically disabled by setting AES_DECRYPTION to 0 in aes.h.
|
||||
*/
|
||||
// We always need our forward tables
|
||||
static unsigned char FSb[256]; // Forward substitution box (FSb)
|
||||
static uint32_t FT0[256]; // Forward key schedule assembly tables
|
||||
static unsigned char FSb[256]; // Forward substitution box (FSb)
|
||||
static uint32_t FT0[256]; // Forward key schedule assembly tables
|
||||
static uint32_t FT1[256];
|
||||
static uint32_t FT2[256];
|
||||
static uint32_t FT3[256];
|
||||
|
||||
#if AES_DECRYPTION // We ONLY need reverse for decryption
|
||||
static unsigned char RSb[256]; // Reverse substitution box (RSb)
|
||||
static uint32_t RT0[256]; // Reverse key schedule assembly tables
|
||||
#if AES_DECRYPTION // We ONLY need reverse for decryption
|
||||
static unsigned char RSb[256]; // Reverse substitution box (RSb)
|
||||
static uint32_t RT0[256]; // Reverse key schedule assembly tables
|
||||
static uint32_t RT1[256];
|
||||
static uint32_t RT2[256];
|
||||
static uint32_t RT3[256];
|
||||
@@ -230,8 +232,8 @@ static uint32_t RCON[10]; // AES round constants
|
||||
((uint32_t) (b)[(i) + 2] << 16) | ((uint32_t) (b)[(i) + 3] << 24); \
|
||||
}
|
||||
|
||||
#define PUT_UINT32_LE(n, b, i) \
|
||||
{ \
|
||||
#define PUT_UINT32_LE(n, b, i) \
|
||||
{ \
|
||||
(b)[(i)] = (unsigned char) ((n)); \
|
||||
(b)[(i) + 1] = (unsigned char) ((n) >> 8); \
|
||||
(b)[(i) + 2] = (unsigned char) ((n) >> 16); \
|
||||
@@ -376,7 +378,7 @@ void aes_init_keygen_tables(void) {
|
||||
******************************************************************************/
|
||||
static int aes_set_encryption_key(aes_context *ctx, const unsigned char *key,
|
||||
unsigned int keysize) {
|
||||
unsigned int i; // general purpose iteration local
|
||||
unsigned int i; // general purpose iteration local
|
||||
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
|
||||
|
||||
for (i = 0; i < (keysize >> 2); i++) {
|
||||
@@ -711,8 +713,8 @@ static const uint64_t last4[16] = {
|
||||
((uint32_t) (b)[(i) + 2] << 8) | ((uint32_t) (b)[(i) + 3]); \
|
||||
}
|
||||
|
||||
#define PUT_UINT32_BE(n, b, i) \
|
||||
{ \
|
||||
#define PUT_UINT32_BE(n, b, i) \
|
||||
{ \
|
||||
(b)[(i)] = (unsigned char) ((n) >> 24); \
|
||||
(b)[(i) + 1] = (unsigned char) ((n) >> 16); \
|
||||
(b)[(i) + 2] = (unsigned char) ((n) >> 8); \
|
||||
@@ -745,9 +747,10 @@ int mg_gcm_initialize(void) {
|
||||
* 'x' and 'output' are seen as elements of GCM's GF(2^128) Galois field.
|
||||
*
|
||||
******************************************************************************/
|
||||
static void gcm_mult(gcm_context *ctx, // pointer to established context
|
||||
const unsigned char x[16], // pointer to 128-bit input vector
|
||||
unsigned char output[16]) // pointer to 128-bit output vector
|
||||
static void gcm_mult(
|
||||
gcm_context *ctx, // pointer to established context
|
||||
const unsigned char x[16], // pointer to 128-bit input vector
|
||||
unsigned char output[16]) // pointer to 128-bit output vector
|
||||
{
|
||||
int i;
|
||||
unsigned char lo, hi, rem;
|
||||
@@ -792,10 +795,10 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context
|
||||
*
|
||||
******************************************************************************/
|
||||
static int gcm_setkey(
|
||||
gcm_context *ctx, // pointer to caller-provided gcm context
|
||||
gcm_context *ctx, // pointer to caller-provided gcm context
|
||||
const unsigned char *key, // pointer to the AES encryption key
|
||||
const unsigned int keysize) // size in bytes (must be 16, 24, 32 for
|
||||
// 128, 192 or 256-bit keys respectively)
|
||||
// 128, 192 or 256-bit keys respectively)
|
||||
{
|
||||
int ret, i, j;
|
||||
uint64_t hi, lo;
|
||||
@@ -864,18 +867,19 @@ static int gcm_setkey(
|
||||
* mode, and preprocesses the initialization vector and additional AEAD data.
|
||||
*
|
||||
******************************************************************************/
|
||||
int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
int mode, // GCM_ENCRYPT or GCM_DECRYPT
|
||||
const unsigned char *iv, // pointer to initialization vector
|
||||
size_t iv_len, // IV length in bytes (should == 12)
|
||||
const unsigned char *add, // ptr to additional AEAD data (NULL if none)
|
||||
size_t add_len) // length of additional AEAD data (bytes)
|
||||
int gcm_start(
|
||||
gcm_context *ctx, // pointer to user-provided GCM context
|
||||
int mode, // GCM_ENCRYPT or GCM_DECRYPT
|
||||
const unsigned char *iv, // pointer to initialization vector
|
||||
size_t iv_len, // IV length in bytes (should == 12)
|
||||
const unsigned char *add, // ptr to additional AEAD data (NULL if none)
|
||||
size_t add_len) // length of additional AEAD data (bytes)
|
||||
{
|
||||
int ret; // our error return if the AES encrypt fails
|
||||
int ret; // our error return if the AES encrypt fails
|
||||
unsigned char work_buf[16]; // XOR source built from provided IV if len != 16
|
||||
const unsigned char *p; // general purpose array pointer
|
||||
size_t use_len; // byte count to process, up to 16 bytes
|
||||
size_t i; // local loop iterator
|
||||
size_t use_len; // byte count to process, up to 16 bytes
|
||||
size_t i; // local loop iterator
|
||||
|
||||
// since the context might be reused under the same key
|
||||
// we zero the working buffers for this next new process
|
||||
@@ -932,15 +936,15 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
* have a partial block length of < 128 bits.)
|
||||
*
|
||||
******************************************************************************/
|
||||
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
size_t length, // length, in bytes, of data to process
|
||||
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
size_t length, // length, in bytes, of data to process
|
||||
const unsigned char *input, // pointer to source data
|
||||
unsigned char *output) // pointer to destination data
|
||||
{
|
||||
int ret; // our error return if the AES encrypt fails
|
||||
int ret; // our error return if the AES encrypt fails
|
||||
unsigned char ectr[16]; // counter-mode cipher output for XORing
|
||||
size_t use_len; // byte count to process, up to 16 bytes
|
||||
size_t i; // local loop iterator
|
||||
size_t use_len; // byte count to process, up to 16 bytes
|
||||
size_t i; // local loop iterator
|
||||
|
||||
ctx->len += length; // bump the GCM context's running length count
|
||||
|
||||
@@ -996,9 +1000,9 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
* It performs the final GHASH to produce the resulting authentication TAG.
|
||||
*
|
||||
******************************************************************************/
|
||||
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
unsigned char *tag, // pointer to buffer which receives the tag
|
||||
size_t tag_len) // length, in bytes, of the tag-receiving buf
|
||||
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
unsigned char *tag, // pointer to buffer which receives the tag
|
||||
size_t tag_len) // length, in bytes, of the tag-receiving buf
|
||||
{
|
||||
unsigned char work_buf[16];
|
||||
uint64_t orig_len = ctx->len * 8;
|
||||
@@ -1040,22 +1044,22 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
*
|
||||
******************************************************************************/
|
||||
int gcm_crypt_and_tag(
|
||||
gcm_context *ctx, // gcm context with key already setup
|
||||
int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT
|
||||
gcm_context *ctx, // gcm context with key already setup
|
||||
int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT
|
||||
const unsigned char *iv, // pointer to the 12-byte initialization vector
|
||||
size_t iv_len, // byte length if the IV. should always be 12
|
||||
size_t iv_len, // byte length if the IV. should always be 12
|
||||
const unsigned char *add, // pointer to the non-ciphered additional data
|
||||
size_t add_len, // byte length of the additional AEAD data
|
||||
size_t add_len, // byte length of the additional AEAD data
|
||||
const unsigned char *input, // pointer to the cipher data source
|
||||
unsigned char *output, // pointer to the cipher data destination
|
||||
size_t length, // byte length of the cipher data
|
||||
size_t length, // byte length of the cipher data
|
||||
unsigned char *tag, // pointer to the tag to be generated
|
||||
size_t tag_len) // byte length of the tag to be generated
|
||||
{ /*
|
||||
assuming that the caller has already invoked gcm_setkey to
|
||||
prepare the gcm context with the keying material, we simply
|
||||
invoke each of the three GCM sub-functions in turn...
|
||||
*/
|
||||
size_t tag_len) // byte length of the tag to be generated
|
||||
{ /*
|
||||
assuming that the caller has already invoked gcm_setkey to
|
||||
prepare the gcm context with the keying material, we simply
|
||||
invoke each of the three GCM sub-functions in turn...
|
||||
*/
|
||||
gcm_start(ctx, mode, iv, iv_len, add, add_len);
|
||||
gcm_update(ctx, length, input, output);
|
||||
gcm_finish(ctx, tag, tag_len);
|
||||
@@ -1105,20 +1109,28 @@ int mg_aes_gcm_encrypt(unsigned char *output, //
|
||||
int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
|
||||
size_t input_length, const unsigned char *key,
|
||||
const size_t key_len, const unsigned char *iv,
|
||||
const size_t iv_len) {
|
||||
const size_t iv_len, unsigned char *aead,
|
||||
size_t aead_len, const unsigned char *tag,
|
||||
const size_t tag_len) {
|
||||
int ret = 0; // our return value
|
||||
gcm_context ctx; // includes the AES context structure
|
||||
unsigned char computed_tag[16];
|
||||
size_t i;
|
||||
int diff = 0;
|
||||
|
||||
size_t tag_len = 0;
|
||||
unsigned char *tag_buf = NULL;
|
||||
if (tag_len > sizeof(computed_tag)) return -1;
|
||||
|
||||
gcm_setkey(&ctx, key, (unsigned int) key_len);
|
||||
|
||||
ret = gcm_crypt_and_tag(&ctx, MG_DECRYPT, iv, iv_len, NULL, 0, input, output,
|
||||
input_length, tag_buf, tag_len);
|
||||
ret = gcm_crypt_and_tag(&ctx, MG_DECRYPT, iv, iv_len, aead, aead_len, input,
|
||||
output, input_length, computed_tag, tag_len);
|
||||
|
||||
gcm_zero_ctx(&ctx);
|
||||
|
||||
// compare tags
|
||||
for (i = 0; i < tag_len; i++) diff |= computed_tag[i] ^ tag[i];
|
||||
if (diff != 0) ret = -1;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
+3
-1
@@ -59,7 +59,9 @@ int mg_aes_gcm_encrypt(unsigned char *output, const unsigned char *input,
|
||||
int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
|
||||
size_t input_length, const unsigned char *key,
|
||||
const size_t key_len, const unsigned char *iv,
|
||||
const size_t iv_len);
|
||||
const size_t iv_len, unsigned char *aead,
|
||||
size_t aead_len, const unsigned char *tag,
|
||||
const size_t tag_len);
|
||||
|
||||
#endif /* TLS_AES128_H */
|
||||
|
||||
|
||||
+30
-7
@@ -555,14 +555,19 @@ static int mg_tls_recv_record(struct mg_connection *c) {
|
||||
nonce[11] ^= (uint8_t) ((seq) & 255U);
|
||||
#if MG_ENABLE_CHACHA20
|
||||
{
|
||||
uint8_t associated_data[5] = {MG_TLS_APP_DATA, 0x03, 0x03,
|
||||
(uint8_t) ((msgsz >> 8) & 0xff),
|
||||
(uint8_t) (msgsz & 0xff)};
|
||||
uint8_t *dec = (uint8_t *) mg_calloc(1, msgsz);
|
||||
size_t n;
|
||||
if (dec == NULL) {
|
||||
mg_error(c, "TLS OOM");
|
||||
return -1;
|
||||
}
|
||||
n = mg_chacha20_poly1305_decrypt(dec, key, nonce, msg, msgsz);
|
||||
n = mg_chacha20_poly1305_decrypt(dec, key, nonce, associated_data,
|
||||
sizeof(associated_data), msg, msgsz);
|
||||
if (n == (size_t) -1) {
|
||||
mg_free(dec);
|
||||
mg_error(c, "decryption error");
|
||||
return -1;
|
||||
}
|
||||
@@ -570,8 +575,18 @@ static int mg_tls_recv_record(struct mg_connection *c) {
|
||||
mg_free(dec);
|
||||
}
|
||||
#else
|
||||
mg_gcm_initialize();
|
||||
mg_aes_gcm_decrypt(msg, msg, msgsz - 16, key, 16, nonce, sizeof(nonce));
|
||||
{
|
||||
uint8_t associated_data[5] = {MG_TLS_APP_DATA, 0x03, 0x03,
|
||||
(uint8_t) ((msgsz >> 8) & 0xff),
|
||||
(uint8_t) (msgsz & 0xff)};
|
||||
mg_gcm_initialize();
|
||||
if (mg_aes_gcm_decrypt(msg, msg, msgsz - 16, key, 16, nonce, sizeof(nonce),
|
||||
associated_data, sizeof(associated_data),
|
||||
msg + msgsz - 16, 16) != 0) {
|
||||
mg_error(c, "GCM tag verify failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
r = msgsz - 16 - 1;
|
||||
@@ -1497,7 +1512,7 @@ static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz,
|
||||
if (mg_match(mg_str(server_name), mg_str_n((char *) name.value, name.len),
|
||||
NULL))
|
||||
return 1; // and matches the host name
|
||||
} // TODO(): add IPv6 comparison, more items ?
|
||||
} // TODO(): add IPv6 comparison, more items ?
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -1525,7 +1540,7 @@ static int mg_tls_verify_cert_signature(const struct mg_tls_cert *cert,
|
||||
mg_uecc_secp256r1());
|
||||
} else if (issuer->pubkey.len == 96) {
|
||||
MG_VERBOSE(("ignore secp386 for now"));
|
||||
return 1;
|
||||
return 0;
|
||||
} else {
|
||||
MG_ERROR(("unsupported public key length: %d", issuer->pubkey.len));
|
||||
return 0;
|
||||
@@ -1642,6 +1657,14 @@ static int mg_tls_recv_cert(struct mg_connection *c, bool is_client) {
|
||||
mg_error(c, "failed to verify hostname");
|
||||
return -1;
|
||||
}
|
||||
if (ci->pubkey.len > sizeof(tls->pubkey)) {
|
||||
mg_error(c, "invalid certificate length");
|
||||
return -1;
|
||||
}
|
||||
if (ci->pubkey.len > sizeof(tls->pubkey)) {
|
||||
mg_error(c, "peer public key too large");
|
||||
return -1;
|
||||
}
|
||||
memmove(tls->pubkey, ci->pubkey.buf, ci->pubkey.len);
|
||||
tls->pubkeysz = ci->pubkey.len;
|
||||
} else {
|
||||
@@ -1989,7 +2012,7 @@ static int mg_rsa_parse_der_int(const uint8_t **p, const uint8_t *end,
|
||||
*p = value_end;
|
||||
|
||||
MG_VERBOSE(("DER INT: parsed %u bytes (skipped zero=%d)", len,
|
||||
(size_t)(value_end - value_start) != (size_t) len ? 1 : 0));
|
||||
(size_t) (value_end - value_start) != (size_t) len ? 1 : 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2499,7 +2522,7 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
|
||||
if (!mg_tls_encrypt(c, (const uint8_t *) buf, len, MG_TLS_APP_DATA))
|
||||
return 0; // returning 0 means an OOM condition (iobuf couldn't resize),
|
||||
// yet this is so far recoverable, let the caller decide
|
||||
} // else, resend outstanding encrypted data in tls->send
|
||||
} // else, resend outstanding encrypted data in tls->send
|
||||
while (tls->send.len > 0 &&
|
||||
(n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) {
|
||||
mg_iobuf_del(&tls->send, 0, (size_t) n);
|
||||
|
||||
+28
-15
@@ -82,7 +82,8 @@ static PORTABLE_8439_DECL void poly1305_finish(poly1305_context *ctx,
|
||||
defined(__AVR__)
|
||||
#define __HAVE_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
// DO NOT test for LITTLE_ENDIAN, as it is defined as 1234 when including sys/types.h in GCC
|
||||
// DO NOT test for LITTLE_ENDIAN, as it is defined as 1234 when including
|
||||
// sys/types.h in GCC
|
||||
|
||||
#ifndef TEST_SLOW_PATH
|
||||
#if defined(__HAVE_LITTLE_ENDIAN)
|
||||
@@ -178,7 +179,7 @@ static void core_block(const uint32_t *restrict start,
|
||||
TIMES16(__FIN)
|
||||
}
|
||||
|
||||
#define U8(x) ((uint8_t) ((x) &0xFF))
|
||||
#define U8(x) ((uint8_t) ((x) & 0xFF))
|
||||
|
||||
#ifdef FAST_PATH
|
||||
#define xor32_le(dst, src, pad) \
|
||||
@@ -503,7 +504,7 @@ static unsigned short U8TO16(const unsigned char *p) {
|
||||
/* store a 16 bit unsigned integer as two 8 bit unsigned integers in little
|
||||
* endian */
|
||||
static void U16TO8(unsigned char *p, unsigned short v) {
|
||||
p[0] = (v) &0xff;
|
||||
p[0] = (v) & 0xff;
|
||||
p[1] = (v >> 8) & 0xff;
|
||||
}
|
||||
|
||||
@@ -514,7 +515,7 @@ static void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
|
||||
|
||||
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
|
||||
t0 = U8TO16(&key[0]);
|
||||
st->r[0] = (t0) &0x1fff;
|
||||
st->r[0] = (t0) & 0x1fff;
|
||||
t1 = U8TO16(&key[2]);
|
||||
st->r[1] = ((t0 >> 13) | (t1 << 3)) & 0x1fff;
|
||||
t2 = U8TO16(&key[4]);
|
||||
@@ -554,7 +555,7 @@ static void poly1305_blocks(poly1305_state_internal_t *st,
|
||||
|
||||
/* h += m[i] */
|
||||
t0 = U8TO16(&m[0]);
|
||||
st->h[0] += (t0) &0x1fff;
|
||||
st->h[0] += (t0) & 0x1fff;
|
||||
t1 = U8TO16(&m[2]);
|
||||
st->h[1] += ((t0 >> 13) | (t1 << 3)) & 0x1fff;
|
||||
t2 = U8TO16(&m[4]);
|
||||
@@ -716,7 +717,7 @@ static unsigned long U8TO32(const unsigned char *p) {
|
||||
/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little
|
||||
* endian */
|
||||
static void U32TO8(unsigned char *p, unsigned long v) {
|
||||
p[0] = (unsigned char) ((v) &0xff);
|
||||
p[0] = (unsigned char) ((v) & 0xff);
|
||||
p[1] = (unsigned char) ((v >> 8) & 0xff);
|
||||
p[2] = (unsigned char) ((v >> 16) & 0xff);
|
||||
p[3] = (unsigned char) ((v >> 24) & 0xff);
|
||||
@@ -980,8 +981,8 @@ typedef unsigned uint128_t __attribute__((mode(TI)));
|
||||
#define MUL128(out, x, y) out = ((uint128_t) x * y)
|
||||
#define ADD(out, in) out += in
|
||||
#define ADDLO(out, in) out += in
|
||||
#define SHR(in, shift) (uint64_t)(in >> (shift))
|
||||
#define LO(in) (uint64_t)(in)
|
||||
#define SHR(in, shift) (uint64_t) (in >> (shift))
|
||||
#define LO(in) (uint64_t) (in)
|
||||
|
||||
#define POLY1305_NOINLINE __attribute__((noinline))
|
||||
#endif
|
||||
@@ -1010,7 +1011,7 @@ static uint64_t U8TO64(const unsigned char *p) {
|
||||
/* store a 64 bit unsigned integer as eight 8 bit unsigned integers in little
|
||||
* endian */
|
||||
static void U64TO8(unsigned char *p, uint64_t v) {
|
||||
p[0] = (unsigned char) ((v) &0xff);
|
||||
p[0] = (unsigned char) ((v) & 0xff);
|
||||
p[1] = (unsigned char) ((v >> 8) & 0xff);
|
||||
p[2] = (unsigned char) ((v >> 16) & 0xff);
|
||||
p[3] = (unsigned char) ((v >> 24) & 0xff);
|
||||
@@ -1028,7 +1029,7 @@ static void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
|
||||
t0 = U8TO64(&key[0]);
|
||||
t1 = U8TO64(&key[8]);
|
||||
|
||||
st->r[0] = (t0) &0xffc0fffffff;
|
||||
st->r[0] = (t0) & 0xffc0fffffff;
|
||||
st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
|
||||
st->r[2] = ((t1 >> 24)) & 0x00ffffffc0f;
|
||||
|
||||
@@ -1072,7 +1073,7 @@ static void poly1305_blocks(poly1305_state_internal_t *st,
|
||||
t0 = U8TO64(&m[0]);
|
||||
t1 = U8TO64(&m[8]);
|
||||
|
||||
h0 += ((t0) &0xfffffffffff);
|
||||
h0 += ((t0) & 0xfffffffffff);
|
||||
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
|
||||
h2 += (((t1 >> 24)) & 0x3ffffffffff) | hibit;
|
||||
|
||||
@@ -1179,7 +1180,7 @@ static POLY1305_NOINLINE void poly1305_finish(poly1305_context *ctx,
|
||||
t0 = st->pad[0];
|
||||
t1 = st->pad[1];
|
||||
|
||||
h0 += ((t0) &0xfffffffffff);
|
||||
h0 += ((t0) & 0xfffffffffff);
|
||||
c = (h0 >> 44);
|
||||
h0 &= 0xfffffffffff;
|
||||
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c;
|
||||
@@ -1256,7 +1257,7 @@ static PORTABLE_8439_DECL void pad_if_needed(poly1305_context *ctx,
|
||||
}
|
||||
}
|
||||
|
||||
#define __u8(v) ((uint8_t) ((v) &0xFF))
|
||||
#define __u8(v) ((uint8_t) ((v) & 0xFF))
|
||||
|
||||
// TODO: make this depending on the unaligned/native read size possible
|
||||
static PORTABLE_8439_DECL void write_64bit_int(poly1305_context *ctx,
|
||||
@@ -1329,14 +1330,26 @@ PORTABLE_8439_DECL size_t mg_chacha20_poly1305_encrypt(
|
||||
|
||||
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
|
||||
uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
|
||||
const uint8_t nonce[RFC_8439_NONCE_SIZE],
|
||||
const uint8_t *restrict cipher_text, size_t cipher_text_size) {
|
||||
const uint8_t nonce[RFC_8439_NONCE_SIZE], const uint8_t *restrict ad,
|
||||
size_t ad_size, const uint8_t *restrict cipher_text,
|
||||
size_t cipher_text_size) {
|
||||
// first we calculate the mac and see if it lines up, only then do we decrypt
|
||||
size_t actual_size = cipher_text_size - RFC_8439_TAG_SIZE;
|
||||
uint8_t computed_mac[RFC_8439_TAG_SIZE];
|
||||
int diff = 0;
|
||||
size_t i;
|
||||
if (MG_OVERLAPPING(plain_text, actual_size, cipher_text, cipher_text_size)) {
|
||||
return (size_t) -1;
|
||||
}
|
||||
|
||||
poly1305_calculate_mac(computed_mac, cipher_text, actual_size, key, nonce, ad,
|
||||
ad_size);
|
||||
|
||||
// compare tags
|
||||
for (i = 0; i < RFC_8439_TAG_SIZE; i++)
|
||||
diff |= computed_mac[i] ^ cipher_text[actual_size + i];
|
||||
if (diff != 0) return (size_t) -1;
|
||||
|
||||
chacha20_xor_stream(plain_text, cipher_text, actual_size, key, nonce, 1);
|
||||
return actual_size;
|
||||
}
|
||||
|
||||
@@ -105,6 +105,7 @@ PORTABLE_8439_DECL size_t mg_chacha20_poly1305_encrypt(
|
||||
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
|
||||
uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
|
||||
const uint8_t nonce[RFC_8439_NONCE_SIZE],
|
||||
const uint8_t *restrict ad, size_t ad_size,
|
||||
const uint8_t *restrict cipher_text, size_t cipher_text_size);
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
||||
+72
-12
@@ -72,6 +72,14 @@ static void test_match(void) {
|
||||
ASSERT(mg_match(mg_str_n("caabxa", 6), mg_str_n("#aa#bb#", 7), NULL) == 0);
|
||||
ASSERT(mg_match(mg_str_n("a__b_c", 6), mg_str_n("a*b*c", 5), NULL) == 1);
|
||||
|
||||
{
|
||||
char *ae_value = malloc(1); // Exact size for ASAN
|
||||
ae_value[0] = 'g';
|
||||
struct mg_str input = {ae_value, 1};
|
||||
mg_match(input, mg_str("*gzip*"), NULL); // Check for OOB
|
||||
free(ae_value);
|
||||
}
|
||||
|
||||
{
|
||||
struct mg_str caps[3];
|
||||
ASSERT(mg_match(mg_str("//a.c"), mg_str("#.c"), NULL) == true);
|
||||
@@ -1796,15 +1804,15 @@ static void test_http_parse(void) {
|
||||
}
|
||||
|
||||
// #2292: fail on stray \r inside the headers
|
||||
ASSERT(mg_http_parse("a є\n\n", 6, &req) == 6);
|
||||
ASSERT(mg_http_parse("a b\n\n", 5, &req) == 5);
|
||||
ASSERT(mg_http_parse("a b\na:\n\n", 8, &req) > 0);
|
||||
ASSERT(mg_http_parse("a b\na:\r\n\n", 9, &req) > 0);
|
||||
ASSERT(mg_http_parse("a b\n\ra:\r\n\n", 10, &req) == -1);
|
||||
ASSERT(mg_http_parse("a b\na:\r1\n\n", 10, &req) == -1);
|
||||
ASSERT(mg_http_parse("a b\na: \r1\n\n", 11, &req) == -1);
|
||||
ASSERT(mg_http_parse("a b\na: \rb:\n\n", 12, &req) == -1);
|
||||
ASSERT(mg_http_parse("a b\na: \nb:\n\n", 12, &req) > 0);
|
||||
ASSERT(mg_http_parse("a є HTTP/1.0\n\n", 15, &req) == 15);
|
||||
ASSERT(mg_http_parse("a b HTTP/1.0\n\n", 14, &req) == 14);
|
||||
ASSERT(mg_http_parse("a b HTTP/1.0\na:\n\n", 17, &req) > 0);
|
||||
ASSERT(mg_http_parse("a b HTTP/1.0\na:\r\n\n", 18, &req) > 0);
|
||||
ASSERT(mg_http_parse("a b HTTP/1.0\n\ra:\r\n\n", 19, &req) == -1);
|
||||
ASSERT(mg_http_parse("a b HTTP/1.0\na:\r1\n\n", 19, &req) == -1);
|
||||
ASSERT(mg_http_parse("a b HTTP/1.0\na: \r1\n\n", 20, &req) == -1);
|
||||
ASSERT(mg_http_parse("a b HTTP/1.0\na: \rb:\n\n", 21, &req) == -1);
|
||||
ASSERT(mg_http_parse("a b HTTP/1.0\na: \nb:\n\n", 21, &req) > 0);
|
||||
|
||||
{
|
||||
const char *s = "ґєт /слеш HTTP/1.0\nмісто: кіїв \n\n";
|
||||
@@ -1891,6 +1899,24 @@ static void test_http_parse(void) {
|
||||
ASSERT((v = mg_http_get_header(&req, "h")) == NULL); // MG_MAX_HTTP_HEADERS
|
||||
}
|
||||
|
||||
{
|
||||
// no HTTP version
|
||||
static char *s = "a b\na:1\nb:2\nc:2\n\n";
|
||||
ASSERT(mg_http_parse(s, strlen(s), &req) == -1);
|
||||
|
||||
// HTTP version
|
||||
s = "a b HTTP/1.0\na:1\nb:2\nc:2\n\n";
|
||||
ASSERT(mg_http_parse(s, strlen(s), &req) == strlen(s));
|
||||
|
||||
// Content-Length
|
||||
s = "a b HTTP/1.0\nContent-Length:10\nb:2\nc:2\n\n";
|
||||
ASSERT(mg_http_parse(s, strlen(s), &req) == strlen(s));
|
||||
|
||||
// duplicated Content-Length
|
||||
s = "a b HTTP/1.0\nContent-Length:10\nb:2\nContent-Length:20\n\n";
|
||||
ASSERT(mg_http_parse(s, strlen(s), &req) == -1);
|
||||
}
|
||||
|
||||
{
|
||||
struct mg_connection c;
|
||||
struct mg_str s,
|
||||
@@ -1916,15 +1942,15 @@ static void test_http_parse(void) {
|
||||
struct mg_http_message hm;
|
||||
const char *s = "a b HTTP/1.0\n\n";
|
||||
ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s));
|
||||
s = "a b\nc:d\n\n";
|
||||
s = "a b HTTP/1.0\nc:d\n\n";
|
||||
ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s));
|
||||
s = "a\nb:b\nc:c\n\n";
|
||||
ASSERT(mg_http_parse(s, strlen(s), &hm) < 0);
|
||||
s = "a b\nc: \xc0\n\n"; // Invalid UTF in the header value: accept
|
||||
s = "a b HTTP/1.0\nc: \xc0\n\n"; // Invalid UTF in the header value: accept
|
||||
ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s));
|
||||
ASSERT((v = mg_http_get_header(&hm, "c")) != NULL);
|
||||
ASSERT(vcmp(*v, "\xc0"));
|
||||
s = "a b\n\xc0: 2\n\n"; // Invalid UTF in the header name: do NOT accept
|
||||
s = "a b HTTP/1.0\n\xc0: 2\n\n"; // Invalid UTF in the header name: do NOT accept
|
||||
ASSERT(mg_http_parse(s, strlen(s), &hm) == -1);
|
||||
}
|
||||
|
||||
@@ -3625,6 +3651,40 @@ static void test_json(void) {
|
||||
val = mg_json_get_tok(json, "$.a");
|
||||
ASSERT(mg_strcmp(val, expected) == 0);
|
||||
}
|
||||
|
||||
// mg_json_get_num: parsing exponential
|
||||
{
|
||||
double d = 0.0;
|
||||
json = mg_str(
|
||||
"{"
|
||||
"\"i\":1e3,"
|
||||
"\"n\":-2.5e2,"
|
||||
"\"p\":3E+4,"
|
||||
"\"m\":4.25E-1,"
|
||||
"\"z\":0e0,"
|
||||
"\"s\":-0.0e+0,"
|
||||
"\"a\":[6.123456789e3,-1e-9],"
|
||||
"\"bad\":\"1e3\""
|
||||
"}");
|
||||
double tolerance = 1e-12;
|
||||
ASSERT(mg_json_get_num(json, "$.i", &d) == true);
|
||||
ASSERT(fabs(d - 1000.0) < tolerance);
|
||||
ASSERT(mg_json_get_num(json, "$.n", &d) == true);
|
||||
ASSERT(fabs(d - -250.0) < tolerance);
|
||||
ASSERT(mg_json_get_num(json, "$.p", &d) == true);
|
||||
ASSERT(fabs(d - 30000.0) < tolerance);
|
||||
ASSERT(mg_json_get_num(json, "$.m", &d) == true);
|
||||
ASSERT(fabs(d - 0.425) < tolerance);
|
||||
ASSERT(mg_json_get_num(json, "$.z", &d) == true);
|
||||
ASSERT(fabs(d - 0.0) < tolerance);
|
||||
ASSERT(mg_json_get_num(json, "$.s", &d) == true);
|
||||
ASSERT(fabs(d - 0.0) < tolerance);
|
||||
ASSERT(mg_json_get_num(json, "$.a[0]", &d) == true);
|
||||
ASSERT(fabs(d - 6123.456789) < tolerance);
|
||||
ASSERT(mg_json_get_num(json, "$.a[1]", &d) == true);
|
||||
ASSERT(fabs(d - -1e-9) < tolerance);
|
||||
ASSERT(mg_json_get_num(json, "$.bad", &d) == false);
|
||||
}
|
||||
}
|
||||
|
||||
static void resp_rpc(struct mg_rpc_req *r) {
|
||||
|
||||
Reference in New Issue
Block a user