diff options
author | Sumit Bose <sbose@redhat.com> | 2017-02-22 17:58:15 +0100 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2017-02-23 10:15:11 +0100 |
commit | ead25e32c52c8c2f5fd9abd179e9e81de58f9ca3 (patch) | |
tree | db5939116e6d35e6486266c7112c3ff0c81deb80 | |
parent | 82c5971fafe6063a90289ebba08035fc49ae8590 (diff) | |
download | sssd-ead25e32c52c8c2f5fd9abd179e9e81de58f9ca3.tar.gz sssd-ead25e32c52c8c2f5fd9abd179e9e81de58f9ca3.tar.xz sssd-ead25e32c52c8c2f5fd9abd179e9e81de58f9ca3.zip |
p11: return name of PKCS#11 module and key id to pam_sss
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-rw-r--r-- | src/p11_child/p11_child_nss.c | 55 | ||||
-rw-r--r-- | src/responder/pam/pamsrv.h | 6 | ||||
-rw-r--r-- | src/responder/pam/pamsrv_cmd.c | 8 | ||||
-rw-r--r-- | src/responder/pam/pamsrv_p11.c | 86 | ||||
-rw-r--r-- | src/sss_client/pam_message.h | 2 | ||||
-rw-r--r-- | src/sss_client/pam_sss.c | 49 | ||||
-rw-r--r-- | src/tests/cmocka/test_pam_srv.c | 33 |
7 files changed, 221 insertions, 18 deletions
diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c index 84772692e..f165b58e6 100644 --- a/src/p11_child/p11_child_nss.c +++ b/src/p11_child/p11_child_nss.c @@ -72,13 +72,15 @@ 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, struct cert_verify_opts *cert_verify_opts, - char **cert, char **token_name_out) + char **cert, char **token_name_out, char **module_name_out, + char **key_id_out) { int ret; SECStatus rv; NSSInitContext *nss_ctx; SECMODModuleList *mod_list; SECMODModuleList *mod_list_item; + SECMODModule *module; const char *slot_name; const char *token_name; uint32_t flags = NSS_INIT_READONLY @@ -91,6 +93,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, PK11SlotInfo *slot = NULL; CK_SLOT_ID slot_id; SECMODModuleID module_id; + const char *module_name; CERTCertList *cert_list = NULL; CERTCertListNode *cert_list_node; const PK11DefaultArrayEntry friendly_attr = { "Publicly-readable certs", @@ -105,6 +108,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, CERTCertificate *found_cert = NULL; PK11SlotList *list = NULL; PK11SlotListElement *le; + SECItem *key_id = NULL; + char *key_id_str = NULL; nss_ctx = NSS_InitContext(nss_db, "", "", SECMOD_DB, ¶meters, flags); @@ -187,8 +192,11 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, module_id = PK11_GetModuleID(slot); slot_name = PK11_GetSlotName(slot); token_name = PK11_GetTokenName(slot); - DEBUG(SSSDBG_TRACE_ALL, "Found [%s] in slot [%s][%d] of module [%d].\n", - token_name, slot_name, (int) slot_id, (int) module_id); + module = PK11_GetModule(slot); + module_name = module->dllName == NULL ? "NSS-Internal" : module->dllName; + + DEBUG(SSSDBG_TRACE_ALL, "Found [%s] in slot [%s][%d] of module [%d][%s].\n", + token_name, slot_name, (int) slot_id, (int) module_id, module_name); if (PK11_IsFriendly(slot)) { DEBUG(SSSDBG_TRACE_ALL, "Token is friendly.\n"); @@ -346,6 +354,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, DEBUG(SSSDBG_TRACE_ALL, "No certificate found.\n"); *cert = NULL; *token_name_out = NULL; + *module_name_out = NULL; ret = EOK; goto done; } @@ -412,6 +421,30 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, "Certificate verified and validated.\n"); } + key_id = PK11_GetLowLevelKeyIDForCert(slot, found_cert, NULL); + if (key_id == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "PK11_GetLowLevelKeyIDForCert failed [%d].\n", + PR_GetError()); + ret = EINVAL; + goto done; + } + + key_id_str = CERT_Hexify(key_id, PR_FALSE); + if (key_id_str == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d].\n", PR_GetError()); + ret = ENOMEM; + goto done; + } + + DEBUG(SSSDBG_TRACE_ALL, "Found certificate has key id [%s].\n", key_id_str); + + *key_id_out = talloc_strdup(mem_ctx, key_id_str); + if (*key_id_out == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy key id.\n"); + ret = ENOMEM; + goto done; + } + *cert = sss_base64_encode(mem_ctx, found_cert->derCert.data, found_cert->derCert.len); if (*cert == NULL) { @@ -427,6 +460,13 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, goto done; } + *module_name_out = talloc_strdup(mem_ctx, module_name); + if (*module_name_out == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy module_name_out name.\n"); + ret = ENOMEM; + goto done; + } + ret = EOK; done: @@ -438,6 +478,9 @@ done: CERT_DestroyCertList(cert_list); } + SECITEM_FreeItem(key_id, PR_TRUE); + PORT_Free(key_id_str); + PORT_Free(signed_random_value.data); rv = NSS_ShutdownContext(nss_ctx); @@ -502,6 +545,8 @@ int main(int argc, const char *argv[]) char *pin = NULL; char *slot_name_in = NULL; char *token_name_out = NULL; + char *module_name_out = NULL; + char *key_id_out = NULL; char *nss_db = NULL; struct cert_verify_opts *cert_verify_opts; char *verify_opts = NULL; @@ -665,7 +710,7 @@ int main(int argc, const char *argv[]) } ret = do_work(main_ctx, nss_db, slot_name_in, mode, pin, cert_verify_opts, - &cert, &token_name_out); + &cert, &token_name_out, &module_name_out, &key_id_out); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "do_work failed.\n"); goto fail; @@ -673,6 +718,8 @@ int main(int argc, const char *argv[]) if (cert != NULL) { fprintf(stdout, "%s\n", token_name_out); + fprintf(stdout, "%s\n", module_name_out); + fprintf(stdout, "%s\n", key_id_out); fprintf(stdout, "%s\n", cert); } diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h index 389888eca..7860a99a8 100644 --- a/src/responder/pam/pamsrv.h +++ b/src/responder/pam/pamsrv.h @@ -92,10 +92,12 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, 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); + char **cert, char **token_name, char **module_name, + char **key_id); errno_t add_pam_cert_response(struct pam_data *pd, const char *user, - const char *token_name); + const char *token_name, const char *module_name, + const char *key_id); bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd); diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index 529c74f70..6b7a9493b 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -1401,7 +1401,9 @@ static void pam_forwarder_cert_cb(struct tevent_req *req) struct pam_ctx *pctx = talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx); - ret = pam_check_cert_recv(req, preq, &cert, &preq->token_name); + ret = pam_check_cert_recv(req, preq, &cert, &preq->token_name, + &preq->module_name, + &preq->key_id); talloc_free(req); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "get_cert request failed.\n"); @@ -2051,7 +2053,9 @@ static void pam_dom_forwarder(struct pam_auth_req *preq) } ret = add_pam_cert_response(preq->pd, cert_user, - preq->token_name); + preq->token_name, + preq->module_name, + preq->key_id); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n"); preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL; diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c index 570bfe09d..365300b90 100644 --- a/src/responder/pam/pamsrv_p11.c +++ b/src/responder/pam/pamsrv_p11.c @@ -133,7 +133,8 @@ static errno_t get_p11_child_write_buffer(TALLOC_CTX *mem_ctx, static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, ssize_t buf_len, char **_cert, - char **_token_name) + char **_token_name, char **_module_name, + char **_key_id) { int ret; TALLOC_CTX *tmp_ctx = NULL; @@ -141,6 +142,8 @@ static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, uint8_t *pn; char *cert = NULL; char *token_name = NULL; + char *module_name = NULL; + char *key_id = NULL; if (buf_len < 0) { DEBUG(SSSDBG_CRIT_FAILURE, @@ -187,6 +190,54 @@ static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, } if (pn == p) { + DEBUG(SSSDBG_OP_FAILURE, + "Missing module name in p11_child response.\n"); + ret = EINVAL; + goto done; + } + + module_name = talloc_strndup(tmp_ctx, (char *) p, (pn - p)); + if (module_name == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); + ret = ENOMEM; + goto done; + } + DEBUG(SSSDBG_TRACE_ALL, "Found module name [%s].\n", module_name); + + p = ++pn; + pn = memchr(p, '\n', buf_len - (p - buf)); + if (pn == NULL) { + DEBUG(SSSDBG_OP_FAILURE, + "Missing new-line in p11_child response.\n"); + ret = EINVAL; + goto done; + } + + if (pn == p) { + DEBUG(SSSDBG_OP_FAILURE, + "Missing key id in p11_child response.\n"); + ret = EINVAL; + goto done; + } + + key_id = talloc_strndup(tmp_ctx, (char *) p, (pn - p)); + if (key_id == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); + ret = ENOMEM; + goto done; + } + DEBUG(SSSDBG_TRACE_ALL, "Found key id [%s].\n", key_id); + + p = pn + 1; + pn = memchr(p, '\n', buf_len - (p - buf)); + if (pn == NULL) { + DEBUG(SSSDBG_OP_FAILURE, + "Missing new-line in p11_child response.\n"); + ret = EINVAL; + goto done; + } + + if (pn == p) { DEBUG(SSSDBG_OP_FAILURE, "Missing cert in p11_child response.\n"); ret = EINVAL; goto done; @@ -206,6 +257,8 @@ done: if (ret == EOK) { *_token_name = talloc_steal(mem_ctx, token_name); *_cert = talloc_steal(mem_ctx, cert); + *_module_name = talloc_steal(mem_ctx, module_name); + *_key_id = talloc_steal(mem_ctx, key_id); } talloc_free(tmp_ctx); @@ -222,6 +275,8 @@ struct pam_check_cert_state { struct child_io_fds *io; char *cert; char *token_name; + char *module_name; + char *key_id; }; static void p11_child_write_done(struct tevent_req *subreq); @@ -296,6 +351,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, state->child_status = EFAULT; state->cert = NULL; state->token_name = NULL; + state->module_name = NULL; state->io = talloc(state, struct child_io_fds); if (state->io == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n"); @@ -459,7 +515,8 @@ static void p11_child_done(struct tevent_req *subreq) PIPE_FD_CLOSE(state->io->read_from_child_fd); ret = parse_p11_child_response(state, buf, buf_len, &state->cert, - &state->token_name); + &state->token_name, &state->module_name, + &state->key_id); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "parse_p11_child_respose failed.\n"); tevent_req_error(req, ret); @@ -486,7 +543,8 @@ static void p11_child_timeout(struct tevent_context *ev, } errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - char **cert, char **token_name) + char **cert, char **token_name, char **module_name, + char **key_id) { struct pam_check_cert_state *state = tevent_req_data(req, struct pam_check_cert_state); @@ -501,6 +559,14 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, *token_name = talloc_steal(mem_ctx, state->token_name); } + if (module_name != NULL) { + *module_name = talloc_steal(mem_ctx, state->module_name); + } + + if (key_id != NULL) { + *key_id = talloc_steal(mem_ctx, state->key_id); + } + return EOK; } @@ -513,23 +579,29 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, #define PKCS11_LOGIN_TOKEN_ENV_NAME "PKCS11_LOGIN_TOKEN_NAME" errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, - const char *token_name) + const char *token_name, const char *module_name, + const char *key_id) { uint8_t *msg = NULL; char *env = NULL; size_t user_len; size_t msg_len; size_t slot_len; + size_t module_len; + size_t key_id_len; int ret; - if (sysdb_username == NULL || token_name == NULL) { + if (sysdb_username == NULL || token_name == NULL || module_name == NULL + || key_id == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Missing mandatory user or slot name.\n"); return EINVAL; } user_len = strlen(sysdb_username) + 1; slot_len = strlen(token_name) + 1; - msg_len = user_len + slot_len; + module_len = strlen(module_name) + 1; + key_id_len = strlen(key_id) + 1; + msg_len = user_len + slot_len + module_len + key_id_len; msg = talloc_zero_size(pd, msg_len); if (msg == NULL) { @@ -546,6 +618,8 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, * being I think using sysdb_username is fine. */ memcpy(msg, sysdb_username, user_len); memcpy(msg + user_len, token_name, slot_len); + memcpy(msg + user_len + slot_len, module_name, module_len); + memcpy(msg + user_len + slot_len + module_len, key_id, key_id_len); ret = pam_add_response(pd, SSS_PAM_CERT_INFO, msg_len, msg); talloc_free(msg); diff --git a/src/sss_client/pam_message.h b/src/sss_client/pam_message.h index 34889e074..3f4a770ac 100644 --- a/src/sss_client/pam_message.h +++ b/src/sss_client/pam_message.h @@ -61,6 +61,8 @@ struct pam_items { char *cert_user; char *token_name; + char *module_name; + char *key_id; }; int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer); diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c index 8f97af77e..fa30889e7 100644 --- a/src/sss_client/pam_sss.c +++ b/src/sss_client/pam_sss.c @@ -162,6 +162,12 @@ static void overwrite_and_free_pam_items(struct pam_items *pi) free(pi->token_name); pi->token_name = NULL; + + free(pi->module_name); + pi->module_name = NULL; + + free(pi->key_id); + pi->key_id = NULL; } static int null_strcmp(const char *s1, const char *s2) { @@ -1019,10 +1025,47 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, pi->token_name = strdup((char *) &buf[p + offset]); if (pi->token_name == NULL) { D(("strdup failed")); + free(pi->cert_user); + pi->cert_user = NULL; + break; + } + + offset += strlen(pi->token_name) + 1; + if (offset >= len) { + D(("Cert message size mismatch")); + free(pi->cert_user); + pi->cert_user = NULL; + free(pi->token_name); + pi->token_name = NULL; + break; + } + free(pi->module_name); + pi->module_name = strdup((char *) &buf[p + offset]); + if (pi->module_name == NULL) { + D(("strdup failed")); + break; + } + + offset += strlen(pi->module_name) + 1; + if (offset >= len) { + D(("Cert message size mismatch")); + free(pi->cert_user); + pi->cert_user = NULL; + free(pi->token_name); + pi->token_name = NULL; + free(pi->module_name); + pi->module_name = NULL; + break; + } + free(pi->key_id); + pi->key_id = strdup((char *) &buf[p + offset]); + if (pi->key_id == NULL) { + D(("strdup failed")); break; } - D(("cert user: [%s] token name: [%s]", pi->cert_user, - pi->token_name)); + D(("cert user: [%s] token name: [%s] module: [%s] key id: [%s]", + pi->cert_user, pi->token_name, pi->module_name, + pi->key_id)); break; case SSS_PASSWORD_PROMPTING: D(("Password prompting available.")); @@ -1120,6 +1163,8 @@ static int get_pam_items(pam_handle_t *pamh, uint32_t flags, pi->cert_user = NULL; pi->token_name = NULL; + pi->module_name = NULL; + pi->key_id = NULL; return PAM_SUCCESS; } diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c index 6b91f49c6..cbc1d0367 100644 --- a/src/tests/cmocka/test_pam_srv.c +++ b/src/tests/cmocka/test_pam_srv.c @@ -48,6 +48,8 @@ #define NSS_DB "sql:"NSS_DB_PATH #define TEST_TOKEN_NAME "SSSD Test Token" +#define TEST_MODULE_NAME "NSS-Internal" +#define TEST_KEY_ID "6822EDDD231DAB8DBCD83721BE16A13DD0E31C08" #define TEST_TOKEN_CERT \ "MIIECTCCAvGgAwIBAgIBCDANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNTA2MjMx" \ @@ -668,7 +670,10 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, assert_int_equal(val, SSS_PAM_CERT_INFO); SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); - assert_int_equal(val, (sizeof("pamuser@"TEST_DOM_NAME) + sizeof(TEST_TOKEN_NAME))); + assert_int_equal(val, (sizeof("pamuser@"TEST_DOM_NAME) + + sizeof(TEST_TOKEN_NAME) + + sizeof(TEST_MODULE_NAME) + + sizeof(TEST_KEY_ID))); assert_int_equal(*(body + rp + sizeof("pamuser@"TEST_DOM_NAME) - 1), 0); assert_string_equal(body + rp, "pamuser@"TEST_DOM_NAME); @@ -676,7 +681,17 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, assert_int_equal(*(body + rp + sizeof(TEST_TOKEN_NAME) - 1), 0); assert_string_equal(body + rp, TEST_TOKEN_NAME); + rp += sizeof(TEST_TOKEN_NAME); + assert_int_equal(*(body + rp + sizeof(TEST_MODULE_NAME) - 1), 0); + assert_string_equal(body + rp, TEST_MODULE_NAME); + rp += sizeof(TEST_MODULE_NAME); + + assert_int_equal(*(body + rp + sizeof(TEST_KEY_ID) - 1), 0); + assert_string_equal(body + rp, TEST_KEY_ID); + rp += sizeof(TEST_KEY_ID); + + assert_int_equal(rp, blen); return EOK; } @@ -707,7 +722,10 @@ static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen) assert_int_equal(val, SSS_PAM_CERT_INFO); SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); - assert_int_equal(val, (sizeof("pamuser@"TEST_DOM_NAME) + sizeof(TEST_TOKEN_NAME))); + assert_int_equal(val, (sizeof("pamuser@"TEST_DOM_NAME) + + sizeof(TEST_TOKEN_NAME) + + sizeof(TEST_MODULE_NAME) + + sizeof(TEST_KEY_ID))); assert_int_equal(*(body + rp + sizeof("pamuser@"TEST_DOM_NAME) - 1), 0); assert_string_equal(body + rp, "pamuser@"TEST_DOM_NAME); @@ -715,6 +733,17 @@ static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen) assert_int_equal(*(body + rp + sizeof(TEST_TOKEN_NAME) - 1), 0); assert_string_equal(body + rp, TEST_TOKEN_NAME); + rp += sizeof(TEST_TOKEN_NAME); + + assert_int_equal(*(body + rp + sizeof(TEST_MODULE_NAME) - 1), 0); + assert_string_equal(body + rp, TEST_MODULE_NAME); + rp += sizeof(TEST_MODULE_NAME); + + assert_int_equal(*(body + rp + sizeof(TEST_KEY_ID) - 1), 0); + assert_string_equal(body + rp, TEST_KEY_ID); + rp += sizeof(TEST_KEY_ID); + + assert_int_equal(rp, blen); return EOK; } |