From 2f92d0dab77a3f3b1005dae3401ea1316d6789b2 Mon Sep 17 00:00:00 2001 From: Lionel Cons Date: Fri, 17 May 2013 15:00:09 +0200 Subject: added support for client authentication via SSL diff --git a/plugins/check_http.c b/plugins/check_http.c index 9231a55..ddaca33 100644 --- a/plugins/check_http.c +++ b/plugins/check_http.c @@ -124,6 +124,8 @@ char *http_method; char *http_post_data; char *http_content_type; char buffer[MAX_INPUT_BUFFER]; +char *client_cert = NULL; +char *client_privkey = NULL; int process_arguments (int, char **); int check_http (void); @@ -170,7 +172,14 @@ main (int argc, char **argv) return result; } - +/* check whether a file exists */ +void +test_file (char *path) +{ + if (access(path, R_OK) == 0) + return; + usage2 (_("file does not exist or is not readable"), path); +} /* process command-line arguments */ int @@ -207,6 +216,8 @@ process_arguments (int argc, char **argv) {"linespan", no_argument, 0, 'l'}, {"onredirect", required_argument, 0, 'f'}, {"certificate", required_argument, 0, 'C'}, + {"client-cert", required_argument, 0, 'E'}, + {"private-key", required_argument, 0, 'K'}, {"useragent", required_argument, 0, 'A'}, {"header", required_argument, 0, 'k'}, {"no-body", no_argument, 0, 'N'}, @@ -236,7 +247,7 @@ process_arguments (int argc, char **argv) } while (1) { - c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:e:p:s:R:r:u:f:C:nlLS::m:M:N", longopts, &option); + c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:e:p:s:R:r:u:f:C:E:K:nlLS::m:M:N", longopts, &option); if (c == -1 || c == EOF) break; @@ -301,10 +312,23 @@ process_arguments (int argc, char **argv) days_till_exp_warn = atoi (optarg); } check_cert = TRUE; - /* Fall through to -S option */ + goto enable_ssl; +#endif + case 'E': /* use client certificate */ +#ifdef HAVE_SSL + test_file(optarg); + client_cert = optarg; + goto enable_ssl; +#endif + case 'K': /* use client private key */ +#ifdef HAVE_SSL + test_file(optarg); + client_privkey = optarg; + goto enable_ssl; #endif case 'S': /* use SSL */ #ifdef HAVE_SSL + enable_ssl: use_ssl = TRUE; if (optarg == NULL || c != 'S') ssl_version = 0; @@ -316,6 +340,7 @@ process_arguments (int argc, char **argv) if (specify_port == FALSE) server_port = HTTPS_PORT; #else + /* -C -E and -K fall through to here without SSL */ usage4 (_("Invalid option - SSL is not available")); #endif break; @@ -497,6 +522,9 @@ process_arguments (int argc, char **argv) if (http_method == NULL) http_method = strdup ("GET"); + if (client_cert && !client_privkey) + usage4 (_("If you use a client certificate you must also specify a private key file")); + return TRUE; } @@ -820,7 +848,7 @@ check_http (void) die (STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n")); #ifdef HAVE_SSL if (use_ssl == TRUE) { - result = np_net_ssl_init_with_hostname_and_version(sd, (use_sni ? host_name : NULL), ssl_version); + result = np_net_ssl_init_with_hostname_version_and_certificate(sd, (use_sni ? host_name : NULL), ssl_version, client_cert, client_privkey); if (result != STATE_OK) return result; if (check_cert == TRUE) { @@ -1354,7 +1382,13 @@ print_help (void) printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]"); printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443")); - printf (" %s\n", _("(when this option is used the URL is not checked.)\n")); + printf (" %s\n", _("(when this option is used the URL is not checked.)")); + printf (" %s\n", "-E, --client-cert=FILE"); + printf (" %s\n", _("Name of file that contains the client certificate (PEM format)")); + printf (" %s\n", _("to be used in establishing the SSL session")); + printf (" %s\n", "-K, --private-key=FILE"); + printf (" %s\n", _("Name of file containing the private key (PEM format)")); + printf (" %s\n", _("matching the client certificate")); #endif printf (" %s\n", "-e, --expect=STRING"); @@ -1461,6 +1495,7 @@ print_usage (void) { printf ("%s\n", _("Usage:")); printf (" %s -H | -I [-u ] [-p ]\n",progname); + printf (" [-E ] [-K ]\n"); printf (" [-w ] [-c ] [-t ] [-L] [-a auth]\n"); printf (" [-b proxy_auth] [-f ]\n"); printf (" [-e ] [-s string] [-l] [-r | -R ]\n"); diff --git a/plugins/netutils.h b/plugins/netutils.h index 21017f1..765b3d5 100644 --- a/plugins/netutils.h +++ b/plugins/netutils.h @@ -100,6 +100,8 @@ extern int address_family; /* maybe this could be merged with the above np_net_connect, via some flags */ int np_net_ssl_init(int sd); int np_net_ssl_init_with_hostname(int sd, char *host_name); +int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int version); +int np_net_ssl_init_with_hostname_version_and_certificate(int sd, char *host_name, int version, char *cert, char *privkey); void np_net_ssl_cleanup(); int np_net_ssl_write(const void *buf, int num); int np_net_ssl_read(void *buf, int num); diff --git a/plugins/sslutils.c b/plugins/sslutils.c index a1ce560..4927e36 100644 --- a/plugins/sslutils.c +++ b/plugins/sslutils.c @@ -45,6 +45,10 @@ int np_net_ssl_init_with_hostname(int sd, char *host_name) { } int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int version) { + return np_net_ssl_init_with_hostname_version_and_certificate(sd, host_name, version, NULL, NULL); +} + +int np_net_ssl_init_with_hostname_version_and_certificate(int sd, char *host_name, int version, char *cert, char *privkey) { const SSL_METHOD *method = NULL; switch (version) { @@ -80,6 +84,14 @@ int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int versi printf("%s\n", _("CRITICAL - Cannot create SSL context.")); return STATE_CRITICAL; } + if (cert && privkey) { + SSL_CTX_use_certificate_file(c, cert, SSL_FILETYPE_PEM); + SSL_CTX_use_PrivateKey_file(c, privkey, SSL_FILETYPE_PEM); + if (!SSL_CTX_check_private_key(c)) { + printf ("%s\n", _("CRITICAL - Private key does not seem to match certificate!\n")); + return STATE_CRITICAL; + } + } #ifdef SSL_OP_NO_TICKET SSL_CTX_set_options(c, SSL_OP_NO_TICKET); #endif -- cgit v0.10-9-g596f