Fixed ssl client certs for evhtp.

* Added SSL cert info as options: CLICON_SSL_SERVER_CERT, CLICON_SSL_SERVER_KEY, CLICON_SSL_CA_CERT
Added config.sh for testing for autotools
This commit is contained in:
Olof hagsand 2020-07-01 15:11:22 +02:00
parent 9c82e97072
commit c049a397b0
22 changed files with 515 additions and 80 deletions

View file

@ -35,9 +35,6 @@
* libevhtp code
*/
/* XXX temp constant should go away, */
#undef _EVHTP_NYI
#ifdef HAVE_CONFIG_H
#include "clixon_config.h" /* generated by config & autoconf */
#endif
@ -82,7 +79,7 @@
#include "restconf_root.h"
/* Command line options to be passed to getopt(3) */
#define RESTCONF_OPTS "hD:f:l:p:d:y:a:u:o:P:s"
#define RESTCONF_OPTS "hD:f:l:p:d:y:a:u:o:P:sc"
/* Need global variable to for signal handler XXX */
static clicon_handle _CLICON_HANDLE = NULL;
@ -100,9 +97,7 @@ restconf_sig_term(int arg)
else
exit(-1);
if (_CLICON_HANDLE){
#ifdef _EVHTP_NYI
stream_child_freeall(_CLICON_HANDLE);
#endif
// stream_child_freeall(_CLICON_HANDLE);
restconf_terminate(_CLICON_HANDLE);
}
clicon_exit_set(); /* checked in clixon_event_loop() */
@ -116,9 +111,6 @@ restconf_sig_child(int arg)
int pid;
if ((pid = waitpid(-1, &status, 0)) != -1 && WIFEXITED(status)){
#ifdef _EVHTP_NYI
;
#endif
}
}
@ -267,11 +259,16 @@ evhtp_params_set(clicon_handle h,
evhtp_request_t *req,
cvec *qvec)
{
int retval = -1;
htp_method meth;
evhtp_uri_t *uri;
evhtp_path_t *path;
int retval = -1;
htp_method meth;
evhtp_uri_t *uri;
evhtp_path_t *path;
evhtp_ssl_t *ssl = NULL;
char *subject;
cvec *cvv = NULL;
char *cn;
if ((uri = req->uri) == NULL){
clicon_err(OE_DAEMON, EFAULT, "No uri");
goto done;
@ -303,9 +300,18 @@ evhtp_params_set(clicon_handle h,
goto fail;
}
clicon_debug(1, "%s conn->ssl:%d", __FUNCTION__, req->conn->ssl?1:0);
if (req->conn->ssl != NULL){
if ((ssl = req->conn->ssl) != NULL){
if (restconf_param_set(h, "HTTPS", "https") < 0) /* some string or NULL */
goto done;
/* SSL subject fields, eg CN (Common Name) , can add more here? */
if ((subject = (char*)htp_sslutil_subject_tostr(req->conn->ssl)) != NULL){
if (str2cvec(subject, '/', '=', &cvv) < 0)
goto done;
if ((cn = cvec_find_str(cvv, "CN")) != NULL){
if (restconf_param_set(h, "SSL_CN", cn) < 0)
goto done;
}
}
}
/* Translate all http headers by capitalizing, prepend w HTTP_ and - -> _
@ -315,6 +321,8 @@ evhtp_params_set(clicon_handle h,
goto done;
retval = 1;
done:
if (cvv)
cvec_free(cvv);
return retval;
fail:
retval = 0;
@ -423,6 +431,8 @@ cx_path_restconf(evhtp_request_t *req,
/* input debug */
if (clicon_debug_get())
evhtp_headers_for_each(req->headers_in, print_header, h);
/* get accepted connection */
/* Query vector, ie the ?a=x&b=y stuff */
if ((qvec = cvec_new(0)) ==NULL){
@ -446,51 +456,93 @@ cx_path_restconf(evhtp_request_t *req,
}
/*! Get Server cert info
* @param[out] ssl_config
* @param[in] h Clicon handle
* @param[out] ssl_config evhtp ssl config struct
*/
static int
get_servercerts(evhtp_ssl_cfg_t *ssl_config,
const char *pki_dir,
const char *ssl_server_cert)
cx_get_certs(clicon_handle h,
int ssl_verify_clients,
evhtp_ssl_cfg_t *ssl_config)
{
int retval = -1;
cbuf *cb = NULL;
struct stat f_stat;
char *filename;
if (ssl_config == NULL){
clicon_err(OE_CFG, EINVAL, "ssl_config is NULL");
clicon_err(OE_CFG, EINVAL, "Input parameter is NULL");
goto done;
}
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
if ((filename = clicon_option_str(h, "CLICON_SSL_SERVER_CERT")) == NULL){
clicon_err(OE_CFG, EFAULT, "CLICON_SSL_SERVER_CERT option missing");
goto done;
}
cprintf(cb, "%s/%s-crt.pem", pki_dir, ssl_server_cert);
if ((ssl_config->pemfile = strdup(cbuf_get(cb))) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
if ((ssl_config->pemfile = strdup(filename)) == NULL){
clicon_err(OE_CFG, errno, "strdup");
goto done;
}
if (stat(ssl_config->pemfile, &f_stat) != 0) {
clicon_err(OE_FATAL, errno, "Cannot load SSL cert '%s'", ssl_config->pemfile);
goto done;
}
cbuf_reset(cb);
cprintf(cb, "%s/%s-key.pem", pki_dir, ssl_server_cert);
if ((ssl_config->privfile = strdup(cbuf_get(cb))) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
if ((filename = clicon_option_str(h, "CLICON_SSL_SERVER_KEY")) == NULL){
clicon_err(OE_CFG, EFAULT, "CLICON_SSL_SERVER_KEY option missing");
goto done;
}
if ((ssl_config->privfile = strdup(filename)) == NULL){
clicon_err(OE_CFG, errno, "strdup");
goto done;
}
if (stat(ssl_config->privfile, &f_stat) != 0) {
clicon_err(OE_FATAL, errno, "Cannot load SSL key '%s'", ssl_config->privfile);
goto done;
}
if (ssl_verify_clients){
if ((filename = clicon_option_str(h, "CLICON_SSL_CA_CERT")) == NULL){
clicon_err(OE_CFG, EFAULT, "CLICON_SSL_CA_CERT option missing");
goto done;
}
if ((ssl_config->cafile = strdup(filename)) == NULL){
clicon_err(OE_CFG, errno, "strdup");
goto done;
}
if (stat(ssl_config->cafile, &f_stat) != 0) {
clicon_err(OE_FATAL, errno, "Cannot load SSL key '%s'", ssl_config->privfile);
goto done;
}
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
return retval;
}
static int
cx_verify_certs(int pre_verify,
evhtp_x509_store_ctx_t *store)
{
#ifdef NOTYET
char buf[256];
X509 * err_cert;
int err;
int depth;
SSL * ssl;
evhtp_connection_t * connection;
evhtp_ssl_cfg_t * ssl_cfg;
fprintf(stderr, "%s %d\n", __FUNCTION__, pre_verify);
err_cert = X509_STORE_CTX_get_current_cert(store);
err = X509_STORE_CTX_get_error(store);
depth = X509_STORE_CTX_get_error_depth(store);
ssl = X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx());
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
connection = SSL_get_app_data(ssl);
ssl_cfg = connection->htp->ssl_cfg;
#endif
return pre_verify;
}
/*! Usage help routine
* @param[in] argv0 command line
* @param[in] h Clicon handle
@ -513,6 +565,7 @@ usage(clicon_handle h,
"\t-u <path|addr>\t Internal socket domain path or IP addr (see -a)\n"
"\t-o \"<option>=<value>\" Give configuration option overriding config file (see clixon-config.yang)\n"
"\t-s\t SSL server, https\n"
"\t-c\t SSL verify client certs\n"
"\t-P <port>\t HTTP port (default 80, or 443 if -s is given)\n"
,
argv0,
@ -521,6 +574,8 @@ usage(clicon_handle h,
exit(0);
}
/*! Main routine for libevhtp restconf
*/
int
@ -541,15 +596,12 @@ main(int argc,
size_t cligen_bufthreshold;
uint16_t defaultport = 80;
uint16_t port = 0;
#ifdef _EVHTP_NYI
char *stream_path;
#endif
evhtp_t *htp = NULL;
struct event_base *evbase = NULL;
evhtp_ssl_cfg_t *ssl_config = NULL;
int dbg = 0;
char *ssl_server = NULL; /* SSL server name, default "server", base for srv certs */
char *pki_dir = CLIXON_PKI_DIR;
int use_ssl = 0;
int ssl_verify_clients = 0;
/* In the startup, logs to stderr & debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
@ -607,9 +659,7 @@ main(int argc,
/* Find and read configfile */
if (clicon_options_main(h) < 0)
goto done;
#ifdef _EVHTP_NYI
stream_path = clicon_option_str(h, "CLICON_STREAM_PATH");
#endif
// stream_path = clicon_option_str(h, "CLICON_STREAM_PATH");
/* Now rest of options, some overwrite option file */
optind = 1;
@ -651,9 +701,12 @@ main(int argc,
break;
}
case 's': /* ssl: use https */
ssl_server = CLIXON_SERVER_CERT;
use_ssl = 1;
defaultport = 443; /* unless explicit -P ? */
break;
case 'c': /* ssl: verify clients */
ssl_verify_clients = 1;
break;
case 'P': /* http port */
if (!strlen(optarg))
usage(h, argv0);
@ -669,7 +722,7 @@ main(int argc,
if (port == 0)
port = defaultport;
/* Check server ssl certs */
if (ssl_server){
if (use_ssl){
/* Init evhtp ssl config struct */
if ((ssl_config = malloc(sizeof(evhtp_ssl_cfg_t))) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
@ -678,8 +731,14 @@ main(int argc,
memset(ssl_config, 0, sizeof(evhtp_ssl_cfg_t));
ssl_config->ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1;
if (get_servercerts(ssl_config, pki_dir, ssl_server) < 0)
if (cx_get_certs(h, ssl_verify_clients, ssl_config) < 0)
goto done;
ssl_config->x509_verify_cb = cx_verify_certs; /* Is extra verification necessary? */
if (ssl_verify_clients){
ssl_config->verify_peer = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
ssl_config->x509_verify_cb = cx_verify_certs;
ssl_config->verify_depth = 2;
}
}
// ssl_verify_mode = htp_sslutil_verify2opts(optarg);
@ -697,7 +756,7 @@ main(int argc,
clicon_err(OE_UNIX, errno, "evhtp_new");
goto done;
}
if (ssl_server){
if (use_ssl){
if (evhtp_ssl_init(htp, ssl_config) < 0){
clicon_err(OE_UNIX, errno, "evhtp_new");
goto done;
@ -835,9 +894,7 @@ main(int argc,
retval = 0;
done:
#ifdef _EVHTP_NYI
stream_child_freeall(h);
#endif
// stream_child_freeall(h);
restconf_terminate(h);
return retval;
}