Annotation of src/usr.bin/openssl/s_time.c, Revision 1.5
1.5 ! jsing 1: /* $OpenBSD: s_time.c,v 1.4 2015/02/08 10:22:45 doug Exp $ */
1.1 jsing 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:
1.3 deraadt 66: #include <sys/types.h>
1.1 jsing 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>
1.3 deraadt 74: #include <poll.h>
1.1 jsing 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 BUFSIZZ 1024*10
88:
89: #define MYBUFSIZ 1024*8
90:
91: #undef min
92: #undef max
93: #define min(a,b) (((a) < (b)) ? (a) : (b))
94: #define max(a,b) (((a) > (b)) ? (a) : (b))
95:
96: #define SECONDS 30
97: extern int verify_depth;
98: extern int verify_error;
99:
100: static void s_time_usage(void);
101: static SSL *doConnection(SSL * scon);
102:
103: static SSL_CTX *tm_ctx = NULL;
104: static const SSL_METHOD *s_time_meth = NULL;
105: static long bytes_read = 0;
106:
1.5 ! jsing 107: struct {
! 108: int bugs;
! 109: char *CAfile;
! 110: char *CApath;
! 111: char *certfile;
! 112: char *cipher;
! 113: char *host;
! 114: char *keyfile;
! 115: int maxtime;
! 116: int nbio;
! 117: int perform;
! 118: int ssl3;
! 119: int verify;
! 120: int verify_depth;
! 121: char *www_path;
! 122: } s_time_config;
! 123:
! 124: struct option s_time_options[] = {
! 125: {
! 126: .name = "bugs",
! 127: .desc = "Enable workarounds for known SSL/TLS bugs",
! 128: .type = OPTION_FLAG,
! 129: .opt.flag = &s_time_config.bugs,
! 130: },
! 131: {
! 132: .name = "CAfile",
! 133: .argname = "file",
! 134: .desc = "File containing trusted certificates in PEM format",
! 135: .type = OPTION_ARG,
! 136: .opt.arg = &s_time_config.CAfile,
! 137: },
! 138: {
! 139: .name = "CApath",
! 140: .argname = "path",
! 141: .desc = "Directory containing trusted certificates",
! 142: .type = OPTION_ARG,
! 143: .opt.arg = &s_time_config.CApath,
! 144: },
! 145: {
! 146: .name = "cert",
! 147: .argname = "file",
! 148: .desc = "Client certificate to use, if one is requested",
! 149: .type = OPTION_ARG,
! 150: .opt.arg = &s_time_config.certfile,
! 151: },
! 152: {
! 153: .name = "cipher",
! 154: .argname = "list",
! 155: .desc = "List of cipher suites to send to the server",
! 156: .type = OPTION_ARG,
! 157: .opt.arg = &s_time_config.cipher,
! 158: },
! 159: {
! 160: .name = "connect",
! 161: .argname = "host:port",
! 162: .desc = "Host and port to connect to (default "
! 163: SSL_CONNECT_NAME ")",
! 164: .type = OPTION_ARG,
! 165: .opt.arg = &s_time_config.host,
! 166: },
! 167: {
! 168: .name = "key",
! 169: .argname = "file",
! 170: .desc = "Client private key to use, if one is required",
! 171: .type = OPTION_ARG,
! 172: .opt.arg = &s_time_config.keyfile,
! 173: },
! 174: {
! 175: .name = "nbio",
! 176: .desc = "Use non-blocking I/O",
! 177: .type = OPTION_FLAG,
! 178: .opt.flag = &s_time_config.nbio,
! 179: },
! 180: {
! 181: .name = "new",
! 182: .desc = "Use a new session ID for each connection",
! 183: .type = OPTION_VALUE,
! 184: .opt.value = &s_time_config.perform,
! 185: .value = 1,
! 186: },
! 187: {
! 188: .name = "reuse",
! 189: .desc = "Reuse the same session ID for each connection",
! 190: .type = OPTION_VALUE,
! 191: .opt.value = &s_time_config.perform,
! 192: .value = 2,
! 193: },
! 194: {
! 195: .name = "ssl3",
! 196: .desc = "Only use SSLv3",
! 197: .type = OPTION_FLAG,
! 198: .opt.flag = &s_time_config.ssl3,
! 199: },
! 200: {
! 201: .name = "time",
! 202: .argname = "seconds",
! 203: .desc = "Duration to perform timing tests for (default 30)",
! 204: .type = OPTION_ARG_INT,
! 205: .opt.value = &s_time_config.maxtime,
! 206: },
! 207: {
! 208: .name = "verify",
! 209: .argname = "depth",
! 210: .desc = "Enable peer certificate verification with given depth",
! 211: .type = OPTION_ARG_INT,
! 212: .opt.value = &s_time_config.verify_depth,
! 213: },
! 214: {
! 215: .name = "www",
! 216: .argname = "page",
! 217: .desc = "Page to GET from the server (default none)",
! 218: .type = OPTION_ARG,
! 219: .opt.arg = &s_time_config.www_path,
! 220: },
! 221: { NULL },
! 222: };
1.1 jsing 223:
224: static void
225: s_time_usage(void)
226: {
1.5 ! jsing 227: fprintf(stderr,
! 228: "usage: s_time "
! 229: "[-bugs] [-CAfile file] [-CApath directory] [-cert file]\n"
! 230: " [-cipher cipherlist] [-connect host:port] [-key keyfile]\n"
! 231: " [-nbio] [-new] [-reuse] [-ssl3] [-time seconds]\n"
! 232: " [-verify depth] [-www page]\n\n");
! 233: options_usage(s_time_options);
1.1 jsing 234: }
235:
236: /***********************************************************************
237: * TIME - time functions
238: */
239: #define START 0
240: #define STOP 1
241:
242: static double
243: tm_Time_F(int s)
244: {
245: return app_tminterval(s, 1);
246: }
247:
248: /***********************************************************************
249: * MAIN - main processing area for client
250: * real name depends on MONOLITH
251: */
252: int s_time_main(int, char **);
253:
254: int
255: s_time_main(int argc, char **argv)
256: {
257: double totalTime = 0.0;
258: int nConn = 0;
259: SSL *scon = NULL;
260: long finishtime = 0;
261: int ret = 1, i;
262: char buf[1024 * 8];
263: int ver;
1.5 ! jsing 264:
! 265: s_time_meth = SSLv23_client_method();
1.1 jsing 266:
1.5 ! jsing 267: verify_depth = 0;
! 268: verify_error = X509_V_OK;
! 269:
! 270: memset(&s_time_config, 0, sizeof(s_time_config));
! 271:
! 272: s_time_config.host = SSL_CONNECT_NAME;
! 273: s_time_config.maxtime = SECONDS;
! 274: s_time_config.perform = 3;
! 275: s_time_config.verify = SSL_VERIFY_NONE;
! 276: s_time_config.verify_depth = -1;
1.1 jsing 277:
1.5 ! jsing 278: if (options_parse(argc, argv, s_time_options, NULL, NULL) != 0) {
! 279: s_time_usage();
! 280: goto end;
! 281: }
! 282:
! 283: if (s_time_config.ssl3)
! 284: s_time_meth = SSLv3_client_method();
! 285:
! 286: if (s_time_config.verify_depth >= 0) {
! 287: s_time_config.verify = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
! 288: verify_depth = s_time_config.verify_depth;
! 289: BIO_printf(bio_err, "verify depth is %d\n", verify_depth);
! 290: }
1.1 jsing 291:
1.5 ! jsing 292: if (s_time_config.www_path != NULL &&
! 293: strlen(s_time_config.www_path) > MYBUFSIZ - 100) {
! 294: BIO_printf(bio_err, "-www option too long\n");
1.1 jsing 295: goto end;
1.5 ! jsing 296: }
1.1 jsing 297:
298: if ((tm_ctx = SSL_CTX_new(s_time_meth)) == NULL)
299: return (1);
300:
301: SSL_CTX_set_quiet_shutdown(tm_ctx, 1);
302:
1.5 ! jsing 303: if (s_time_config.bugs)
1.1 jsing 304: SSL_CTX_set_options(tm_ctx, SSL_OP_ALL);
1.5 ! jsing 305: SSL_CTX_set_cipher_list(tm_ctx, s_time_config.cipher);
! 306: if (!set_cert_stuff(tm_ctx, s_time_config.certfile,
! 307: s_time_config.keyfile))
1.1 jsing 308: goto end;
309:
1.5 ! jsing 310: if ((!SSL_CTX_load_verify_locations(tm_ctx, s_time_config.CAfile,
! 311: s_time_config.CApath)) ||
1.1 jsing 312: (!SSL_CTX_set_default_verify_paths(tm_ctx))) {
313: /*
314: * BIO_printf(bio_err,"error setting default verify
315: * locations\n");
316: */
317: ERR_print_errors(bio_err);
318: /* goto end; */
319: }
1.5 ! jsing 320: if (s_time_config.cipher == NULL)
! 321: s_time_config.cipher = getenv("SSL_CIPHER");
1.1 jsing 322:
1.5 ! jsing 323: if (s_time_config.cipher == NULL) {
1.1 jsing 324: fprintf(stderr, "No CIPHER specified\n");
325: }
1.5 ! jsing 326: if (!(s_time_config.perform & 1))
1.1 jsing 327: goto next;
1.5 ! jsing 328: printf("Collecting connection statistics for %d seconds\n",
! 329: s_time_config.maxtime);
1.1 jsing 330:
331: /* Loop and time how long it takes to make connections */
332:
333: bytes_read = 0;
1.5 ! jsing 334: finishtime = (long) time(NULL) + s_time_config.maxtime;
1.1 jsing 335: tm_Time_F(START);
336: for (;;) {
337: if (finishtime < (long) time(NULL))
338: break;
339: if ((scon = doConnection(NULL)) == NULL)
340: goto end;
341:
1.5 ! jsing 342: if (s_time_config.www_path != NULL) {
1.2 doug 343: int retval = snprintf(buf, sizeof buf,
1.5 ! jsing 344: "GET %s HTTP/1.0\r\n\r\n", s_time_config.www_path);
1.2 doug 345: if ((size_t)retval >= sizeof buf) {
1.1 jsing 346: fprintf(stderr, "URL too long\n");
347: goto end;
348: }
349: SSL_write(scon, buf, strlen(buf));
350: while ((i = SSL_read(scon, buf, sizeof(buf))) > 0)
351: bytes_read += i;
352: }
353: #ifdef NO_SHUTDOWN
354: SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
355: #else
356: SSL_shutdown(scon);
357: #endif
358: shutdown(SSL_get_fd(scon), SHUT_RDWR);
359: close(SSL_get_fd(scon));
360:
361: nConn += 1;
362: if (SSL_session_reused(scon))
363: ver = 'r';
364: else {
365: ver = SSL_version(scon);
366: if (ver == TLS1_VERSION)
367: ver = 't';
368: else if (ver == SSL3_VERSION)
369: ver = '3';
370: else if (ver == SSL2_VERSION)
371: ver = '2';
372: else
373: ver = '*';
374: }
375: fputc(ver, stdout);
376: fflush(stdout);
377:
378: SSL_free(scon);
379: scon = NULL;
380: }
381: totalTime += tm_Time_F(STOP); /* Add the time for this iteration */
382:
1.5 ! jsing 383: i = (int) ((long) time(NULL) - finishtime + s_time_config.maxtime);
1.1 jsing 384: printf("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double) nConn / totalTime), bytes_read);
1.5 ! jsing 385: printf("%d connections in %ld real seconds, %ld bytes read per connection\n", nConn, (long) time(NULL) - finishtime + s_time_config.maxtime, bytes_read / nConn);
1.1 jsing 386:
387: /*
388: * Now loop and time connections using the same session id over and
389: * over
390: */
391:
392: next:
1.5 ! jsing 393: if (!(s_time_config.perform & 2))
1.1 jsing 394: goto end;
395: printf("\n\nNow timing with session id reuse.\n");
396:
397: /* Get an SSL object so we can reuse the session id */
398: if ((scon = doConnection(NULL)) == NULL) {
399: fprintf(stderr, "Unable to get connection\n");
400: goto end;
401: }
1.5 ! jsing 402: if (s_time_config.www_path != NULL) {
1.2 doug 403: int retval = snprintf(buf, sizeof buf,
1.5 ! jsing 404: "GET %s HTTP/1.0\r\n\r\n", s_time_config.www_path);
1.2 doug 405: if ((size_t)retval >= sizeof buf) {
1.1 jsing 406: fprintf(stderr, "URL too long\n");
407: goto end;
408: }
409: SSL_write(scon, buf, strlen(buf));
410: while (SSL_read(scon, buf, sizeof(buf)) > 0);
411: }
412: #ifdef NO_SHUTDOWN
413: SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
414: #else
415: SSL_shutdown(scon);
416: #endif
417: shutdown(SSL_get_fd(scon), SHUT_RDWR);
418: close(SSL_get_fd(scon));
419:
420: nConn = 0;
421: totalTime = 0.0;
422:
1.5 ! jsing 423: finishtime = (long) time(NULL) + s_time_config.maxtime;
1.1 jsing 424:
425: printf("starting\n");
426: bytes_read = 0;
427: tm_Time_F(START);
428:
429: for (;;) {
430: if (finishtime < (long) time(NULL))
431: break;
432: if ((doConnection(scon)) == NULL)
433: goto end;
434:
1.5 ! jsing 435: if (s_time_config.www_path) {
1.2 doug 436: int retval = snprintf(buf, sizeof buf,
1.5 ! jsing 437: "GET %s HTTP/1.0\r\n\r\n", s_time_config.www_path);
1.2 doug 438: if ((size_t)retval >= sizeof buf) {
1.1 jsing 439: fprintf(stderr, "URL too long\n");
440: goto end;
441: }
442: SSL_write(scon, buf, strlen(buf));
443: while ((i = SSL_read(scon, buf, sizeof(buf))) > 0)
444: bytes_read += i;
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 += 1;
455: if (SSL_session_reused(scon))
456: ver = 'r';
457: else {
458: ver = SSL_version(scon);
459: if (ver == TLS1_VERSION)
460: ver = 't';
461: else if (ver == SSL3_VERSION)
462: ver = '3';
463: else if (ver == SSL2_VERSION)
464: ver = '2';
465: else
466: ver = '*';
467: }
468: fputc(ver, stdout);
469: fflush(stdout);
470: }
471: totalTime += tm_Time_F(STOP); /* Add the time for this iteration */
472:
473:
474: printf("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double) nConn / totalTime), bytes_read);
1.5 ! jsing 475: printf("%d connections in %ld real seconds, %ld bytes read per connection\n", nConn, (long) time(NULL) - finishtime + s_time_config.maxtime, bytes_read / nConn);
1.1 jsing 476:
477: ret = 0;
478: end:
479: if (scon != NULL)
480: SSL_free(scon);
481:
482: if (tm_ctx != NULL) {
483: SSL_CTX_free(tm_ctx);
484: tm_ctx = NULL;
485: }
486:
487: return (ret);
488: }
489:
490: /***********************************************************************
491: * doConnection - make a connection
492: * Args:
493: * scon = earlier ssl connection for session id, or NULL
494: * Returns:
495: * SSL * = the connection pointer.
496: */
497: static SSL *
498: doConnection(SSL * scon)
499: {
1.3 deraadt 500: struct pollfd pfd[1];
501: SSL *serverCon;
1.1 jsing 502: BIO *conn;
1.3 deraadt 503: int i;
1.1 jsing 504:
505: if ((conn = BIO_new(BIO_s_connect())) == NULL)
506: return (NULL);
507:
508: /* BIO_set_conn_port(conn,port);*/
1.5 ! jsing 509: BIO_set_conn_hostname(conn, s_time_config.host);
1.1 jsing 510:
511: if (scon == NULL)
512: serverCon = SSL_new(tm_ctx);
513: else {
514: serverCon = scon;
515: SSL_set_connect_state(serverCon);
516: }
517:
518: SSL_set_bio(serverCon, conn, conn);
519:
520: /* ok, lets connect */
521: for (;;) {
522: i = SSL_connect(serverCon);
523: if (BIO_sock_should_retry(i)) {
524: BIO_printf(bio_err, "DELAY\n");
525:
526: i = SSL_get_fd(serverCon);
1.3 deraadt 527: pfd[0].fd = i;
528: pfd[0].events = POLLIN;
529: poll(pfd, 1, -1);
1.1 jsing 530: continue;
531: }
532: break;
533: }
534: if (i <= 0) {
535: BIO_printf(bio_err, "ERROR\n");
536: if (verify_error != X509_V_OK)
537: BIO_printf(bio_err, "verify error:%s\n",
538: X509_verify_cert_error_string(verify_error));
539: else
540: ERR_print_errors(bio_err);
541: if (scon == NULL)
542: SSL_free(serverCon);
543: return NULL;
544: }
545: return serverCon;
546: }