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 #ifdef NO_STDIO 71 #define APPS_WIN16 72 #endif 73 #define USE_SOCKETS 74 #include <openssl/x509.h> 75 #include <openssl/ssl.h> 76 #include <openssl/pem.h> 77 #include "apps.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 85 #if !defined(MSDOS) && !defined(VXWORKS) && (!defined(VMS) || defined(__DECC)) || defined (_DARWIN) 86 #define TIMES 87 #endif 88 89 #ifndef _IRIX 90 #include <time.h> 91 #endif 92 #ifdef TIMES 93 #include <sys/types.h> 94 #include <sys/times.h> 95 #endif 96 97 /* Depending on the VMS version, the tms structure is perhaps defined. 98 The __TMS macro will show if it was. If it wasn't defined, we should 99 undefine TIMES, since that tells the rest of the program how things 100 should be handled. -- Richard Levitte */ 101 #if defined(VMS) && defined(__DECC) && !defined(__TMS) 102 #undef TIMES 103 #endif 104 105 #if !defined(TIMES) && !defined(VXWORKS) 106 #include <sys/timeb.h> 107 #endif 108 109 #ifdef _AIX 110 #include <sys/select.h> 111 #endif 112 113 #if defined(sun) || defined(__ultrix) 114 #define _POSIX_SOURCE 115 #include <limits.h> 116 #include <sys/param.h> 117 #endif 118 119 /* The following if from times(3) man page. It may need to be changed 120 */ 121 #ifndef HZ 122 #ifndef CLK_TCK 123 #define HZ 100.0 124 #else /* CLK_TCK */ 125 #define HZ ((double)CLK_TCK) 126 #endif 127 #endif 128 129 #undef PROG 130 #define PROG s_time_main 131 132 #undef ioctl 133 #define ioctl ioctlsocket 134 135 #define SSL_CONNECT_NAME "localhost:4433" 136 137 /*#define TEST_CERT "client.pem" */ /* no default cert. */ 138 139 #undef BUFSIZZ 140 #define BUFSIZZ 1024*10 141 142 #undef min 143 #undef max 144 #define min(a,b) (((a) < (b)) ? (a) : (b)) 145 #define max(a,b) (((a) > (b)) ? (a) : (b)) 146 147 #undef SECONDS 148 #define SECONDS 30 149 extern int verify_depth; 150 extern int verify_error; 151 152 static void s_time_usage(void); 153 static int parseArgs( int argc, char **argv ); 154 static SSL *doConnection( SSL *scon ); 155 static void s_time_init(void); 156 157 /*********************************************************************** 158 * Static data declarations 159 */ 160 161 /* static char *port=PORT_STR;*/ 162 static char *host=SSL_CONNECT_NAME; 163 static char *t_cert_file=NULL; 164 static char *t_key_file=NULL; 165 static char *CApath=NULL; 166 static char *CAfile=NULL; 167 static char *tm_cipher=NULL; 168 static int tm_verify = SSL_VERIFY_NONE; 169 static int maxTime = SECONDS; 170 static SSL_CTX *tm_ctx=NULL; 171 static SSL_METHOD *s_time_meth=NULL; 172 static char *s_www_path=NULL; 173 static long bytes_read=0; 174 static int st_bugs=0; 175 static int perform=0; 176 #ifdef FIONBIO 177 static int t_nbio=0; 178 #endif 179 #ifdef WIN32 180 static int exitNow = 0; /* Set when it's time to exit main */ 181 #endif 182 183 static void s_time_init(void) 184 { 185 host=SSL_CONNECT_NAME; 186 t_cert_file=NULL; 187 t_key_file=NULL; 188 CApath=NULL; 189 CAfile=NULL; 190 tm_cipher=NULL; 191 tm_verify = SSL_VERIFY_NONE; 192 maxTime = SECONDS; 193 tm_ctx=NULL; 194 s_time_meth=NULL; 195 s_www_path=NULL; 196 bytes_read=0; 197 st_bugs=0; 198 perform=0; 199 200 #ifdef FIONBIO 201 t_nbio=0; 202 #endif 203 #ifdef WIN32 204 exitNow = 0; /* Set when it's time to exit main */ 205 #endif 206 } 207 208 /*********************************************************************** 209 * usage - display usage message 210 */ 211 static void s_time_usage(void) 212 { 213 static char umsg[] = "\ 214 -time arg - max number of seconds to collect data, default %d\n\ 215 -verify arg - turn on peer certificate verification, arg == depth\n\ 216 -cert arg - certificate file to use, PEM format assumed\n\ 217 -key arg - RSA file to use, PEM format assumed, key is in cert file\n\ 218 file if not specified by this option\n\ 219 -CApath arg - PEM format directory of CA's\n\ 220 -CAfile arg - PEM format file of CA's\n\ 221 -cipher - preferred cipher to use, play with 'openssl ciphers'\n\n"; 222 223 printf( "usage: s_time <args>\n\n" ); 224 225 printf("-connect host:port - host:port to connect to (default is %s)\n",SSL_CONNECT_NAME); 226 #ifdef FIONBIO 227 printf("-nbio - Run with non-blocking IO\n"); 228 printf("-ssl2 - Just use SSLv2\n"); 229 printf("-ssl3 - Just use SSLv3\n"); 230 printf("-bugs - Turn on SSL bug compatibility\n"); 231 printf("-new - Just time new connections\n"); 232 printf("-reuse - Just time connection reuse\n"); 233 printf("-www page - Retrieve 'page' from the site\n"); 234 #endif 235 printf( umsg,SECONDS ); 236 } 237 238 /*********************************************************************** 239 * parseArgs - Parse command line arguments and initialize data 240 * 241 * Returns 0 if ok, -1 on bad args 242 */ 243 static int parseArgs(int argc, char **argv) 244 { 245 int badop = 0; 246 247 verify_depth=0; 248 verify_error=X509_V_OK; 249 250 argc--; 251 argv++; 252 253 while (argc >= 1) { 254 if (strcmp(*argv,"-connect") == 0) 255 { 256 if (--argc < 1) goto bad; 257 host= *(++argv); 258 } 259 #if 0 260 else if( strcmp(*argv,"-host") == 0) 261 { 262 if (--argc < 1) goto bad; 263 host= *(++argv); 264 } 265 else if( strcmp(*argv,"-port") == 0) 266 { 267 if (--argc < 1) goto bad; 268 port= *(++argv); 269 } 270 #endif 271 else if (strcmp(*argv,"-reuse") == 0) 272 perform=2; 273 else if (strcmp(*argv,"-new") == 0) 274 perform=1; 275 else if( strcmp(*argv,"-verify") == 0) { 276 277 tm_verify=SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE; 278 if (--argc < 1) goto bad; 279 verify_depth=atoi(*(++argv)); 280 BIO_printf(bio_err,"verify depth is %d\n",verify_depth); 281 282 } else if( strcmp(*argv,"-cert") == 0) { 283 284 if (--argc < 1) goto bad; 285 t_cert_file= *(++argv); 286 287 } else if( strcmp(*argv,"-key") == 0) { 288 289 if (--argc < 1) goto bad; 290 t_key_file= *(++argv); 291 292 } else if( strcmp(*argv,"-CApath") == 0) { 293 294 if (--argc < 1) goto bad; 295 CApath= *(++argv); 296 297 } else if( strcmp(*argv,"-CAfile") == 0) { 298 299 if (--argc < 1) goto bad; 300 CAfile= *(++argv); 301 302 } else if( strcmp(*argv,"-cipher") == 0) { 303 304 if (--argc < 1) goto bad; 305 tm_cipher= *(++argv); 306 } 307 #ifdef FIONBIO 308 else if(strcmp(*argv,"-nbio") == 0) { 309 t_nbio=1; 310 } 311 #endif 312 else if(strcmp(*argv,"-www") == 0) 313 { 314 if (--argc < 1) goto bad; 315 s_www_path= *(++argv); 316 } 317 else if(strcmp(*argv,"-bugs") == 0) 318 st_bugs=1; 319 #ifndef NO_SSL2 320 else if(strcmp(*argv,"-ssl2") == 0) 321 s_time_meth=SSLv2_client_method(); 322 #endif 323 #ifndef NO_SSL3 324 else if(strcmp(*argv,"-ssl3") == 0) 325 s_time_meth=SSLv3_client_method(); 326 #endif 327 else if( strcmp(*argv,"-time") == 0) { 328 329 if (--argc < 1) goto bad; 330 maxTime= atoi(*(++argv)); 331 } 332 else { 333 BIO_printf(bio_err,"unknown option %s\n",*argv); 334 badop=1; 335 break; 336 } 337 338 argc--; 339 argv++; 340 } 341 342 if (perform == 0) perform=3; 343 344 if(badop) { 345 bad: 346 s_time_usage(); 347 return -1; 348 } 349 350 return 0; /* Valid args */ 351 } 352 353 /*********************************************************************** 354 * TIME - time functions 355 */ 356 #define START 0 357 #define STOP 1 358 359 static double tm_Time_F(int s) 360 { 361 static double ret; 362 #ifdef TIMES 363 static struct tms tstart,tend; 364 365 if(s == START) { 366 times(&tstart); 367 return(0); 368 } else { 369 times(&tend); 370 ret=((double)(tend.tms_utime-tstart.tms_utime))/HZ; 371 return((ret == 0.0)?1e-6:ret); 372 } 373 #elif defined(VXWORKS) 374 { 375 static unsigned long tick_start, tick_end; 376 377 if( s == START ) 378 { 379 tick_start = tickGet(); 380 return 0; 381 } 382 else 383 { 384 tick_end = tickGet(); 385 ret = (double)(tick_end - tick_start) / (double)sysClkRateGet(); 386 return((ret == 0.0)?1e-6:ret); 387 } 388 } 389 #else /* !times() */ 390 static struct timeb tstart,tend; 391 long i; 392 393 if(s == START) { 394 ftime(&tstart); 395 return(0); 396 } else { 397 ftime(&tend); 398 i=(long)tend.millitm-(long)tstart.millitm; 399 ret=((double)(tend.time-tstart.time))+((double)i)/1000.0; 400 return((ret == 0.0)?1e-6:ret); 401 } 402 #endif 403 } 404 405 /*********************************************************************** 406 * MAIN - main processing area for client 407 * real name depends on MONOLITH 408 */ 409 int MAIN(int, char **); 410 411 int MAIN(int argc, char **argv) 412 { 413 double totalTime = 0.0; 414 int nConn = 0; 415 SSL *scon=NULL; 416 long finishtime=0; 417 int ret=1,i; 418 MS_STATIC char buf[1024*8]; 419 int ver; 420 421 apps_startup(); 422 s_time_init(); 423 424 if (bio_err == NULL) 425 bio_err=BIO_new_fp(stderr,BIO_NOCLOSE); 426 427 #if !defined(NO_SSL2) && !defined(NO_SSL3) 428 s_time_meth=SSLv23_client_method(); 429 #elif !defined(NO_SSL3) 430 s_time_meth=SSLv3_client_method(); 431 #elif !defined(NO_SSL2) 432 s_time_meth=SSLv2_client_method(); 433 #endif 434 435 /* parse the command line arguments */ 436 if( parseArgs( argc, argv ) < 0 ) 437 goto end; 438 439 OpenSSL_add_ssl_algorithms(); 440 if ((tm_ctx=SSL_CTX_new(s_time_meth)) == NULL) return(1); 441 442 SSL_CTX_set_quiet_shutdown(tm_ctx,1); 443 444 if (st_bugs) SSL_CTX_set_options(tm_ctx,SSL_OP_ALL); 445 SSL_CTX_set_cipher_list(tm_ctx,tm_cipher); 446 if(!set_cert_stuff(tm_ctx,t_cert_file,t_key_file)) 447 goto end; 448 449 SSL_load_error_strings(); 450 451 if ((!SSL_CTX_load_verify_locations(tm_ctx,CAfile,CApath)) || 452 (!SSL_CTX_set_default_verify_paths(tm_ctx))) 453 { 454 /* BIO_printf(bio_err,"error setting default verify locations\n"); */ 455 ERR_print_errors(bio_err); 456 /* goto end; */ 457 } 458 459 if (tm_cipher == NULL) 460 tm_cipher = getenv("SSL_CIPHER"); 461 462 if (tm_cipher == NULL ) { 463 fprintf( stderr, "No CIPHER specified\n" ); 464 /* EXIT(1); */ 465 } 466 467 if (!(perform & 1)) goto next; 468 printf( "Collecting connection statistics for %d seconds\n", maxTime ); 469 470 /* Loop and time how long it takes to make connections */ 471 472 bytes_read=0; 473 finishtime=(long)time(NULL)+maxTime; 474 tm_Time_F(START); 475 for (;;) 476 { 477 if (finishtime < time(NULL)) break; 478 #ifdef WIN32_STUFF 479 480 if( flushWinMsgs(0) == -1 ) 481 goto end; 482 483 if( waitingToDie || exitNow ) /* we're dead */ 484 goto end; 485 #endif 486 487 if( (scon = doConnection( NULL )) == NULL ) 488 goto end; 489 490 if (s_www_path != NULL) 491 { 492 sprintf(buf,"GET %s HTTP/1.0\r\n\r\n",s_www_path); 493 SSL_write(scon,buf,strlen(buf)); 494 while ((i=SSL_read(scon,buf,sizeof(buf))) > 0) 495 bytes_read+=i; 496 } 497 498 #ifdef NO_SHUTDOWN 499 SSL_set_shutdown(scon,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); 500 #else 501 SSL_shutdown(scon); 502 #endif 503 SHUTDOWN2(SSL_get_fd(scon)); 504 505 nConn += 1; 506 if (SSL_session_reused(scon)) 507 ver='r'; 508 else 509 { 510 ver=SSL_version(scon); 511 if (ver == TLS1_VERSION) 512 ver='t'; 513 else if (ver == SSL3_VERSION) 514 ver='3'; 515 else if (ver == SSL2_VERSION) 516 ver='2'; 517 else 518 ver='*'; 519 } 520 fputc(ver,stdout); 521 fflush(stdout); 522 523 SSL_free( scon ); 524 scon=NULL; 525 } 526 totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ 527 528 i=(int)(time(NULL)-finishtime+maxTime); 529 printf( "\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double)nConn/totalTime),bytes_read); 530 printf( "%d connections in %ld real seconds, %ld bytes read per connection\n",nConn,time(NULL)-finishtime+maxTime,bytes_read/nConn); 531 532 /* Now loop and time connections using the same session id over and over */ 533 534 next: 535 if (!(perform & 2)) goto end; 536 printf( "\n\nNow timing with session id reuse.\n" ); 537 538 /* Get an SSL object so we can reuse the session id */ 539 if( (scon = doConnection( NULL )) == NULL ) 540 { 541 fprintf( stderr, "Unable to get connection\n" ); 542 goto end; 543 } 544 545 if (s_www_path != NULL) 546 { 547 sprintf(buf,"GET %s HTTP/1.0\r\n\r\n",s_www_path); 548 SSL_write(scon,buf,strlen(buf)); 549 while (SSL_read(scon,buf,sizeof(buf)) > 0) 550 ; 551 } 552 #ifdef NO_SHUTDOWN 553 SSL_set_shutdown(scon,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); 554 #else 555 SSL_shutdown(scon); 556 #endif 557 SHUTDOWN2(SSL_get_fd(scon)); 558 559 nConn = 0; 560 totalTime = 0.0; 561 562 finishtime=time(NULL)+maxTime; 563 564 printf( "starting\n" ); 565 bytes_read=0; 566 tm_Time_F(START); 567 568 for (;;) 569 { 570 if (finishtime < time(NULL)) break; 571 572 #ifdef WIN32_STUFF 573 if( flushWinMsgs(0) == -1 ) 574 goto end; 575 576 if( waitingToDie || exitNow ) /* we're dead */ 577 goto end; 578 #endif 579 580 if( (doConnection( scon )) == NULL ) 581 goto end; 582 583 if (s_www_path) 584 { 585 sprintf(buf,"GET %s HTTP/1.0\r\n\r\n",s_www_path); 586 SSL_write(scon,buf,strlen(buf)); 587 while ((i=SSL_read(scon,buf,sizeof(buf))) > 0) 588 bytes_read+=i; 589 } 590 591 #ifdef NO_SHUTDOWN 592 SSL_set_shutdown(scon,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); 593 #else 594 SSL_shutdown(scon); 595 #endif 596 SHUTDOWN2(SSL_get_fd(scon)); 597 598 nConn += 1; 599 if (SSL_session_reused(scon)) 600 ver='r'; 601 else 602 { 603 ver=SSL_version(scon); 604 if (ver == TLS1_VERSION) 605 ver='t'; 606 else if (ver == SSL3_VERSION) 607 ver='3'; 608 else if (ver == SSL2_VERSION) 609 ver='2'; 610 else 611 ver='*'; 612 } 613 fputc(ver,stdout); 614 fflush(stdout); 615 } 616 totalTime += tm_Time_F(STOP); /* Add the time for this iteration*/ 617 618 619 printf( "\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double)nConn/totalTime),bytes_read); 620 printf( "%d connections in %ld real seconds, %ld bytes read per connection\n",nConn,time(NULL)-finishtime+maxTime,bytes_read/nConn); 621 622 ret=0; 623 end: 624 if (scon != NULL) SSL_free(scon); 625 626 if (tm_ctx != NULL) 627 { 628 SSL_CTX_free(tm_ctx); 629 tm_ctx=NULL; 630 } 631 EXIT(ret); 632 } 633 634 /*********************************************************************** 635 * doConnection - make a connection 636 * Args: 637 * scon = earlier ssl connection for session id, or NULL 638 * Returns: 639 * SSL * = the connection pointer. 640 */ 641 static SSL *doConnection(SSL *scon) 642 { 643 BIO *conn; 644 SSL *serverCon; 645 int width, i; 646 fd_set readfds; 647 648 if ((conn=BIO_new(BIO_s_connect())) == NULL) 649 return(NULL); 650 651 /* BIO_set_conn_port(conn,port);*/ 652 BIO_set_conn_hostname(conn,host); 653 654 if (scon == NULL) 655 serverCon=SSL_new(tm_ctx); 656 else 657 { 658 serverCon=scon; 659 SSL_set_connect_state(serverCon); 660 } 661 662 SSL_set_bio(serverCon,conn,conn); 663 664 #if 0 665 if( scon != NULL ) 666 SSL_set_session(serverCon,SSL_get_session(scon)); 667 #endif 668 669 /* ok, lets connect */ 670 for(;;) { 671 i=SSL_connect(serverCon); 672 if (BIO_sock_should_retry(i)) 673 { 674 BIO_printf(bio_err,"DELAY\n"); 675 676 i=SSL_get_fd(serverCon); 677 width=i+1; 678 FD_ZERO(&readfds); 679 FD_SET(i,&readfds); 680 /* Note: under VMS with SOCKETSHR the 2nd parameter 681 * is currently of type (int *) whereas under other 682 * systems it is (void *) if you don't have a cast it 683 * will choke the compiler: if you do have a cast then 684 * you can either go for (int *) or (void *). 685 */ 686 select(width,(void *)&readfds,NULL,NULL,NULL); 687 continue; 688 } 689 break; 690 } 691 if(i <= 0) 692 { 693 BIO_printf(bio_err,"ERROR\n"); 694 if (verify_error != X509_V_OK) 695 BIO_printf(bio_err,"verify error:%s\n", 696 X509_verify_cert_error_string(verify_error)); 697 else 698 ERR_print_errors(bio_err); 699 if (scon == NULL) 700 SSL_free(serverCon); 701 return NULL; 702 } 703 704 return serverCon; 705 } 706 707 708