diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-01-16 04:25:01 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-01-16 04:25:01 +0100 |
commit | 936e83e694b3225dbcc14fc99ca8053e2518ab35 (patch) | |
tree | 337ba121f89a9b2c5ce56d932470e43f56605766 /networking/tls.c | |
parent | 6c73aaff38819533c55aecc53487d53521915e91 (diff) | |
download | busybox-w32-936e83e694b3225dbcc14fc99ca8053e2518ab35.tar.gz busybox-w32-936e83e694b3225dbcc14fc99ca8053e2518ab35.tar.bz2 busybox-w32-936e83e694b3225dbcc14fc99ca8053e2518ab35.zip |
tls: add sha256 hmac and prf code
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking/tls.c')
-rw-r--r-- | networking/tls.c | 256 |
1 files changed, 223 insertions, 33 deletions
diff --git a/networking/tls.c b/networking/tls.c index 44c9da195..9bc75f824 100644 --- a/networking/tls.c +++ b/networking/tls.c | |||
@@ -146,6 +146,11 @@ typedef struct tls_state { | |||
146 | 146 | ||
147 | psRsaKey_t server_rsa_pub_key; | 147 | psRsaKey_t server_rsa_pub_key; |
148 | 148 | ||
149 | sha256_ctx_t handshake_sha256_ctx; | ||
150 | |||
151 | uint8_t client_and_server_rand32[2 * 32]; | ||
152 | uint8_t master_secret[48]; | ||
153 | |||
149 | // RFC 5246 | 154 | // RFC 5246 |
150 | // |6.2.1. Fragmentation | 155 | // |6.2.1. Fragmentation |
151 | // | The record layer fragments information blocks into TLSPlaintext | 156 | // | The record layer fragments information blocks into TLSPlaintext |
@@ -187,9 +192,18 @@ tls_state_t *new_tls_state(void) | |||
187 | { | 192 | { |
188 | tls_state_t *tls = xzalloc(sizeof(*tls)); | 193 | tls_state_t *tls = xzalloc(sizeof(*tls)); |
189 | tls->fd = -1; | 194 | tls->fd = -1; |
195 | sha256_begin(&tls->handshake_sha256_ctx); | ||
190 | return tls; | 196 | return tls; |
191 | } | 197 | } |
192 | 198 | ||
199 | static void xwrite_and_hash(tls_state_t *tls, const void *buf, unsigned size) | ||
200 | { | ||
201 | xwrite(tls->fd, buf, size); | ||
202 | /* hash does not include record headers */ | ||
203 | if (size > 5) | ||
204 | sha256_hash(&tls->handshake_sha256_ctx, (uint8_t*)buf + 5, size - 5); | ||
205 | } | ||
206 | |||
193 | static unsigned get24be(const uint8_t *p) | 207 | static unsigned get24be(const uint8_t *p) |
194 | { | 208 | { |
195 | return 0x100*(0x100*p[0] + p[1]) + p[2]; | 209 | return 0x100*(0x100*p[0] + p[1]) + p[2]; |
@@ -494,6 +508,156 @@ static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len) | |||
494 | dbg("server_rsa_pub_key.size:%d\n", tls->server_rsa_pub_key.size); | 508 | dbg("server_rsa_pub_key.size:%d\n", tls->server_rsa_pub_key.size); |
495 | } | 509 | } |
496 | 510 | ||
511 | enum { | ||
512 | SHA256_INSIZE = 64, | ||
513 | SHA256_OUTSIZE = 32, | ||
514 | }; | ||
515 | |||
516 | static void hash_sha256(uint8_t out[SHA256_OUTSIZE], const void *data, unsigned size) | ||
517 | { | ||
518 | sha256_ctx_t ctx; | ||
519 | sha256_begin(&ctx); | ||
520 | sha256_hash(&ctx, data, size); | ||
521 | sha256_end(&ctx, out); | ||
522 | } | ||
523 | |||
524 | // RFC 2104: HMAC(key, text) based on a hash H (say, sha256) is: | ||
525 | // ipad = [0x36 x INSIZE] | ||
526 | // opad = [0x5c x INSIZE] | ||
527 | // HMAC(key, text) = H((key XOR opad) + H((key XOR ipad) + text)) | ||
528 | // | ||
529 | // H(key XOR opad) and H(key XOR ipad) can be precomputed | ||
530 | // if we often need HMAC hmac with the same key. | ||
531 | // | ||
532 | // text is often given in disjoint pieces. | ||
533 | static void hmac_sha256_precomputed_v(uint8_t out[SHA256_OUTSIZE], | ||
534 | sha256_ctx_t *hashed_key_xor_ipad, | ||
535 | sha256_ctx_t *hashed_key_xor_opad, | ||
536 | va_list va) | ||
537 | { | ||
538 | uint8_t *text; | ||
539 | |||
540 | /* hashed_key_xor_ipad contains unclosed "H((key XOR ipad) +" state */ | ||
541 | /* hashed_key_xor_opad contains unclosed "H((key XOR opad) +" state */ | ||
542 | |||
543 | /* calculate out = H((key XOR ipad) + text) */ | ||
544 | while ((text = va_arg(va, uint8_t*)) != NULL) { | ||
545 | unsigned text_size = va_arg(va, unsigned); | ||
546 | sha256_hash(hashed_key_xor_ipad, text, text_size); | ||
547 | } | ||
548 | sha256_end(hashed_key_xor_ipad, out); | ||
549 | |||
550 | /* out = H((key XOR opad) + out) */ | ||
551 | sha256_hash(hashed_key_xor_opad, out, SHA256_OUTSIZE); | ||
552 | sha256_end(hashed_key_xor_opad, out); | ||
553 | } | ||
554 | |||
555 | static void hmac_sha256(uint8_t out[SHA256_OUTSIZE], uint8_t *key, unsigned key_size, ...) | ||
556 | { | ||
557 | sha256_ctx_t hashed_key_xor_ipad; | ||
558 | sha256_ctx_t hashed_key_xor_opad; | ||
559 | uint8_t key_xor_ipad[SHA256_INSIZE]; | ||
560 | uint8_t key_xor_opad[SHA256_INSIZE]; | ||
561 | uint8_t tempkey[SHA256_OUTSIZE]; | ||
562 | va_list va; | ||
563 | int i; | ||
564 | |||
565 | va_start(va, key_size); | ||
566 | |||
567 | // "The authentication key can be of any length up to INSIZE, the | ||
568 | // block length of the hash function. Applications that use keys longer | ||
569 | // than INSIZE bytes will first hash the key using H and then use the | ||
570 | // resultant OUTSIZE byte string as the actual key to HMAC." | ||
571 | if (key_size > SHA256_INSIZE) { | ||
572 | hash_sha256(tempkey, key, key_size); | ||
573 | key = tempkey; | ||
574 | key_size = SHA256_OUTSIZE; | ||
575 | } | ||
576 | |||
577 | for (i = 0; i < key_size; i++) { | ||
578 | key_xor_ipad[i] = key[i] ^ 0x36; | ||
579 | key_xor_opad[i] = key[i] ^ 0x5c; | ||
580 | } | ||
581 | for (; i < SHA256_INSIZE; i++) { | ||
582 | key_xor_ipad[i] = 0x36; | ||
583 | key_xor_opad[i] = 0x5c; | ||
584 | } | ||
585 | sha256_begin(&hashed_key_xor_ipad); | ||
586 | sha256_hash(&hashed_key_xor_ipad, key_xor_ipad, SHA256_INSIZE); | ||
587 | sha256_begin(&hashed_key_xor_opad); | ||
588 | sha256_hash(&hashed_key_xor_opad, key_xor_opad, SHA256_INSIZE); | ||
589 | |||
590 | hmac_sha256_precomputed_v(out, &hashed_key_xor_ipad, &hashed_key_xor_opad, va); | ||
591 | va_end(va); | ||
592 | } | ||
593 | |||
594 | // RFC 5246: | ||
595 | // 5. HMAC and the Pseudorandom Function | ||
596 | //... | ||
597 | // In this section, we define one PRF, based on HMAC. This PRF with the | ||
598 | // SHA-256 hash function is used for all cipher suites defined in this | ||
599 | // document and in TLS documents published prior to this document when | ||
600 | // TLS 1.2 is negotiated. | ||
601 | //... | ||
602 | // P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + | ||
603 | // HMAC_hash(secret, A(2) + seed) + | ||
604 | // HMAC_hash(secret, A(3) + seed) + ... | ||
605 | // where + indicates concatenation. | ||
606 | // A() is defined as: | ||
607 | // A(0) = seed | ||
608 | // A(1) = HMAC_hash(secret, A(0)) = HMAC_hash(secret, seed) | ||
609 | // A(i) = HMAC_hash(secret, A(i-1)) | ||
610 | // P_hash can be iterated as many times as necessary to produce the | ||
611 | // required quantity of data. For example, if P_SHA256 is being used to | ||
612 | // create 80 bytes of data, it will have to be iterated three times | ||
613 | // (through A(3)), creating 96 bytes of output data; the last 16 bytes | ||
614 | // of the final iteration will then be discarded, leaving 80 bytes of | ||
615 | // output data. | ||
616 | // | ||
617 | // TLS's PRF is created by applying P_hash to the secret as: | ||
618 | // | ||
619 | // PRF(secret, label, seed) = P_<hash>(secret, label + seed) | ||
620 | // | ||
621 | // The label is an ASCII string. | ||
622 | static void tls_prf_hmac_sha256( | ||
623 | uint8_t *outbuf, unsigned outbuf_size, | ||
624 | uint8_t *secret, unsigned secret_size, | ||
625 | const char *label, | ||
626 | uint8_t *seed, unsigned seed_size) | ||
627 | { | ||
628 | uint8_t a[SHA256_OUTSIZE]; | ||
629 | uint8_t *out_p = outbuf; | ||
630 | unsigned label_size = strlen(label); | ||
631 | |||
632 | /* In P_hash() calculation, "seed" is "label + seed": */ | ||
633 | #define SEED label, label_size, seed, seed_size | ||
634 | #define SECRET secret, secret_size | ||
635 | #define A a, (int)(sizeof(a)) | ||
636 | |||
637 | /* A(1) = HMAC_hash(secret, seed) */ | ||
638 | hmac_sha256(a, SECRET, SEED, NULL); | ||
639 | |||
640 | for(;;) { | ||
641 | /* HMAC_hash(secret, A(1) + seed) */ | ||
642 | if (outbuf_size <= SHA256_OUTSIZE) { | ||
643 | /* Last, possibly incomplete, block */ | ||
644 | /* (use a[] as temp buffer) */ | ||
645 | hmac_sha256(a, SECRET, A, SEED, NULL); | ||
646 | memcpy(out_p, a, outbuf_size); | ||
647 | return; | ||
648 | } | ||
649 | /* Not last block. Store directly to result buffer */ | ||
650 | hmac_sha256(out_p, SECRET, A, SEED, NULL); | ||
651 | out_p += SHA256_OUTSIZE; | ||
652 | outbuf_size -= SHA256_OUTSIZE; | ||
653 | /* A(2) = HMAC_hash(secret, A(1)) */ | ||
654 | hmac_sha256(a, SECRET, A, NULL); | ||
655 | } | ||
656 | #undef A | ||
657 | #undef SECRET | ||
658 | #undef SEED | ||
659 | } | ||
660 | |||
497 | /* | 661 | /* |
498 | * TLS Handshake routines | 662 | * TLS Handshake routines |
499 | */ | 663 | */ |
@@ -535,7 +699,9 @@ static void send_client_hello(tls_state_t *tls) | |||
535 | hello.comprtypes_len = 1; | 699 | hello.comprtypes_len = 1; |
536 | //hello.comprtypes[0] = 0; | 700 | //hello.comprtypes[0] = 0; |
537 | 701 | ||
538 | xwrite(tls->fd, &hello, sizeof(hello)); | 702 | xwrite_and_hash(tls, &hello, sizeof(hello)); |
703 | memcpy(tls->client_and_server_rand32, hello.rand32, sizeof(hello.rand32)); | ||
704 | |||
539 | #if 0 /* dump */ | 705 | #if 0 /* dump */ |
540 | for (;;) { | 706 | for (;;) { |
541 | uint8_t buf[16*1024]; | 707 | uint8_t buf[16*1024]; |
@@ -589,6 +755,7 @@ static void get_server_hello(tls_state_t *tls) | |||
589 | tls_error_die(tls); | 755 | tls_error_die(tls); |
590 | } | 756 | } |
591 | dbg("got SERVER_HELLO\n"); | 757 | dbg("got SERVER_HELLO\n"); |
758 | memcpy(tls->client_and_server_rand32 + 32, hp->rand32, sizeof(hp->rand32)); | ||
592 | } | 759 | } |
593 | 760 | ||
594 | static void get_server_cert(tls_state_t *tls) | 761 | static void get_server_cert(tls_state_t *tls) |
@@ -665,7 +832,23 @@ static void send_client_key_exchange(tls_state_t *tls) | |||
665 | data_param_ignored | 832 | data_param_ignored |
666 | ); | 833 | ); |
667 | 834 | ||
668 | xwrite(tls->fd, &record, sizeof(record)); | 835 | xwrite_and_hash(tls, &record, sizeof(record)); |
836 | |||
837 | // RFC 5246 | ||
838 | // For all key exchange methods, the same algorithm is used to convert | ||
839 | // the pre_master_secret into the master_secret. The pre_master_secret | ||
840 | // should be deleted from memory once the master_secret has been | ||
841 | // computed. | ||
842 | // master_secret = PRF(pre_master_secret, "master secret", | ||
843 | // ClientHello.random + ServerHello.random) | ||
844 | // [0..47]; | ||
845 | // The master secret is always exactly 48 bytes in length. The length | ||
846 | // of the premaster secret will vary depending on key exchange method. | ||
847 | tls_prf_hmac_sha256(tls->master_secret, sizeof(tls->master_secret), | ||
848 | rsa_premaster, sizeof(rsa_premaster), | ||
849 | "master secret", | ||
850 | tls->client_and_server_rand32, sizeof(tls->client_and_server_rand32) | ||
851 | ); | ||
669 | } | 852 | } |
670 | 853 | ||
671 | static void send_change_cipher_spec(tls_state_t *tls) | 854 | static void send_change_cipher_spec(tls_state_t *tls) |
@@ -674,42 +857,12 @@ static void send_change_cipher_spec(tls_state_t *tls) | |||
674 | RECORD_TYPE_CHANGE_CIPHER_SPEC, TLS_MAJ, TLS_MIN, 00, 01, | 857 | RECORD_TYPE_CHANGE_CIPHER_SPEC, TLS_MAJ, TLS_MIN, 00, 01, |
675 | 01 | 858 | 01 |
676 | }; | 859 | }; |
860 | /* Not "xwrite_and_hash": this is not a handshake message */ | ||
677 | xwrite(tls->fd, rec, sizeof(rec)); | 861 | xwrite(tls->fd, rec, sizeof(rec)); |
678 | } | 862 | } |
679 | 863 | ||
680 | static void send_client_finished(tls_state_t *tls) | 864 | static void send_client_finished(tls_state_t *tls) |
681 | { | 865 | { |
682 | // RFC 5246 on pseudorandom function (PRF): | ||
683 | // | ||
684 | // 5. HMAC and the Pseudorandom Function | ||
685 | //... | ||
686 | // In this section, we define one PRF, based on HMAC. This PRF with the | ||
687 | // SHA-256 hash function is used for all cipher suites defined in this | ||
688 | // document and in TLS documents published prior to this document when | ||
689 | // TLS 1.2 is negotiated. | ||
690 | //... | ||
691 | // P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + | ||
692 | // HMAC_hash(secret, A(2) + seed) + | ||
693 | // HMAC_hash(secret, A(3) + seed) + ... | ||
694 | // where + indicates concatenation. | ||
695 | // A() is defined as: | ||
696 | // A(0) = seed | ||
697 | // A(i) = HMAC_hash(secret, A(i-1)) | ||
698 | // P_hash can be iterated as many times as necessary to produce the | ||
699 | // required quantity of data. For example, if P_SHA256 is being used to | ||
700 | // create 80 bytes of data, it will have to be iterated three times | ||
701 | // (through A(3)), creating 96 bytes of output data; the last 16 bytes | ||
702 | // of the final iteration will then be discarded, leaving 80 bytes of | ||
703 | // output data. | ||
704 | // | ||
705 | // TLS's PRF is created by applying P_hash to the secret as: | ||
706 | // | ||
707 | // PRF(secret, label, seed) = P_<hash>(secret, label + seed) | ||
708 | // | ||
709 | // The label is an ASCII string. | ||
710 | |||
711 | tls->fd = 0; | ||
712 | |||
713 | // 7.4.9. Finished | 866 | // 7.4.9. Finished |
714 | // A Finished message is always sent immediately after a change | 867 | // A Finished message is always sent immediately after a change |
715 | // cipher spec message to verify that the key exchange and | 868 | // cipher spec message to verify that the key exchange and |
@@ -747,6 +900,39 @@ static void send_client_finished(tls_state_t *tls) | |||
747 | // suite. Any cipher suite which does not explicitly specify | 900 | // suite. Any cipher suite which does not explicitly specify |
748 | // verify_data_length has a verify_data_length equal to 12. This | 901 | // verify_data_length has a verify_data_length equal to 12. This |
749 | // includes all existing cipher suites. | 902 | // includes all existing cipher suites. |
903 | struct client_finished { | ||
904 | struct record_hdr xhdr; | ||
905 | uint8_t type; | ||
906 | uint8_t len24_hi, len24_mid, len24_lo; | ||
907 | uint8_t prf_result[12]; | ||
908 | }; | ||
909 | struct client_finished record; | ||
910 | uint8_t handshake_hash[SHA256_OUTSIZE]; | ||
911 | sha256_ctx_t ctx; | ||
912 | |||
913 | memset(&record, 0, sizeof(record)); | ||
914 | record.xhdr.type = RECORD_TYPE_HANDSHAKE; | ||
915 | record.xhdr.proto_maj = TLS_MAJ; | ||
916 | record.xhdr.proto_min = TLS_MIN; | ||
917 | record.xhdr.len16_hi = (sizeof(record) - sizeof(record.xhdr)) >> 8; | ||
918 | record.xhdr.len16_lo = (sizeof(record) - sizeof(record.xhdr)) & 0xff; | ||
919 | record.type = HANDSHAKE_FINISHED; | ||
920 | //record.len24_hi = 0; | ||
921 | record.len24_mid = (sizeof(record) - sizeof(record.xhdr) - 4) >> 8; | ||
922 | record.len24_lo = (sizeof(record) - sizeof(record.xhdr) - 4) & 0xff; | ||
923 | //FIXME ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this code is repeatable | ||
924 | |||
925 | ctx = tls->handshake_sha256_ctx; /* struct copy */ | ||
926 | sha256_end(&ctx, handshake_hash); | ||
927 | tls_prf_hmac_sha256(record.prf_result, sizeof(record.prf_result), | ||
928 | tls->master_secret, sizeof(tls->master_secret), | ||
929 | "client finished", | ||
930 | handshake_hash, sizeof(handshake_hash) | ||
931 | ); | ||
932 | |||
933 | //(1) TODO: well, this should be encrypted on send, really. | ||
934 | //(2) do we really need to also hash it? | ||
935 | xwrite_and_hash(tls, &record, sizeof(record)); | ||
750 | } | 936 | } |
751 | 937 | ||
752 | static void get_change_cipher_spec(tls_state_t *tls) | 938 | static void get_change_cipher_spec(tls_state_t *tls) |
@@ -831,6 +1017,10 @@ static void tls_handshake(tls_state_t *tls) | |||
831 | } | 1017 | } |
832 | } | 1018 | } |
833 | 1019 | ||
1020 | // To run a test server using openssl: | ||
1021 | // openssl s_server -key key.pem -cert server.pem -debug -tls1_2 -no_tls1 -no_tls1_1 | ||
1022 | // openssl req -x509 -newkey rsa:$((4096/4*3)) -keyout key.pem -out server.pem -nodes -days 99999 -subj '/CN=localhost' | ||
1023 | |||
834 | int tls_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1024 | int tls_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
835 | int tls_main(int argc UNUSED_PARAM, char **argv) | 1025 | int tls_main(int argc UNUSED_PARAM, char **argv) |
836 | { | 1026 | { |