diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-01-20 03:15:09 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-01-20 03:15:09 +0100 |
commit | abbf17abccbf832365d9acf1c280369ba7d5f8b2 (patch) | |
tree | 8efda8ec7a3f95d2e4e5f90dc5af933d02b6b1f4 | |
parent | f7806f9d8fc889f1d6cd365b69d9d99a4a5a6e26 (diff) | |
download | busybox-w32-abbf17abccbf832365d9acf1c280369ba7d5f8b2.tar.gz busybox-w32-abbf17abccbf832365d9acf1c280369ba7d5f8b2.tar.bz2 busybox-w32-abbf17abccbf832365d9acf1c280369ba7d5f8b2.zip |
tls: add the i/o loop - largish rework of i/o buffering
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/tls.c | 274 |
1 files changed, 166 insertions, 108 deletions
diff --git a/networking/tls.c b/networking/tls.c index 092735884..71be2def8 100644 --- a/networking/tls.c +++ b/networking/tls.c | |||
@@ -23,9 +23,10 @@ | |||
23 | //usage:#define tls_full_usage "\n\n" | 23 | //usage:#define tls_full_usage "\n\n" |
24 | 24 | ||
25 | #include "tls.h" | 25 | #include "tls.h" |
26 | #include "common_bufsiz.h" | ||
26 | 27 | ||
27 | #define TLS_DEBUG 1 | 28 | #define TLS_DEBUG 1 |
28 | #define TLS_DEBUG_HASH 0 | 29 | #define TLS_DEBUG_HASH 1 |
29 | #define TLS_DEBUG_DER 0 | 30 | #define TLS_DEBUG_DER 0 |
30 | 31 | ||
31 | #if TLS_DEBUG | 32 | #if TLS_DEBUG |
@@ -150,9 +151,8 @@ | |||
150 | // works against "openssl s_server -cipher NULL" | 151 | // works against "openssl s_server -cipher NULL" |
151 | // and against wolfssl-3.9.10-stable/examples/server/server.c: | 152 | // and against wolfssl-3.9.10-stable/examples/server/server.c: |
152 | //#define CIPHER_ID TLS_RSA_WITH_NULL_SHA256 // for testing (does everything except encrypting) | 153 | //#define CIPHER_ID TLS_RSA_WITH_NULL_SHA256 // for testing (does everything except encrypting) |
153 | // "works", meaning | 154 | // works against wolfssl-3.9.10-stable/examples/server/server.c |
154 | // "can send encrypted FINISHED to wolfssl-3.9.10-stable/examples/server/server.c", | 155 | // (getting back and decrypt ok first application data message) |
155 | // don't yet read its encrypted answers: | ||
156 | #define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // ok, no SERVER_KEY_EXCHANGE | 156 | #define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // ok, no SERVER_KEY_EXCHANGE |
157 | 157 | ||
158 | enum { | 158 | enum { |
@@ -162,6 +162,11 @@ enum { | |||
162 | AES_BLOCKSIZE = 16, | 162 | AES_BLOCKSIZE = 16, |
163 | AES128_KEYSIZE = 16, | 163 | AES128_KEYSIZE = 16, |
164 | AES256_KEYSIZE = 32, | 164 | AES256_KEYSIZE = 32, |
165 | |||
166 | MAX_TLS_RECORD = (1 << 14), | ||
167 | OUTBUF_PFX = 8 + AES_BLOCKSIZE, /* header + IV */ | ||
168 | OUTBUF_SFX = SHA256_OUTSIZE + AES_BLOCKSIZE, /* MAC + padding */ | ||
169 | MAX_OTBUF = MAX_TLS_RECORD - OUTBUF_PFX - OUTBUF_SFX, | ||
165 | }; | 170 | }; |
166 | 171 | ||
167 | struct record_hdr { | 172 | struct record_hdr { |
@@ -195,6 +200,9 @@ typedef struct tls_state { | |||
195 | // exceed 2^64-1. | 200 | // exceed 2^64-1. |
196 | uint64_t write_seq64_be; | 201 | uint64_t write_seq64_be; |
197 | 202 | ||
203 | int outbuf_size; | ||
204 | uint8_t *outbuf; | ||
205 | |||
198 | // RFC 5246 | 206 | // RFC 5246 |
199 | // |6.2.1. Fragmentation | 207 | // |6.2.1. Fragmentation |
200 | // | The record layer fragments information blocks into TLSPlaintext | 208 | // | The record layer fragments information blocks into TLSPlaintext |
@@ -225,7 +233,6 @@ typedef struct tls_state { | |||
225 | //needed? | 233 | //needed? |
226 | uint64_t align____; | 234 | uint64_t align____; |
227 | uint8_t inbuf[20*1024]; | 235 | uint8_t inbuf[20*1024]; |
228 | uint8_t outbuf[20*1024]; | ||
229 | } tls_state_t; | 236 | } tls_state_t; |
230 | 237 | ||
231 | 238 | ||
@@ -462,6 +469,17 @@ static void tls_error_die(tls_state_t *tls) | |||
462 | xfunc_die(); | 469 | xfunc_die(); |
463 | } | 470 | } |
464 | 471 | ||
472 | static void *tls_get_outbuf(tls_state_t *tls, int len) | ||
473 | { | ||
474 | if (len > MAX_OTBUF) | ||
475 | xfunc_die(); | ||
476 | if (tls->outbuf_size < len + OUTBUF_PFX + OUTBUF_SFX) { | ||
477 | tls->outbuf_size = len + OUTBUF_PFX + OUTBUF_SFX; | ||
478 | tls->outbuf = xrealloc(tls->outbuf, tls->outbuf_size); | ||
479 | } | ||
480 | return tls->outbuf + OUTBUF_PFX; | ||
481 | } | ||
482 | |||
465 | // RFC 5246 | 483 | // RFC 5246 |
466 | // 6.2.3.1. Null or Standard Stream Cipher | 484 | // 6.2.3.1. Null or Standard Stream Cipher |
467 | // | 485 | // |
@@ -501,39 +519,41 @@ static void tls_error_die(tls_state_t *tls) | |||
501 | // -------- ----------- ---------- -------------- | 519 | // -------- ----------- ---------- -------------- |
502 | // SHA HMAC-SHA1 20 20 | 520 | // SHA HMAC-SHA1 20 20 |
503 | // SHA256 HMAC-SHA256 32 32 | 521 | // SHA256 HMAC-SHA256 32 32 |
504 | static void xwrite_and_hash(tls_state_t *tls, /*const*/ void *buf, unsigned size) | 522 | static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type) |
505 | { | 523 | { |
506 | uint8_t mac_hash[SHA256_OUTSIZE]; | 524 | uint8_t *buf = tls->outbuf + OUTBUF_PFX; |
507 | struct record_hdr *xhdr = buf; | 525 | struct record_hdr *xhdr; |
508 | 526 | ||
509 | if (!tls->encrypt_on_write) { | 527 | xhdr = (void*)(buf - sizeof(*xhdr)); |
510 | xwrite(tls->fd, buf, size); | 528 | if (CIPHER_ID != TLS_RSA_WITH_NULL_SHA256) |
511 | dbg("wrote %u bytes\n", size); | 529 | xhdr = (void*)(buf - sizeof(*xhdr) - AES_BLOCKSIZE); /* place for IV */ |
512 | /* Handshake hash does not include record headers */ | 530 | |
513 | if (size > 5 && xhdr->type == RECORD_TYPE_HANDSHAKE) { | 531 | xhdr->type = type; |
514 | sha256_hash_dbg(">> sha256:%s", &tls->handshake_sha256_ctx, (uint8_t*)buf + 5, size - 5); | 532 | xhdr->proto_maj = TLS_MAJ; |
515 | } | 533 | xhdr->proto_min = TLS_MIN; |
516 | return; | 534 | /* fake unencrypted record header len for MAC calculation */ |
517 | } | 535 | xhdr->len16_hi = size >> 8; |
536 | xhdr->len16_lo = size & 0xff; | ||
518 | 537 | ||
538 | /* Calculate MAC signature */ | ||
519 | //TODO: convert hmac_sha256 to precomputed | 539 | //TODO: convert hmac_sha256 to precomputed |
520 | hmac_sha256(mac_hash, | 540 | hmac_sha256(buf + size, |
521 | tls->client_write_MAC_key, sizeof(tls->client_write_MAC_key), | 541 | tls->client_write_MAC_key, sizeof(tls->client_write_MAC_key), |
522 | &tls->write_seq64_be, sizeof(tls->write_seq64_be), | 542 | &tls->write_seq64_be, sizeof(tls->write_seq64_be), |
543 | xhdr, sizeof(*xhdr), | ||
523 | buf, size, | 544 | buf, size, |
524 | NULL); | 545 | NULL); |
525 | tls->write_seq64_be = SWAP_BE64(1 + SWAP_BE64(tls->write_seq64_be)); | 546 | tls->write_seq64_be = SWAP_BE64(1 + SWAP_BE64(tls->write_seq64_be)); |
526 | 547 | ||
548 | size += SHA256_OUTSIZE; | ||
549 | |||
527 | if (CIPHER_ID == TLS_RSA_WITH_NULL_SHA256) { | 550 | if (CIPHER_ID == TLS_RSA_WITH_NULL_SHA256) { |
528 | /* No encryption, only signing */ | 551 | /* No encryption, only signing */ |
529 | xhdr->len16_lo += SHA256_OUTSIZE; | 552 | xhdr->len16_hi = size >> 8; |
530 | //FIXME: overflow into len16_hi? | 553 | xhdr->len16_lo = size & 0xff; |
531 | xwrite(tls->fd, buf, size); | 554 | dump_hex(">> %s\n", xhdr, sizeof(*xhdr) + size); |
532 | xhdr->len16_lo -= SHA256_OUTSIZE; | 555 | xwrite(tls->fd, xhdr, sizeof(*xhdr) + size); |
533 | dbg("wrote %u bytes\n", size); | 556 | dbg("wrote %u bytes (NULL crypt, SHA256 hash)\n", size); |
534 | |||
535 | xwrite(tls->fd, mac_hash, sizeof(mac_hash)); | ||
536 | dbg("wrote %u bytes of hash\n", (int)sizeof(mac_hash)); | ||
537 | return; | 557 | return; |
538 | } | 558 | } |
539 | 559 | ||
@@ -579,13 +599,8 @@ static void xwrite_and_hash(tls_state_t *tls, /*const*/ void *buf, unsigned size | |||
579 | uint8_t padding_length; | 599 | uint8_t padding_length; |
580 | 600 | ||
581 | /* Build IV+content+MAC+padding in outbuf */ | 601 | /* Build IV+content+MAC+padding in outbuf */ |
582 | tls_get_random(tls->outbuf, AES_BLOCKSIZE); /* IV */ | 602 | tls_get_random(buf - AES_BLOCKSIZE, AES_BLOCKSIZE); /* IV */ |
583 | p = tls->outbuf + AES_BLOCKSIZE; | 603 | dbg("before crypt: 5 hdr + %u data + %u hash bytes\n", size, SHA256_OUTSIZE); |
584 | size -= sizeof(*xhdr); | ||
585 | dbg("before crypt: 5 hdr + %u data + %u hash bytes\n", size, (int)sizeof(mac_hash)); | ||
586 | p = mempcpy(p, buf + sizeof(*xhdr), size); /* content */ | ||
587 | p = mempcpy(p, mac_hash, sizeof(mac_hash)); /* MAC */ | ||
588 | size += sizeof(mac_hash); | ||
589 | // RFC is talking nonsense: | 604 | // RFC is talking nonsense: |
590 | // Padding that is added to force the length of the plaintext to be | 605 | // Padding that is added to force the length of the plaintext to be |
591 | // an integral multiple of the block cipher's block length. | 606 | // an integral multiple of the block cipher's block length. |
@@ -601,6 +616,7 @@ static void xwrite_and_hash(tls_state_t *tls, /*const*/ void *buf, unsigned size | |||
601 | // If you need no bytes to reach BLOCKSIZE, you have to pad a full | 616 | // If you need no bytes to reach BLOCKSIZE, you have to pad a full |
602 | // BLOCKSIZE with bytes of value (BLOCKSIZE-1). | 617 | // BLOCKSIZE with bytes of value (BLOCKSIZE-1). |
603 | // It's ok to have more than minimum padding, but we do minimum. | 618 | // It's ok to have more than minimum padding, but we do minimum. |
619 | p = buf + size; | ||
604 | padding_length = (~size) & (AES_BLOCKSIZE - 1); | 620 | padding_length = (~size) & (AES_BLOCKSIZE - 1); |
605 | do { | 621 | do { |
606 | *p++ = padding_length; /* padding */ | 622 | *p++ = padding_length; /* padding */ |
@@ -608,12 +624,12 @@ static void xwrite_and_hash(tls_state_t *tls, /*const*/ void *buf, unsigned size | |||
608 | } while ((size & (AES_BLOCKSIZE - 1)) != 0); | 624 | } while ((size & (AES_BLOCKSIZE - 1)) != 0); |
609 | 625 | ||
610 | /* Encrypt content+MAC+padding in place */ | 626 | /* Encrypt content+MAC+padding in place */ |
611 | psAesInit(&ctx, tls->outbuf, /* IV */ | 627 | psAesInit(&ctx, buf - AES_BLOCKSIZE, /* IV */ |
612 | tls->client_write_key, sizeof(tls->client_write_key) | 628 | tls->client_write_key, sizeof(tls->client_write_key) |
613 | ); | 629 | ); |
614 | psAesEncrypt(&ctx, | 630 | psAesEncrypt(&ctx, |
615 | tls->outbuf + AES_BLOCKSIZE, /* plaintext */ | 631 | buf, /* plaintext */ |
616 | tls->outbuf + AES_BLOCKSIZE, /* ciphertext */ | 632 | buf, /* ciphertext */ |
617 | size | 633 | size |
618 | ); | 634 | ); |
619 | 635 | ||
@@ -623,14 +639,33 @@ static void xwrite_and_hash(tls_state_t *tls, /*const*/ void *buf, unsigned size | |||
623 | size += AES_BLOCKSIZE; /* + IV */ | 639 | size += AES_BLOCKSIZE; /* + IV */ |
624 | xhdr->len16_hi = size >> 8; | 640 | xhdr->len16_hi = size >> 8; |
625 | xhdr->len16_lo = size & 0xff; | 641 | xhdr->len16_lo = size & 0xff; |
626 | xwrite(tls->fd, xhdr, sizeof(*xhdr)); | 642 | dump_hex(">> %s\n", xhdr, sizeof(*xhdr) + size); |
627 | xwrite(tls->fd, tls->outbuf, size); | 643 | xwrite(tls->fd, xhdr, sizeof(*xhdr) + size); |
628 | dbg("wrote %u bytes\n", (int)sizeof(*xhdr) + size); | 644 | dbg("wrote %u bytes\n", (int)sizeof(*xhdr) + size); |
629 | //restore xhdr->len16_hi = ; | ||
630 | //restore xhdr->len16_lo = ; | ||
631 | } | 645 | } |
632 | } | 646 | } |
633 | 647 | ||
648 | static void xwrite_and_update_handshake_hash(tls_state_t *tls, unsigned size) | ||
649 | { | ||
650 | if (!tls->encrypt_on_write) { | ||
651 | uint8_t *buf = tls->outbuf + OUTBUF_PFX; | ||
652 | struct record_hdr *xhdr = (void*)(buf - sizeof(*xhdr)); | ||
653 | |||
654 | xhdr->type = RECORD_TYPE_HANDSHAKE; | ||
655 | xhdr->proto_maj = TLS_MAJ; | ||
656 | xhdr->proto_min = TLS_MIN; | ||
657 | xhdr->len16_hi = size >> 8; | ||
658 | xhdr->len16_lo = size & 0xff; | ||
659 | dump_hex(">> %s\n", xhdr, sizeof(*xhdr) + size); | ||
660 | xwrite(tls->fd, xhdr, sizeof(*xhdr) + size); | ||
661 | dbg("wrote %u bytes\n", (int)sizeof(*xhdr) + size); | ||
662 | /* Handshake hash does not include record headers */ | ||
663 | sha256_hash_dbg(">> sha256:%s", &tls->handshake_sha256_ctx, buf, size); | ||
664 | return; | ||
665 | } | ||
666 | xwrite_encrypted(tls, size, RECORD_TYPE_HANDSHAKE); | ||
667 | } | ||
668 | |||
634 | static int xread_tls_block(tls_state_t *tls) | 669 | static int xread_tls_block(tls_state_t *tls) |
635 | { | 670 | { |
636 | struct record_hdr *xhdr; | 671 | struct record_hdr *xhdr; |
@@ -668,7 +703,7 @@ static int xread_tls_block(tls_state_t *tls) | |||
668 | sz = target - sizeof(*xhdr); | 703 | sz = target - sizeof(*xhdr); |
669 | 704 | ||
670 | /* Needs to be decrypted? */ | 705 | /* Needs to be decrypted? */ |
671 | if (tls->min_encrypted_len_on_read) { | 706 | if (tls->min_encrypted_len_on_read > SHA256_OUTSIZE) { |
672 | psCipherContext_t ctx; | 707 | psCipherContext_t ctx; |
673 | uint8_t *p = tls->inbuf + sizeof(*xhdr); | 708 | uint8_t *p = tls->inbuf + sizeof(*xhdr); |
674 | int padding_len; | 709 | int padding_len; |
@@ -698,6 +733,10 @@ static int xread_tls_block(tls_state_t *tls) | |||
698 | /* Skip IV */ | 733 | /* Skip IV */ |
699 | memmove(tls->inbuf + 5, tls->inbuf + 5 + AES_BLOCKSIZE, sz); | 734 | memmove(tls->inbuf + 5, tls->inbuf + 5 + AES_BLOCKSIZE, sz); |
700 | } | 735 | } |
736 | } else { | ||
737 | /* if nonzero, then it's TLS_RSA_WITH_NULL_SHA256: drop MAC */ | ||
738 | /* else: no encryption yet on input, subtract zero = NOP */ | ||
739 | sz -= tls->min_encrypted_len_on_read; | ||
701 | } | 740 | } |
702 | 741 | ||
703 | /* RFC 5246 is not saying it explicitly, but sha256 hash | 742 | /* RFC 5246 is not saying it explicitly, but sha256 hash |
@@ -943,39 +982,24 @@ static int xread_tls_handshake_block(tls_state_t *tls, int min_len) | |||
943 | return len; | 982 | return len; |
944 | } | 983 | } |
945 | 984 | ||
946 | static void fill_handshake_record_hdr(struct record_hdr *xhdr, unsigned len) | 985 | static ALWAYS_INLINE void fill_handshake_record_hdr(void *buf, unsigned type, unsigned len) |
947 | { | 986 | { |
948 | struct handshake_hdr { | 987 | struct handshake_hdr { |
949 | struct record_hdr xhdr; | ||
950 | uint8_t type; | 988 | uint8_t type; |
951 | uint8_t len24_hi, len24_mid, len24_lo; | 989 | uint8_t len24_hi, len24_mid, len24_lo; |
952 | } *h = (void*)xhdr; | 990 | } *h = buf; |
953 | |||
954 | h->xhdr.type = RECORD_TYPE_HANDSHAKE; | ||
955 | h->xhdr.proto_maj = TLS_MAJ; | ||
956 | h->xhdr.proto_min = TLS_MIN; | ||
957 | len -= 5; | ||
958 | h->xhdr.len16_hi = len >> 8; | ||
959 | // can be optimized to do one store instead of four: | ||
960 | // uint32_t v = htonl(0x100*(RECORD_TYPE_HANDSHAKE + 0x100*(TLS_MAJ + 0x100*(TLS_MIN)))) | ||
961 | // | ((len >> 8) << 24); // little-endian specific, don't use in this form | ||
962 | // *(uint32_t *)xhdr = v; | ||
963 | |||
964 | h->xhdr.len16_lo = len & 0xff; | ||
965 | 991 | ||
966 | len -= 4; | 992 | len -= 4; |
993 | h->type = type; | ||
967 | h->len24_hi = len >> 16; | 994 | h->len24_hi = len >> 16; |
968 | h->len24_mid = len >> 8; | 995 | h->len24_mid = len >> 8; |
969 | h->len24_lo = len & 0xff; | 996 | h->len24_lo = len & 0xff; |
970 | |||
971 | memset(h + 1, 0, len); | ||
972 | } | 997 | } |
973 | 998 | ||
974 | //TODO: implement RFC 5746 (Renegotiation Indication Extension) - some servers will refuse to work with us otherwise | 999 | //TODO: implement RFC 5746 (Renegotiation Indication Extension) - some servers will refuse to work with us otherwise |
975 | static void send_client_hello(tls_state_t *tls) | 1000 | static void send_client_hello(tls_state_t *tls) |
976 | { | 1001 | { |
977 | struct client_hello { | 1002 | struct client_hello { |
978 | struct record_hdr xhdr; | ||
979 | uint8_t type; | 1003 | uint8_t type; |
980 | uint8_t len24_hi, len24_mid, len24_lo; | 1004 | uint8_t len24_hi, len24_mid, len24_lo; |
981 | uint8_t proto_maj, proto_min; | 1005 | uint8_t proto_maj, proto_min; |
@@ -987,25 +1011,25 @@ static void send_client_hello(tls_state_t *tls) | |||
987 | uint8_t comprtypes_len; | 1011 | uint8_t comprtypes_len; |
988 | uint8_t comprtypes[1]; /* actually variable */ | 1012 | uint8_t comprtypes[1]; /* actually variable */ |
989 | }; | 1013 | }; |
990 | struct client_hello record; | 1014 | struct client_hello *record = tls_get_outbuf(tls, sizeof(*record)); |
991 | 1015 | ||
992 | fill_handshake_record_hdr(&record.xhdr, sizeof(record)); | 1016 | fill_handshake_record_hdr(record, HANDSHAKE_CLIENT_HELLO, sizeof(*record)); |
993 | record.type = HANDSHAKE_CLIENT_HELLO; | 1017 | record->proto_maj = TLS_MAJ; /* the "requested" version of the protocol, */ |
994 | record.proto_maj = TLS_MAJ; /* the "requested" version of the protocol, */ | 1018 | record->proto_min = TLS_MIN; /* can be higher than one in record headers */ |
995 | record.proto_min = TLS_MIN; /* can be higher than one in record headers */ | 1019 | tls_get_random(record->rand32, sizeof(record->rand32)); |
996 | tls_get_random(record.rand32, sizeof(record.rand32)); | 1020 | memset(record->rand32, 0x11, sizeof(record->rand32)); |
997 | /* record.session_id_len = 0; - already is */ | 1021 | memcpy(tls->client_and_server_rand32, record->rand32, sizeof(record->rand32)); |
998 | /* record.cipherid_len16_hi = 0; */ | 1022 | record->session_id_len = 0; |
999 | record.cipherid_len16_lo = 2 * 1; | 1023 | record->cipherid_len16_hi = 0; |
1000 | record.cipherid[0] = CIPHER_ID >> 8; | 1024 | record->cipherid_len16_lo = 2 * 1; |
1001 | record.cipherid[1] = CIPHER_ID & 0xff; | 1025 | record->cipherid[0] = CIPHER_ID >> 8; |
1002 | record.comprtypes_len = 1; | 1026 | record->cipherid[1] = CIPHER_ID & 0xff; |
1003 | /* record.comprtypes[0] = 0; */ | 1027 | record->comprtypes_len = 1; |
1028 | record->comprtypes[0] = 0; | ||
1004 | 1029 | ||
1005 | //dbg (make it repeatable): memset(record.rand32, 0x11, sizeof(record.rand32)); | 1030 | //dbg (make it repeatable): memset(record.rand32, 0x11, sizeof(record.rand32)); |
1006 | dbg(">> CLIENT_HELLO\n"); | 1031 | dbg(">> CLIENT_HELLO\n"); |
1007 | xwrite_and_hash(tls, &record, sizeof(record)); | 1032 | xwrite_and_update_handshake_hash(tls, sizeof(*record)); |
1008 | memcpy(tls->client_and_server_rand32, record.rand32, sizeof(record.rand32)); | ||
1009 | } | 1033 | } |
1010 | 1034 | ||
1011 | static void get_server_hello(tls_state_t *tls) | 1035 | static void get_server_hello(tls_state_t *tls) |
@@ -1099,21 +1123,19 @@ static void get_server_cert(tls_state_t *tls) | |||
1099 | static void send_client_key_exchange(tls_state_t *tls) | 1123 | static void send_client_key_exchange(tls_state_t *tls) |
1100 | { | 1124 | { |
1101 | struct client_key_exchange { | 1125 | struct client_key_exchange { |
1102 | struct record_hdr xhdr; | ||
1103 | uint8_t type; | 1126 | uint8_t type; |
1104 | uint8_t len24_hi, len24_mid, len24_lo; | 1127 | uint8_t len24_hi, len24_mid, len24_lo; |
1105 | /* keylen16 exists for RSA (in TLS, not in SSL), but not for some other key types */ | 1128 | /* keylen16 exists for RSA (in TLS, not in SSL), but not for some other key types */ |
1106 | uint8_t keylen16_hi, keylen16_lo; | 1129 | uint8_t keylen16_hi, keylen16_lo; |
1107 | uint8_t key[4 * 1024]; // size?? | 1130 | uint8_t key[4 * 1024]; // size?? |
1108 | }; | 1131 | }; |
1109 | struct client_key_exchange record; | 1132 | //FIXME: better size estimate |
1133 | struct client_key_exchange *record = tls_get_outbuf(tls, sizeof(*record)); | ||
1110 | uint8_t rsa_premaster[SSL_HS_RSA_PREMASTER_SIZE]; | 1134 | uint8_t rsa_premaster[SSL_HS_RSA_PREMASTER_SIZE]; |
1111 | int len; | 1135 | int len; |
1112 | 1136 | ||
1113 | fill_handshake_record_hdr(&record.xhdr, sizeof(record) - sizeof(record.key)); | ||
1114 | record.type = HANDSHAKE_CLIENT_KEY_EXCHANGE; | ||
1115 | |||
1116 | tls_get_random(rsa_premaster, sizeof(rsa_premaster)); | 1137 | tls_get_random(rsa_premaster, sizeof(rsa_premaster)); |
1138 | memset(rsa_premaster, 0x44, sizeof(rsa_premaster)); | ||
1117 | // RFC 5246 | 1139 | // RFC 5246 |
1118 | // "Note: The version number in the PreMasterSecret is the version | 1140 | // "Note: The version number in the PreMasterSecret is the version |
1119 | // offered by the client in the ClientHello.client_version, not the | 1141 | // offered by the client in the ClientHello.client_version, not the |
@@ -1123,22 +1145,20 @@ static void send_client_key_exchange(tls_state_t *tls) | |||
1123 | len = psRsaEncryptPub(/*pool:*/ NULL, | 1145 | len = psRsaEncryptPub(/*pool:*/ NULL, |
1124 | /* psRsaKey_t* */ &tls->server_rsa_pub_key, | 1146 | /* psRsaKey_t* */ &tls->server_rsa_pub_key, |
1125 | rsa_premaster, /*inlen:*/ sizeof(rsa_premaster), | 1147 | rsa_premaster, /*inlen:*/ sizeof(rsa_premaster), |
1126 | record.key, sizeof(record.key), | 1148 | record->key, sizeof(record->key), |
1127 | data_param_ignored | 1149 | data_param_ignored |
1128 | ); | 1150 | ); |
1129 | /* length fields need fixing */ | 1151 | record->keylen16_hi = len >> 8; |
1130 | record.keylen16_hi = len >> 8; | 1152 | record->keylen16_lo = len & 0xff; |
1131 | record.keylen16_lo = len & 0xff; | ||
1132 | len += 2; | 1153 | len += 2; |
1133 | /* record.len24_hi = 0; - already is */ | 1154 | record->type = HANDSHAKE_CLIENT_KEY_EXCHANGE; |
1134 | record.len24_mid = len >> 8; | 1155 | record->len24_hi = 0; |
1135 | record.len24_lo = len & 0xff; | 1156 | record->len24_mid = len >> 8; |
1157 | record->len24_lo = len & 0xff; | ||
1136 | len += 4; | 1158 | len += 4; |
1137 | record.xhdr.len16_hi = len >> 8; | ||
1138 | record.xhdr.len16_lo = len & 0xff; | ||
1139 | 1159 | ||
1140 | dbg(">> CLIENT_KEY_EXCHANGE\n"); | 1160 | dbg(">> CLIENT_KEY_EXCHANGE\n"); |
1141 | xwrite_and_hash(tls, &record, sizeof(record.xhdr) + len); | 1161 | xwrite_and_update_handshake_hash(tls, len); |
1142 | 1162 | ||
1143 | // RFC 5246 | 1163 | // RFC 5246 |
1144 | // For all key exchange methods, the same algorithm is used to convert | 1164 | // For all key exchange methods, the same algorithm is used to convert |
@@ -1224,7 +1244,6 @@ static const uint8_t rec_CHANGE_CIPHER_SPEC[] = { | |||
1224 | 1244 | ||
1225 | static void send_change_cipher_spec(tls_state_t *tls) | 1245 | static void send_change_cipher_spec(tls_state_t *tls) |
1226 | { | 1246 | { |
1227 | /* Not "xwrite_and_hash": this is not a handshake message */ | ||
1228 | dbg(">> CHANGE_CIPHER_SPEC\n"); | 1247 | dbg(">> CHANGE_CIPHER_SPEC\n"); |
1229 | xwrite(tls->fd, rec_CHANGE_CIPHER_SPEC, sizeof(rec_CHANGE_CIPHER_SPEC)); | 1248 | xwrite(tls->fd, rec_CHANGE_CIPHER_SPEC, sizeof(rec_CHANGE_CIPHER_SPEC)); |
1230 | } | 1249 | } |
@@ -1269,19 +1288,17 @@ static void send_change_cipher_spec(tls_state_t *tls) | |||
1269 | static void send_client_finished(tls_state_t *tls) | 1288 | static void send_client_finished(tls_state_t *tls) |
1270 | { | 1289 | { |
1271 | struct finished { | 1290 | struct finished { |
1272 | struct record_hdr xhdr; | ||
1273 | uint8_t type; | 1291 | uint8_t type; |
1274 | uint8_t len24_hi, len24_mid, len24_lo; | 1292 | uint8_t len24_hi, len24_mid, len24_lo; |
1275 | uint8_t prf_result[12]; | 1293 | uint8_t prf_result[12]; |
1276 | }; | 1294 | }; |
1277 | struct finished record; | 1295 | struct finished *record = tls_get_outbuf(tls, sizeof(*record)); |
1278 | uint8_t handshake_hash[SHA256_OUTSIZE]; | 1296 | uint8_t handshake_hash[SHA256_OUTSIZE]; |
1279 | 1297 | ||
1280 | fill_handshake_record_hdr(&record.xhdr, sizeof(record)); | 1298 | fill_handshake_record_hdr(record, HANDSHAKE_FINISHED, sizeof(*record)); |
1281 | record.type = HANDSHAKE_FINISHED; | ||
1282 | 1299 | ||
1283 | sha256_peek(&tls->handshake_sha256_ctx, handshake_hash); | 1300 | sha256_peek(&tls->handshake_sha256_ctx, handshake_hash); |
1284 | prf_hmac_sha256(record.prf_result, sizeof(record.prf_result), | 1301 | prf_hmac_sha256(record->prf_result, sizeof(record->prf_result), |
1285 | tls->master_secret, sizeof(tls->master_secret), | 1302 | tls->master_secret, sizeof(tls->master_secret), |
1286 | "client finished", | 1303 | "client finished", |
1287 | handshake_hash, sizeof(handshake_hash) | 1304 | handshake_hash, sizeof(handshake_hash) |
@@ -1289,13 +1306,10 @@ static void send_client_finished(tls_state_t *tls) | |||
1289 | dump_hex("from secret: %s\n", tls->master_secret, sizeof(tls->master_secret)); | 1306 | dump_hex("from secret: %s\n", tls->master_secret, sizeof(tls->master_secret)); |
1290 | dump_hex("from labelSeed: %s", "client finished", sizeof("client finished")-1); | 1307 | dump_hex("from labelSeed: %s", "client finished", sizeof("client finished")-1); |
1291 | dump_hex("%s\n", handshake_hash, sizeof(handshake_hash)); | 1308 | dump_hex("%s\n", handshake_hash, sizeof(handshake_hash)); |
1292 | dump_hex("=> digest: %s\n", record.prf_result, sizeof(record.prf_result)); | 1309 | dump_hex("=> digest: %s\n", record->prf_result, sizeof(record->prf_result)); |
1293 | |||
1294 | //(1) TODO: well, this should be encrypted on send, really. | ||
1295 | //(2) do we really need to also hash it? | ||
1296 | 1310 | ||
1297 | dbg(">> FINISHED\n"); | 1311 | dbg(">> FINISHED\n"); |
1298 | xwrite_and_hash(tls, &record, sizeof(record)); | 1312 | xwrite_encrypted(tls, sizeof(*record), RECORD_TYPE_HANDSHAKE); |
1299 | } | 1313 | } |
1300 | 1314 | ||
1301 | static void tls_handshake(tls_state_t *tls) | 1315 | static void tls_handshake(tls_state_t *tls) |
@@ -1376,8 +1390,11 @@ static void tls_handshake(tls_state_t *tls) | |||
1376 | if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0) | 1390 | if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0) |
1377 | tls_error_die(tls); | 1391 | tls_error_die(tls); |
1378 | dbg("<< CHANGE_CIPHER_SPEC\n"); | 1392 | dbg("<< CHANGE_CIPHER_SPEC\n"); |
1379 | /* all incoming packets now should be encrypted and have IV + MAC + padding */ | 1393 | if (CIPHER_ID == TLS_RSA_WITH_NULL_SHA256) |
1380 | tls->min_encrypted_len_on_read = AES_BLOCKSIZE + SHA256_OUTSIZE + AES_BLOCKSIZE; | 1394 | tls->min_encrypted_len_on_read = SHA256_OUTSIZE; |
1395 | else | ||
1396 | /* all incoming packets now should be encrypted and have IV + MAC + padding */ | ||
1397 | tls->min_encrypted_len_on_read = AES_BLOCKSIZE + SHA256_OUTSIZE + AES_BLOCKSIZE; | ||
1381 | 1398 | ||
1382 | /* Get (encrypted) FINISHED from the server */ | 1399 | /* Get (encrypted) FINISHED from the server */ |
1383 | len = xread_tls_block(tls); | 1400 | len = xread_tls_block(tls); |
@@ -1387,6 +1404,12 @@ static void tls_handshake(tls_state_t *tls) | |||
1387 | /* application data can be sent/received */ | 1404 | /* application data can be sent/received */ |
1388 | } | 1405 | } |
1389 | 1406 | ||
1407 | static void tls_xwrite(tls_state_t *tls, int len) | ||
1408 | { | ||
1409 | dbg(">> DATA\n"); | ||
1410 | xwrite_encrypted(tls, len, RECORD_TYPE_APPLICATION_DATA); | ||
1411 | } | ||
1412 | |||
1390 | // To run a test server using openssl: | 1413 | // To run a test server using openssl: |
1391 | // openssl req -x509 -newkey rsa:$((4096/4*3)) -keyout key.pem -out server.pem -nodes -days 99999 -subj '/CN=localhost' | 1414 | // openssl req -x509 -newkey rsa:$((4096/4*3)) -keyout key.pem -out server.pem -nodes -days 99999 -subj '/CN=localhost' |
1392 | // openssl s_server -key key.pem -cert server.pem -debug -tls1_2 -no_tls1 -no_tls1_1 | 1415 | // openssl s_server -key key.pem -cert server.pem -debug -tls1_2 -no_tls1 -no_tls1_1 |
@@ -1400,8 +1423,8 @@ int tls_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
1400 | int tls_main(int argc UNUSED_PARAM, char **argv) | 1423 | int tls_main(int argc UNUSED_PARAM, char **argv) |
1401 | { | 1424 | { |
1402 | tls_state_t *tls; | 1425 | tls_state_t *tls; |
1403 | len_and_sockaddr *lsa; | 1426 | fd_set readfds, testfds; |
1404 | int fd; | 1427 | int cfd; |
1405 | 1428 | ||
1406 | // INIT_G(); | 1429 | // INIT_G(); |
1407 | // getopt32(argv, "myopts") | 1430 | // getopt32(argv, "myopts") |
@@ -1409,13 +1432,48 @@ int tls_main(int argc UNUSED_PARAM, char **argv) | |||
1409 | if (!argv[1]) | 1432 | if (!argv[1]) |
1410 | bb_show_usage(); | 1433 | bb_show_usage(); |
1411 | 1434 | ||
1412 | lsa = xhost2sockaddr(argv[1], 443); | 1435 | cfd = create_and_connect_stream_or_die(argv[1], 443); |
1413 | fd = xconnect_stream(lsa); | ||
1414 | 1436 | ||
1415 | tls = new_tls_state(); | 1437 | tls = new_tls_state(); |
1416 | tls->fd = fd; | 1438 | tls->fd = cfd; |
1417 | tls_handshake(tls); | 1439 | tls_handshake(tls); |
1418 | 1440 | ||
1441 | /* Select loop copying stdin to cfd, and cfd to stdout */ | ||
1442 | FD_ZERO(&readfds); | ||
1443 | FD_SET(cfd, &readfds); | ||
1444 | FD_SET(STDIN_FILENO, &readfds); | ||
1445 | |||
1446 | #define iobuf bb_common_bufsiz1 | ||
1447 | setup_common_bufsiz(); | ||
1448 | for (;;) { | ||
1449 | int nread; | ||
1450 | |||
1451 | testfds = readfds; | ||
1452 | |||
1453 | if (select(cfd + 1, &testfds, NULL, NULL, NULL) < 0) | ||
1454 | bb_perror_msg_and_die("select"); | ||
1455 | |||
1456 | if (FD_ISSET(STDIN_FILENO, &testfds)) { | ||
1457 | void *buf = tls_get_outbuf(tls, COMMON_BUFSIZE); | ||
1458 | nread = safe_read(STDIN_FILENO, buf, COMMON_BUFSIZE); | ||
1459 | if (nread < 1) { | ||
1460 | //&& errno != EAGAIN | ||
1461 | /* Close outgoing half-connection so they get EOF, | ||
1462 | * but leave incoming alone so we can see response */ | ||
1463 | // shutdown(cfd, SHUT_WR); | ||
1464 | FD_CLR(STDIN_FILENO, &readfds); | ||
1465 | } | ||
1466 | tls_xwrite(tls, nread); | ||
1467 | } | ||
1468 | if (FD_ISSET(cfd, &testfds)) { | ||
1469 | nread = xread_tls_block(tls); | ||
1470 | if (nread < 1) | ||
1471 | //if eof, just close stdout, but not exit! | ||
1472 | return EXIT_SUCCESS; | ||
1473 | xwrite(STDOUT_FILENO, tls->inbuf + 5, nread); | ||
1474 | } | ||
1475 | } | ||
1476 | |||
1419 | return EXIT_SUCCESS; | 1477 | return EXIT_SUCCESS; |
1420 | } | 1478 | } |
1421 | /* Unencryped SHA256 example: | 1479 | /* Unencryped SHA256 example: |