From 3da0e186904ad81dd87cf74bfae88270f14bb770 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 21 Aug 2018 17:25:21 -0400 Subject: [PATCH 1/7] Use the correct slot when saving certificates in NSS Certificates were always stored in the NSS certdb. --- src/certsave-n.c | 915 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 474 insertions(+), 441 deletions(-) diff --git a/src/certsave-n.c b/src/certsave-n.c index 8e15a18a..af176ce5 100644 --- a/src/certsave-n.c +++ b/src/certsave-n.c @@ -92,7 +92,11 @@ cm_certsave_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry, SECStatus error; SECItem *item, subject; char *p, *q, *pin; + const char *token; const char *es; + PK11SlotList *slotlist; + PK11SlotListElement *sle; + CK_MECHANISM_TYPE mech; NSSInitContext *ctx; CERTCertDBHandle *certdb; CERTCertList *certlist; @@ -192,231 +196,253 @@ cm_certsave_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry, } _exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR); } - /* Be ready to count our uses of a PIN. */ - memset(&cb_data, 0, sizeof(cb_data)); - cb_data.entry = entry; - cb_data.n_attempts = 0; - pin = NULL; - if (cm_pin_read_for_key(entry, &pin) != 0) { - cm_log(1, "Error reading PIN for key store, " - "failing to save certificate.\n"); + /* Find the tokens that we might use for cert storage. */ + mech = CKM_RSA_X_509; + slotlist = PK11_GetAllTokens(mech, PR_FALSE, PR_FALSE, NULL); + if (slotlist == NULL) { + cm_log(1, "Error getting list of tokens.\n"); PORT_FreeArena(arena, PR_TRUE); - error = NSS_ShutdownContext(ctx); - if (error != SECSuccess) { + if (NSS_ShutdownContext(ctx) != SECSuccess) { cm_log(1, "Error shutting down NSS.\n"); } - _exit(CM_CERTSAVE_STATUS_AUTH); + _exit(2); } - /* Set a PIN if we're supposed to be using one and aren't using - * one yet in this database. */ - if (PK11_NeedUserInit(PK11_GetInternalKeySlot())) { - PK11_InitPin(PK11_GetInternalKeySlot(), NULL, - pin ? pin : ""); - ec = PORT_GetError(); - if (ec != 0) { - es = PR_ErrorToName(ec); + /* Walk the list looking for the requested slot, or the first one if + * none was requested. */ + if (cm_pin_read_for_cert(entry, &pin) != 0) { + cm_log(1, "Error reading PIN for cert db.\n"); + _exit(CM_SUB_STATUS_ERROR_AUTH); + } + PK11_SetPasswordFunc(&cm_pin_read_for_cert_nss_cb); + for (sle = slotlist->head; + ((sle != NULL) && (sle->slot != NULL)); + sle = sle->next) + { + /* Log the slot's name. */ + token = PK11_GetTokenName(sle->slot); + if (token != NULL) { + cm_log(3, "Found token '%s'.\n", token); } else { - es = NULL; + cm_log(3, "Found unnamed token.\n"); } - if (PK11_NeedUserInit(PK11_GetInternalKeySlot())) { - if (es != NULL) { - cm_log(1, "Key storage slot still " - "needs user PIN to be set: " - "%s.\n", es); - } else { - cm_log(1, "Key storage slot still " - "needs user PIN to be set.\n"); - } + /* If we're looking for a specific slot, and this isn't it, + * keep going. */ + if ((entry->cm_cert_token != NULL) && + ((token == NULL) || + (strcmp(entry->cm_cert_token, token) != 0))) { + if (token != NULL) { + cm_log(1, + "Token is named \"%s\", not \"%s\", " + "skipping.\n", + token, entry->cm_cert_token); + } else { + cm_log(1, + "Token is unnamed, not \"%s\", " + "skipping.\n", + entry->cm_cert_token); + } + goto next_slot; + } + /* Be ready to count our uses of a PIN. */ + memset(&cb_data, 0, sizeof(cb_data)); + cb_data.entry = entry; + cb_data.n_attempts = 0; + pin = NULL; + if (cm_pin_read_for_key(entry, &pin) != 0) { + cm_log(1, "Error reading PIN for key store, " + "failing to save certificate.\n"); PORT_FreeArena(arena, PR_TRUE); error = NSS_ShutdownContext(ctx); if (error != SECSuccess) { cm_log(1, "Error shutting down NSS.\n"); } - switch (ec) { - case PR_NO_ACCESS_RIGHTS_ERROR: /* EACCES or EPERM */ - _exit(CM_CERTSAVE_STATUS_PERMS); - break; - default: - _exit(CM_CERTSAVE_STATUS_AUTH); - break; - } + _exit(CM_CERTSAVE_STATUS_AUTH); } - /* We're authenticated now, so count this as a use of - * the PIN. */ - if ((pin != NULL) && (strlen(pin) > 0)) { - cb_data.n_attempts++; - } - } - /* Log in, if case we need to muck around with the key - * database. */ - PK11_SetPasswordFunc(&cm_pin_read_for_key_nss_cb); - error = PK11_Authenticate(PK11_GetInternalKeySlot(), PR_TRUE, - &cb_data); - ec = PORT_GetError(); - if (error != SECSuccess) { - if (ec != 0) { + if (PK11_NeedUserInit(sle->slot)) { + PK11_InitPin(sle->slot, NULL, pin ? pin : ""); + ec = PORT_GetError(); es = PR_ErrorToName(ec); - } else { - es = NULL; - } - if (es != NULL) { - cm_log(1, "Error authenticating to key store: %s.\n", - es); - } else { - cm_log(1, "Error authenticating to key store.\n"); - } - PORT_FreeArena(arena, PR_TRUE); - error = NSS_ShutdownContext(ctx); - if (error != SECSuccess) { - cm_log(1, "Error shutting down NSS.\n"); - } - _exit(CM_CERTSAVE_STATUS_AUTH); - } - if ((pin != NULL) && - (strlen(pin) > 0) && - (cb_data.n_attempts == 0)) { - cm_log(1, "PIN was not needed to auth to key " - "store, though one was provided. " - "Treating this as an error.\n"); - PORT_FreeArena(arena, PR_TRUE); - error = NSS_ShutdownContext(ctx); - if (error != SECSuccess) { - cm_log(1, "Error shutting down NSS.\n"); - } - _exit(CM_CERTSAVE_STATUS_AUTH); - } - certdb = CERT_GetDefaultCertDB(); - if (certdb != NULL) { - /* Strip the header and footer. */ - p = entry->cm_cert; - q = NULL; - if (p != NULL) { - while (strncmp(p, "-----BEGIN ", 11) == 0) { - p += strcspn(p, "\r\n"); - p += strspn(p, "\r\n"); + if (PK11_NeedUserInit(sle->slot)) { + if (es != NULL) { + cm_log(1, "Key storage slot still " + "needs user PIN to be set: " + "%s.\n", es); + } else { + cm_log(1, "Key storage slot still " + "needs user PIN to be set.\n"); + } + PORT_FreeArena(arena, PR_TRUE); + error = NSS_ShutdownContext(ctx); + if (error != SECSuccess) { + cm_log(1, "Error shutting down NSS.\n"); + } + switch (ec) { + case PR_NO_ACCESS_RIGHTS_ERROR: /* EACCES or EPERM */ + _exit(CM_CERTSAVE_STATUS_PERMS); + break; + default: + _exit(CM_CERTSAVE_STATUS_AUTH); + break; + } } - q = strstr(p, "-----END"); + /* count this as use of the PIN */ + cb_data.n_attempts++; } - if ((q == NULL) || (*p == '\0')) { - cm_log(1, "Unable to parse certificate.\n"); - PORT_FreeArena(arena, PR_TRUE); - if (NSS_ShutdownContext(ctx) != SECSuccess) { - cm_log(1, "Error shutting down NSS.\n"); + if (PK11_NeedLogin(sle->slot)) { + error = PK11_Authenticate(sle->slot, PR_TRUE, &cb_data); + if (error != SECSuccess) { + cm_log(1, "Error authenticating to cert db for token " + "%s.\n", token); + goto next_slot; } - _exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR); + cb_data.n_attempts++; } - /* Handle the base64 decode. */ - item = NSSBase64_DecodeBuffer(arena, NULL, p, q - p); - if (item == NULL) { - cm_log(1, "Unable to decode certificate " - "into buffer.\n"); + if ((pin != NULL) && + (strlen(pin) > 0) && + (cb_data.n_attempts == 0)) { + cm_log(1, "PIN was not needed to auth to key " + "store, though one was provided. " + "Treating this as an error.\n"); PORT_FreeArena(arena, PR_TRUE); - if (NSS_ShutdownContext(ctx) != SECSuccess) { + error = NSS_ShutdownContext(ctx); + if (error != SECSuccess) { cm_log(1, "Error shutting down NSS.\n"); } - _exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR); + _exit(CM_CERTSAVE_STATUS_AUTH); } - /* Do a "shallow" decode to pull out the subject name - * so that we can check for a conflict. */ - memset(&csdata, 0, sizeof(csdata)); - if (SEC_ASN1DecodeItem(arena, &csdata, - CERT_SignedDataTemplate, - item) != SECSuccess) { - cm_log(1, "Unable to decode certificate " - "signed data into buffer.\n"); - PORT_FreeArena(arena, PR_TRUE); - if (NSS_ShutdownContext(ctx) != SECSuccess) { - cm_log(1, "Error shutting down NSS.\n"); + certdb = CERT_GetDefaultCertDB(); + if (certdb != NULL) { + /* Strip the header and footer. */ + p = entry->cm_cert; + q = NULL; + if (p != NULL) { + while (strncmp(p, "-----BEGIN ", 11) == 0) { + p += strcspn(p, "\r\n"); + p += strspn(p, "\r\n"); + } + q = strstr(p, "-----END"); } - _exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR); - } - memset(&cert, 0, sizeof(cert)); - if (SEC_ASN1DecodeItem(arena, &cert, - CERT_CertificateTemplate, - &csdata.data) != SECSuccess) { - cm_log(1, "Unable to decode certificate " - "data into buffer.\n"); - PORT_FreeArena(arena, PR_TRUE); - if (NSS_ShutdownContext(ctx) != SECSuccess) { - cm_log(1, "Error shutting down NSS.\n"); + if ((q == NULL) || (*p == '\0')) { + cm_log(1, "Unable to parse certificate.\n"); + PORT_FreeArena(arena, PR_TRUE); + if (NSS_ShutdownContext(ctx) != SECSuccess) { + cm_log(1, "Error shutting down NSS.\n"); + } + _exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR); } - _exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR); - } - subject = cert.derSubject; - /* Ask NSS if there would be a conflict. */ - have_trust = PR_FALSE; - if (SEC_CertNicknameConflict(entry->cm_cert_nickname, - &subject, - certdb)) { - /* Delete the certificate that's already there - * with the nickname we want, otherwise our - * cert with a different subject name will be - * discarded. */ - certlist = PK11_FindCertsFromNickname(entry->cm_cert_nickname, - NULL); + /* Handle the base64 decode. */ + item = NSSBase64_DecodeBuffer(arena, NULL, p, q - p); + if (item == NULL) { + cm_log(1, "Unable to decode certificate " + "into buffer.\n"); + PORT_FreeArena(arena, PR_TRUE); + if (NSS_ShutdownContext(ctx) != SECSuccess) { + cm_log(1, "Error shutting down NSS.\n"); + } + _exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR); + } + /* Do a "shallow" decode to pull out the subject name + * so that we can check for a conflict. */ + memset(&csdata, 0, sizeof(csdata)); + if (SEC_ASN1DecodeItem(arena, &csdata, + CERT_SignedDataTemplate, + item) != SECSuccess) { + cm_log(1, "Unable to decode certificate " + "signed data into buffer.\n"); + PORT_FreeArena(arena, PR_TRUE); + if (NSS_ShutdownContext(ctx) != SECSuccess) { + cm_log(1, "Error shutting down NSS.\n"); + } + _exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR); + } + memset(&cert, 0, sizeof(cert)); + if (SEC_ASN1DecodeItem(arena, &cert, + CERT_CertificateTemplate, + &csdata.data) != SECSuccess) { + cm_log(1, "Unable to decode certificate " + "data into buffer.\n"); + PORT_FreeArena(arena, PR_TRUE); + if (NSS_ShutdownContext(ctx) != SECSuccess) { + cm_log(1, "Error shutting down NSS.\n"); + } + _exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR); + } + subject = cert.derSubject; + /* Ask NSS if there would be a conflict. */ + have_trust = PR_FALSE; + if (SEC_CertNicknameConflict(entry->cm_cert_nickname, + &subject, + certdb)) { + /* Delete the certificate that's already there + * with the nickname we want, otherwise our + * cert with a different subject name will be + * discarded. */ + certlist = PK11_FindCertsFromNickname(entry->cm_cert_nickname, + NULL); + if (certlist != NULL) { + /* Look for certs with different + * subject names but the same nickname, + * because they've got to go. */ + for (node = CERT_LIST_HEAD(certlist); + (node != NULL) && + !CERT_LIST_EMPTY(certlist) && + !CERT_LIST_END(node, certlist); + node = CERT_LIST_NEXT(node)) { + if (!SECITEM_ItemsAreEqual(&subject, + &node->cert->derSubject)) { + cm_log(3, "Found a " + "certificate " + "with the same " + "nickname but " + "different " + "subject, " + "removing " + "certificate " + "\"%s\" with " + "subject " + "\"%s\".\n", + node->cert->nickname, + node->cert->subjectName ? + node->cert->subjectName : + ""); + /* Get a handle for + * this certificate's + * private key, in case + * we need to remove + * it. */ + privkey = PK11_FindKeyByAnyCert(node->cert, NULL); + privkeys = add_privkey_to_list(privkeys, privkey); + SEC_DeletePermCertificate(node->cert); + } + } + CERT_DestroyCertList(certlist); + } + } else { + cm_log(3, "No duplicate nickname entries.\n"); + } + /* This certificate's subject may already be present + * with a different nickname. Delete those, too. */ + certlist = CERT_CreateSubjectCertList(NULL, certdb, + &subject, + PR_FALSE, + PR_FALSE); if (certlist != NULL) { - /* Look for certs with different - * subject names but the same nickname, - * because they've got to go. */ + /* Look for certs with different nicknames but + * the same subject name, because those have + * got to go. */ + i = 0; for (node = CERT_LIST_HEAD(certlist); (node != NULL) && !CERT_LIST_EMPTY(certlist) && !CERT_LIST_END(node, certlist); node = CERT_LIST_NEXT(node)) { - if (!SECITEM_ItemsAreEqual(&subject, - &node->cert->derSubject)) { + if ((node->cert->nickname != NULL) && + (strcmp(entry->cm_cert_nickname, + node->cert->nickname) != 0)) + { + i++; cm_log(3, "Found a " - "certificate " - "with the same " - "nickname but " - "different " - "subject, " - "removing " - "certificate " - "\"%s\" with " - "subject " - "\"%s\".\n", - node->cert->nickname, - node->cert->subjectName ? - node->cert->subjectName : - ""); - /* Get a handle for - * this certificate's - * private key, in case - * we need to remove - * it. */ - privkey = PK11_FindKeyByAnyCert(node->cert, NULL); - privkeys = add_privkey_to_list(privkeys, privkey); - SEC_DeletePermCertificate(node->cert); - } - } - CERT_DestroyCertList(certlist); - } - } else { - cm_log(3, "No duplicate nickname entries.\n"); - } - /* This certificate's subject may already be present - * with a different nickname. Delete those, too. */ - certlist = CERT_CreateSubjectCertList(NULL, certdb, - &subject, - PR_FALSE, - PR_FALSE); - if (certlist != NULL) { - /* Look for certs with different nicknames but - * the same subject name, because those have - * got to go. */ - i = 0; - for (node = CERT_LIST_HEAD(certlist); - (node != NULL) && - !CERT_LIST_EMPTY(certlist) && - !CERT_LIST_END(node, certlist); - node = CERT_LIST_NEXT(node)) { - if ((node->cert->nickname != NULL) && - (strcmp(entry->cm_cert_nickname, - node->cert->nickname) != 0)) { - i++; - cm_log(3, "Found a " - "certificate with a " + "certificate with a " "different nickname but " "the same subject, " "removing certificate " @@ -426,284 +452,291 @@ cm_certsave_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry, node->cert->subjectName ? node->cert->subjectName : ""); - /* Get a handle for this - * certificate's private key, - * in case we need to remove - * it. */ - privkey = PK11_FindKeyByAnyCert(node->cert, NULL); - privkeys = add_privkey_to_list(privkeys, privkey); - SEC_DeletePermCertificate(node->cert); - } else { - /* Same nickname, and we - * already know it has the same - * subject name. Save its - * trust. */ - if (!have_trust) { - if (CERT_GetCertTrust(node->cert, + /* Get a handle for this + * certificate's private key, + * in case we need to remove + * it. */ + privkey = PK11_FindKeyByAnyCert(node->cert, NULL); + privkeys = add_privkey_to_list(privkeys, privkey); + SEC_DeletePermCertificate(node->cert); + } else { + /* Same nickname, and we + * already know it has the same + * subject name. Save its + * trust. */ + if (!have_trust) { + if (CERT_GetCertTrust(node->cert, &trust) == SECSuccess) { - have_trust = PR_TRUE; + have_trust = PR_TRUE; + } } } } - } - if (i == 0) { - cm_log(3, "No duplicate subject name entries.\n"); - } - CERT_DestroyCertList(certlist); - } else { - cm_log(3, "No duplicate subject name entries.\n"); - } - /* Make one more attempt at finding an existing trust - * value. */ - if (!have_trust) { - oldcert = PK11_FindCertFromNickname(entry->cm_cert_nickname, NULL); - if (oldcert != NULL) { - if (CERT_GetCertTrust(oldcert, - &trust) == SECSuccess) { - have_trust = PR_TRUE; + if (i == 0) { + cm_log(3, "No duplicate subject name entries.\n"); } - CERT_DestroyCertificate(oldcert); + CERT_DestroyCertList(certlist); + } else { + cm_log(3, "No duplicate subject name entries.\n"); } - } - /* Import the certificate. */ - returned = NULL; - error = CERT_ImportCerts(certdb, - certUsageUserCertImport, - 1, &item, &returned, - PR_TRUE, - PR_FALSE, - entry->cm_cert_nickname); - ec = PORT_GetError(); - if (error == SECSuccess) { - /* If NSS uses SQL DB storage, CERT_ImportCerts creates - * an incomplete internal state (the cert isn't - * associated with the private key, and calling - * PK11_FindKeyByAnyCert returns no result). - * As a workaround, we import the cert again using - * PK11_ImportCert, which magically fixes the issue. - * See rhbz#1532188 */ - error = PK11_ImportCert(PK11_GetInternalKeySlot(), - returned[0], - CK_INVALID_HANDLE, - returned[0]->nickname, - PR_FALSE); - } - if (error == SECSuccess) { - cm_log(1, "Imported certificate \"%s\", got " - "nickname \"%s\".\n", - entry->cm_cert_nickname, - returned[0]->nickname); - status = 0; - /* Set the trust on the new certificate, - * perhaps matching the trust on an - * already-present certificate with the same - * nickname. */ + /* Make one more attempt at finding an existing trust + * value. */ if (!have_trust) { - memset(&trust, 0, sizeof(trust)); - trust.sslFlags = CERTDB_USER; - trust.emailFlags = CERTDB_USER; - trust.objectSigningFlags = CERTDB_USER; + oldcert = PK11_FindCertFromNickname(entry->cm_cert_nickname, NULL); + if (oldcert != NULL) { + if (CERT_GetCertTrust(oldcert, + &trust) == SECSuccess) { + have_trust = PR_TRUE; + } + CERT_DestroyCertificate(oldcert); + } } - error = CERT_ChangeCertTrust(certdb, - returned[0], - &trust); + /* Import the certificate. */ + returned = NULL; + error = CERT_ImportCerts(certdb, + certUsageUserCertImport, + 1, &item, &returned, + PR_TRUE, + PR_FALSE, + entry->cm_cert_nickname); ec = PORT_GetError(); - if (error != SECSuccess) { + if (error == SECSuccess) { + /* If NSS uses SQL DB storage, CERT_ImportCerts creates + * an incomplete internal state (the cert isn't + * associated with the private key, and calling + * PK11_FindKeyByAnyCert returns no result). + * As a workaround, we import the cert again using + * PK11_ImportCert, which magically fixes the issue. + * See rhbz#1532188 */ + error = PK11_ImportCert(sle->slot, + returned[0], + CK_INVALID_HANDLE, + returned[0]->nickname, + PR_FALSE); + } + if (error == SECSuccess) { + cm_log(1, "Imported certificate \"%s\", got " + "nickname \"%s\".\n", + entry->cm_cert_nickname, + returned[0]->nickname); + status = 0; + /* Set the trust on the new certificate, + * perhaps matching the trust on an + * already-present certificate with the same + * nickname. */ + if (!have_trust) { + memset(&trust, 0, sizeof(trust)); + trust.sslFlags = CERTDB_USER; + trust.emailFlags = CERTDB_USER; + trust.objectSigningFlags = CERTDB_USER; + } + error = CERT_ChangeCertTrust(certdb, + returned[0], + &trust); + ec = PORT_GetError(); + if (error != SECSuccess) { + if (ec != 0) { + es = PR_ErrorToName(ec); + } else { + es = NULL; + } + if (es != NULL) { + cm_log(0, "Error setting trust " + "on certificate \"%s\": " + "%s.\n", + entry->cm_cert_nickname, es); + } else { + cm_log(0, "Error setting trust " + "on certificate \"%s\".\n", + entry->cm_cert_nickname); + } + } + /* Delete any other certificates that are there + * with the same nickname. While NSS's + * database allows duplicates so long as they + * have the same subject name and nickname, + * several APIs and many applications can't + * dependably find the right one among more + * than one. So bye-bye, old certificates. */ + certlist = PK11_FindCertsFromNickname(entry->cm_cert_nickname, + NULL); + if (certlist != NULL) { + /* Look for certs with contents. */ + for (node = CERT_LIST_HEAD(certlist); + (node != NULL) && + !CERT_LIST_EMPTY(certlist) && + !CERT_LIST_END(node, certlist); + node = CERT_LIST_NEXT(node)) { + if (!SECITEM_ItemsAreEqual(item, + &node->cert->derCert)) { + cm_log(3, "Found a " + "certificate " + "with the same " + "nickname and " + "subject, but " + "different " + "contents, " + "removing it.\n"); + /* Get a handle for + * this certificate's + * private key, in case + * we need to remove + * it. */ + privkey = PK11_FindKeyByAnyCert(node->cert, NULL); + privkeys = add_privkey_to_list(privkeys, privkey); + SEC_DeletePermCertificate(node->cert); + } + } + CERT_DestroyCertList(certlist); + } + } else { if (ec != 0) { es = PR_ErrorToName(ec); } else { es = NULL; } if (es != NULL) { - cm_log(0, "Error setting trust " - "on certificate \"%s\": " - "%s.\n", - entry->cm_cert_nickname, es); + cm_log(0, "Error importing certificate " + "into NSSDB \"%s\": %s.\n", + entry->cm_cert_storage_location, + es); } else { - cm_log(0, "Error setting trust " - "on certificate \"%s\".\n", - entry->cm_cert_nickname); + cm_log(0, "Error importing certificate " + "into NSSDB \"%s\".\n", + entry->cm_cert_storage_location); } - } - /* Delete any other certificates that are there - * with the same nickname. While NSS's - * database allows duplicates so long as they - * have the same subject name and nickname, - * several APIs and many applications can't - * dependably find the right one among more - * than one. So bye-bye, old certificates. */ - certlist = PK11_FindCertsFromNickname(entry->cm_cert_nickname, - NULL); - if (certlist != NULL) { - /* Look for certs with contents. */ - for (node = CERT_LIST_HEAD(certlist); - (node != NULL) && - !CERT_LIST_EMPTY(certlist) && - !CERT_LIST_END(node, certlist); - node = CERT_LIST_NEXT(node)) { - if (!SECITEM_ItemsAreEqual(item, - &node->cert->derCert)) { - cm_log(3, "Found a " - "certificate " - "with the same " - "nickname and " - "subject, but " - "different " - "contents, " - "removing it.\n"); - /* Get a handle for - * this certificate's - * private key, in case - * we need to remove - * it. */ - privkey = PK11_FindKeyByAnyCert(node->cert, NULL); - privkeys = add_privkey_to_list(privkeys, privkey); - SEC_DeletePermCertificate(node->cert); - } + switch (ec) { + case PR_NO_ACCESS_RIGHTS_ERROR: /* ACCES/PERM */ + status = CM_CERTSAVE_STATUS_PERMS; + break; + default: + status = CM_CERTSAVE_STATUS_INTERNAL_ERROR; + break; } - CERT_DestroyCertList(certlist); - } - } else { - if (ec != 0) { - es = PR_ErrorToName(ec); - } else { - es = NULL; } - if (es != NULL) { - cm_log(0, "Error importing certificate " - "into NSSDB \"%s\": %s.\n", - entry->cm_cert_storage_location, - es); - } else { - cm_log(0, "Error importing certificate " - "into NSSDB \"%s\".\n", - entry->cm_cert_storage_location); - } - switch (ec) { - case PR_NO_ACCESS_RIGHTS_ERROR: /* ACCES/PERM */ - status = CM_CERTSAVE_STATUS_PERMS; - break; - default: - status = CM_CERTSAVE_STATUS_INTERNAL_ERROR; - break; + /* If we managed to import the certificate, mark its + * key for having its nickname removed. */ + if ((returned != NULL) && (returned[0] != NULL)) { + privkey = PK11_FindKeyByAnyCert(returned[0], NULL); + privkeys = add_privkey_to_list(privkeys, privkey); + CERT_DestroyCertArray(returned, 1); } - } - /* If we managed to import the certificate, mark its - * key for having its nickname removed. */ - if ((returned != NULL) && (returned[0] != NULL)) { - privkey = PK11_FindKeyByAnyCert(returned[0], NULL); - privkeys = add_privkey_to_list(privkeys, privkey); - CERT_DestroyCertArray(returned, 1); - } - /* In case we're rekeying, but failed, mark the - * candidate key for name-clearing or removal, too. */ - if ((entry->cm_key_next_marker != NULL) && - (strlen(entry->cm_key_next_marker) > 0)) { - p = util_build_next_nickname(entry->cm_key_nickname, - entry->cm_key_next_marker); - privkeylist = PK11_ListPrivKeysInSlot(PK11_GetInternalKeySlot(), p, NULL); - if (privkeylist != NULL) { - for (knode = PRIVKEY_LIST_HEAD(privkeylist); - !PRIVKEY_LIST_EMPTY(privkeylist) && - !PRIVKEY_LIST_END(knode, privkeylist); - knode = PRIVKEY_LIST_NEXT(knode)) { - q = PK11_GetPrivateKeyNickname(knode->key); - if ((q != NULL) && - (strcmp(p, q) == 0)) { - privkey = SECKEY_CopyPrivateKey(knode->key); - privkeys = add_privkey_to_list(privkeys, privkey); - break; + /* In case we're rekeying, but failed, mark the + * candidate key for name-clearing or removal, too. */ + if ((entry->cm_key_next_marker != NULL) && + (strlen(entry->cm_key_next_marker) > 0)) { + p = util_build_next_nickname(entry->cm_key_nickname, + entry->cm_key_next_marker); + privkeylist = PK11_ListPrivKeysInSlot(sle->slot, p, NULL); + if (privkeylist != NULL) { + for (knode = PRIVKEY_LIST_HEAD(privkeylist); + !PRIVKEY_LIST_EMPTY(privkeylist) && + !PRIVKEY_LIST_END(knode, privkeylist); + knode = PRIVKEY_LIST_NEXT(knode)) { + q = PK11_GetPrivateKeyNickname(knode->key); + if ((q != NULL) && + (strcmp(p, q) == 0)) { + privkey = SECKEY_CopyPrivateKey(knode->key); + privkeys = add_privkey_to_list(privkeys, privkey); + break; + } } + SECKEY_DestroyPrivateKeyList(privkeylist); } - SECKEY_DestroyPrivateKeyList(privkeylist); } - } - if (privkeys != NULL) { - /* Check if any certificates are still using - * the keys that correspond to certificates - * that we removed. */ - for (i = 0; privkeys[i] != NULL; i++) { - privkey = privkeys[i]; - oldcert = PK11_GetCertFromPrivateKey(privkey); - if (!entry->cm_key_preserve && (oldcert == NULL)) { - /* We're not preserving - * orphaned keys, so remove - * this one. No need to mess - * with its nickname first. */ - PK11_DeleteTokenPrivateKey(privkey, PR_FALSE); - if (error == SECSuccess) { - cm_log(3, "Removed old key.\n"); - } else { - ec = PORT_GetError(); - if (ec != 0) { - es = PR_ErrorToName(ec); + if (privkeys != NULL) { + /* Check if any certificates are still using + * the keys that correspond to certificates + * that we removed. */ + for (i = 0; privkeys[i] != NULL; i++) { + privkey = privkeys[i]; + oldcert = PK11_GetCertFromPrivateKey(privkey); + if (!entry->cm_key_preserve && (oldcert == NULL)) { + /* We're not preserving + * orphaned keys, so remove + * this one. No need to mess + * with its nickname first. */ + PK11_DeleteTokenPrivateKey(privkey, PR_FALSE); + if (error == SECSuccess) { + cm_log(3, "Removed old key.\n"); } else { - es = NULL; + ec = PORT_GetError(); + if (ec != 0) { + es = PR_ErrorToName(ec); + } else { + es = NULL; + } + if (es != NULL) { + cm_log(0, "Failed " + "to remove " + "old key: " + "%s.\n", es); + } else { + cm_log(0, "Failed " + "to remove " + "old key.\n"); + } } - if (es != NULL) { - cm_log(0, "Failed " - "to remove " - "old key: " - "%s.\n", es); - } else { - cm_log(0, "Failed " - "to remove " - "old key.\n"); - } - } - } else { - /* Remove the explicit - * nickname, so that the key - * will have to be found using - * the certificate's nickname, - * and certutil will display - * the matching certificate's - * nickname when it's asked to - * list the keys in the - * database. */ - error = PK11_SetPrivateKeyNickname(privkey, ""); - if (error == SECSuccess) { - cm_log(3, "Removed " - "name from old " - "key.\n"); } else { - ec = PORT_GetError(); - if (ec != 0) { - es = PR_ErrorToName(ec); + /* Remove the explicit + * nickname, so that the key + * will have to be found using + * the certificate's nickname, + * and certutil will display + * the matching certificate's + * nickname when it's asked to + * list the keys in the + * database. */ + error = PK11_SetPrivateKeyNickname(privkey, ""); + if (error == SECSuccess) { + cm_log(3, "Removed " + "name from old " + "key.\n"); } else { - es = NULL; - } - if (es != NULL) { - cm_log(0, "Failed " - "to unname " - "old key: " - "%s.\n", es); - } else { - cm_log(0, "Failed " - "to unname " - "old key.\n"); + ec = PORT_GetError(); + if (ec != 0) { + es = PR_ErrorToName(ec); + } else { + es = NULL; + } + if (es != NULL) { + cm_log(0, "Failed " + "to unname " + "old key: " + "%s.\n", es); + } else { + cm_log(0, "Failed " + "to unname " + "old key.\n"); + } } + SECKEY_DestroyPrivateKey(privkey); + } + if (oldcert != NULL) { + CERT_DestroyCertificate(oldcert); } - SECKEY_DestroyPrivateKey(privkey); - } - if (oldcert != NULL) { - CERT_DestroyCertificate(oldcert); } + free(privkeys); } - free(privkeys); + } else { + cm_log(1, "Error getting handle to default NSS DB.\n"); } - } else { - cm_log(1, "Error getting handle to default NSS DB.\n"); - } - PORT_FreeArena(arena, PR_TRUE); - if (NSS_ShutdownContext(ctx) != SECSuccess) { - cm_log(1, "Error shutting down NSS.\n"); - } - /* Fixup the ownership and permissions on the key and - * certificate databases. */ - util_set_db_entry_key_owner(entry->cm_key_storage_location, entry); - util_set_db_entry_cert_owner(entry->cm_cert_storage_location, entry); - } + PORT_FreeArena(arena, PR_TRUE); + if (NSS_ShutdownContext(ctx) != SECSuccess) { + cm_log(1, "Error shutting down NSS.\n"); + } + /* Fixup the ownership and permissions on the key and + * certificate databases. */ + util_set_db_entry_key_owner(entry->cm_key_storage_location, entry); + util_set_db_entry_cert_owner(entry->cm_cert_storage_location, entry); + break; +next_slot: + if (sle == slotlist->tail) { + break; + } + } /* for slot loop */ + } /* ctx == NULL */ + if (status != 0) { _exit(status); } -- 2.14.4