krb5 commit: Use config storage for client identity selection
Greg Hudson
ghudson at MIT.EDU
Wed Oct 17 15:42:25 EDT 2012
https://github.com/krb5/krb5/commit/5349a2b129cd569d903fe698d2857881d3c05a43
commit 5349a2b129cd569d903fe698d2857881d3c05a43
Author: Nalin Dahyabhai <nalin at redhat.com>
Date: Tue Jul 24 17:49:05 2012 -0400
Use config storage for client identity selection
* Keep track of the names of client identities when we load them.
* Store the client identity we just used when we create or retry a
client request.
* If we read a client identity from the configuration, treat it like the
KDC does: pick the "this is it, there is no other" logic branch.
src/plugins/preauth/pkinit/pkinit.h | 3 +
src/plugins/preauth/pkinit/pkinit_clnt.c | 19 ++-
src/plugins/preauth/pkinit/pkinit_crypto.h | 10 +
src/plugins/preauth/pkinit/pkinit_crypto_nss.c | 290 +++++++++++++++++---
src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 104 +++++++-
src/plugins/preauth/pkinit/pkinit_crypto_openssl.h | 2 +
src/plugins/preauth/pkinit/pkinit_identity.c | 12 +
src/plugins/preauth/pkinit/pkinit_srv.c | 3 +-
8 files changed, 403 insertions(+), 40 deletions(-)
diff --git a/src/plugins/preauth/pkinit/pkinit.h b/src/plugins/preauth/pkinit/pkinit.h
index 62df7ed..5ecc489 100644
--- a/src/plugins/preauth/pkinit/pkinit.h
+++ b/src/plugins/preauth/pkinit/pkinit.h
@@ -226,6 +226,7 @@ struct _pkinit_req_context {
pkinit_req_opts *opts;
pkinit_identity_crypto_context idctx;
pkinit_identity_opts *idopts;
+ int do_identity_matching;
krb5_preauthtype pa_type;
int rfc6112_kdc;
};
@@ -284,6 +285,8 @@ krb5_error_code pkinit_identity_initialize
pkinit_req_crypto_context req_cryptoctx, /* IN */
pkinit_identity_opts *idopts, /* IN */
pkinit_identity_crypto_context id_cryptoctx, /* IN/OUT */
+ krb5_clpreauth_callbacks cb, /* IN/OUT */
+ krb5_clpreauth_rock rock, /* IN/OUT */
int do_matching, /* IN */
krb5_principal princ); /* IN (optional) */
diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
index d70da49..f84012c 100644
--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
+++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
@@ -964,8 +964,11 @@ static void
pkinit_client_profile(krb5_context context,
pkinit_context plgctx,
pkinit_req_context reqctx,
+ krb5_clpreauth_callbacks cb,
+ krb5_clpreauth_rock rock,
const krb5_data *realm)
{
+ const char *configured_identity;
char *eku_string = NULL;
pkiDebug("pkinit_client_profile %p %p %p %p\n",
@@ -1035,6 +1038,16 @@ pkinit_client_profile(krb5_context context,
pkinit_libdefault_strings(context, realm,
KRB5_CONF_PKINIT_IDENTITIES,
&reqctx->idopts->identity_alt);
+ reqctx->do_identity_matching = TRUE;
+
+ /* If we had a primary identity in the stored configuration, pick it up. */
+ configured_identity = cb->get_cc_config(context, rock,
+ "X509_user_identity");
+ if (configured_identity != NULL) {
+ free(reqctx->idopts->identity);
+ reqctx->idopts->identity = strdup(configured_identity);
+ reqctx->do_identity_matching = FALSE;
+ }
}
static krb5_error_code
@@ -1092,12 +1105,14 @@ pkinit_client_process(krb5_context context, krb5_clpreauth_moddata moddata,
}
if (processing_request) {
- pkinit_client_profile(context, plgctx, reqctx,
+ pkinit_client_profile(context, plgctx, reqctx, cb, rock,
&request->server->realm);
pkinit_identity_set_prompter(reqctx->idctx, prompter, prompter_data);
retval = pkinit_identity_initialize(context, plgctx->cryptoctx,
reqctx->cryptoctx, reqctx->idopts,
- reqctx->idctx, 1, request->client);
+ reqctx->idctx, cb, rock,
+ reqctx->do_identity_matching,
+ request->client);
if (retval) {
TRACE_PKINIT_CLIENT_NO_IDENTITY(context);
pkiDebug("pkinit_identity_initialize returned %d (%s)\n",
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h
index a3cecc4..8b4b62b 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto.h
+++ b/src/plugins/preauth/pkinit/pkinit_crypto.h
@@ -231,6 +231,16 @@ krb5_error_code cms_envelopeddata_verify
receives length of signed_data */
/*
+ * This function retrieves the signer's identity, in a form that could
+ * be passed back in to a future invocation of this module as a candidate
+ * client identity location.
+ */
+krb5_error_code crypto_retrieve_signer_identity
+ (krb5_context context, /* IN */
+ pkinit_identity_crypto_context id_cryptoctx, /* IN */
+ const char **identity); /* OUT */
+
+/*
* this function returns SAN information found in the
* received certificate. at least one of pkinit_sans,
* upn_sans, or kdc_hostnames must be non-NULL.
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c
index 59b27b2..7f73fbd 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c
@@ -38,6 +38,7 @@
#include <errno.h>
#include "k5-platform.h"
+#include "k5-buf.h"
#include "k5-utf8.h"
#include "krb5.h"
@@ -96,6 +97,8 @@ static krb5_error_code cert_retrieve_cert_sans(krb5_context context,
krb5_principal **pkinit_sans,
krb5_principal **upn_sans,
unsigned char ***kdc_hostname);
+static void crypto_update_signer_identity(krb5_context,
+ pkinit_identity_crypto_context);
/* DomainParameters: RFC 2459, 7.3.2. */
struct domain_parameters {
@@ -119,11 +122,25 @@ struct _pkinit_req_crypto_context {
struct _pkinit_identity_crypto_context {
PLArenaPool *pool;
+ const char *identity;
SECMODModule *pem_module; /* used for FILE: and DIR: */
- SECMODModule **id_modules; /* used for PKCS11: */
- PK11SlotInfo **id_userdbs; /* used for NSS: */
- PK11SlotInfo *id_p12_slot; /* used for PKCS12: */
- PK11GenericObject **id_objects; /* used with FILE: and DIR: */
+ struct _pkinit_identity_crypto_module {
+ char *name;
+ SECMODModule *module;
+ } **id_modules; /* used for PKCS11: */
+ struct _pkinit_identity_crypto_userdb {
+ char *name;
+ PK11SlotInfo *userdb;
+ } **id_userdbs; /* used for NSS: */
+ struct _pkinit_identity_crypto_p12slot {
+ char *p12name;
+ PK11SlotInfo *slot;
+ } id_p12_slot; /* used for PKCS12: */
+ struct _pkinit_identity_crypto_file {
+ char *name;
+ PK11GenericObject *obj;
+ CERTCertificate *cert;
+ } **id_objects; /* used with FILE: and DIR: */
SECItem **id_crls;
CERTCertList *id_certs, *ca_certs;
CERTCertificate *id_cert;
@@ -681,7 +698,7 @@ crypto_get_p12_slot(struct _pkinit_identity_crypto_context *id)
size_t spec_size;
int attempts;
- if (id->id_p12_slot == NULL) {
+ if (id->id_p12_slot.slot == NULL) {
configdir = DEFAULT_CONFIGDIR;
#ifdef PKCS12_HACK
/* Figure out where to put the temporary userdb. */
@@ -710,7 +727,7 @@ crypto_get_p12_slot(struct _pkinit_identity_crypto_context *id)
else
snprintf(spec, spec_size, "configDir='%s' flags=readOnly",
configdir);
- id->id_p12_slot = SECMOD_OpenUserDB(spec);
+ id->id_p12_slot.slot = SECMOD_OpenUserDB(spec);
}
#ifdef PKCS12_HACK
if (strcmp(configdir, DEFAULT_CONFIGDIR) != 0) {
@@ -718,9 +735,9 @@ crypto_get_p12_slot(struct _pkinit_identity_crypto_context *id)
struct dirent *ent;
char *path;
/* First, initialize the slot. */
- if (id->id_p12_slot != NULL)
- if (PK11_NeedUserInit(id->id_p12_slot))
- PK11_InitPin(id->id_p12_slot, "", "");
+ if (id->id_p12_slot.slot != NULL)
+ if (PK11_NeedUserInit(id->id_p12_slot.slot))
+ PK11_InitPin(id->id_p12_slot.slot, "", "");
/* Scan the directory, deleting all of the contents. */
dir = opendir(configdir);
if (dir == NULL)
@@ -745,7 +762,7 @@ crypto_get_p12_slot(struct _pkinit_identity_crypto_context *id)
}
}
#endif
- return id->id_p12_slot;
+ return id->id_p12_slot.slot;
}
/* Close the slot which we've been using for holding imported PKCS12
@@ -753,7 +770,7 @@ crypto_get_p12_slot(struct _pkinit_identity_crypto_context *id)
static int
crypto_close_p12_slot(struct _pkinit_identity_crypto_context *id)
{
- SECMOD_CloseUserDB(id->id_p12_slot);
+ SECMOD_CloseUserDB(id->id_p12_slot.slot);
return 0;
}
@@ -770,18 +787,21 @@ pkinit_fini_identity_crypto(pkinit_identity_crypto_context id_cryptoctx)
CERT_DestroyCertList(id_cryptoctx->ca_certs);
CERT_DestroyCertList(id_cryptoctx->id_certs);
if (id_cryptoctx->id_objects != NULL)
- for (i = 0; id_cryptoctx->id_objects[i] != NULL; i++)
- PK11_DestroyGenericObjects(id_cryptoctx->id_objects[i]);
- if (id_cryptoctx->id_p12_slot != NULL)
+ for (i = 0; id_cryptoctx->id_objects[i] != NULL; i++) {
+ PK11_DestroyGenericObjects(id_cryptoctx->id_objects[i]->obj);
+ if (id_cryptoctx->id_objects[i]->cert != NULL)
+ CERT_DestroyCertificate(id_cryptoctx->id_objects[i]->cert);
+ }
+ if (id_cryptoctx->id_p12_slot.slot != NULL)
if ((i = crypto_close_p12_slot(id_cryptoctx)) != 0)
pkiDebug("%s: error closing pkcs12 slot: %s\n",
__FUNCTION__, strerror(i));
if (id_cryptoctx->id_userdbs != NULL)
for (i = 0; id_cryptoctx->id_userdbs[i] != NULL; i++)
- SECMOD_CloseUserDB(id_cryptoctx->id_userdbs[i]);
+ SECMOD_CloseUserDB(id_cryptoctx->id_userdbs[i]->userdb);
if (id_cryptoctx->id_modules != NULL)
for (i = 0; id_cryptoctx->id_modules[i] != NULL; i++)
- SECMOD_UnloadUserModule(id_cryptoctx->id_modules[i]);
+ SECMOD_UnloadUserModule(id_cryptoctx->id_modules[i]->module);
if (id_cryptoctx->id_crls != NULL)
for (i = 0; id_cryptoctx->id_crls[i] != NULL; i++)
CERT_UncacheCRL(CERT_GetDefaultCertDB(), id_cryptoctx->id_crls[i]);
@@ -2026,6 +2046,49 @@ cert_load_certs_with_keys_from_slot(krb5_context context,
return status;
}
+static char *
+reassemble_pkcs11_name(PLArenaPool *pool, pkinit_identity_opts *idopts)
+{
+ struct k5buf buf;
+ int n = 0;
+ char *ret;
+
+ krb5int_buf_init_dynamic(&buf);
+ krb5int_buf_add(&buf, "PKCS11:");
+ n = 0;
+ if (idopts->p11_module_name != NULL) {
+ krb5int_buf_add_fmt(&buf, "%smodule_name=%s",
+ n++ ? "," : "",
+ idopts->p11_module_name);
+ }
+ if (idopts->token_label != NULL) {
+ krb5int_buf_add_fmt(&buf, "%stoken=%s",
+ n++ ? "," : "",
+ idopts->token_label);
+ }
+ if (idopts->cert_label != NULL) {
+ krb5int_buf_add_fmt(&buf, "%scertlabel=%s",
+ n++ ? "," : "",
+ idopts->cert_label);
+ }
+ if (idopts->cert_id_string != NULL) {
+ krb5int_buf_add_fmt(&buf, "%scertid=%s",
+ n++ ? "," : "",
+ idopts->cert_id_string);
+ }
+ if (idopts->slotid != PK_NOSLOT) {
+ krb5int_buf_add_fmt(&buf, "%sslotid=%ld",
+ n++ ? "," : "",
+ (long)idopts->slotid);
+ }
+ if (krb5int_buf_len(&buf) >= 0)
+ ret = PORT_ArenaStrdup(pool, krb5int_buf_data(&buf));
+ else
+ ret = NULL;
+ krb5int_free_buf(&buf);
+ return ret;
+}
+
static SECStatus
crypto_load_pkcs11(krb5_context context,
pkinit_plg_crypto_context plg_cryptoctx,
@@ -2033,7 +2096,7 @@ crypto_load_pkcs11(krb5_context context,
pkinit_identity_opts *idopts,
pkinit_identity_crypto_context id_cryptoctx)
{
- SECMODModule **id_modules, *module;
+ struct _pkinit_identity_crypto_module **id_modules, *module;
PK11SlotInfo *slot;
char *spec;
size_t spec_size;
@@ -2063,8 +2126,9 @@ crypto_load_pkcs11(krb5_context context,
if (id_cryptoctx->id_modules != NULL) {
for (i = 0; id_cryptoctx->id_modules[i] != NULL; i++)
continue;
- } else
+ } else {
i = 0;
+ }
/* Allocate a bigger list. */
id_modules = PORT_ArenaZAlloc(id_cryptoctx->pool,
@@ -2073,19 +2137,23 @@ crypto_load_pkcs11(krb5_context context,
id_modules[j] = id_cryptoctx->id_modules[j];
/* Actually load the module. */
- module = SECMOD_LoadUserModule(spec, NULL, PR_FALSE);
- if (module == NULL) {
+ module = PORT_ArenaZAlloc(id_cryptoctx->pool, sizeof(*module));
+ if (module == NULL)
+ return SECFailure;
+ module->name = reassemble_pkcs11_name(id_cryptoctx->pool, idopts);
+ module->module = SECMOD_LoadUserModule(spec, NULL, PR_FALSE);
+ if (module->module == NULL) {
pkiDebug("%s: error loading PKCS11 module \"%s\"",
__FUNCTION__, idopts->p11_module_name);
return SECFailure;
}
- if (!module->loaded) {
+ if (!module->module->loaded) {
pkiDebug("%s: error really loading PKCS11 module \"%s\"",
__FUNCTION__, idopts->p11_module_name);
- SECMOD_UnloadUserModule(module);
+ SECMOD_UnloadUserModule(module->module);
return SECFailure;
}
- SECMOD_UpdateSlotList(module);
+ SECMOD_UpdateSlotList(module->module);
pkiDebug("%s: loaded PKCS11 module \"%s\"\n", __FUNCTION__,
idopts->p11_module_name);
@@ -2097,7 +2165,8 @@ crypto_load_pkcs11(krb5_context context,
/* Walk the list of slots in the module. */
status = SECFailure;
for (i = 0;
- (i < module->slotCount) && ((slot = module->slots[i]) != NULL);
+ (i < module->module->slotCount) &&
+ ((slot = module->module->slots[i]) != NULL);
i++) {
if (idopts->token_label != NULL) {
label = idopts->token_label;
@@ -2246,6 +2315,18 @@ crypto_nickname_c_cb(SECItem *old_nickname, PRBool *cancel, void *arg)
return new_nickname;
}
+static char *
+reassemble_pkcs12_name(PLArenaPool *pool, const char *filename)
+{
+ char *tmp, *ret;
+
+ if (asprintf(&tmp, "PKCS12:%s", filename) < 0)
+ return NULL;
+ ret = PORT_ArenaStrdup(pool, tmp);
+ free(tmp);
+ return ret;
+}
+
static SECStatus
crypto_load_pkcs12(krb5_context context,
pkinit_plg_crypto_context plg_cryptoctx,
@@ -2362,6 +2443,8 @@ crypto_load_pkcs12(krb5_context context,
free(password.data);
return SECFailure;
}
+ id_cryptoctx->id_p12_slot.p12name =
+ reassemble_pkcs12_name(id_cryptoctx->pool, name);
pkiDebug("%s: imported PKCS12 bundle \"%s\"\n", __FUNCTION__, name);
SEC_PKCS12DecoderFinish(ctx);
if (password.data != emptypwd)
@@ -2385,6 +2468,24 @@ crypto_set_attributes(CK_ATTRIBUTE *attr,
attr->ulValueLen = ulValueLen;
}
+static char *
+reassemble_files_name(PLArenaPool *pool, const char *certfile,
+ const char *keyfile)
+{
+ char *tmp, *ret;
+
+ if (keyfile != NULL) {
+ if (asprintf(&tmp, "FILE:%s,%s", certfile, keyfile) < 0)
+ return NULL;
+ } else {
+ if (asprintf(&tmp, "FILE:%s", certfile) < 0)
+ return NULL;
+ }
+ ret = PORT_ArenaStrdup(pool, tmp);
+ free(tmp);
+ return ret;
+}
+
/* Load keys, certs, and/or CRLs from files. */
static SECStatus
crypto_load_files(krb5_context context,
@@ -2397,7 +2498,7 @@ crypto_load_files(krb5_context context,
pkinit_identity_crypto_context id_cryptoctx)
{
PK11SlotInfo *slot;
- PK11GenericObject *obj, **id_objects;
+ struct _pkinit_identity_crypto_file *obj, **id_objects;
PRBool permanent, match;
CERTCertificate *cert;
CERTCertList *before, *after;
@@ -2438,8 +2539,11 @@ crypto_load_files(krb5_context context,
crypto_set_attributes(&attrs[n_attrs++], CKA_LABEL,
(char *) keyfile, strlen(keyfile) + 1);
permanent = PR_FALSE; /* set lifetime to "session" */
- obj = PK11_CreateGenericObject(slot, attrs, n_attrs, permanent);
- if (obj == NULL) {
+ obj = PORT_ArenaZAlloc(id_cryptoctx->pool, sizeof(*obj));
+ if (obj == NULL)
+ return SECFailure;
+ obj->obj = PK11_CreateGenericObject(slot, attrs, n_attrs, permanent);
+ if (obj->obj == NULL) {
pkiDebug("%s: error loading key \"%s\"\n", __FUNCTION__, keyfile);
status = SECFailure;
} else {
@@ -2479,8 +2583,13 @@ crypto_load_files(krb5_context context,
crypto_set_attributes(&attrs[n_attrs++], CKA_TRUST,
&cktrust, sizeof(cktrust));
permanent = PR_FALSE; /* set lifetime to "session" */
- obj = PK11_CreateGenericObject(slot, attrs, n_attrs, permanent);
- if (obj == NULL) {
+ obj = PORT_ArenaZAlloc(id_cryptoctx->pool, sizeof(*obj));
+ if (obj == NULL)
+ return SECFailure;
+ obj->name = reassemble_files_name(id_cryptoctx->pool,
+ certfile, keyfile);
+ obj->obj = PK11_CreateGenericObject(slot, attrs, n_attrs, permanent);
+ if (obj->obj == NULL) {
pkiDebug("%s: error loading %scertificate \"%s\"\n",
__FUNCTION__, cert_mark_trusted ? "CA " : "", certfile);
status = SECFailure;
@@ -2539,6 +2648,7 @@ crypto_load_files(krb5_context context,
(id_cryptoctx->id_certs, cert) != SECSuccess) {
status = SECFailure;
}
+ obj->cert = CERT_DupCertificate(cert);
} else if (cert_mark_trusted) {
/* Add to the CA list. */
if (cert_maybe_add_to_list
@@ -2685,6 +2795,18 @@ crypto_load_dir(krb5_context context,
return status;
}
+static char *
+reassemble_nssdb_name(PLArenaPool *pool, const char *dbdir)
+{
+ char *tmp, *ret;
+
+ if (asprintf(&tmp, "NSS:%s", dbdir) < 0)
+ return NULL;
+ ret = PORT_ArenaStrdup(pool, tmp);
+ free(tmp);
+ return ret;
+}
+
/* Load up a certificate database. */
static krb5_error_code
crypto_load_nssdb(krb5_context context,
@@ -2693,7 +2815,7 @@ crypto_load_nssdb(krb5_context context,
const char *configdir,
pkinit_identity_crypto_context id_cryptoctx)
{
- PK11SlotInfo *userdb, **id_userdbs;
+ struct _pkinit_identity_crypto_userdb *userdb, **id_userdbs;
char *p;
size_t spec_size;
int i, j;
@@ -2732,8 +2854,12 @@ crypto_load_nssdb(krb5_context context,
id_userdbs[j] = id_cryptoctx->id_userdbs[j];
/* Actually load the module. */
- userdb = SECMOD_OpenUserDB(p);
- if (userdb == NULL) {
+ userdb = PORT_ArenaZAlloc(id_cryptoctx->pool, sizeof(*userdb));
+ if (userdb == NULL)
+ return SECFailure;
+ userdb->name = reassemble_nssdb_name(id_cryptoctx->pool, configdir);
+ userdb->userdb = SECMOD_OpenUserDB(p);
+ if (userdb->userdb == NULL) {
pkiDebug("%s: error loading NSS cert database \"%s\"\n",
__FUNCTION__, configdir);
return ENOENT;
@@ -2746,11 +2872,11 @@ crypto_load_nssdb(krb5_context context,
id_cryptoctx->id_userdbs = id_userdbs;
/* Load the CAs from the database. */
- cert_load_ca_certs_from_slot(context, id_cryptoctx, userdb);
+ cert_load_ca_certs_from_slot(context, id_cryptoctx, userdb->userdb);
/* Load the keys from the database. */
return cert_load_certs_with_keys_from_slot(context, id_cryptoctx,
- userdb, NULL, NULL);
+ userdb->userdb, NULL, NULL);
}
/* Load up a certificate and associated key. */
@@ -3082,6 +3208,7 @@ crypto_cert_select(krb5_context context, pkinit_cert_matching_data *data)
if (data->ch->id_cryptoctx->id_cert != NULL)
CERT_DestroyCertificate(data->ch->id_cryptoctx->id_cert);
data->ch->id_cryptoctx->id_cert = cert;
+ crypto_update_signer_identity(context, data->ch->id_cryptoctx);
return 0;
}
@@ -3148,6 +3275,7 @@ crypto_cert_select_default(krb5_context context,
if (id_cryptoctx->id_cert != NULL)
CERT_DestroyCertificate(id_cryptoctx->id_cert);
id_cryptoctx->id_cert = CERT_DupCertificate(cert);
+ crypto_update_signer_identity(context, id_cryptoctx);
return 0;
}
@@ -4081,6 +4209,100 @@ cert_add_kpn(PLArenaPool * pool, krb5_context context, SECItem *name,
return i;
}
+static const char *
+crypto_get_identity_by_slot(krb5_context context,
+ pkinit_identity_crypto_context id_cryptoctx,
+ PK11SlotInfo *slot)
+{
+ PK11SlotInfo *mslot;
+ struct _pkinit_identity_crypto_userdb *userdb;
+ struct _pkinit_identity_crypto_module *module;
+ int i, j;
+
+ mslot = id_cryptoctx->id_p12_slot.slot;
+ if ((mslot != NULL) && (PK11_GetSlotID(mslot) == PK11_GetSlotID(slot)))
+ return id_cryptoctx->id_p12_slot.p12name;
+ for (i = 0;
+ (id_cryptoctx->id_userdbs != NULL) &&
+ (id_cryptoctx->id_userdbs[i] != NULL);
+ i++) {
+ userdb = id_cryptoctx->id_userdbs[i];
+ if (PK11_GetSlotID(userdb->userdb) == PK11_GetSlotID(slot))
+ return userdb->name;
+ }
+ for (i = 0;
+ (id_cryptoctx->id_modules != NULL) &&
+ (id_cryptoctx->id_modules[i] != NULL);
+ i++) {
+ module = id_cryptoctx->id_modules[i];
+ for (j = 0; j < module->module->slotCount; j++) {
+ mslot = module->module->slots[j];
+ if (PK11_GetSlotID(mslot) == PK11_GetSlotID(slot))
+ return module->name;
+ }
+ }
+ return NULL;
+}
+
+static void
+crypto_update_signer_identity(krb5_context context,
+ pkinit_identity_crypto_context id_cryptoctx)
+{
+ PK11SlotList *slist;
+ PK11SlotListElement *sle;
+ CERTCertificate *cert;
+ struct _pkinit_identity_crypto_file *obj;
+ int i;
+
+ id_cryptoctx->identity = NULL;
+ if (id_cryptoctx->id_cert == NULL)
+ return;
+ cert = id_cryptoctx->id_cert;
+ for (i = 0;
+ (id_cryptoctx->id_objects != NULL) &&
+ (id_cryptoctx->id_objects[i] != NULL);
+ i++) {
+ obj = id_cryptoctx->id_objects[i];
+ if ((obj->cert != NULL) && CERT_CompareCerts(obj->cert, cert)) {
+ id_cryptoctx->identity = obj->name;
+ return;
+ }
+ }
+ if (cert->slot != NULL) {
+ id_cryptoctx->identity = crypto_get_identity_by_slot(context,
+ id_cryptoctx,
+ cert->slot);
+ if (id_cryptoctx->identity != NULL)
+ return;
+ }
+ slist = PK11_GetAllSlotsForCert(cert, NULL);
+ if (slist != NULL) {
+ for (sle = PK11_GetFirstSafe(slist);
+ sle != NULL;
+ sle = PK11_GetNextSafe(slist, sle, PR_FALSE)) {
+ id_cryptoctx->identity = crypto_get_identity_by_slot(context,
+ id_cryptoctx,
+ sle->slot);
+ if (id_cryptoctx->identity != NULL) {
+ PK11_FreeSlotList(slist);
+ return;
+ }
+ }
+ PK11_FreeSlotList(slist);
+ }
+}
+
+krb5_error_code
+crypto_retrieve_signer_identity(krb5_context context,
+ pkinit_identity_crypto_context id_cryptoctx,
+ const char **identity)
+{
+ *identity = id_cryptoctx->identity;
+ if (*identity == NULL)
+ return ENOENT;
+ return 0;
+}
+
static krb5_error_code
cert_retrieve_cert_sans(krb5_context context,
CERTCertificate *cert,
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index b8c95e8..dfb45c1 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -39,6 +39,7 @@
#include <arpa/inet.h>
#include "k5-platform.h"
+#include "k5-buf.h"
#include "pkinit_crypto_openssl.h"
@@ -479,6 +480,8 @@ pkinit_init_identity_crypto(pkinit_identity_crypto_context *idctx)
goto out;
memset(ctx, 0, sizeof(*ctx));
+ ctx->identity = NULL;
+
retval = pkinit_init_certs(ctx);
if (retval)
goto out;
@@ -506,6 +509,7 @@ pkinit_fini_identity_crypto(pkinit_identity_crypto_context idctx)
return;
pkiDebug("%s: freeing ctx at %p\n", __FUNCTION__, idctx);
+ free(idctx->identity);
pkinit_fini_certs(idctx);
pkinit_fini_pkcs11(idctx);
free(idctx);
@@ -2138,6 +2142,17 @@ cleanup:
}
krb5_error_code
+crypto_retrieve_signer_identity(krb5_context context,
+ pkinit_identity_crypto_context id_cryptoctx,
+ const char **identity)
+{
+ *identity = id_cryptoctx->identity;
+ if (*identity == NULL)
+ return ENOENT;
+ return 0;
+}
+
+krb5_error_code
crypto_retrieve_cert_sans(krb5_context context,
pkinit_plg_crypto_context plgctx,
pkinit_req_crypto_context reqctx,
@@ -3776,7 +3791,7 @@ pkinit_open_session(krb5_context context,
}
cctx->slotid = slotlist[i];
free(slotlist);
- pkiDebug("open_session: slotid %d (%d of %d)\n", (int) cctx->slotid,
+ pkiDebug("open_session: slotid %d (%lu of %d)\n", (int) cctx->slotid,
i + 1, (int) count);
/* Login if needed */
@@ -4168,6 +4183,16 @@ pkinit_get_kdc_cert(krb5_context context,
return retval;
}
+static char *
+reassemble_pkcs12_name(const char *filename)
+{
+ char *ret;
+
+ if (asprintf(&ret, "PKCS12:%s", filename) < 0)
+ return NULL;
+ return ret;
+}
+
static krb5_error_code
pkinit_get_certs_pkcs12(krb5_context context,
pkinit_plg_crypto_context plg_cryptoctx,
@@ -4255,6 +4280,8 @@ pkinit_get_certs_pkcs12(krb5_context context,
id_cryptoctx->creds[0] = malloc(sizeof(struct _pkinit_cred_info));
if (id_cryptoctx->creds[0] == NULL)
goto cleanup;
+ id_cryptoctx->creds[0]->name =
+ reassemble_pkcs12_name(idopts->cert_filename);
id_cryptoctx->creds[0]->cert = x;
#ifndef WITHOUT_PKCS11
id_cryptoctx->creds[0]->cert_id = NULL;
@@ -4277,6 +4304,21 @@ cleanup:
return retval;
}
+static char *
+reassemble_files_name(const char *certfile, const char *keyfile)
+{
+ char *ret;
+
+ if (keyfile != NULL) {
+ if (asprintf(&ret, "FILE:%s,%s", certfile, keyfile) < 0)
+ return NULL;
+ } else {
+ if (asprintf(&ret, "FILE:%s", certfile) < 0)
+ return NULL;
+ }
+ return ret;
+}
+
static krb5_error_code
pkinit_load_fs_cert_and_key(krb5_context context,
pkinit_identity_crypto_context id_cryptoctx,
@@ -4305,6 +4347,8 @@ pkinit_load_fs_cert_and_key(krb5_context context,
retval = ENOMEM;
goto cleanup;
}
+ id_cryptoctx->creds[cindex]->name = reassemble_files_name(certname,
+ keyname);
id_cryptoctx->creds[cindex]->cert = x;
#ifndef WITHOUT_PKCS11
id_cryptoctx->creds[cindex]->cert_id = NULL;
@@ -4440,6 +4484,49 @@ cleanup:
}
#ifndef WITHOUT_PKCS11
+static char *
+reassemble_pkcs11_name(pkinit_identity_opts *idopts)
+{
+ struct k5buf buf;
+ int n = 0;
+ char *ret;
+
+ krb5int_buf_init_dynamic(&buf);
+ krb5int_buf_add(&buf, "PKCS11:");
+ n = 0;
+ if (idopts->p11_module_name != NULL) {
+ krb5int_buf_add_fmt(&buf, "%smodule_name=%s",
+ n++ ? "," : "",
+ idopts->p11_module_name);
+ }
+ if (idopts->token_label != NULL) {
+ krb5int_buf_add_fmt(&buf, "%stoken=%s",
+ n++ ? "," : "",
+ idopts->token_label);
+ }
+ if (idopts->cert_label != NULL) {
+ krb5int_buf_add_fmt(&buf, "%scertlabel=%s",
+ n++ ? "," : "",
+ idopts->cert_label);
+ }
+ if (idopts->cert_id_string != NULL) {
+ krb5int_buf_add_fmt(&buf, "%scertid=%s",
+ n++ ? "," : "",
+ idopts->cert_id_string);
+ }
+ if (idopts->slotid != PK_NOSLOT) {
+ krb5int_buf_add_fmt(&buf, "%sslotid=%ld",
+ n++ ? "," : "",
+ (long)idopts->slotid);
+ }
+ if (krb5int_buf_len(&buf) >= 0)
+ ret = strdup(krb5int_buf_data(&buf));
+ else
+ ret = NULL;
+ krb5int_free_buf(&buf);
+ return ret;
+}
+
static krb5_error_code
pkinit_get_certs_pkcs11(krb5_context context,
pkinit_plg_crypto_context plg_cryptoctx,
@@ -4497,8 +4584,6 @@ pkinit_get_certs_pkcs11(krb5_context context,
id_cryptoctx->slotid = idopts->slotid;
id_cryptoctx->pkcs11_method = 1;
-
-
if (pkinit_open_session(context, id_cryptoctx)) {
pkiDebug("can't open pkcs11 session\n");
return KRB5KDC_ERR_PREAUTH_FAILED;
@@ -4632,6 +4717,7 @@ pkinit_get_certs_pkcs11(krb5_context context,
id_cryptoctx->creds[i] = malloc(sizeof(struct _pkinit_cred_info));
if (id_cryptoctx->creds[i] == NULL)
return KRB5KDC_ERR_PREAUTH_FAILED;
+ id_cryptoctx->creds[i]->name = reassemble_pkcs11_name(idopts);
id_cryptoctx->creds[i]->cert = x;
id_cryptoctx->creds[i]->key = NULL;
id_cryptoctx->creds[i]->cert_id = cert_id;
@@ -4659,6 +4745,7 @@ free_cred_info(krb5_context context,
#ifndef WITHOUT_PKCS11
free(cred->cert_id);
#endif
+ free(cred->name);
free(cred);
}
}
@@ -5099,6 +5186,12 @@ crypto_cert_select(krb5_context context,
}
cd->idctx->my_certs = sk_X509_new_null();
sk_X509_push(cd->idctx->my_certs, cd->cred->cert);
+ free(cd->idctx->identity);
+ /* hang on to the selected credential name */
+ if (cd->idctx->creds[cd->index]->name != NULL)
+ cd->idctx->identity = strdup(cd->idctx->creds[cd->index]->name);
+ else
+ cd->idctx->identity = NULL;
cd->idctx->creds[cd->index]->cert = NULL; /* Don't free it twice */
cd->idctx->cert_index = 0;
@@ -5150,6 +5243,11 @@ crypto_cert_select_default(krb5_context context,
sk_X509_push(id_cryptoctx->my_certs, id_cryptoctx->creds[0]->cert);
id_cryptoctx->creds[0]->cert = NULL; /* Don't free it twice */
id_cryptoctx->cert_index = 0;
+ /* hang on to the selected credential name */
+ if (id_cryptoctx->creds[0]->name != NULL)
+ id_cryptoctx->identity = strdup(id_cryptoctx->creds[0]->name);
+ else
+ id_cryptoctx->identity = NULL;
if (id_cryptoctx->pkcs11_method != 1) {
id_cryptoctx->my_key = id_cryptoctx->creds[0]->key;
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h
index 2e56203..0c14e00 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h
@@ -51,6 +51,7 @@
#define MAX_CREDS_ALLOWED 20
struct _pkinit_cred_info {
+ char *name;
X509 *cert;
EVP_PKEY *key;
#ifndef WITHOUT_PKCS11
@@ -63,6 +64,7 @@ typedef struct _pkinit_cred_info * pkinit_cred_info;
struct _pkinit_identity_crypto_context {
pkinit_cred_info creds[MAX_CREDS_ALLOWED+1];
STACK_OF(X509) *my_certs; /* available user certs */
+ char *identity; /* identity name for user cert */
int cert_index; /* cert to use out of available certs*/
EVP_PKEY *my_key; /* available user keys if in filesystem */
STACK_OF(X509) *trustedCAs; /* available trusted ca certs */
diff --git a/src/plugins/preauth/pkinit/pkinit_identity.c b/src/plugins/preauth/pkinit/pkinit_identity.c
index cdee841..98c0f00 100644
--- a/src/plugins/preauth/pkinit/pkinit_identity.c
+++ b/src/plugins/preauth/pkinit/pkinit_identity.c
@@ -517,10 +517,13 @@ pkinit_identity_initialize(krb5_context context,
pkinit_req_crypto_context req_cryptoctx,
pkinit_identity_opts *idopts,
pkinit_identity_crypto_context id_cryptoctx,
+ krb5_clpreauth_callbacks cb,
+ krb5_clpreauth_rock rock,
int do_matching,
krb5_principal princ)
{
krb5_error_code retval = EINVAL;
+ const char *signer_identity;
int i;
pkiDebug("%s: %p %p %p\n", __FUNCTION__, context, idopts, id_cryptoctx);
@@ -584,6 +587,15 @@ pkinit_identity_initialize(krb5_context context,
}
}
+ if (rock != NULL && cb != NULL && retval == 0) {
+ /* Save the signer identity if we're the client. */
+ if (crypto_retrieve_signer_identity(context, id_cryptoctx,
+ &signer_identity) == 0) {
+ cb->set_cc_config(context, rock, "X509_user_identity",
+ signer_identity);
+ }
+ }
+
retval = crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
id_cryptoctx);
if (retval)
diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
index 00d4126..dcfda89 100644
--- a/src/plugins/preauth/pkinit/pkinit_srv.c
+++ b/src/plugins/preauth/pkinit/pkinit_srv.c
@@ -1295,7 +1295,8 @@ pkinit_server_plugin_init_realm(krb5_context context, const char *realmname,
goto errout;
retval = pkinit_identity_initialize(context, plgctx->cryptoctx, NULL,
- plgctx->idopts, plgctx->idctx, 0, NULL);
+ plgctx->idopts, plgctx->idctx,
+ NULL, NULL, 0, NULL);
if (retval)
goto errout;
More information about the cvs-krb5
mailing list