Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / security / nss / lib / pki / pki3hack.c
blobf68ab0914e18ebdb2226ed2bf6a74527c30cc683
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #ifdef DEBUG
38 static const char CVS_ID[] = "@(#) $RCSfile: pki3hack.c,v $ $Revision: 1.96 $ $Date: 2008/08/09 01:26:05 $";
39 #endif /* DEBUG */
42 * Hacks to integrate NSS 3.4 and NSS 4.0 certificates.
45 #ifndef NSSPKI_H
46 #include "nsspki.h"
47 #endif /* NSSPKI_H */
49 #ifndef PKI_H
50 #include "pki.h"
51 #endif /* PKI_H */
53 #ifndef PKIM_H
54 #include "pkim.h"
55 #endif /* PKIM_H */
57 #ifndef DEV_H
58 #include "dev.h"
59 #endif /* DEV_H */
61 #ifndef DEVNSS3HACK_H
62 #include "dev3hack.h"
63 #endif /* DEVNSS3HACK_H */
65 #ifndef PKINSS3HACK_H
66 #include "pki3hack.h"
67 #endif /* PKINSS3HACK_H */
69 #include "secitem.h"
70 #include "certdb.h"
71 #include "certt.h"
72 #include "cert.h"
73 #include "certi.h"
74 #include "pk11func.h"
75 #include "pkistore.h"
76 #include "secmod.h"
77 #include "nssrwlk.h"
79 NSSTrustDomain *g_default_trust_domain = NULL;
81 NSSCryptoContext *g_default_crypto_context = NULL;
83 NSSTrustDomain *
84 STAN_GetDefaultTrustDomain()
86 return g_default_trust_domain;
89 NSSCryptoContext *
90 STAN_GetDefaultCryptoContext()
92 return g_default_crypto_context;
95 extern const NSSError NSS_ERROR_ALREADY_INITIALIZED;
96 extern const NSSError NSS_ERROR_INTERNAL_ERROR;
98 NSS_IMPLEMENT PRStatus
99 STAN_InitTokenForSlotInfo(NSSTrustDomain *td, PK11SlotInfo *slot)
101 NSSToken *token;
102 if (!td) {
103 td = g_default_trust_domain;
105 token = nssToken_CreateFromPK11SlotInfo(td, slot);
106 PK11Slot_SetNSSToken(slot, token);
107 /* Don't add non-existent token to TD's token list */
108 if (token) {
109 NSSRWLock_LockWrite(td->tokensLock);
110 nssList_Add(td->tokenList, token);
111 NSSRWLock_UnlockWrite(td->tokensLock);
113 return PR_SUCCESS;
116 NSS_IMPLEMENT PRStatus
117 STAN_ResetTokenInterator(NSSTrustDomain *td)
119 if (!td) {
120 td = g_default_trust_domain;
122 NSSRWLock_LockWrite(td->tokensLock);
123 nssListIterator_Destroy(td->tokens);
124 td->tokens = nssList_CreateIterator(td->tokenList);
125 NSSRWLock_UnlockWrite(td->tokensLock);
126 return PR_SUCCESS;
129 NSS_IMPLEMENT PRStatus
130 STAN_LoadDefaultNSS3TrustDomain (
131 void
134 NSSTrustDomain *td;
135 SECMODModuleList *mlp;
136 SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
137 int i;
139 if (g_default_trust_domain || g_default_crypto_context) {
140 /* Stan is already initialized or a previous shutdown failed. */
141 nss_SetError(NSS_ERROR_ALREADY_INITIALIZED);
142 return PR_FAILURE;
144 td = NSSTrustDomain_Create(NULL, NULL, NULL, NULL);
145 if (!td) {
146 return PR_FAILURE;
149 * Deadlock warning: we should never acquire the moduleLock while
150 * we hold the tokensLock. We can use the NSSRWLock Rank feature to
151 * guarrentee this. tokensLock have a higher rank than module lock.
153 td->tokenList = nssList_Create(td->arena, PR_TRUE);
154 if (!td->tokenList) {
155 goto loser;
157 SECMOD_GetReadLock(moduleLock);
158 NSSRWLock_LockWrite(td->tokensLock);
159 for (mlp = SECMOD_GetDefaultModuleList(); mlp != NULL; mlp=mlp->next) {
160 for (i=0; i < mlp->module->slotCount; i++) {
161 STAN_InitTokenForSlotInfo(td, mlp->module->slots[i]);
164 td->tokens = nssList_CreateIterator(td->tokenList);
165 NSSRWLock_UnlockWrite(td->tokensLock);
166 SECMOD_ReleaseReadLock(moduleLock);
167 if (!td->tokens) {
168 goto loser;
170 g_default_crypto_context = NSSTrustDomain_CreateCryptoContext(td, NULL);
171 if (!g_default_crypto_context) {
172 goto loser;
174 g_default_trust_domain = td;
175 return PR_SUCCESS;
177 loser:
178 NSSTrustDomain_Destroy(td);
179 return PR_FAILURE;
183 * must be called holding the ModuleListLock (either read or write).
185 NSS_IMPLEMENT SECStatus
186 STAN_AddModuleToDefaultTrustDomain (
187 SECMODModule *module
190 NSSTrustDomain *td;
191 int i;
192 td = STAN_GetDefaultTrustDomain();
193 for (i=0; i<module->slotCount; i++) {
194 STAN_InitTokenForSlotInfo(td, module->slots[i]);
196 STAN_ResetTokenInterator(td);
197 return SECSuccess;
201 * must be called holding the ModuleListLock (either read or write).
203 NSS_IMPLEMENT SECStatus
204 STAN_RemoveModuleFromDefaultTrustDomain (
205 SECMODModule *module
208 NSSToken *token;
209 NSSTrustDomain *td;
210 int i;
211 td = STAN_GetDefaultTrustDomain();
212 NSSRWLock_LockWrite(td->tokensLock);
213 for (i=0; i<module->slotCount; i++) {
214 token = PK11Slot_GetNSSToken(module->slots[i]);
215 if (token) {
216 nssToken_NotifyCertsNotVisible(token);
217 nssList_Remove(td->tokenList, token);
218 PK11Slot_SetNSSToken(module->slots[i], NULL);
219 nssToken_Destroy(token);
222 nssListIterator_Destroy(td->tokens);
223 td->tokens = nssList_CreateIterator(td->tokenList);
224 NSSRWLock_UnlockWrite(td->tokensLock);
225 return SECSuccess;
228 NSS_IMPLEMENT PRStatus
229 STAN_Shutdown()
231 PRStatus status = PR_SUCCESS;
232 if (g_default_trust_domain) {
233 if (NSSTrustDomain_Destroy(g_default_trust_domain) == PR_SUCCESS) {
234 g_default_trust_domain = NULL;
235 } else {
236 status = PR_FAILURE;
239 if (g_default_crypto_context) {
240 if (NSSCryptoContext_Destroy(g_default_crypto_context) == PR_SUCCESS) {
241 g_default_crypto_context = NULL;
242 } else {
243 status = PR_FAILURE;
246 return status;
249 /* this function should not be a hack; it will be needed in 4.0 (rename) */
250 NSS_IMPLEMENT NSSItem *
251 STAN_GetCertIdentifierFromDER(NSSArena *arenaOpt, NSSDER *der)
253 NSSItem *rvKey;
254 SECItem secDER;
255 SECItem secKey = { 0 };
256 SECStatus secrv;
257 PRArenaPool *arena;
259 SECITEM_FROM_NSSITEM(&secDER, der);
261 /* nss3 call uses nss3 arena's */
262 arena = PORT_NewArena(256);
263 if (!arena) {
264 return NULL;
266 secrv = CERT_KeyFromDERCert(arena, &secDER, &secKey);
267 if (secrv != SECSuccess) {
268 return NULL;
270 rvKey = nssItem_Create(arenaOpt, NULL, secKey.len, (void *)secKey.data);
271 PORT_FreeArena(arena,PR_FALSE);
272 return rvKey;
275 NSS_IMPLEMENT PRStatus
276 nssPKIX509_GetIssuerAndSerialFromDER(NSSDER *der, NSSArena *arena,
277 NSSDER *issuer, NSSDER *serial)
279 SECStatus secrv;
280 SECItem derCert;
281 SECItem derIssuer = { 0 };
282 SECItem derSerial = { 0 };
283 SECITEM_FROM_NSSITEM(&derCert, der);
284 secrv = CERT_SerialNumberFromDERCert(&derCert, &derSerial);
285 if (secrv != SECSuccess) {
286 return PR_FAILURE;
288 (void)nssItem_Create(arena, serial, derSerial.len, derSerial.data);
289 secrv = CERT_IssuerNameFromDERCert(&derCert, &derIssuer);
290 if (secrv != SECSuccess) {
291 PORT_Free(derSerial.data);
292 return PR_FAILURE;
294 (void)nssItem_Create(arena, issuer, derIssuer.len, derIssuer.data);
295 PORT_Free(derSerial.data);
296 PORT_Free(derIssuer.data);
297 return PR_SUCCESS;
300 static NSSItem *
301 nss3certificate_getIdentifier(nssDecodedCert *dc)
303 NSSItem *rvID;
304 CERTCertificate *c = (CERTCertificate *)dc->data;
305 rvID = nssItem_Create(NULL, NULL, c->certKey.len, c->certKey.data);
306 return rvID;
309 static void *
310 nss3certificate_getIssuerIdentifier(nssDecodedCert *dc)
312 CERTCertificate *c = (CERTCertificate *)dc->data;
313 return (void *)c->authKeyID;
316 static nssCertIDMatch
317 nss3certificate_matchIdentifier(nssDecodedCert *dc, void *id)
319 CERTCertificate *c = (CERTCertificate *)dc->data;
320 CERTAuthKeyID *authKeyID = (CERTAuthKeyID *)id;
321 SECItem skid;
322 nssCertIDMatch match = nssCertIDMatch_Unknown;
324 /* keyIdentifier */
325 if (authKeyID->keyID.len > 0 &&
326 CERT_FindSubjectKeyIDExtension(c, &skid) == SECSuccess) {
327 PRBool skiEqual;
328 skiEqual = SECITEM_ItemsAreEqual(&authKeyID->keyID, &skid);
329 PORT_Free(skid.data);
330 if (skiEqual) {
331 /* change the state to positive match, but keep going */
332 match = nssCertIDMatch_Yes;
333 } else {
334 /* exit immediately on failure */
335 return nssCertIDMatch_No;
339 /* issuer/serial (treated as pair) */
340 if (authKeyID->authCertIssuer) {
341 SECItem *caName = NULL;
342 SECItem *caSN = &authKeyID->authCertSerialNumber;
344 caName = (SECItem *)CERT_GetGeneralNameByType(
345 authKeyID->authCertIssuer,
346 certDirectoryName, PR_TRUE);
347 if (caName != NULL &&
348 SECITEM_ItemsAreEqual(&c->derIssuer, caName) &&
349 SECITEM_ItemsAreEqual(&c->serialNumber, caSN))
351 match = nssCertIDMatch_Yes;
352 } else {
353 match = nssCertIDMatch_Unknown;
356 return match;
359 static PRBool
360 nss3certificate_isValidIssuer(nssDecodedCert *dc)
362 CERTCertificate *c = (CERTCertificate *)dc->data;
363 unsigned int ignore;
364 return CERT_IsCACert(c, &ignore);
367 static NSSUsage *
368 nss3certificate_getUsage(nssDecodedCert *dc)
370 /* CERTCertificate *c = (CERTCertificate *)dc->data; */
371 return NULL;
374 static PRBool
375 nss3certificate_isValidAtTime(nssDecodedCert *dc, NSSTime *time)
377 SECCertTimeValidity validity;
378 CERTCertificate *c = (CERTCertificate *)dc->data;
379 validity = CERT_CheckCertValidTimes(c, NSSTime_GetPRTime(time), PR_TRUE);
380 if (validity == secCertTimeValid) {
381 return PR_TRUE;
383 return PR_FALSE;
386 static PRBool
387 nss3certificate_isNewerThan(nssDecodedCert *dc, nssDecodedCert *cmpdc)
389 /* I know this isn't right, but this is glue code anyway */
390 if (cmpdc->type == dc->type) {
391 CERTCertificate *certa = (CERTCertificate *)dc->data;
392 CERTCertificate *certb = (CERTCertificate *)cmpdc->data;
393 return CERT_IsNewer(certa, certb);
395 return PR_FALSE;
398 /* CERT_FilterCertListByUsage */
399 static PRBool
400 nss3certificate_matchUsage(nssDecodedCert *dc, const NSSUsage *usage)
402 CERTCertificate *cc;
403 unsigned int requiredKeyUsage = 0;
404 unsigned int requiredCertType = 0;
405 SECStatus secrv;
406 PRBool match;
407 PRBool ca;
409 /* This is for NSS 3.3 functions that do not specify a usage */
410 if (usage->anyUsage) {
411 return PR_TRUE;
413 ca = usage->nss3lookingForCA;
414 secrv = CERT_KeyUsageAndTypeForCertUsage(usage->nss3usage, ca,
415 &requiredKeyUsage,
416 &requiredCertType);
417 if (secrv != SECSuccess) {
418 return PR_FALSE;
420 cc = (CERTCertificate *)dc->data;
421 secrv = CERT_CheckKeyUsage(cc, requiredKeyUsage);
422 match = (PRBool)(secrv == SECSuccess);
423 if (match) {
424 unsigned int certType = 0;
425 if (ca) {
426 (void)CERT_IsCACert(cc, &certType);
427 } else {
428 certType = cc->nsCertType;
430 if (!(certType & requiredCertType)) {
431 match = PR_FALSE;
434 return match;
437 static NSSASCII7 *
438 nss3certificate_getEmailAddress(nssDecodedCert *dc)
440 CERTCertificate *cc = (CERTCertificate *)dc->data;
441 return (cc && cc->emailAddr && cc->emailAddr[0])
442 ? (NSSASCII7 *)cc->emailAddr : NULL;
445 static PRStatus
446 nss3certificate_getDERSerialNumber(nssDecodedCert *dc,
447 NSSDER *serial, NSSArena *arena)
449 CERTCertificate *cc = (CERTCertificate *)dc->data;
450 SECItem derSerial = { 0 };
451 SECStatus secrv;
452 secrv = CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial);
453 if (secrv == SECSuccess) {
454 (void)nssItem_Create(arena, serial, derSerial.len, derSerial.data);
455 PORT_Free(derSerial.data);
456 return PR_SUCCESS;
458 return PR_FAILURE;
461 /* Returns NULL if "encoding" cannot be decoded. */
462 NSS_IMPLEMENT nssDecodedCert *
463 nssDecodedPKIXCertificate_Create (
464 NSSArena *arenaOpt,
465 NSSDER *encoding
468 nssDecodedCert *rvDC = NULL;
469 CERTCertificate *cert;
470 SECItem secDER;
472 SECITEM_FROM_NSSITEM(&secDER, encoding);
473 cert = CERT_DecodeDERCertificate(&secDER, PR_TRUE, NULL);
474 if (cert) {
475 rvDC = nss_ZNEW(arenaOpt, nssDecodedCert);
476 if (rvDC) {
477 rvDC->type = NSSCertificateType_PKIX;
478 rvDC->data = (void *)cert;
479 rvDC->getIdentifier = nss3certificate_getIdentifier;
480 rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier;
481 rvDC->matchIdentifier = nss3certificate_matchIdentifier;
482 rvDC->isValidIssuer = nss3certificate_isValidIssuer;
483 rvDC->getUsage = nss3certificate_getUsage;
484 rvDC->isValidAtTime = nss3certificate_isValidAtTime;
485 rvDC->isNewerThan = nss3certificate_isNewerThan;
486 rvDC->matchUsage = nss3certificate_matchUsage;
487 rvDC->getEmailAddress = nss3certificate_getEmailAddress;
488 rvDC->getDERSerialNumber = nss3certificate_getDERSerialNumber;
489 } else {
490 CERT_DestroyCertificate(cert);
493 return rvDC;
496 static nssDecodedCert *
497 create_decoded_pkix_cert_from_nss3cert (
498 NSSArena *arenaOpt,
499 CERTCertificate *cc
502 nssDecodedCert *rvDC = nss_ZNEW(arenaOpt, nssDecodedCert);
503 if (rvDC) {
504 rvDC->type = NSSCertificateType_PKIX;
505 rvDC->data = (void *)cc;
506 rvDC->getIdentifier = nss3certificate_getIdentifier;
507 rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier;
508 rvDC->matchIdentifier = nss3certificate_matchIdentifier;
509 rvDC->isValidIssuer = nss3certificate_isValidIssuer;
510 rvDC->getUsage = nss3certificate_getUsage;
511 rvDC->isValidAtTime = nss3certificate_isValidAtTime;
512 rvDC->isNewerThan = nss3certificate_isNewerThan;
513 rvDC->matchUsage = nss3certificate_matchUsage;
514 rvDC->getEmailAddress = nss3certificate_getEmailAddress;
516 return rvDC;
519 NSS_IMPLEMENT PRStatus
520 nssDecodedPKIXCertificate_Destroy (
521 nssDecodedCert *dc
524 CERTCertificate *cert = (CERTCertificate *)dc->data;
526 /* The decoder may only be half initialized (the case where we find we
527 * could not decode the certificate). In this case, there is not cert to
528 * free, just free the dc structure. */
529 if (cert) {
530 PRBool freeSlot = cert->ownSlot;
531 PK11SlotInfo *slot = cert->slot;
532 PRArenaPool *arena = cert->arena;
533 /* zero cert before freeing. Any stale references to this cert
534 * after this point will probably cause an exception. */
535 PORT_Memset(cert, 0, sizeof *cert);
536 /* free the arena that contains the cert. */
537 PORT_FreeArena(arena, PR_FALSE);
538 if (slot && freeSlot) {
539 PK11_FreeSlot(slot);
542 nss_ZFreeIf(dc);
543 return PR_SUCCESS;
546 /* see pk11cert.c:pk11_HandleTrustObject */
547 static unsigned int
548 get_nss3trust_from_nss4trust(CK_TRUST t)
550 unsigned int rt = 0;
551 if (t == nssTrustLevel_Trusted) {
552 rt |= CERTDB_VALID_PEER | CERTDB_TRUSTED;
554 if (t == nssTrustLevel_TrustedDelegator) {
555 rt |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA /*| CERTDB_NS_TRUSTED_CA*/;
557 if (t == nssTrustLevel_Valid) {
558 rt |= CERTDB_VALID_PEER;
560 if (t == nssTrustLevel_ValidDelegator) {
561 rt |= CERTDB_VALID_CA;
563 return rt;
566 static CERTCertTrust *
567 cert_trust_from_stan_trust(NSSTrust *t, PRArenaPool *arena)
569 CERTCertTrust *rvTrust;
570 unsigned int client;
571 if (!t) {
572 return NULL;
574 rvTrust = PORT_ArenaAlloc(arena, sizeof(CERTCertTrust));
575 if (!rvTrust) return NULL;
576 rvTrust->sslFlags = get_nss3trust_from_nss4trust(t->serverAuth);
577 client = get_nss3trust_from_nss4trust(t->clientAuth);
578 if (client & (CERTDB_TRUSTED_CA|CERTDB_NS_TRUSTED_CA)) {
579 client &= ~(CERTDB_TRUSTED_CA|CERTDB_NS_TRUSTED_CA);
580 rvTrust->sslFlags |= CERTDB_TRUSTED_CLIENT_CA;
582 rvTrust->sslFlags |= client;
583 rvTrust->emailFlags = get_nss3trust_from_nss4trust(t->emailProtection);
584 rvTrust->objectSigningFlags = get_nss3trust_from_nss4trust(t->codeSigning);
585 /* The cert is a valid step-up cert (in addition to/lieu of trust above */
586 if (t->stepUpApproved) {
587 rvTrust->sslFlags |= CERTDB_GOVT_APPROVED_CA;
589 return rvTrust;
592 CERTCertTrust *
593 nssTrust_GetCERTCertTrustForCert(NSSCertificate *c, CERTCertificate *cc)
595 CERTCertTrust *rvTrust = NULL;
596 NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
597 NSSTrust *t;
598 t = nssTrustDomain_FindTrustForCertificate(td, c);
599 if (t) {
600 rvTrust = cert_trust_from_stan_trust(t, cc->arena);
601 if (!rvTrust) {
602 nssTrust_Destroy(t);
603 return NULL;
605 nssTrust_Destroy(t);
606 } else {
607 rvTrust = PORT_ArenaAlloc(cc->arena, sizeof(CERTCertTrust));
608 if (!rvTrust) {
609 return NULL;
611 memset(rvTrust, 0, sizeof(*rvTrust));
613 if (NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL)) {
614 rvTrust->sslFlags |= CERTDB_USER;
615 rvTrust->emailFlags |= CERTDB_USER;
616 rvTrust->objectSigningFlags |= CERTDB_USER;
618 return rvTrust;
621 static nssCryptokiInstance *
622 get_cert_instance(NSSCertificate *c)
624 nssCryptokiObject *instance, **ci;
625 nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
626 if (!instances) {
627 return NULL;
629 instance = NULL;
630 for (ci = instances; *ci; ci++) {
631 if (!instance) {
632 instance = nssCryptokiObject_Clone(*ci);
633 } else {
634 /* This only really works for two instances... But 3.4 can't
635 * handle more anyway. The logic is, if there are multiple
636 * instances, prefer the one that is not internal (e.g., on
637 * a hardware device.
639 if (PK11_IsInternal(instance->token->pk11slot)) {
640 nssCryptokiObject_Destroy(instance);
641 instance = nssCryptokiObject_Clone(*ci);
645 nssCryptokiObjectArray_Destroy(instances);
646 return instance;
649 char *
650 STAN_GetCERTCertificateNameForInstance (
651 PLArenaPool *arenaOpt,
652 NSSCertificate *c,
653 nssCryptokiInstance *instance
656 NSSCryptoContext *context = c->object.cryptoContext;
657 PRStatus nssrv;
658 int nicklen, tokenlen, len;
659 NSSUTF8 *tokenName = NULL;
660 NSSUTF8 *stanNick = NULL;
661 char *nickname = NULL;
662 char *nick;
664 if (instance) {
665 stanNick = instance->label;
666 } else if (context) {
667 stanNick = c->object.tempName;
669 if (stanNick) {
670 /* fill other fields needed by NSS3 functions using CERTCertificate */
671 if (instance && (!PK11_IsInternal(instance->token->pk11slot) ||
672 PORT_Strchr(stanNick, ':') != NULL) ) {
673 tokenName = nssToken_GetName(instance->token);
674 tokenlen = nssUTF8_Size(tokenName, &nssrv);
675 } else {
676 /* don't use token name for internal slot; 3.3 didn't */
677 tokenlen = 0;
679 nicklen = nssUTF8_Size(stanNick, &nssrv);
680 len = tokenlen + nicklen;
681 if (arenaOpt) {
682 nickname = PORT_ArenaAlloc(arenaOpt, len);
683 } else {
684 nickname = PORT_Alloc(len);
686 nick = nickname;
687 if (tokenName) {
688 memcpy(nick, tokenName, tokenlen-1);
689 nick += tokenlen-1;
690 *nick++ = ':';
692 memcpy(nick, stanNick, nicklen-1);
693 nickname[len-1] = '\0';
695 return nickname;
698 char *
699 STAN_GetCERTCertificateName(PLArenaPool *arenaOpt, NSSCertificate *c)
701 char * result;
702 nssCryptokiInstance *instance = get_cert_instance(c);
703 /* It's OK to call this function, even if instance is NULL */
704 result = STAN_GetCERTCertificateNameForInstance(arenaOpt, c, instance);
705 if (instance)
706 nssCryptokiObject_Destroy(instance);
707 return result;
710 static void
711 fill_CERTCertificateFields(NSSCertificate *c, CERTCertificate *cc, PRBool forced)
713 CERTCertTrust* trust = NULL;
714 NSSTrust *nssTrust;
715 NSSCryptoContext *context = c->object.cryptoContext;
716 nssCryptokiInstance *instance;
717 NSSUTF8 *stanNick = NULL;
719 /* We are holding the base class object's lock on entry of this function
720 * This lock protects writes to fields of the CERTCertificate .
721 * It is also needed by some functions to compute values such as trust.
723 instance = get_cert_instance(c);
725 if (instance) {
726 stanNick = instance->label;
727 } else if (context) {
728 stanNick = c->object.tempName;
730 /* fill other fields needed by NSS3 functions using CERTCertificate */
731 if ((!cc->nickname && stanNick) || forced) {
732 PRStatus nssrv;
733 int nicklen, tokenlen, len;
734 NSSUTF8 *tokenName = NULL;
735 char *nick;
736 if (instance &&
737 (!PK11_IsInternal(instance->token->pk11slot) ||
738 (stanNick && PORT_Strchr(stanNick, ':') != NULL))) {
739 tokenName = nssToken_GetName(instance->token);
740 tokenlen = nssUTF8_Size(tokenName, &nssrv);
741 } else {
742 /* don't use token name for internal slot; 3.3 didn't */
743 tokenlen = 0;
745 if (stanNick) {
746 nicklen = nssUTF8_Size(stanNick, &nssrv);
747 len = tokenlen + nicklen;
748 nick = PORT_ArenaAlloc(cc->arena, len);
749 if (tokenName) {
750 memcpy(nick, tokenName, tokenlen-1);
751 nick[tokenlen-1] = ':';
752 memcpy(nick+tokenlen, stanNick, nicklen-1);
753 } else {
754 memcpy(nick, stanNick, nicklen-1);
756 nick[len-1] = '\0';
757 cc->nickname = nick;
758 } else {
759 cc->nickname = NULL;
762 if (context) {
763 /* trust */
764 nssTrust = nssCryptoContext_FindTrustForCertificate(context, c);
765 if (nssTrust) {
766 trust = cert_trust_from_stan_trust(nssTrust, cc->arena);
767 if (trust) {
768 /* we should destroy cc->trust before replacing it, but it's
769 allocated in cc->arena, so memory growth will occur on each
770 refresh */
771 cc->trust = trust;
773 nssTrust_Destroy(nssTrust);
775 } else if (instance) {
776 /* slot */
777 if (cc->slot != instance->token->pk11slot) {
778 if (cc->slot) {
779 PK11_FreeSlot(cc->slot);
781 cc->slot = PK11_ReferenceSlot(instance->token->pk11slot);
783 cc->ownSlot = PR_TRUE;
784 /* pkcs11ID */
785 cc->pkcs11ID = instance->handle;
786 /* trust */
787 trust = nssTrust_GetCERTCertTrustForCert(c, cc);
788 if (trust) {
789 /* we should destroy cc->trust before replacing it, but it's
790 allocated in cc->arena, so memory growth will occur on each
791 refresh */
792 cc->trust = trust;
794 nssCryptokiObject_Destroy(instance);
796 /* database handle is now the trust domain */
797 cc->dbhandle = c->object.trustDomain;
798 /* subjectList ? */
799 /* istemp and isperm are supported in NSS 3.4 */
800 cc->istemp = PR_FALSE; /* CERT_NewTemp will override this */
801 cc->isperm = PR_TRUE; /* by default */
802 /* pointer back */
803 cc->nssCertificate = c;
804 if (trust) {
805 /* force the cert type to be recomputed to include trust info */
806 PRUint32 nsCertType = cert_ComputeCertType(cc);
808 /* Assert that it is safe to cast &cc->nsCertType to "PRInt32 *" */
809 PORT_Assert(sizeof(cc->nsCertType) == sizeof(PRInt32));
810 PR_AtomicSet((PRInt32 *)&cc->nsCertType, nsCertType);
814 static CERTCertificate *
815 stan_GetCERTCertificate(NSSCertificate *c, PRBool forceUpdate)
817 nssDecodedCert *dc = NULL;
818 CERTCertificate *cc = NULL;
820 nssPKIObject_Lock(&c->object);
822 dc = c->decoding;
823 if (!dc) {
824 dc = nssDecodedPKIXCertificate_Create(NULL, &c->encoding);
825 if (!dc) {
826 goto loser;
828 cc = (CERTCertificate *)dc->data;
829 PORT_Assert(cc); /* software error */
830 if (!cc) {
831 nssDecodedPKIXCertificate_Destroy(dc);
832 nss_SetError(NSS_ERROR_INTERNAL_ERROR);
833 goto loser;
835 PORT_Assert(!c->decoding);
836 if (!c->decoding) {
837 c->decoding = dc;
838 } else {
839 /* this should never happen. Fail. */
840 nssDecodedPKIXCertificate_Destroy(dc);
841 nss_SetError(NSS_ERROR_INTERNAL_ERROR);
842 goto loser;
845 cc = (CERTCertificate *)dc->data;
846 PORT_Assert(cc);
847 if (!cc) {
848 nss_SetError(NSS_ERROR_INTERNAL_ERROR);
849 goto loser;
851 if (!cc->nssCertificate || forceUpdate) {
852 fill_CERTCertificateFields(c, cc, forceUpdate);
853 } else if (!cc->trust && !c->object.cryptoContext) {
854 /* if it's a perm cert, it might have been stored before the
855 * trust, so look for the trust again. But a temp cert can be
856 * ignored.
858 CERTCertTrust* trust = NULL;
859 trust = nssTrust_GetCERTCertTrustForCert(c, cc);
860 cc->trust = trust;
863 loser:
864 nssPKIObject_Unlock(&c->object);
865 return cc;
868 NSS_IMPLEMENT CERTCertificate *
869 STAN_ForceCERTCertificateUpdate(NSSCertificate *c)
871 if (c->decoding) {
872 return stan_GetCERTCertificate(c, PR_TRUE);
874 return NULL;
877 NSS_IMPLEMENT CERTCertificate *
878 STAN_GetCERTCertificate(NSSCertificate *c)
880 return stan_GetCERTCertificate(c, PR_FALSE);
883 * many callers of STAN_GetCERTCertificate() intend that
884 * the CERTCertificate returned inherits the reference to the
885 * NSSCertificate. For these callers it's convenient to have
886 * this function 'own' the reference and either return a valid
887 * CERTCertificate structure which inherits the reference or
888 * destroy the reference to NSSCertificate and returns NULL.
890 NSS_IMPLEMENT CERTCertificate *
891 STAN_GetCERTCertificateOrRelease(NSSCertificate *c)
893 CERTCertificate *nss3cert = stan_GetCERTCertificate(c, PR_FALSE);
894 if (!nss3cert) {
895 nssCertificate_Destroy(c);
897 return nss3cert;
900 static nssTrustLevel
901 get_stan_trust(unsigned int t, PRBool isClientAuth)
903 if (isClientAuth) {
904 if (t & CERTDB_TRUSTED_CLIENT_CA) {
905 return nssTrustLevel_TrustedDelegator;
907 } else {
908 if (t & CERTDB_TRUSTED_CA || t & CERTDB_NS_TRUSTED_CA) {
909 return nssTrustLevel_TrustedDelegator;
912 if (t & CERTDB_TRUSTED) {
913 return nssTrustLevel_Trusted;
915 if (t & CERTDB_VALID_CA) {
916 return nssTrustLevel_ValidDelegator;
918 if (t & CERTDB_VALID_PEER) {
919 return nssTrustLevel_Valid;
921 return nssTrustLevel_NotTrusted;
924 NSS_EXTERN NSSCertificate *
925 STAN_GetNSSCertificate(CERTCertificate *cc)
927 NSSCertificate *c;
928 nssCryptokiInstance *instance;
929 nssPKIObject *pkiob;
930 NSSArena *arena;
931 c = cc->nssCertificate;
932 if (c) {
933 return c;
935 /* i don't think this should happen. but if it can, need to create
936 * NSSCertificate from CERTCertificate values here. */
937 /* Yup, it can happen. */
938 arena = NSSArena_Create();
939 if (!arena) {
940 return NULL;
942 c = nss_ZNEW(arena, NSSCertificate);
943 if (!c) {
944 nssArena_Destroy(arena);
945 return NULL;
947 NSSITEM_FROM_SECITEM(&c->encoding, &cc->derCert);
948 c->type = NSSCertificateType_PKIX;
949 pkiob = nssPKIObject_Create(arena, NULL, cc->dbhandle, NULL, nssPKIMonitor);
950 if (!pkiob) {
951 nssArena_Destroy(arena);
952 return NULL;
954 c->object = *pkiob;
955 nssItem_Create(arena,
956 &c->issuer, cc->derIssuer.len, cc->derIssuer.data);
957 nssItem_Create(arena,
958 &c->subject, cc->derSubject.len, cc->derSubject.data);
959 if (PR_TRUE) {
960 /* CERTCertificate stores serial numbers decoded. I need the DER
961 * here. sigh.
963 SECItem derSerial;
964 SECStatus secrv;
965 secrv = CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial);
966 if (secrv == SECFailure) {
967 nssArena_Destroy(arena);
968 return NULL;
970 nssItem_Create(arena, &c->serial, derSerial.len, derSerial.data);
971 PORT_Free(derSerial.data);
973 if (cc->emailAddr && cc->emailAddr[0]) {
974 c->email = nssUTF8_Create(arena,
975 nssStringType_PrintableString,
976 (NSSUTF8 *)cc->emailAddr,
977 PORT_Strlen(cc->emailAddr));
979 if (cc->slot) {
980 instance = nss_ZNEW(arena, nssCryptokiInstance);
981 if (!instance) {
982 nssArena_Destroy(arena);
983 return NULL;
985 instance->token = nssToken_AddRef(PK11Slot_GetNSSToken(cc->slot));
986 instance->handle = cc->pkcs11ID;
987 instance->isTokenObject = PR_TRUE;
988 if (cc->nickname) {
989 instance->label = nssUTF8_Create(arena,
990 nssStringType_UTF8String,
991 (NSSUTF8 *)cc->nickname,
992 PORT_Strlen(cc->nickname));
994 nssPKIObject_AddInstance(&c->object, instance);
996 c->decoding = create_decoded_pkix_cert_from_nss3cert(NULL, cc);
997 cc->nssCertificate = c;
998 return c;
1001 static NSSToken*
1002 stan_GetTrustToken (
1003 NSSCertificate *c
1006 NSSToken *ttok = NULL;
1007 NSSToken *rtok = NULL;
1008 NSSToken *tok = NULL;
1009 nssCryptokiObject **ip;
1010 nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
1011 if (!instances) {
1012 return PR_FALSE;
1014 for (ip = instances; *ip; ip++) {
1015 nssCryptokiObject *instance = *ip;
1016 nssCryptokiObject *to =
1017 nssToken_FindTrustForCertificate(instance->token, NULL,
1018 &c->encoding, &c->issuer, &c->serial,
1019 nssTokenSearchType_TokenOnly);
1020 NSSToken *ctok = instance->token;
1021 PRBool ro = PK11_IsReadOnly(ctok->pk11slot);
1023 if (to) {
1024 nssCryptokiObject_Destroy(to);
1025 ttok = ctok;
1026 if (!ro) {
1027 break;
1029 } else {
1030 if (!rtok && ro) {
1031 rtok = ctok;
1033 if (!tok && !ro) {
1034 tok = ctok;
1038 nssCryptokiObjectArray_Destroy(instances);
1039 return ttok ? ttok : (tok ? tok : rtok);
1042 NSS_EXTERN PRStatus
1043 STAN_ChangeCertTrust(CERTCertificate *cc, CERTCertTrust *trust)
1045 PRStatus nssrv;
1046 NSSCertificate *c = STAN_GetNSSCertificate(cc);
1047 NSSToken *tok;
1048 NSSTrustDomain *td;
1049 NSSTrust *nssTrust;
1050 NSSArena *arena;
1051 CERTCertTrust *oldTrust;
1052 nssListIterator *tokens;
1053 PRBool moving_object;
1054 nssCryptokiObject *newInstance;
1055 nssPKIObject *pkiob;
1057 if (c == NULL) {
1058 return SECFailure;
1060 oldTrust = nssTrust_GetCERTCertTrustForCert(c, cc);
1061 if (oldTrust) {
1062 if (memcmp(oldTrust, trust, sizeof (CERTCertTrust)) == 0) {
1063 /* ... and the new trust is no different, done) */
1064 return PR_SUCCESS;
1065 } else {
1066 /* take over memory already allocated in cc's arena */
1067 cc->trust = oldTrust;
1069 } else {
1070 cc->trust = PORT_ArenaAlloc(cc->arena, sizeof(CERTCertTrust));
1072 memcpy(cc->trust, trust, sizeof(CERTCertTrust));
1073 /* Set the NSSCerticate's trust */
1074 arena = nssArena_Create();
1075 if (!arena) return PR_FAILURE;
1076 nssTrust = nss_ZNEW(arena, NSSTrust);
1077 if (!nssTrust) {
1078 nssArena_Destroy(arena);
1079 return PR_FAILURE;
1081 pkiob = nssPKIObject_Create(arena, NULL, cc->dbhandle, NULL, nssPKILock);
1082 if (!pkiob) {
1083 nssArena_Destroy(arena);
1084 return PR_FAILURE;
1086 nssTrust->object = *pkiob;
1087 nssTrust->certificate = c;
1088 nssTrust->serverAuth = get_stan_trust(trust->sslFlags, PR_FALSE);
1089 nssTrust->clientAuth = get_stan_trust(trust->sslFlags, PR_TRUE);
1090 nssTrust->emailProtection = get_stan_trust(trust->emailFlags, PR_FALSE);
1091 nssTrust->codeSigning = get_stan_trust(trust->objectSigningFlags, PR_FALSE);
1092 nssTrust->stepUpApproved =
1093 (PRBool)(trust->sslFlags & CERTDB_GOVT_APPROVED_CA);
1094 if (c->object.cryptoContext != NULL) {
1095 /* The cert is in a context, set the trust there */
1096 NSSCryptoContext *cc = c->object.cryptoContext;
1097 nssrv = nssCryptoContext_ImportTrust(cc, nssTrust);
1098 if (nssrv != PR_SUCCESS) {
1099 goto done;
1101 if (c->object.numInstances == 0) {
1102 /* The context is the only instance, finished */
1103 goto done;
1106 td = STAN_GetDefaultTrustDomain();
1107 tok = stan_GetTrustToken(c);
1108 moving_object = PR_FALSE;
1109 if (tok && PK11_IsReadOnly(tok->pk11slot)) {
1110 NSSRWLock_LockRead(td->tokensLock);
1111 tokens = nssList_CreateIterator(td->tokenList);
1112 if (!tokens) {
1113 nssrv = PR_FAILURE;
1114 NSSRWLock_UnlockRead(td->tokensLock);
1115 goto done;
1117 for (tok = (NSSToken *)nssListIterator_Start(tokens);
1118 tok != (NSSToken *)NULL;
1119 tok = (NSSToken *)nssListIterator_Next(tokens))
1121 if (!PK11_IsReadOnly(tok->pk11slot)) break;
1123 nssListIterator_Finish(tokens);
1124 nssListIterator_Destroy(tokens);
1125 NSSRWLock_UnlockRead(td->tokensLock);
1126 moving_object = PR_TRUE;
1128 if (tok) {
1129 if (moving_object) {
1130 /* this is kind of hacky. the softoken needs the cert
1131 * object in order to store trust. forcing it to be perm
1133 NSSUTF8 *nickname = nssCertificate_GetNickname(c, NULL);
1134 NSSASCII7 *email = NULL;
1136 if (PK11_IsInternal(tok->pk11slot)) {
1137 email = c->email;
1139 newInstance = nssToken_ImportCertificate(tok, NULL,
1140 NSSCertificateType_PKIX,
1141 &c->id,
1142 nickname,
1143 &c->encoding,
1144 &c->issuer,
1145 &c->subject,
1146 &c->serial,
1147 email,
1148 PR_TRUE);
1149 if (!newInstance) {
1150 nssrv = PR_FAILURE;
1151 goto done;
1153 nssPKIObject_AddInstance(&c->object, newInstance);
1155 newInstance = nssToken_ImportTrust(tok, NULL, &c->encoding,
1156 &c->issuer, &c->serial,
1157 nssTrust->serverAuth,
1158 nssTrust->clientAuth,
1159 nssTrust->codeSigning,
1160 nssTrust->emailProtection,
1161 nssTrust->stepUpApproved, PR_TRUE);
1162 /* If the selected token can't handle trust, dump the trust on
1163 * the internal token */
1164 if (!newInstance && !PK11_IsInternal(tok->pk11slot)) {
1165 PK11SlotInfo *slot = PK11_GetInternalKeySlot();
1166 NSSUTF8 *nickname = nssCertificate_GetNickname(c, NULL);
1167 NSSASCII7 *email = c->email;
1168 tok = PK11Slot_GetNSSToken(slot);
1169 PK11_FreeSlot(slot);
1171 newInstance = nssToken_ImportCertificate(tok, NULL,
1172 NSSCertificateType_PKIX,
1173 &c->id,
1174 nickname,
1175 &c->encoding,
1176 &c->issuer,
1177 &c->subject,
1178 &c->serial,
1179 email,
1180 PR_TRUE);
1181 if (!newInstance) {
1182 nssrv = PR_FAILURE;
1183 goto done;
1185 nssPKIObject_AddInstance(&c->object, newInstance);
1186 newInstance = nssToken_ImportTrust(tok, NULL, &c->encoding,
1187 &c->issuer, &c->serial,
1188 nssTrust->serverAuth,
1189 nssTrust->clientAuth,
1190 nssTrust->codeSigning,
1191 nssTrust->emailProtection,
1192 nssTrust->stepUpApproved, PR_TRUE);
1194 if (newInstance) {
1195 nssCryptokiObject_Destroy(newInstance);
1196 nssrv = PR_SUCCESS;
1197 } else {
1198 nssrv = PR_FAILURE;
1200 } else {
1201 nssrv = PR_FAILURE;
1203 done:
1204 (void)nssTrust_Destroy(nssTrust);
1205 return nssrv;
1208 /* CERT_TraversePermCertsForSubject */
1209 NSS_IMPLEMENT PRStatus
1210 nssTrustDomain_TraverseCertificatesBySubject (
1211 NSSTrustDomain *td,
1212 NSSDER *subject,
1213 PRStatus (*callback)(NSSCertificate *c, void *arg),
1214 void *arg
1217 PRStatus nssrv = PR_SUCCESS;
1218 NSSArena *tmpArena;
1219 NSSCertificate **subjectCerts;
1220 NSSCertificate *c;
1221 PRIntn i;
1222 tmpArena = NSSArena_Create();
1223 if (!tmpArena) {
1224 return PR_FAILURE;
1226 subjectCerts = NSSTrustDomain_FindCertificatesBySubject(td, subject, NULL,
1227 0, tmpArena);
1228 if (subjectCerts) {
1229 for (i=0, c = subjectCerts[i]; c; i++) {
1230 nssrv = callback(c, arg);
1231 if (nssrv != PR_SUCCESS) break;
1234 nssArena_Destroy(tmpArena);
1235 return nssrv;
1238 /* CERT_TraversePermCertsForNickname */
1239 NSS_IMPLEMENT PRStatus
1240 nssTrustDomain_TraverseCertificatesByNickname (
1241 NSSTrustDomain *td,
1242 NSSUTF8 *nickname,
1243 PRStatus (*callback)(NSSCertificate *c, void *arg),
1244 void *arg
1247 PRStatus nssrv = PR_SUCCESS;
1248 NSSArena *tmpArena;
1249 NSSCertificate **nickCerts;
1250 NSSCertificate *c;
1251 PRIntn i;
1252 tmpArena = NSSArena_Create();
1253 if (!tmpArena) {
1254 return PR_FAILURE;
1256 nickCerts = NSSTrustDomain_FindCertificatesByNickname(td, nickname, NULL,
1257 0, tmpArena);
1258 if (nickCerts) {
1259 for (i=0, c = nickCerts[i]; c; i++) {
1260 nssrv = callback(c, arg);
1261 if (nssrv != PR_SUCCESS) break;
1264 nssArena_Destroy(tmpArena);
1265 return nssrv;
1268 static void cert_dump_iter(const void *k, void *v, void *a)
1270 NSSCertificate *c = (NSSCertificate *)k;
1271 CERTCertificate *cert = STAN_GetCERTCertificate(c);
1272 printf("[%2d] \"%s\"\n", c->object.refCount, cert->subjectName);
1275 void
1276 nss_DumpCertificateCacheInfo()
1278 NSSTrustDomain *td;
1279 NSSCryptoContext *cc;
1280 td = STAN_GetDefaultTrustDomain();
1281 cc = STAN_GetDefaultCryptoContext();
1282 printf("\n\nCertificates in the cache:\n");
1283 nssTrustDomain_DumpCacheInfo(td, cert_dump_iter, NULL);
1284 printf("\n\nCertificates in the temporary store:\n");
1285 if (cc->certStore) {
1286 nssCertificateStore_DumpStoreInfo(cc->certStore, cert_dump_iter, NULL);