From 5738c0e838c7b4e95310a159a478325261205fe7 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Mon, 21 Jan 2013 09:53:35 +0800 Subject: [PATCH] remove all support for pre v13 protocols Since v13 was defined as the released ietf version the older versions are deprecated. This patch strips out everything to do with the older versions and gets rid of the option to send stuff unmasked. The in-tree md5 implementation is then also deleted as nothing needs it any more, 1280 loc are shed in all Signed-off-by: Andy Green --- lib/Makefile.am | 2 +- lib/client-handshake.c | 33 ------ lib/client-parser.c | 147 +------------------------- lib/client.c | 251 +------------------------------------------- lib/handshake.c | 21 ---- lib/libwebsockets.c | 6 -- lib/libwebsockets.h | 1 - lib/md5.c | 217 -------------------------------------- lib/output.c | 221 ++++++-------------------------------- lib/parsers.c | 193 ++-------------------------------- lib/private-libwebsockets.h | 34 ------ lib/server-handshake.c | 240 ------------------------------------------ test-server/test-client.c | 6 +- test-server/test-fraggle.c | 8 +- test-server/test-server.c | 6 +- 15 files changed, 49 insertions(+), 1337 deletions(-) delete mode 100644 lib/md5.c diff --git a/lib/Makefile.am b/lib/Makefile.am index cf467d8..a067189 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -39,7 +39,7 @@ endif if LIBCRYPTO else -dist_libwebsockets_la_SOURCES += md5.c sha-1.c +dist_libwebsockets_la_SOURCES += sha-1.c endif libwebsockets_la_CFLAGS=-Wall -std=gnu99 -pedantic -g diff --git a/lib/client-handshake.c b/lib/client-handshake.c index ff20b17..d168084 100644 --- a/lib/client-handshake.c +++ b/lib/client-handshake.c @@ -270,34 +270,6 @@ libwebsocket_client_connect(struct libwebsocket_context *context, if (!wsi->c_callback) wsi->c_callback = context->protocols[0].callback; - /* set up appropriate masking */ - - wsi->xor_mask = xor_no_mask; - - switch (wsi->ietf_spec_revision) { - case 0: - break; - case 4: - wsi->xor_mask = xor_mask_04; - break; - case 5: - case 6: - case 7: - case 8: - case 13: - wsi->xor_mask = xor_mask_05; - break; - default: - lwsl_parser("Client ietf version %d not supported\n", - wsi->ietf_spec_revision); - goto oom4; - } - - /* force no mask if he asks for that though */ - - if (context->options & LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK) - wsi->xor_mask = xor_no_mask; - for (n = 0; n < WSI_TOKEN_COUNT; n++) { wsi->utf8_token[n].token = NULL; wsi->utf8_token[n].token_len = 0; @@ -340,11 +312,6 @@ libwebsocket_client_connect(struct libwebsocket_context *context, return __libwebsocket_client_connect_2(context, wsi); - -oom4: - if (wsi->c_protocol) - free(wsi->c_protocol); - oom3: if (wsi->c_origin) free(wsi->c_origin); diff --git a/lib/client-parser.c b/lib/client-parser.c index 8eea869..ba06147 100644 --- a/lib/client-parser.c +++ b/lib/client-parser.c @@ -28,7 +28,6 @@ int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c) { int n; - unsigned char buf[20 + 4]; int callback_action = LWS_CALLBACK_CLIENT_RECEIVE; int handled; struct lws_tokens eff_buf; @@ -42,103 +41,9 @@ int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c) case LWS_RXPS_NEW: switch (wsi->ietf_spec_revision) { - /* Firefox 4.0b6 likes this as of 30 Oct */ - case 0: - if (c == 0xff) - wsi->lws_rx_parse_state = LWS_RXPS_SEEN_76_FF; - if (c == 0) { - wsi->lws_rx_parse_state = - LWS_RXPS_EAT_UNTIL_76_FF; - wsi->rx_user_buffer_head = 0; - } - break; - case 4: - case 5: - case 6: - case 7: - case 8: - case 13: - /* - * 04 logical framing from the spec (all this is masked when - * incoming and has to be unmasked) - * - * We ignore the possibility of extension data because we don't - * negotiate any extensions at the moment. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-------+-+-------------+-------------------------------+ - * |F|R|R|R| opcode|R| Payload len | Extended payload length | - * |I|S|S|S| (4) |S| (7) | (16/63) | - * |N|V|V|V| |V| | (if payload len==126/127) | - * | |1|2|3| |4| | | - * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + - * | Extended payload length continued, if payload len == 127 | - * + - - - - - - - - - - - - - - - +-------------------------------+ - * | | Extension data | - * +-------------------------------+ - - - - - - - - - - - - - - - + - * : : - * +---------------------------------------------------------------+ - * : Application data : - * +---------------------------------------------------------------+ - * - * We pass payload through to userland as soon as we get it, ignoring - * FIN. It's up to userland to buffer it up if it wants to see a - * whole unfragmented block of the original size (which may be up to - * 2^63 long!) - * - * Notice in v7 RSV4 is set to indicate 32-bit frame key is coming in - * after length, unlike extension data which is now deprecated, this - * does not impact the payload length calculation. - */ - - /* - * 04 spec defines the opcode like this: (1, 2, and 3 are - * "control frame" opcodes which may not be fragmented or - * have size larger than 126) - * - * frame-opcode = - * %x0 ; continuation frame - * / %x1 ; connection close - * / %x2 ; ping - * / %x3 ; pong - * / %x4 ; text frame - * / %x5 ; binary frame - * / %x6-F ; reserved - * - * FIN (b7) - */ - if (wsi->ietf_spec_revision < 7) - switch (c & 0xf) { - case LWS_WS_OPCODE_04__CONTINUATION: - wsi->opcode = - LWS_WS_OPCODE_07__CONTINUATION; - break; - case LWS_WS_OPCODE_04__CLOSE: - wsi->opcode = LWS_WS_OPCODE_07__CLOSE; - break; - case LWS_WS_OPCODE_04__PING: - wsi->opcode = LWS_WS_OPCODE_07__PING; - break; - case LWS_WS_OPCODE_04__PONG: - wsi->opcode = LWS_WS_OPCODE_07__PONG; - break; - case LWS_WS_OPCODE_04__TEXT_FRAME: - wsi->opcode = - LWS_WS_OPCODE_07__TEXT_FRAME; - break; - case LWS_WS_OPCODE_04__BINARY_FRAME: - wsi->opcode = - LWS_WS_OPCODE_07__BINARY_FRAME; - break; - default: - lwsl_warn("reserved opcodes not " - "usable pre v7 protocol\n"); - return -1; - } - else - wsi->opcode = c & 0xf; + case 13: + wsi->opcode = c & 0xf; wsi->rsv = (c & 0x70); wsi->final = !!((c >> 7) & 1); switch (wsi->opcode) { @@ -161,12 +66,6 @@ int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c) case LWS_RXPS_04_FRAME_HDR_LEN: - if ((c & 0x80) && wsi->ietf_spec_revision < 7) { - lwsl_warn("Frame has extensions set illegally 4\n"); - /* kill the connection */ - return -1; - } - wsi->this_frame_masked = !!(c & 0x80); switch (c & 0x7f) { @@ -322,46 +221,6 @@ int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c) } break; - case LWS_RXPS_EAT_UNTIL_76_FF: - if (c == 0xff) { - wsi->lws_rx_parse_state = LWS_RXPS_NEW; - goto issue; - } - wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + - (wsi->rx_user_buffer_head++)] = c; - - if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER) - break; -issue: - if (wsi->protocol->callback) - wsi->protocol->callback(wsi->protocol->owning_server, - wsi, - LWS_CALLBACK_CLIENT_RECEIVE, - wsi->user_space, - &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING], - wsi->rx_user_buffer_head); - wsi->rx_user_buffer_head = 0; - break; - case LWS_RXPS_SEEN_76_FF: - if (c) - break; - - lwsl_parser("Seen that client is requesting " - "a v76 close, sending ack\n"); - buf[0] = 0xff; - buf[1] = 0; - n = libwebsocket_write(wsi, buf, 2, LWS_WRITE_HTTP); - if (n < 0) { - lwsl_warn("LWS_RXPS_SEEN_76_FF: ERROR writing to socket\n"); - return -1; - } - lwsl_parser(" v76 close ack sent, server closing skt\n"); - /* returning < 0 will get it closed in parent */ - return -1; - - case LWS_RXPS_PULLING_76_LENGTH: - break; - case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED: if ((!wsi->this_frame_masked) || wsi->all_zero_nonce) wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + @@ -369,7 +228,7 @@ issue: else wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + (wsi->rx_user_buffer_head++)] = - wsi->xor_mask(wsi, c); + c ^ wsi->frame_masking_nonce_04[(wsi->frame_mask_index++) & 3]; if (--wsi->rx_packet_length == 0) { wsi->lws_rx_parse_state = LWS_RXPS_NEW; diff --git a/lib/client.c b/lib/client.c index a11de1f..40b24fa 100644 --- a/lib/client.c +++ b/lib/client.c @@ -310,10 +310,6 @@ int lws_client_interpret_server_handshake(struct libwebsocket_context *context, struct libwebsocket *wsi) { - unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1 + - MAX_BROADCAST_PAYLOAD + LWS_SEND_BUFFER_POST_PADDING]; - char pkt[1024]; - char *p = &pkt[0]; const char *pc; int okay = 0; #ifndef LWS_NO_EXTENSIONS @@ -323,57 +319,7 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context, int more = 1; const char *c; #endif - int len = 0; int n; - static const char magic_websocket_04_masking_guid[] = - "61AC5F19-FBBA-4540-B96F-6561F1AB40A8"; - - /* - * 00 / 76 --> - * - * HTTP/1.1 101 WebSocket Protocol Handshake - * Upgrade: WebSocket - * Connection: Upgrade - * Sec-WebSocket-Origin: http://127.0.0.1 - * Sec-WebSocket-Location: ws://127.0.0.1:9999/socket.io/websocket - * - * xxxxxxxxxxxxxxxx - */ - - if (wsi->ietf_spec_revision == 0) { - if (!wsi->utf8_token[WSI_TOKEN_HTTP].token_len || - !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len || - !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len || - !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len - ) { - lwsl_parser("libwebsocket_client_handshake " - "missing required header(s)\n"); - pkt[len] = '\0'; - lwsl_parser("%s", pkt); - goto bail3; - } - - strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token); - if (strncmp(wsi->utf8_token[WSI_TOKEN_HTTP].token, "101", 3)) { - lwsl_warn("libwebsocket_client_handshake " - "server sent bad HTTP response '%s'\n", - wsi->utf8_token[WSI_TOKEN_HTTP].token); - goto bail3; - } - - if (wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len < 16) { - lwsl_parser("libwebsocket_client_handshake " - "challenge reply too short %d\n", - wsi->utf8_token[ - WSI_TOKEN_CHALLENGE].token_len); - pkt[len] = '\0'; - lwsl_parser("%s", pkt); - goto bail3; - - } - - goto select_protocol; - } /* * well, what the server sent looked reasonable for syntax. @@ -393,24 +339,6 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context, lwsl_parser("WSI_TOKEN_PROTOCOL: %d\n", wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len); #endif - if (!wsi->utf8_token[WSI_TOKEN_HTTP].token_len || - !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len || - !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len || - !wsi->utf8_token[WSI_TOKEN_ACCEPT].token_len || - (!wsi->utf8_token[WSI_TOKEN_NONCE].token_len && - wsi->ietf_spec_revision == 4) - ) { - lwsl_parser("libwebsocket_client_handshake " - "missing required header(s) revision=%d\n", wsi->ietf_spec_revision); - pkt[len] = '\0'; - lwsl_parser("%s", pkt); - goto bail3; - } - - /* - * Everything seems to be there, now take a closer look at what - * is in each header - */ strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token); if (strncmp(wsi->utf8_token[WSI_TOKEN_HTTP].token, "101", 3)) { @@ -438,7 +366,6 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context, goto bail3; } -select_protocol: pc = wsi->c_protocol; if (pc == NULL) lwsl_parser("lws_client_interpret_server_handshake: " @@ -608,20 +535,6 @@ check_extensions: check_accept: #endif - if (wsi->ietf_spec_revision == 0) { - - if (memcmp(wsi->initial_handshake_hash_base64, - wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 16)) { - lwsl_warn("libwebsocket_client_handshake " - "failed 00 challenge compare\n"); - pkt[len] = '\0'; - lwsl_warn("%s", pkt); - goto bail2; - } - - goto accept_ok; - } - /* * Confirm his accept token is the one we precomputed */ @@ -635,21 +548,6 @@ check_accept: goto bail2; } - if (wsi->ietf_spec_revision == 4) { - /* - * Calculate the 04 masking key to use when - * sending data to server - */ - - strcpy((char *)buf, wsi->key_b64); - p = (char *)buf + strlen(wsi->key_b64); - strcpy(p, wsi->utf8_token[WSI_TOKEN_NONCE].token); - p += wsi->utf8_token[WSI_TOKEN_NONCE].token_len; - strcpy(p, magic_websocket_04_masking_guid); - SHA1(buf, strlen((char *)buf), wsi->masking_key_04); - } -accept_ok: - /* allocate the per-connection user memory (if any) */ if (wsi->protocol->per_session_data_size && !libwebsocket_ensure_user_space(wsi)) @@ -708,46 +606,6 @@ bail2: return 1; } -void libwebsockets_00_spaceout(char *key, int spaces, int seed) -{ - char *p; - - key++; - while (spaces--) { - if (*key && (seed & 1)) - key++; - seed >>= 1; - - p = key + strlen(key); - while (p >= key) { - p[1] = p[0]; - p--; - } - *key++ = ' '; - } -} - -void libwebsockets_00_spam(char *key, int count, int seed) -{ - char *p; - - key++; - while (count--) { - - if (*key && (seed & 1)) - key++; - seed >>= 1; - - p = key + strlen(key); - while (p >= key) { - p[1] = p[0]; - p--; - } - *key++ = 0x21 + ((seed & 0xffff) % 15); - /* 4 would use it up too fast.. not like it matters */ - seed >>= 1; - } -} char * libwebsockets_generate_client_handshake(struct libwebsocket_context *context, @@ -819,96 +677,6 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context, p += sprintf(p, "Pragma: no-cache\x0d\x0a" "Cache-Control: no-cache\x0d\x0a"); - if (wsi->ietf_spec_revision == 0) { - unsigned char spaces_1, spaces_2; - unsigned int max_1, max_2; - unsigned int num_1, num_2; - unsigned long product_1, product_2; - char key_1[40]; - char key_2[40]; - unsigned int seed; - unsigned int count; - char challenge[16]; - - libwebsockets_get_random(context, &spaces_1, sizeof(char)); - libwebsockets_get_random(context, &spaces_2, sizeof(char)); - - spaces_1 = (spaces_1 % 12) + 1; - spaces_2 = (spaces_2 % 12) + 1; - - max_1 = 4294967295 / spaces_1; - max_2 = 4294967295 / spaces_2; - - libwebsockets_get_random(context, &num_1, sizeof(int)); - libwebsockets_get_random(context, &num_2, sizeof(int)); - - num_1 = (num_1 % max_1); - num_2 = (num_2 % max_2); - - challenge[0] = num_1 >> 24; - challenge[1] = num_1 >> 16; - challenge[2] = num_1 >> 8; - challenge[3] = num_1; - challenge[4] = num_2 >> 24; - challenge[5] = num_2 >> 16; - challenge[6] = num_2 >> 8; - challenge[7] = num_2; - - product_1 = num_1 * spaces_1; - product_2 = num_2 * spaces_2; - - sprintf(key_1, "%lu", product_1); - sprintf(key_2, "%lu", product_2); - - libwebsockets_get_random(context, &seed, sizeof(int)); - libwebsockets_get_random(context, &count, sizeof(int)); - - libwebsockets_00_spam(key_1, (count % 12) + 1, seed); - - libwebsockets_get_random(context, &seed, sizeof(int)); - libwebsockets_get_random(context, &count, sizeof(int)); - - libwebsockets_00_spam(key_2, (count % 12) + 1, seed); - - libwebsockets_get_random(context, &seed, sizeof(int)); - - libwebsockets_00_spaceout(key_1, spaces_1, seed); - libwebsockets_00_spaceout(key_2, spaces_2, seed >> 16); - - p += sprintf(p, "Upgrade: WebSocket\x0d\x0a" - "Connection: Upgrade\x0d\x0aHost: %s\x0d\x0a", - wsi->c_host); - if (wsi->c_origin) - p += sprintf(p, "Origin: %s\x0d\x0a", wsi->c_origin); - - if (wsi->c_protocol) - p += sprintf(p, "Sec-WebSocket-Protocol: %s" - "\x0d\x0a", wsi->c_protocol); - - p += sprintf(p, "Sec-WebSocket-Key1: %s\x0d\x0a", key_1); - p += sprintf(p, "Sec-WebSocket-Key2: %s\x0d\x0a", key_2); - - /* give userland a chance to append, eg, cookies */ - - context->protocols[0].callback(context, wsi, - LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, - NULL, &p, (pkt + sizeof(pkt)) - p - 12); - - p += sprintf(p, "\x0d\x0a"); - - if (libwebsockets_get_random(context, p, 8) != 8) - return NULL; - memcpy(&challenge[8], p, 8); - p += 8; - - /* precompute what we want to see from the server */ - - MD5((unsigned char *)challenge, 16, - (unsigned char *)wsi->initial_handshake_hash_base64); - - goto issue_hdr; - } - p += sprintf(p, "Host: %s\x0d\x0a", wsi->c_host); p += sprintf(p, "Upgrade: websocket\x0d\x0a" "Connection: Upgrade\x0d\x0a" @@ -917,15 +685,12 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context, p += strlen(wsi->key_b64); p += sprintf(p, "\x0d\x0a"); if (wsi->c_origin) { - if (wsi->ietf_spec_revision == 13) { - p += sprintf(p, "Origin: %s\x0d\x0a", - wsi->c_origin); - } - else { - p += sprintf(p, "Sec-WebSocket-Origin: %s\x0d\x0a", + if (wsi->ietf_spec_revision == 13) + p += sprintf(p, "Origin: %s\x0d\x0a", wsi->c_origin); + else + p += sprintf(p, "Sec-WebSocket-Origin: %s\x0d\x0a", wsi->c_origin); - } - } + } if (wsi->c_protocol) p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a", wsi->c_protocol); @@ -1005,12 +770,6 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context, wsi->initial_handshake_hash_base64, sizeof wsi->initial_handshake_hash_base64); -issue_hdr: - -#if 0 - puts(pkt); -#endif - /* done with these now */ free(wsi->c_path); diff --git a/lib/handshake.c b/lib/handshake.c index b04df7f..3a03310 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -94,7 +94,6 @@ libwebsocket_read(struct libwebsocket_context *context, #ifndef LWS_NO_SERVER /* LWS_CONNMODE_WS_SERVING */ - extern int handshake_00(struct libwebsocket_context *context, struct libwebsocket *wsi); extern int handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi); for (n = 0; n < len; n++) @@ -188,27 +187,7 @@ libwebsocket_read(struct libwebsocket_context *context, */ switch (wsi->ietf_spec_revision) { - case 0: /* applies to 76 and 00 */ - wsi->xor_mask = xor_no_mask; - if (handshake_00(context, wsi)) { - lwsl_info("handshake_00 has failed the connection\n"); - goto bail; - } - break; - case 4: /* 04 */ - wsi->xor_mask = xor_mask_04; - lwsl_parser("libwebsocket_parse calling handshake_04\n"); - if (handshake_0405(context, wsi)) { - lwsl_info("handshake_0405 has failed the connection\n"); - goto bail; - } - break; - case 5: - case 6: - case 7: - case 8: case 13: - wsi->xor_mask = xor_mask_05; lwsl_parser("libwebsocket_parse calling handshake_04\n"); if (handshake_0405(context, wsi)) { lwsl_info("handshake_0405 xor 05 has failed the connection\n"); diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 76dc3f5..1d97782 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -483,12 +483,6 @@ int libwebsockets_get_random(struct libwebsocket_context *context, return n; } -unsigned char * -libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md) -{ - return SHA1(d, n, md); -} - int lws_send_pipe_choked(struct libwebsocket *wsi) { struct pollfd fds; diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 0900fc2..f1395ef 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -111,7 +111,6 @@ extern void lwsl_hexdump(void *buf, size_t len); #endif enum libwebsocket_context_options { - LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK = 1, LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = 2, LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME = 4, }; diff --git a/lib/md5.c b/lib/md5.c deleted file mode 100644 index 042db3b..0000000 --- a/lib/md5.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Modified from Polarssl here - * http://polarssl.org/show_source?file=md5 - * under GPL2 or later - */ - -#include -#include - - -#define GET_ULONG_LE(n, b, i) \ -{ \ - (n) = ((unsigned long)(b)[i]) \ - | ((unsigned long)(b)[(i) + 1] << 8) \ - | ((unsigned long)(b)[(i) + 2] << 16) \ - | ((unsigned long)(b)[(i) + 3] << 24); \ -} - -#define PUT_ULONG_LE(n, b, i) \ -{ \ - (b)[i] = (unsigned char)(n); \ - (b)[(i) + 1] = (unsigned char)((n) >> 8); \ - (b)[(i) + 2] = (unsigned char)((n) >> 16); \ - (b)[(i) + 3] = (unsigned char)((n) >> 24); \ -} - -static const unsigned char md5_padding[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -}; - -static const unsigned long state_init[] = { - 0, 0, 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476 -}; - -static void -md5_process(unsigned long *state, const unsigned char *data) -{ - unsigned long X[16], A, B, C, D; - int v; - - for (v = 0; v < 16; v++) - GET_ULONG_LE(X[v], data, v << 2); - -#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) - -#define P(a, b, c, d, k, s, t) { a += F(b, c, d) + X[k] + t; a = S(a, s) + b; } - - A = state[0]; - B = state[1]; - C = state[2]; - D = state[3]; - -#define F(x, y, z) (z ^ (x & (y ^ z))) - - P(A, B, C, D, 0, 7, 0xD76AA478); - P(D, A, B, C, 1, 12, 0xE8C7B756); - P(C, D, A, B, 2, 17, 0x242070DB); - P(B, C, D, A, 3, 22, 0xC1BDCEEE); - P(A, B, C, D, 4, 7, 0xF57C0FAF); - P(D, A, B, C, 5, 12, 0x4787C62A); - P(C, D, A, B, 6, 17, 0xA8304613); - P(B, C, D, A, 7, 22, 0xFD469501); - P(A, B, C, D, 8, 7, 0x698098D8); - P(D, A, B, C, 9, 12, 0x8B44F7AF); - P(C, D, A, B, 10, 17, 0xFFFF5BB1); - P(B, C, D, A, 11, 22, 0x895CD7BE); - P(A, B, C, D, 12, 7, 0x6B901122); - P(D, A, B, C, 13, 12, 0xFD987193); - P(C, D, A, B, 14, 17, 0xA679438E); - P(B, C, D, A, 15, 22, 0x49B40821); - -#undef F - -#define F(x, y, z) (y ^ (z & (x ^ y))) - - P(A, B, C, D, 1, 5, 0xF61E2562); - P(D, A, B, C, 6, 9, 0xC040B340); - P(C, D, A, B, 11, 14, 0x265E5A51); - P(B, C, D, A, 0, 20, 0xE9B6C7AA); - P(A, B, C, D, 5, 5, 0xD62F105D); - P(D, A, B, C, 10, 9, 0x02441453); - P(C, D, A, B, 15, 14, 0xD8A1E681); - P(B, C, D, A, 4, 20, 0xE7D3FBC8); - P(A, B, C, D, 9, 5, 0x21E1CDE6); - P(D, A, B, C, 14, 9, 0xC33707D6); - P(C, D, A, B, 3, 14, 0xF4D50D87); - P(B, C, D, A, 8, 20, 0x455A14ED); - P(A, B, C, D, 13, 5, 0xA9E3E905); - P(D, A, B, C, 2, 9, 0xFCEFA3F8); - P(C, D, A, B, 7, 14, 0x676F02D9); - P(B, C, D, A, 12, 20, 0x8D2A4C8A); - -#undef F - -#define F(x, y, z) (x ^ y ^ z) - - P(A, B, C, D, 5, 4, 0xFFFA3942); - P(D, A, B, C, 8, 11, 0x8771F681); - P(C, D, A, B, 11, 16, 0x6D9D6122); - P(B, C, D, A, 14, 23, 0xFDE5380C); - P(A, B, C, D, 1, 4, 0xA4BEEA44); - P(D, A, B, C, 4, 11, 0x4BDECFA9); - P(C, D, A, B, 7, 16, 0xF6BB4B60); - P(B, C, D, A, 10, 23, 0xBEBFBC70); - P(A, B, C, D, 13, 4, 0x289B7EC6); - P(D, A, B, C, 0, 11, 0xEAA127FA); - P(C, D, A, B, 3, 16, 0xD4EF3085); - P(B, C, D, A, 6, 23, 0x04881D05); - P(A, B, C, D, 9, 4, 0xD9D4D039); - P(D, A, B, C, 12, 11, 0xE6DB99E5); - P(C, D, A, B, 15, 16, 0x1FA27CF8); - P(B, C, D, A, 2, 23, 0xC4AC5665); - -#undef F - -#define F(x, y, z) (y ^ (x | ~z)) - - P(A, B, C, D, 0, 6, 0xF4292244); - P(D, A, B, C, 7, 10, 0x432AFF97); - P(C, D, A, B, 14, 15, 0xAB9423A7); - P(B, C, D, A, 5, 21, 0xFC93A039); - P(A, B, C, D, 12, 6, 0x655B59C3); - P(D, A, B, C, 3, 10, 0x8F0CCC92); - P(C, D, A, B, 10, 15, 0xFFEFF47D); - P(B, C, D, A, 1, 21, 0x85845DD1); - P(A, B, C, D, 8, 6, 0x6FA87E4F); - P(D, A, B, C, 15, 10, 0xFE2CE6E0); - P(C, D, A, B, 6, 15, 0xA3014314); - P(B, C, D, A, 13, 21, 0x4E0811A1); - P(A, B, C, D, 4, 6, 0xF7537E82); - P(D, A, B, C, 11, 10, 0xBD3AF235); - P(C, D, A, B, 2, 15, 0x2AD7D2BB); - P(B, C, D, A, 9, 21, 0xEB86D391); - -#undef F - - state[0] += A; - state[1] += B; - state[2] += C; - state[3] += D; -} - -static -void md5_update(unsigned long *state, unsigned char *buffer, - const unsigned char *input, int ilen) -{ - int fill; - unsigned long left; - - if (ilen <= 0) - return; - - left = state[0] & 0x3F; - fill = 64 - left; - - state[0] += ilen; - state[0] &= 0xFFFFFFFF; - - if (state[0] < (unsigned long)ilen) - state[1]++; - - if (left && ilen >= fill) { - memcpy(buffer + left, input, fill); - md5_process(&state[2], buffer); - input += fill; - ilen -= fill; - left = 0; - } - - while (ilen >= 64) { - md5_process(&state[2], input); - input += 64; - ilen -= 64; - } - - if (ilen > 0) - memcpy(buffer + left, input, ilen); -} - -void -MD5(const unsigned char *input, int ilen, unsigned char *output) -{ - unsigned long last, padn; - unsigned long high, low; - unsigned char msglen[8]; - unsigned long state[6]; - unsigned char buffer[64]; - - memcpy(&state[0], &state_init[0], sizeof(state_init)); - - md5_update(state, buffer, input, ilen); - - high = (state[0] >> 29) | (state[1] << 3); - low = state[0] << 3; - - PUT_ULONG_LE(low, msglen, 0); - PUT_ULONG_LE(high, msglen, 4); - - last = state[0] & 0x3F; - padn = (last < 56) ? (56 - last) : (120 - last); - - md5_update(state, buffer, md5_padding, padn); - md5_update(state, buffer, msglen, 8); - - PUT_ULONG_LE(state[2], output, 0); - PUT_ULONG_LE(state[3], output, 4); - PUT_ULONG_LE(state[4], output, 8); - PUT_ULONG_LE(state[5], output, 12); -} - diff --git a/lib/output.c b/lib/output.c index b5cf7ea..d16451f 100644 --- a/lib/output.c +++ b/lib/output.c @@ -28,7 +28,6 @@ static int libwebsocket_0405_frame_mask_generate(struct libwebsocket *wsi) { - char buf[4 + 20]; int n; /* fetch the per-frame nonce */ @@ -44,24 +43,6 @@ libwebsocket_0405_frame_mask_generate(struct libwebsocket *wsi) /* start masking from first byte of masking key buffer */ wsi->frame_mask_index = 0; - if (wsi->ietf_spec_revision != 4) - return 0; - - /* 04 only does SHA-1 more complex key */ - - /* - * the frame key is the frame nonce (4 bytes) followed by the - * connection masking key, hashed by SHA1 - */ - - memcpy(buf, wsi->frame_masking_nonce_04, 4); - - memcpy(buf + 4, wsi->masking_key_04, 20); - - /* concatenate the nonce with the connection key then hash it */ - - SHA1((unsigned char *)buf, 4 + 20, wsi->frame_mask_04); - return 0; } @@ -297,9 +278,7 @@ int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, int n; int pre = 0; int post = 0; - int shift = 7; - int masked7 = wsi->mode == LWS_CONNMODE_WS_CLIENT && - wsi->xor_mask != xor_no_mask; + int masked7 = wsi->mode == LWS_CONNMODE_WS_CLIENT; unsigned char *dropmask = NULL; unsigned char is_masked_bit = 0; #ifndef LWS_NO_EXTENSIONS @@ -352,138 +331,46 @@ int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, #endif switch (wsi->ietf_spec_revision) { - /* chrome likes this as of 30 Oct 2010 */ - /* Firefox 4.0b6 likes this as of 30 Oct 2010 */ - case 0: - if ((protocol & 0xf) == LWS_WRITE_BINARY) { - /* in binary mode we send 7-bit used length blocks */ - pre = 1; - while (len & (127 << shift)) { - pre++; - shift += 7; - } - n = 0; - shift -= 7; - while (shift >= 0) { - if (shift) - buf[0 - pre + n] = - ((len >> shift) & 127) | 0x80; - else - buf[0 - pre + n] = - ((len >> shift) & 127); - n++; - shift -= 7; - } - break; - } - - /* frame type = text, length-free spam mode */ - - pre = 1; - buf[-pre] = 0; - buf[len] = 0xff; /* EOT marker */ - post = 1; - break; - - case 7: - case 8: case 13: if (masked7) { pre += 4; dropmask = &buf[0 - pre]; is_masked_bit = 0x80; } - /* fallthru */ - case 4: - case 5: - case 6: + switch (protocol & 0xf) { case LWS_WRITE_TEXT: - if (wsi->ietf_spec_revision < 7) - n = LWS_WS_OPCODE_04__TEXT_FRAME; - else - n = LWS_WS_OPCODE_07__TEXT_FRAME; + n = LWS_WS_OPCODE_07__TEXT_FRAME; break; case LWS_WRITE_BINARY: - if (wsi->ietf_spec_revision < 7) - n = LWS_WS_OPCODE_04__BINARY_FRAME; - else - n = LWS_WS_OPCODE_07__BINARY_FRAME; + n = LWS_WS_OPCODE_07__BINARY_FRAME; break; case LWS_WRITE_CONTINUATION: - if (wsi->ietf_spec_revision < 7) - n = LWS_WS_OPCODE_04__CONTINUATION; - else - n = LWS_WS_OPCODE_07__CONTINUATION; + n = LWS_WS_OPCODE_07__CONTINUATION; break; case LWS_WRITE_CLOSE: - if (wsi->ietf_spec_revision < 7) - n = LWS_WS_OPCODE_04__CLOSE; - else - n = LWS_WS_OPCODE_07__CLOSE; + n = LWS_WS_OPCODE_07__CLOSE; /* - * v5 mandates the first byte of close packet - * in both client and server directions + * 06+ has a 2-byte status code in network order + * we can do this because we demand post-buf */ - switch (wsi->ietf_spec_revision) { - case 0: - case 4: - break; - case 5: - /* we can do this because we demand post-buf */ - - if (len < 1) - len = 1; - - switch (wsi->mode) { - case LWS_CONNMODE_WS_SERVING: - /* - lwsl_debug("LWS_WRITE_CLOSE S\n"); - */ - buf[0] = 'S'; - break; - case LWS_CONNMODE_WS_CLIENT: - /* - lwsl_debug("LWS_WRITE_CLOSE C\n"); - */ - buf[0] = 'C'; - break; - default: - break; - } - break; - default: - /* - * 06 has a 2-byte status code in network order - * we can do this because we demand post-buf - */ - - if (wsi->close_reason) { - /* reason codes count as data bytes */ - buf -= 2; - buf[0] = wsi->close_reason >> 8; - buf[1] = wsi->close_reason; - len += 2; - } - break; + if (wsi->close_reason) { + /* reason codes count as data bytes */ + buf -= 2; + buf[0] = wsi->close_reason >> 8; + buf[1] = wsi->close_reason; + len += 2; } break; case LWS_WRITE_PING: - if (wsi->ietf_spec_revision < 7) - n = LWS_WS_OPCODE_04__PING; - else - n = LWS_WS_OPCODE_07__PING; - + n = LWS_WS_OPCODE_07__PING; wsi->pings_vs_pongs++; break; case LWS_WRITE_PONG: - if (wsi->ietf_spec_revision < 7) - n = LWS_WS_OPCODE_04__PONG; - else - n = LWS_WS_OPCODE_07__PONG; + n = LWS_WS_OPCODE_07__PONG; break; default: lwsl_warn("libwebsocket_write: unknown write " @@ -534,72 +421,24 @@ int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, * the protocol demands it */ - if (wsi->mode == LWS_CONNMODE_WS_CLIENT && - wsi->ietf_spec_revision >= 4) { + if (wsi->mode == LWS_CONNMODE_WS_CLIENT) { + + if (libwebsocket_0405_frame_mask_generate(wsi)) { + lwsl_err("libwebsocket_write: " + "frame mask generation failed\n"); + return 1; + } /* - * this is only useful for security tests where it's required - * to control the raw packet payload content + * in v7, just mask the payload */ + for (n = 4; n < (int)len + 4; n++) + dropmask[n] = dropmask[n] ^ wsi->frame_masking_nonce_04[(wsi->frame_mask_index++) & 3]; - if (!(protocol & LWS_WRITE_CLIENT_IGNORE_XOR_MASK) && - wsi->xor_mask != xor_no_mask) { - - if (libwebsocket_0405_frame_mask_generate(wsi)) { - lwsl_err("libwebsocket_write: " - "frame mask generation failed\n"); - return 1; - } - - - if (wsi->ietf_spec_revision < 7) - /* - * use the XOR masking against everything we - * send past the frame key - */ - for (n = -pre; n < ((int)len + post); n++) - buf[n] = wsi->xor_mask(wsi, buf[n]); - else - /* - * in v7, just mask the payload - */ - for (n = 0; n < (int)len; n++) - dropmask[n + 4] = - wsi->xor_mask(wsi, dropmask[n + 4]); - - - if (wsi->ietf_spec_revision < 7) { - /* make space for the frame nonce in clear */ - pre += 4; - - dropmask = &buf[0 - pre]; - } - - if (dropmask) - /* copy the frame nonce into place */ - memcpy(dropmask, - wsi->frame_masking_nonce_04, 4); - - } else { - if (wsi->ietf_spec_revision < 7) { - - /* make space for the frame nonce in clear */ - pre += 4; - - buf[0 - pre] = 0; - buf[1 - pre] = 0; - buf[2 - pre] = 0; - buf[3 - pre] = 0; - } else { - if (dropmask && wsi->xor_mask != xor_no_mask) { - dropmask[0] = 0; - dropmask[1] = 0; - dropmask[2] = 0; - dropmask[3] = 0; - } - } - } - + if (dropmask) + /* copy the frame nonce into place */ + memcpy(dropmask, + wsi->frame_masking_nonce_04, 4); } send_raw: diff --git a/lib/parsers.c b/lib/parsers.c index c503534..ea3a0ad 100644 --- a/lib/parsers.c +++ b/lib/parsers.c @@ -528,10 +528,8 @@ int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c) /* client parser? */ - if (wsi->ietf_spec_revision >= 4) { - lwsl_parser("04 header completed\n"); - wsi->parser_state = WSI_PARSING_COMPLETE; - } + lwsl_parser("04 header completed\n"); + wsi->parser_state = WSI_PARSING_COMPLETE; break; @@ -562,27 +560,6 @@ int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c) return 0; } -unsigned char -xor_no_mask(struct libwebsocket *wsi, unsigned char c) -{ - return c; -} - -unsigned char -xor_mask_04(struct libwebsocket *wsi, unsigned char c) -{ - c ^= wsi->masking_key_04[wsi->frame_mask_index++]; - if (wsi->frame_mask_index == 20) - wsi->frame_mask_index = 0; - - return c; -} - -unsigned char -xor_mask_05(struct libwebsocket *wsi, unsigned char c) -{ - return c ^ wsi->frame_masking_nonce_04[(wsi->frame_mask_index++) & 3]; -} /** * lws_frame_is_binary: true if the current frame was sent in binary mode @@ -603,7 +580,6 @@ int libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c) { int n; - unsigned char buf[20 + 4]; struct lws_tokens eff_buf; #ifndef LWS_NO_EXTENSIONS int handled; @@ -618,27 +594,6 @@ libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c) case LWS_RXPS_NEW: switch (wsi->ietf_spec_revision) { - /* Firefox 4.0b6 likes this as of 30 Oct 2010 */ - case 0: - if (c == 0xff) - wsi->lws_rx_parse_state = LWS_RXPS_SEEN_76_FF; - if (c == 0) { - wsi->lws_rx_parse_state = - LWS_RXPS_EAT_UNTIL_76_FF; - wsi->rx_user_buffer_head = 0; - } - break; - case 4: - case 5: - case 6: - wsi->all_zero_nonce = 1; - wsi->frame_masking_nonce_04[0] = c; - if (c) - wsi->all_zero_nonce = 0; - wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_1; - break; - case 7: - case 8: case 13: /* * no prepended frame key any more @@ -669,37 +624,6 @@ libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c) if (c) wsi->all_zero_nonce = 0; - if (wsi->protocol->owning_server->options & - LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK) - goto post_mask; - - if (wsi->ietf_spec_revision > 4) - goto post_sha1; - - /* - * we are able to compute the frame key now - * it's a SHA1 of ( frame nonce we were just sent, concatenated - * with the connection masking key we computed at handshake - * time ) -- yeah every frame from the client invokes a SHA1 - * for no real reason so much for lightweight. - */ - - buf[0] = wsi->frame_masking_nonce_04[0]; - buf[1] = wsi->frame_masking_nonce_04[1]; - buf[2] = wsi->frame_masking_nonce_04[2]; - buf[3] = wsi->frame_masking_nonce_04[3]; - - memcpy(buf + 4, wsi->masking_key_04, 20); - - /* - * wsi->frame_mask_04 will be our recirculating 20-byte XOR key - * for this frame - */ - - SHA1((unsigned char *)buf, 4 + 20, wsi->frame_mask_04); - -post_sha1: - /* * start from the zero'th byte in the XOR key buffer since * this is the start of a frame with a new key @@ -707,7 +631,6 @@ post_sha1: wsi->frame_mask_index = 0; -post_mask: wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_1; break; @@ -761,38 +684,8 @@ handle_first: * FIN (b7) */ - if (wsi->ietf_spec_revision < 7) - c = wsi->xor_mask(wsi, c); - - /* translate all incoming opcodes into v7+ map */ - if (wsi->ietf_spec_revision < 7) - switch (c & 0xf) { - case LWS_WS_OPCODE_04__CONTINUATION: - wsi->opcode = LWS_WS_OPCODE_07__CONTINUATION; - break; - case LWS_WS_OPCODE_04__CLOSE: - wsi->opcode = LWS_WS_OPCODE_07__CLOSE; - break; - case LWS_WS_OPCODE_04__PING: - wsi->opcode = LWS_WS_OPCODE_07__PING; - break; - case LWS_WS_OPCODE_04__PONG: - wsi->opcode = LWS_WS_OPCODE_07__PONG; - break; - case LWS_WS_OPCODE_04__TEXT_FRAME: - wsi->opcode = LWS_WS_OPCODE_07__TEXT_FRAME; - break; - case LWS_WS_OPCODE_04__BINARY_FRAME: - wsi->opcode = LWS_WS_OPCODE_07__BINARY_FRAME; - break; - default: - lwsl_warn("reserved opcodes not " - "usable pre v7 protocol\n"); - return -1; - } - else - wsi->opcode = c & 0xf; - wsi->rsv = (c & 0x70); + wsi->opcode = c & 0xf; + wsi->rsv = c & 0x70; wsi->final = !!((c >> 7) & 1); switch (wsi->opcode) { case LWS_WS_OPCODE_07__TEXT_FRAME: @@ -805,15 +698,6 @@ handle_first: case LWS_RXPS_04_FRAME_HDR_LEN: - if (wsi->ietf_spec_revision < 7) - c = wsi->xor_mask(wsi, c); - - if ((c & 0x80) && wsi->ietf_spec_revision < 7) { - lwsl_warn("Frame has extensions set illegally 2\n"); - /* kill the connection */ - return -1; - } - wsi->this_frame_masked = !!(c & 0x80); switch (c & 0x7f) { @@ -844,17 +728,11 @@ handle_first: break; case LWS_RXPS_04_FRAME_HDR_LEN16_2: - if (wsi->ietf_spec_revision < 7) - c = wsi->xor_mask(wsi, c); - wsi->rx_packet_length = c << 8; wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1; break; case LWS_RXPS_04_FRAME_HDR_LEN16_1: - if (wsi->ietf_spec_revision < 7) - c = wsi->xor_mask(wsi, c); - wsi->rx_packet_length |= c; if (wsi->this_frame_masked) wsi->lws_rx_parse_state = @@ -865,8 +743,6 @@ handle_first: break; case LWS_RXPS_04_FRAME_HDR_LEN64_8: - if (wsi->ietf_spec_revision < 7) - c = wsi->xor_mask(wsi, c); if (c & 0x80) { lwsl_warn("b63 of length must be zero\n"); /* kill the connection */ @@ -881,8 +757,6 @@ handle_first: break; case LWS_RXPS_04_FRAME_HDR_LEN64_7: - if (wsi->ietf_spec_revision < 7) - c = wsi->xor_mask(wsi, c); #if defined __LP64__ wsi->rx_packet_length |= ((size_t)c) << 48; #endif @@ -890,8 +764,6 @@ handle_first: break; case LWS_RXPS_04_FRAME_HDR_LEN64_6: - if (wsi->ietf_spec_revision < 7) - c = wsi->xor_mask(wsi, c); #if defined __LP64__ wsi->rx_packet_length |= ((size_t)c) << 40; #endif @@ -899,8 +771,6 @@ handle_first: break; case LWS_RXPS_04_FRAME_HDR_LEN64_5: - if (wsi->ietf_spec_revision < 7) - c = wsi->xor_mask(wsi, c); #if defined __LP64__ wsi->rx_packet_length |= ((size_t)c) << 32; #endif @@ -908,29 +778,21 @@ handle_first: break; case LWS_RXPS_04_FRAME_HDR_LEN64_4: - if (wsi->ietf_spec_revision < 7) - c = wsi->xor_mask(wsi, c); wsi->rx_packet_length |= ((size_t)c) << 24; wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3; break; case LWS_RXPS_04_FRAME_HDR_LEN64_3: - if (wsi->ietf_spec_revision < 7) - c = wsi->xor_mask(wsi, c); wsi->rx_packet_length |= ((size_t)c) << 16; wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2; break; case LWS_RXPS_04_FRAME_HDR_LEN64_2: - if (wsi->ietf_spec_revision < 7) - c = wsi->xor_mask(wsi, c); wsi->rx_packet_length |= ((size_t)c) << 8; wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1; break; case LWS_RXPS_04_FRAME_HDR_LEN64_1: - if (wsi->ietf_spec_revision < 7) - c = wsi->xor_mask(wsi, c); wsi->rx_packet_length |= ((size_t)c); if (wsi->this_frame_masked) wsi->lws_rx_parse_state = @@ -940,48 +802,6 @@ handle_first: LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; break; - case LWS_RXPS_EAT_UNTIL_76_FF: - - if (c == 0xff) { - wsi->lws_rx_parse_state = LWS_RXPS_NEW; - goto issue; - } - wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + - (wsi->rx_user_buffer_head++)] = c; - - if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER) - break; -issue: - if (wsi->protocol->callback) - user_callback_handle_rxflow(wsi->protocol->callback, - wsi->protocol->owning_server, - wsi, LWS_CALLBACK_RECEIVE, - wsi->user_space, - &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING], - wsi->rx_user_buffer_head); - wsi->rx_user_buffer_head = 0; - break; - case LWS_RXPS_SEEN_76_FF: - if (c) - break; - - lwsl_parser("Seen that client is requesting " - "a v76 close, sending ack\n"); - buf[0] = 0xff; - buf[1] = 0; - n = libwebsocket_write(wsi, buf, 2, LWS_WRITE_HTTP); - if (n < 0) { - lwsl_warn("ERROR writing to socket"); - return -1; - } - lwsl_parser(" v76 close ack sent, server closing skt\n"); - /* returning < 0 will get it closed in parent */ - return -1; - - case LWS_RXPS_PULLING_76_LENGTH: - break; - - case LWS_RXPS_07_COLLECT_FRAME_KEY_1: wsi->frame_masking_nonce_04[0] = c; if (c) @@ -1015,14 +835,13 @@ issue: case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED: - if (wsi->ietf_spec_revision < 4 || - (wsi->all_zero_nonce && wsi->ietf_spec_revision >= 5)) + if (wsi->all_zero_nonce) wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + (wsi->rx_user_buffer_head++)] = c; else wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + (wsi->rx_user_buffer_head++)] = - wsi->xor_mask(wsi, c); + c ^ wsi->frame_masking_nonce_04[(wsi->frame_mask_index++) & 3]; if (--wsi->rx_packet_length == 0) { wsi->lws_rx_parse_state = LWS_RXPS_NEW; diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 526a788..42c8995 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -144,26 +144,6 @@ */ #define LWS_LISTEN_SERVICE_MODULO 10 -enum lws_websocket_opcodes_04 { - LWS_WS_OPCODE_04__CONTINUATION = 0, - LWS_WS_OPCODE_04__CLOSE = 1, - LWS_WS_OPCODE_04__PING = 2, - LWS_WS_OPCODE_04__PONG = 3, - LWS_WS_OPCODE_04__TEXT_FRAME = 4, - LWS_WS_OPCODE_04__BINARY_FRAME = 5, - - LWS_WS_OPCODE_04__RESERVED_6 = 6, - LWS_WS_OPCODE_04__RESERVED_7 = 7, - LWS_WS_OPCODE_04__RESERVED_8 = 8, - LWS_WS_OPCODE_04__RESERVED_9 = 9, - LWS_WS_OPCODE_04__RESERVED_A = 0xa, - LWS_WS_OPCODE_04__RESERVED_B = 0xb, - LWS_WS_OPCODE_04__RESERVED_C = 0xc, - LWS_WS_OPCODE_04__RESERVED_D = 0xd, - LWS_WS_OPCODE_04__RESERVED_E = 0xe, - LWS_WS_OPCODE_04__RESERVED_F = 0xf, -}; - enum lws_websocket_opcodes_07 { LWS_WS_OPCODE_07__CONTINUATION = 0, LWS_WS_OPCODE_07__TEXT_FRAME = 1, @@ -193,10 +173,6 @@ enum lws_connection_states { enum lws_rx_parse_state { LWS_RXPS_NEW, - LWS_RXPS_SEEN_76_FF, - LWS_RXPS_PULLING_76_LENGTH, - LWS_RXPS_EAT_UNTIL_76_FF, - LWS_RXPS_04_MASK_NONCE_1, LWS_RXPS_04_MASK_NONCE_2, LWS_RXPS_04_MASK_NONCE_3, @@ -350,7 +326,6 @@ struct libwebsocket { int frame_is_binary:1; int pings_vs_pongs; - unsigned char (*xor_mask)(struct libwebsocket *, unsigned char); char all_zero_nonce; enum lws_close_status close_reason; @@ -405,15 +380,6 @@ libwebsocket_read(struct libwebsocket_context *context, extern int lws_b64_selftest(void); -extern unsigned char -xor_no_mask(struct libwebsocket *wsi, unsigned char c); - -extern unsigned char -xor_mask_04(struct libwebsocket *wsi, unsigned char c); - -extern unsigned char -xor_mask_05(struct libwebsocket *wsi, unsigned char c); - extern struct libwebsocket * wsi_from_fd(struct libwebsocket_context *context, int fd); diff --git a/lib/server-handshake.c b/lib/server-handshake.c index 1fdb332..2a0e886 100644 --- a/lib/server-handshake.c +++ b/lib/server-handshake.c @@ -25,184 +25,6 @@ #define LWS_CPYAPP_TOKEN(ptr, tok) { strcpy(p, wsi->utf8_token[tok].token); \ p += wsi->utf8_token[tok].token_len; } -static int -interpret_key(const char *key, unsigned long *result) -{ - char digits[20]; - int digit_pos = 0; - const char *p = key; - unsigned int spaces = 0; - unsigned long acc = 0; - int rem = 0; - - while (*p) { - if (!isdigit(*p)) { - p++; - continue; - } - if (digit_pos == sizeof(digits) - 1) - return -1; - digits[digit_pos++] = *p++; - } - digits[digit_pos] = '\0'; - if (!digit_pos) - return -2; - - while (*key) { - if (*key == ' ') - spaces++; - key++; - } - - if (!spaces) - return -3; - - p = &digits[0]; - while (*p) { - rem = (rem * 10) + ((*p++) - '0'); - acc = (acc * 10) + (rem / spaces); - rem -= (rem / spaces) * spaces; - } - - if (rem) { - lwsl_warn("nonzero handshake remainder\n"); - return -1; - } - - *result = acc; - - return 0; -} - - -int handshake_00(struct libwebsocket_context *context, struct libwebsocket *wsi) -{ - unsigned long key1, key2; - unsigned char sum[16]; - char *response; - char *p; - int n; - - /* Confirm we have all the necessary pieces */ - - if (!wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len || - !wsi->utf8_token[WSI_TOKEN_HOST].token_len || - !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len || - !wsi->utf8_token[WSI_TOKEN_KEY1].token_len || - !wsi->utf8_token[WSI_TOKEN_KEY2].token_len) - /* completed header processing, but missing some bits */ - goto bail; - - /* allocate the per-connection user memory (if any) */ - if (wsi->protocol->per_session_data_size && - !libwebsocket_ensure_user_space(wsi)) - goto bail; - - /* create the response packet */ - - /* make a buffer big enough for everything */ - - response = (char *)malloc(256 + - wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len + - wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len + - wsi->utf8_token[WSI_TOKEN_HOST].token_len + - wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len + - wsi->utf8_token[WSI_TOKEN_GET_URI].token_len + - wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len); - if (!response) { - lwsl_err("Out of memory for response buffer\n"); - goto bail; - } - - p = response; - LWS_CPYAPP(p, "HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a" - "Upgrade: WebSocket\x0d\x0a" - "Connection: Upgrade\x0d\x0a" - "Sec-WebSocket-Origin: "); - strcpy(p, wsi->utf8_token[WSI_TOKEN_ORIGIN].token); - p += wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len; -#ifdef LWS_OPENSSL_SUPPORT - if (wsi->ssl) { - LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: wss://"); - } else { - LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: ws://"); - } -#else - LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: ws://"); -#endif - - LWS_CPYAPP_TOKEN(p, WSI_TOKEN_HOST); - LWS_CPYAPP_TOKEN(p, WSI_TOKEN_GET_URI); - - if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) { - LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: "); - LWS_CPYAPP_TOKEN(p, WSI_TOKEN_PROTOCOL); - } - - LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a"); - - /* convert the two keys into 32-bit integers */ - - if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY1].token, &key1)) - goto bail; - if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY2].token, &key2)) - goto bail; - - /* lay them out in network byte order (MSB first */ - - sum[0] = (unsigned char)(key1 >> 24); - sum[1] = (unsigned char)(key1 >> 16); - sum[2] = (unsigned char)(key1 >> 8); - sum[3] = (unsigned char)(key1); - sum[4] = (unsigned char)(key2 >> 24); - sum[5] = (unsigned char)(key2 >> 16); - sum[6] = (unsigned char)(key2 >> 8); - sum[7] = (unsigned char)(key2); - - /* follow them with the challenge token we were sent */ - - memcpy(&sum[8], wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 8); - - /* - * compute the md5sum of that 16-byte series and use as our - * payload after our headers - */ - - MD5(sum, 16, (unsigned char *)p); - p += 16; - - /* it's complete: go ahead and send it */ - - lwsl_parser("issuing response packet %d len\n", (int)(p - response)); -#ifdef _DEBUG - fwrite(response, 1, p - response, stderr); -#endif - n = libwebsocket_write(wsi, (unsigned char *)response, - p - response, LWS_WRITE_HTTP); - if (n < 0) { - lwsl_debug("handshake_00: ERROR writing to socket\n"); - goto bail; - } - - /* alright clean up and set ourselves into established state */ - - free(response); - wsi->state = WSI_STATE_ESTABLISHED; - wsi->lws_rx_parse_state = LWS_RXPS_NEW; - - /* notify user code that we're ready to roll */ - - if (wsi->protocol->callback) - wsi->protocol->callback(wsi->protocol->owning_server, - wsi, LWS_CALLBACK_ESTABLISHED, - wsi->user_space, NULL, 0); - - return 0; - -bail: - return -1; -} - /* * Perform the newer BASE64-encoded handshake scheme */ @@ -212,17 +34,11 @@ handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi) { static const char *websocket_magic_guid_04 = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - static const char *websocket_magic_guid_04_masking = - "61AC5F19-FBBA-4540-B96F-6561F1AB40A8"; char accept_buf[MAX_WEBSOCKET_04_KEY_LEN + 37]; - char nonce_buf[256]; - char mask_summing_buf[256 + MAX_WEBSOCKET_04_KEY_LEN + 37]; unsigned char hash[20]; int n; char *response; char *p; - char *m = mask_summing_buf; - int nonce_len = 0; int accept_len; #ifndef LWS_NO_EXTENSIONS char *c; @@ -287,38 +103,6 @@ handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi) strcpy(p, accept_buf); p += accept_len; - if (wsi->ietf_spec_revision == 4) { - LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Nonce: "); - - /* select the nonce */ - - n = libwebsockets_get_random(wsi->protocol->owning_server, - hash, 16); - if (n != 16) { - lwsl_err("Unable to read random device %s %d\n", - SYSTEM_RANDOM_FILEPATH, n); - if (wsi->user_space) - free(wsi->user_space); - goto bail; - } - - /* encode the nonce */ - - nonce_len = lws_b64_encode_string((const char *)hash, 16, - nonce_buf, sizeof nonce_buf); - if (nonce_len < 0) { - lwsl_err("Failed to base 64 encode the nonce\n"); - if (wsi->user_space) - free(wsi->user_space); - goto bail; - } - - /* apply the nonce */ - - strcpy(p, nonce_buf); - p += nonce_len; - } - if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) { LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: "); LWS_CPYAPP_TOKEN(p, WSI_TOKEN_PROTOCOL); @@ -447,30 +231,6 @@ handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi) LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a"); - if (wsi->ietf_spec_revision == 4) { - - /* - * precompute the masking key the client will use from the SHA1 - * hash of ( base 64 client key we were sent, concatenated with - * the bse 64 nonce we sent, concatenated with a magic constant - * guid specified by the 04 standard ) - * - * We store the hash in the connection's wsi ready to use with - * undoing the masking the client has done on framed data it - * sends (we send our data to the client in clear). - */ - - strcpy(mask_summing_buf, wsi->utf8_token[WSI_TOKEN_KEY].token); - m += wsi->utf8_token[WSI_TOKEN_KEY].token_len; - strcpy(m, nonce_buf); - m += nonce_len; - strcpy(m, websocket_magic_guid_04_masking); - m += strlen(websocket_magic_guid_04_masking); - - SHA1((unsigned char *)mask_summing_buf, m - mask_summing_buf, - wsi->masking_key_04); - } - #ifndef LWS_NO_EXTENSIONS if (!lws_any_extension_handled(context, wsi, LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX, diff --git a/test-server/test-client.c b/test-server/test-client.c index 348196b..b556a17 100644 --- a/test-server/test-client.c +++ b/test-server/test-client.c @@ -184,7 +184,6 @@ static struct option options[] = { { "debug", required_argument, NULL, 'd' }, { "port", required_argument, NULL, 'p' }, { "ssl", no_argument, NULL, 's' }, - { "killmask", no_argument, NULL, 'k' }, { "version", required_argument, NULL, 'v' }, { "undeflated", no_argument, NULL, 'u' }, { "nomux", no_argument, NULL, 'n' }, @@ -213,7 +212,7 @@ int main(int argc, char **argv) goto usage; while (n >= 0) { - n = getopt_long(argc, argv, "nuv:khsp:d:l", options, NULL); + n = getopt_long(argc, argv, "nuv:hsp:d:l", options, NULL); if (n < 0) continue; switch (n) { @@ -229,9 +228,6 @@ int main(int argc, char **argv) case 'l': longlived = 1; break; - case 'k': - opts = LWS_WRITE_CLIENT_IGNORE_XOR_MASK; - break; case 'v': ietf_version = atoi(optarg); break; diff --git a/test-server/test-fraggle.c b/test-server/test-fraggle.c index abff7bc..f2c8d7c 100644 --- a/test-server/test-fraggle.c +++ b/test-server/test-fraggle.c @@ -231,7 +231,6 @@ static struct option options[] = { { "debug", required_argument, NULL, 'd' }, { "port", required_argument, NULL, 'p' }, { "ssl", no_argument, NULL, 's' }, - { "killmask", no_argument, NULL, 'k' }, { "interface", required_argument, NULL, 'i' }, { "client", no_argument, NULL, 'c' }, { NULL, 0, 0, 0 } @@ -255,11 +254,11 @@ int main(int argc, char **argv) int server_port = port; fprintf(stderr, "libwebsockets test fraggle\n" - "(C) Copyright 2010-2011 Andy Green " + "(C) Copyright 2010-2013 Andy Green " "licensed under LGPL2.1\n"); while (n >= 0) { - n = getopt_long(argc, argv, "ci:khsp:d:", options, NULL); + n = getopt_long(argc, argv, "ci:hsp:d:", options, NULL); if (n < 0) continue; switch (n) { @@ -269,9 +268,6 @@ int main(int argc, char **argv) case 's': use_ssl = 1; break; - case 'k': - opts = LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK; - break; case 'p': port = atoi(optarg); server_port = port; diff --git a/test-server/test-server.c b/test-server/test-server.c index 51b65ce..c98fe0f 100644 --- a/test-server/test-server.c +++ b/test-server/test-server.c @@ -489,7 +489,6 @@ static struct option options[] = { { "debug", required_argument, NULL, 'd' }, { "port", required_argument, NULL, 'p' }, { "ssl", no_argument, NULL, 's' }, - { "killmask", no_argument, NULL, 'k' }, { "interface", required_argument, NULL, 'i' }, { "closetest", no_argument, NULL, 'c' }, #ifndef NO_DAEMONIZE @@ -523,7 +522,7 @@ int main(int argc, char **argv) #endif while (n >= 0) { - n = getopt_long(argc, argv, "ci:khsp:d:D", options, NULL); + n = getopt_long(argc, argv, "ci:hsp:d:D", options, NULL); if (n < 0) continue; switch (n) { @@ -539,9 +538,6 @@ int main(int argc, char **argv) case 's': use_ssl = 1; break; - case 'k': - opts = LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK; - break; case 'p': port = atoi(optarg); break; -- 2.7.4