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 OPENSSL_UNISTD 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 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 SSL_CTX_set_cipher_list(tm_ctx, tm_cipher); 379 if (!set_cert_stuff(tm_ctx, t_cert_file, t_key_file)) 380 goto end; 381 382 SSL_load_error_strings(); 383 384 if ((!SSL_CTX_load_verify_locations(tm_ctx, CAfile, CApath)) || 385 (!SSL_CTX_set_default_verify_paths(tm_ctx))) { 386 /* 387 * BIO_printf(bio_err,"error setting default verify locations\n"); 388 */ 389 ERR_print_errors(bio_err); 390 /* goto end; */ 391 } 392 393 if (tm_cipher == NULL) 394 tm_cipher = getenv("SSL_CIPHER"); 395 396 if (tm_cipher == NULL) { 397 fprintf(stderr, "No CIPHER specified\n"); 398 } 399 400 if (!(perform & 1)) 401 goto next; 402 printf("Collecting connection statistics for %d seconds\n", maxTime); 403 404 /* Loop and time how long it takes to make connections */ 405 406 bytes_read = 0; 407 finishtime = (long)time(NULL) + maxTime; 408 tm_Time_F(START); 409 for (;;) { 410 if (finishtime < (long)time(NULL)) 411 break; 412 #ifdef WIN32_STUFF 413 414 if (flushWinMsgs(0) == -1) 415 goto end; 416 417 if (waitingToDie || exitNow) /* we're dead */ 418 goto end; 419 #endif 420 421 if ((scon = doConnection(NULL)) == NULL) 422 goto end; 423 424 if (s_www_path != NULL) { 425 BIO_snprintf(buf, sizeof(buf), "GET %s HTTP/1.0\r\n\r\n", 426 s_www_path); 427 SSL_write(scon, buf, strlen(buf)); 428 while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) 429 bytes_read += i; 430 } 431 #ifdef NO_SHUTDOWN 432 SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); 433 #else 434 SSL_shutdown(scon); 435 #endif 436 SHUTDOWN2(SSL_get_fd(scon)); 437 438 nConn += 1; 439 if (SSL_session_reused(scon)) 440 ver = 'r'; 441 else { 442 ver = SSL_version(scon); 443 if (ver == TLS1_VERSION) 444 ver = 't'; 445 else if (ver == SSL3_VERSION) 446 ver = '3'; 447 else if (ver == SSL2_VERSION) 448 ver = '2'; 449 else 450 ver = '*'; 451 } 452 fputc(ver, stdout); 453 fflush(stdout); 454 455 SSL_free(scon); 456 scon = NULL; 457 } 458 totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ 459 460 i = (int)((long)time(NULL) - finishtime + maxTime); 461 printf 462 ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", 463 nConn, totalTime, ((double)nConn / totalTime), bytes_read); 464 printf 465 ("%d connections in %ld real seconds, %ld bytes read per connection\n", 466 nConn, (long)time(NULL) - finishtime + maxTime, bytes_read / nConn); 467 468 /* 469 * Now loop and time connections using the same session id over and over 470 */ 471 472 next: 473 if (!(perform & 2)) 474 goto end; 475 printf("\n\nNow timing with session id reuse.\n"); 476 477 /* Get an SSL object so we can reuse the session id */ 478 if ((scon = doConnection(NULL)) == NULL) { 479 fprintf(stderr, "Unable to get connection\n"); 480 goto end; 481 } 482 483 if (s_www_path != NULL) { 484 BIO_snprintf(buf, sizeof(buf), "GET %s HTTP/1.0\r\n\r\n", s_www_path); 485 SSL_write(scon, buf, strlen(buf)); 486 while (SSL_read(scon, buf, sizeof(buf)) > 0) ; 487 } 488 #ifdef NO_SHUTDOWN 489 SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); 490 #else 491 SSL_shutdown(scon); 492 #endif 493 SHUTDOWN2(SSL_get_fd(scon)); 494 495 nConn = 0; 496 totalTime = 0.0; 497 498 finishtime = (long)time(NULL) + maxTime; 499 500 printf("starting\n"); 501 bytes_read = 0; 502 tm_Time_F(START); 503 504 for (;;) { 505 if (finishtime < (long)time(NULL)) 506 break; 507 508 #ifdef WIN32_STUFF 509 if (flushWinMsgs(0) == -1) 510 goto end; 511 512 if (waitingToDie || exitNow) /* we're dead */ 513 goto end; 514 #endif 515 516 if ((doConnection(scon)) == NULL) 517 goto end; 518 519 if (s_www_path) { 520 BIO_snprintf(buf, sizeof(buf), "GET %s HTTP/1.0\r\n\r\n", 521 s_www_path); 522 SSL_write(scon, buf, strlen(buf)); 523 while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) 524 bytes_read += i; 525 } 526 #ifdef NO_SHUTDOWN 527 SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); 528 #else 529 SSL_shutdown(scon); 530 #endif 531 SHUTDOWN2(SSL_get_fd(scon)); 532 533 nConn += 1; 534 if (SSL_session_reused(scon)) 535 ver = 'r'; 536 else { 537 ver = SSL_version(scon); 538 if (ver == TLS1_VERSION) 539 ver = 't'; 540 else if (ver == SSL3_VERSION) 541 ver = '3'; 542 else if (ver == SSL2_VERSION) 543 ver = '2'; 544 else 545 ver = '*'; 546 } 547 fputc(ver, stdout); 548 fflush(stdout); 549 } 550 totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ 551 552 printf 553 ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", 554 nConn, totalTime, ((double)nConn / totalTime), bytes_read); 555 printf 556 ("%d connections in %ld real seconds, %ld bytes read per connection\n", 557 nConn, (long)time(NULL) - finishtime + maxTime, 558 bytes_read / (nConn?nConn:1)); 559 560 ret = 0; 561 end: 562 if (scon != NULL) 563 SSL_free(scon); 564 565 if (tm_ctx != NULL) { 566 SSL_CTX_free(tm_ctx); 567 tm_ctx = NULL; 568 } 569 apps_shutdown(); 570 OPENSSL_EXIT(ret); 571 } 572 573 /*- 574 * doConnection - make a connection 575 * Args: 576 * scon = earlier ssl connection for session id, or NULL 577 * Returns: 578 * SSL * = the connection pointer. 579 */ 580 static SSL *doConnection(SSL *scon) 581 { 582 BIO *conn; 583 SSL *serverCon; 584 int width, i; 585 fd_set readfds; 586 587 if ((conn = BIO_new(BIO_s_connect())) == NULL) 588 return (NULL); 589 590 /* BIO_set_conn_port(conn,port);*/ 591 BIO_set_conn_hostname(conn, host); 592 593 if (scon == NULL) 594 serverCon = SSL_new(tm_ctx); 595 else { 596 serverCon = scon; 597 SSL_set_connect_state(serverCon); 598 } 599 600 SSL_set_bio(serverCon, conn, conn); 601 602 #if 0 603 if (scon != NULL) 604 SSL_set_session(serverCon, SSL_get_session(scon)); 605 #endif 606 607 /* ok, lets connect */ 608 for (;;) { 609 i = SSL_connect(serverCon); 610 if (BIO_sock_should_retry(i)) { 611 BIO_printf(bio_err, "DELAY\n"); 612 613 i = SSL_get_fd(serverCon); 614 width = i + 1; 615 FD_ZERO(&readfds); 616 openssl_fdset(i, &readfds); 617 /* 618 * Note: under VMS with SOCKETSHR the 2nd parameter is currently 619 * of type (int *) whereas under other systems it is (void *) if 620 * you don't have a cast it will choke the compiler: if you do 621 * have a cast then you can either go for (int *) or (void *). 622 */ 623 select(width, (void *)&readfds, NULL, NULL, NULL); 624 continue; 625 } 626 break; 627 } 628 if (i <= 0) { 629 BIO_printf(bio_err, "ERROR\n"); 630 if (verify_error != X509_V_OK) 631 BIO_printf(bio_err, "verify error:%s\n", 632 X509_verify_cert_error_string(verify_error)); 633 else 634 ERR_print_errors(bio_err); 635 if (scon == NULL) 636 SSL_free(serverCon); 637 return NULL; 638 } 639 640 return serverCon; 641 } 642