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