From 756cbf446d234bf395475bceb785a23a3c7bcba3 Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Wed, 29 Sep 2010 11:39:00 -0400 Subject: [PATCH 019/150] - note the places where we'll have to carry a callback context - add any key/cert pairs that we can read to the identity_context at init-time --- src/plugins/preauth/pkinit/pkinit_crypto_nss.c | 128 +++++++++++++++++++----- 1 files changed, 102 insertions(+), 26 deletions(-) diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c index e0696f5..a2b2966 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c +++ b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c @@ -48,6 +48,7 @@ #include #define CONFIGDIR "/etc/pki/nssdb" +#define NULLCX NULL /* Forward declarations. */ static krb5_error_code cert_retrieve_cert_sans(krb5_context context, @@ -55,6 +56,7 @@ static krb5_error_code cert_retrieve_cert_sans(krb5_context context, krb5_principal **pkinit_sans, krb5_principal **upn_sans, unsigned char ***kdc_hostname); +static int cert_load_default_identity(pkinit_identity_crypto_context id); /* Plugin and request state. */ struct _pkinit_plg_crypto_context { @@ -73,7 +75,8 @@ struct _pkinit_identity_crypto_context { PK11SlotList *slots; PK11SlotInfo *slot; CERTCertList *id_certs, *ca_certs, *other_certs; - CERTCertificate *cert; + SECKEYPrivateKeyList *id_keys; + CERTCertificate *id_cert; krb5_prompter_fct prompter; void *prompter_data; }; @@ -237,11 +240,14 @@ pkinit_init_identity_crypto(pkinit_identity_crypto_context *id_cryptoctx) if (*id_cryptoctx != NULL) { (*id_cryptoctx)->pool = pool; (*id_cryptoctx)->id_certs = CERT_NewCertList(); + (*id_cryptoctx)->id_keys = SECKEY_NewPrivateKeyList(); (*id_cryptoctx)->ca_certs = CERT_NewCertList(); (*id_cryptoctx)->other_certs = CERT_NewCertList(); if (((*id_cryptoctx)->id_certs != NULL) && + ((*id_cryptoctx)->id_keys != NULL) && ((*id_cryptoctx)->ca_certs != NULL) && ((*id_cryptoctx)->other_certs != NULL)) { + cert_load_default_identity(*id_cryptoctx); return 0; } if ((*id_cryptoctx)->other_certs != NULL) { @@ -250,6 +256,9 @@ pkinit_init_identity_crypto(pkinit_identity_crypto_context *id_cryptoctx) if ((*id_cryptoctx)->ca_certs != NULL) { CERT_DestroyCertList((*id_cryptoctx)->ca_certs); } + if ((*id_cryptoctx)->id_keys != NULL) { + SECKEY_DestroyPrivateKeyList((*id_cryptoctx)->id_keys); + } if ((*id_cryptoctx)->id_certs != NULL) { CERT_DestroyCertList((*id_cryptoctx)->id_certs); } @@ -264,6 +273,7 @@ pkinit_fini_identity_crypto(pkinit_identity_crypto_context id_cryptoctx) { CERT_DestroyCertList(id_cryptoctx->other_certs); CERT_DestroyCertList(id_cryptoctx->ca_certs); + SECKEY_DestroyPrivateKeyList(id_cryptoctx->id_keys); CERT_DestroyCertList(id_cryptoctx->id_certs); PORT_FreeArena(id_cryptoctx->pool, PR_TRUE); } @@ -466,7 +476,7 @@ client_create_dh(krb5_context context, dh_param.base = pqg_params->base; /* Generate a public value and a private key. */ - slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN, NULL); + slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN, NULLCX); if (slot == NULL) { PK11_PQG_DestroyParams(pqg_params); PORT_FreeArena(pool, PR_TRUE); @@ -474,7 +484,8 @@ client_create_dh(krb5_context context, } pub = NULL; priv = PK11_GenerateKeyPair(slot, CKM_DH_PKCS_KEY_PAIR_GEN, - &dh_param, &pub, PR_FALSE, PR_FALSE, NULL); + &dh_param, &pub, PR_FALSE, PR_FALSE, + NULLCX); /* Finish building the return values. */ params.p = pqg_params->prime; @@ -558,7 +569,7 @@ client_process_dh(krb5_context context, /* Generate the shared value using our private key and the KDC's * public key. */ - slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN, NULL); + slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN, NULLCX); if (slot == NULL) { SECKEY_DestroyPublicKey(pub); PORT_FreeArena(pool, PR_TRUE); @@ -570,7 +581,7 @@ client_process_dh(krb5_context context, CKM_TLS_MASTER_KEY_DERIVE_DH, CKA_DERIVE, 0, - NULL); + NULLCX); if (sym == NULL) { SECKEY_DestroyPublicKey(pub); PK11_FreeSlot(slot); @@ -698,7 +709,7 @@ server_process_dh(krb5_context context, dh_params.base = params.g; /* Generate a public value and a private key. */ - slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN, NULL); + slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN, NULLCX); if (slot == NULL) { SECKEY_DestroySubjectPublicKeyInfo(spki); PORT_FreeArena(pool, PR_TRUE); @@ -706,7 +717,8 @@ server_process_dh(krb5_context context, } pub = NULL; priv = PK11_GenerateKeyPair(slot, CKM_DH_PKCS_KEY_PAIR_GEN, - &dh_params, &pub, PR_FALSE, PR_FALSE, NULL); + &dh_params, &pub, PR_FALSE, PR_FALSE, + NULLCX); if (priv == NULL) { PK11_FreeSlot(slot); SECKEY_DestroySubjectPublicKeyInfo(spki); @@ -737,7 +749,7 @@ server_process_dh(krb5_context context, CKM_TLS_MASTER_KEY_DERIVE_DH, CKA_DERIVE, 0, - NULL); + NULLCX); if (sym == NULL) { SECKEY_DestroyPrivateKey(priv); SECKEY_DestroyPublicKey(pub); @@ -789,7 +801,7 @@ create_issuerAndSerial(krb5_context context, SECItem item; /* Check if we have selected an identity cert. */ - if (id_cryptoctx->cert == NULL) { + if (id_cryptoctx->id_cert == NULL) { return ENOENT; } @@ -799,9 +811,9 @@ create_issuerAndSerial(krb5_context context, } /* Encode the issuer/serial. */ - isn.issuer = id_cryptoctx->cert->derIssuer; - isn.serial = id_cryptoctx->cert->serialNumber; - if (SEC_ASN1EncodeItem(id_cryptoctx->cert->arena, &item, &isn, + isn.issuer = id_cryptoctx->id_cert->derIssuer; + isn.serial = id_cryptoctx->id_cert->serialNumber; + if (SEC_ASN1EncodeItem(id_cryptoctx->id_cert->arena, &item, &isn, issuer_and_serial_number_template) != &item) { PORT_FreeArena(pool, PR_TRUE); return ENOMEM; @@ -1079,10 +1091,73 @@ crypto_cert_iteration_next(krb5_context context, /* Record that we iterated. */ iter_handle->node = node; (*cert_handle)->id_cryptoctx = iter_handle->id_cryptoctx; - (*cert_handle)->cert = node->cert; + (*cert_handle)->cert = CERT_DupCertificate(node->cert); return 0; } +/* Load all of the certificates in all of the tokens for which we also have + * matching secret keys. */ +static int +cert_load_default_identity(pkinit_identity_crypto_context id) +{ + PK11SlotList *slist; + PK11SlotListElement *sle; + SECKEYPrivateKey *key; + CERTCertList *clist; + CERTCertListNode *cnode; + int status; + + /* Get the list of tokens. All of them. */ + slist = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, + PR_FALSE, NULLCX); + if (slist == NULL) { + return ENOENT; + } + + /* First try logged-in/no-login-necessary slots. */ + status = 0; + for (sle = slist->head; sle != NULL; sle = sle->next) { + /* Skip over slots we don't want to use. */ + if (!PK11_IsLoggedIn(sle->slot, NULLCX) && + PK11_NeedLogin(sle->slot)) { + continue; + } + /* Get the list of certs, and skip the slot if it doesn't have + * any. */ + clist = PK11_ListCertsInSlot(sle->slot); + if (clist == NULL) { + continue; + } + if (CERT_LIST_EMPTY(clist)) { + CERT_DestroyCertList(clist); + continue; + } + /* Walk the list of certs, and for each one for which we can + * find the matching private key, add it and the keys to the + * lists. */ + for (cnode = CERT_LIST_HEAD(clist); + (cnode != NULL) && (cnode->cert != NULL); + cnode = CERT_LIST_NEXT(cnode)) { + key = PK11_FindKeyByAnyCert(cnode->cert, NULLCX); + if (key == NULL) { + continue; + } + if (CERT_AddCertToListTail(id->id_certs, + cnode->cert) != SECSuccess) { + status = ENOMEM; + } + if (SECKEY_AddPrivateKeyToListTail(id->id_keys, + key) != SECSuccess) { + status = ENOMEM; + } + SECKEY_DestroyPrivateKey(key); + } + CERT_DestroyCertList(clist); + } + PK11_FreeSlotList(slist); + return status; +} + /* Read names, key usage, and extended key usage from the cert. */ static SECItem * cert_get_ext_by_tag(CERTCertificate *cert, SECOidTag tag) @@ -1200,21 +1275,19 @@ crypto_cert_get_matching_data(krb5_context context, pkinit_cert_handle cert_handle, pkinit_cert_matching_data **ret_data) { - struct _pkinit_cert_info *cert; pkinit_cert_matching_data *md; - cert = cert_handle; md = malloc(sizeof(*md)); if (md == NULL) { return ENOMEM; } - md->ch = cert; - md->subject_dn = strdup(cert->cert->subjectName); + md->ch = cert_handle; + md->subject_dn = strdup(cert_handle->cert->subjectName); /* FIXME: not RFC2253 */ - md->issuer_dn = strdup(cert->cert->issuerName); + md->issuer_dn = strdup(cert_handle->cert->issuerName); /* FIXME: not RFC2253 */ md->ku_bits = cert_get_ku_bits(context, cert_handle->cert); md->eku_bits = cert_get_eku_bits(context, cert_handle->cert, 0); - if (cert_retrieve_cert_sans(context, cert->cert, + if (cert_retrieve_cert_sans(context, cert_handle->cert, &md->sans, &md->sans, NULL) != 0) { free(md->subject_dn); free(md->issuer_dn); @@ -1225,11 +1298,14 @@ crypto_cert_get_matching_data(krb5_context context, return 0; } -/* Free up "this" "self" certificate and key. */ +/* Free up "this" certificate. */ krb5_error_code crypto_cert_release(krb5_context context, pkinit_cert_handle cert_handle) { - return ENOSYS; + /* Free the contents, but not the handle itself. That's part of a + * pool. */ + CERT_DestroyCertificate(cert_handle->cert); + return 0; } /* Free names, key usage, and extended key usage from the cert matching data @@ -1251,10 +1327,10 @@ crypto_cert_select(krb5_context context, pkinit_cert_matching_data *data) { CERTCertificate *cert; cert = CERT_DupCertificate(data->ch->cert); - if (data->ch->id_cryptoctx->cert != NULL) { - CERT_DestroyCertificate(data->ch->id_cryptoctx->cert); + if (data->ch->id_cryptoctx->id_cert != NULL) { + CERT_DestroyCertificate(data->ch->id_cryptoctx->id_cert); } - data->ch->id_cryptoctx->cert = cert; + data->ch->id_cryptoctx->id_cert = cert; return 0; } @@ -2061,7 +2137,7 @@ cms_signeddata_create(krb5_context context, PLArenaPool *pool; SECItem plain, encoded; - if (id_cryptoctx->cert == NULL) { + if (id_cryptoctx->id_cert == NULL) { return ENOENT; } @@ -2096,7 +2172,7 @@ cms_signeddata_create(krb5_context context, } /* Create a signer and add it to the signed-data pointer. */ - signer = NSS_CMSSignerInfo_Create(msg, id_cryptoctx->cert, + signer = NSS_CMSSignerInfo_Create(msg, id_cryptoctx->id_cert, SEC_OID_SHA1); if (signer == NULL) { PORT_FreeArena(pool, PR_TRUE); -- 1.7.6.4