diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | src/confdb/confdb.h | 1 | ||||
-rw-r--r-- | src/config/SSSDConfig/__init__.py.in | 1 | ||||
-rwxr-xr-x | src/config/SSSDConfigTest.py | 3 | ||||
-rw-r--r-- | src/config/etc/sssd.api.conf | 1 | ||||
-rw-r--r-- | src/man/sssd.conf.5.xml | 29 | ||||
-rw-r--r-- | src/p11_child/p11_child_nss.c | 25 | ||||
-rw-r--r-- | src/responder/pam/pamsrv.h | 1 | ||||
-rw-r--r-- | src/responder/pam/pamsrv_cmd.c | 14 | ||||
-rw-r--r-- | src/responder/pam/pamsrv_p11.c | 21 | ||||
-rw-r--r-- | src/responder/ssh/sshsrv_cmd.c | 25 | ||||
-rw-r--r-- | src/tests/cmocka/test_cert_utils.c | 2 | ||||
-rw-r--r-- | src/tests/cmocka/test_pam_srv.c | 41 | ||||
-rw-r--r-- | src/util/cert.h | 1 | ||||
-rw-r--r-- | src/util/cert/libcrypto/cert.c | 1 | ||||
-rw-r--r-- | src/util/cert/nss/cert.c | 15 | ||||
-rw-r--r-- | src/util/util.c | 46 | ||||
-rw-r--r-- | src/util/util.h | 3 |
18 files changed, 210 insertions, 22 deletions
diff --git a/Makefile.am b/Makefile.am index ba59b16b4..848f70e48 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3163,6 +3163,7 @@ proxy_child_LDADD = \ p11_child_SOURCES = \ src/p11_child/p11_child_nss.c \ src/util/atomic_io.c \ + src/util/util.c \ $(NULL) p11_child_CFLAGS = \ $(AM_CFLAGS) \ @@ -3172,6 +3173,7 @@ p11_child_CFLAGS = \ p11_child_LDADD = \ libsss_debug.la \ $(TALLOC_LIBS) \ + $(DHASH_LIBS) \ $(POPT_LIBS) \ $(NSS_LIBS) \ libsss_crypt.la \ diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h index 0ef7268f9..fcffcb5a6 100644 --- a/src/confdb/confdb.h +++ b/src/confdb/confdb.h @@ -72,6 +72,7 @@ #define CONFDB_MONITOR_OVERRIDE_SPACE "override_space" #define CONFDB_MONITOR_USER_RUNAS "user" #define CONFDB_MONITOR_PRE_KILL_CMD "diag_cmd" +#define CONFDB_MONITOR_CERT_VERIFICATION "certificate_verification" /* Both monitor and domains */ #define CONFDB_NAME_REGEX "re_expression" diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in index 60129e6e7..fe2971d99 100644 --- a/src/config/SSSDConfig/__init__.py.in +++ b/src/config/SSSDConfig/__init__.py.in @@ -61,6 +61,7 @@ option_strings = { 'krb5_rcache_dir' : _('Directory on the filesystem where SSSD should store Kerberos replay cache files.'), 'default_domain_suffix' : _('Domain to add to names without a domain component.'), 'user' : _('The user to drop privileges to'), + 'certificate_verification' : _('Tune certificate verification'), # [nss] 'enum_cache_timeout' : _('Enumeration cache timeout length (seconds)'), diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py index abd4a3925..681d8be96 100755 --- a/src/config/SSSDConfigTest.py +++ b/src/config/SSSDConfigTest.py @@ -308,7 +308,8 @@ class SSSDConfigTestSSSDService(unittest.TestCase): 'fd_limit', 'client_idle_timeout', 'diag_cmd', - 'description'] + 'description', + 'certificate_verification'] self.assertTrue(type(options) == dict, "Options should be a dictionary") diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf index 0c03625bd..89cf8634f 100644 --- a/src/config/etc/sssd.api.conf +++ b/src/config/etc/sssd.api.conf @@ -26,6 +26,7 @@ full_name_format = str, None, false krb5_rcache_dir = str, None, false user = str, None, false default_domain_suffix = str, None, false +certificate_verification = str, None, false [nss] # Name service diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml index 573f421a7..030485cd7 100644 --- a/src/man/sssd.conf.5.xml +++ b/src/man/sssd.conf.5.xml @@ -365,6 +365,35 @@ </para> </listitem> </varlistentry> + <varlistentry> + <term>certificate_verification (string)</term> + <listitem> + <para> + With this parameter the certificate verification + can be tuned with a comma separated list of + options. Supported options are: + <variablelist> + <varlistentry> + <term>no_ocsp</term> + <listitem> + <para>Disables Online Certificate Status + Protocol (OCSP) checks. This might be + needed if the OCSP servers defined in + the certificate are not reachable from + the client.</para> + </listitem> + </varlistentry> + </variablelist> + </para> + <para> + Unknown options are reported but ignored. + </para> + <para> + Default: not set, i.e. do not restrict + certificate vertification + </para> + </listitem> + </varlistentry> </variablelist> </para> </refsect2> diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c index 39c88d9f4..fe092bb05 100644 --- a/src/p11_child/p11_child_nss.c +++ b/src/p11_child/p11_child_nss.c @@ -38,10 +38,12 @@ #include <keyhi.h> #include <pk11pub.h> #include <prerror.h> +#include <ocsp.h> #include "util/child_common.h" #include "providers/dp_backend.h" #include "util/crypto/sss_crypto.h" +#include "util/cert.h" enum op_mode { OP_NONE, @@ -68,7 +70,7 @@ static char *password_passthrough(PK11SlotInfo *slot, PRBool retry, void *arg) int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, - enum op_mode mode, const char *pin, char **cert, + enum op_mode mode, const char *pin, bool do_ocsp, char **cert, char **token_name_out) { int ret; @@ -261,6 +263,14 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, return EIO; } + if (do_ocsp) { + rv = CERT_EnableOCSPChecking(handle); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, "CERT_EnableOCSPChecking failed: [%d].\n", + PR_GetError()); + return EIO; + } + } found_cert = NULL; DEBUG(SSSDBG_TRACE_ALL, "Filtered certificates:\n"); @@ -456,6 +466,8 @@ int main(int argc, const char *argv[]) char *slot_name_in = NULL; char *token_name_out = NULL; char *nss_db = NULL; + bool do_ocsp = true; + char *verify_opts = NULL; struct poptOption long_options[] = { POPT_AUTOHELP @@ -475,6 +487,8 @@ int main(int argc, const char *argv[]) {"pin", 0, POPT_ARG_NONE, NULL, 'i', _("Expect PIN on stdin"), NULL}, {"keypad", 0, POPT_ARG_NONE, NULL, 'k', _("Expect PIN on keypad"), NULL}, + {"verify", 0, POPT_ARG_STRING, &verify_opts, 0 , _("Tune validation"), + NULL}, {"nssdb", 0, POPT_ARG_STRING, &nss_db, 0, _("NSS DB to use"), NULL}, POPT_TABLEEND @@ -599,6 +613,13 @@ int main(int argc, const char *argv[]) } talloc_steal(main_ctx, debug_prg_name); + if (verify_opts != NULL) { + ret = parse_cert_verify_opts(verify_opts, &do_ocsp); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Failed to parse verifiy option.\n"); + goto fail; + } + } if (mode == OP_AUTH && pin_mode == PIN_STDIN) { ret = p11c_recv_data(main_ctx, STDIN_FILENO, &pin); @@ -608,7 +629,7 @@ int main(int argc, const char *argv[]) } } - ret = do_work(main_ctx, nss_db, slot_name_in, mode, pin, &cert, + ret = do_work(main_ctx, nss_db, slot_name_in, mode, pin, do_ocsp, &cert, &token_name_out); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "do_work failed.\n"); diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h index 64a7d8573..b44e1c337 100644 --- a/src/responder/pam/pamsrv.h +++ b/src/responder/pam/pamsrv.h @@ -87,6 +87,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, int child_debug_fd, const char *nss_db, time_t timeout, + const char *verify_opts, struct pam_data *pd); errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, char **cert, char **token_name); diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index 80095cc0b..b9fd35325 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -1032,6 +1032,7 @@ static errno_t check_cert(TALLOC_CTX *mctx, { int p11_child_timeout; const int P11_CHILD_TIMEOUT_DEFAULT = 10; + char *cert_verification_opts; errno_t ret; struct tevent_req *req; @@ -1046,8 +1047,19 @@ static errno_t check_cert(TALLOC_CTX *mctx, return ret; } + ret = confdb_get_string(pctx->rctx->cdb, mctx, CONFDB_MONITOR_CONF_ENTRY, + CONFDB_MONITOR_CERT_VERIFICATION, NULL, + &cert_verification_opts); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to read certificate_verification from confdb: [%d]: %s\n", + ret, sss_strerror(ret)); + return ret; + } + req = pam_check_cert_send(mctx, ev, pctx->p11_child_debug_fd, - pctx->nss_db, p11_child_timeout, pd); + pctx->nss_db, p11_child_timeout, + cert_verification_opts, pd); if (req == NULL) { DEBUG(SSSDBG_OP_FAILURE, "pam_check_cert_send failed.\n"); return ENOMEM; diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c index afb28fd52..58310a253 100644 --- a/src/responder/pam/pamsrv_p11.c +++ b/src/responder/pam/pamsrv_p11.c @@ -236,6 +236,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, int child_debug_fd, const char *nss_db, time_t timeout, + const char *verify_opts, struct pam_data *pd) { errno_t ret; @@ -246,9 +247,10 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, struct timeval tv; int pipefd_to_child[2]; int pipefd_from_child[2]; - const char *extra_args[5] = {NULL, NULL, NULL, NULL, NULL}; + const char *extra_args[7] = { NULL }; uint8_t *write_buf = NULL; size_t write_buf_len = 0; + size_t arg_c; req = tevent_req_create(mem_ctx, &state, struct pam_check_cert_state); if (req == NULL) { @@ -262,16 +264,21 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, } /* extra_args are added in revers order */ - extra_args[1] = "--nssdb"; - extra_args[0] = nss_db; + arg_c = 0; + extra_args[arg_c++] = nss_db; + extra_args[arg_c++] = "--nssdb"; + if (verify_opts != NULL) { + extra_args[arg_c++] = verify_opts; + extra_args[arg_c++] = "--verify"; + } if (pd->cmd == SSS_PAM_AUTHENTICATE) { - extra_args[2] = "--auth"; + extra_args[arg_c++] = "--auth"; switch (sss_authtok_get_type(pd->authtok)) { case SSS_AUTHTOK_TYPE_SC_PIN: - extra_args[3] = "--pin"; + extra_args[arg_c++] = "--pin"; break; case SSS_AUTHTOK_TYPE_SC_KEYPAD: - extra_args[3] = "--keypad"; + extra_args[arg_c++] = "--keypad"; break; default: DEBUG(SSSDBG_OP_FAILURE, "Unsupported authtok type.\n"); @@ -279,7 +286,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, goto done; } } else if (pd->cmd == SSS_PAM_PREAUTH) { - extra_args[2] = "--pre"; + extra_args[arg_c++] = "--pre"; } else { DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected PAM command [%d}.\n", pd->cmd); ret = EINVAL; diff --git a/src/responder/ssh/sshsrv_cmd.c b/src/responder/ssh/sshsrv_cmd.c index 5f5487035..af385fde8 100644 --- a/src/responder/ssh/sshsrv_cmd.c +++ b/src/responder/ssh/sshsrv_cmd.c @@ -797,6 +797,8 @@ static errno_t decode_and_add_base64_data(struct ssh_cmd_ctx *cmd_ctx, int ret; size_t d; TALLOC_CTX *tmp_ctx; + char *cert_verification_opts; + bool do_ocsp = true; if (el == NULL) { DEBUG(SSSDBG_TRACE_ALL, "Mssing element, nothing to do.\n"); @@ -811,9 +813,30 @@ static errno_t decode_and_add_base64_data(struct ssh_cmd_ctx *cmd_ctx, for (d = 0; d < el->num_values; d++) { if (cert_data) { + + ret = confdb_get_string(cctx->rctx->cdb, tmp_ctx, + CONFDB_MONITOR_CONF_ENTRY, + CONFDB_MONITOR_CERT_VERIFICATION, NULL, + &cert_verification_opts); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to read p11_child_timeout from confdb: [%d] %s\n", + ret, sss_strerror(ret)); + return ret; + } + + if (cert_verification_opts != NULL) { + ret = parse_cert_verify_opts(cert_verification_opts, &do_ocsp); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to parse verifiy option.\n"); + return ret; + } + } + ret = cert_to_ssh_key(tmp_ctx, ssh_ctx->ca_db, el->values[d].data, el->values[d].length, - &key, &key_len); + do_ocsp, &key, &key_len); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "cert_to_ssh_key failed.\n"); return ret; diff --git a/src/tests/cmocka/test_cert_utils.c b/src/tests/cmocka/test_cert_utils.c index 7bd8cf234..658391d14 100644 --- a/src/tests/cmocka/test_cert_utils.c +++ b/src/tests/cmocka/test_cert_utils.c @@ -356,7 +356,7 @@ void test_cert_to_ssh_key(void **state) assert_non_null(exp_key); ret = cert_to_ssh_key(ts, "sql:" ABS_SRC_DIR "/src/tests/cmocka/p11_nssdb", - der, der_size, &key, &key_size); + der, der_size, false, &key, &key_size); assert_int_equal(ret, EOK); assert_int_equal(key_size, exp_key_size); assert_memory_equal(key, exp_key, exp_key_size); diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c index f3fbf907a..75411feee 100644 --- a/src/tests/cmocka/test_pam_srv.c +++ b/src/tests/cmocka/test_pam_srv.c @@ -188,26 +188,38 @@ struct pam_ctx *mock_pctx(TALLOC_CTX *mem_ctx) return pctx; } -static int add_pam_params(struct sss_test_conf_param pam_params[], - struct confdb_ctx *cdb) +static int add_confdb_params(struct sss_test_conf_param params[], + struct confdb_ctx *cdb, const char *section) { const char *val[2]; int ret; val[1] = NULL; - for (int i = 0; pam_params[i].key; i++) { - val[0] = pam_params[i].value; - ret = confdb_add_param(cdb, true, CONFDB_PAM_CONF_ENTRY, - pam_params[i].key, val); + for (int i = 0; params[i].key; i++) { + val[0] = params[i].value; + ret = confdb_add_param(cdb, true, section, params[i].key, val); assert_int_equal(ret, EOK); } return EOK; } +static int add_pam_params(struct sss_test_conf_param pam_params[], + struct confdb_ctx *cdb) +{ + return add_confdb_params(pam_params, cdb, CONFDB_PAM_CONF_ENTRY); +} + +static int add_monitor_params(struct sss_test_conf_param monitor_params[], + struct confdb_ctx *cdb) +{ + return add_confdb_params(monitor_params, cdb, CONFDB_MONITOR_CONF_ENTRY); +} + void test_pam_setup(struct sss_test_conf_param dom_params[], struct sss_test_conf_param pam_params[], + struct sss_test_conf_param monitor_params[], void **state) { errno_t ret; @@ -243,6 +255,9 @@ void test_pam_setup(struct sss_test_conf_param dom_params[], ret = add_pam_params(pam_params, pam_test_ctx->rctx->cdb); assert_int_equal(ret, EOK); + ret = add_monitor_params(monitor_params, pam_test_ctx->rctx->cdb); + assert_int_equal(ret, EOK); + /* Create client context */ pam_test_ctx->cctx = mock_cctx(pam_test_ctx, pam_test_ctx->rctx); assert_non_null(pam_test_ctx->cctx); @@ -299,7 +314,12 @@ static int pam_test_setup(void **state) { NULL, NULL }, /* Sentinel */ }; - test_pam_setup(dom_params, pam_params, state); + struct sss_test_conf_param monitor_params[] = { + { "certificate_verification", "no_ocsp"}, + { NULL, NULL }, /* Sentinel */ + }; + + test_pam_setup(dom_params, pam_params, monitor_params, state); pam_test_setup_common(); return 0; @@ -319,7 +339,12 @@ static int pam_cached_test_setup(void **state) { NULL, NULL }, /* Sentinel */ }; - test_pam_setup(dom_params, pam_params, state); + struct sss_test_conf_param monitor_params[] = { + { "certificate_verification", "no_ocsp"}, + { NULL, NULL }, /* Sentinel */ + }; + + test_pam_setup(dom_params, pam_params, monitor_params, state); pam_test_setup_common(); return 0; diff --git a/src/util/cert.h b/src/util/cert.h index edbafc492..c8c425487 100644 --- a/src/util/cert.h +++ b/src/util/cert.h @@ -47,5 +47,6 @@ errno_t bin_to_ldap_filter_value(TALLOC_CTX *mem_ctx, errno_t cert_to_ssh_key(TALLOC_CTX *mem_ctx, const char *ca_db, const uint8_t *der_blob, size_t der_size, + bool do_ocsp, uint8_t **key, size_t *key_size); #endif /* __CERT_H__ */ diff --git a/src/util/cert/libcrypto/cert.c b/src/util/cert/libcrypto/cert.c index 01f9554b9..4e2dbe70c 100644 --- a/src/util/cert/libcrypto/cert.c +++ b/src/util/cert/libcrypto/cert.c @@ -172,6 +172,7 @@ done: errno_t cert_to_ssh_key(TALLOC_CTX *mem_ctx, const char *ca_db, const uint8_t *der_blob, size_t der_size, + bool do_ocsp, uint8_t **key, size_t *key_size) { int ret; diff --git a/src/util/cert/nss/cert.c b/src/util/cert/nss/cert.c index 1ada35b63..fbd063cf5 100644 --- a/src/util/cert/nss/cert.c +++ b/src/util/cert/nss/cert.c @@ -18,16 +18,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "util/util.h" +#include "config.h" #include <nss.h> #include <cert.h> #include <base64.h> #include <key.h> #include <prerror.h> +#include <ocsp.h> +#include <talloc.h> #include "util/crypto/sss_crypto.h" #include "util/crypto/nss/nss_util.h" +#include "util/cert.h" #define NS_CERT_HEADER "-----BEGIN CERTIFICATE-----" #define NS_CERT_TRAILER "-----END CERTIFICATE-----" @@ -220,6 +223,7 @@ done: errno_t cert_to_ssh_key(TALLOC_CTX *mem_ctx, const char *ca_db, const uint8_t *der_blob, size_t der_size, + bool do_ocsp, uint8_t **key, size_t *key_size) { CERTCertDBHandle *handle; @@ -255,6 +259,15 @@ errno_t cert_to_ssh_key(TALLOC_CTX *mem_ctx, const char *ca_db, handle = CERT_GetDefaultCertDB(); + if (do_ocsp) { + rv = CERT_EnableOCSPChecking(handle); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, "CERT_EnableOCSPChecking failed: [%d].\n", + PR_GetError()); + return EIO; + } + } + der_item.len = der_size; der_item.data = discard_const(der_blob); diff --git a/src/util/util.c b/src/util/util.c index 11924a371..8c0899b06 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -1106,3 +1106,49 @@ errno_t sss_unique_filename(TALLOC_CTX *owner, char *path_tmpl) return ret; } + +errno_t parse_cert_verify_opts(const char *verify_opts, bool *do_ocsp) +{ + int ret; + TALLOC_CTX *tmp_ctx; + char **opts; + size_t c; + + if (verify_opts == NULL) { + *do_ocsp = true; + + return EOK; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); + return ENOMEM; + } + + ret = split_on_separator(tmp_ctx, verify_opts, ',', true, true, &opts, + NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "split_on_separator failed.\n"); + goto done; + } + + for (c = 0; opts[c] != NULL; c++) { + if (strcasecmp(opts[c], "no_ocsp") == 0) { + DEBUG(SSSDBG_TRACE_ALL, + "Found 'no_ocsp' option, disabling OCSP.\n"); + *do_ocsp = false; + } else { + DEBUG(SSSDBG_CRIT_FAILURE, + "Unsupported certificate verification option [%s], " \ + "skipping.\n", opts[c]); + } + } + + ret = EOK; + +done: + talloc_free(tmp_ctx); + + return ret; +} diff --git a/src/util/util.h b/src/util/util.h index 3693a5e9f..e1245bb0f 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -424,6 +424,9 @@ int split_on_separator(TALLOC_CTX *mem_ctx, const char *str, char **parse_args(const char *str); +errno_t parse_cert_verify_opts(const char *verify_opts, bool *do_ocsp); + + errno_t sss_hash_create(TALLOC_CTX *mem_ctx, unsigned long count, hash_table_t **tbl); |