aboutsummaryrefslogtreecommitdiff
path: root/networking/tls.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-01-23 16:12:17 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2017-01-23 16:12:17 +0100
commitb5bf1913d31512d1c5f4c9656dc96e6b8dcd92ba (patch)
tree2739d19dc6c99f73d84b25a616928c5cb36281ce /networking/tls.c
parent9492da7e63deae898d7bf924be5790c7fab1a4fb (diff)
downloadbusybox-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.c112
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
160enum { 168enum {
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
456static 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
448static void tls_error_die(tls_state_t *tls) 468static 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
694static 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
674static int tls_xread_record(tls_state_t *tls) 706static 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
1055static void send_client_hello(tls_state_t *tls, const char *sni) 1098static 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;