From 4f09838b50cc771d52c7b00cc47fb3362d8ecda2 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Mon, 30 Oct 2017 08:03:42 +0100 Subject: [PATCH 40/46] pam: add prompt string for certificate authentication MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A new certificate attribute is added which contains a string which is used in the certificate selection list displayed to the user. The Subject-DN of the certificate is used here because it is present in all certificate and in general differs for certificate with different usage. libsss_certmap is used to extract the subject-DN from the certificate and convert it into a string. Related to https://pagure.io/SSSD/sssd/issue/3560 Reviewed-by: Fabiano FidĂȘncio Tested-by: Scott Poore (cherry picked from commit 06c2300353faf3983e38fecb1d6afe1f6cc8fe32) --- Makefile.am | 2 ++ src/responder/pam/pamsrv_p11.c | 65 ++++++++++++++++++++++++++++++++++++++++- src/sss_client/pam_sss.c | 31 ++++++++++++++++---- src/tests/cmocka/test_pam_srv.c | 23 +++++++++++++-- 4 files changed, 111 insertions(+), 10 deletions(-) diff --git a/Makefile.am b/Makefile.am index 4ed872a532daf9b934537cc5f64ce77778121e2a..16bcb4efc028b05c1196249245f4f3091b9366af 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1400,6 +1400,7 @@ sssd_pam_LDADD = \ $(SELINUX_LIBS) \ $(PAM_LIBS) \ $(SYSTEMD_DAEMON_LIBS) \ + libsss_certmap.la \ $(SSSD_INTERNAL_LTLIBS) \ $(NULL) @@ -2423,6 +2424,7 @@ pam_srv_tests_LDADD = \ $(SYSTEMD_DAEMON_LIBS) \ libsss_test_common.la \ libsss_idmap.la \ + libsss_certmap.la \ $(NULL) EXTRA_responder_get_domains_tests_DEPENDENCIES = \ diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c index 4d5572164763ed0b3a842019f820680a4dc2dfdc..5a3eeff0ec977829a9ad8c80b4fc6b2e06857097 100644 --- a/src/responder/pam/pamsrv_p11.c +++ b/src/responder/pam/pamsrv_p11.c @@ -26,6 +26,8 @@ #include "util/child_common.h" #include "util/strtonum.h" #include "responder/pam/pamsrv.h" +#include "lib/certmap/sss_certmap.h" +#include "util/crypto/sss_crypto.h" #ifndef SSSD_LIBEXEC_PATH @@ -683,6 +685,54 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, return EOK; } +static char *get_cert_prompt(TALLOC_CTX *mem_ctx, const char *cert) +{ + int ret; + struct sss_certmap_ctx *ctx = NULL; + unsigned char *der = NULL; + size_t der_size; + char *prompt = NULL; + char *filter = NULL; + char **domains = NULL; + + ret = sss_certmap_init(mem_ctx, NULL, NULL, &ctx); + if (ret != 0) { + DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_init failed.\n"); + return NULL; + } + + ret = sss_certmap_add_rule(ctx, 10, "KRB5:.*", + "LDAP:{subject_dn!nss}", NULL); + if (ret != 0) { + DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_add_rule failed.\n"); + goto done; + } + + der = sss_base64_decode(mem_ctx, cert, &der_size); + if (der == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n"); + goto done; + } + + ret = sss_certmap_get_search_filter(ctx, der, der_size, &filter, &domains); + if (ret != 0) { + DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_get_search_filter failed.\n"); + goto done; + } + + prompt = talloc_strdup(mem_ctx, filter); + if (prompt == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); + } + +done: + sss_certmap_free_filter_and_domains(filter, domains); + sss_certmap_free_ctx(ctx); + talloc_free(der); + + return prompt; +} + static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, struct cert_auth_info *cert_info, uint8_t **_msg, size_t *_msg_len) @@ -692,16 +742,24 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, const char *token_name; const char *module_name; const char *key_id; + char *prompt; size_t user_len; size_t token_len; size_t module_len; size_t key_id_len; + size_t prompt_len; const char *username = ""; if (sysdb_username != NULL) { username = sysdb_username; } + prompt = get_cert_prompt(mem_ctx, sss_cai_get_cert(cert_info)); + if (prompt == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "get_cert_prompt failed.\n"); + return EIO; + } + token_name = sss_cai_get_token_name(cert_info); module_name = sss_cai_get_module_name(cert_info); key_id = sss_cai_get_key_id(cert_info); @@ -710,10 +768,12 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, token_len = strlen(token_name) + 1; module_len = strlen(module_name) + 1; key_id_len = strlen(key_id) + 1; - msg_len = user_len + token_len + module_len + key_id_len; + prompt_len = strlen(prompt) + 1; + msg_len = user_len + token_len + module_len + key_id_len + prompt_len; msg = talloc_zero_size(mem_ctx, msg_len); if (msg == NULL) { + talloc_free(prompt); DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n"); return ENOMEM; } @@ -722,6 +782,9 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, memcpy(msg + user_len, token_name, token_len); memcpy(msg + user_len + token_len, module_name, module_len); memcpy(msg + user_len + token_len + module_len, key_id, key_id_len); + memcpy(msg + user_len + token_len + module_len + key_id_len, + prompt, prompt_len); + talloc_free(prompt); if (_msg != NULL) { *_msg = msg; diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c index c147d4b3d76443d69e27eb2da042f8eebd1ae6ab..1dc51ea0536a92a63ec2f4d97f65dbb02604dbb3 100644 --- a/src/sss_client/pam_sss.c +++ b/src/sss_client/pam_sss.c @@ -129,6 +129,7 @@ struct cert_auth_info { char *token_name; char *module_name; char *key_id; + char *prompt_str; struct cert_auth_info *prev; struct cert_auth_info *next; }; @@ -140,6 +141,7 @@ static void free_cai(struct cert_auth_info *cai) free(cai->cert); free(cai->token_name); free(cai->key_id); + free(cai->prompt_str); free(cai); } } @@ -921,9 +923,25 @@ static int parse_cert_info(struct pam_items *pi, uint8_t *buf, size_t len, goto done; } - D(("cert user: [%s] token name: [%s] module: [%s] key id: [%s]", + offset += strlen(cai->key_id) + 1; + if (offset >= len) { + D(("Cert message size mismatch")); + ret = EINVAL; + goto done; + } + + cai->prompt_str = strdup((char *) &buf[*p + offset]); + if (cai->prompt_str == NULL) { + D(("strdup failed")); + ret = ENOMEM; + goto done; + } + + + D(("cert user: [%s] token name: [%s] module: [%s] key id: [%s] " + "prompt: [%s]", cai->cert_user, cai->token_name, cai->module_name, - cai->key_id)); + cai->key_id, cai->prompt_str)); DLIST_ADD(pi->cert_list, cai); ret = 0; @@ -1543,7 +1561,7 @@ done: #define discard_const(ptr) ((void *)((uintptr_t)(ptr))) #endif -#define CERT_SEL_PROMPT_FMT "Certificate: %s" +#define CERT_SEL_PROMPT_FMT "%s" #define SEL_TITLE discard_const("Please select a certificate") static int prompt_multi_cert_gdm(pam_handle_t *pamh, struct pam_items *pi) @@ -1588,7 +1606,7 @@ static int prompt_multi_cert_gdm(pam_handle_t *pamh, struct pam_items *pi) c = 0; DLIST_FOR_EACH(cai, pi->cert_list) { - ret = asprintf(&prompt, CERT_SEL_PROMPT_FMT, cai->key_id); + ret = asprintf(&prompt, CERT_SEL_PROMPT_FMT, cai->prompt_str); if (ret == -1) { ret = ENOMEM; goto done; @@ -1637,9 +1655,10 @@ done: #endif } -#define TEXT_CERT_SEL_PROMPT_FMT "%s[%zu] Certificate: %s\n" +#define TEXT_CERT_SEL_PROMPT_FMT "%s\n[%zu]:\n%s\n" #define TEXT_SEL_TITLE discard_const("Please select a certificate by typing " \ "the corresponding number\n") + static int prompt_multi_cert(pam_handle_t *pamh, struct pam_items *pi) { int ret; @@ -1670,7 +1689,7 @@ static int prompt_multi_cert(pam_handle_t *pamh, struct pam_items *pi) DLIST_FOR_EACH(cai, pi->cert_list) { cert_count++; ret = asprintf(&tmp, TEXT_CERT_SEL_PROMPT_FMT, prompt, cert_count, - cai->key_id); + cai->prompt_str); free(prompt); if (ret == -1) { return ENOMEM; diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c index 5c1f621ccead75717d1721714d953d7d4d415d7b..50d3ed005468375ff02c60bebd1c61047ca1c6d4 100644 --- a/src/tests/cmocka/test_pam_srv.c +++ b/src/tests/cmocka/test_pam_srv.c @@ -53,6 +53,7 @@ #define TEST_TOKEN_NAME "SSSD Test Token" #define TEST_MODULE_NAME "NSS-Internal" #define TEST_KEY_ID "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7" +#define TEST_SUBJECT_DN "CN=ipa-devel.ipa.devel,O=IPA.DEVEL" #define TEST_TOKEN_CERT \ "MIIECTCCAvGgAwIBAgIBCTANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \ @@ -78,6 +79,7 @@ "XyQBwOYRORlnfGyu+Yc9c3E0Wx8Tlznz0lqPR9g=" #define TEST2_KEY_ID "C8D60E009EB195D01A7083EE1D5419251AA87C2C" +#define TEST2_SUBJECT_DN "CN=IPA RA,O=IPA.DEVEL" #define TEST_TOKEN_2ND_CERT \ "MIIDazCCAlOgAwIBAgIBBzANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \ @@ -831,7 +833,8 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, assert_int_equal(val, (sizeof("pamuser@"TEST_DOM_NAME) + sizeof(TEST_TOKEN_NAME) + sizeof(TEST_MODULE_NAME) - + sizeof(TEST_KEY_ID))); + + sizeof(TEST_KEY_ID) + + sizeof(TEST_SUBJECT_DN))); assert_int_equal(*(body + rp + sizeof("pamuser@"TEST_DOM_NAME) - 1), 0); assert_string_equal(body + rp, "pamuser@"TEST_DOM_NAME); @@ -849,6 +852,10 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, assert_string_equal(body + rp, TEST_KEY_ID); rp += sizeof(TEST_KEY_ID); + assert_int_equal(*(body + rp + sizeof(TEST_SUBJECT_DN) - 1), 0); + assert_string_equal(body + rp, TEST_SUBJECT_DN); + rp += sizeof(TEST_SUBJECT_DN); + assert_int_equal(rp, blen); return EOK; } @@ -893,7 +900,8 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, assert_int_equal(val, (strlen(name) + 1 + sizeof(TEST_TOKEN_NAME) + sizeof(TEST_MODULE_NAME) - + sizeof(TEST_KEY_ID))); + + sizeof(TEST_KEY_ID) + + sizeof(TEST_SUBJECT_DN))); assert_int_equal(*(body + rp + strlen(name)), 0); assert_string_equal(body + rp, name); @@ -911,6 +919,10 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, assert_string_equal(body + rp, TEST_KEY_ID); rp += sizeof(TEST_KEY_ID); + assert_int_equal(*(body + rp + sizeof(TEST_SUBJECT_DN) - 1), 0); + assert_string_equal(body + rp, TEST_SUBJECT_DN); + rp += sizeof(TEST_SUBJECT_DN); + if (name2 != NULL && *name2 != '\0') { SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); assert_int_equal(val, type); @@ -919,7 +931,8 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, assert_int_equal(val, (strlen(name) + 1 + sizeof(TEST_TOKEN_NAME) + sizeof(TEST_MODULE_NAME) - + sizeof(TEST2_KEY_ID))); + + sizeof(TEST2_KEY_ID) + + sizeof(TEST2_SUBJECT_DN))); assert_int_equal(*(body + rp + strlen(name)), 0); assert_string_equal(body + rp, name); @@ -936,6 +949,10 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, assert_int_equal(*(body + rp + sizeof(TEST2_KEY_ID) - 1), 0); assert_string_equal(body + rp, TEST2_KEY_ID); rp += sizeof(TEST2_KEY_ID); + + assert_int_equal(*(body + rp + sizeof(TEST2_SUBJECT_DN) - 1), 0); + assert_string_equal(body + rp, TEST2_SUBJECT_DN); + rp += sizeof(TEST2_SUBJECT_DN); } assert_int_equal(rp, blen); -- 2.13.6