krb5 commit: Add support for PKINIT deferring identity prompts
Greg Hudson
ghudson at MIT.EDU
Thu Jul 18 00:58:54 EDT 2013
https://github.com/krb5/krb5/commit/805cd6078b5970750b979bd97b4b9f6147e1fd0d
commit 805cd6078b5970750b979bd97b4b9f6147e1fd0d
Author: Nalin Dahyabhai <nalin at redhat.com>
Date: Fri Jun 28 17:12:39 2013 -0400
Add support for PKINIT deferring identity prompts
Learn to manage a list of deferred identities, for which we want to
prompt for passwords or PINs, in pkinit_identity_crypto_context
structures, along with their associated token flags. These are opaque
outside of pkinit_crypto_openssl and pkinit_crypto_nss, so both
implementations need to provide wrapper functions that can be called
from elsewhere in the module to populate and query the lists.
ticket: 7680
src/plugins/preauth/pkinit/pkinit.h | 21 ++++
src/plugins/preauth/pkinit/pkinit_crypto.h | 11 ++
src/plugins/preauth/pkinit/pkinit_crypto_nss.c | 40 +++++++
src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 38 +++++++
src/plugins/preauth/pkinit/pkinit_crypto_openssl.h | 2 +
src/plugins/preauth/pkinit/pkinit_identity.c | 114 ++++++++++++++++++++
6 files changed, 226 insertions(+), 0 deletions(-)
diff --git a/src/plugins/preauth/pkinit/pkinit.h b/src/plugins/preauth/pkinit/pkinit.h
index b44dfe7..38a43f5 100644
--- a/src/plugins/preauth/pkinit/pkinit.h
+++ b/src/plugins/preauth/pkinit/pkinit.h
@@ -71,6 +71,7 @@ extern int longhorn; /* XXX Talking to a Longhorn server? */
#define PKINIT_CTX_MAGIC 0x05551212
#define PKINIT_REQ_CTX_MAGIC 0xdeadbeef
+#define PKINIT_DEFERRED_ID_MAGIC 0x3ca20d21
#define PKINIT_DEFAULT_DH_MIN_BITS 2048
#define PKINIT_DH_MIN_CONFIG_BITS 1024
@@ -309,6 +310,26 @@ krb5_error_code pkinit_cert_matching
krb5_principal princ);
/*
+ * Client's list of identities for which it needs PINs or passwords
+ */
+struct _pkinit_deferred_id {
+ int magic;
+ char *identity;
+ unsigned long ck_flags;
+ char *password;
+};
+typedef struct _pkinit_deferred_id *pkinit_deferred_id;
+
+krb5_error_code pkinit_set_deferred_id
+ (pkinit_deferred_id **identities, const char *identity,
+ unsigned long ck_flags, const char *password);
+const char * pkinit_find_deferred_id
+ (pkinit_deferred_id *identities, const char *identity);
+unsigned long pkinit_get_deferred_id_flags
+ (pkinit_deferred_id *identities, const char *identity);
+void pkinit_free_deferred_ids(pkinit_deferred_id *identities);
+
+/*
* initialization and free functions
*/
void init_krb5_pa_pk_as_req(krb5_pa_pk_as_req **in);
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h
index 8c2b006..b483aff 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto.h
+++ b/src/plugins/preauth/pkinit/pkinit_crypto.h
@@ -424,6 +424,17 @@ krb5_error_code create_issuerAndSerial
receives length of encoded kdcPKId */
/*
+ * These functions manipulate the deferred-identities list in the identity
+ * context, which is opaque outside of the crypto-specific bits.
+ */
+const pkinit_deferred_id * crypto_get_deferred_ids
+ (krb5_context context, pkinit_identity_crypto_context id_cryptoctx);
+krb5_error_code crypto_set_deferred_id
+ (krb5_context context,
+ pkinit_identity_crypto_context id_cryptoctx,
+ const char *identity, const char *password);
+
+/*
* process the values from idopts and obtain the cert(s)
* specified by those options, populating the id_cryptoctx.
*/
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c
index ef0e94d..3c6a87d 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c
@@ -149,6 +149,8 @@ struct _pkinit_identity_crypto_context {
krb5_prompter_fct prompter;
void *prompter_data;
} pwcb_args;
+ krb5_boolean defer_id_prompt;
+ pkinit_deferred_id *deferred_ids;
};
struct _pkinit_cert_info { /* aka _pkinit_cert_handle */
@@ -785,6 +787,8 @@ pkinit_fini_identity_crypto(pkinit_identity_crypto_context id_cryptoctx)
pkiDebug("%s\n", __FUNCTION__);
/* The order of cleanup here is intended to ensure that nothing gets
* freed before anything that might have a reference to it. */
+ if (id_cryptoctx->deferred_ids != NULL)
+ pkinit_free_deferred_ids(id_cryptoctx->deferred_ids);
if (id_cryptoctx->id_cert != NULL)
CERT_DestroyCertificate(id_cryptoctx->id_cert);
CERT_DestroyCertList(id_cryptoctx->ca_certs);
@@ -2895,6 +2899,8 @@ crypto_load_certs(krb5_context context,
{
SECStatus status;
+ id_cryptoctx->defer_id_prompt = defer_id_prompts;
+
switch (idopts->idtype) {
case IDTYPE_FILE:
status = crypto_load_files(context,
@@ -5550,3 +5556,37 @@ cms_signeddata_verify(krb5_context context,
return 0;
}
+
+/*
+ * Add an item to the pkinit_identity_crypto_context's list of deferred
+ * identities.
+ */
+krb5_error_code
+crypto_set_deferred_id(krb5_context context,
+ pkinit_identity_crypto_context id_cryptoctx,
+ const char *identity, const char *password)
+{
+ unsigned long ck_flags;
+
+ ck_flags = pkinit_get_deferred_id_flags(id_cryptoctx->deferred_ids,
+ identity);
+ return pkinit_set_deferred_id(&id_cryptoctx->deferred_ids,
+ identity, ck_flags, password);
+}
+
+/*
+ * Retrieve a read-only copy of the pkinit_identity_crypto_context's list of
+ * deferred identities, sure to be valid only until the next time someone calls
+ * either pkinit_set_deferred_id() or crypto_set_deferred_id().
+ */
+const pkinit_deferred_id *
+crypto_get_deferred_ids(krb5_context context,
+ pkinit_identity_crypto_context id_cryptoctx)
+{
+ pkinit_deferred_id *deferred;
+ const pkinit_deferred_id *ret;
+
+ deferred = id_cryptoctx->deferred_ids;
+ ret = (const pkinit_deferred_id *)deferred;
+ return ret;
+}
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index a780e71..1312555 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -510,6 +510,8 @@ pkinit_fini_identity_crypto(pkinit_identity_crypto_context idctx)
return;
pkiDebug("%s: freeing ctx at %p\n", __FUNCTION__, idctx);
+ if (idctx->deferred_ids != NULL)
+ pkinit_free_deferred_ids(idctx->deferred_ids);
free(idctx->identity);
pkinit_fini_certs(idctx);
pkinit_fini_pkcs11(idctx);
@@ -4797,6 +4799,8 @@ crypto_load_certs(krb5_context context,
{
krb5_error_code retval;
+ id_cryptoctx->defer_id_prompt = defer_id_prompts;
+
switch(idopts->idtype) {
case IDTYPE_FILE:
retval = pkinit_get_certs_fs(context, plg_cryptoctx,
@@ -6078,3 +6082,37 @@ pkinit_pkcs11_code_to_text(int err)
snprintf(uc, sizeof(uc), _("unknown code 0x%x"), err);
return (uc);
}
+
+/*
+ * Add an item to the pkinit_identity_crypto_context's list of deferred
+ * identities.
+ */
+krb5_error_code
+crypto_set_deferred_id(krb5_context context,
+ pkinit_identity_crypto_context id_cryptoctx,
+ const char *identity, const char *password)
+{
+ unsigned long flags;
+
+ flags = pkinit_get_deferred_id_flags(id_cryptoctx->deferred_ids,
+ identity);
+ return pkinit_set_deferred_id(&id_cryptoctx->deferred_ids,
+ identity, flags, password);
+}
+
+/*
+ * Retrieve a read-only copy of the pkinit_identity_crypto_context's list of
+ * deferred identities, sure to be valid only until the next time someone calls
+ * either pkinit_set_deferred_id() or crypto_set_deferred_id().
+ */
+const pkinit_deferred_id *
+crypto_get_deferred_ids(krb5_context context,
+ pkinit_identity_crypto_context id_cryptoctx)
+{
+ pkinit_deferred_id *deferred;
+ const pkinit_deferred_id *ret;
+
+ deferred = id_cryptoctx->deferred_ids;
+ ret = (const pkinit_deferred_id *)deferred;
+ return ret;
+}
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h
index 0c14e00..3c73394 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h
@@ -86,6 +86,8 @@ struct _pkinit_identity_crypto_context {
int cert_id_len;
CK_MECHANISM_TYPE mech;
#endif
+ krb5_boolean defer_id_prompt;
+ pkinit_deferred_id *deferred_ids;
};
struct _pkinit_plg_crypto_context {
diff --git a/src/plugins/preauth/pkinit/pkinit_identity.c b/src/plugins/preauth/pkinit/pkinit_identity.c
index a53810c..eb198f4 100644
--- a/src/plugins/preauth/pkinit/pkinit_identity.c
+++ b/src/plugins/preauth/pkinit/pkinit_identity.c
@@ -683,3 +683,117 @@ pkinit_identity_prompt(krb5_context context,
errout:
return retval;
}
+
+/*
+ * Create an entry in the passed-in list for the named identity, optionally
+ * with the specified token flag value and/or supplied password, replacing any
+ * existing entry with the same identity name.
+ */
+krb5_error_code
+pkinit_set_deferred_id(pkinit_deferred_id **identities,
+ const char *identity, unsigned long ck_flags,
+ const char *password)
+{
+ int i;
+ pkinit_deferred_id *out = NULL, *ids;
+ char *tmp;
+
+ /* Search for an entry that's already in the list. */
+ ids = *identities;
+ for (i = 0; ids != NULL && ids[i] != NULL; i++) {
+ if (strcmp(ids[i]->identity, identity) == 0) {
+ /* Replace its password value, then we're done. */
+ tmp = password ? strdup(password) : NULL;
+ if (password != NULL && tmp == NULL)
+ return ENOMEM;
+ ids[i]->ck_flags = ck_flags;
+ free(ids[i]->password);
+ ids[i]->password = tmp;
+ return 0;
+ }
+ }
+
+ /* Resize the list. */
+ out = realloc(ids, sizeof(*ids) * (i + 2));
+ if (out == NULL)
+ goto oom;
+ *identities = out;
+
+ /* Allocate the new final entry. */
+ out[i] = malloc(sizeof(*(out[i])));
+ if (out[i] == NULL)
+ goto oom;
+
+ /* Populate the new entry. */
+ out[i]->magic = PKINIT_DEFERRED_ID_MAGIC;
+ out[i]->identity = strdup(identity);
+ if (out[i]->identity == NULL)
+ goto oom;
+
+ out[i]->ck_flags = ck_flags;
+ out[i]->password = password ? strdup(password) : NULL;
+ if (password != NULL && out[i]->password == NULL)
+ goto oom;
+
+ /* Terminate the list. */
+ out[i + 1] = NULL;
+ return 0;
+
+oom:
+ if (out != NULL && out[i] != NULL) {
+ free(out[i]->identity);
+ free(out[i]);
+ out[i] = NULL;
+ }
+ return ENOMEM;
+}
+
+/*
+ * Return a password which we've associated with the named identity, if we've
+ * stored one. Otherwise return NULL.
+ */
+const char *
+pkinit_find_deferred_id(pkinit_deferred_id *identities,
+ const char *identity)
+{
+ int i;
+
+ for (i = 0; identities != NULL && identities[i] != NULL; i++) {
+ if (strcmp(identities[i]->identity, identity) == 0)
+ return identities[i]->password;
+ }
+ return NULL;
+}
+
+/*
+ * Return the flags associated with the specified identity, or 0 if we don't
+ * have such an identity.
+ */
+unsigned long
+pkinit_get_deferred_id_flags(pkinit_deferred_id *identities,
+ const char *identity)
+{
+ int i;
+
+ for (i = 0; identities != NULL && identities[i] != NULL; i++) {
+ if (strcmp(identities[i]->identity, identity) == 0)
+ return identities[i]->ck_flags;
+ }
+ return 0;
+}
+
+/*
+ * Free a deferred_id list.
+ */
+void
+pkinit_free_deferred_ids(pkinit_deferred_id *identities)
+{
+ int i;
+
+ for (i = 0; identities != NULL && identities[i] != NULL; i++) {
+ free(identities[i]->identity);
+ free(identities[i]->password);
+ free(identities[i]);
+ }
+ free(identities);
+}
More information about the cvs-krb5
mailing list