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>' path to a client CA file used to verify.
'crlfile <path>' path to a client CRL file used to verify.
This commit is contained in:
Emeric Brun 2012-09-20 18:23:56 +02:00 committed by Willy Tarreau
parent 7fb34422fe
commit d94b3fe98f
4 changed files with 84 additions and 1 deletions

View File

@ -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 */

View File

@ -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 */
}

View File

@ -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);

View File

@ -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 <const> 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 },
}};