1 /* 2 * QEMU VNC display driver: Websockets support 3 * 4 * Copyright (C) 2010 Joel Martin 5 * Copyright (C) 2012 Tim Hardeck 6 * 7 * This is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This software is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this software; if not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #include "vnc.h" 22 #include "qemu/main-loop.h" 23 #include "crypto/hash.h" 24 25 static int vncws_start_tls_handshake(VncState *vs) 26 { 27 Error *err = NULL; 28 29 if (qcrypto_tls_session_handshake(vs->tls, &err) < 0) { 30 goto error; 31 } 32 33 switch (qcrypto_tls_session_get_handshake_status(vs->tls)) { 34 case QCRYPTO_TLS_HANDSHAKE_COMPLETE: 35 VNC_DEBUG("Handshake done, checking credentials\n"); 36 if (qcrypto_tls_session_check_credentials(vs->tls, &err) < 0) { 37 goto error; 38 } 39 VNC_DEBUG("Client verification passed, starting TLS I/O\n"); 40 qemu_set_fd_handler(vs->csock, vncws_handshake_read, NULL, vs); 41 break; 42 43 case QCRYPTO_TLS_HANDSHAKE_RECVING: 44 VNC_DEBUG("Handshake interrupted (blocking read)\n"); 45 qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io, NULL, vs); 46 break; 47 48 case QCRYPTO_TLS_HANDSHAKE_SENDING: 49 VNC_DEBUG("Handshake interrupted (blocking write)\n"); 50 qemu_set_fd_handler(vs->csock, NULL, vncws_tls_handshake_io, vs); 51 break; 52 } 53 54 return 0; 55 56 error: 57 VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err)); 58 error_free(err); 59 vnc_client_error(vs); 60 return -1; 61 } 62 63 void vncws_tls_handshake_io(void *opaque) 64 { 65 VncState *vs = (VncState *)opaque; 66 Error *err = NULL; 67 68 vs->tls = qcrypto_tls_session_new(vs->vd->tlscreds, 69 NULL, 70 vs->vd->tlsaclname, 71 QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, 72 &err); 73 if (!vs->tls) { 74 VNC_DEBUG("Failed to setup TLS %s\n", 75 error_get_pretty(err)); 76 error_free(err); 77 vnc_client_error(vs); 78 return; 79 } 80 81 qcrypto_tls_session_set_callbacks(vs->tls, 82 vnc_tls_push, 83 vnc_tls_pull, 84 vs); 85 86 VNC_DEBUG("Start TLS WS handshake process\n"); 87 vncws_start_tls_handshake(vs); 88 } 89 90 void vncws_handshake_read(void *opaque) 91 { 92 VncState *vs = opaque; 93 uint8_t *handshake_end; 94 long ret; 95 /* Typical HTTP headers from novnc are 512 bytes, so limiting 96 * total header size to 4096 is easily enough. */ 97 size_t want = 4096 - vs->ws_input.offset; 98 buffer_reserve(&vs->ws_input, want); 99 ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), want); 100 101 if (!ret) { 102 if (vs->csock == -1) { 103 vnc_disconnect_finish(vs); 104 } 105 return; 106 } 107 vs->ws_input.offset += ret; 108 109 handshake_end = (uint8_t *)g_strstr_len((char *)vs->ws_input.buffer, 110 vs->ws_input.offset, WS_HANDSHAKE_END); 111 if (handshake_end) { 112 qemu_set_fd_handler(vs->csock, vnc_client_read, NULL, vs); 113 vncws_process_handshake(vs, vs->ws_input.buffer, vs->ws_input.offset); 114 buffer_advance(&vs->ws_input, handshake_end - vs->ws_input.buffer + 115 strlen(WS_HANDSHAKE_END)); 116 } else if (vs->ws_input.offset >= 4096) { 117 VNC_DEBUG("End of headers not found in first 4096 bytes\n"); 118 vnc_client_error(vs); 119 } 120 } 121 122 123 long vnc_client_read_ws(VncState *vs) 124 { 125 int ret, err; 126 uint8_t *payload; 127 size_t payload_size, header_size; 128 VNC_DEBUG("Read websocket %p size %zd offset %zd\n", vs->ws_input.buffer, 129 vs->ws_input.capacity, vs->ws_input.offset); 130 buffer_reserve(&vs->ws_input, 4096); 131 ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), 4096); 132 if (!ret) { 133 return 0; 134 } 135 vs->ws_input.offset += ret; 136 137 ret = 0; 138 /* consume as much of ws_input buffer as possible */ 139 do { 140 if (vs->ws_payload_remain == 0) { 141 err = vncws_decode_frame_header(&vs->ws_input, 142 &header_size, 143 &vs->ws_payload_remain, 144 &vs->ws_payload_mask); 145 if (err <= 0) { 146 return err; 147 } 148 149 buffer_advance(&vs->ws_input, header_size); 150 } 151 if (vs->ws_payload_remain != 0) { 152 err = vncws_decode_frame_payload(&vs->ws_input, 153 &vs->ws_payload_remain, 154 &vs->ws_payload_mask, 155 &payload, 156 &payload_size); 157 if (err < 0) { 158 return err; 159 } 160 if (err == 0) { 161 return ret; 162 } 163 ret += err; 164 165 buffer_reserve(&vs->input, payload_size); 166 buffer_append(&vs->input, payload, payload_size); 167 168 buffer_advance(&vs->ws_input, payload_size); 169 } 170 } while (vs->ws_input.offset > 0); 171 172 return ret; 173 } 174 175 long vnc_client_write_ws(VncState *vs) 176 { 177 long ret; 178 VNC_DEBUG("Write WS: Pending output %p size %zd offset %zd\n", 179 vs->output.buffer, vs->output.capacity, vs->output.offset); 180 vncws_encode_frame(&vs->ws_output, vs->output.buffer, vs->output.offset); 181 buffer_reset(&vs->output); 182 ret = vnc_client_write_buf(vs, vs->ws_output.buffer, vs->ws_output.offset); 183 if (!ret) { 184 return 0; 185 } 186 187 buffer_advance(&vs->ws_output, ret); 188 189 if (vs->ws_output.offset == 0) { 190 qemu_set_fd_handler(vs->csock, vnc_client_read, NULL, vs); 191 } 192 193 return ret; 194 } 195 196 static char *vncws_extract_handshake_entry(const char *handshake, 197 size_t handshake_len, const char *name) 198 { 199 char *begin, *end, *ret = NULL; 200 char *line = g_strdup_printf("%s%s: ", WS_HANDSHAKE_DELIM, name); 201 begin = g_strstr_len(handshake, handshake_len, line); 202 if (begin != NULL) { 203 begin += strlen(line); 204 end = g_strstr_len(begin, handshake_len - (begin - handshake), 205 WS_HANDSHAKE_DELIM); 206 if (end != NULL) { 207 ret = g_strndup(begin, end - begin); 208 } 209 } 210 g_free(line); 211 return ret; 212 } 213 214 static void vncws_send_handshake_response(VncState *vs, const char* key) 215 { 216 char combined_key[WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1]; 217 char *accept = NULL, *response = NULL; 218 Error *err = NULL; 219 220 g_strlcpy(combined_key, key, WS_CLIENT_KEY_LEN + 1); 221 g_strlcat(combined_key, WS_GUID, WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1); 222 223 /* hash and encode it */ 224 if (qcrypto_hash_base64(QCRYPTO_HASH_ALG_SHA1, 225 combined_key, 226 WS_CLIENT_KEY_LEN + WS_GUID_LEN, 227 &accept, 228 &err) < 0) { 229 VNC_DEBUG("Hashing Websocket combined key failed %s\n", 230 error_get_pretty(err)); 231 error_free(err); 232 vnc_client_error(vs); 233 return; 234 } 235 236 response = g_strdup_printf(WS_HANDSHAKE, accept); 237 vnc_client_write_buf(vs, (const uint8_t *)response, strlen(response)); 238 239 g_free(accept); 240 g_free(response); 241 242 vs->encode_ws = 1; 243 vnc_init_state(vs); 244 } 245 246 void vncws_process_handshake(VncState *vs, uint8_t *line, size_t size) 247 { 248 char *protocols = vncws_extract_handshake_entry((const char *)line, size, 249 "Sec-WebSocket-Protocol"); 250 char *version = vncws_extract_handshake_entry((const char *)line, size, 251 "Sec-WebSocket-Version"); 252 char *key = vncws_extract_handshake_entry((const char *)line, size, 253 "Sec-WebSocket-Key"); 254 255 if (protocols && version && key 256 && g_strrstr(protocols, "binary") 257 && !strcmp(version, WS_SUPPORTED_VERSION) 258 && strlen(key) == WS_CLIENT_KEY_LEN) { 259 vncws_send_handshake_response(vs, key); 260 } else { 261 VNC_DEBUG("Defective Websockets header or unsupported protocol\n"); 262 vnc_client_error(vs); 263 } 264 265 g_free(protocols); 266 g_free(version); 267 g_free(key); 268 } 269 270 void vncws_encode_frame(Buffer *output, const void *payload, 271 const size_t payload_size) 272 { 273 size_t header_size = 0; 274 unsigned char opcode = WS_OPCODE_BINARY_FRAME; 275 union { 276 char buf[WS_HEAD_MAX_LEN]; 277 WsHeader ws; 278 } header; 279 280 if (!payload_size) { 281 return; 282 } 283 284 header.ws.b0 = 0x80 | (opcode & 0x0f); 285 if (payload_size <= 125) { 286 header.ws.b1 = (uint8_t)payload_size; 287 header_size = 2; 288 } else if (payload_size < 65536) { 289 header.ws.b1 = 0x7e; 290 header.ws.u.s16.l16 = cpu_to_be16((uint16_t)payload_size); 291 header_size = 4; 292 } else { 293 header.ws.b1 = 0x7f; 294 header.ws.u.s64.l64 = cpu_to_be64(payload_size); 295 header_size = 10; 296 } 297 298 buffer_reserve(output, header_size + payload_size); 299 buffer_append(output, header.buf, header_size); 300 buffer_append(output, payload, payload_size); 301 } 302 303 int vncws_decode_frame_header(Buffer *input, 304 size_t *header_size, 305 size_t *payload_remain, 306 WsMask *payload_mask) 307 { 308 unsigned char opcode = 0, fin = 0, has_mask = 0; 309 size_t payload_len; 310 WsHeader *header = (WsHeader *)input->buffer; 311 312 if (input->offset < WS_HEAD_MIN_LEN + 4) { 313 /* header not complete */ 314 return 0; 315 } 316 317 fin = (header->b0 & 0x80) >> 7; 318 opcode = header->b0 & 0x0f; 319 has_mask = (header->b1 & 0x80) >> 7; 320 payload_len = header->b1 & 0x7f; 321 322 if (opcode == WS_OPCODE_CLOSE) { 323 /* disconnect */ 324 return -1; 325 } 326 327 /* Websocket frame sanity check: 328 * * Websocket fragmentation is not supported. 329 * * All websockets frames sent by a client have to be masked. 330 * * Only binary encoding is supported. 331 */ 332 if (!fin || !has_mask || opcode != WS_OPCODE_BINARY_FRAME) { 333 VNC_DEBUG("Received faulty/unsupported Websocket frame\n"); 334 return -2; 335 } 336 337 if (payload_len < 126) { 338 *payload_remain = payload_len; 339 *header_size = 6; 340 *payload_mask = header->u.m; 341 } else if (payload_len == 126 && input->offset >= 8) { 342 *payload_remain = be16_to_cpu(header->u.s16.l16); 343 *header_size = 8; 344 *payload_mask = header->u.s16.m16; 345 } else if (payload_len == 127 && input->offset >= 14) { 346 *payload_remain = be64_to_cpu(header->u.s64.l64); 347 *header_size = 14; 348 *payload_mask = header->u.s64.m64; 349 } else { 350 /* header not complete */ 351 return 0; 352 } 353 354 return 1; 355 } 356 357 int vncws_decode_frame_payload(Buffer *input, 358 size_t *payload_remain, WsMask *payload_mask, 359 uint8_t **payload, size_t *payload_size) 360 { 361 size_t i; 362 uint32_t *payload32; 363 364 *payload = input->buffer; 365 /* If we aren't at the end of the payload, then drop 366 * off the last bytes, so we're always multiple of 4 367 * for purpose of unmasking, except at end of payload 368 */ 369 if (input->offset < *payload_remain) { 370 *payload_size = input->offset - (input->offset % 4); 371 } else { 372 *payload_size = *payload_remain; 373 } 374 if (*payload_size == 0) { 375 return 0; 376 } 377 *payload_remain -= *payload_size; 378 379 /* unmask frame */ 380 /* process 1 frame (32 bit op) */ 381 payload32 = (uint32_t *)(*payload); 382 for (i = 0; i < *payload_size / 4; i++) { 383 payload32[i] ^= payload_mask->u; 384 } 385 /* process the remaining bytes (if any) */ 386 for (i *= 4; i < *payload_size; i++) { 387 (*payload)[i] ^= payload_mask->c[i % 4]; 388 } 389 390 return 1; 391 } 392