From: Nalin Dahyabhai Date: Tue, 24 Jul 2012 21:49:05 +0000 (-0400) Subject: Use config storage for client identity selection X-Git-Tag: krb5-1.11-alpha1~27 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5349a2b129cd569d903fe698d2857881d3c05a43;p=thirdparty%2Fkrb5.git 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. --- diff --git a/src/plugins/preauth/pkinit/pkinit.h b/src/plugins/preauth/pkinit/pkinit.h index 62df7edea2..5ecc489728 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 d70da49b1c..f84012cfd9 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 a3cecc4847..8b4b62b6d0 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto.h +++ b/src/plugins/preauth/pkinit/pkinit_crypto.h @@ -230,6 +230,16 @@ krb5_error_code cms_envelopeddata_verify unsigned int *signed_data_len); /* OUT 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, diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c index 59b27b2f72..7f73fbd25a 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c +++ b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c @@ -38,6 +38,7 @@ #include #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 b8c95e8e65..dfb45c1b42 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c @@ -39,6 +39,7 @@ #include #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); @@ -2137,6 +2141,17 @@ cleanup: return retval; } +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, @@ -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 2e56203b13..0c14e0047e 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 cdee8417e1..98c0f0083a 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 00d4126a75..dcfda894bc 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;