1 /* 2 * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 14 #include <openssl/opensslconf.h> 15 16 #ifndef OPENSSL_NO_SOCK 17 18 #include "apps.h" 19 #include "progs.h" 20 #include <openssl/x509.h> 21 #include <openssl/ssl.h> 22 #include <openssl/pem.h> 23 #include "s_apps.h" 24 #include <openssl/err.h> 25 #include "internal/sockets.h" 26 #if !defined(OPENSSL_SYS_MSDOS) 27 #include <unistd.h> 28 #endif 29 30 #define SSL_CONNECT_NAME "localhost:4433" 31 32 #define SECONDS 30 33 #define SECONDSSTR "30" 34 35 static SSL *doConnection(SSL *scon, const char *host, SSL_CTX *ctx); 36 37 /* 38 * Define a HTTP get command globally. 39 * Also define the size of the command, this is two bytes less than 40 * the size of the string because the %s is replaced by the URL. 41 */ 42 static const char fmt_http_get_cmd[] = "GET %s HTTP/1.0\r\n\r\n"; 43 static const size_t fmt_http_get_cmd_size = sizeof(fmt_http_get_cmd) - 2; 44 45 typedef enum OPTION_choice { 46 OPT_COMMON, 47 OPT_CONNECT, 48 OPT_CIPHER, 49 OPT_CIPHERSUITES, 50 OPT_CERT, 51 OPT_NAMEOPT, 52 OPT_KEY, 53 OPT_CAPATH, 54 OPT_CAFILE, 55 OPT_CASTORE, 56 OPT_NOCAPATH, 57 OPT_NOCAFILE, 58 OPT_NOCASTORE, 59 OPT_NEW, 60 OPT_REUSE, 61 OPT_BUGS, 62 OPT_VERIFY, 63 OPT_TIME, 64 OPT_SSL3, 65 OPT_WWW, 66 OPT_TLS1, 67 OPT_TLS1_1, 68 OPT_TLS1_2, 69 OPT_TLS1_3, 70 OPT_PROV_ENUM 71 } OPTION_CHOICE; 72 73 const OPTIONS s_time_options[] = { 74 OPT_SECTION("General"), 75 { "help", OPT_HELP, '-', "Display this summary" }, 76 77 OPT_SECTION("Connection"), 78 { "connect", OPT_CONNECT, 's', 79 "Where to connect as post:port (default is " SSL_CONNECT_NAME ")" }, 80 { "new", OPT_NEW, '-', "Just time new connections" }, 81 { "reuse", OPT_REUSE, '-', "Just time connection reuse" }, 82 { "bugs", OPT_BUGS, '-', "Turn on SSL bug compatibility" }, 83 { "cipher", OPT_CIPHER, 's', "TLSv1.2 and below cipher list to be used" }, 84 { "ciphersuites", OPT_CIPHERSUITES, 's', 85 "Specify TLSv1.3 ciphersuites to be used" }, 86 #ifndef OPENSSL_NO_SSL3 87 { "ssl3", OPT_SSL3, '-', "Just use SSLv3" }, 88 #endif 89 #ifndef OPENSSL_NO_TLS1 90 { "tls1", OPT_TLS1, '-', "Just use TLSv1.0" }, 91 #endif 92 #ifndef OPENSSL_NO_TLS1_1 93 { "tls1_1", OPT_TLS1_1, '-', "Just use TLSv1.1" }, 94 #endif 95 #ifndef OPENSSL_NO_TLS1_2 96 { "tls1_2", OPT_TLS1_2, '-', "Just use TLSv1.2" }, 97 #endif 98 #ifndef OPENSSL_NO_TLS1_3 99 { "tls1_3", OPT_TLS1_3, '-', "Just use TLSv1.3" }, 100 #endif 101 { "verify", OPT_VERIFY, 'p', 102 "Turn on peer certificate verification, set depth" }, 103 { "time", OPT_TIME, 'p', "Seconds to collect data, default " SECONDSSTR }, 104 { "www", OPT_WWW, 's', "Fetch specified page from the site" }, 105 106 OPT_SECTION("Certificate"), 107 { "nameopt", OPT_NAMEOPT, 's', "Certificate subject/issuer name printing options" }, 108 { "cert", OPT_CERT, '<', "Cert file to use, PEM format assumed" }, 109 { "key", OPT_KEY, '<', "File with key, PEM; default is -cert file" }, 110 { "cafile", OPT_CAFILE, '<', "PEM format file of CA's" }, 111 { "CAfile", OPT_CAFILE, '<', "PEM format file of CA's" }, 112 { "CApath", OPT_CAPATH, '/', "PEM format directory of CA's" }, 113 { "CAstore", OPT_CASTORE, ':', "URI to store of CA's" }, 114 { "no-CAfile", OPT_NOCAFILE, '-', 115 "Do not load the default certificates file" }, 116 { "no-CApath", OPT_NOCAPATH, '-', 117 "Do not load certificates from the default certificates directory" }, 118 { "no-CAstore", OPT_NOCASTORE, '-', 119 "Do not load certificates from the default certificates store URI" }, 120 121 OPT_PROV_OPTIONS, 122 { NULL } 123 }; 124 125 #define START 0 126 #define STOP 1 127 128 static double tm_Time_F(int s) 129 { 130 return app_tminterval(s, 1); 131 } 132 133 int s_time_main(int argc, char **argv) 134 { 135 char buf[1024 * 8]; 136 SSL *scon = NULL; 137 SSL_CTX *ctx = NULL; 138 const SSL_METHOD *meth = NULL; 139 char *CApath = NULL, *CAfile = NULL, *CAstore = NULL; 140 char *cipher = NULL, *ciphersuites = NULL; 141 char *www_path = NULL; 142 char *host = SSL_CONNECT_NAME, *certfile = NULL, *keyfile = NULL, *prog; 143 double totalTime = 0.0; 144 int noCApath = 0, noCAfile = 0, noCAstore = 0; 145 int maxtime = SECONDS, nConn = 0, perform = 3, ret = 1, i, st_bugs = 0; 146 long bytes_read = 0, finishtime = 0; 147 OPTION_CHOICE o; 148 int min_version = 0, max_version = 0, ver, buf_len, fd; 149 size_t buf_size; 150 151 meth = TLS_client_method(); 152 153 prog = opt_init(argc, argv, s_time_options); 154 while ((o = opt_next()) != OPT_EOF) { 155 switch (o) { 156 case OPT_EOF: 157 case OPT_ERR: 158 opthelp: 159 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); 160 goto end; 161 case OPT_HELP: 162 opt_help(s_time_options); 163 ret = 0; 164 goto end; 165 case OPT_CONNECT: 166 host = opt_arg(); 167 break; 168 case OPT_REUSE: 169 perform = 2; 170 break; 171 case OPT_NEW: 172 perform = 1; 173 break; 174 case OPT_VERIFY: 175 verify_args.depth = opt_int_arg(); 176 BIO_printf(bio_err, "%s: verify depth is %d\n", 177 prog, verify_args.depth); 178 break; 179 case OPT_CERT: 180 certfile = opt_arg(); 181 break; 182 case OPT_NAMEOPT: 183 if (!set_nameopt(opt_arg())) 184 goto end; 185 break; 186 case OPT_KEY: 187 keyfile = opt_arg(); 188 break; 189 case OPT_CAPATH: 190 CApath = opt_arg(); 191 break; 192 case OPT_CAFILE: 193 CAfile = opt_arg(); 194 break; 195 case OPT_NOCAPATH: 196 noCApath = 1; 197 break; 198 case OPT_NOCAFILE: 199 noCAfile = 1; 200 break; 201 case OPT_CASTORE: 202 CAstore = opt_arg(); 203 break; 204 case OPT_NOCASTORE: 205 noCAstore = 1; 206 break; 207 case OPT_CIPHER: 208 cipher = opt_arg(); 209 break; 210 case OPT_CIPHERSUITES: 211 ciphersuites = opt_arg(); 212 break; 213 case OPT_BUGS: 214 st_bugs = 1; 215 break; 216 case OPT_TIME: 217 maxtime = opt_int_arg(); 218 break; 219 case OPT_WWW: 220 www_path = opt_arg(); 221 buf_size = strlen(www_path) + fmt_http_get_cmd_size; 222 if (buf_size > sizeof(buf)) { 223 BIO_printf(bio_err, "%s: -www option is too long\n", prog); 224 goto end; 225 } 226 break; 227 case OPT_SSL3: 228 min_version = SSL3_VERSION; 229 max_version = SSL3_VERSION; 230 break; 231 case OPT_TLS1: 232 min_version = TLS1_VERSION; 233 max_version = TLS1_VERSION; 234 break; 235 case OPT_TLS1_1: 236 min_version = TLS1_1_VERSION; 237 max_version = TLS1_1_VERSION; 238 break; 239 case OPT_TLS1_2: 240 min_version = TLS1_2_VERSION; 241 max_version = TLS1_2_VERSION; 242 break; 243 case OPT_TLS1_3: 244 min_version = TLS1_3_VERSION; 245 max_version = TLS1_3_VERSION; 246 break; 247 case OPT_PROV_CASES: 248 if (!opt_provider(o)) 249 goto end; 250 break; 251 } 252 } 253 254 /* No extra arguments. */ 255 if (!opt_check_rest_arg(NULL)) 256 goto opthelp; 257 258 if (cipher == NULL) 259 cipher = getenv("SSL_CIPHER"); 260 261 if ((ctx = SSL_CTX_new(meth)) == NULL) 262 goto end; 263 264 SSL_CTX_set_quiet_shutdown(ctx, 1); 265 if (SSL_CTX_set_min_proto_version(ctx, min_version) == 0) 266 goto end; 267 if (SSL_CTX_set_max_proto_version(ctx, max_version) == 0) 268 goto end; 269 270 if (st_bugs) 271 SSL_CTX_set_options(ctx, SSL_OP_ALL); 272 if (cipher != NULL && !SSL_CTX_set_cipher_list(ctx, cipher)) 273 goto end; 274 if (ciphersuites != NULL && !SSL_CTX_set_ciphersuites(ctx, ciphersuites)) 275 goto end; 276 if (!set_cert_stuff(ctx, certfile, keyfile)) 277 goto end; 278 279 if (!ctx_set_verify_locations(ctx, CAfile, noCAfile, CApath, noCApath, 280 CAstore, noCAstore)) { 281 ERR_print_errors(bio_err); 282 goto end; 283 } 284 if (!(perform & 1)) 285 goto next; 286 printf("Collecting connection statistics for %d seconds\n", maxtime); 287 288 /* Loop and time how long it takes to make connections */ 289 290 bytes_read = 0; 291 finishtime = (long)time(NULL) + maxtime; 292 tm_Time_F(START); 293 for (;;) { 294 if (finishtime < (long)time(NULL)) 295 break; 296 297 if ((scon = doConnection(NULL, host, ctx)) == NULL) 298 goto end; 299 300 if (www_path != NULL) { 301 buf_len = BIO_snprintf(buf, sizeof(buf), fmt_http_get_cmd, 302 www_path); 303 if (buf_len <= 0 || SSL_write(scon, buf, buf_len) <= 0) 304 goto end; 305 while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) 306 bytes_read += i; 307 } 308 SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); 309 BIO_closesocket(SSL_get_fd(scon)); 310 311 nConn += 1; 312 if (SSL_session_reused(scon)) { 313 ver = 'r'; 314 } else { 315 ver = SSL_version(scon); 316 if (ver == TLS1_VERSION) 317 ver = 't'; 318 else if (ver == SSL3_VERSION) 319 ver = '3'; 320 else 321 ver = '*'; 322 } 323 fputc(ver, stdout); 324 fflush(stdout); 325 326 SSL_free(scon); 327 scon = NULL; 328 } 329 totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ 330 331 printf("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", 332 nConn, totalTime, ((double)nConn / totalTime), bytes_read); 333 printf("%d connections in %ld real seconds, %ld bytes read per connection\n", 334 nConn, (long)time(NULL) - finishtime + maxtime, 335 nConn > 0 ? bytes_read / nConn : 0l); 336 337 /* 338 * Now loop and time connections using the same session id over and over 339 */ 340 341 next: 342 if (!(perform & 2)) { 343 ret = 0; 344 goto end; 345 } 346 printf("\n\nNow timing with session id reuse.\n"); 347 348 /* Get an SSL object so we can reuse the session id */ 349 if ((scon = doConnection(NULL, host, ctx)) == NULL) { 350 BIO_printf(bio_err, "Unable to get connection\n"); 351 goto end; 352 } 353 354 if (www_path != NULL) { 355 buf_len = BIO_snprintf(buf, sizeof(buf), fmt_http_get_cmd, www_path); 356 if (buf_len <= 0 || SSL_write(scon, buf, buf_len) <= 0) 357 goto end; 358 while (SSL_read(scon, buf, sizeof(buf)) > 0) 359 continue; 360 } 361 SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); 362 if ((fd = SSL_get_fd(scon)) >= 0) 363 BIO_closesocket(fd); 364 365 nConn = 0; 366 totalTime = 0.0; 367 368 finishtime = (long)time(NULL) + maxtime; 369 370 printf("starting\n"); 371 bytes_read = 0; 372 tm_Time_F(START); 373 374 for (;;) { 375 if (finishtime < (long)time(NULL)) 376 break; 377 378 if ((doConnection(scon, host, ctx)) == NULL) 379 goto end; 380 381 if (www_path != NULL) { 382 buf_len = BIO_snprintf(buf, sizeof(buf), fmt_http_get_cmd, 383 www_path); 384 if (buf_len <= 0 || SSL_write(scon, buf, buf_len) <= 0) 385 goto end; 386 while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) 387 bytes_read += i; 388 } 389 SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); 390 if ((fd = SSL_get_fd(scon)) >= 0) 391 BIO_closesocket(fd); 392 393 nConn += 1; 394 if (SSL_session_reused(scon)) { 395 ver = 'r'; 396 } else { 397 ver = SSL_version(scon); 398 if (ver == TLS1_VERSION) 399 ver = 't'; 400 else if (ver == SSL3_VERSION) 401 ver = '3'; 402 else 403 ver = '*'; 404 } 405 fputc(ver, stdout); 406 fflush(stdout); 407 } 408 totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ 409 410 printf("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", 411 nConn, totalTime, ((double)nConn / totalTime), bytes_read); 412 if (nConn > 0) 413 printf("%d connections in %ld real seconds, %ld bytes read per connection\n", 414 nConn, (long)time(NULL) - finishtime + maxtime, bytes_read / nConn); 415 else 416 printf("0 connections in %ld real seconds\n", 417 (long)time(NULL) - finishtime + maxtime); 418 ret = 0; 419 420 end: 421 SSL_free(scon); 422 SSL_CTX_free(ctx); 423 return ret; 424 } 425 426 /*- 427 * doConnection - make a connection 428 */ 429 static SSL *doConnection(SSL *scon, const char *host, SSL_CTX *ctx) 430 { 431 BIO *conn; 432 SSL *serverCon; 433 int i; 434 435 if ((conn = BIO_new(BIO_s_connect())) == NULL) 436 return NULL; 437 438 if (BIO_set_conn_hostname(conn, host) <= 0 439 || BIO_set_conn_mode(conn, BIO_SOCK_NODELAY) <= 0) { 440 BIO_free(conn); 441 return NULL; 442 } 443 444 if (scon == NULL) { 445 serverCon = SSL_new(ctx); 446 if (serverCon == NULL) { 447 BIO_free(conn); 448 return NULL; 449 } 450 } else { 451 serverCon = scon; 452 /* 453 * Reset the SSL object before reusing it for a new connection. 454 * This clears prior handshake and I/O state while keeping 455 * configuration inherited from the SSL_CTX. 456 */ 457 if (!SSL_clear(serverCon)) { 458 ERR_print_errors(bio_err); 459 BIO_free(conn); 460 return NULL; 461 } 462 SSL_set_connect_state(serverCon); 463 } 464 465 SSL_set_bio(serverCon, conn, conn); 466 467 /* ok, lets connect */ 468 i = SSL_connect(serverCon); 469 if (i <= 0) { 470 BIO_printf(bio_err, "ERROR\n"); 471 if (verify_args.error != X509_V_OK) 472 BIO_printf(bio_err, "verify error:%s\n", 473 X509_verify_cert_error_string(verify_args.error)); 474 else 475 ERR_print_errors(bio_err); 476 if (scon == NULL) 477 SSL_free(serverCon); 478 return NULL; 479 } 480 481 #if defined(SOL_SOCKET) && defined(SO_LINGER) 482 { 483 struct linger no_linger; 484 int fd; 485 486 no_linger.l_onoff = 1; 487 no_linger.l_linger = 0; 488 fd = SSL_get_fd(serverCon); 489 if (fd >= 0) 490 (void)setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&no_linger, 491 sizeof(no_linger)); 492 } 493 #endif 494 495 return serverCon; 496 } 497 #endif /* OPENSSL_NO_SOCK */ 498