diff options
author | Sumit Bose <sbose@redhat.com> | 2016-04-12 18:14:08 +0200 |
---|---|---|
committer | Lukas Slebodnik <lslebodn@redhat.com> | 2016-06-09 11:58:17 +0200 |
commit | 53ef8f81b60929a6c866efdd133627e7d7d61705 (patch) | |
tree | dec625c6cd01e15e73ace5d2e71054e95921e9f4 | |
parent | aa35995ef056aa8ae052a47c62c6750b7adf065e (diff) | |
download | sssd-53ef8f81b60929a6c866efdd133627e7d7d61705.tar.gz sssd-53ef8f81b60929a6c866efdd133627e7d7d61705.tar.xz sssd-53ef8f81b60929a6c866efdd133627e7d7d61705.zip |
p11: add OCSP default responder options
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-rw-r--r-- | src/man/sssd.conf.5.xml | 28 | ||||
-rw-r--r-- | src/p11_child/p11_child_nss.c | 33 | ||||
-rw-r--r-- | src/tests/cmocka/test_utils.c | 80 | ||||
-rw-r--r-- | src/util/cert/nss/cert.c | 43 | ||||
-rw-r--r-- | src/util/util.c | 60 | ||||
-rw-r--r-- | src/util/util.h | 2 |
6 files changed, 242 insertions, 4 deletions
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml index 5396a490a..6cff0dc87 100644 --- a/src/man/sssd.conf.5.xml +++ b/src/man/sssd.conf.5.xml @@ -391,6 +391,34 @@ testing.</para> </listitem> </varlistentry> + <varlistentry> + <term>ocsp_default_responder=URL</term> + <listitem> + <para>Sets the OCSP default responder + which should be used instead of the one + mentioned in the certificate. URL must + be replaced with the URL of the OCSP + default responder e.g. + http://example.com:80/ocsp.</para> + <para>This option must be used together + with + ocsp_default_responder_signing_cert. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + ocsp_default_responder_signing_cert=NAME</term> + <listitem> + <para>The nickname of the cert to trust + (expected) to sign the OCSP responses. + The certificate with the given nickname + must be availble in the systems NSS + database.</para> + <para>This option must be used together + with ocsp_default_responder.</para> + </listitem> + </varlistentry> </variablelist> </para> <para> diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c index be3f33981..feae88436 100644 --- a/src/p11_child/p11_child_nss.c +++ b/src/p11_child/p11_child_nss.c @@ -271,6 +271,27 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, PR_GetError()); return EIO; } + + if (cert_verify_opts->ocsp_default_responder != NULL + && cert_verify_opts->ocsp_default_responder_signing_cert != NULL) { + rv = CERT_SetOCSPDefaultResponder(handle, + cert_verify_opts->ocsp_default_responder, + cert_verify_opts->ocsp_default_responder_signing_cert); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, + "CERT_SetOCSPDefaultResponder failed: [%d].\n", + PR_GetError()); + return EIO; + } + + rv = CERT_EnableOCSPDefaultResponder(handle); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, + "CERT_EnableOCSPDefaultResponder failed: [%d].\n", + PR_GetError()); + return EIO; + } + } } found_cert = NULL; @@ -309,6 +330,18 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, } } + /* Disable OCSP default responder so that NSS can shutdown properly */ + if (cert_verify_opts->do_ocsp + && cert_verify_opts->ocsp_default_responder != NULL + && cert_verify_opts->ocsp_default_responder_signing_cert != NULL) { + rv = CERT_DisableOCSPDefaultResponder(handle); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, + "CERT_DisableOCSPDefaultResponder failed: [%d].\n", + PR_GetError()); + } + } + if (found_cert == NULL) { DEBUG(SSSDBG_TRACE_ALL, "No certificate found.\n"); *cert = NULL; diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c index 3aea17f36..aaba2df6d 100644 --- a/src/tests/cmocka/test_utils.c +++ b/src/tests/cmocka/test_utils.c @@ -1487,6 +1487,83 @@ static void test_sss_unique_filename_destruct(void **state) sss_unique_filename_test(test_ctx, true); } +static void test_parse_cert_verify_opts(void **state) +{ + int ret; + struct cert_verify_opts *cv_opts; + + ret = parse_cert_verify_opts(global_talloc_context, NULL, &cv_opts); + assert_int_equal(ret, EOK); + assert_true(cv_opts->do_verification); + assert_true(cv_opts->do_ocsp); + assert_null(cv_opts->ocsp_default_responder); + assert_null(cv_opts->ocsp_default_responder_signing_cert); + talloc_free(cv_opts); + + ret = parse_cert_verify_opts(global_talloc_context, "wedfkwefjk", &cv_opts); + assert_int_equal(ret, EOK); + assert_true(cv_opts->do_verification); + assert_true(cv_opts->do_ocsp); + assert_null(cv_opts->ocsp_default_responder); + assert_null(cv_opts->ocsp_default_responder_signing_cert); + talloc_free(cv_opts); + + ret = parse_cert_verify_opts(global_talloc_context, "no_ocsp", &cv_opts); + assert_int_equal(ret, EOK); + assert_true(cv_opts->do_verification); + assert_false(cv_opts->do_ocsp); + assert_null(cv_opts->ocsp_default_responder); + assert_null(cv_opts->ocsp_default_responder_signing_cert); + talloc_free(cv_opts); + + ret = parse_cert_verify_opts(global_talloc_context, "no_verification", + &cv_opts); + assert_int_equal(ret, EOK); + assert_false(cv_opts->do_verification); + assert_true(cv_opts->do_ocsp); + assert_null(cv_opts->ocsp_default_responder); + assert_null(cv_opts->ocsp_default_responder_signing_cert); + talloc_free(cv_opts); + + ret = parse_cert_verify_opts(global_talloc_context, + "no_ocsp,no_verification", &cv_opts); + assert_int_equal(ret, EOK); + assert_false(cv_opts->do_verification); + assert_false(cv_opts->do_ocsp); + assert_null(cv_opts->ocsp_default_responder); + assert_null(cv_opts->ocsp_default_responder_signing_cert); + talloc_free(cv_opts); + + ret = parse_cert_verify_opts(global_talloc_context, + "ocsp_default_responder=", &cv_opts); + assert_int_equal(ret, EINVAL); + + ret = parse_cert_verify_opts(global_talloc_context, + "ocsp_default_responder_signing_cert=", + &cv_opts); + assert_int_equal(ret, EINVAL); + + ret = parse_cert_verify_opts(global_talloc_context, + "ocsp_default_responder=abc", &cv_opts); + assert_int_equal(ret, EINVAL); + + ret = parse_cert_verify_opts(global_talloc_context, + "ocsp_default_responder_signing_cert=def", + &cv_opts); + assert_int_equal(ret, EINVAL); + + ret = parse_cert_verify_opts(global_talloc_context, + "ocsp_default_responder=abc," + "ocsp_default_responder_signing_cert=def", + &cv_opts); + assert_int_equal(ret, EOK); + assert_true(cv_opts->do_verification); + assert_true(cv_opts->do_ocsp); + assert_string_equal(cv_opts->ocsp_default_responder, "abc"); + assert_string_equal(cv_opts->ocsp_default_responder_signing_cert, "def"); + talloc_free(cv_opts); +} + int main(int argc, const char *argv[]) { poptContext pc; @@ -1566,6 +1643,9 @@ int main(int argc, const char *argv[]) cmocka_unit_test_setup_teardown(test_sss_unique_filename_destruct, unique_file_test_setup, unique_file_test_teardown), + cmocka_unit_test_setup_teardown(test_parse_cert_verify_opts, + setup_add_strings_lists, + teardown_add_strings_lists), }; /* Set debug level to invalid value so we can deside if -d 0 was used. */ diff --git a/src/util/cert/nss/cert.c b/src/util/cert/nss/cert.c index 9c1c965dd..7bf9a8bfc 100644 --- a/src/util/cert/nss/cert.c +++ b/src/util/cert/nss/cert.c @@ -238,6 +238,7 @@ errno_t cert_to_ssh_key(TALLOC_CTX *mem_ctx, const char *ca_db, NSSInitParameters parameters = { 0 }; parameters.length = sizeof (parameters); SECStatus rv; + SECStatus rv_verify; if (der_blob == NULL || der_size == 0) { return EINVAL; @@ -266,6 +267,27 @@ errno_t cert_to_ssh_key(TALLOC_CTX *mem_ctx, const char *ca_db, PR_GetError()); return EIO; } + + if (cert_verify_opts->ocsp_default_responder != NULL + && cert_verify_opts->ocsp_default_responder_signing_cert != NULL) { + rv = CERT_SetOCSPDefaultResponder(handle, + cert_verify_opts->ocsp_default_responder, + cert_verify_opts->ocsp_default_responder_signing_cert); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, + "CERT_SetOCSPDefaultResponder failed: [%d].\n", + PR_GetError()); + return EIO; + } + + rv = CERT_EnableOCSPDefaultResponder(handle); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, + "CERT_EnableOCSPDefaultResponder failed: [%d].\n", + PR_GetError()); + return EIO; + } + } } der_item.len = der_size; @@ -279,9 +301,24 @@ errno_t cert_to_ssh_key(TALLOC_CTX *mem_ctx, const char *ca_db, } if (cert_verify_opts->do_verification) { - rv = CERT_VerifyCertificateNow(handle, cert, PR_TRUE, - certificateUsageSSLClient, NULL, NULL); - if (rv != SECSuccess) { + rv_verify = CERT_VerifyCertificateNow(handle, cert, PR_TRUE, + certificateUsageSSLClient, + NULL, NULL); + + /* Disable OCSP default responder so that NSS can shutdown properly */ + if (cert_verify_opts->do_ocsp + && cert_verify_opts->ocsp_default_responder != NULL + && cert_verify_opts->ocsp_default_responder_signing_cert + != NULL) { + rv = CERT_DisableOCSPDefaultResponder(handle); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, + "CERT_DisableOCSPDefaultResponder failed: [%d].\n", + PR_GetError()); + } + } + + if (rv_verify != SECSuccess) { DEBUG(SSSDBG_CRIT_FAILURE, "CERT_VerifyCertificateNow failed [%d].\n", PR_GetError()); ret = EACCES; diff --git a/src/util/util.c b/src/util/util.c index 2449a0ff3..d7d3ac90a 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -1111,7 +1111,7 @@ static struct cert_verify_opts *init_cert_verify_opts(TALLOC_CTX *mem_ctx) { struct cert_verify_opts *cert_verify_opts; - cert_verify_opts = talloc(mem_ctx, struct cert_verify_opts); + cert_verify_opts = talloc_zero(mem_ctx, struct cert_verify_opts); if (cert_verify_opts == NULL) { DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); return NULL; @@ -1119,10 +1119,20 @@ static struct cert_verify_opts *init_cert_verify_opts(TALLOC_CTX *mem_ctx) cert_verify_opts->do_ocsp = true; cert_verify_opts->do_verification = true; + cert_verify_opts->ocsp_default_responder = NULL; + cert_verify_opts->ocsp_default_responder_signing_cert = NULL; return cert_verify_opts; } +#define OCSP_DEFAUL_RESPONDER "ocsp_default_responder=" +#define OCSP_DEFAUL_RESPONDER_LEN (sizeof(OCSP_DEFAUL_RESPONDER) - 1) + +#define OCSP_DEFAUL_RESPONDER_SIGNING_CERT \ + "ocsp_default_responder_signing_cert=" +#define OCSP_DEFAUL_RESPONDER_SIGNING_CERT_LEN \ + (sizeof(OCSP_DEFAUL_RESPONDER_SIGNING_CERT) - 1) + errno_t parse_cert_verify_opts(TALLOC_CTX *mem_ctx, const char *verify_opts, struct cert_verify_opts **_cert_verify_opts) { @@ -1168,6 +1178,41 @@ errno_t parse_cert_verify_opts(TALLOC_CTX *mem_ctx, const char *verify_opts, "disabling verification completely. " "This should not be used in production.\n"); cert_verify_opts->do_verification = false; + } else if (strncasecmp(opts[c], OCSP_DEFAUL_RESPONDER, + OCSP_DEFAUL_RESPONDER_LEN) == 0) { + cert_verify_opts->ocsp_default_responder = + talloc_strdup(cert_verify_opts, + &opts[c][OCSP_DEFAUL_RESPONDER_LEN]); + if (cert_verify_opts->ocsp_default_responder == NULL + || *cert_verify_opts->ocsp_default_responder == '\0') { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to parse ocsp_default_responder option [%s].\n", + opts[c]); + ret = EINVAL; + goto done; + } + + DEBUG(SSSDBG_TRACE_ALL, "Using OCSP default responder [%s]\n", + cert_verify_opts->ocsp_default_responder); + } else if (strncasecmp(opts[c], + OCSP_DEFAUL_RESPONDER_SIGNING_CERT, + OCSP_DEFAUL_RESPONDER_SIGNING_CERT_LEN) == 0) { + cert_verify_opts->ocsp_default_responder_signing_cert = + talloc_strdup(cert_verify_opts, + &opts[c][OCSP_DEFAUL_RESPONDER_SIGNING_CERT_LEN]); + if (cert_verify_opts->ocsp_default_responder_signing_cert == NULL + || *cert_verify_opts->ocsp_default_responder_signing_cert + == '\0') { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to parse ocsp_default_responder_signing_cert " + "option [%s].\n", opts[c]); + ret = EINVAL; + goto done; + } + + DEBUG(SSSDBG_TRACE_ALL, + "Using OCSP default responder signing cert nickname [%s]\n", + cert_verify_opts->ocsp_default_responder_signing_cert); } else { DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported certificate verification option [%s], " \ @@ -1175,6 +1220,19 @@ errno_t parse_cert_verify_opts(TALLOC_CTX *mem_ctx, const char *verify_opts, } } + if ((cert_verify_opts->ocsp_default_responder == NULL + && cert_verify_opts->ocsp_default_responder_signing_cert != NULL) + || (cert_verify_opts->ocsp_default_responder != NULL + && cert_verify_opts->ocsp_default_responder_signing_cert == NULL)) { + + DEBUG(SSSDBG_CRIT_FAILURE, + "ocsp_default_responder and ocsp_default_responder_signing_cert " + "must be used together.\n"); + + ret = EINVAL; + goto done; + } + ret = EOK; done: diff --git a/src/util/util.h b/src/util/util.h index d7dc0aaf2..d36bb6086 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -330,6 +330,8 @@ char **parse_args(const char *str); struct cert_verify_opts { bool do_ocsp; bool do_verification; + char *ocsp_default_responder; + char *ocsp_default_responder_signing_cert; }; errno_t parse_cert_verify_opts(TALLOC_CTX *mem_ctx, const char *verify_opts, |