diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-01-23 16:12:17 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-01-23 16:12:17 +0100 |
commit | b5bf1913d31512d1c5f4c9656dc96e6b8dcd92ba (patch) | |
tree | 2739d19dc6c99f73d84b25a616928c5cb36281ce /networking/tls.c | |
parent | 9492da7e63deae898d7bf924be5790c7fab1a4fb (diff) | |
download | busybox-w32-b5bf1913d31512d1c5f4c9656dc96e6b8dcd92ba.tar.gz busybox-w32-b5bf1913d31512d1c5f4c9656dc96e6b8dcd92ba.tar.bz2 busybox-w32-b5bf1913d31512d1c5f4c9656dc96e6b8dcd92ba.zip |
tls: send EMPTY_RENEGOTIATION_INFO_SCSV in our client hello
Hoped this can make cdn.kernel.org to like us more. Nope.
While at it, made error reporting more useful.
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking/tls.c')
-rw-r--r-- | networking/tls.c | 112 |
1 files changed, 86 insertions, 26 deletions
diff --git a/networking/tls.c b/networking/tls.c index 89f2ec603..4456c7d26 100644 --- a/networking/tls.c +++ b/networking/tls.c | |||
@@ -22,6 +22,16 @@ | |||
22 | #define TLS_DEBUG_HASH 0 | 22 | #define TLS_DEBUG_HASH 0 |
23 | #define TLS_DEBUG_DER 0 | 23 | #define TLS_DEBUG_DER 0 |
24 | #define TLS_DEBUG_FIXED_SECRETS 0 | 24 | #define TLS_DEBUG_FIXED_SECRETS 0 |
25 | #if 0 | ||
26 | # define dump_raw_out(...) dump_hex(__VA_ARGS__) | ||
27 | #else | ||
28 | # define dump_raw_out(...) ((void)0) | ||
29 | #endif | ||
30 | #if 0 | ||
31 | # define dump_raw_in(...) dump_hex(__VA_ARGS__) | ||
32 | #else | ||
33 | # define dump_raw_in(...) ((void)0) | ||
34 | #endif | ||
25 | 35 | ||
26 | #if TLS_DEBUG | 36 | #if TLS_DEBUG |
27 | # define dbg(...) fprintf(stderr, __VA_ARGS__) | 37 | # define dbg(...) fprintf(stderr, __VA_ARGS__) |
@@ -35,18 +45,6 @@ | |||
35 | # define dbg_der(...) ((void)0) | 45 | # define dbg_der(...) ((void)0) |
36 | #endif | 46 | #endif |
37 | 47 | ||
38 | #if 0 | ||
39 | # define dump_raw_out(...) dump_hex(__VA_ARGS__) | ||
40 | #else | ||
41 | # define dump_raw_out(...) ((void)0) | ||
42 | #endif | ||
43 | |||
44 | #if 0 | ||
45 | # define dump_raw_in(...) dump_hex(__VA_ARGS__) | ||
46 | #else | ||
47 | # define dump_raw_in(...) ((void)0) | ||
48 | #endif | ||
49 | |||
50 | #define RECORD_TYPE_CHANGE_CIPHER_SPEC 20 | 48 | #define RECORD_TYPE_CHANGE_CIPHER_SPEC 20 |
51 | #define RECORD_TYPE_ALERT 21 | 49 | #define RECORD_TYPE_ALERT 21 |
52 | #define RECORD_TYPE_HANDSHAKE 22 | 50 | #define RECORD_TYPE_HANDSHAKE 22 |
@@ -154,8 +152,18 @@ | |||
154 | // works against "openssl s_server -cipher NULL" | 152 | // works against "openssl s_server -cipher NULL" |
155 | // and against wolfssl-3.9.10-stable/examples/server/server.c: | 153 | // and against wolfssl-3.9.10-stable/examples/server/server.c: |
156 | //#define CIPHER_ID TLS_RSA_WITH_NULL_SHA256 // for testing (does everything except encrypting) | 154 | //#define CIPHER_ID TLS_RSA_WITH_NULL_SHA256 // for testing (does everything except encrypting) |
155 | |||
157 | // works against wolfssl-3.9.10-stable/examples/server/server.c | 156 | // works against wolfssl-3.9.10-stable/examples/server/server.c |
158 | #define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // ok, no SERVER_KEY_EXCHANGE | 157 | // works for kernel.org |
158 | // does not work for cdn.kernel.org (e.g. downloading an actual tarball, not a web page) | ||
159 | // getting alert 40 "handshake failure" at once | ||
160 | // with GNU Wget 1.18, they agree on TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xC02F) cipher | ||
161 | // fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES256-SHA256 | ||
162 | // fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES256-GCM-SHA384 | ||
163 | // fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-SHA256 | ||
164 | // ok: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-GCM-SHA256 | ||
165 | // ok: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-SHA | ||
166 | #define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // no SERVER_KEY_EXCHANGE from peer | ||
159 | 167 | ||
160 | enum { | 168 | enum { |
161 | RSA_PREMASTER_SIZE = 48, | 169 | RSA_PREMASTER_SIZE = 48, |
@@ -445,6 +453,18 @@ static void prf_hmac_sha256( | |||
445 | #undef SEED | 453 | #undef SEED |
446 | } | 454 | } |
447 | 455 | ||
456 | static void bad_record_die(tls_state_t *tls, const char *expected, int len) | ||
457 | { | ||
458 | bb_error_msg_and_die("got bad TLS record (len:%d) while expecting %s", len, expected); | ||
459 | if (len > 0) { | ||
460 | uint8_t *p = tls->inbuf; | ||
461 | while (len > 0) | ||
462 | fprintf(stderr, " %02x", *p++); | ||
463 | fputc('\n', stderr); | ||
464 | } | ||
465 | xfunc_die(); | ||
466 | } | ||
467 | |||
448 | static void tls_error_die(tls_state_t *tls) | 468 | static void tls_error_die(tls_state_t *tls) |
449 | { | 469 | { |
450 | dump_tls_record(tls->inbuf, tls->ofs_to_buffered + tls->buffered_size); | 470 | dump_tls_record(tls->inbuf, tls->ofs_to_buffered + tls->buffered_size); |
@@ -671,6 +691,18 @@ static int tls_has_buffered_record(tls_state_t *tls) | |||
671 | return rec_size; | 691 | return rec_size; |
672 | } | 692 | } |
673 | 693 | ||
694 | static const char *alert_text(int code) | ||
695 | { | ||
696 | switch (code) { | ||
697 | case 20: return "bad MAC"; | ||
698 | case 50: return "decode error"; | ||
699 | case 51: return "decrypt error"; | ||
700 | case 40: return "handshake failure"; | ||
701 | case 112: return "unrecognized name"; | ||
702 | } | ||
703 | return itoa(code); | ||
704 | } | ||
705 | |||
674 | static int tls_xread_record(tls_state_t *tls) | 706 | static int tls_xread_record(tls_state_t *tls) |
675 | { | 707 | { |
676 | struct record_hdr *xhdr; | 708 | struct record_hdr *xhdr; |
@@ -780,16 +812,28 @@ static int tls_xread_record(tls_state_t *tls) | |||
780 | if (xhdr->type == RECORD_TYPE_ALERT && sz >= 2) { | 812 | if (xhdr->type == RECORD_TYPE_ALERT && sz >= 2) { |
781 | uint8_t *p = tls->inbuf + RECHDR_LEN; | 813 | uint8_t *p = tls->inbuf + RECHDR_LEN; |
782 | dbg("ALERT size:%d level:%d description:%d\n", sz, p[0], p[1]); | 814 | dbg("ALERT size:%d level:%d description:%d\n", sz, p[0], p[1]); |
815 | if (p[0] == 2) { /* fatal */ | ||
816 | bb_error_msg_and_die("TLS %s from peer (alert code %d): %s", | ||
817 | "error", | ||
818 | p[1], alert_text(p[1]) | ||
819 | ); | ||
820 | } | ||
783 | if (p[0] == 1) { /* warning */ | 821 | if (p[0] == 1) { /* warning */ |
784 | if (p[1] == 0) { /* "close_notify" warning: it's EOF */ | 822 | if (p[1] == 0) { /* "close_notify" warning: it's EOF */ |
785 | dbg("EOF (TLS encoded) from peer\n"); | 823 | dbg("EOF (TLS encoded) from peer\n"); |
786 | sz = 0; | 824 | sz = 0; |
787 | goto end; | 825 | goto end; |
788 | } | 826 | } |
827 | //This possibly needs to be cached and shown only if | ||
828 | //a fatal alert follows | ||
829 | // bb_error_msg("TLS %s from peer (alert code %d): %s", | ||
830 | // "warning", | ||
831 | // p[1], alert_text(p[1]) | ||
832 | // ); | ||
789 | /* discard it, get next record */ | 833 | /* discard it, get next record */ |
790 | goto again; | 834 | goto again; |
791 | } | 835 | } |
792 | /* p[0] == 1: fatal error, others: not defined in protocol */ | 836 | /* p[0] not 1 or 2: not defined in protocol */ |
793 | sz = 0; | 837 | sz = 0; |
794 | goto end; | 838 | goto end; |
795 | } | 839 | } |
@@ -1031,7 +1075,7 @@ static int tls_xread_handshake_block(tls_state_t *tls, int min_len) | |||
1031 | || xhdr->proto_maj != TLS_MAJ | 1075 | || xhdr->proto_maj != TLS_MAJ |
1032 | || xhdr->proto_min != TLS_MIN | 1076 | || xhdr->proto_min != TLS_MIN |
1033 | ) { | 1077 | ) { |
1034 | tls_error_die(tls); | 1078 | bad_record_die(tls, "handshake record", len); |
1035 | } | 1079 | } |
1036 | dbg("got HANDSHAKE\n"); | 1080 | dbg("got HANDSHAKE\n"); |
1037 | return len; | 1081 | return len; |
@@ -1051,7 +1095,6 @@ static ALWAYS_INLINE void fill_handshake_record_hdr(void *buf, unsigned type, un | |||
1051 | h->len24_lo = len & 0xff; | 1095 | h->len24_lo = len & 0xff; |
1052 | } | 1096 | } |
1053 | 1097 | ||
1054 | //TODO: implement RFC 5746 (Renegotiation Indication Extension) - some servers will refuse to work with us otherwise | ||
1055 | static void send_client_hello(tls_state_t *tls, const char *sni) | 1098 | static void send_client_hello(tls_state_t *tls, const char *sni) |
1056 | { | 1099 | { |
1057 | struct client_hello { | 1100 | struct client_hello { |
@@ -1062,18 +1105,27 @@ static void send_client_hello(tls_state_t *tls, const char *sni) | |||
1062 | uint8_t session_id_len; | 1105 | uint8_t session_id_len; |
1063 | /* uint8_t session_id[]; */ | 1106 | /* uint8_t session_id[]; */ |
1064 | uint8_t cipherid_len16_hi, cipherid_len16_lo; | 1107 | uint8_t cipherid_len16_hi, cipherid_len16_lo; |
1065 | uint8_t cipherid[2 * 1]; /* actually variable */ | 1108 | uint8_t cipherid[2 * 2]; /* actually variable */ |
1066 | uint8_t comprtypes_len; | 1109 | uint8_t comprtypes_len; |
1067 | uint8_t comprtypes[1]; /* actually variable */ | 1110 | uint8_t comprtypes[1]; /* actually variable */ |
1068 | /* Extensions (SNI shown): | 1111 | /* Extensions (SNI shown): |
1069 | * hi,lo // len of all extensions | 1112 | * hi,lo // len of all extensions |
1070 | * 0x00,0x00 // extension_type: "Server Name" | 1113 | * 00,00 // extension_type: "Server Name" |
1071 | * 0x00,0x0e // list len (there can be more than one SNI) | 1114 | * 00,0e // list len (there can be more than one SNI) |
1072 | * 0x00,0x0c // len of 1st Server Name Indication | 1115 | * 00,0c // len of 1st Server Name Indication |
1073 | * 0x00 // name type: host_name | 1116 | * 00 // name type: host_name |
1074 | * 0x00,0x09 // name len | 1117 | * 00,09 // name len |
1075 | * "localhost" // name | 1118 | * "localhost" // name |
1076 | */ | 1119 | */ |
1120 | // GNU Wget 1.18 to cdn.kernel.org sends these extensions: | ||
1121 | // 0055 | ||
1122 | // 0005 0005 0100000000 - status_request | ||
1123 | // 0000 0013 0011 00 000e 63646e 2e 6b65726e656c 2e 6f7267 - server_name | ||
1124 | // ff01 0001 00 - renegotiation_info | ||
1125 | // 0023 0000 - session_ticket | ||
1126 | // 000a 0008 0006001700180019 - supported_groups | ||
1127 | // 000b 0002 0100 - ec_point_formats | ||
1128 | // 000d 0016 00140401040305010503060106030301030302010203 - signature_algorithms | ||
1077 | }; | 1129 | }; |
1078 | struct client_hello *record; | 1130 | struct client_hello *record; |
1079 | int len; | 1131 | int len; |
@@ -1084,6 +1136,7 @@ static void send_client_hello(tls_state_t *tls, const char *sni) | |||
1084 | len += 11 + strlen(sni); | 1136 | len += 11 + strlen(sni); |
1085 | record = tls_get_outbuf(tls, len); | 1137 | record = tls_get_outbuf(tls, len); |
1086 | memset(record, 0, len); | 1138 | memset(record, 0, len); |
1139 | |||
1087 | fill_handshake_record_hdr(record, HANDSHAKE_CLIENT_HELLO, len); | 1140 | fill_handshake_record_hdr(record, HANDSHAKE_CLIENT_HELLO, len); |
1088 | record->proto_maj = TLS_MAJ; /* the "requested" version of the protocol, */ | 1141 | record->proto_maj = TLS_MAJ; /* the "requested" version of the protocol, */ |
1089 | record->proto_min = TLS_MIN; /* can be higher than one in record headers */ | 1142 | record->proto_min = TLS_MIN; /* can be higher than one in record headers */ |
@@ -1092,10 +1145,16 @@ static void send_client_hello(tls_state_t *tls, const char *sni) | |||
1092 | memset(record->rand32, 0x11, sizeof(record->rand32)); | 1145 | memset(record->rand32, 0x11, sizeof(record->rand32)); |
1093 | memcpy(tls->hsd->client_and_server_rand32, record->rand32, sizeof(record->rand32)); | 1146 | memcpy(tls->hsd->client_and_server_rand32, record->rand32, sizeof(record->rand32)); |
1094 | /* record->session_id_len = 0; - already is */ | 1147 | /* record->session_id_len = 0; - already is */ |
1148 | |||
1095 | /* record->cipherid_len16_hi = 0; */ | 1149 | /* record->cipherid_len16_hi = 0; */ |
1096 | record->cipherid_len16_lo = 2 * 1; | 1150 | record->cipherid_len16_lo = 2 * 2; |
1097 | record->cipherid[0] = CIPHER_ID >> 8; | 1151 | if ((CIPHER_ID >> 8) != 0) |
1152 | record->cipherid[0] = CIPHER_ID >> 8; | ||
1098 | record->cipherid[1] = CIPHER_ID & 0xff; | 1153 | record->cipherid[1] = CIPHER_ID & 0xff; |
1154 | /* RFC 5746 Renegotiation Indication Extension - some servers will refuse to work with us otherwise */ | ||
1155 | /*record->cipherid[2] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV >> 8; - zero */ | ||
1156 | record->cipherid[3] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV & 0xff; | ||
1157 | |||
1099 | record->comprtypes_len = 1; | 1158 | record->comprtypes_len = 1; |
1100 | /* record->comprtypes[0] = 0; */ | 1159 | /* record->comprtypes[0] = 0; */ |
1101 | 1160 | ||
@@ -1136,8 +1195,9 @@ static void get_server_hello(tls_state_t *tls) | |||
1136 | 1195 | ||
1137 | struct server_hello *hp; | 1196 | struct server_hello *hp; |
1138 | uint8_t *cipherid; | 1197 | uint8_t *cipherid; |
1198 | int len; | ||
1139 | 1199 | ||
1140 | tls_xread_handshake_block(tls, 74); | 1200 | len = tls_xread_handshake_block(tls, 74); |
1141 | 1201 | ||
1142 | hp = (void*)tls->inbuf; | 1202 | hp = (void*)tls->inbuf; |
1143 | // 74 bytes: | 1203 | // 74 bytes: |
@@ -1150,7 +1210,7 @@ static void get_server_hello(tls_state_t *tls) | |||
1150 | || hp->proto_maj != TLS_MAJ | 1210 | || hp->proto_maj != TLS_MAJ |
1151 | || hp->proto_min != TLS_MIN | 1211 | || hp->proto_min != TLS_MIN |
1152 | ) { | 1212 | ) { |
1153 | tls_error_die(tls); | 1213 | bad_record_die(tls, "'server hello'", len); |
1154 | } | 1214 | } |
1155 | 1215 | ||
1156 | cipherid = &hp->cipherid_hi; | 1216 | cipherid = &hp->cipherid_hi; |