Skip to content

Commit f0bc1c0

Browse files
authored
Merge pull request #3331 from cesanta/tls2
TLS: fix resuming handshake, fix improper cert req length
2 parents f7a86f8 + 19d2b93 commit f0bc1c0

File tree

3 files changed

+94
-56
lines changed

3 files changed

+94
-56
lines changed

mongoose.c

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4968,10 +4968,8 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
49684968
// if not already running, setup a timer to send an ACK later
49694969
if (s->ttype != MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_ACK);
49704970
}
4971-
if (c->is_tls && c->is_tls_hs) {
4972-
mg_tls_handshake(c);
4973-
} else if (c->is_tls) {
4974-
handle_tls_recv(c);
4971+
if (c->is_tls) {
4972+
c->is_tls_hs ? mg_tls_handshake(c) : handle_tls_recv(c);
49754973
} else {
49764974
// Plain text connection, data is already in c->recv, trigger MG_EV_READ
49774975
mg_call(c, MG_EV_READ, &pkt->pay.len);
@@ -5592,7 +5590,7 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
55925590
mg_tls_pending(c), c->rtls.len));
55935591
// order is important, TLS conn close with > 1 record in buffer (below)
55945592
if (is_tls && (c->rtls.len > 0 || mg_tls_pending(c) > 0))
5595-
handle_tls_recv(c);
5593+
c->is_tls_hs ? mg_tls_handshake(c) : handle_tls_recv(c);
55965594
if (can_write(c)) write_conn(c);
55975595
if (is_tls && c->send.len == 0) mg_tls_flush(c);
55985596
if (c->is_draining && c->send.len == 0 && s->ttype != MIP_TTYPE_FIN)
@@ -11164,7 +11162,8 @@ struct tls_data {
1116411162
size_t pubkeysz; // size of the server public key
1116511163
uint8_t sighash[32]; // calculated signature verification hash
1116611164

11167-
struct tls_enc enc;
11165+
struct tls_enc enc; // actual keys in use at this time
11166+
struct tls_enc app_keys; // storage during two-way auth handshake
1116811167
};
1116911168

1117011169
#define TLS_RECHDR_SIZE 5 // 1 byte type, 2 bytes version, 2 bytes length
@@ -11554,8 +11553,7 @@ static int mg_tls_recv_record(struct mg_connection *c) {
1155411553
}
1155511554
if (rio->buf[0] == MG_TLS_APP_DATA) {
1155611555
break;
11557-
} else if (rio->buf[0] ==
11558-
MG_TLS_CHANGE_CIPHER) { // Skip ChangeCipher messages
11556+
} else if (rio->buf[0] == MG_TLS_CHANGE_CIPHER) { // skip CCS
1155911557
mg_tls_drop_record(c);
1156011558
} else if (rio->buf[0] == MG_TLS_ALERT) { // Skip Alerts
1156111559
MG_INFO(("TLS ALERT packet received"));
@@ -11764,29 +11762,28 @@ static void mg_tls_server_send_ext(struct mg_connection *c) {
1176411762
// signature algorithms we actually support:
1176511763
// rsa_pkcs1_sha256, rsa_pss_rsae_sha256 and ecdsa_secp256r1_sha256
1176611764
static const uint8_t secp256r1_sig_algs[12] = {
11767-
0x00, 0x0d, 0x00, 0x08, 0x00, 0x06, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01,
11765+
0x00, 0x0d, 0x00, 0x08, 0x00, 0x06, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01
1176811766
};
1176911767

1177011768
static void mg_tls_server_send_cert_request(struct mg_connection *c) {
1177111769
struct tls_data *tls = (struct tls_data *) c->tls;
11772-
size_t n = sizeof(secp256r1_sig_algs) + 6;
11773-
uint8_t *req = (uint8_t *) mg_calloc(1, 13 + n);
11770+
uint8_t *req = (uint8_t *) mg_calloc(1, 13 + sizeof(secp256r1_sig_algs));
1177411771
if (req == NULL) {
1177511772
mg_error(c, "tls cert req oom");
1177611773
return;
1177711774
}
1177811775
req[0] = MG_TLS_CERTIFICATE_REQUEST; // handshake header
11779-
MG_STORE_BE24(req + 1, n + 9);
11780-
req[4] = 0; // context length
11781-
MG_STORE_BE16(req + 5, n); // extensions length
11776+
MG_STORE_BE24(req + 1, 9 + sizeof(secp256r1_sig_algs));
11777+
req[4] = 0; // context length
11778+
MG_STORE_BE16(req + 5, 6 + sizeof(secp256r1_sig_algs)); // extensions length
1178211779
MG_STORE_BE16(req + 7, 13); // "signature algorithms"
11783-
MG_STORE_BE16(req + 9, sizeof(secp256r1_sig_algs) + 2); // length
11780+
MG_STORE_BE16(req + 9, 2 + sizeof(secp256r1_sig_algs)); // length
1178411781
MG_STORE_BE16(
1178511782
req + 11,
1178611783
sizeof(secp256r1_sig_algs)); // signature hash algorithms length
1178711784
memcpy(req + 13, (uint8_t *) secp256r1_sig_algs, sizeof(secp256r1_sig_algs));
11788-
mg_sha256_update(&tls->sha256, req, 13 + n);
11789-
mg_tls_encrypt(c, req, 13 + n, MG_TLS_HANDSHAKE);
11785+
mg_sha256_update(&tls->sha256, req, 13 + sizeof(secp256r1_sig_algs));
11786+
mg_tls_encrypt(c, req, 13 + sizeof(secp256r1_sig_algs), MG_TLS_HANDSHAKE);
1179011787
mg_free(req);
1179111788
}
1179211789

@@ -12259,7 +12256,8 @@ static int mg_tls_parse_cert_der(void *buf, size_t dersz,
1225912256
}
1226012257

1226112258
static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz,
12262-
const char *server_name) {
12259+
const char *server_name,
12260+
struct mg_addr *server_ip) {
1226312261
struct mg_der_tlv root, field, name;
1226412262
if (mg_der_parse((uint8_t *) der, dersz, &root) < 0) {
1226512263
MG_ERROR(("failed to parse certificate"));
@@ -12274,12 +12272,16 @@ static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz,
1227412272
return -1;
1227512273
}
1227612274
while (mg_der_next(&field, &name) > 0) {
12277-
MG_DEBUG(("Found SAN: %.*s", name.len, name.value));
12278-
if (mg_match(mg_str(server_name), mg_str_n((char *) name.value, name.len),
12279-
NULL)) {
12280-
// Found SAN that matches the host name
12281-
return 1;
12282-
}
12275+
if (name.type == 0x87 && name.len == 4) { // this is an IPv4 address
12276+
MG_DEBUG(("Found SAN, IP: %M", mg_print_ip4, name.value));
12277+
if (!server_ip->is_ip6 && *((uint32_t *) name.value) == server_ip->ip4)
12278+
return 1; // and matches the one we're connected to
12279+
} else { // this is a text SAN
12280+
MG_DEBUG(("Found SAN, (%u): %.*s", name.type, name.len, name.value));
12281+
if (mg_match(mg_str(server_name), mg_str_n((char *) name.value, name.len),
12282+
NULL))
12283+
return 1; // and matches the host name
12284+
} // TODO(): add IPv6 comparison, more items ?
1228312285
}
1228412286
return -1;
1228512287
}
@@ -12419,7 +12421,7 @@ static int mg_tls_recv_cert(struct mg_connection *c, bool is_client) {
1241912421
// First certificate in the chain is peer cert, check SAN if requested,
1242012422
// and store public key for further CertVerify step
1242112423
if (tls->hostname[0] != '\0' &&
12422-
mg_tls_verify_cert_san(cert, certsz, tls->hostname) <= 0 &&
12424+
mg_tls_verify_cert_san(cert, certsz, tls->hostname, &c->rem) <= 0 &&
1242312425
mg_tls_verify_cert_cn(&ci->subj, tls->hostname) <= 0) {
1242412426
mg_error(c, "failed to verify hostname");
1242512427
return -1;
@@ -12627,11 +12629,19 @@ static void mg_tls_client_handshake(struct mg_connection *c) {
1262712629
break;
1262812630
}
1262912631
if (tls->cert_requested && tls->cert_der.len > 0) { // two-way auth
12632+
// generate application keys at this point, keep using handshake keys
12633+
struct tls_enc hs_keys = tls->enc;
12634+
mg_tls_generate_application_keys(c);
12635+
tls->app_keys = tls->enc;
12636+
tls->enc = hs_keys;
1263012637
mg_tls_send_cert(c, true);
1263112638
mg_tls_send_cert_verify(c, true);
12639+
mg_tls_client_send_finish(c);
12640+
tls->enc = tls->app_keys;
12641+
} else {
12642+
mg_tls_client_send_finish(c);
12643+
mg_tls_generate_application_keys(c);
1263212644
}
12633-
mg_tls_client_send_finish(c);
12634-
mg_tls_generate_application_keys(c);
1263512645
tls->state = MG_TLS_STATE_CLIENT_CONNECTED;
1263612646
c->is_tls_hs = 0;
1263712647
mg_call(c, MG_EV_TLS_HS, NULL);
@@ -12657,6 +12667,11 @@ static void mg_tls_server_handshake(struct mg_connection *c) {
1265712667
mg_tls_send_cert_verify(c, false);
1265812668
mg_tls_server_send_finish(c);
1265912669
if (tls->is_twoway) {
12670+
// generate application keys at this point, keep using handshake keys
12671+
struct tls_enc hs_keys = tls->enc;
12672+
mg_tls_generate_application_keys(c);
12673+
tls->app_keys = tls->enc;
12674+
tls->enc = hs_keys;
1266012675
tls->state = MG_TLS_STATE_SERVER_WAIT_CERT;
1266112676
break;
1266212677
}
@@ -12666,7 +12681,11 @@ static void mg_tls_server_handshake(struct mg_connection *c) {
1266612681
if (mg_tls_server_recv_finish(c) < 0) {
1266712682
return;
1266812683
}
12669-
mg_tls_generate_application_keys(c);
12684+
if (tls->is_twoway) { // use previously generated keys
12685+
tls->enc = tls->app_keys;
12686+
} else { // generate keys now
12687+
mg_tls_generate_application_keys(c);
12688+
}
1267012689
tls->state = MG_TLS_STATE_SERVER_CONNECTED;
1267112690
c->is_tls_hs = 0;
1267212691
return;

src/net_builtin.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -804,10 +804,8 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
804804
// if not already running, setup a timer to send an ACK later
805805
if (s->ttype != MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_ACK);
806806
}
807-
if (c->is_tls && c->is_tls_hs) {
808-
mg_tls_handshake(c);
809-
} else if (c->is_tls) {
810-
handle_tls_recv(c);
807+
if (c->is_tls) {
808+
c->is_tls_hs ? mg_tls_handshake(c) : handle_tls_recv(c);
811809
} else {
812810
// Plain text connection, data is already in c->recv, trigger MG_EV_READ
813811
mg_call(c, MG_EV_READ, &pkt->pay.len);
@@ -1428,7 +1426,7 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
14281426
mg_tls_pending(c), c->rtls.len));
14291427
// order is important, TLS conn close with > 1 record in buffer (below)
14301428
if (is_tls && (c->rtls.len > 0 || mg_tls_pending(c) > 0))
1431-
handle_tls_recv(c);
1429+
c->is_tls_hs ? mg_tls_handshake(c) : handle_tls_recv(c);
14321430
if (can_write(c)) write_conn(c);
14331431
if (is_tls && c->send.len == 0) mg_tls_flush(c);
14341432
if (c->is_draining && c->send.len == 0 && s->ttype != MIP_TTYPE_FIN)

src/tls_builtin.c

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ struct tls_data {
9393
size_t pubkeysz; // size of the server public key
9494
uint8_t sighash[32]; // calculated signature verification hash
9595

96-
struct tls_enc enc;
96+
struct tls_enc enc; // actual keys in use at this time
97+
struct tls_enc app_keys; // storage during two-way auth handshake
9798
};
9899

99100
#define TLS_RECHDR_SIZE 5 // 1 byte type, 2 bytes version, 2 bytes length
@@ -483,8 +484,7 @@ static int mg_tls_recv_record(struct mg_connection *c) {
483484
}
484485
if (rio->buf[0] == MG_TLS_APP_DATA) {
485486
break;
486-
} else if (rio->buf[0] ==
487-
MG_TLS_CHANGE_CIPHER) { // Skip ChangeCipher messages
487+
} else if (rio->buf[0] == MG_TLS_CHANGE_CIPHER) { // skip CCS
488488
mg_tls_drop_record(c);
489489
} else if (rio->buf[0] == MG_TLS_ALERT) { // Skip Alerts
490490
MG_INFO(("TLS ALERT packet received"));
@@ -693,29 +693,28 @@ static void mg_tls_server_send_ext(struct mg_connection *c) {
693693
// signature algorithms we actually support:
694694
// rsa_pkcs1_sha256, rsa_pss_rsae_sha256 and ecdsa_secp256r1_sha256
695695
static const uint8_t secp256r1_sig_algs[12] = {
696-
0x00, 0x0d, 0x00, 0x08, 0x00, 0x06, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01,
696+
0x00, 0x0d, 0x00, 0x08, 0x00, 0x06, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01
697697
};
698698

699699
static void mg_tls_server_send_cert_request(struct mg_connection *c) {
700700
struct tls_data *tls = (struct tls_data *) c->tls;
701-
size_t n = sizeof(secp256r1_sig_algs) + 6;
702-
uint8_t *req = (uint8_t *) mg_calloc(1, 13 + n);
701+
uint8_t *req = (uint8_t *) mg_calloc(1, 13 + sizeof(secp256r1_sig_algs));
703702
if (req == NULL) {
704703
mg_error(c, "tls cert req oom");
705704
return;
706705
}
707706
req[0] = MG_TLS_CERTIFICATE_REQUEST; // handshake header
708-
MG_STORE_BE24(req + 1, n + 9);
709-
req[4] = 0; // context length
710-
MG_STORE_BE16(req + 5, n); // extensions length
707+
MG_STORE_BE24(req + 1, 9 + sizeof(secp256r1_sig_algs));
708+
req[4] = 0; // context length
709+
MG_STORE_BE16(req + 5, 6 + sizeof(secp256r1_sig_algs)); // extensions length
711710
MG_STORE_BE16(req + 7, 13); // "signature algorithms"
712-
MG_STORE_BE16(req + 9, sizeof(secp256r1_sig_algs) + 2); // length
711+
MG_STORE_BE16(req + 9, 2 + sizeof(secp256r1_sig_algs)); // length
713712
MG_STORE_BE16(
714713
req + 11,
715714
sizeof(secp256r1_sig_algs)); // signature hash algorithms length
716715
memcpy(req + 13, (uint8_t *) secp256r1_sig_algs, sizeof(secp256r1_sig_algs));
717-
mg_sha256_update(&tls->sha256, req, 13 + n);
718-
mg_tls_encrypt(c, req, 13 + n, MG_TLS_HANDSHAKE);
716+
mg_sha256_update(&tls->sha256, req, 13 + sizeof(secp256r1_sig_algs));
717+
mg_tls_encrypt(c, req, 13 + sizeof(secp256r1_sig_algs), MG_TLS_HANDSHAKE);
719718
mg_free(req);
720719
}
721720

@@ -1188,7 +1187,8 @@ static int mg_tls_parse_cert_der(void *buf, size_t dersz,
11881187
}
11891188

11901189
static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz,
1191-
const char *server_name) {
1190+
const char *server_name,
1191+
struct mg_addr *server_ip) {
11921192
struct mg_der_tlv root, field, name;
11931193
if (mg_der_parse((uint8_t *) der, dersz, &root) < 0) {
11941194
MG_ERROR(("failed to parse certificate"));
@@ -1203,12 +1203,16 @@ static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz,
12031203
return -1;
12041204
}
12051205
while (mg_der_next(&field, &name) > 0) {
1206-
MG_DEBUG(("Found SAN: %.*s", name.len, name.value));
1207-
if (mg_match(mg_str(server_name), mg_str_n((char *) name.value, name.len),
1208-
NULL)) {
1209-
// Found SAN that matches the host name
1210-
return 1;
1211-
}
1206+
if (name.type == 0x87 && name.len == 4) { // this is an IPv4 address
1207+
MG_DEBUG(("Found SAN, IP: %M", mg_print_ip4, name.value));
1208+
if (!server_ip->is_ip6 && *((uint32_t *) name.value) == server_ip->ip4)
1209+
return 1; // and matches the one we're connected to
1210+
} else { // this is a text SAN
1211+
MG_DEBUG(("Found SAN, (%u): %.*s", name.type, name.len, name.value));
1212+
if (mg_match(mg_str(server_name), mg_str_n((char *) name.value, name.len),
1213+
NULL))
1214+
return 1; // and matches the host name
1215+
} // TODO(): add IPv6 comparison, more items ?
12121216
}
12131217
return -1;
12141218
}
@@ -1348,7 +1352,7 @@ static int mg_tls_recv_cert(struct mg_connection *c, bool is_client) {
13481352
// First certificate in the chain is peer cert, check SAN if requested,
13491353
// and store public key for further CertVerify step
13501354
if (tls->hostname[0] != '\0' &&
1351-
mg_tls_verify_cert_san(cert, certsz, tls->hostname) <= 0 &&
1355+
mg_tls_verify_cert_san(cert, certsz, tls->hostname, &c->rem) <= 0 &&
13521356
mg_tls_verify_cert_cn(&ci->subj, tls->hostname) <= 0) {
13531357
mg_error(c, "failed to verify hostname");
13541358
return -1;
@@ -1556,11 +1560,19 @@ static void mg_tls_client_handshake(struct mg_connection *c) {
15561560
break;
15571561
}
15581562
if (tls->cert_requested && tls->cert_der.len > 0) { // two-way auth
1563+
// generate application keys at this point, keep using handshake keys
1564+
struct tls_enc hs_keys = tls->enc;
1565+
mg_tls_generate_application_keys(c);
1566+
tls->app_keys = tls->enc;
1567+
tls->enc = hs_keys;
15591568
mg_tls_send_cert(c, true);
15601569
mg_tls_send_cert_verify(c, true);
1570+
mg_tls_client_send_finish(c);
1571+
tls->enc = tls->app_keys;
1572+
} else {
1573+
mg_tls_client_send_finish(c);
1574+
mg_tls_generate_application_keys(c);
15611575
}
1562-
mg_tls_client_send_finish(c);
1563-
mg_tls_generate_application_keys(c);
15641576
tls->state = MG_TLS_STATE_CLIENT_CONNECTED;
15651577
c->is_tls_hs = 0;
15661578
mg_call(c, MG_EV_TLS_HS, NULL);
@@ -1586,6 +1598,11 @@ static void mg_tls_server_handshake(struct mg_connection *c) {
15861598
mg_tls_send_cert_verify(c, false);
15871599
mg_tls_server_send_finish(c);
15881600
if (tls->is_twoway) {
1601+
// generate application keys at this point, keep using handshake keys
1602+
struct tls_enc hs_keys = tls->enc;
1603+
mg_tls_generate_application_keys(c);
1604+
tls->app_keys = tls->enc;
1605+
tls->enc = hs_keys;
15891606
tls->state = MG_TLS_STATE_SERVER_WAIT_CERT;
15901607
break;
15911608
}
@@ -1595,7 +1612,11 @@ static void mg_tls_server_handshake(struct mg_connection *c) {
15951612
if (mg_tls_server_recv_finish(c) < 0) {
15961613
return;
15971614
}
1598-
mg_tls_generate_application_keys(c);
1615+
if (tls->is_twoway) { // use previously generated keys
1616+
tls->enc = tls->app_keys;
1617+
} else { // generate keys now
1618+
mg_tls_generate_application_keys(c);
1619+
}
15991620
tls->state = MG_TLS_STATE_SERVER_CONNECTED;
16001621
c->is_tls_hs = 0;
16011622
return;

0 commit comments

Comments
 (0)