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