Blame SOURCES/0044-PAM-add-certificate-s-label-to-the-selection-prompt.patch

ced1f5
From 35790511fd43b0c33f3b410b20a31e007b3e5d20 Mon Sep 17 00:00:00 2001
ced1f5
From: Sumit Bose <sbose@redhat.com>
ced1f5
Date: Tue, 7 Nov 2017 09:52:56 +0100
ced1f5
Subject: [PATCH 44/46] PAM: add certificate's label to the selection prompt
ced1f5
MIME-Version: 1.0
ced1f5
Content-Type: text/plain; charset=UTF-8
ced1f5
Content-Transfer-Encoding: 8bit
ced1f5
ced1f5
Some types of Smartcards contain multiple certificate with the same
ced1f5
subject-DN for different usages. To make it easier to choose between
ced1f5
them in case the matching rules allow more than one of them for
ced1f5
authentication the label assigned to the certificate on the Smartcard is
ced1f5
shown in the selection prompt as well.
ced1f5
ced1f5
Related to https://pagure.io/SSSD/sssd/issue/3560
ced1f5
ced1f5
Reviewed-by: Fabiano FidĂȘncio <fidencio@redhat.com>
ced1f5
Tested-by: Scott Poore <spoore@redhat.com>
ced1f5
(cherry picked from commit 57cefea8305a57c1c0491afb739813b7f17d5a25)
ced1f5
---
ced1f5
 src/p11_child/p11_child_nss.c   | 18 ++++++++++++++----
ced1f5
 src/responder/pam/pamsrv.h      |  1 +
ced1f5
 src/responder/pam/pamsrv_p11.c  | 41 +++++++++++++++++++++++++++++++++++++----
ced1f5
 src/tests/cmocka/test_pam_srv.c | 28 ++++++++++++++--------------
ced1f5
 4 files changed, 66 insertions(+), 22 deletions(-)
ced1f5
ced1f5
diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
ced1f5
index e59aba0d1561f58206252f7251ecd88315836b1b..21c508eb1b1b68b3606d0a5eed36573b01f27a19 100644
ced1f5
--- a/src/p11_child/p11_child_nss.c
ced1f5
+++ b/src/p11_child/p11_child_nss.c
ced1f5
@@ -130,7 +130,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
ced1f5
     CERTCertificate *found_cert = NULL;
ced1f5
     PK11SlotList *list = NULL;
ced1f5
     PK11SlotListElement *le;
ced1f5
-    SECItem *key_id = NULL;
ced1f5
+    const char *label;
ced1f5
     char *key_id_str = NULL;
ced1f5
     CERTCertList *valid_certs = NULL;
ced1f5
     char *cert_b64 = NULL;
ced1f5
@@ -505,6 +505,17 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
ced1f5
             goto done;
ced1f5
         }
ced1f5
 
ced1f5
+        /* The NSS nickname is typically token_name:label, so the label starts
ced1f5
+         * after the ':'. */
ced1f5
+        if (found_cert->nickname != NULL) {
ced1f5
+            if ((label = strchr(found_cert->nickname, ':')) == NULL) {
ced1f5
+                label = found_cert->nickname;
ced1f5
+            } else {
ced1f5
+                label++;
ced1f5
+            }
ced1f5
+        } else {
ced1f5
+            label = "- no label found -";
ced1f5
+        }
ced1f5
         talloc_free(cert_b64);
ced1f5
         cert_b64 = sss_base64_encode(mem_ctx, found_cert->derCert.data,
ced1f5
                                      found_cert->derCert.len);
ced1f5
@@ -517,9 +528,9 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
ced1f5
         DEBUG(SSSDBG_TRACE_ALL, "Found certificate has key id [%s].\n",
ced1f5
               key_id_str);
ced1f5
 
ced1f5
-        multi = talloc_asprintf_append(multi, "%s\n%s\n%s\n%s\n",
ced1f5
+        multi = talloc_asprintf_append(multi, "%s\n%s\n%s\n%s\n%s\n",
ced1f5
                                        token_name, module_name, key_id_str,
ced1f5
-                                       cert_b64);
ced1f5
+                                       label, cert_b64);
ced1f5
     }
ced1f5
     *_multi = multi;
ced1f5
 
ced1f5
@@ -546,7 +557,6 @@ done:
ced1f5
         CERT_DestroyCertList(cert_list);
ced1f5
     }
ced1f5
 
ced1f5
-    SECITEM_FreeItem(key_id, PR_TRUE);
ced1f5
     PORT_Free(key_id_str);
ced1f5
 
ced1f5
     PORT_Free(signed_random_value.data);
ced1f5
diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
ced1f5
index 0bc229212844602ed461d1c7db48bf51ac2e2194..dfd982178446d6327e09afc652018886c08fd88a 100644
ced1f5
--- a/src/responder/pam/pamsrv.h
ced1f5
+++ b/src/responder/pam/pamsrv.h
ced1f5
@@ -93,6 +93,7 @@ const char *sss_cai_get_cert(struct cert_auth_info *i);
ced1f5
 const char *sss_cai_get_token_name(struct cert_auth_info *i);
ced1f5
 const char *sss_cai_get_module_name(struct cert_auth_info *i);
ced1f5
 const char *sss_cai_get_key_id(struct cert_auth_info *i);
ced1f5
+const char *sss_cai_get_label(struct cert_auth_info *i);
ced1f5
 struct cert_auth_info *sss_cai_get_next(struct cert_auth_info *i);
ced1f5
 struct ldb_result *sss_cai_get_cert_user_objs(struct cert_auth_info *i);
ced1f5
 void sss_cai_set_cert_user_objs(struct cert_auth_info *i,
ced1f5
diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
ced1f5
index ec52c5ae7163d41144fe082643a201b766a1e201..fa2435543ea305f7cdb1e18753525beb373eaf4c 100644
ced1f5
--- a/src/responder/pam/pamsrv_p11.c
ced1f5
+++ b/src/responder/pam/pamsrv_p11.c
ced1f5
@@ -43,6 +43,7 @@ struct cert_auth_info {
ced1f5
     char *token_name;
ced1f5
     char *module_name;
ced1f5
     char *key_id;
ced1f5
+    char *label;
ced1f5
     struct ldb_result *cert_user_objs;
ced1f5
     struct cert_auth_info *prev;
ced1f5
     struct cert_auth_info *next;
ced1f5
@@ -68,6 +69,11 @@ const char *sss_cai_get_key_id(struct cert_auth_info *i)
ced1f5
     return i != NULL ? i->key_id : NULL;
ced1f5
 }
ced1f5
 
ced1f5
+const char *sss_cai_get_label(struct cert_auth_info *i)
ced1f5
+{
ced1f5
+    return i != NULL ? i->label : NULL;
ced1f5
+}
ced1f5
+
ced1f5
 struct cert_auth_info *sss_cai_get_next(struct cert_auth_info *i)
ced1f5
 {
ced1f5
     return i != NULL ? i->next : NULL;
ced1f5
@@ -439,6 +445,31 @@ static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf,
ced1f5
         }
ced1f5
 
ced1f5
         if (pn == p) {
ced1f5
+            DEBUG(SSSDBG_OP_FAILURE,
ced1f5
+                  "Missing label in p11_child response.\n");
ced1f5
+            ret = EINVAL;
ced1f5
+            goto done;
ced1f5
+        }
ced1f5
+
ced1f5
+        cert_auth_info->label = talloc_strndup(cert_auth_info, (char *) p,
ced1f5
+                                               (pn - p));
ced1f5
+        if (cert_auth_info->label == NULL) {
ced1f5
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
ced1f5
+            ret = ENOMEM;
ced1f5
+            goto done;
ced1f5
+        }
ced1f5
+        DEBUG(SSSDBG_TRACE_ALL, "Found label [%s].\n", cert_auth_info->label);
ced1f5
+
ced1f5
+        p = ++pn;
ced1f5
+        pn = memchr(p, '\n', buf_len - (p - buf));
ced1f5
+        if (pn == NULL) {
ced1f5
+            DEBUG(SSSDBG_OP_FAILURE,
ced1f5
+                  "Missing new-line in p11_child response.\n");
ced1f5
+            ret = EINVAL;
ced1f5
+            goto done;
ced1f5
+        }
ced1f5
+
ced1f5
+        if (pn == p) {
ced1f5
             DEBUG(SSSDBG_OP_FAILURE, "Missing cert in p11_child response.\n");
ced1f5
             ret = EINVAL;
ced1f5
             goto done;
ced1f5
@@ -816,7 +847,8 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
ced1f5
     return EOK;
ced1f5
 }
ced1f5
 
ced1f5
-static char *get_cert_prompt(TALLOC_CTX *mem_ctx, const char *cert)
ced1f5
+static char *get_cert_prompt(TALLOC_CTX *mem_ctx,
ced1f5
+                             struct cert_auth_info *cert_info)
ced1f5
 {
ced1f5
     int ret;
ced1f5
     struct sss_certmap_ctx *ctx = NULL;
ced1f5
@@ -839,7 +871,7 @@ static char *get_cert_prompt(TALLOC_CTX *mem_ctx, const char *cert)
ced1f5
         goto done;
ced1f5
     }
ced1f5
 
ced1f5
-    der = sss_base64_decode(mem_ctx, cert, &der_size);
ced1f5
+    der = sss_base64_decode(mem_ctx, sss_cai_get_cert(cert_info), &der_size);
ced1f5
     if (der == NULL) {
ced1f5
         DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n");
ced1f5
         goto done;
ced1f5
@@ -851,7 +883,8 @@ static char *get_cert_prompt(TALLOC_CTX *mem_ctx, const char *cert)
ced1f5
         goto done;
ced1f5
     }
ced1f5
 
ced1f5
-    prompt = talloc_strdup(mem_ctx, filter);
ced1f5
+    prompt = talloc_asprintf(mem_ctx, "%s\n%s", sss_cai_get_label(cert_info),
ced1f5
+                                                filter);
ced1f5
     if (prompt == NULL) {
ced1f5
         DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
ced1f5
     }
ced1f5
@@ -885,7 +918,7 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username,
ced1f5
         username = sysdb_username;
ced1f5
     }
ced1f5
 
ced1f5
-    prompt = get_cert_prompt(mem_ctx, sss_cai_get_cert(cert_info));
ced1f5
+    prompt = get_cert_prompt(mem_ctx, cert_info);
ced1f5
     if (prompt == NULL) {
ced1f5
         DEBUG(SSSDBG_OP_FAILURE, "get_cert_prompt failed.\n");
ced1f5
         return EIO;
ced1f5
diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
ced1f5
index bccf9972dacbb414076904a783772198620fd73c..4752648796ab4c863706780a2f470853cddbcc11 100644
ced1f5
--- a/src/tests/cmocka/test_pam_srv.c
ced1f5
+++ b/src/tests/cmocka/test_pam_srv.c
ced1f5
@@ -53,7 +53,7 @@
ced1f5
 #define TEST_TOKEN_NAME "SSSD Test Token"
ced1f5
 #define TEST_MODULE_NAME "NSS-Internal"
ced1f5
 #define TEST_KEY_ID "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7"
ced1f5
-#define TEST_SUBJECT_DN "CN=ipa-devel.ipa.devel,O=IPA.DEVEL"
ced1f5
+#define TEST_PROMPT "Server-Cert\nCN=ipa-devel.ipa.devel,O=IPA.DEVEL"
ced1f5
 #define TEST_TOKEN_CERT \
ced1f5
 "MIIECTCCAvGgAwIBAgIBCTANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \
ced1f5
 "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \
ced1f5
@@ -79,7 +79,7 @@
ced1f5
 "XyQBwOYRORlnfGyu+Yc9c3E0Wx8Tlznz0lqPR9g="
ced1f5
 
ced1f5
 #define TEST2_KEY_ID "C8D60E009EB195D01A7083EE1D5419251AA87C2C"
ced1f5
-#define TEST2_SUBJECT_DN "CN=IPA RA,O=IPA.DEVEL"
ced1f5
+#define TEST2_PROMPT "ipaCert\nCN=IPA RA,O=IPA.DEVEL"
ced1f5
 #define TEST_TOKEN_2ND_CERT \
ced1f5
 "MIIDazCCAlOgAwIBAgIBBzANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \
ced1f5
 "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \
ced1f5
@@ -837,7 +837,7 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body,
ced1f5
                                 + sizeof(TEST_TOKEN_NAME)
ced1f5
                                 + sizeof(TEST_MODULE_NAME)
ced1f5
                                 + sizeof(TEST_KEY_ID)
ced1f5
-                                + sizeof(TEST_SUBJECT_DN)));
ced1f5
+                                + sizeof(TEST_PROMPT)));
ced1f5
 
ced1f5
     assert_int_equal(*(body + rp + sizeof("pamuser@"TEST_DOM_NAME) - 1), 0);
ced1f5
     assert_string_equal(body + rp, "pamuser@"TEST_DOM_NAME);
ced1f5
@@ -855,9 +855,9 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body,
ced1f5
     assert_string_equal(body + rp, TEST_KEY_ID);
ced1f5
     rp += sizeof(TEST_KEY_ID);
ced1f5
 
ced1f5
-    assert_int_equal(*(body + rp + sizeof(TEST_SUBJECT_DN) - 1), 0);
ced1f5
-    assert_string_equal(body + rp, TEST_SUBJECT_DN);
ced1f5
-    rp += sizeof(TEST_SUBJECT_DN);
ced1f5
+    assert_int_equal(*(body + rp + sizeof(TEST_PROMPT) - 1), 0);
ced1f5
+    assert_string_equal(body + rp, TEST_PROMPT);
ced1f5
+    rp += sizeof(TEST_PROMPT);
ced1f5
 
ced1f5
     assert_int_equal(rp, blen);
ced1f5
     return EOK;
ced1f5
@@ -904,7 +904,7 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen,
ced1f5
                                 + sizeof(TEST_TOKEN_NAME)
ced1f5
                                 + sizeof(TEST_MODULE_NAME)
ced1f5
                                 + sizeof(TEST_KEY_ID)
ced1f5
-                                + sizeof(TEST_SUBJECT_DN)));
ced1f5
+                                + sizeof(TEST_PROMPT)));
ced1f5
 
ced1f5
     assert_int_equal(*(body + rp + strlen(name)), 0);
ced1f5
     assert_string_equal(body + rp, name);
ced1f5
@@ -922,9 +922,9 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen,
ced1f5
     assert_string_equal(body + rp, TEST_KEY_ID);
ced1f5
     rp += sizeof(TEST_KEY_ID);
ced1f5
 
ced1f5
-    assert_int_equal(*(body + rp + sizeof(TEST_SUBJECT_DN) - 1), 0);
ced1f5
-    assert_string_equal(body + rp, TEST_SUBJECT_DN);
ced1f5
-    rp += sizeof(TEST_SUBJECT_DN);
ced1f5
+    assert_int_equal(*(body + rp + sizeof(TEST_PROMPT) - 1), 0);
ced1f5
+    assert_string_equal(body + rp, TEST_PROMPT);
ced1f5
+    rp += sizeof(TEST_PROMPT);
ced1f5
 
ced1f5
     if (name2 != NULL && *name2 != '\0') {
ced1f5
         SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
ced1f5
@@ -935,7 +935,7 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen,
ced1f5
                                     + sizeof(TEST_TOKEN_NAME)
ced1f5
                                     + sizeof(TEST_MODULE_NAME)
ced1f5
                                     + sizeof(TEST2_KEY_ID)
ced1f5
-                                    + sizeof(TEST2_SUBJECT_DN)));
ced1f5
+                                    + sizeof(TEST2_PROMPT)));
ced1f5
 
ced1f5
         assert_int_equal(*(body + rp + strlen(name)), 0);
ced1f5
         assert_string_equal(body + rp, name);
ced1f5
@@ -953,9 +953,9 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen,
ced1f5
         assert_string_equal(body + rp, TEST2_KEY_ID);
ced1f5
         rp += sizeof(TEST2_KEY_ID);
ced1f5
 
ced1f5
-        assert_int_equal(*(body + rp + sizeof(TEST2_SUBJECT_DN) - 1), 0);
ced1f5
-        assert_string_equal(body + rp, TEST2_SUBJECT_DN);
ced1f5
-        rp += sizeof(TEST2_SUBJECT_DN);
ced1f5
+        assert_int_equal(*(body + rp + sizeof(TEST2_PROMPT) - 1), 0);
ced1f5
+        assert_string_equal(body + rp, TEST2_PROMPT);
ced1f5
+        rp += sizeof(TEST2_PROMPT);
ced1f5
     }
ced1f5
 
ced1f5
     assert_int_equal(rp, blen);
ced1f5
-- 
ced1f5
2.13.6
ced1f5