1 /* apps/s_time.c */ 2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59 #define NO_SHUTDOWN 60 61 /* ---------------------------------------- 62 s_time - SSL client connection timer program 63 Written and donated by Larry Streepy <streepy@healthcare.com> 64 -----------------------------------------*/ 65 66 #include <stdio.h> 67 #include <stdlib.h> 68 #include <string.h> 69 70 #define USE_SOCKETS 71 #include "apps.h" 72 #ifdef OPENSSL_NO_STDIO 73 # define APPS_WIN16 74 #endif 75 #include <openssl/x509.h> 76 #include <openssl/ssl.h> 77 #include <openssl/pem.h> 78 #include "s_apps.h" 79 #include <openssl/err.h> 80 #ifdef WIN32_STUFF 81 # include "winmain.h" 82 # include "wintext.h" 83 #endif 84 #if !defined(OPENSSL_SYS_MSDOS) 85 # include <unistd.h> 86 #endif 87 88 #undef PROG 89 #define PROG s_time_main 90 91 #undef ioctl 92 #define ioctl ioctlsocket 93 94 #define SSL_CONNECT_NAME "localhost:4433" 95 96 /* no default cert. */ 97 /* 98 * #define TEST_CERT "client.pem" 99 */ 100 101 #undef BUFSIZZ 102 #define BUFSIZZ 1024*10 103 104 #define MYBUFSIZ 1024*8 105 106 #undef min 107 #undef max 108 #define min(a,b) (((a) < (b)) ? (a) : (b)) 109 #define max(a,b) (((a) > (b)) ? (a) : (b)) 110 111 #undef SECONDS 112 #define SECONDS 30 113 extern int verify_depth; 114 extern int verify_error; 115 116 static void s_time_usage(void); 117 static int parseArgs(int argc, char **argv); 118 static SSL *doConnection(SSL *scon); 119 static void s_time_init(void); 120 121 /*********************************************************************** 122 * Static data declarations 123 */ 124 125 /* static char *port=PORT_STR;*/ 126 static char *host = SSL_CONNECT_NAME; 127 static char *t_cert_file = NULL; 128 static char *t_key_file = NULL; 129 static char *CApath = NULL; 130 static char *CAfile = NULL; 131 static char *tm_cipher = NULL; 132 static int tm_verify = SSL_VERIFY_NONE; 133 static int maxTime = SECONDS; 134 static SSL_CTX *tm_ctx = NULL; 135 static const SSL_METHOD *s_time_meth = NULL; 136 static char *s_www_path = NULL; 137 static long bytes_read = 0; 138 static int st_bugs = 0; 139 static int perform = 0; 140 #ifdef FIONBIO 141 static int t_nbio = 0; 142 #endif 143 #ifdef OPENSSL_SYS_WIN32 144 static int exitNow = 0; /* Set when it's time to exit main */ 145 #endif 146 147 static void s_time_init(void) 148 { 149 host = SSL_CONNECT_NAME; 150 t_cert_file = NULL; 151 t_key_file = NULL; 152 CApath = NULL; 153 CAfile = NULL; 154 tm_cipher = NULL; 155 tm_verify = SSL_VERIFY_NONE; 156 maxTime = SECONDS; 157 tm_ctx = NULL; 158 s_time_meth = NULL; 159 s_www_path = NULL; 160 bytes_read = 0; 161 st_bugs = 0; 162 perform = 0; 163 164 #ifdef FIONBIO 165 t_nbio = 0; 166 #endif 167 #ifdef OPENSSL_SYS_WIN32 168 exitNow = 0; /* Set when it's time to exit main */ 169 #endif 170 } 171 172 /*********************************************************************** 173 * usage - display usage message 174 */ 175 static void s_time_usage(void) 176 { 177 static const char umsg[] = "\ 178 -time arg - max number of seconds to collect data, default %d\n\ 179 -verify arg - turn on peer certificate verification, arg == depth\n\ 180 -cert arg - certificate file to use, PEM format assumed\n\ 181 -key arg - RSA file to use, PEM format assumed, key is in cert file\n\ 182 file if not specified by this option\n\ 183 -CApath arg - PEM format directory of CA's\n\ 184 -CAfile arg - PEM format file of CA's\n\ 185 -cipher - preferred cipher to use, play with 'openssl ciphers'\n\n"; 186 187 printf("usage: s_time <args>\n\n"); 188 189 printf("-connect host:port - host:port to connect to (default is %s)\n", 190 SSL_CONNECT_NAME); 191 #ifdef FIONBIO 192 printf("-nbio - Run with non-blocking IO\n"); 193 printf("-ssl2 - Just use SSLv2\n"); 194 printf("-ssl3 - Just use SSLv3\n"); 195 printf("-bugs - Turn on SSL bug compatibility\n"); 196 printf("-new - Just time new connections\n"); 197 printf("-reuse - Just time connection reuse\n"); 198 printf("-www page - Retrieve 'page' from the site\n"); 199 #endif 200 printf(umsg, SECONDS); 201 } 202 203 /*********************************************************************** 204 * parseArgs - Parse command line arguments and initialize data 205 * 206 * Returns 0 if ok, -1 on bad args 207 */ 208 static int parseArgs(int argc, char **argv) 209 { 210 int badop = 0; 211 212 verify_depth = 0; 213 verify_error = X509_V_OK; 214 215 argc--; 216 argv++; 217 218 while (argc >= 1) { 219 if (strcmp(*argv, "-connect") == 0) { 220 if (--argc < 1) 221 goto bad; 222 host = *(++argv); 223 } 224 #if 0 225 else if (strcmp(*argv, "-host") == 0) { 226 if (--argc < 1) 227 goto bad; 228 host = *(++argv); 229 } else if (strcmp(*argv, "-port") == 0) { 230 if (--argc < 1) 231 goto bad; 232 port = *(++argv); 233 } 234 #endif 235 else if (strcmp(*argv, "-reuse") == 0) 236 perform = 2; 237 else if (strcmp(*argv, "-new") == 0) 238 perform = 1; 239 else if (strcmp(*argv, "-verify") == 0) { 240 241 tm_verify = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; 242 if (--argc < 1) 243 goto bad; 244 verify_depth = atoi(*(++argv)); 245 BIO_printf(bio_err, "verify depth is %d\n", verify_depth); 246 247 } else if (strcmp(*argv, "-cert") == 0) { 248 249 if (--argc < 1) 250 goto bad; 251 t_cert_file = *(++argv); 252 253 } else if (strcmp(*argv, "-key") == 0) { 254 255 if (--argc < 1) 256 goto bad; 257 t_key_file = *(++argv); 258 259 } else if (strcmp(*argv, "-CApath") == 0) { 260 261 if (--argc < 1) 262 goto bad; 263 CApath = *(++argv); 264 265 } else if (strcmp(*argv, "-CAfile") == 0) { 266 267 if (--argc < 1) 268 goto bad; 269 CAfile = *(++argv); 270 271 } else if (strcmp(*argv, "-cipher") == 0) { 272 273 if (--argc < 1) 274 goto bad; 275 tm_cipher = *(++argv); 276 } 277 #ifdef FIONBIO 278 else if (strcmp(*argv, "-nbio") == 0) { 279 t_nbio = 1; 280 } 281 #endif 282 else if (strcmp(*argv, "-www") == 0) { 283 if (--argc < 1) 284 goto bad; 285 s_www_path = *(++argv); 286 if (strlen(s_www_path) > MYBUFSIZ - 100) { 287 BIO_printf(bio_err, "-www option too long\n"); 288 badop = 1; 289 } 290 } else if (strcmp(*argv, "-bugs") == 0) 291 st_bugs = 1; 292 #ifndef OPENSSL_NO_SSL2 293 else if (strcmp(*argv, "-ssl2") == 0) 294 s_time_meth = SSLv2_client_method(); 295 #endif 296 #ifndef OPENSSL_NO_SSL3 297 else if (strcmp(*argv, "-ssl3") == 0) 298 s_time_meth = SSLv3_client_method(); 299 #endif 300 else if (strcmp(*argv, "-time") == 0) { 301 302 if (--argc < 1) 303 goto bad; 304 maxTime = atoi(*(++argv)); 305 if (maxTime <= 0) { 306 BIO_printf(bio_err, "time must be > 0\n"); 307 badop = 1; 308 } 309 } else { 310 BIO_printf(bio_err, "unknown option %s\n", *argv); 311 badop = 1; 312 break; 313 } 314 315 argc--; 316 argv++; 317 } 318 319 if (perform == 0) 320 perform = 3; 321 322 if (badop) { 323 bad: 324 s_time_usage(); 325 return -1; 326 } 327 328 return 0; /* Valid args */ 329 } 330 331 /*********************************************************************** 332 * TIME - time functions 333 */ 334 #define START 0 335 #define STOP 1 336 337 static double tm_Time_F(int s) 338 { 339 return app_tminterval(s, 1); 340 } 341 342 /*********************************************************************** 343 * MAIN - main processing area for client 344 * real name depends on MONOLITH 345 */ 346 int MAIN(int, char **); 347 348 int MAIN(int argc, char **argv) 349 { 350 double totalTime = 0.0; 351 int nConn = 0; 352 SSL *scon = NULL; 353 long finishtime = 0; 354 int ret = 1, i; 355 MS_STATIC char buf[1024 * 8]; 356 int ver; 357 358 apps_startup(); 359 s_time_init(); 360 361 if (bio_err == NULL) 362 bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); 363 364 s_time_meth = SSLv23_client_method(); 365 366 /* parse the command line arguments */ 367 if (parseArgs(argc, argv) < 0) 368 goto end; 369 370 OpenSSL_add_ssl_algorithms(); 371 if ((tm_ctx = SSL_CTX_new(s_time_meth)) == NULL) 372 return (1); 373 374 SSL_CTX_set_quiet_shutdown(tm_ctx, 1); 375 376 if (st_bugs) 377 SSL_CTX_set_options(tm_ctx, SSL_OP_ALL); 378 if (!SSL_CTX_set_cipher_list(tm_ctx, tm_cipher)) { 379 /* BIO_printf(bio_err, "Error in cipher list\n"); */ 380 goto end; 381 } 382 383 if (!set_cert_stuff(tm_ctx, t_cert_file, t_key_file)) 384 goto end; 385 386 SSL_load_error_strings(); 387 388 if ((!SSL_CTX_load_verify_locations(tm_ctx, CAfile, CApath)) || 389 (!SSL_CTX_set_default_verify_paths(tm_ctx))) { 390 /* 391 * BIO_printf(bio_err,"error setting default verify locations\n"); 392 */ 393 ERR_print_errors(bio_err); 394 /* goto end; */ 395 } 396 397 if (tm_cipher == NULL) 398 tm_cipher = getenv("SSL_CIPHER"); 399 400 if (tm_cipher == NULL) { 401 fprintf(stderr, "No CIPHER specified\n"); 402 } 403 404 if (!(perform & 1)) 405 goto next; 406 printf("Collecting connection statistics for %d seconds\n", maxTime); 407 408 /* Loop and time how long it takes to make connections */ 409 410 bytes_read = 0; 411 finishtime = (long)time(NULL) + maxTime; 412 tm_Time_F(START); 413 for (;;) { 414 if (finishtime < (long)time(NULL)) 415 break; 416 #ifdef WIN32_STUFF 417 418 if (flushWinMsgs(0) == -1) 419 goto end; 420 421 if (waitingToDie || exitNow) /* we're dead */ 422 goto end; 423 #endif 424 425 if ((scon = doConnection(NULL)) == NULL) 426 goto end; 427 428 if (s_www_path != NULL) { 429 BIO_snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\n\r\n", 430 s_www_path); 431 SSL_write(scon, buf, strlen(buf)); 432 while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) 433 bytes_read += i; 434 } 435 #ifdef NO_SHUTDOWN 436 SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); 437 #else 438 SSL_shutdown(scon); 439 #endif 440 SHUTDOWN2(SSL_get_fd(scon)); 441 442 nConn += 1; 443 if (SSL_session_reused(scon)) 444 ver = 'r'; 445 else { 446 ver = SSL_version(scon); 447 if (ver == TLS1_VERSION) 448 ver = 't'; 449 else if (ver == SSL3_VERSION) 450 ver = '3'; 451 else if (ver == SSL2_VERSION) 452 ver = '2'; 453 else 454 ver = '*'; 455 } 456 fputc(ver, stdout); 457 fflush(stdout); 458 459 SSL_free(scon); 460 scon = NULL; 461 } 462 totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ 463 464 i = (int)((long)time(NULL) - finishtime + maxTime); 465 printf 466 ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", 467 nConn, totalTime, ((double)nConn / totalTime), bytes_read); 468 printf 469 ("%d connections in %ld real seconds, %ld bytes read per connection\n", 470 nConn, (long)time(NULL) - finishtime + maxTime, bytes_read / nConn); 471 472 /* 473 * Now loop and time connections using the same session id over and over 474 */ 475 476 next: 477 if (!(perform & 2)) 478 goto end; 479 printf("\n\nNow timing with session id reuse.\n"); 480 481 /* Get an SSL object so we can reuse the session id */ 482 if ((scon = doConnection(NULL)) == NULL) { 483 fprintf(stderr, "Unable to get connection\n"); 484 goto end; 485 } 486 487 if (s_www_path != NULL) { 488 BIO_snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\n\r\n", s_www_path); 489 SSL_write(scon, buf, strlen(buf)); 490 while (SSL_read(scon, buf, sizeof(buf)) > 0) ; 491 } 492 #ifdef NO_SHUTDOWN 493 SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); 494 #else 495 SSL_shutdown(scon); 496 #endif 497 SHUTDOWN2(SSL_get_fd(scon)); 498 499 nConn = 0; 500 totalTime = 0.0; 501 502 finishtime = (long)time(NULL) + maxTime; 503 504 printf("starting\n"); 505 bytes_read = 0; 506 tm_Time_F(START); 507 508 for (;;) { 509 if (finishtime < (long)time(NULL)) 510 break; 511 512 #ifdef WIN32_STUFF 513 if (flushWinMsgs(0) == -1) 514 goto end; 515 516 if (waitingToDie || exitNow) /* we're dead */ 517 goto end; 518 #endif 519 520 if ((doConnection(scon)) == NULL) 521 goto end; 522 523 if (s_www_path) { 524 BIO_snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\n\r\n", 525 s_www_path); 526 SSL_write(scon, buf, strlen(buf)); 527 while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) 528 bytes_read += i; 529 } 530 #ifdef NO_SHUTDOWN 531 SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); 532 #else 533 SSL_shutdown(scon); 534 #endif 535 SHUTDOWN2(SSL_get_fd(scon)); 536 537 nConn += 1; 538 if (SSL_session_reused(scon)) 539 ver = 'r'; 540 else { 541 ver = SSL_version(scon); 542 if (ver == TLS1_VERSION) 543 ver = 't'; 544 else if (ver == SSL3_VERSION) 545 ver = '3'; 546 else if (ver == SSL2_VERSION) 547 ver = '2'; 548 else 549 ver = '*'; 550 } 551 fputc(ver, stdout); 552 fflush(stdout); 553 } 554 totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ 555 556 printf 557 ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", 558 nConn, totalTime, ((double)nConn / totalTime), bytes_read); 559 printf 560 ("%d connections in %ld real seconds, %ld bytes read per connection\n", 561 nConn, (long)time(NULL) - finishtime + maxTime, 562 bytes_read / (nConn?nConn:1)); 563 564 ret = 0; 565 end: 566 if (scon != NULL) 567 SSL_free(scon); 568 569 if (tm_ctx != NULL) { 570 SSL_CTX_free(tm_ctx); 571 tm_ctx = NULL; 572 } 573 apps_shutdown(); 574 OPENSSL_EXIT(ret); 575 } 576 577 /*- 578 * doConnection - make a connection 579 * Args: 580 * scon = earlier ssl connection for session id, or NULL 581 * Returns: 582 * SSL * = the connection pointer. 583 */ 584 static SSL *doConnection(SSL *scon) 585 { 586 BIO *conn; 587 SSL *serverCon; 588 int width, i; 589 fd_set readfds; 590 591 if ((conn = BIO_new(BIO_s_connect())) == NULL) 592 return (NULL); 593 594 /* BIO_set_conn_port(conn,port);*/ 595 BIO_set_conn_hostname(conn, host); 596 597 if (scon == NULL) 598 serverCon = SSL_new(tm_ctx); 599 else { 600 serverCon = scon; 601 SSL_set_connect_state(serverCon); 602 } 603 604 SSL_set_bio(serverCon, conn, conn); 605 606 #if 0 607 if (scon != NULL) 608 SSL_set_session(serverCon, SSL_get_session(scon)); 609 #endif 610 611 /* ok, lets connect */ 612 for (;;) { 613 i = SSL_connect(serverCon); 614 if (BIO_sock_should_retry(i)) { 615 BIO_printf(bio_err, "DELAY\n"); 616 617 i = SSL_get_fd(serverCon); 618 width = i + 1; 619 FD_ZERO(&readfds); 620 openssl_fdset(i, &readfds); 621 /* 622 * Note: under VMS with SOCKETSHR the 2nd parameter is currently 623 * of type (int *) whereas under other systems it is (void *) if 624 * you don't have a cast it will choke the compiler: if you do 625 * have a cast then you can either go for (int *) or (void *). 626 */ 627 select(width, (void *)&readfds, NULL, NULL, NULL); 628 continue; 629 } 630 break; 631 } 632 if (i <= 0) { 633 BIO_printf(bio_err, "ERROR\n"); 634 if (verify_error != X509_V_OK) 635 BIO_printf(bio_err, "verify error:%s\n", 636 X509_verify_cert_error_string(verify_error)); 637 else 638 ERR_print_errors(bio_err); 639 if (scon == NULL) 640 SSL_free(serverCon); 641 return NULL; 642 } 643 644 return serverCon; 645 } 646