From e29b82077a78157a1e4d90e2308c1272d7612f3d Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Tue, 2 Oct 2018 12:13:29 +0200 Subject: [PATCH 56/83] p11: handle multiple certs during auth with OpenSSL This patch adds missing code already available in the NSS version to select a certificate for authentication if multiple certificates are available on the Smartcard. A unit test to check this feature is added as well. Related to https://pagure.io/SSSD/sssd/issue/3489 Reviewed-by: Jakub Hrozek --- src/p11_child/p11_child_openssl.c | 46 ++++++++++++++++++++++++++++++++++++++- src/tests/cmocka/test_pam_srv.c | 36 ++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/p11_child/p11_child_openssl.c b/src/p11_child/p11_child_openssl.c index be58726..bf4418f 100644 --- a/src/p11_child/p11_child_openssl.c +++ b/src/p11_child/p11_child_openssl.c @@ -572,8 +572,10 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx, char *slot_name = NULL; char *token_name = NULL; CK_SESSION_HANDLE session = 0; + struct cert_list *all_cert_list = NULL; struct cert_list *cert_list = NULL; struct cert_list *item = NULL; + struct cert_list *tmp_cert = NULL; char *multi = NULL; bool pkcs11_session = false; bool pkcs11_login = false; @@ -691,12 +693,54 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx, DEBUG(SSSDBG_TRACE_ALL, "Login NOT required.\n"); } - ret = read_certs(mem_ctx, module, session, p11_ctx, &cert_list); + ret = read_certs(mem_ctx, module, session, p11_ctx, &all_cert_list); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "read_certs failed.\n"); goto done; } + DLIST_FOR_EACH(item, all_cert_list) { + /* Check if we found the certificates we needed for authentication or + * the requested ones for pre-auth. For authentication all attributes + * must be given and match, for pre-auth only the given ones must + * match. */ + DEBUG(SSSDBG_TRACE_ALL, "%s %s %s %s %s %s.\n", + module_name_in, module_file_name, token_name_in, token_name, + key_id_in, item->id); + + if ((mode == OP_AUTH + && module_name_in != NULL + && token_name_in != NULL + && key_id_in != NULL + && item->id != NULL + && strcmp(key_id_in, item->id) == 0 + && strcmp(token_name_in, token_name) == 0 + && strcmp(module_name_in, module_file_name) == 0) + || (mode == OP_PREAUTH + && (module_name_in == NULL + || (module_name_in != NULL + && strcmp(module_name_in, module_file_name) == 0)) + && (token_name_in == NULL + || (token_name_in != NULL + && strcmp(token_name_in, token_name) == 0)) + && (key_id_in == NULL + || (key_id_in != NULL && item->id != NULL + && strcmp(key_id_in, item->id) == 0)))) { + + tmp_cert = talloc_memdup(mem_ctx, item, sizeof(struct cert_list)); + if (tmp_cert == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_memdup failed.\n"); + ret = ENOMEM; + goto done; + } + tmp_cert->prev = NULL; + tmp_cert->next = NULL; + + DLIST_ADD(cert_list, tmp_cert); + + } + } + /* TODO: check module_name_in, token_name_in, key_id_in */ if (cert_list == NULL) { diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c index 446985d..2b02ac2 100644 --- a/src/tests/cmocka/test_pam_srv.c +++ b/src/tests/cmocka/test_pam_srv.c @@ -2443,6 +2443,40 @@ void test_pam_cert_preauth_2certs_two_mappings(void **state) assert_int_equal(ret, EOK); } +void test_pam_cert_auth_2certs_one_mapping(void **state) +{ + int ret; + +#ifdef HAVE_NSS + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB_2CERTS); +#else + set_cert_auth_param(pam_test_ctx->pctx, CA_DB); + putenv(discard_const("SOFTHSM2_CONF=" ABS_BUILD_DIR "/src/tests/test_CA/softhsm2_two.conf")); +#endif + + mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", "SSSD Test Token", + TEST_MODULE_NAME, + "C554C9F82C2A9D58B70921C143304153A8A42F17", NULL, + test_lookup_by_cert_double_cb, SSSD_TEST_CERT_0001, + true); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + + /* Assume backend cannot handle Smartcard credentials */ + pam_test_ctx->exp_pam_status = PAM_BAD_ITEM; + + set_cmd_cb(test_pam_simple_check_success); + ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, + pam_test_ctx->pam_cmds); + assert_int_equal(ret, EOK); + + /* Wait until the test finishes with EOK */ + ret = test_ev_loop(pam_test_ctx->tctx); + assert_int_equal(ret, EOK); +} + + void test_filter_response(void **state) { int ret; @@ -2875,6 +2909,8 @@ int main(int argc, const char *argv[]) pam_test_setup, pam_test_teardown), cmocka_unit_test_setup_teardown(test_pam_cert_preauth_2certs_two_mappings, pam_test_setup, pam_test_teardown), + cmocka_unit_test_setup_teardown(test_pam_cert_auth_2certs_one_mapping, + pam_test_setup, pam_test_teardown), cmocka_unit_test_setup_teardown(test_pam_cert_auth_no_logon_name, pam_test_setup, pam_test_teardown), cmocka_unit_test_setup_teardown(test_pam_cert_auth_no_logon_name_no_key_id, -- 2.9.5