]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: ssl: add client certificate authentication support
authorEmeric Brun <ebrun@exceliance.fr>
Thu, 20 Sep 2012 16:23:56 +0000 (18:23 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 2 Oct 2012 06:04:49 +0000 (08:04 +0200)
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.

include/types/listener.h
src/cfgparse.c
src/haproxy.c
src/ssl_sock.c

index a6b81f45433254a1c0e35af29b49cd3cacfced4b..d07e1da48f71191473e53ecdcc4132aab056d77b 100644 (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 */
index 2afd5e746409c8a8eacb61d94d8198fee3c26e7d..7f03d64141590bbff5f2a8fda05a0da5b305d1c5 100644 (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 */
                }
 
index 8b06743076f99e8c9a3b6383df9e525b7a6cd38e..b9179f001e631eb810c4ba94da552929f55bcc03 100644 (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);
index abaef02c451051238dd9cc5c8f560ad636b171c4..40de1ae7c0626db805d89f95a5216cf503cb106d 100644 (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 },
 }};