From 2ee54772d5d4f22c3097b8f4dbcfcc20fd95a760 Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Mon, 8 Nov 2010 15:37:34 -0500 Subject: [PATCH 106/150] - initialize a userdb in a temporary directory and use it when we process pkcs12 identities --- src/plugins/preauth/pkinit/pkinit_crypto_nss.c | 133 +++++++++++++++++++++--- 1 files changed, 117 insertions(+), 16 deletions(-) diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c index 82fdbcd..9879e33 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c +++ b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c @@ -76,6 +76,10 @@ /* #define DEBUG_DER "/usr/lib64/nss/unsupported-tools/derdump" */ /* #define DEBUG_SENSITIVE */ +/* Define to do create a temporary on-disk database when we need to import + * PKCS12 identities. */ +#define PKCS12_HACK + /* Forward declaration. */ static krb5_error_code cert_retrieve_cert_sans(krb5_context context, CERTCertificate *cert, @@ -109,6 +113,9 @@ struct _pkinit_identity_crypto_context { SECMODModule **id_modules; /* used for PKCS11: */ PK11SlotInfo **id_userdbs; /* used for NSS: */ PK11SlotInfo *id_p12_slot; /* used for PKCS12: */ +#ifdef PKCS12_HACK + char *id_p12_slot_dir; /* used for PKCS12: */ +#endif PK11GenericObject **id_objects; /* used with FILE: and DIR: */ CERTCertList *id_certs, *ca_certs; CERTCertificate *id_cert; @@ -628,6 +635,101 @@ pkinit_init_identity_crypto(pkinit_identity_crypto_context *id_cryptoctx) return ENOMEM; } +/* Return the slot which we'll use for holding imported PKCS12 certificates + * and keys. Open the module if we need to, first. */ +static PK11SlotInfo * +crypto_get_p12_slot(struct _pkinit_identity_crypto_context *id) +{ + char *configdir, *spec; + if (id->id_p12_slot == NULL) { + configdir = DEFAULT_CONFIGDIR; +#ifdef PKCS12_HACK + while ((spec = tempnam(NULL, "p12")) != NULL) { + if (spec != NULL) { + if (mkdir(spec, S_IRWXU) == 0) { + configdir = spec; + break; + } else { + free(spec); + if (errno != EEXIST) { + break; + } + } + } + } +#endif + spec = PORT_ArenaZAlloc(id->pool, + strlen("configDir='' flags=readOnly") + + strlen(configdir) + 1); + if (spec != NULL) { + if (strcmp(configdir, DEFAULT_CONFIGDIR) != 0) { + sprintf(spec, "configDir='%s'", configdir); + } else { + sprintf(spec, "configDir='%s' flags=readOnly", + configdir); + } + id->id_p12_slot = SECMOD_OpenUserDB(spec); + } +#ifdef PKCS12_HACK + if ((strcmp(configdir, DEFAULT_CONFIGDIR) != 0) && + (id->id_p12_slot != NULL)) { + id->id_p12_slot_dir = PORT_ArenaZAlloc(id->pool, + strlen(configdir) + 1); + if (id->id_p12_slot_dir != NULL) { + strcpy(id->id_p12_slot_dir, configdir); + } + free(configdir); + if (PK11_NeedUserInit(id->id_p12_slot)) { + PK11_InitPin(id->id_p12_slot, "", ""); + } + } +#endif + } + return id->id_p12_slot; +} + +/* Close the slot which we've been using for holding imported PKCS12 + * certificates and keys. */ +static int +crypto_close_p12_slot(struct _pkinit_identity_crypto_context *id) +{ + int ret = 0; + SECMOD_CloseUserDB(id->id_p12_slot); +#ifdef PKCS12_HACK + if (id->id_p12_slot_dir != NULL) { + DIR *dir; + struct dirent *ent; + char *path; + pkiDebug("%s: removing %s\n", __FUNCTION__, + id->id_p12_slot_dir); + dir = opendir(id->id_p12_slot_dir); + if (dir == NULL) { + pkiDebug("%s: error removing directory \"%s\": %s\n", + __FUNCTION__, id->id_p12_slot_dir, + strerror(errno)); + } else { + while ((ent = readdir(dir)) != NULL) { + path = PORT_Alloc(strlen(ent->d_name) + + 1 + + strlen(id->id_p12_slot_dir) + + 1); + if (path != NULL) { + sprintf(path, "%s/%s", + id->id_p12_slot_dir, + ent->d_name); + unlink(path); + PORT_Free(path); + } + + } + closedir(dir); + } + ret = rmdir(id->id_p12_slot_dir); + } +#endif + return ret; +} + void pkinit_fini_identity_crypto(pkinit_identity_crypto_context id_cryptoctx) { @@ -646,7 +748,10 @@ pkinit_fini_identity_crypto(pkinit_identity_crypto_context id_cryptoctx) } } if (id_cryptoctx->id_p12_slot != NULL) { - SECMOD_CloseUserDB(id_cryptoctx->id_p12_slot); + 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++) { @@ -2007,19 +2112,6 @@ crypto_get_pem_slot(struct _pkinit_identity_crypto_context *id) return slot; } -/* Return the slot which we'll use for holding imported PKCS12 certificates - * and keys. Open the module if we need to, first. */ -static PK11SlotInfo * -crypto_get_p12_slot(struct _pkinit_identity_crypto_context *id) -{ - if (id->id_p12_slot == NULL) { - id->id_p12_slot = SECMOD_OpenUserDB("configDir='" - DEFAULT_CONFIGDIR - "' flags=readOnly"); - } - return id->id_p12_slot; -} - /* Resolve any ambiguities from having a duplicate nickname in the PKCS12 * bundle and in the database. */ static SECItem * @@ -2107,7 +2199,12 @@ crypto_load_pkcs12(krb5_context context, } pkiDebug("%s: imported PKCS12 bundle \"%s\"\n", __FUNCTION__, name); SEC_PKCS12DecoderFinish(ctx); - return SECSuccess; + if (cert_load_certs_with_keys_from_slot(context, id_cryptoctx, + slot) == 0) { + return SECSuccess; + } else { + return SECFailure; + } } /* Helper to fill out a CK_ATTRIBUTE. */ @@ -2473,7 +2570,7 @@ crypto_load_certdb(krb5_context context, /* Add us to the list and set the new list. */ id_userdbs[i++] = userdb; - id_userdbs[i] = NULL; + id_userdbs[i++] = NULL; id_cryptoctx->id_userdbs = id_userdbs; /* Load the CAs from the database. */ @@ -2697,6 +2794,10 @@ cert_get_ext_by_tag(CERTCertificate *cert, SECOidTag tag) return NULL; } +/* Check for the presence of a particular key usage in the cert's keyUsage + * extension field. If it's not there, NSS makes an educated guess, and we + * trust it here. This may have to be changed to check if keyUsagePresent is + * clear, and then just return both, like the OpenSSL version of this does. */ static unsigned int cert_get_ku_bits(krb5_context context, CERTCertificate *cert) { -- 1.7.6.4