diff options
author | Nalin Dahyabhai <nalin@redhat.com> | 2013-06-28 17:12:39 -0400 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2013-07-17 12:24:20 -0400 |
commit | 805cd6078b5970750b979bd97b4b9f6147e1fd0d (patch) | |
tree | e488a5c8b544bad957367ce8f8a349d4fd19343e /src/plugins | |
parent | 60426439f672fe273ceead17910f818da1954c5b (diff) | |
download | krb5-805cd6078b5970750b979bd97b4b9f6147e1fd0d.tar.gz krb5-805cd6078b5970750b979bd97b4b9f6147e1fd0d.tar.xz krb5-805cd6078b5970750b979bd97b4b9f6147e1fd0d.zip |
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
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit.h | 21 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit_crypto.h | 11 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit_crypto_nss.c | 40 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 38 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit_crypto_openssl.h | 2 | ||||
-rw-r--r-- | 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 b44dfe7b7..38a43f503 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 8c2b0063a..b483affed 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 ef0e94d68..3c6a87d5e 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 a780e7122..1312555b6 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 0c14e0047..3c7339419 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 a53810c5c..eb198f4f7 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); +} |