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: |
