Closed Bug 115954 Opened 23 years ago Closed 23 years ago

CERTCertListNode nickname field is empty after PK11_ListCerts

Categories

(NSS :: Libraries, defect, P1)

Other
Other
defect

Tracking

(Not tracked)

VERIFIED FIXED

People

(Reporter: julien.pierre, Assigned: bugz)

References

Details

Attachments

(1 file, 2 obsolete files)

In NSS 3.4 the root certs returned from PK11_ListCerts don't have a slot set. This makes it impossible to display the slot/token name and breaks the web server admin UI. Specifically, the code that displays the cert in the CGI UI does : PRInt32 mgcrt :: printcert(const SecCert& acert) { // prints an individual cert CERTCertificate* cert = acert.cert; char * typestr; char * datestr; char * nn = (char*)acert.nickname; char * jsnn; char * escname; char * escpass = ""; char * keyfilepw = ""; char cgiVar[512]; PRInt32 flags = acert.flags; SECStatus rv; SECCertTimeValidity certtimestatus; if (!nn) { nn = (char *) cmgGetNameDesc(&cert->subject); if (!nn) { return SECSuccess; } } if ((!strcmp(nn, "Server-Cert")) || (flags & (CERTDB_USER))) { typestr = "Own"; } else if (flags & CERTDB_VALID_CA) { if (flags & CERTDB_TRUSTED_CLIENT_CA) { if (flags & CERTDB_TRUSTED_CA) { typestr = "Trusted Client & Server CA"; } else { typestr = "Trusted Client CA"; }; } else { if (flags & CERTDB_TRUSTED_CA) { typestr = "Trusted Server CA"; } else { typestr = "Untrusted CA"; }; }; } else if (flags & CERTDB_VALID_PEER) { typestr = (flags & CERTDB_TRUSTED) ? "Trusted Peer" : "Untrusted Peer"; } else if (flags & CERTDB_TRUSTED) typestr = "Trusted"; else { PR_ASSERT(0); typestr = ""; //typestr = "Server CA"; }; datestr = (char *)DER_UTCTimeToAscii(&cert->validity.notAfter); certtimestatus = CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE); rv = SECSuccess; if (certtimestatus == secCertTimeExpired) { rv = SECFailure; } jsnn = cmgJSString(nn); escname = util_uri_escape(NULL, nn); if ( cert->slot) { sprintf(cgiVar, "%s%s", PK11_GetSlotName(cert->slot), PK11_GetTokenName(cert->slot)); keyfilepw = get_cgi_var(cgiVar, NULL, NULL); if (keyfilepw) { escpass = util_uri_escape(NULL, keyfilepw); }; }; printf("<tr><td><a href=javascript:pop_up(\"security?cmd=sec-ecrt&nickname=%s&keyfilepw=%s\") ", util_uri_escape(NULL, (char*)acert.nickname), escpass); printf(SHOW_CERT " >", jsnn); printf("%s</a></td>", nn); printf("<td>%s</td><td>%s%s</td></tr>", typestr, datestr, rv ? "[*]" : ""); PORT_Free(escname); PORT_Free(jsnn); return SECSuccess; }; It never goes to the case after if (cert->slot) for root certs, which it did with 3.3.2 correctly but no longer does with 3.4 . As a result the certs are assumed to be in the internal token rather than in a PKCS#11 module. When a user clicks on the link which passes the nickname and is supposed to contain the slot/token name, the web server admin UI tries to lookup the cert with CERT_FindCertFromNickname instead of PK11_FindCertFromNickname, and thus fails to find the cert subsequently.
Severity: normal → blocker
Priority: -- → P1
Target Milestone: --- → 3.4
I can't reproduce this. I tried by putting a call to PK11_ListCerts in certutil and then listing the builtins, they all had a slot. Unless something bad has happened (the cert was prematurely destroyed?), the only way for slot to be NULL in NSS 3.4 is for the cert to be a temp cert.
Assigned the bug to Ian.
Assignee: wtc → ian.mcgreer
Never mind, the cert->slot is set. The problem is that the nickname field of the CERTCertListNode structure from PK11_ListCerts is NULL for the root certs. It needs to be filled with a nickname including the token name, as it was in 3.3.2 . This is what breaks the UI.
Summary: cert->slot isn't set for built-in token root certs → CERTCertListNode nickname field is empty after PK11_ListCerts
The only thing I notice is that the nickname does not include the token name, as it used to. But it is present in node->appData, and node->cert->nickname. This is from calling PK11_ListCerts with the type PK11CertListCA. If PK11_ListCerts is called with PK11CertListUnique or PK11CertListRootUnique, node->appData will not be set. This has not changed from 3.2.2, as far as I can tell. For now, I'm going to make sure the token name is included. Can you tell me what type of list PK11_ListCerts is called with?
Ian, The problem is indeed that the token name is missing from the nickname in the list structure. It was supposed to be there in order to resolve issues with duplicate certs in different tokens. I'm making the calls the following way : void certcb :: populate() { // get all the user certs CERTCertList* clist; clist = PK11_ListCerts(PK11CertListUser, NULL); populate(clist); // then get all the root certs clist = PK11_ListCerts(PK11CertListRootUnique, NULL); populate(clist); } I believe the reason for having the root certs with the unique parameter was to resolve trust issues with the built-in certs so that they wouldn't show twice in the UI if the trust bits had been changed from the default. There are several ways that the UI code would get the token name. Either it would get it from the list structure, if present, or if missing, it would do a PK11_GetTokenName . But the name from the list always had the priority.
Ian, Another problem I have seen is that occasionally, the root certs are not displayed at all in the web server UI. This is an intermittent, random problem, most likely depending on the state of memory, so unfortunately I do not have a test case for it. I can see it on my machine right now though.
FYI I opened another bug on PK11_ListCerts for the root certs not showing. The bug is 116315 - http://bugzilla.mozilla.org/show_bug.cgi?id=116315 .
Depends on: 116315
AFAIK, this bug is fixed. The intermittent failures in PK11_ListCerts is another bug, so I'll close this one. Please reopen if this isn't actually fixed.
Status: NEW → RESOLVED
Closed: 23 years ago
Resolution: --- → FIXED
Reopening this. Unfortunately, this is broken again in the latest build of NSS 3.4 , 20020329. After changing the trust on a root certificate, the token name is no longer returned by PK11_ListCerts in the CERTCertListNode . So the certificate just shows with the nickname. The relevant admin UI web server code is below : // walk the list and add the certs to our own lists CERTCertListNode *cln; for (cln = CERT_LIST_HEAD(clist); !CERT_LIST_END(cln,clist); cln = CERT_LIST_NEXT(cln)) { CERTCertificate* cert = cln->cert; const char* nickname = (const char*) cln->appData; if (!nickname) { nickname = cert->nickname; } The cln->appData is set for root certs if the trust has not changed and contains the proper "Builtin Object Token:xxx" string. After trust is changed, the value is NULL, so we grab cert->nickname ...
Status: RESOLVED → REOPENED
Resolution: FIXED → ---
There may be a workaround on the application side, suggested by Ian, which would be to look for the DER of all CA certs in the built-in slot, and then if matching, display the built-in prefix. This would only work for the specific case of the built-ins though, not for other CA certs living in multiple tokens. Therefore, an NSS fix would be preferable. I talked to Bob about it and he said basically the cert->slot should be set to a token other than the internal cert/key db token if the cert existed in multiple tokens. That works for the case of a CA cert existing in any external token and the key db, which is the case of the root certs that we are concerned with here. I have been investigating the code in mozilla/security/nss/lib/pki/pki3hack.c . I tried to fix fillCERTCertificateFields and set the right slot, but could not. That function only got called once on my root cert with changed trust, and the cc->slot got set to the key db slot. So I would need to set the slot somewhere else. Bob suggested there is some code in the cert cache that deals with nicknames which would be the proper place to set this also. I couldn't find the appropriate functions in that directory. Most of them dealt with NSSCertificates rather than CERTCertificates.
Julien, bug 129298 is about nicknames. It may have the information you need.
Thanks. I did notice the NSSCertificate_GetNickname function. I already even put code of my own in my tree to try to iterate through every token and not just take the first nickname. But in no case was I able to get more than one token name returned. Maybe I didn't do it right. I have to look at it some more tomorrow.
Attached patch a proposed workaround (obsolete) — Splinter Review
This is an application-level workaround for this bug, the one I mentioned. Here it is implemented in certutil. This is what the output looks like: [k@24-164-150-83 certutil]$ ./Linux2.4_x86_glibc_PTH_DBG.OBJ/certutil -L -d test -h all Builtin Object Token--v E-Certify CA c,c,c Builtin Object Token:Verisign/RSA Secure Server CA C,C,p Builtin Object Token:GTE CyberTrust Root CA C,C,C I agree that it is limited, but it does work for this particular problem.
Comment on attachment 77457 [details] [diff] [review] a proposed workaround Sigh. It doesn't work. PK11_FindCertFromDERCert will return a cert that is not on the slot if the cert is cached. So certs that are on the softoken but *not* the builtins will return from it.
Attachment #77457 - Attachment is obsolete: true
Attached patch patch to NSS 3.4 (obsolete) — Splinter Review
As I thought, the code already existed to always choose other tokens over the softoken when there are multiple instances of a cert. It just wasn't being called when the instances were added, so if the softoken comes first, its instance is used. This patch forces an update of CERTCertificate fields once a new instance of the cert is discovered. Here's what it looks like with regular certutil: [k@24-164-150-83 certutil]$ ./Linux2.4_x86_glibc_PTH_DBG.OBJ/certutil -L -d test -h all negative c,c, Builtin Object Token:E-Certify CA c,c,c Builtin Object Token:Verisign/RSA Secure Server CA C,C,p "negative" is a softoken cert, "E-Certify CA" is a cert on both the softoken and builtin token, with the trust "c,c," on the softoken.
Comment on attachment 77460 [details] [diff] [review] patch to NSS 3.4 OK, I'm assuming the ForceCERT call is in the correct spot (It looks right to me). The logic for prefering the non-internal token is in get_cet_instance (which is already existing). The two other pointers that are overridden are nickname and trust, both are allocated out of the arena, so there's no leak. Approval based on positive purify output. bob
Attachment #77460 - Flags: review+
1. Include pki3hack.h in order to get definition of STAN_ForceCERTCertificateUpdate 2. change the check to: if (cert->decoding && inCache) The previous patch would force the update for all certs, instead of just ones that had already been created. That is, the code did not match the comment. This code does. I have verified this by stepping through the debugger for various cases. I have verified that this patch only affects certs with multiple instances. I have run the patch through purify and saw no leaks.
Attachment #77460 - Attachment is obsolete: true
Ian, please go ahead and check in your patch on the trunk and NSS_3_4_BRANCH. Julien, please test this fix with the web server. Thanks.
checked in to both places.
I tested this fix with the web server and it did not resolve the problem.
Seems there was a problem with my NSS 3.4 build. With a full rebuild it resolved the problem.
Status: REOPENED → RESOLVED
Closed: 23 years ago23 years ago
Resolution: --- → FIXED
verified
Status: RESOLVED → VERIFIED
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: