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