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