1 /* 2 * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the OpenSSL license (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 OPENSSL_UNISTD 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_ERR = -1, OPT_EOF = 0, OPT_HELP, 47 OPT_CONNECT, OPT_CIPHER, OPT_CIPHERSUITES, OPT_CERT, OPT_NAMEOPT, OPT_KEY, 48 OPT_CAPATH, OPT_CAFILE, OPT_NOCAPATH, OPT_NOCAFILE, OPT_NEW, OPT_REUSE, 49 OPT_BUGS, OPT_VERIFY, OPT_TIME, OPT_SSL3, 50 OPT_WWW 51 } OPTION_CHOICE; 52 53 const OPTIONS s_time_options[] = { 54 {"help", OPT_HELP, '-', "Display this summary"}, 55 {"connect", OPT_CONNECT, 's', 56 "Where to connect as post:port (default is " SSL_CONNECT_NAME ")"}, 57 {"cipher", OPT_CIPHER, 's', "TLSv1.2 and below cipher list to be used"}, 58 {"ciphersuites", OPT_CIPHERSUITES, 's', 59 "Specify TLSv1.3 ciphersuites to be used"}, 60 {"cert", OPT_CERT, '<', "Cert file to use, PEM format assumed"}, 61 {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"}, 62 {"key", OPT_KEY, '<', "File with key, PEM; default is -cert file"}, 63 {"CApath", OPT_CAPATH, '/', "PEM format directory of CA's"}, 64 {"cafile", OPT_CAFILE, '<', "PEM format file of CA's"}, 65 {"no-CAfile", OPT_NOCAFILE, '-', 66 "Do not load the default certificates file"}, 67 {"no-CApath", OPT_NOCAPATH, '-', 68 "Do not load certificates from the default certificates directory"}, 69 {"new", OPT_NEW, '-', "Just time new connections"}, 70 {"reuse", OPT_REUSE, '-', "Just time connection reuse"}, 71 {"bugs", OPT_BUGS, '-', "Turn on SSL bug compatibility"}, 72 {"verify", OPT_VERIFY, 'p', 73 "Turn on peer certificate verification, set depth"}, 74 {"time", OPT_TIME, 'p', "Seconds to collect data, default " SECONDSSTR}, 75 {"www", OPT_WWW, 's', "Fetch specified page from the site"}, 76 #ifndef OPENSSL_NO_SSL3 77 {"ssl3", OPT_SSL3, '-', "Just use SSLv3"}, 78 #endif 79 {NULL} 80 }; 81 82 #define START 0 83 #define STOP 1 84 85 static double tm_Time_F(int s) 86 { 87 return app_tminterval(s, 1); 88 } 89 90 int s_time_main(int argc, char **argv) 91 { 92 char buf[1024 * 8]; 93 SSL *scon = NULL; 94 SSL_CTX *ctx = NULL; 95 const SSL_METHOD *meth = NULL; 96 char *CApath = NULL, *CAfile = NULL, *cipher = NULL, *ciphersuites = NULL; 97 char *www_path = NULL; 98 char *host = SSL_CONNECT_NAME, *certfile = NULL, *keyfile = NULL, *prog; 99 double totalTime = 0.0; 100 int noCApath = 0, noCAfile = 0; 101 int maxtime = SECONDS, nConn = 0, perform = 3, ret = 1, i, st_bugs = 0; 102 long bytes_read = 0, finishtime = 0; 103 OPTION_CHOICE o; 104 int max_version = 0, ver, buf_len; 105 size_t buf_size; 106 107 meth = TLS_client_method(); 108 109 prog = opt_init(argc, argv, s_time_options); 110 while ((o = opt_next()) != OPT_EOF) { 111 switch (o) { 112 case OPT_EOF: 113 case OPT_ERR: 114 opthelp: 115 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); 116 goto end; 117 case OPT_HELP: 118 opt_help(s_time_options); 119 ret = 0; 120 goto end; 121 case OPT_CONNECT: 122 host = opt_arg(); 123 break; 124 case OPT_REUSE: 125 perform = 2; 126 break; 127 case OPT_NEW: 128 perform = 1; 129 break; 130 case OPT_VERIFY: 131 if (!opt_int(opt_arg(), &verify_args.depth)) 132 goto opthelp; 133 BIO_printf(bio_err, "%s: verify depth is %d\n", 134 prog, verify_args.depth); 135 break; 136 case OPT_CERT: 137 certfile = opt_arg(); 138 break; 139 case OPT_NAMEOPT: 140 if (!set_nameopt(opt_arg())) 141 goto end; 142 break; 143 case OPT_KEY: 144 keyfile = opt_arg(); 145 break; 146 case OPT_CAPATH: 147 CApath = opt_arg(); 148 break; 149 case OPT_CAFILE: 150 CAfile = opt_arg(); 151 break; 152 case OPT_NOCAPATH: 153 noCApath = 1; 154 break; 155 case OPT_NOCAFILE: 156 noCAfile = 1; 157 break; 158 case OPT_CIPHER: 159 cipher = opt_arg(); 160 break; 161 case OPT_CIPHERSUITES: 162 ciphersuites = opt_arg(); 163 break; 164 case OPT_BUGS: 165 st_bugs = 1; 166 break; 167 case OPT_TIME: 168 if (!opt_int(opt_arg(), &maxtime)) 169 goto opthelp; 170 break; 171 case OPT_WWW: 172 www_path = opt_arg(); 173 buf_size = strlen(www_path) + fmt_http_get_cmd_size; 174 if (buf_size > sizeof(buf)) { 175 BIO_printf(bio_err, "%s: -www option is too long\n", prog); 176 goto end; 177 } 178 break; 179 case OPT_SSL3: 180 max_version = SSL3_VERSION; 181 break; 182 } 183 } 184 argc = opt_num_rest(); 185 if (argc != 0) 186 goto opthelp; 187 188 if (cipher == NULL) 189 cipher = getenv("SSL_CIPHER"); 190 191 if ((ctx = SSL_CTX_new(meth)) == NULL) 192 goto end; 193 194 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); 195 SSL_CTX_set_quiet_shutdown(ctx, 1); 196 if (SSL_CTX_set_max_proto_version(ctx, max_version) == 0) 197 goto end; 198 199 if (st_bugs) 200 SSL_CTX_set_options(ctx, SSL_OP_ALL); 201 if (cipher != NULL && !SSL_CTX_set_cipher_list(ctx, cipher)) 202 goto end; 203 if (ciphersuites != NULL && !SSL_CTX_set_ciphersuites(ctx, ciphersuites)) 204 goto end; 205 if (!set_cert_stuff(ctx, certfile, keyfile)) 206 goto end; 207 208 if (!ctx_set_verify_locations(ctx, CAfile, CApath, noCAfile, noCApath)) { 209 ERR_print_errors(bio_err); 210 goto end; 211 } 212 if (!(perform & 1)) 213 goto next; 214 printf("Collecting connection statistics for %d seconds\n", maxtime); 215 216 /* Loop and time how long it takes to make connections */ 217 218 bytes_read = 0; 219 finishtime = (long)time(NULL) + maxtime; 220 tm_Time_F(START); 221 for (;;) { 222 if (finishtime < (long)time(NULL)) 223 break; 224 225 if ((scon = doConnection(NULL, host, ctx)) == NULL) 226 goto end; 227 228 if (www_path != NULL) { 229 buf_len = BIO_snprintf(buf, sizeof(buf), fmt_http_get_cmd, 230 www_path); 231 if (buf_len <= 0 || SSL_write(scon, buf, buf_len) <= 0) 232 goto end; 233 while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) 234 bytes_read += i; 235 } 236 SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); 237 BIO_closesocket(SSL_get_fd(scon)); 238 239 nConn += 1; 240 if (SSL_session_reused(scon)) { 241 ver = 'r'; 242 } else { 243 ver = SSL_version(scon); 244 if (ver == TLS1_VERSION) 245 ver = 't'; 246 else if (ver == SSL3_VERSION) 247 ver = '3'; 248 else 249 ver = '*'; 250 } 251 fputc(ver, stdout); 252 fflush(stdout); 253 254 SSL_free(scon); 255 scon = NULL; 256 } 257 totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ 258 259 i = (int)((long)time(NULL) - finishtime + maxtime); 260 printf 261 ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", 262 nConn, totalTime, ((double)nConn / totalTime), bytes_read); 263 printf 264 ("%d connections in %ld real seconds, %ld bytes read per connection\n", 265 nConn, (long)time(NULL) - finishtime + maxtime, bytes_read / nConn); 266 267 /* 268 * Now loop and time connections using the same session id over and over 269 */ 270 271 next: 272 if (!(perform & 2)) 273 goto end; 274 printf("\n\nNow timing with session id reuse.\n"); 275 276 /* Get an SSL object so we can reuse the session id */ 277 if ((scon = doConnection(NULL, host, ctx)) == NULL) { 278 BIO_printf(bio_err, "Unable to get connection\n"); 279 goto end; 280 } 281 282 if (www_path != NULL) { 283 buf_len = BIO_snprintf(buf, sizeof(buf), fmt_http_get_cmd, www_path); 284 if (buf_len <= 0 || SSL_write(scon, buf, buf_len) <= 0) 285 goto end; 286 while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) 287 continue; 288 } 289 SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); 290 BIO_closesocket(SSL_get_fd(scon)); 291 292 nConn = 0; 293 totalTime = 0.0; 294 295 finishtime = (long)time(NULL) + maxtime; 296 297 printf("starting\n"); 298 bytes_read = 0; 299 tm_Time_F(START); 300 301 for (;;) { 302 if (finishtime < (long)time(NULL)) 303 break; 304 305 if ((doConnection(scon, host, ctx)) == NULL) 306 goto end; 307 308 if (www_path != NULL) { 309 buf_len = BIO_snprintf(buf, sizeof(buf), fmt_http_get_cmd, 310 www_path); 311 if (buf_len <= 0 || SSL_write(scon, buf, buf_len) <= 0) 312 goto end; 313 while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) 314 bytes_read += i; 315 } 316 SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); 317 BIO_closesocket(SSL_get_fd(scon)); 318 319 nConn += 1; 320 if (SSL_session_reused(scon)) { 321 ver = 'r'; 322 } else { 323 ver = SSL_version(scon); 324 if (ver == TLS1_VERSION) 325 ver = 't'; 326 else if (ver == SSL3_VERSION) 327 ver = '3'; 328 else 329 ver = '*'; 330 } 331 fputc(ver, stdout); 332 fflush(stdout); 333 } 334 totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ 335 336 printf 337 ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", 338 nConn, totalTime, ((double)nConn / totalTime), bytes_read); 339 printf 340 ("%d connections in %ld real seconds, %ld bytes read per connection\n", 341 nConn, (long)time(NULL) - finishtime + maxtime, bytes_read / nConn); 342 343 ret = 0; 344 345 end: 346 SSL_free(scon); 347 SSL_CTX_free(ctx); 348 return ret; 349 } 350 351 /*- 352 * doConnection - make a connection 353 */ 354 static SSL *doConnection(SSL *scon, const char *host, SSL_CTX *ctx) 355 { 356 BIO *conn; 357 SSL *serverCon; 358 int i; 359 360 if ((conn = BIO_new(BIO_s_connect())) == NULL) 361 return NULL; 362 363 BIO_set_conn_hostname(conn, host); 364 BIO_set_conn_mode(conn, BIO_SOCK_NODELAY); 365 366 if (scon == NULL) 367 serverCon = SSL_new(ctx); 368 else { 369 serverCon = scon; 370 SSL_set_connect_state(serverCon); 371 } 372 373 SSL_set_bio(serverCon, conn, conn); 374 375 /* ok, lets connect */ 376 i = SSL_connect(serverCon); 377 if (i <= 0) { 378 BIO_printf(bio_err, "ERROR\n"); 379 if (verify_args.error != X509_V_OK) 380 BIO_printf(bio_err, "verify error:%s\n", 381 X509_verify_cert_error_string(verify_args.error)); 382 else 383 ERR_print_errors(bio_err); 384 if (scon == NULL) 385 SSL_free(serverCon); 386 return NULL; 387 } 388 389 #if defined(SOL_SOCKET) && defined(SO_LINGER) 390 { 391 struct linger no_linger; 392 int fd; 393 394 no_linger.l_onoff = 1; 395 no_linger.l_linger = 0; 396 fd = SSL_get_fd(serverCon); 397 if (fd >= 0) 398 (void)setsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&no_linger, 399 sizeof(no_linger)); 400 } 401 #endif 402 403 return serverCon; 404 } 405 #endif /* OPENSSL_NO_SOCK */ 406