1 /* 2 * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 * "Software"), to deal in the Software without restriction, including 7 * without limitation the rights to use, copy, modify, merge, publish, 8 * distribute, sublicense, and/or sell copies of the Software, and to 9 * permit persons to whom the Software is furnished to do so, subject to 10 * the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <stdint.h> 29 #include <errno.h> 30 31 #ifdef _WIN32 32 #include <winsock2.h> 33 #include <ws2tcpip.h> 34 #else 35 #include <sys/types.h> 36 #include <sys/socket.h> 37 #include <netdb.h> 38 #include <netinet/in.h> 39 #include <arpa/inet.h> 40 #include <unistd.h> 41 #include <fcntl.h> 42 #include <poll.h> 43 44 #define SOCKET int 45 #define INVALID_SOCKET (-1) 46 #endif 47 48 #include "brssl.h" 49 50 static void 51 dump_blob(const char *name, const void *data, size_t len) 52 { 53 const unsigned char *buf; 54 size_t u; 55 56 buf = data; 57 fprintf(stderr, "%s (len = %lu)", name, (unsigned long)len); 58 for (u = 0; u < len; u ++) { 59 if ((u & 15) == 0) { 60 fprintf(stderr, "\n%08lX ", (unsigned long)u); 61 } else if ((u & 7) == 0) { 62 fprintf(stderr, " "); 63 } 64 fprintf(stderr, " %02x", buf[u]); 65 } 66 fprintf(stderr, "\n"); 67 } 68 69 /* 70 * Inspect the provided data in case it is a "command" to trigger a 71 * special behaviour. If the command is recognised, then it is executed 72 * and this function returns 1. Otherwise, this function returns 0. 73 */ 74 static int 75 run_command(br_ssl_engine_context *cc, unsigned char *buf, size_t len) 76 { 77 /* 78 * A single static slot for saving session parameters. 79 */ 80 static br_ssl_session_parameters slot; 81 static int slot_used = 0; 82 83 size_t u; 84 85 if (len < 2 || len > 3) { 86 return 0; 87 } 88 if (len == 3 && (buf[1] != '\r' || buf[2] != '\n')) { 89 return 0; 90 } 91 if (len == 2 && buf[1] != '\n') { 92 return 0; 93 } 94 switch (buf[0]) { 95 case 'Q': 96 fprintf(stderr, "closing...\n"); 97 br_ssl_engine_close(cc); 98 return 1; 99 case 'R': 100 if (br_ssl_engine_renegotiate(cc)) { 101 fprintf(stderr, "renegotiating...\n"); 102 } else { 103 fprintf(stderr, "not renegotiating.\n"); 104 } 105 return 1; 106 case 'F': 107 /* 108 * Session forget is nominally client-only. But the 109 * session parameters are in the engine structure, which 110 * is the first field of the client context, so the cast 111 * still works properly. On the server, this forgetting 112 * has no effect. 113 */ 114 fprintf(stderr, "forgetting session...\n"); 115 br_ssl_client_forget_session((br_ssl_client_context *)cc); 116 return 1; 117 case 'S': 118 fprintf(stderr, "saving session parameters...\n"); 119 br_ssl_engine_get_session_parameters(cc, &slot); 120 fprintf(stderr, " id = "); 121 for (u = 0; u < slot.session_id_len; u ++) { 122 fprintf(stderr, "%02X", slot.session_id[u]); 123 } 124 fprintf(stderr, "\n"); 125 slot_used = 1; 126 return 1; 127 case 'P': 128 if (slot_used) { 129 fprintf(stderr, "restoring session parameters...\n"); 130 fprintf(stderr, " id = "); 131 for (u = 0; u < slot.session_id_len; u ++) { 132 fprintf(stderr, "%02X", slot.session_id[u]); 133 } 134 fprintf(stderr, "\n"); 135 br_ssl_engine_set_session_parameters(cc, &slot); 136 return 1; 137 } 138 return 0; 139 default: 140 return 0; 141 } 142 } 143 144 #ifdef _WIN32 145 146 typedef struct { 147 unsigned char buf[1024]; 148 size_t ptr, len; 149 } in_buffer; 150 151 static int 152 in_return_bytes(in_buffer *bb, unsigned char *buf, size_t len) 153 { 154 if (bb->ptr < bb->len) { 155 size_t clen; 156 157 if (buf == NULL) { 158 return 1; 159 } 160 clen = bb->len - bb->ptr; 161 if (clen > len) { 162 clen = len; 163 } 164 memcpy(buf, bb->buf + bb->ptr, clen); 165 bb->ptr += clen; 166 if (bb->ptr == bb->len) { 167 bb->ptr = bb->len = 0; 168 } 169 return (int)clen; 170 } 171 return 0; 172 } 173 174 /* 175 * A buffered version of in_read(), using a buffer to return only 176 * full lines when feasible. 177 */ 178 static int 179 in_read_buffered(HANDLE h_in, in_buffer *bb, unsigned char *buf, size_t len) 180 { 181 int n; 182 183 if (len == 0) { 184 return 0; 185 } 186 n = in_return_bytes(bb, buf, len); 187 if (n != 0) { 188 return n; 189 } 190 for (;;) { 191 INPUT_RECORD inrec; 192 DWORD v; 193 194 if (!PeekConsoleInput(h_in, &inrec, 1, &v)) { 195 fprintf(stderr, "ERROR: PeekConsoleInput()" 196 " failed with 0x%08lX\n", 197 (unsigned long)GetLastError()); 198 return -1; 199 } 200 if (v == 0) { 201 return 0; 202 } 203 if (!ReadConsoleInput(h_in, &inrec, 1, &v)) { 204 fprintf(stderr, "ERROR: ReadConsoleInput()" 205 " failed with 0x%08lX\n", 206 (unsigned long)GetLastError()); 207 return -1; 208 } 209 if (v == 0) { 210 return 0; 211 } 212 if (inrec.EventType == KEY_EVENT 213 && inrec.Event.KeyEvent.bKeyDown) 214 { 215 int c; 216 217 c = inrec.Event.KeyEvent.uChar.AsciiChar; 218 if (c == '\n' || c == '\r' || c == '\t' 219 || (c >= 32 && c != 127)) 220 { 221 if (c == '\r') { 222 c = '\n'; 223 } 224 bb->buf[bb->ptr ++] = (unsigned char)c; 225 printf("%c", c); 226 fflush(stdout); 227 bb->len = bb->ptr; 228 if (bb->len == sizeof bb->buf || c == '\n') { 229 bb->ptr = 0; 230 return in_return_bytes(bb, buf, len); 231 } 232 } 233 } 234 } 235 } 236 237 static int 238 in_avail_buffered(HANDLE h_in, in_buffer *bb) 239 { 240 return in_read_buffered(h_in, bb, NULL, 1); 241 } 242 243 #endif 244 245 /* see brssl.h */ 246 int 247 run_ssl_engine(br_ssl_engine_context *cc, unsigned long fd, unsigned flags) 248 { 249 int hsdetails; 250 int retcode; 251 int verbose; 252 int trace; 253 #ifdef _WIN32 254 WSAEVENT fd_event; 255 int can_send, can_recv; 256 HANDLE h_in, h_out; 257 in_buffer bb; 258 #endif 259 260 hsdetails = 0; 261 retcode = 0; 262 verbose = (flags & RUN_ENGINE_VERBOSE) != 0; 263 trace = (flags & RUN_ENGINE_TRACE) != 0; 264 265 /* 266 * Print algorithm details. 267 */ 268 if (verbose) { 269 const char *rngname; 270 271 fprintf(stderr, "Algorithms:\n"); 272 br_prng_seeder_system(&rngname); 273 fprintf(stderr, " RNG: %s\n", rngname); 274 if (cc->iaes_cbcenc != 0) { 275 fprintf(stderr, " AES/CBC (enc): %s\n", 276 get_algo_name(cc->iaes_cbcenc, 0)); 277 } 278 if (cc->iaes_cbcdec != 0) { 279 fprintf(stderr, " AES/CBC (dec): %s\n", 280 get_algo_name(cc->iaes_cbcdec, 0)); 281 } 282 if (cc->iaes_ctr != 0) { 283 fprintf(stderr, " AES/CTR: %s\n", 284 get_algo_name(cc->iaes_ctr, 0)); 285 } 286 if (cc->iaes_ctrcbc != 0) { 287 fprintf(stderr, " AES/CCM: %s\n", 288 get_algo_name(cc->iaes_ctrcbc, 0)); 289 } 290 if (cc->ides_cbcenc != 0) { 291 fprintf(stderr, " DES/CBC (enc): %s\n", 292 get_algo_name(cc->ides_cbcenc, 0)); 293 } 294 if (cc->ides_cbcdec != 0) { 295 fprintf(stderr, " DES/CBC (dec): %s\n", 296 get_algo_name(cc->ides_cbcdec, 0)); 297 } 298 if (cc->ighash != 0) { 299 fprintf(stderr, " GHASH (GCM): %s\n", 300 get_algo_name(cc->ighash, 0)); 301 } 302 if (cc->ichacha != 0) { 303 fprintf(stderr, " ChaCha20: %s\n", 304 get_algo_name(cc->ichacha, 0)); 305 } 306 if (cc->ipoly != 0) { 307 fprintf(stderr, " Poly1305: %s\n", 308 get_algo_name(cc->ipoly, 0)); 309 } 310 if (cc->iec != 0) { 311 fprintf(stderr, " EC: %s\n", 312 get_algo_name(cc->iec, 0)); 313 } 314 if (cc->iecdsa != 0) { 315 fprintf(stderr, " ECDSA: %s\n", 316 get_algo_name(cc->iecdsa, 0)); 317 } 318 if (cc->irsavrfy != 0) { 319 fprintf(stderr, " RSA (vrfy): %s\n", 320 get_algo_name(cc->irsavrfy, 0)); 321 } 322 } 323 324 #ifdef _WIN32 325 fd_event = WSA_INVALID_EVENT; 326 can_send = 0; 327 can_recv = 0; 328 bb.ptr = bb.len = 0; 329 #endif 330 331 /* 332 * On Unix systems, we need to follow three descriptors: 333 * standard input (0), standard output (1), and the socket 334 * itself (for both read and write). This is done with a poll() 335 * call. 336 * 337 * On Windows systems, we use WSAEventSelect() to associate 338 * an event handle with the network activity, and we use 339 * WaitForMultipleObjectsEx() on that handle and the standard 340 * input handle, when appropriate. Standard output is assumed 341 * to be always writeable, and standard input to be the console; 342 * this does not work well (or at all) with redirections (to 343 * pipes or files) but it should be enough for a debug tool 344 * (TODO: make something that handles redirections as well). 345 */ 346 347 #ifdef _WIN32 348 fd_event = WSACreateEvent(); 349 if (fd_event == WSA_INVALID_EVENT) { 350 fprintf(stderr, "ERROR: WSACreateEvent() failed with %d\n", 351 WSAGetLastError()); 352 retcode = -2; 353 goto engine_exit; 354 } 355 WSAEventSelect(fd, fd_event, FD_READ | FD_WRITE | FD_CLOSE); 356 h_in = GetStdHandle(STD_INPUT_HANDLE); 357 h_out = GetStdHandle(STD_OUTPUT_HANDLE); 358 SetConsoleMode(h_in, ENABLE_ECHO_INPUT 359 | ENABLE_LINE_INPUT 360 | ENABLE_PROCESSED_INPUT 361 | ENABLE_PROCESSED_OUTPUT 362 | ENABLE_WRAP_AT_EOL_OUTPUT); 363 #else 364 /* 365 * Make sure that stdin and stdout are non-blocking. 366 */ 367 fcntl(0, F_SETFL, O_NONBLOCK); 368 fcntl(1, F_SETFL, O_NONBLOCK); 369 #endif 370 371 /* 372 * Perform the loop. 373 */ 374 for (;;) { 375 unsigned st; 376 int sendrec, recvrec, sendapp, recvapp; 377 #ifdef _WIN32 378 HANDLE pfd[2]; 379 DWORD wt; 380 #else 381 struct pollfd pfd[3]; 382 int n; 383 #endif 384 size_t u, k_fd, k_in, k_out; 385 int sendrec_ok, recvrec_ok, sendapp_ok, recvapp_ok; 386 387 /* 388 * Get current engine state. 389 */ 390 st = br_ssl_engine_current_state(cc); 391 if (st == BR_SSL_CLOSED) { 392 int err; 393 394 err = br_ssl_engine_last_error(cc); 395 if (err == BR_ERR_OK) { 396 if (verbose) { 397 fprintf(stderr, 398 "SSL closed normally\n"); 399 } 400 retcode = 0; 401 goto engine_exit; 402 } else { 403 fprintf(stderr, "ERROR: SSL error %d", err); 404 retcode = err; 405 if (err >= BR_ERR_SEND_FATAL_ALERT) { 406 err -= BR_ERR_SEND_FATAL_ALERT; 407 fprintf(stderr, 408 " (sent alert %d)\n", err); 409 } else if (err >= BR_ERR_RECV_FATAL_ALERT) { 410 err -= BR_ERR_RECV_FATAL_ALERT; 411 fprintf(stderr, 412 " (received alert %d)\n", err); 413 } else { 414 const char *ename; 415 416 ename = find_error_name(err, NULL); 417 if (ename == NULL) { 418 ename = "unknown"; 419 } 420 fprintf(stderr, " (%s)\n", ename); 421 } 422 goto engine_exit; 423 } 424 } 425 426 /* 427 * Compute descriptors that must be polled, depending 428 * on engine state. 429 */ 430 sendrec = ((st & BR_SSL_SENDREC) != 0); 431 recvrec = ((st & BR_SSL_RECVREC) != 0); 432 sendapp = ((st & BR_SSL_SENDAPP) != 0); 433 recvapp = ((st & BR_SSL_RECVAPP) != 0); 434 if (verbose && sendapp && !hsdetails) { 435 char csn[80]; 436 const char *pname; 437 438 fprintf(stderr, "Handshake completed\n"); 439 fprintf(stderr, " version: "); 440 switch (cc->session.version) { 441 case BR_SSL30: 442 fprintf(stderr, "SSL 3.0"); 443 break; 444 case BR_TLS10: 445 fprintf(stderr, "TLS 1.0"); 446 break; 447 case BR_TLS11: 448 fprintf(stderr, "TLS 1.1"); 449 break; 450 case BR_TLS12: 451 fprintf(stderr, "TLS 1.2"); 452 break; 453 default: 454 fprintf(stderr, "unknown (0x%04X)", 455 (unsigned)cc->session.version); 456 break; 457 } 458 fprintf(stderr, "\n"); 459 get_suite_name_ext( 460 cc->session.cipher_suite, csn, sizeof csn); 461 fprintf(stderr, " cipher suite: %s\n", csn); 462 if (uses_ecdhe(cc->session.cipher_suite)) { 463 get_curve_name_ext( 464 br_ssl_engine_get_ecdhe_curve(cc), 465 csn, sizeof csn); 466 fprintf(stderr, 467 " ECDHE curve: %s\n", csn); 468 } 469 fprintf(stderr, " secure renegotiation: %s\n", 470 cc->reneg == 1 ? "no" : "yes"); 471 pname = br_ssl_engine_get_selected_protocol(cc); 472 if (pname != NULL) { 473 fprintf(stderr, 474 " protocol name (ALPN): %s\n", 475 pname); 476 } 477 hsdetails = 1; 478 } 479 480 k_fd = (size_t)-1; 481 k_in = (size_t)-1; 482 k_out = (size_t)-1; 483 484 u = 0; 485 #ifdef _WIN32 486 /* 487 * If we recorded that we can send or receive data, and we 488 * want to do exactly that, then we don't wait; we just do 489 * it. 490 */ 491 recvapp_ok = 0; 492 sendrec_ok = 0; 493 recvrec_ok = 0; 494 sendapp_ok = 0; 495 496 if (sendrec && can_send) { 497 sendrec_ok = 1; 498 } else if (recvrec && can_recv) { 499 recvrec_ok = 1; 500 } else if (recvapp) { 501 recvapp_ok = 1; 502 } else if (sendapp && in_avail_buffered(h_in, &bb)) { 503 sendapp_ok = 1; 504 } else { 505 /* 506 * If we cannot do I/O right away, then we must 507 * wait for some event, and try again. 508 */ 509 pfd[u] = (HANDLE)fd_event; 510 k_fd = u; 511 u ++; 512 if (sendapp) { 513 pfd[u] = h_in; 514 k_in = u; 515 u ++; 516 } 517 wt = WaitForMultipleObjectsEx(u, pfd, 518 FALSE, INFINITE, FALSE); 519 if (wt == WAIT_FAILED) { 520 fprintf(stderr, "ERROR:" 521 " WaitForMultipleObjectsEx()" 522 " failed with 0x%08lX", 523 (unsigned long)GetLastError()); 524 retcode = -2; 525 goto engine_exit; 526 } 527 if (wt == k_fd) { 528 WSANETWORKEVENTS e; 529 530 if (WSAEnumNetworkEvents(fd, fd_event, &e)) { 531 fprintf(stderr, "ERROR:" 532 " WSAEnumNetworkEvents()" 533 " failed with %d\n", 534 WSAGetLastError()); 535 retcode = -2; 536 goto engine_exit; 537 } 538 if (e.lNetworkEvents & (FD_WRITE | FD_CLOSE)) { 539 can_send = 1; 540 } 541 if (e.lNetworkEvents & (FD_READ | FD_CLOSE)) { 542 can_recv = 1; 543 } 544 } 545 continue; 546 } 547 #else 548 if (sendrec || recvrec) { 549 pfd[u].fd = fd; 550 pfd[u].revents = 0; 551 pfd[u].events = 0; 552 if (sendrec) { 553 pfd[u].events |= POLLOUT; 554 } 555 if (recvrec) { 556 pfd[u].events |= POLLIN; 557 } 558 k_fd = u; 559 u ++; 560 } 561 if (sendapp) { 562 pfd[u].fd = 0; 563 pfd[u].revents = 0; 564 pfd[u].events = POLLIN; 565 k_in = u; 566 u ++; 567 } 568 if (recvapp) { 569 pfd[u].fd = 1; 570 pfd[u].revents = 0; 571 pfd[u].events = POLLOUT; 572 k_out = u; 573 u ++; 574 } 575 n = poll(pfd, u, -1); 576 if (n < 0) { 577 if (errno == EINTR) { 578 continue; 579 } 580 perror("ERROR: poll()"); 581 retcode = -2; 582 goto engine_exit; 583 } 584 if (n == 0) { 585 continue; 586 } 587 588 /* 589 * We transform closures/errors into read+write accesses 590 * so as to force the read() or write() call that will 591 * detect the situation. 592 */ 593 while (u -- > 0) { 594 if (pfd[u].revents & (POLLERR | POLLHUP)) { 595 pfd[u].revents |= POLLIN | POLLOUT; 596 } 597 } 598 599 recvapp_ok = recvapp && (pfd[k_out].revents & POLLOUT) != 0; 600 sendrec_ok = sendrec && (pfd[k_fd].revents & POLLOUT) != 0; 601 recvrec_ok = recvrec && (pfd[k_fd].revents & POLLIN) != 0; 602 sendapp_ok = sendapp && (pfd[k_in].revents & POLLIN) != 0; 603 #endif 604 605 /* 606 * We give preference to outgoing data, on stdout and on 607 * the socket. 608 */ 609 if (recvapp_ok) { 610 unsigned char *buf; 611 size_t len; 612 #ifdef _WIN32 613 DWORD wlen; 614 #else 615 ssize_t wlen; 616 #endif 617 618 buf = br_ssl_engine_recvapp_buf(cc, &len); 619 #ifdef _WIN32 620 if (!WriteFile(h_out, buf, len, &wlen, NULL)) { 621 if (verbose) { 622 fprintf(stderr, "stdout closed...\n"); 623 } 624 retcode = -2; 625 goto engine_exit; 626 } 627 #else 628 wlen = write(1, buf, len); 629 if (wlen <= 0) { 630 if (verbose) { 631 fprintf(stderr, "stdout closed...\n"); 632 } 633 retcode = -2; 634 goto engine_exit; 635 } 636 #endif 637 br_ssl_engine_recvapp_ack(cc, wlen); 638 continue; 639 } 640 if (sendrec_ok) { 641 unsigned char *buf; 642 size_t len; 643 int wlen; 644 645 buf = br_ssl_engine_sendrec_buf(cc, &len); 646 wlen = send(fd, buf, len, 0); 647 if (wlen <= 0) { 648 #ifdef _WIN32 649 int err; 650 651 err = WSAGetLastError(); 652 if (err == EWOULDBLOCK 653 || err == WSAEWOULDBLOCK) 654 { 655 can_send = 0; 656 continue; 657 } 658 #else 659 if (errno == EINTR || errno == EWOULDBLOCK) { 660 continue; 661 } 662 #endif 663 if (verbose) { 664 fprintf(stderr, "socket closed...\n"); 665 } 666 retcode = -1; 667 goto engine_exit; 668 } 669 if (trace) { 670 dump_blob("Outgoing bytes", buf, wlen); 671 } 672 br_ssl_engine_sendrec_ack(cc, wlen); 673 continue; 674 } 675 if (recvrec_ok) { 676 unsigned char *buf; 677 size_t len; 678 int rlen; 679 680 buf = br_ssl_engine_recvrec_buf(cc, &len); 681 rlen = recv(fd, buf, len, 0); 682 if (rlen == 0) { 683 if (verbose) { 684 fprintf(stderr, "socket closed...\n"); 685 } 686 retcode = -1; 687 goto engine_exit; 688 } 689 if (rlen < 0) { 690 #ifdef _WIN32 691 int err; 692 693 err = WSAGetLastError(); 694 if (err == EWOULDBLOCK 695 || err == WSAEWOULDBLOCK) 696 { 697 can_recv = 0; 698 continue; 699 } 700 #else 701 if (errno == EINTR || errno == EWOULDBLOCK) { 702 continue; 703 } 704 #endif 705 if (verbose) { 706 fprintf(stderr, "socket broke...\n"); 707 } 708 retcode = -1; 709 goto engine_exit; 710 } 711 if (trace) { 712 dump_blob("Incoming bytes", buf, rlen); 713 } 714 br_ssl_engine_recvrec_ack(cc, rlen); 715 continue; 716 } 717 if (sendapp_ok) { 718 unsigned char *buf; 719 size_t len; 720 #ifdef _WIN32 721 int rlen; 722 #else 723 ssize_t rlen; 724 #endif 725 726 buf = br_ssl_engine_sendapp_buf(cc, &len); 727 #ifdef _WIN32 728 rlen = in_read_buffered(h_in, &bb, buf, len); 729 #else 730 rlen = read(0, buf, len); 731 #endif 732 if (rlen <= 0) { 733 if (verbose) { 734 fprintf(stderr, "stdin closed...\n"); 735 } 736 br_ssl_engine_close(cc); 737 } else if (!run_command(cc, buf, rlen)) { 738 br_ssl_engine_sendapp_ack(cc, rlen); 739 } 740 br_ssl_engine_flush(cc, 0); 741 continue; 742 } 743 744 /* We should never reach that point. */ 745 fprintf(stderr, "ERROR: poll() misbehaves\n"); 746 retcode = -2; 747 goto engine_exit; 748 } 749 750 /* 751 * Release allocated structures. 752 */ 753 engine_exit: 754 #ifdef _WIN32 755 if (fd_event != WSA_INVALID_EVENT) { 756 WSACloseEvent(fd_event); 757 } 758 #endif 759 return retcode; 760 } 761