aboutsummaryrefslogtreecommitdiff
path: root/networking/tls.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-01-16 04:25:01 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2017-01-16 04:25:01 +0100
commit936e83e694b3225dbcc14fc99ca8053e2518ab35 (patch)
tree337ba121f89a9b2c5ce56d932470e43f56605766 /networking/tls.c
parent6c73aaff38819533c55aecc53487d53521915e91 (diff)
downloadbusybox-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.c256
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
199static 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
193static unsigned get24be(const uint8_t *p) 207static 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
511enum {
512 SHA256_INSIZE = 64,
513 SHA256_OUTSIZE = 32,
514};
515
516static 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.
533static 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
555static 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.
622static 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
594static void get_server_cert(tls_state_t *tls) 761static 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
671static void send_change_cipher_spec(tls_state_t *tls) 854static 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
680static void send_client_finished(tls_state_t *tls) 864static 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
752static void get_change_cipher_spec(tls_state_t *tls) 938static 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
834int tls_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1024int tls_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
835int tls_main(int argc UNUSED_PARAM, char **argv) 1025int tls_main(int argc UNUSED_PARAM, char **argv)
836{ 1026{