aboutsummaryrefslogtreecommitdiff
path: root/networking/tls.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-01-20 19:11:14 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2017-01-20 19:11:14 +0100
commit38972a8df1df970a5878bbd7fc5ef6259f1168ab (patch)
treed205e830156c71b04058e8e7d28c2bda8f6a67df /networking/tls.c
parente7863f394e6a963d1e2c6af77ea064442d3ef594 (diff)
downloadbusybox-w32-38972a8df1df970a5878bbd7fc5ef6259f1168ab.tar.gz
busybox-w32-38972a8df1df970a5878bbd7fc5ef6259f1168ab.tar.bz2
busybox-w32-38972a8df1df970a5878bbd7fc5ef6259f1168ab.zip
tls: improve i/o loop
With tls_has_buffered_record(), entire kernel.org response is printed at once, without 6 second pause to see its delayed EOF. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking/tls.c')
-rw-r--r--networking/tls.c130
1 files changed, 92 insertions, 38 deletions
diff --git a/networking/tls.c b/networking/tls.c
index cdce1004e..000d2aedc 100644
--- a/networking/tls.c
+++ b/networking/tls.c
@@ -48,7 +48,7 @@
48# define dump_raw_out(...) ((void)0) 48# define dump_raw_out(...) ((void)0)
49#endif 49#endif
50 50
51#if 1 51#if 0
52# define dump_raw_in(...) dump_hex(__VA_ARGS__) 52# define dump_raw_in(...) dump_hex(__VA_ARGS__)
53#else 53#else
54# define dump_raw_in(...) ((void)0) 54# define dump_raw_in(...) ((void)0)
@@ -72,9 +72,6 @@
72#define HANDSHAKE_CLIENT_KEY_EXCHANGE 16 72#define HANDSHAKE_CLIENT_KEY_EXCHANGE 16
73#define HANDSHAKE_FINISHED 20 73#define HANDSHAKE_FINISHED 20
74 74
75#define SSL_HS_RANDOM_SIZE 32
76#define SSL_HS_RSA_PREMASTER_SIZE 48
77
78#define SSL_NULL_WITH_NULL_NULL 0x0000 75#define SSL_NULL_WITH_NULL_NULL 0x0000
79#define SSL_RSA_WITH_NULL_MD5 0x0001 76#define SSL_RSA_WITH_NULL_MD5 0x0001
80#define SSL_RSA_WITH_NULL_SHA 0x0002 77#define SSL_RSA_WITH_NULL_SHA 0x0002
@@ -175,12 +172,15 @@ enum {
175 AES128_KEYSIZE = 16, 172 AES128_KEYSIZE = 16,
176 AES256_KEYSIZE = 32, 173 AES256_KEYSIZE = 32,
177 174
175 RSA_PREMASTER_SIZE = 48,
176
178 RECHDR_LEN = 5, 177 RECHDR_LEN = 5,
179 178
180 MAX_TLS_RECORD = (1 << 14), 179 MAX_TLS_RECORD = (1 << 14),
180 /* 8 = 3+5. 3 extra bytes result in record data being 32-bit aligned */
181 OUTBUF_PFX = 8 + AES_BLOCKSIZE, /* header + IV */ 181 OUTBUF_PFX = 8 + AES_BLOCKSIZE, /* header + IV */
182 OUTBUF_SFX = SHA256_OUTSIZE + AES_BLOCKSIZE, /* MAC + padding */ 182 OUTBUF_SFX = SHA256_OUTSIZE + AES_BLOCKSIZE, /* MAC + padding */
183 MAX_OTBUF = MAX_TLS_RECORD - OUTBUF_PFX - OUTBUF_SFX, 183 MAX_OUTBUF = MAX_TLS_RECORD - OUTBUF_PFX - OUTBUF_SFX,
184}; 184};
185 185
186struct record_hdr { 186struct record_hdr {
@@ -205,20 +205,21 @@ typedef struct tls_state {
205 uint8_t server_write_MAC_key[SHA256_OUTSIZE]; 205 uint8_t server_write_MAC_key[SHA256_OUTSIZE];
206 uint8_t client_write_key[AES256_KEYSIZE]; 206 uint8_t client_write_key[AES256_KEYSIZE];
207 uint8_t server_write_key[AES256_KEYSIZE]; 207 uint8_t server_write_key[AES256_KEYSIZE];
208// RFC 5246 208
209// sequence number 209 // RFC 5246
210// Each connection state contains a sequence number, which is 210 // sequence number
211// maintained separately for read and write states. The sequence 211 // Each connection state contains a sequence number, which is
212// number MUST be set to zero whenever a connection state is made the 212 // maintained separately for read and write states. The sequence
213// active state. Sequence numbers are of type uint64 and may not 213 // number MUST be set to zero whenever a connection state is made the
214// exceed 2^64-1. 214 // active state. Sequence numbers are of type uint64 and may not
215 // exceed 2^64-1.
215 uint64_t write_seq64_be; 216 uint64_t write_seq64_be;
216 217
217 int outbuf_size; 218 int outbuf_size;
218 uint8_t *outbuf; 219 uint8_t *outbuf;
219 220
220 // RFC 5246 221 // RFC 5246
221 // |6.2.1. Fragmentation 222 // | 6.2.1. Fragmentation
222 // | The record layer fragments information blocks into TLSPlaintext 223 // | The record layer fragments information blocks into TLSPlaintext
223 // | records carrying data in chunks of 2^14 bytes or less. Client 224 // | records carrying data in chunks of 2^14 bytes or less. Client
224 // | message boundaries are not preserved in the record layer (i.e., 225 // | message boundaries are not preserved in the record layer (i.e.,
@@ -290,6 +291,9 @@ static void dump_tls_record(const void *vp, int len)
290 len -= xhdr_len; 291 len -= xhdr_len;
291 } 292 }
292} 293}
294#else
295# define dump_hex(...) ((void)0)
296# define dump_tls_record(...) ((void)0)
293#endif 297#endif
294 298
295void tls_get_random(void *buf, unsigned len) 299void tls_get_random(void *buf, unsigned len)
@@ -480,12 +484,19 @@ static tls_state_t *new_tls_state(void)
480static void tls_error_die(tls_state_t *tls) 484static void tls_error_die(tls_state_t *tls)
481{ 485{
482 dump_tls_record(tls->inbuf, tls->insize + tls->tail); 486 dump_tls_record(tls->inbuf, tls->insize + tls->tail);
483 xfunc_die(); 487 bb_error_msg_and_die("TODO: useful diagnostic about %p", tls);
488}
489
490static void tls_free_outbuf(tls_state_t *tls)
491{
492 free(tls->outbuf);
493 tls->outbuf_size = 0;
494 tls->outbuf = NULL;
484} 495}
485 496
486static void *tls_get_outbuf(tls_state_t *tls, int len) 497static void *tls_get_outbuf(tls_state_t *tls, int len)
487{ 498{
488 if (len > MAX_OTBUF) 499 if (len > MAX_OUTBUF)
489 xfunc_die(); 500 xfunc_die();
490 if (tls->outbuf_size < len + OUTBUF_PFX + OUTBUF_SFX) { 501 if (tls->outbuf_size < len + OUTBUF_PFX + OUTBUF_SFX) {
491 tls->outbuf_size = len + OUTBUF_PFX + OUTBUF_SFX; 502 tls->outbuf_size = len + OUTBUF_PFX + OUTBUF_SFX;
@@ -670,7 +681,22 @@ static void xwrite_and_update_handshake_hash(tls_state_t *tls, unsigned size)
670 xwrite_encrypted(tls, size, RECORD_TYPE_HANDSHAKE); 681 xwrite_encrypted(tls, size, RECORD_TYPE_HANDSHAKE);
671} 682}
672 683
673static int xread_tls_block(tls_state_t *tls) 684static int tls_has_buffered_record(tls_state_t *tls)
685{
686 int buffered = tls->tail;
687 struct record_hdr *xhdr;
688 int rec_size;
689
690 if (buffered < RECHDR_LEN)
691 return 0;
692 xhdr = (void*)(tls->inbuf + tls->insize);
693 rec_size = RECHDR_LEN + (0x100 * xhdr->len16_hi + xhdr->len16_lo);
694 if (buffered < rec_size)
695 return 0;
696 return rec_size;
697}
698
699static int tls_xread_record(tls_state_t *tls)
674{ 700{
675 struct record_hdr *xhdr; 701 struct record_hdr *xhdr;
676 int sz; 702 int sz;
@@ -1012,7 +1038,7 @@ static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len)
1012static int xread_tls_handshake_block(tls_state_t *tls, int min_len) 1038static int xread_tls_handshake_block(tls_state_t *tls, int min_len)
1013{ 1039{
1014 struct record_hdr *xhdr; 1040 struct record_hdr *xhdr;
1015 int len = xread_tls_block(tls); 1041 int len = tls_xread_record(tls);
1016 1042
1017 xhdr = (void*)tls->inbuf; 1043 xhdr = (void*)tls->inbuf;
1018 if (len < min_len 1044 if (len < min_len
@@ -1177,7 +1203,7 @@ static void send_client_key_exchange(tls_state_t *tls)
1177 }; 1203 };
1178//FIXME: better size estimate 1204//FIXME: better size estimate
1179 struct client_key_exchange *record = tls_get_outbuf(tls, sizeof(*record)); 1205 struct client_key_exchange *record = tls_get_outbuf(tls, sizeof(*record));
1180 uint8_t rsa_premaster[SSL_HS_RSA_PREMASTER_SIZE]; 1206 uint8_t rsa_premaster[RSA_PREMASTER_SIZE];
1181 int len; 1207 int len;
1182 1208
1183 tls_get_random(rsa_premaster, sizeof(rsa_premaster)); 1209 tls_get_random(rsa_premaster, sizeof(rsa_premaster));
@@ -1383,7 +1409,7 @@ static void tls_handshake(tls_state_t *tls)
1383 send_client_hello(tls); 1409 send_client_hello(tls);
1384 get_server_hello(tls); 1410 get_server_hello(tls);
1385 1411
1386 //RFC 5246 1412 // RFC 5246
1387 // The server MUST send a Certificate message whenever the agreed- 1413 // The server MUST send a Certificate message whenever the agreed-
1388 // upon key exchange method uses certificates for authentication 1414 // upon key exchange method uses certificates for authentication
1389 // (this includes all key exchange methods defined in this document 1415 // (this includes all key exchange methods defined in this document
@@ -1408,7 +1434,7 @@ static void tls_handshake(tls_state_t *tls)
1408 1434
1409// if (tls->inbuf[RECHDR_LEN] == HANDSHAKE_CERTIFICATE_REQUEST) { 1435// if (tls->inbuf[RECHDR_LEN] == HANDSHAKE_CERTIFICATE_REQUEST) {
1410// dbg("<< CERTIFICATE_REQUEST\n"); 1436// dbg("<< CERTIFICATE_REQUEST\n");
1411//RFC 5246: (in response to this,) "If no suitable certificate is available, 1437// RFC 5246: (in response to this,) "If no suitable certificate is available,
1412// the client MUST send a certificate message containing no 1438// the client MUST send a certificate message containing no
1413// certificates. That is, the certificate_list structure has a 1439// certificates. That is, the certificate_list structure has a
1414// length of zero. ... 1440// length of zero. ...
@@ -1433,7 +1459,7 @@ static void tls_handshake(tls_state_t *tls)
1433 send_client_finished(tls); 1459 send_client_finished(tls);
1434 1460
1435 /* Get CHANGE_CIPHER_SPEC */ 1461 /* Get CHANGE_CIPHER_SPEC */
1436 len = xread_tls_block(tls); 1462 len = tls_xread_record(tls);
1437 if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0) 1463 if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0)
1438 tls_error_die(tls); 1464 tls_error_die(tls);
1439 dbg("<< CHANGE_CIPHER_SPEC\n"); 1465 dbg("<< CHANGE_CIPHER_SPEC\n");
@@ -1444,7 +1470,7 @@ static void tls_handshake(tls_state_t *tls)
1444 tls->min_encrypted_len_on_read = AES_BLOCKSIZE + SHA256_OUTSIZE + AES_BLOCKSIZE; 1470 tls->min_encrypted_len_on_read = AES_BLOCKSIZE + SHA256_OUTSIZE + AES_BLOCKSIZE;
1445 1471
1446 /* Get (encrypted) FINISHED from the server */ 1472 /* Get (encrypted) FINISHED from the server */
1447 len = xread_tls_block(tls); 1473 len = tls_xread_record(tls);
1448 if (len < 4 || tls->inbuf[RECHDR_LEN] != HANDSHAKE_FINISHED) 1474 if (len < 4 || tls->inbuf[RECHDR_LEN] != HANDSHAKE_FINISHED)
1449 tls_error_die(tls); 1475 tls_error_die(tls);
1450 dbg("<< FINISHED\n"); 1476 dbg("<< FINISHED\n");
@@ -1473,9 +1499,12 @@ int tls_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1473int tls_main(int argc UNUSED_PARAM, char **argv) 1499int tls_main(int argc UNUSED_PARAM, char **argv)
1474{ 1500{
1475 tls_state_t *tls; 1501 tls_state_t *tls;
1476 fd_set readfds, testfds; 1502 fd_set readfds;
1503 int inbuf_size;
1504 const int INBUF_STEP = 4 * 1024;
1477 int cfd; 1505 int cfd;
1478 1506
1507
1479 // INIT_G(); 1508 // INIT_G();
1480 // getopt32(argv, "myopts") 1509 // getopt32(argv, "myopts")
1481 1510
@@ -1493,13 +1522,12 @@ int tls_main(int argc UNUSED_PARAM, char **argv)
1493 FD_SET(cfd, &readfds); 1522 FD_SET(cfd, &readfds);
1494 FD_SET(STDIN_FILENO, &readfds); 1523 FD_SET(STDIN_FILENO, &readfds);
1495 1524
1496//#define iobuf bb_common_bufsiz1 1525 inbuf_size = INBUF_STEP;
1497// setup_common_bufsiz();
1498 for (;;) { 1526 for (;;) {
1527 fd_set testfds;
1499 int nread; 1528 int nread;
1500 1529
1501 testfds = readfds; 1530 testfds = readfds;
1502
1503 if (select(cfd + 1, &testfds, NULL, NULL, NULL) < 0) 1531 if (select(cfd + 1, &testfds, NULL, NULL, NULL) < 0)
1504 bb_perror_msg_and_die("select"); 1532 bb_perror_msg_and_die("select");
1505 1533
@@ -1507,26 +1535,52 @@ int tls_main(int argc UNUSED_PARAM, char **argv)
1507 void *buf; 1535 void *buf;
1508 1536
1509 dbg("STDIN HAS DATA\n"); 1537 dbg("STDIN HAS DATA\n");
1510//TODO: growable buffer 1538 buf = tls_get_outbuf(tls, inbuf_size);
1511 buf = tls_get_outbuf(tls, 4 * 1024); 1539 nread = safe_read(STDIN_FILENO, buf, inbuf_size);
1512 nread = safe_read(STDIN_FILENO, buf, 4 * 1024);
1513 if (nread < 1) { 1540 if (nread < 1) {
1514//&& errno != EAGAIN 1541 /* We'd want to do this: */
1515 /* Close outgoing half-connection so they get EOF, 1542 /* Close outgoing half-connection so they get EOF,
1516 * but leave incoming alone so we can see response */ 1543 * but leave incoming alone so we can see response
1517//TLS has no way to encode this, doubt it's ok to do it "raw" 1544 */
1518// shutdown(cfd, SHUT_WR); 1545 //shutdown(cfd, SHUT_WR);
1546 /* But TLS has no way to encode this,
1547 * doubt it's ok to do it "raw"
1548 */
1519 FD_CLR(STDIN_FILENO, &readfds); 1549 FD_CLR(STDIN_FILENO, &readfds);
1550 tls_free_outbuf(tls);
1551 } else {
1552 if (nread == inbuf_size) {
1553 /* TLS has per record overhead, if input comes fast,
1554 * read, encrypt and send bigger chunks
1555 */
1556 inbuf_size += INBUF_STEP;
1557 if (inbuf_size > MAX_OUTBUF)
1558 inbuf_size = MAX_OUTBUF;
1559 }
1560 tls_xwrite(tls, nread);
1520 } 1561 }
1521 tls_xwrite(tls, nread);
1522 } 1562 }
1523 if (FD_ISSET(cfd, &testfds)) { 1563 if (FD_ISSET(cfd, &testfds)) {
1524 dbg("NETWORK HAS DATA\n"); 1564 dbg("NETWORK HAS DATA\n");
1525 nread = xread_tls_block(tls); 1565 read_record:
1526 if (nread < 1) 1566 nread = tls_xread_record(tls);
1527//TODO: if eof, just close stdout, but not exit! 1567 if (nread < 1) {
1528 return EXIT_SUCCESS; 1568 /* TLS protocol has no real concept of one-sided shutdowns:
1569 * if we get "TLS EOF" from the peer, writes will fail too
1570 */
1571 //FD_CLR(cfd, &readfds);
1572 //close(STDOUT_FILENO);
1573 //continue;
1574 break;
1575 }
1576 if (tls->inbuf[0] != RECORD_TYPE_APPLICATION_DATA)
1577 bb_error_msg_and_die("unexpected record type %d", tls->inbuf[0]);
1529 xwrite(STDOUT_FILENO, tls->inbuf + RECHDR_LEN, nread); 1578 xwrite(STDOUT_FILENO, tls->inbuf + RECHDR_LEN, nread);
1579 /* We may already have a complete next record buffered,
1580 * can process it without network reads (and possible blocking)
1581 */
1582 if (tls_has_buffered_record(tls))
1583 goto read_record;
1530 } 1584 }
1531 } 1585 }
1532 1586