diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a711dac --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +/data/ +/nbproject/ +*.o +*.a +.deps/ +Makefile +Makefile.in +/src/httperf +/depcomp +/install-sh +/stamp-h1 +/config.status +/config.h +/config.guess +/config.sub +/configure +/aclocal.m4 +/compile +/ltmain.sh +/config.h.in +/config.log +/missing +/libtool +/autom4te.cache/ \ No newline at end of file diff --git a/src/httperf.c b/src/httperf.c index 18fded1..60d609e 100755 --- a/src/httperf.c +++ b/src/httperf.c @@ -143,6 +143,12 @@ static struct option longopts[] = { {"ssl", no_argument, ¶m.use_ssl, 1}, {"ssl-ciphers", required_argument, (int *) ¶m.ssl_cipher_list, 0}, {"ssl-no-reuse", no_argument, ¶m.ssl_reuse, 0}, + {"ssl-certificate", required_argument, (int *) ¶m.ssl_cert, 0}, + {"ssl-key", required_argument, (int *) ¶m.ssl_key, 0}, + {"ssl-verify", optional_argument, (int *) ¶m.ssl_verify, 0}, + {"ssl-ca-file", required_argument, (int *) ¶m.ssl_ca_file, 0}, + {"ssl-ca-path", required_argument, (int *) ¶m.ssl_ca_path, 0}, + {"ssl-protocol", required_argument, ¶m.ssl_protocol, 0}, #endif {"think-timeout", required_argument, (int *) ¶m.think_timeout, 0}, {"timeout", required_argument, (int *) ¶m.timeout, 0}, @@ -174,6 +180,9 @@ usage(void) "\t<--server file> [--port N] [--uri S] [--myaddr S]\n" #ifdef HAVE_SSL "\t[--ssl] [--ssl-ciphers L] [--ssl-no-reuse]\n" + "\t[--ssl-certificate file] [--ssl-key file]\n" + "\t[--ssl-ca-file file] [--ssl-ca-path path]\n" + "\t[--ssl-verify [yes|no]] [--ssl-protocol S]\n" #endif "\t[--think-timeout X] [--timeout X] [--verbose] [--version]\n" "\t[--wlog y|n,file] [--wsess N,N,X] [--wsesslog N,X,file]\n" @@ -274,6 +283,8 @@ main(int argc, char **argv) param.rate.dist = DETERMINISTIC; #ifdef HAVE_SSL param.ssl_reuse = 1; + param.ssl_verify = 0; + param.ssl_protocol = 0; #endif /* @@ -629,6 +640,43 @@ main(int argc, char **argv) #ifdef HAVE_SSL else if (flag == ¶m.ssl_cipher_list) param.ssl_cipher_list = optarg; + else if (flag == ¶m.ssl_cert) + param.ssl_cert = optarg; + else if (flag == ¶m.ssl_key) + param.ssl_key = optarg; + else if (flag == ¶m.ssl_verify) + { + if (!optarg) + param.ssl_verify = 1; + else + switch (tolower (optarg[0])) + { + case 'y': param.ssl_verify = 1; break; + case 'n': param.ssl_verify = 0; break; + default: param.ssl_verify = 0; break; + } + } + else if (flag == ¶m.ssl_ca_file) + param.ssl_ca_file = optarg; + else if (flag == ¶m.ssl_ca_path) + param.ssl_ca_path = optarg; + else if (flag == ¶m.ssl_protocol) + { + if (strcasecmp (optarg, "auto") == 0) + param.ssl_protocol = 0; + else if (strcasecmp (optarg, "SSLv2") == 0) + param.ssl_protocol = 2; + else if (strcasecmp (optarg, "SSLv3") == 0) + param.ssl_protocol = 3; + else if (strcasecmp (optarg, "TLSv1") == 0) + param.ssl_protocol = 4; + else + { + fprintf (stderr, "%s: illegal SSL protocol %s\n", + prog_name, optarg); + exit (1); + } + } #endif else if (flag == ¶m.uri) param.uri = optarg; @@ -940,14 +988,23 @@ main(int argc, char **argv) if (param.port < 0) param.port = 443; - SSL_load_error_strings(); - SSLeay_add_ssl_algorithms(); - - /* - * for some strange reason, SSLv23_client_method () doesn't - * work here - */ - ssl_ctx = SSL_CTX_new(SSLv3_client_method()); + SSL_library_init (); + SSL_load_error_strings (); + SSLeay_add_all_algorithms (); + SSLeay_add_ssl_algorithms (); + + switch (param.ssl_protocol) + { + /* 0/auto for SSLv23 */ + case 0: ssl_ctx = SSL_CTX_new (SSLv23_client_method ()); break; + /* 2/SSLv2 */ + case 2: ssl_ctx = SSL_CTX_new (SSLv2_client_method ()); break; + /* 3/SSLv3 */ + case 3: ssl_ctx = SSL_CTX_new (SSLv3_client_method ()); break; + /* 4/TLSv1 */ + case 4: ssl_ctx = SSL_CTX_new (TLSv1_client_method ()); break; + } + if (!ssl_ctx) { ERR_print_errors_fp(stderr); exit(-1); @@ -955,6 +1012,60 @@ main(int argc, char **argv) memset(buf, 0, sizeof(buf)); RAND_seed(buf, sizeof(buf)); + + /* set server certificate verification */ + if (param.ssl_verify == 1) + SSL_CTX_set_verify (ssl_ctx, SSL_VERIFY_PEER, NULL); + else + SSL_CTX_set_verify (ssl_ctx, SSL_VERIFY_NONE, NULL); + + /* set default certificate authority verification path */ + SSL_CTX_set_default_verify_paths (ssl_ctx); + + /* load extra certificate authority files and paths */ + if (param.ssl_ca_file || param.ssl_ca_path) + { + int ssl_err = SSL_CTX_load_verify_locations + (ssl_ctx, param.ssl_ca_file, param.ssl_ca_path); + if (DBG > 2) + fprintf (stderr, "SSL_CTX_load_verify_locations returned %d\n", + ssl_err); + } + + /* if using client SSL authentication, load the certificate file */ + if (param.ssl_cert) + { + int ssl_err = SSL_CTX_use_certificate_file + (ssl_ctx, param.ssl_cert, SSL_FILETYPE_PEM); + if (DBG > 2) + fprintf (stderr, "SSL_CTX_use_certificate_file returned %d\n", + ssl_err); + } + + /* also load the client key */ + if (param.ssl_key) + { + int ssl_err = SSL_CTX_use_PrivateKey_file + (ssl_ctx, param.ssl_key, SSL_FILETYPE_PEM); + if (DBG > 2) + fprintf (stderr, "SSL_CTX_use_PrivateKey_file returned %d\n", + ssl_err); + } + + /* check client certificate and key consistency */ + if (param.ssl_cert && param.ssl_key) + { + int ssl_err = SSL_CTX_check_private_key (ssl_ctx); + if (DBG > 2) + fprintf (stderr, "SSL_CTX_check_private_key returned %d\n", + ssl_err); + if (!ssl_err) + { + fprintf (stderr, + "SSL certificate and key failed consistency check\n"); + exit (1); + } + } } #endif if (param.port < 0) @@ -1085,6 +1196,18 @@ main(int argc, char **argv) printf(" --ssl-ciphers=%s", param.ssl_cipher_list); if (!param.ssl_reuse) printf(" --ssl-no-reuse"); + if (param.ssl_cert) printf (" --ssl-cert=%s", param.ssl_cert); + if (param.ssl_key) printf (" --ssl-key=%s", param.ssl_key); + if (param.ssl_ca_file) printf (" --ssl-ca-file=%s", param.ssl_ca_file); + if (param.ssl_ca_path) printf (" --ssl-ca-path=%s", param.ssl_ca_path); + if (param.ssl_verify) printf (" --ssl-verify"); + switch (param.ssl_protocol) + { + case 0: printf (" --ssl-protocol=auto"); break; + case 2: printf (" --ssl-protocol=SSLv2"); break; + case 3: printf (" --ssl-protocol=SSLv3"); break; + case 4: printf (" --ssl-protocol=TLSv1"); break; + } #endif if (param.additional_header) printf(" --add-header='%s'", param.additional_header); diff --git a/src/httperf.h b/src/httperf.h index 7e73a3d..37567d2 100755 --- a/src/httperf.h +++ b/src/httperf.h @@ -117,7 +117,13 @@ typedef struct Cmdline_Params #ifdef HAVE_SSL int use_ssl; /* connect via SSL */ int ssl_reuse; /* reuse SSL Session ID */ + int ssl_verify; /* whether to verify the server certificate */ + int ssl_protocol; /* which SSL protocol to use */ const char *ssl_cipher_list; /* client's list of SSL cipher suites */ + const char *ssl_cert; /* client certificate file name */ + const char *ssl_key; /* client key file name */ + const char *ssl_ca_file; /* certificate authority file */ + const char *ssl_ca_path; /* certificate authority path */ #endif int use_timer_cache; const char *additional_header; /* additional request header(s) */