From 948348215d3c4fcaff971f0eabb175aff785084f Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Tue, 26 Oct 2010 17:20:42 -0400 Subject: [PATCH 070/150] - rework part of the logic for loading external keys and whatnot --- src/plugins/preauth/pkinit/pkinit_crypto_nss.c | 374 +++++++++++++++++------- 1 files changed, 271 insertions(+), 103 deletions(-) diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c index 19cb93f..e75eba5 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c +++ b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c @@ -32,6 +32,7 @@ */ #include +#include #include #include "k5-int.h" @@ -1689,6 +1690,175 @@ create_krb5_trustedCertifiers(krb5_context context, return 0; } +static SECStatus +crypto_load_pkcs11(krb5_context context, + pkinit_plg_crypto_context plg_cryptoctx, + pkinit_req_crypto_context req_cryptoctx, + const char *spec, + PRBool self, PRBool mark_trusted, PRBool load_crl, + pkinit_identity_crypto_context id_cryptoctx) +{ + SECMODModule **id_modules, *module; + PK11SlotInfo *slot; + CERTCertDBHandle *certdb; + CERTCertificate *cert; + CERTCertList *certs; + CERTCertListNode *node; + CERTCertTrust trust; + SECStatus status; + int i, j; + + if (spec == NULL) { + return SECFailure; + } + certdb = CERT_GetDefaultCertDB(); + /* Count the number of modules we've already loaded. */ + if (id_cryptoctx->id_modules != NULL) { + for (i = 0; id_cryptoctx->id_modules[i] != NULL; i++) { + continue; + } + } else { + i = 0; + } + /* Allocate a bigger list. */ + id_modules = PORT_ArenaZAlloc(id_cryptoctx->pool, + sizeof(id_modules[0]) * (i + 2)); + for (j = 0; j < i; j++) { + id_modules[j] = id_cryptoctx->id_modules[i]; + } + /* Actually load the module. */ + module = SECMOD_CreateModule(spec, spec, NULL, NULL); + if (module == NULL) { + pkiDebug("%s: error loading PKCS11 module \"%s\"", + __FUNCTION__, spec); + return SECFailure; + } + /* Add us to the list and set the new list. */ + id_modules[j++] = module; + id_modules[j] = NULL; + id_cryptoctx->id_modules = id_modules; + /* Walk the list of slots in the module. */ + for (i = 0; + (slot = SECMOD_LookupSlot(module->moduleID, i)) != NULL; + i++) { + certs = PK11_ListCertsInSlot(slot); + /* Walk the list of certs in the slot. */ + for (node = CERT_LIST_HEAD(certs); + (node != NULL) && (node->cert != NULL) && + !CERT_LIST_END(node, certs); + node = CERT_LIST_NEXT(node)) { + cert = node->cert; + /* Add the cert to our candidate cert list? */ + if (self) { + cert = CERT_DupCertificate(node->cert); + CERT_AddCertToListTail(id_cryptoctx->id_certs, + cert); + } + /* Mark the cert trusted as a CA? */ + if (mark_trusted) { + status = CERT_GetCertTrust(cert, &trust); + if (status == SECSuccess) { + /* FIXME: set trust = CA trust */ + CERT_ChangeCertTrust(certdb, cert, + &trust); + } + } + } + } + return SECSuccess; +} + +static SECStatus +crypto_load_cert_and_key(krb5_context context, + pkinit_plg_crypto_context plg_cryptoctx, + pkinit_req_crypto_context req_cryptoctx, + const char *certfile, + const char *keyfile, + const char *crlfile, + PRBool cert_self, PRBool cert_mark_trusted, + pkinit_identity_crypto_context id_cryptoctx) +{ + if ((certfile == NULL) && (crlfile == NULL)) { + return SECFailure; + } + return SECFailure; +} + +static SECStatus +crypto_load_dir(krb5_context context, + pkinit_plg_crypto_context plg_cryptoctx, + pkinit_req_crypto_context req_cryptoctx, + const char *dirname, + PRBool cert_self, PRBool cert_mark_trusted, PRBool load_crl, + pkinit_identity_crypto_context id_cryptoctx) +{ + SECStatus status; + DIR *dir; + struct dirent *ent; + char *key, *certcrl; + const char *suffix = load_crl ? ".crl" : ".crt"; + int i; + + if (dirname == NULL) { + return SECFailure; + } + dir = opendir(dirname); + if (dir == NULL) { + pkiDebug("%s: error loading directory \"%s\": %s\n", + __FUNCTION__, dirname, strerror(errno)); + return SECFailure; + } + status = SECFailure; + while ((ent = readdir(dir)) != NULL) { + pkiDebug("%s: scanning directory \"%s\"\n", + __FUNCTION__, dirname); + i = strlen(ent->d_name); + /* Skip over anything that isn't named ".crt". */ + if ((i < 5) || (strcmp(ent->d_name + i - 4, suffix) != 0)) { + pkiDebug("%s: skipping candidate \"%s/%s\"\n", + __FUNCTION__, dirname, ent->d_name); + continue; + } + /* Construct full path to the file. */ + certcrl = PORT_Alloc(strlen(dirname) + 1 + i + 1); + if (certcrl == NULL) { + continue; + } + sprintf(certcrl, "%s/%s", dirname, ent->d_name); + if (load_crl) { + /* No key. */ + key = NULL; + } else { + /* Construct the matching key name. */ + key = PORT_Alloc(strlen(dirname) + 1 + i + 1); + if (key == NULL) { + PORT_Free(certcrl); + continue; + } + sprintf(key, "%s/%s", dirname, ent->d_name); + i = strlen(key); + strcpy(key + i - 4, ".key"); + } + /* Try loading the key and file as a pair. */ + if (crypto_load_cert_and_key(context, + plg_cryptoctx, + req_cryptoctx, + load_crl ? NULL : certcrl, + key, + load_crl ? certcrl : NULL, + cert_self, cert_mark_trusted, + id_cryptoctx) == SECSuccess) { + status = SECSuccess; + } + PORT_Free(certcrl); + if (!load_crl) { + PORT_Free(key); + } + } + closedir(dir); + return status; +} + /* Load up a certificate and associated key. */ krb5_error_code crypto_load_certs(krb5_context context, @@ -1698,46 +1868,54 @@ crypto_load_certs(krb5_context context, pkinit_identity_crypto_context id_cryptoctx, krb5_principal princ) { - SECMODModule *module, **id_modules; CERTCertDBHandle *certdb; - int i, j; + SECStatus status; certdb = CERT_GetDefaultCertDB(); switch (idopts->idtype) { case IDTYPE_FILE: - return 0; /* FIXME */ - return ENOSYS; + status = crypto_load_cert_and_key(context, + plg_cryptoctx, + req_cryptoctx, + idopts->cert_filename, + idopts->key_filename, + NULL, + PR_TRUE, PR_FALSE, + id_cryptoctx); + if (status != SECSuccess) { + pkiDebug("%s: error loading files \"%s\" and \"%s\"\n", + __FUNCTION__, idopts->cert_filename, + idopts->key_filename); + return ENOMEM; + } + return 0; break; case IDTYPE_DIR: - return 0; /* FIXME */ - return ENOSYS; + status = crypto_load_dir(context, + plg_cryptoctx, + req_cryptoctx, + idopts->cert_filename, + PR_TRUE, PR_FALSE, PR_FALSE, + id_cryptoctx); + if (status != SECSuccess) { + pkiDebug("%s: error loading directory \"%s\"\n", + __FUNCTION__, idopts->cert_filename); + return ENOMEM; + } + return 0; break; case IDTYPE_PKCS11: - if (id_cryptoctx->id_modules != NULL) { - for (i = 0; id_cryptoctx->id_modules[i] != NULL; i++) { - continue; - } - } else { - i = 0; - } - id_modules = PORT_ArenaZAlloc(id_cryptoctx->pool, - sizeof(id_modules[0]) * (i + 2)); - for (j = 0; j < i; j++) { - id_modules[j] = id_cryptoctx->id_modules[i]; - } - module = SECMOD_CreateModule(idopts->p11_module_name, - idopts->p11_module_name, - NULL, - NULL); - if (module == NULL) { - pkiDebug("%s: error loading PKCS11 module \"%s\"", + status = crypto_load_pkcs11(context, + plg_cryptoctx, + req_cryptoctx, + idopts->p11_module_name, + PR_TRUE, PR_FALSE, PR_FALSE, + id_cryptoctx); + if (status != SECSuccess) { + pkiDebug("%s: error loading module \"%s\"\n", __FUNCTION__, idopts->p11_module_name); + return ENOMEM; } - id_modules[j++] = module; - id_modules[j] = NULL; - id_cryptoctx->id_modules = id_modules; - /* FIXME add certs and private keys from the module's slots to - * the lists we keep in the identity context */ return 0; break; case IDTYPE_PKCS12: @@ -2223,78 +2401,82 @@ crypto_load_cas_and_crls(krb5_context context, pkinit_identity_crypto_context id_cryptoctx, int idtype, int catype, char *id) { - SECMODModule *module, **id_modules; - PK11SlotInfo *slot; CERTCertDBHandle *certdb; - CERTCertificate *cert; - CERTCertList *certs; - CERTCertListNode *node; - CERTCertTrust trust; SECStatus status; - int i, j; + PRBool cert_self, cert_mark_trusted, load_crl; certdb = CERT_GetDefaultCertDB(); + + /* Figure out what we're doing here. */ + switch (catype) { + case CATYPE_ANCHORS: + /* Mark certs we load as trusted roots. */ + cert_self = PR_FALSE; + cert_mark_trusted = PR_TRUE; + load_crl = PR_FALSE; + break; + case CATYPE_INTERMEDIATES: + /* Hang on to certs as reference material. */ + cert_self = PR_FALSE; + cert_mark_trusted = PR_FALSE; + load_crl = PR_FALSE; + break; + case CATYPE_CRLS: + /* Load CRLs. */ + cert_self = PR_FALSE; + cert_mark_trusted = PR_FALSE; + load_crl = PR_TRUE; + break; + default: + return ENOSYS; + break; + } + switch (idtype) { case IDTYPE_FILE: - return 0; /* FIXME */ - return ENOSYS; + status = crypto_load_cert_and_key(context, + plg_cryptoctx, + req_cryptoctx, + load_crl ? NULL : id, + NULL, + load_crl ? id : NULL, + cert_self, cert_mark_trusted, + id_cryptoctx); + if (status != SECSuccess) { + pkiDebug("%s: error loading CA file \"%s\"\n", + __FUNCTION__, idopts->cert_filename); + return ENOMEM; + } + return 0; break; case IDTYPE_DIR: - return 0; /* FIXME */ - return ENOSYS; + status = crypto_load_dir(context, + plg_cryptoctx, + req_cryptoctx, + id, + cert_self, cert_mark_trusted, load_crl, + id_cryptoctx); + if (status != SECSuccess) { + pkiDebug("%s: error loading CA directory \"%s\"\n", + __FUNCTION__, idopts->cert_filename); + return ENOMEM; + } + return 0; break; case IDTYPE_PKCS11: - if (id_cryptoctx->id_modules != NULL) { - for (i = 0; id_cryptoctx->id_modules[i] != NULL; i++) { - continue; - } - } else { - i = 0; - } - id_modules = PORT_ArenaZAlloc(id_cryptoctx->pool, - sizeof(id_modules[0]) * (i + 2)); - for (j = 0; j < i; j++) { - id_modules[j] = id_cryptoctx->id_modules[i]; - } - module = SECMOD_CreateModule(idopts->p11_module_name, - idopts->p11_module_name, - NULL, - NULL); - if (module == NULL) { - pkiDebug("%s: error loading PKCS11 module \"%s\"", + status = crypto_load_pkcs11(context, + plg_cryptoctx, + req_cryptoctx, + id ? id : idopts->p11_module_name, + cert_self, + cert_mark_trusted, + load_crl, + id_cryptoctx); + if (status != SECSuccess) { + pkiDebug("%s: error loading module \"%s\"\n", __FUNCTION__, idopts->p11_module_name); + return ENOMEM; } - switch (catype) { - case CATYPE_ANCHORS: - for (i = 0, - slot = SECMOD_LookupSlot(module->moduleID, i); - slot != NULL; - i++, - slot = SECMOD_LookupSlot(module->moduleID, i)) { - certs = PK11_ListCertsInSlot(slot); - for (node = CERT_LIST_HEAD(certs); - (node != NULL) && - (node->cert != NULL) && - !CERT_LIST_END(node, certs); - node = CERT_LIST_NEXT(node)) { - cert = node->cert; - status = CERT_GetCertTrust(cert, - &trust); - if (status == SECSuccess) { - /* FIXME: set trust = CA trust */ - CERT_ChangeCertTrust(certdb, - cert, - &trust); - } - } - } - break; - default: - break; - } - id_modules[j++] = module; - id_modules[j] = NULL; - id_cryptoctx->id_modules = id_modules; return 0; break; case IDTYPE_PKCS12: @@ -2304,20 +2486,6 @@ crypto_load_cas_and_crls(krb5_context context, return EINVAL; break; } - switch (catype) { - case CATYPE_ANCHORS: - return ENOSYS; - break; - case CATYPE_INTERMEDIATES: - return ENOSYS; - break; - case CATYPE_CRLS: - return ENOSYS; - break; - default: - return ENOSYS; - break; - } } /* Retrieve the client's copy of the KDC's certificate. */ -- 1.7.6.4