]> granicus.if.org Git - apache/blobdiff - support/ab.c
ab: Add client certificate support.
[apache] / support / ab.c
index 89310a0df8cf47ab1113b393d8016ff09d898ad0..410d58e56e587366781d376819efa6aec6cafe95 100644 (file)
 #define SK_VALUE(x,y) sk_X509_value(x,y)
 typedef STACK_OF(X509) X509_STACK_TYPE;
 
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(LIBRESSL_VERSION_NUMBER)
 /* The following logic ensures we correctly glue FILE* within one CRT used
  * by the OpenSSL library build to another CRT used by the ab.exe build.
  * This became especially problematic with Visual Studio 2015.
@@ -353,7 +353,10 @@ int is_ssl;
 SSL_CTX *ssl_ctx;
 char *ssl_cipher = NULL;
 char *ssl_info = NULL;
+char *ssl_cert = NULL;
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
 char *ssl_tmp_key = NULL;
+#endif
 BIO *bio_out,*bio_err;
 #ifdef HAVE_TLSEXT
 int tls_use_sni = 1;         /* used by default, -I disables it */
@@ -733,6 +736,7 @@ static void ssl_proceed_handshake(struct connection *c)
                              SSL_CIPHER_get_name(ci),
                              pk_bits, sk_bits);
             }
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
             if (ssl_tmp_key == NULL) {
                 EVP_PKEY *key;
                 if (SSL_get_server_tmp_key(c->ssl, &key)) {
@@ -752,9 +756,7 @@ static void ssl_proceed_handshake(struct connection *c)
                         EC_KEY *ec = EVP_PKEY_get1_EC_KEY(key);
                         int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
                         EC_KEY_free(ec);
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L
                         cname = EC_curve_nid2nist(nid);
-#endif
                         if (!cname)
                             cname = OBJ_nid2sn(nid);
 
@@ -764,10 +766,16 @@ static void ssl_proceed_handshake(struct connection *c)
                         break;
                         }
 #endif
+                    default:
+                        apr_snprintf(ssl_tmp_key, 128, "%s %d bits",
+                                     OBJ_nid2sn(EVP_PKEY_id(key)),
+                                     EVP_PKEY_bits(key));
+                        break;
                     }
                     EVP_PKEY_free(key);
                 }
             }
+#endif
             write_request(c);
             do_next = 0;
             break;
@@ -845,23 +853,21 @@ static void write_request(struct connection * c)
                 return;
             }
             l = e;
-            e = APR_SUCCESS;
         }
         else
 #endif
         {
             e = apr_socket_send(c->aprsock, request + c->rwrote, &l);
-            if (e != APR_SUCCESS) {
+            if (e != APR_SUCCESS && !l) {
                 if (!APR_STATUS_IS_EAGAIN(e)) {
                     epipe++;
                     printf("Send request failed!\n");
                     close_connection(c);
-                    return;
                 }
-                if (!l) {
+                else {
                     set_polled_events(c, APR_POLLOUT);
-                    return;
                 }
+                return;
             }
         }
         totalposted += l;
@@ -933,9 +939,11 @@ static void output_results(int sig)
     if (is_ssl && ssl_info) {
         printf("SSL/TLS Protocol:       %s\n", ssl_info);
     }
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
     if (is_ssl && ssl_tmp_key) {
         printf("Server Temp Key:        %s\n", ssl_tmp_key);
     }
+#endif
 #ifdef HAVE_TLSEXT
     if (is_ssl && tls_sni) {
         printf("TLS Server Name:        %s\n", tls_sni);
@@ -2163,6 +2171,7 @@ static void usage(const char *progname)
     fprintf(stderr, "    -Z ciphersuite  Specify SSL/TLS cipher suite (See openssl ciphers)\n");
     fprintf(stderr, "    -f protocol     Specify SSL/TLS protocol\n");
     fprintf(stderr, "                    (" SSL2_HELP_MSG SSL3_HELP_MSG "TLS1" TLS1_X_HELP_MSG " or ALL)\n");
+    fprintf(stderr, "    -E certfile     Specify optional client certificate chain and private key\n");
 #endif
     exit(EINVAL);
 }
@@ -2333,7 +2342,7 @@ int main(int argc, const char * const argv[])
     apr_getopt_init(&opt, cntxt, argc, argv);
     while ((status = apr_getopt(opt, "n:c:t:s:b:T:p:u:v:lrkVhwiIx:y:z:C:H:P:A:g:X:de:SqB:m:"
 #ifdef USE_SSL
-            "Z:f:"
+            "Z:f:E:"
 #endif
             ,&c, &opt_arg)) == APR_SUCCESS) {
         switch (c) {
@@ -2517,6 +2526,9 @@ int main(int argc, const char * const argv[])
             case 'Z':
                 ssl_cipher = strdup(opt_arg);
                 break;
+            case 'E':
+                ssl_cert = strdup(opt_arg);
+                break;
             case 'f':
 #if OPENSSL_VERSION_NUMBER < 0x10100000L
                 if (strncasecmp(opt_arg, "ALL", 3) == 0) {
@@ -2651,6 +2663,26 @@ int main(int argc, const char * const argv[])
     if (verbosity >= 3) {
         SSL_CTX_set_info_callback(ssl_ctx, ssl_state_cb);
     }
+    if (ssl_cert != NULL) {
+        if (SSL_CTX_use_certificate_chain_file(ssl_ctx, ssl_cert) <= 0) {
+            BIO_printf(bio_err, "unable to get certificate from '%s'\n",
+                       ssl_cert);
+            ERR_print_errors(bio_err);
+            exit(1);
+        }
+        if (SSL_CTX_use_PrivateKey_file(ssl_ctx, ssl_cert, SSL_FILETYPE_PEM) <= 0) {
+            BIO_printf(bio_err, "unable to get private key from '%s'\n",
+                ssl_cert);
+            ERR_print_errors(bio_err);
+            exit(1);
+        }
+        if (!SSL_CTX_check_private_key(ssl_ctx)) {
+            BIO_printf(bio_err,
+                       "private key does not match the certificate public key in %s\n", ssl_cert);
+            exit(1);
+        }
+    }
+
 #endif
 #ifdef SIGPIPE
     apr_signal(SIGPIPE, SIG_IGN);       /* Ignore writes to connections that