From 1c6e0ab3bc93f3dd5e4be8ec7dab9a3f64319470 Mon Sep 17 00:00:00 2001 From: Landon Fuller Date: Fri, 23 Mar 2007 17:20:40 +0000 Subject: [PATCH] Add support for arbitrary client-to-server certificate CN matching (TLS Allowed CN). This allows the TLS client to either use certificate hostname matching, or an arbitrary administer-supplied CN, and is necessary to support roaming clients with non-static hostnames. Contributed by: Jorj Bauer git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@4397 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/console/authenticate.c | 2 +- bacula/src/dird/authenticate.c | 5 +++-- bacula/src/dird/dird_conf.c | 5 +++++ bacula/src/dird/dird_conf.h | 1 + bacula/src/filed/authenticate.c | 2 +- bacula/src/lib/bnet.c | 24 ++++++++++++++++++------ bacula/src/lib/protos.h | 3 ++- 7 files changed, 31 insertions(+), 11 deletions(-) diff --git a/bacula/src/console/authenticate.c b/bacula/src/console/authenticate.c index 04f7c0829a..2cb65cbd62 100644 --- a/bacula/src/console/authenticate.c +++ b/bacula/src/console/authenticate.c @@ -127,7 +127,7 @@ int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons) if (have_tls) { if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) { /* Engage TLS! Full Speed Ahead! */ - if (!bnet_tls_client(tls_ctx, dir)) { + if (!bnet_tls_client(tls_ctx, dir, NULL)) { sendit(_("TLS negotiation failed\n")); goto bail_out; } diff --git a/bacula/src/dird/authenticate.c b/bacula/src/dird/authenticate.c index a8fdbbbdda..23b5d5f4f5 100644 --- a/bacula/src/dird/authenticate.c +++ b/bacula/src/dird/authenticate.c @@ -131,7 +131,7 @@ bool authenticate_storage_daemon(JCR *jcr, STORE *store) /* Is TLS Enabled? */ if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) { /* Engage TLS! Full Speed Ahead! */ - if (!bnet_tls_client(store->tls_ctx, sd)) { + if (!bnet_tls_client(store->tls_ctx, sd, NULL)) { stop_bsock_timer(tid); Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed with SD on \"%s:%d\"\n"), sd->host(), sd->port()); @@ -235,7 +235,8 @@ int authenticate_file_daemon(JCR *jcr) /* Is TLS Enabled? */ if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) { /* Engage TLS! Full Speed Ahead! */ - if (!bnet_tls_client(client->tls_ctx, fd)) { + if (!bnet_tls_client(client->tls_ctx, fd, client->tls_allowed_cns)) { + stop_bsock_timer(tid); Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed with FD on \"%s:%d\".\n"), fd->host(), fd->port()); diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index e1b534415a..d625fd9af3 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -190,6 +190,7 @@ static RES_ITEM cli_items[] = { {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0}, {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0}, + {"tlsallowedcn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0}, {NULL, NULL, {0}, 0, 0, 0} }; @@ -1043,6 +1044,9 @@ void free_resource(RES *sres, int type) if (res->res_client.tls_keyfile) { free(res->res_client.tls_keyfile); } + if (res->res_client.tls_allowed_cns) { + delete res->res_client.tls_allowed_cns; + } break; case R_STORAGE: if (res->res_store.address) { @@ -1306,6 +1310,7 @@ void save_resource(int type, RES_ITEM *items, int pass) Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name); } res->res_client.catalog = res_all.res_client.catalog; + res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns; break; case R_SCHEDULE: /* diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index cd56a61e91..0bb0455158 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -254,6 +254,7 @@ public: char *tls_ca_certdir; /* TLS CA Certificate Directory */ char *tls_certfile; /* TLS Client Certificate File */ char *tls_keyfile; /* TLS Client Key File */ + alist *tls_allowed_cns; /* TLS Allowed Clients */ TLS_CONTEXT *tls_ctx; /* Shared TLS Context */ bool tls_enable; /* Enable TLS */ bool tls_require; /* Require TLS */ diff --git a/bacula/src/filed/authenticate.c b/bacula/src/filed/authenticate.c index 0a326e9435..e7994c49eb 100644 --- a/bacula/src/filed/authenticate.c +++ b/bacula/src/filed/authenticate.c @@ -263,7 +263,7 @@ int authenticate_storagedaemon(JCR *jcr) if (have_tls && tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) { /* Engage TLS! Full Speed Ahead! */ - if (!bnet_tls_client(me->tls_ctx, sd)) { + if (!bnet_tls_client(me->tls_ctx, sd, NULL)) { Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed.\n")); auth_success = false; goto auth_fatal; diff --git a/bacula/src/lib/bnet.c b/bacula/src/lib/bnet.c index 2fc92200f5..e874fcee4f 100644 --- a/bacula/src/lib/bnet.c +++ b/bacula/src/lib/bnet.c @@ -403,7 +403,7 @@ err: * Returns: true on success * false on failure */ -bool bnet_tls_client(TLS_CONTEXT *ctx, BSOCK * bsock) +bool bnet_tls_client(TLS_CONTEXT *ctx, BSOCK * bsock, alist *verify_list) { TLS_CONNECTION *tls; @@ -420,11 +420,23 @@ bool bnet_tls_client(TLS_CONTEXT *ctx, BSOCK * bsock) goto err; } - if (!tls_postconnect_verify_host(tls, bsock->host())) { - Qmsg1(bsock->jcr(), M_FATAL, 0, _("TLS host certificate verification failed. Host %s did not match presented certificate\n"), - bsock->host()); - goto err; + /* If there's an Allowed CN verify list, use that to validate the remote + * certificate's CN. Otherwise, we use standard host/CN matching. */ + if (verify_list) { + if (!tls_postconnect_verify_cn(tls, verify_list)) { + Qmsg1(bsock->jcr, M_FATAL, 0, _("TLS certificate verification failed." + " Peer certificate did not match a required commonName\n"), + bsock->host); + goto err; + } + } else { + if (!tls_postconnect_verify_host(tls, bsock->host())) { + Qmsg1(bsock->jcr(), M_FATAL, 0, _("TLS host certificate verification failed. Host %s did not match presented certificate\n"), + bsock->host()); + goto err; + } } + return true; err: @@ -438,7 +450,7 @@ bool bnet_tls_server(TLS_CONTEXT *ctx, BSOCK * bsock, alist *verify_list) Jmsg(bsock->jcr(), M_ABORT, 0, _("TLS enabled but not configured.\n")); return false; } -bool bnet_tls_client(TLS_CONTEXT *ctx, BSOCK * bsock) +bool bnet_tls_client(TLS_CONTEXT *ctx, BSOCK * bsock, alist *verify_list, int verify_hostname) { Jmsg(bsock->jcr(), M_ABORT, 0, _("TLS enable but not configured.\n")); return false; diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h index 7dab6cb52b..de121260b9 100644 --- a/bacula/src/lib/protos.h +++ b/bacula/src/lib/protos.h @@ -85,7 +85,8 @@ bool bnet_set_buffer_size (BSOCK *bs, uint32_t size, int rw); bool bnet_sig (BSOCK *bs, int sig); bool bnet_tls_server (TLS_CONTEXT *ctx, BSOCK *bsock, alist *verify_list); -bool bnet_tls_client (TLS_CONTEXT *ctx, BSOCK *bsock); +bool bnet_tls_client (TLS_CONTEXT *ctx, BSOCK *bsock, + alist *verify_list); BSOCK * bnet_connect (JCR *jcr, int retry_interval, utime_t max_retry_time, const char *name, char *host, char *service, int port, int verbose); -- 2.39.5