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