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