xref: /openbsd/usr.bin/openssl/s_time.c (revision a6445c1d)
1 /* $OpenBSD: s_time.c,v 1.3 2014/11/04 18:15:22 deraadt Exp $ */
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 <sys/types.h>
67 #include <sys/socket.h>
68 
69 #include <stdio.h>
70 #include <stdlib.h>
71 #include <limits.h>
72 #include <string.h>
73 #include <unistd.h>
74 #include <poll.h>
75 
76 #include "apps.h"
77 
78 #include <openssl/err.h>
79 #include <openssl/pem.h>
80 #include <openssl/ssl.h>
81 #include <openssl/x509.h>
82 
83 #include "s_apps.h"
84 
85 #define SSL_CONNECT_NAME	"localhost:4433"
86 
87  /*#define TEST_CERT "client.pem" *//* no default cert. */
88 
89 #define BUFSIZZ 1024*10
90 
91 #define MYBUFSIZ 1024*8
92 
93 #undef min
94 #undef max
95 #define min(a,b) (((a) < (b)) ? (a) : (b))
96 #define max(a,b) (((a) > (b)) ? (a) : (b))
97 
98 #define SECONDS	30
99 extern int verify_depth;
100 extern int verify_error;
101 
102 static void s_time_usage(void);
103 static int parseArgs(int argc, char **argv);
104 static SSL *doConnection(SSL * scon);
105 static void s_time_init(void);
106 
107 /***********************************************************************
108  * Static data declarations
109  */
110 
111 /* static char *port=PORT_STR;*/
112 static char *host = SSL_CONNECT_NAME;
113 static char *t_cert_file = NULL;
114 static char *t_key_file = NULL;
115 static char *CApath = NULL;
116 static char *CAfile = NULL;
117 static char *tm_cipher = NULL;
118 static int tm_verify = SSL_VERIFY_NONE;
119 static int maxTime = SECONDS;
120 static SSL_CTX *tm_ctx = NULL;
121 static const SSL_METHOD *s_time_meth = NULL;
122 static char *s_www_path = NULL;
123 static long bytes_read = 0;
124 static int st_bugs = 0;
125 static int perform = 0;
126 static int t_nbio = 0;
127 
128 static void
129 s_time_init(void)
130 {
131 	host = SSL_CONNECT_NAME;
132 	t_cert_file = NULL;
133 	t_key_file = NULL;
134 	CApath = NULL;
135 	CAfile = NULL;
136 	tm_cipher = NULL;
137 	tm_verify = SSL_VERIFY_NONE;
138 	maxTime = SECONDS;
139 	tm_ctx = NULL;
140 	s_time_meth = NULL;
141 	s_www_path = NULL;
142 	bytes_read = 0;
143 	st_bugs = 0;
144 	perform = 0;
145 
146 	t_nbio = 0;
147 }
148 
149 /***********************************************************************
150  * usage - display usage message
151  */
152 static void
153 s_time_usage(void)
154 {
155 	static const char umsg[] = "\
156 -time arg     - max number of seconds to collect data, default %d\n\
157 -verify arg   - turn on peer certificate verification, arg == depth\n\
158 -cert arg     - certificate file to use, PEM format assumed\n\
159 -key arg      - RSA file to use, PEM format assumed, key is in cert file\n\
160                 file if not specified by this option\n\
161 -CApath arg   - PEM format directory of CA's\n\
162 -CAfile arg   - PEM format file of CA's\n\
163 -cipher       - preferred cipher to use, play with 'openssl ciphers'\n\n";
164 
165 	printf("usage: s_time <args>\n\n");
166 
167 	printf("-connect host:port - host:port to connect to (default is %s)\n", SSL_CONNECT_NAME);
168 	printf("-nbio         - Run with non-blocking IO\n");
169 	printf("-ssl2         - Just use SSLv2\n");
170 	printf("-ssl3         - Just use SSLv3\n");
171 	printf("-bugs         - Turn on SSL bug compatibility\n");
172 	printf("-new          - Just time new connections\n");
173 	printf("-reuse        - Just time connection reuse\n");
174 	printf("-www page     - Retrieve 'page' from the site\n");
175 	printf(umsg, SECONDS);
176 }
177 
178 /***********************************************************************
179  * parseArgs - Parse command line arguments and initialize data
180  *
181  * Returns 0 if ok, -1 on bad args
182  */
183 static int
184 parseArgs(int argc, char **argv)
185 {
186 	int badop = 0;
187 	const char *errstr;
188 
189 	verify_depth = 0;
190 	verify_error = X509_V_OK;
191 
192 	argc--;
193 	argv++;
194 
195 	while (argc >= 1) {
196 		if (strcmp(*argv, "-connect") == 0) {
197 			if (--argc < 1)
198 				goto bad;
199 			host = *(++argv);
200 		}
201 #if 0
202 		else if (strcmp(*argv, "-host") == 0) {
203 			if (--argc < 1)
204 				goto bad;
205 			host = *(++argv);
206 		} else if (strcmp(*argv, "-port") == 0) {
207 			if (--argc < 1)
208 				goto bad;
209 			port = *(++argv);
210 		}
211 #endif
212 		else if (strcmp(*argv, "-reuse") == 0)
213 			perform = 2;
214 		else if (strcmp(*argv, "-new") == 0)
215 			perform = 1;
216 		else if (strcmp(*argv, "-verify") == 0) {
217 			tm_verify = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
218 			if (--argc < 1)
219 				goto bad;
220 			verify_depth = strtonum(*(++argv), 0, INT_MAX, &errstr);
221 			if (errstr)
222 				goto bad;
223 			BIO_printf(bio_err, "verify depth is %d\n", verify_depth);
224 
225 		} else if (strcmp(*argv, "-cert") == 0) {
226 
227 			if (--argc < 1)
228 				goto bad;
229 			t_cert_file = *(++argv);
230 
231 		} else if (strcmp(*argv, "-key") == 0) {
232 
233 			if (--argc < 1)
234 				goto bad;
235 			t_key_file = *(++argv);
236 
237 		} else if (strcmp(*argv, "-CApath") == 0) {
238 
239 			if (--argc < 1)
240 				goto bad;
241 			CApath = *(++argv);
242 
243 		} else if (strcmp(*argv, "-CAfile") == 0) {
244 
245 			if (--argc < 1)
246 				goto bad;
247 			CAfile = *(++argv);
248 
249 		} else if (strcmp(*argv, "-cipher") == 0) {
250 
251 			if (--argc < 1)
252 				goto bad;
253 			tm_cipher = *(++argv);
254 		}
255 		else if (strcmp(*argv, "-nbio") == 0) {
256 			t_nbio = 1;
257 		}
258 		else if (strcmp(*argv, "-www") == 0) {
259 			if (--argc < 1)
260 				goto bad;
261 			s_www_path = *(++argv);
262 			if (strlen(s_www_path) > MYBUFSIZ - 100) {
263 				BIO_printf(bio_err, "-www option too long\n");
264 				badop = 1;
265 			}
266 		} else if (strcmp(*argv, "-bugs") == 0)
267 			st_bugs = 1;
268 		else if (strcmp(*argv, "-ssl3") == 0)
269 			s_time_meth = SSLv3_client_method();
270 		else if (strcmp(*argv, "-time") == 0) {
271 
272 			if (--argc < 1)
273 				goto bad;
274 			maxTime = strtonum(*(++argv), 0, INT_MAX, &errstr);
275 			if (errstr)
276 				goto bad;
277 		} else {
278 			BIO_printf(bio_err, "unknown option %s\n", *argv);
279 			badop = 1;
280 			break;
281 		}
282 
283 		argc--;
284 		argv++;
285 	}
286 
287 	if (perform == 0)
288 		perform = 3;
289 
290 	if (badop) {
291 bad:
292 		s_time_usage();
293 		return -1;
294 	}
295 	return 0;		/* Valid args */
296 }
297 
298 /***********************************************************************
299  * TIME - time functions
300  */
301 #define START	0
302 #define STOP	1
303 
304 static double
305 tm_Time_F(int s)
306 {
307 	return app_tminterval(s, 1);
308 }
309 
310 /***********************************************************************
311  * MAIN - main processing area for client
312  *			real name depends on MONOLITH
313  */
314 int s_time_main(int, char **);
315 
316 int
317 s_time_main(int argc, char **argv)
318 {
319 	double totalTime = 0.0;
320 	int nConn = 0;
321 	SSL *scon = NULL;
322 	long finishtime = 0;
323 	int ret = 1, i;
324 	char buf[1024 * 8];
325 	int ver;
326 
327 	s_time_init();
328 
329 	s_time_meth = SSLv23_client_method();
330 
331 	/* parse the command line arguments */
332 	if (parseArgs(argc, argv) < 0)
333 		goto end;
334 
335 	if ((tm_ctx = SSL_CTX_new(s_time_meth)) == NULL)
336 		return (1);
337 
338 	SSL_CTX_set_quiet_shutdown(tm_ctx, 1);
339 
340 	if (st_bugs)
341 		SSL_CTX_set_options(tm_ctx, SSL_OP_ALL);
342 	SSL_CTX_set_cipher_list(tm_ctx, tm_cipher);
343 	if (!set_cert_stuff(tm_ctx, t_cert_file, t_key_file))
344 		goto end;
345 
346 	if ((!SSL_CTX_load_verify_locations(tm_ctx, CAfile, CApath)) ||
347 	    (!SSL_CTX_set_default_verify_paths(tm_ctx))) {
348 		/*
349 		 * BIO_printf(bio_err,"error setting default verify
350 		 * locations\n");
351 		 */
352 		ERR_print_errors(bio_err);
353 		/* goto end; */
354 	}
355 	if (tm_cipher == NULL)
356 		tm_cipher = getenv("SSL_CIPHER");
357 
358 	if (tm_cipher == NULL) {
359 		fprintf(stderr, "No CIPHER specified\n");
360 	}
361 	if (!(perform & 1))
362 		goto next;
363 	printf("Collecting connection statistics for %d seconds\n", maxTime);
364 
365 	/* Loop and time how long it takes to make connections */
366 
367 	bytes_read = 0;
368 	finishtime = (long) time(NULL) + maxTime;
369 	tm_Time_F(START);
370 	for (;;) {
371 		if (finishtime < (long) time(NULL))
372 			break;
373 		if ((scon = doConnection(NULL)) == NULL)
374 			goto end;
375 
376 		if (s_www_path != NULL) {
377 			int retval = snprintf(buf, sizeof buf,
378 			    "GET %s HTTP/1.0\r\n\r\n", s_www_path);
379 			if ((size_t)retval >= sizeof buf) {
380 				fprintf(stderr, "URL too long\n");
381 				goto end;
382 			}
383 			SSL_write(scon, buf, strlen(buf));
384 			while ((i = SSL_read(scon, buf, sizeof(buf))) > 0)
385 				bytes_read += i;
386 		}
387 #ifdef NO_SHUTDOWN
388 		SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
389 #else
390 		SSL_shutdown(scon);
391 #endif
392 		shutdown(SSL_get_fd(scon), SHUT_RDWR);
393 		close(SSL_get_fd(scon));
394 
395 		nConn += 1;
396 		if (SSL_session_reused(scon))
397 			ver = 'r';
398 		else {
399 			ver = SSL_version(scon);
400 			if (ver == TLS1_VERSION)
401 				ver = 't';
402 			else if (ver == SSL3_VERSION)
403 				ver = '3';
404 			else if (ver == SSL2_VERSION)
405 				ver = '2';
406 			else
407 				ver = '*';
408 		}
409 		fputc(ver, stdout);
410 		fflush(stdout);
411 
412 		SSL_free(scon);
413 		scon = NULL;
414 	}
415 	totalTime += tm_Time_F(STOP);	/* Add the time for this iteration */
416 
417 	i = (int) ((long) time(NULL) - finishtime + maxTime);
418 	printf("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double) nConn / totalTime), bytes_read);
419 	printf("%d connections in %ld real seconds, %ld bytes read per connection\n", nConn, (long) time(NULL) - finishtime + maxTime, bytes_read / nConn);
420 
421 	/*
422 	 * Now loop and time connections using the same session id over and
423 	 * over
424 	 */
425 
426 next:
427 	if (!(perform & 2))
428 		goto end;
429 	printf("\n\nNow timing with session id reuse.\n");
430 
431 	/* Get an SSL object so we can reuse the session id */
432 	if ((scon = doConnection(NULL)) == NULL) {
433 		fprintf(stderr, "Unable to get connection\n");
434 		goto end;
435 	}
436 	if (s_www_path != NULL) {
437 		int retval = snprintf(buf, sizeof buf,
438 		    "GET %s HTTP/1.0\r\n\r\n", s_www_path);
439 		if ((size_t)retval >= sizeof buf) {
440 			fprintf(stderr, "URL too long\n");
441 			goto end;
442 		}
443 		SSL_write(scon, buf, strlen(buf));
444 		while (SSL_read(scon, buf, sizeof(buf)) > 0);
445 	}
446 #ifdef NO_SHUTDOWN
447 	SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
448 #else
449 	SSL_shutdown(scon);
450 #endif
451 	shutdown(SSL_get_fd(scon), SHUT_RDWR);
452 	close(SSL_get_fd(scon));
453 
454 	nConn = 0;
455 	totalTime = 0.0;
456 
457 	finishtime = (long) time(NULL) + maxTime;
458 
459 	printf("starting\n");
460 	bytes_read = 0;
461 	tm_Time_F(START);
462 
463 	for (;;) {
464 		if (finishtime < (long) time(NULL))
465 			break;
466 		if ((doConnection(scon)) == NULL)
467 			goto end;
468 
469 		if (s_www_path) {
470 			int retval = snprintf(buf, sizeof buf,
471 			    "GET %s HTTP/1.0\r\n\r\n", s_www_path);
472 			if ((size_t)retval >= sizeof buf) {
473 				fprintf(stderr, "URL too long\n");
474 				goto end;
475 			}
476 			SSL_write(scon, buf, strlen(buf));
477 			while ((i = SSL_read(scon, buf, sizeof(buf))) > 0)
478 				bytes_read += i;
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 		shutdown(SSL_get_fd(scon), SHUT_RDWR);
486 		close(SSL_get_fd(scon));
487 
488 		nConn += 1;
489 		if (SSL_session_reused(scon))
490 			ver = 'r';
491 		else {
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 	totalTime += tm_Time_F(STOP);	/* Add the time for this iteration */
506 
507 
508 	printf("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double) nConn / totalTime), bytes_read);
509 	printf("%d connections in %ld real seconds, %ld bytes read per connection\n", nConn, (long) time(NULL) - finishtime + maxTime, bytes_read / nConn);
510 
511 	ret = 0;
512 end:
513 	if (scon != NULL)
514 		SSL_free(scon);
515 
516 	if (tm_ctx != NULL) {
517 		SSL_CTX_free(tm_ctx);
518 		tm_ctx = NULL;
519 	}
520 
521 	return (ret);
522 }
523 
524 /***********************************************************************
525  * doConnection - make a connection
526  * Args:
527  *		scon	= earlier ssl connection for session id, or NULL
528  * Returns:
529  *		SSL *	= the connection pointer.
530  */
531 static SSL *
532 doConnection(SSL * scon)
533 {
534 	struct pollfd pfd[1];
535 	SSL *serverCon;
536 	BIO *conn;
537 	int i;
538 
539 	if ((conn = BIO_new(BIO_s_connect())) == NULL)
540 		return (NULL);
541 
542 /*	BIO_set_conn_port(conn,port);*/
543 	BIO_set_conn_hostname(conn, host);
544 
545 	if (scon == NULL)
546 		serverCon = SSL_new(tm_ctx);
547 	else {
548 		serverCon = scon;
549 		SSL_set_connect_state(serverCon);
550 	}
551 
552 	SSL_set_bio(serverCon, conn, conn);
553 
554 #if 0
555 	if (scon != NULL)
556 		SSL_set_session(serverCon, SSL_get_session(scon));
557 #endif
558 
559 	/* ok, lets connect */
560 	for (;;) {
561 		i = SSL_connect(serverCon);
562 		if (BIO_sock_should_retry(i)) {
563 			BIO_printf(bio_err, "DELAY\n");
564 
565 			i = SSL_get_fd(serverCon);
566 			pfd[0].fd = i;
567 			pfd[0].events = POLLIN;
568 			poll(pfd, 1, -1);
569 			continue;
570 		}
571 		break;
572 	}
573 	if (i <= 0) {
574 		BIO_printf(bio_err, "ERROR\n");
575 		if (verify_error != X509_V_OK)
576 			BIO_printf(bio_err, "verify error:%s\n",
577 			    X509_verify_cert_error_string(verify_error));
578 		else
579 			ERR_print_errors(bio_err);
580 		if (scon == NULL)
581 			SSL_free(serverCon);
582 		return NULL;
583 	}
584 	return serverCon;
585 }
586