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