From: Emeric Brun Date: Thu, 20 Sep 2012 16:23:56 +0000 (+0200) Subject: MEDIUM: ssl: add client certificate authentication support X-Git-Tag: v1.5-dev13~250 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d94b3fe98f92a5f95a078a8f53e24bd0a02eff02;p=thirdparty%2Fhaproxy.git MEDIUM: ssl: add client certificate authentication support Add keyword 'verify' on bind: 'verify none': authentication disabled (default) 'verify optional': accept connection without certificate and process a verify if the client sent a certificate 'verify required': reject connection without certificate and process a verify if the client send a certificate Add keyword 'cafile' on bind: 'cafile ' path to a client CA file used to verify. 'crlfile ' path to a client CRL file used to verify. --- diff --git a/include/types/listener.h b/include/types/listener.h index a6b81f4543..d07e1da48f 100644 --- a/include/types/listener.h +++ b/include/types/listener.h @@ -96,11 +96,14 @@ enum { /* "bind" line settings */ struct bind_conf { #ifdef USE_OPENSSL + char *cafile; /* CAfile to use on verify */ char *ciphers; /* cipher suite to use if non-null */ + char *crlfile; /* CRLfile to use on verify */ char *ecdhe; /* named curve to use for ECDHE */ int nosslv3; /* disable SSLv3 */ int notlsv1; /* disable TLSv1 */ int prefer_server_ciphers; /* Prefer server ciphers */ + int verify; /* verify method (set of SSL_VERIFY_* flags) */ SSL_CTX *default_ctx; /* SSL context of first/default certificate */ struct eb_root sni_ctx; /* sni_ctx tree of all known certs full-names sorted by name */ struct eb_root sni_w_ctx; /* sni_ctx tree of all known certs wildcards sorted by name */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 2afd5e7464..7f03d64141 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -6599,8 +6599,10 @@ out_uri_auth_compat: continue; #ifdef USE_OPENSSL ssl_sock_free_all_ctx(bind_conf); + free(bind_conf->cafile); free(bind_conf->ciphers); free(bind_conf->ecdhe); + free(bind_conf->crlfile); #endif /* USE_OPENSSL */ } diff --git a/src/haproxy.c b/src/haproxy.c index 8b06743076..b9179f001e 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -1037,8 +1037,10 @@ void deinit(void) list_for_each_entry_safe(bind_conf, bind_back, &p->conf.bind, by_fe) { #ifdef USE_OPENSSL ssl_sock_free_all_ctx(bind_conf); + free(bind_conf->cafile); free(bind_conf->ciphers); free(bind_conf->ecdhe); + free(bind_conf->crlfile); #endif /* USE_OPENSSL */ free(bind_conf->file); free(bind_conf->arg); diff --git a/src/ssl_sock.c b/src/ssl_sock.c index abaef02c45..40de1ae7c0 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -428,7 +428,29 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx, struct proxy SSL_CTX_set_options(ctx, ssloptions); SSL_CTX_set_mode(ctx, sslmode); - SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + SSL_CTX_set_verify(ctx, bind_conf->verify ? bind_conf->verify : SSL_VERIFY_NONE, NULL); + if (bind_conf->verify & SSL_VERIFY_PEER) { + if (bind_conf->cafile) { + /* load CAfile to verify */ + if (!SSL_CTX_load_verify_locations(ctx, bind_conf->cafile, NULL)) { + Alert("Proxy '%s': unable to load CA file '%s' for bind '%s' at [%s:%d].\n", + curproxy->id, bind_conf->cafile, bind_conf->arg, bind_conf->file, bind_conf->line); + cfgerr++; + } + /* set CA names fo client cert request, function returns void */ + SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(bind_conf->cafile)); + } + + if (bind_conf->crlfile) { + X509_STORE *store = SSL_CTX_get_cert_store(ctx); + + if (!store || !X509_STORE_load_locations(store, bind_conf->crlfile, NULL)) { + Alert("Proxy '%s': unable to configure CRL file '%s' for bind '%s' at [%s:%d].\n", + curproxy->id, bind_conf->cafile, bind_conf->arg, bind_conf->file, bind_conf->line); + cfgerr++; + } + } + } shared_context_set_cache(ctx); if (bind_conf->ciphers && @@ -887,6 +909,19 @@ smp_fetch_ssl_sni(struct proxy *px, struct session *l4, void *l7, unsigned int o #endif } +/* parse the "cafile" bind keyword */ +static int bind_parse_cafile(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) +{ + if (!*args[cur_arg + 1]) { + if (err) + memprintf(err, "'%s' : missing CAfile path", args[cur_arg]); + return ERR_ALERT | ERR_FATAL; + } + + conf->cafile = strdup(args[cur_arg + 1]); + return 0; +} + /* parse the "ciphers" bind keyword */ static int bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { @@ -913,6 +948,19 @@ static int bind_parse_crt(char **args, int cur_arg, struct proxy *px, struct bin return 0; } +/* parse the "crlfile" bind keyword */ +static int bind_parse_crlfile(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) +{ + if (!*args[cur_arg + 1]) { + if (err) + memprintf(err, "'%s' : missing CRLfile path", args[cur_arg]); + return ERR_ALERT | ERR_FATAL; + } + + conf->crlfile = strdup(args[cur_arg + 1]); + return 0; +} + /* parse the "ecdhe" bind keyword keywords */ static int bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { @@ -970,6 +1018,31 @@ static int bind_parse_ssl(char **args, int cur_arg, struct proxy *px, struct bin return 0; } +/* parse the "verify" bind keyword */ +static int bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) +{ + if (!*args[cur_arg + 1]) { + if (err) + memprintf(err, "'%s' : missing verify method", args[cur_arg]); + return ERR_ALERT | ERR_FATAL; + } + + if (strcmp(args[cur_arg + 1], "none") == 0) + conf->verify = SSL_VERIFY_NONE; + else if (strcmp(args[cur_arg + 1], "optional") == 0) + conf->verify = SSL_VERIFY_PEER; + else if (strcmp(args[cur_arg + 1], "required") == 0) + conf->verify = SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + else { + if (err) + memprintf(err, "'%s' : unknown verify method '%s', only 'none', 'optional', and 'required' are supported\n", + args[cur_arg], args[cur_arg + 1]); + return ERR_ALERT | ERR_FATAL; + } + + return 0; +} + /* Note: must not be declared as its list will be overwritten. * Please take care of keeping this list alphabetically sorted. */ @@ -1000,13 +1073,16 @@ static struct acl_kw_list acl_kws = {{ },{ * not enabled. */ static struct bind_kw_list bind_kws = { "SSL", { }, { + { "cafile", bind_parse_cafile, 1 }, /* set CAfile to process verify on client cert */ { "ciphers", bind_parse_ciphers, 1 }, /* set SSL cipher suite */ + { "crlfile", bind_parse_crlfile, 1 }, /* set certificat revocation list file use on client cert verify */ { "crt", bind_parse_crt, 1 }, /* load SSL certificates from this location */ { "ecdhe", bind_parse_ecdhe, 1 }, /* defines named curve for elliptic curve Diffie-Hellman */ { "nosslv3", bind_parse_nosslv3, 0 }, /* disable SSLv3 */ { "notlsv1", bind_parse_notlsv1, 0 }, /* disable TLSv1 */ { "prefer-server-ciphers", bind_parse_psc, 0 }, /* prefer server ciphers */ { "ssl", bind_parse_ssl, 0 }, /* enable SSL processing */ + { "verify", bind_parse_verify, 1 }, /* set SSL verify method */ { NULL, NULL, 0 }, }};