security/nss/lib/pki/pki3hack.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * Hacks to integrate NSS 3.4 and NSS 4.0 certificates.
michael@0 7 */
michael@0 8
michael@0 9 #ifndef NSSPKI_H
michael@0 10 #include "nsspki.h"
michael@0 11 #endif /* NSSPKI_H */
michael@0 12
michael@0 13 #ifndef PKI_H
michael@0 14 #include "pki.h"
michael@0 15 #endif /* PKI_H */
michael@0 16
michael@0 17 #ifndef PKIM_H
michael@0 18 #include "pkim.h"
michael@0 19 #endif /* PKIM_H */
michael@0 20
michael@0 21 #ifndef DEV_H
michael@0 22 #include "dev.h"
michael@0 23 #endif /* DEV_H */
michael@0 24
michael@0 25 #ifndef DEVNSS3HACK_H
michael@0 26 #include "dev3hack.h"
michael@0 27 #endif /* DEVNSS3HACK_H */
michael@0 28
michael@0 29 #ifndef PKINSS3HACK_H
michael@0 30 #include "pki3hack.h"
michael@0 31 #endif /* PKINSS3HACK_H */
michael@0 32
michael@0 33 #include "secitem.h"
michael@0 34 #include "certdb.h"
michael@0 35 #include "certt.h"
michael@0 36 #include "cert.h"
michael@0 37 #include "certi.h"
michael@0 38 #include "pk11func.h"
michael@0 39 #include "pkistore.h"
michael@0 40 #include "secmod.h"
michael@0 41 #include "nssrwlk.h"
michael@0 42
michael@0 43 NSSTrustDomain *g_default_trust_domain = NULL;
michael@0 44
michael@0 45 NSSCryptoContext *g_default_crypto_context = NULL;
michael@0 46
michael@0 47 NSSTrustDomain *
michael@0 48 STAN_GetDefaultTrustDomain()
michael@0 49 {
michael@0 50 return g_default_trust_domain;
michael@0 51 }
michael@0 52
michael@0 53 NSSCryptoContext *
michael@0 54 STAN_GetDefaultCryptoContext()
michael@0 55 {
michael@0 56 return g_default_crypto_context;
michael@0 57 }
michael@0 58
michael@0 59 extern const NSSError NSS_ERROR_ALREADY_INITIALIZED;
michael@0 60 extern const NSSError NSS_ERROR_INTERNAL_ERROR;
michael@0 61
michael@0 62 NSS_IMPLEMENT PRStatus
michael@0 63 STAN_InitTokenForSlotInfo(NSSTrustDomain *td, PK11SlotInfo *slot)
michael@0 64 {
michael@0 65 NSSToken *token;
michael@0 66 if (!td) {
michael@0 67 td = g_default_trust_domain;
michael@0 68 if (!td) {
michael@0 69 /* we're called while still initting. slot will get added
michael@0 70 * appropriately through normal init processes */
michael@0 71 return PR_SUCCESS;
michael@0 72 }
michael@0 73 }
michael@0 74 token = nssToken_CreateFromPK11SlotInfo(td, slot);
michael@0 75 PK11Slot_SetNSSToken(slot, token);
michael@0 76 /* Don't add nonexistent token to TD's token list */
michael@0 77 if (token) {
michael@0 78 NSSRWLock_LockWrite(td->tokensLock);
michael@0 79 nssList_Add(td->tokenList, token);
michael@0 80 NSSRWLock_UnlockWrite(td->tokensLock);
michael@0 81 }
michael@0 82 return PR_SUCCESS;
michael@0 83 }
michael@0 84
michael@0 85 NSS_IMPLEMENT PRStatus
michael@0 86 STAN_ResetTokenInterator(NSSTrustDomain *td)
michael@0 87 {
michael@0 88 if (!td) {
michael@0 89 td = g_default_trust_domain;
michael@0 90 if (!td) {
michael@0 91 /* we're called while still initting. slot will get added
michael@0 92 * appropriately through normal init processes */
michael@0 93 return PR_SUCCESS;
michael@0 94 }
michael@0 95 }
michael@0 96 NSSRWLock_LockWrite(td->tokensLock);
michael@0 97 nssListIterator_Destroy(td->tokens);
michael@0 98 td->tokens = nssList_CreateIterator(td->tokenList);
michael@0 99 NSSRWLock_UnlockWrite(td->tokensLock);
michael@0 100 return PR_SUCCESS;
michael@0 101 }
michael@0 102
michael@0 103 NSS_IMPLEMENT PRStatus
michael@0 104 STAN_LoadDefaultNSS3TrustDomain (
michael@0 105 void
michael@0 106 )
michael@0 107 {
michael@0 108 NSSTrustDomain *td;
michael@0 109 SECMODModuleList *mlp;
michael@0 110 SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
michael@0 111 int i;
michael@0 112
michael@0 113 if (g_default_trust_domain || g_default_crypto_context) {
michael@0 114 /* Stan is already initialized or a previous shutdown failed. */
michael@0 115 nss_SetError(NSS_ERROR_ALREADY_INITIALIZED);
michael@0 116 return PR_FAILURE;
michael@0 117 }
michael@0 118 td = NSSTrustDomain_Create(NULL, NULL, NULL, NULL);
michael@0 119 if (!td) {
michael@0 120 return PR_FAILURE;
michael@0 121 }
michael@0 122 /*
michael@0 123 * Deadlock warning: we should never acquire the moduleLock while
michael@0 124 * we hold the tokensLock. We can use the NSSRWLock Rank feature to
michael@0 125 * guarrentee this. tokensLock have a higher rank than module lock.
michael@0 126 */
michael@0 127 td->tokenList = nssList_Create(td->arena, PR_TRUE);
michael@0 128 if (!td->tokenList) {
michael@0 129 goto loser;
michael@0 130 }
michael@0 131 SECMOD_GetReadLock(moduleLock);
michael@0 132 NSSRWLock_LockWrite(td->tokensLock);
michael@0 133 for (mlp = SECMOD_GetDefaultModuleList(); mlp != NULL; mlp=mlp->next) {
michael@0 134 for (i=0; i < mlp->module->slotCount; i++) {
michael@0 135 STAN_InitTokenForSlotInfo(td, mlp->module->slots[i]);
michael@0 136 }
michael@0 137 }
michael@0 138 td->tokens = nssList_CreateIterator(td->tokenList);
michael@0 139 NSSRWLock_UnlockWrite(td->tokensLock);
michael@0 140 SECMOD_ReleaseReadLock(moduleLock);
michael@0 141 if (!td->tokens) {
michael@0 142 goto loser;
michael@0 143 }
michael@0 144 g_default_crypto_context = NSSTrustDomain_CreateCryptoContext(td, NULL);
michael@0 145 if (!g_default_crypto_context) {
michael@0 146 goto loser;
michael@0 147 }
michael@0 148 g_default_trust_domain = td;
michael@0 149 return PR_SUCCESS;
michael@0 150
michael@0 151 loser:
michael@0 152 NSSTrustDomain_Destroy(td);
michael@0 153 return PR_FAILURE;
michael@0 154 }
michael@0 155
michael@0 156 /*
michael@0 157 * must be called holding the ModuleListLock (either read or write).
michael@0 158 */
michael@0 159 NSS_IMPLEMENT SECStatus
michael@0 160 STAN_AddModuleToDefaultTrustDomain (
michael@0 161 SECMODModule *module
michael@0 162 )
michael@0 163 {
michael@0 164 NSSTrustDomain *td;
michael@0 165 int i;
michael@0 166 td = STAN_GetDefaultTrustDomain();
michael@0 167 for (i=0; i<module->slotCount; i++) {
michael@0 168 STAN_InitTokenForSlotInfo(td, module->slots[i]);
michael@0 169 }
michael@0 170 STAN_ResetTokenInterator(td);
michael@0 171 return SECSuccess;
michael@0 172 }
michael@0 173
michael@0 174 /*
michael@0 175 * must be called holding the ModuleListLock (either read or write).
michael@0 176 */
michael@0 177 NSS_IMPLEMENT SECStatus
michael@0 178 STAN_RemoveModuleFromDefaultTrustDomain (
michael@0 179 SECMODModule *module
michael@0 180 )
michael@0 181 {
michael@0 182 NSSToken *token;
michael@0 183 NSSTrustDomain *td;
michael@0 184 int i;
michael@0 185 td = STAN_GetDefaultTrustDomain();
michael@0 186 NSSRWLock_LockWrite(td->tokensLock);
michael@0 187 for (i=0; i<module->slotCount; i++) {
michael@0 188 token = PK11Slot_GetNSSToken(module->slots[i]);
michael@0 189 if (token) {
michael@0 190 nssToken_NotifyCertsNotVisible(token);
michael@0 191 nssList_Remove(td->tokenList, token);
michael@0 192 PK11Slot_SetNSSToken(module->slots[i], NULL);
michael@0 193 nssToken_Destroy(token);
michael@0 194 }
michael@0 195 }
michael@0 196 nssListIterator_Destroy(td->tokens);
michael@0 197 td->tokens = nssList_CreateIterator(td->tokenList);
michael@0 198 NSSRWLock_UnlockWrite(td->tokensLock);
michael@0 199 return SECSuccess;
michael@0 200 }
michael@0 201
michael@0 202 NSS_IMPLEMENT PRStatus
michael@0 203 STAN_Shutdown()
michael@0 204 {
michael@0 205 PRStatus status = PR_SUCCESS;
michael@0 206 if (g_default_trust_domain) {
michael@0 207 if (NSSTrustDomain_Destroy(g_default_trust_domain) == PR_SUCCESS) {
michael@0 208 g_default_trust_domain = NULL;
michael@0 209 } else {
michael@0 210 status = PR_FAILURE;
michael@0 211 }
michael@0 212 }
michael@0 213 if (g_default_crypto_context) {
michael@0 214 if (NSSCryptoContext_Destroy(g_default_crypto_context) == PR_SUCCESS) {
michael@0 215 g_default_crypto_context = NULL;
michael@0 216 } else {
michael@0 217 status = PR_FAILURE;
michael@0 218 }
michael@0 219 }
michael@0 220 return status;
michael@0 221 }
michael@0 222
michael@0 223 /* this function should not be a hack; it will be needed in 4.0 (rename) */
michael@0 224 NSS_IMPLEMENT NSSItem *
michael@0 225 STAN_GetCertIdentifierFromDER(NSSArena *arenaOpt, NSSDER *der)
michael@0 226 {
michael@0 227 NSSItem *rvKey;
michael@0 228 SECItem secDER;
michael@0 229 SECItem secKey = { 0 };
michael@0 230 SECStatus secrv;
michael@0 231 PLArenaPool *arena;
michael@0 232
michael@0 233 SECITEM_FROM_NSSITEM(&secDER, der);
michael@0 234
michael@0 235 /* nss3 call uses nss3 arena's */
michael@0 236 arena = PORT_NewArena(256);
michael@0 237 if (!arena) {
michael@0 238 return NULL;
michael@0 239 }
michael@0 240 secrv = CERT_KeyFromDERCert(arena, &secDER, &secKey);
michael@0 241 if (secrv != SECSuccess) {
michael@0 242 return NULL;
michael@0 243 }
michael@0 244 rvKey = nssItem_Create(arenaOpt, NULL, secKey.len, (void *)secKey.data);
michael@0 245 PORT_FreeArena(arena,PR_FALSE);
michael@0 246 return rvKey;
michael@0 247 }
michael@0 248
michael@0 249 NSS_IMPLEMENT PRStatus
michael@0 250 nssPKIX509_GetIssuerAndSerialFromDER(NSSDER *der, NSSArena *arena,
michael@0 251 NSSDER *issuer, NSSDER *serial)
michael@0 252 {
michael@0 253 SECStatus secrv;
michael@0 254 SECItem derCert;
michael@0 255 SECItem derIssuer = { 0 };
michael@0 256 SECItem derSerial = { 0 };
michael@0 257 SECITEM_FROM_NSSITEM(&derCert, der);
michael@0 258 secrv = CERT_SerialNumberFromDERCert(&derCert, &derSerial);
michael@0 259 if (secrv != SECSuccess) {
michael@0 260 return PR_FAILURE;
michael@0 261 }
michael@0 262 (void)nssItem_Create(arena, serial, derSerial.len, derSerial.data);
michael@0 263 secrv = CERT_IssuerNameFromDERCert(&derCert, &derIssuer);
michael@0 264 if (secrv != SECSuccess) {
michael@0 265 PORT_Free(derSerial.data);
michael@0 266 return PR_FAILURE;
michael@0 267 }
michael@0 268 (void)nssItem_Create(arena, issuer, derIssuer.len, derIssuer.data);
michael@0 269 PORT_Free(derSerial.data);
michael@0 270 PORT_Free(derIssuer.data);
michael@0 271 return PR_SUCCESS;
michael@0 272 }
michael@0 273
michael@0 274 static NSSItem *
michael@0 275 nss3certificate_getIdentifier(nssDecodedCert *dc)
michael@0 276 {
michael@0 277 NSSItem *rvID;
michael@0 278 CERTCertificate *c = (CERTCertificate *)dc->data;
michael@0 279 rvID = nssItem_Create(NULL, NULL, c->certKey.len, c->certKey.data);
michael@0 280 return rvID;
michael@0 281 }
michael@0 282
michael@0 283 static void *
michael@0 284 nss3certificate_getIssuerIdentifier(nssDecodedCert *dc)
michael@0 285 {
michael@0 286 CERTCertificate *c = (CERTCertificate *)dc->data;
michael@0 287 return (void *)c->authKeyID;
michael@0 288 }
michael@0 289
michael@0 290 static nssCertIDMatch
michael@0 291 nss3certificate_matchIdentifier(nssDecodedCert *dc, void *id)
michael@0 292 {
michael@0 293 CERTCertificate *c = (CERTCertificate *)dc->data;
michael@0 294 CERTAuthKeyID *authKeyID = (CERTAuthKeyID *)id;
michael@0 295 SECItem skid;
michael@0 296 nssCertIDMatch match = nssCertIDMatch_Unknown;
michael@0 297
michael@0 298 /* keyIdentifier */
michael@0 299 if (authKeyID->keyID.len > 0 &&
michael@0 300 CERT_FindSubjectKeyIDExtension(c, &skid) == SECSuccess) {
michael@0 301 PRBool skiEqual;
michael@0 302 skiEqual = SECITEM_ItemsAreEqual(&authKeyID->keyID, &skid);
michael@0 303 PORT_Free(skid.data);
michael@0 304 if (skiEqual) {
michael@0 305 /* change the state to positive match, but keep going */
michael@0 306 match = nssCertIDMatch_Yes;
michael@0 307 } else {
michael@0 308 /* exit immediately on failure */
michael@0 309 return nssCertIDMatch_No;
michael@0 310 }
michael@0 311 }
michael@0 312
michael@0 313 /* issuer/serial (treated as pair) */
michael@0 314 if (authKeyID->authCertIssuer) {
michael@0 315 SECItem *caName = NULL;
michael@0 316 SECItem *caSN = &authKeyID->authCertSerialNumber;
michael@0 317
michael@0 318 caName = (SECItem *)CERT_GetGeneralNameByType(
michael@0 319 authKeyID->authCertIssuer,
michael@0 320 certDirectoryName, PR_TRUE);
michael@0 321 if (caName != NULL &&
michael@0 322 SECITEM_ItemsAreEqual(&c->derIssuer, caName) &&
michael@0 323 SECITEM_ItemsAreEqual(&c->serialNumber, caSN))
michael@0 324 {
michael@0 325 match = nssCertIDMatch_Yes;
michael@0 326 } else {
michael@0 327 match = nssCertIDMatch_Unknown;
michael@0 328 }
michael@0 329 }
michael@0 330 return match;
michael@0 331 }
michael@0 332
michael@0 333 static PRBool
michael@0 334 nss3certificate_isValidIssuer(nssDecodedCert *dc)
michael@0 335 {
michael@0 336 CERTCertificate *c = (CERTCertificate *)dc->data;
michael@0 337 unsigned int ignore;
michael@0 338 return CERT_IsCACert(c, &ignore);
michael@0 339 }
michael@0 340
michael@0 341 static NSSUsage *
michael@0 342 nss3certificate_getUsage(nssDecodedCert *dc)
michael@0 343 {
michael@0 344 /* CERTCertificate *c = (CERTCertificate *)dc->data; */
michael@0 345 return NULL;
michael@0 346 }
michael@0 347
michael@0 348 static PRBool
michael@0 349 nss3certificate_isValidAtTime(nssDecodedCert *dc, NSSTime *time)
michael@0 350 {
michael@0 351 SECCertTimeValidity validity;
michael@0 352 CERTCertificate *c = (CERTCertificate *)dc->data;
michael@0 353 validity = CERT_CheckCertValidTimes(c, NSSTime_GetPRTime(time), PR_TRUE);
michael@0 354 if (validity == secCertTimeValid) {
michael@0 355 return PR_TRUE;
michael@0 356 }
michael@0 357 return PR_FALSE;
michael@0 358 }
michael@0 359
michael@0 360 static PRBool
michael@0 361 nss3certificate_isNewerThan(nssDecodedCert *dc, nssDecodedCert *cmpdc)
michael@0 362 {
michael@0 363 /* I know this isn't right, but this is glue code anyway */
michael@0 364 if (cmpdc->type == dc->type) {
michael@0 365 CERTCertificate *certa = (CERTCertificate *)dc->data;
michael@0 366 CERTCertificate *certb = (CERTCertificate *)cmpdc->data;
michael@0 367 return CERT_IsNewer(certa, certb);
michael@0 368 }
michael@0 369 return PR_FALSE;
michael@0 370 }
michael@0 371
michael@0 372 /* CERT_FilterCertListByUsage */
michael@0 373 static PRBool
michael@0 374 nss3certificate_matchUsage(nssDecodedCert *dc, const NSSUsage *usage)
michael@0 375 {
michael@0 376 CERTCertificate *cc;
michael@0 377 unsigned int requiredKeyUsage = 0;
michael@0 378 unsigned int requiredCertType = 0;
michael@0 379 SECStatus secrv;
michael@0 380 PRBool match;
michael@0 381 PRBool ca;
michael@0 382
michael@0 383 /* This is for NSS 3.3 functions that do not specify a usage */
michael@0 384 if (usage->anyUsage) {
michael@0 385 return PR_TRUE;
michael@0 386 }
michael@0 387 ca = usage->nss3lookingForCA;
michael@0 388 secrv = CERT_KeyUsageAndTypeForCertUsage(usage->nss3usage, ca,
michael@0 389 &requiredKeyUsage,
michael@0 390 &requiredCertType);
michael@0 391 if (secrv != SECSuccess) {
michael@0 392 return PR_FALSE;
michael@0 393 }
michael@0 394 cc = (CERTCertificate *)dc->data;
michael@0 395 secrv = CERT_CheckKeyUsage(cc, requiredKeyUsage);
michael@0 396 match = (PRBool)(secrv == SECSuccess);
michael@0 397 if (match) {
michael@0 398 unsigned int certType = 0;
michael@0 399 if (ca) {
michael@0 400 (void)CERT_IsCACert(cc, &certType);
michael@0 401 } else {
michael@0 402 certType = cc->nsCertType;
michael@0 403 }
michael@0 404 if (!(certType & requiredCertType)) {
michael@0 405 match = PR_FALSE;
michael@0 406 }
michael@0 407 }
michael@0 408 return match;
michael@0 409 }
michael@0 410
michael@0 411 static PRBool
michael@0 412 nss3certificate_isTrustedForUsage(nssDecodedCert *dc, const NSSUsage *usage)
michael@0 413 {
michael@0 414 CERTCertificate *cc;
michael@0 415 PRBool ca;
michael@0 416 SECStatus secrv;
michael@0 417 unsigned int requiredFlags;
michael@0 418 unsigned int trustFlags;
michael@0 419 SECTrustType trustType;
michael@0 420 CERTCertTrust trust;
michael@0 421
michael@0 422 /* This is for NSS 3.3 functions that do not specify a usage */
michael@0 423 if (usage->anyUsage) {
michael@0 424 return PR_FALSE; /* XXX is this right? */
michael@0 425 }
michael@0 426 cc = (CERTCertificate *)dc->data;
michael@0 427 ca = usage->nss3lookingForCA;
michael@0 428 if (!ca) {
michael@0 429 PRBool trusted;
michael@0 430 unsigned int failedFlags;
michael@0 431 secrv = cert_CheckLeafTrust(cc, usage->nss3usage,
michael@0 432 &failedFlags, &trusted);
michael@0 433 return secrv == SECSuccess && trusted;
michael@0 434 }
michael@0 435 secrv = CERT_TrustFlagsForCACertUsage(usage->nss3usage, &requiredFlags,
michael@0 436 &trustType);
michael@0 437 if (secrv != SECSuccess) {
michael@0 438 return PR_FALSE;
michael@0 439 }
michael@0 440 secrv = CERT_GetCertTrust(cc, &trust);
michael@0 441 if (secrv != SECSuccess) {
michael@0 442 return PR_FALSE;
michael@0 443 }
michael@0 444 if (trustType == trustTypeNone) {
michael@0 445 /* normally trustTypeNone usages accept any of the given trust bits
michael@0 446 * being on as acceptable. */
michael@0 447 trustFlags = trust.sslFlags | trust.emailFlags |
michael@0 448 trust.objectSigningFlags;
michael@0 449 } else {
michael@0 450 trustFlags = SEC_GET_TRUST_FLAGS(&trust, trustType);
michael@0 451 }
michael@0 452 return (trustFlags & requiredFlags) == requiredFlags;
michael@0 453 }
michael@0 454
michael@0 455 static NSSASCII7 *
michael@0 456 nss3certificate_getEmailAddress(nssDecodedCert *dc)
michael@0 457 {
michael@0 458 CERTCertificate *cc = (CERTCertificate *)dc->data;
michael@0 459 return (cc && cc->emailAddr && cc->emailAddr[0])
michael@0 460 ? (NSSASCII7 *)cc->emailAddr : NULL;
michael@0 461 }
michael@0 462
michael@0 463 static PRStatus
michael@0 464 nss3certificate_getDERSerialNumber(nssDecodedCert *dc,
michael@0 465 NSSDER *serial, NSSArena *arena)
michael@0 466 {
michael@0 467 CERTCertificate *cc = (CERTCertificate *)dc->data;
michael@0 468 SECItem derSerial = { 0 };
michael@0 469 SECStatus secrv;
michael@0 470 secrv = CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial);
michael@0 471 if (secrv == SECSuccess) {
michael@0 472 (void)nssItem_Create(arena, serial, derSerial.len, derSerial.data);
michael@0 473 PORT_Free(derSerial.data);
michael@0 474 return PR_SUCCESS;
michael@0 475 }
michael@0 476 return PR_FAILURE;
michael@0 477 }
michael@0 478
michael@0 479 /* Returns NULL if "encoding" cannot be decoded. */
michael@0 480 NSS_IMPLEMENT nssDecodedCert *
michael@0 481 nssDecodedPKIXCertificate_Create (
michael@0 482 NSSArena *arenaOpt,
michael@0 483 NSSDER *encoding
michael@0 484 )
michael@0 485 {
michael@0 486 nssDecodedCert *rvDC = NULL;
michael@0 487 CERTCertificate *cert;
michael@0 488 SECItem secDER;
michael@0 489
michael@0 490 SECITEM_FROM_NSSITEM(&secDER, encoding);
michael@0 491 cert = CERT_DecodeDERCertificate(&secDER, PR_TRUE, NULL);
michael@0 492 if (cert) {
michael@0 493 rvDC = nss_ZNEW(arenaOpt, nssDecodedCert);
michael@0 494 if (rvDC) {
michael@0 495 rvDC->type = NSSCertificateType_PKIX;
michael@0 496 rvDC->data = (void *)cert;
michael@0 497 rvDC->getIdentifier = nss3certificate_getIdentifier;
michael@0 498 rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier;
michael@0 499 rvDC->matchIdentifier = nss3certificate_matchIdentifier;
michael@0 500 rvDC->isValidIssuer = nss3certificate_isValidIssuer;
michael@0 501 rvDC->getUsage = nss3certificate_getUsage;
michael@0 502 rvDC->isValidAtTime = nss3certificate_isValidAtTime;
michael@0 503 rvDC->isNewerThan = nss3certificate_isNewerThan;
michael@0 504 rvDC->matchUsage = nss3certificate_matchUsage;
michael@0 505 rvDC->isTrustedForUsage = nss3certificate_isTrustedForUsage;
michael@0 506 rvDC->getEmailAddress = nss3certificate_getEmailAddress;
michael@0 507 rvDC->getDERSerialNumber = nss3certificate_getDERSerialNumber;
michael@0 508 } else {
michael@0 509 CERT_DestroyCertificate(cert);
michael@0 510 }
michael@0 511 }
michael@0 512 return rvDC;
michael@0 513 }
michael@0 514
michael@0 515 static nssDecodedCert *
michael@0 516 create_decoded_pkix_cert_from_nss3cert (
michael@0 517 NSSArena *arenaOpt,
michael@0 518 CERTCertificate *cc
michael@0 519 )
michael@0 520 {
michael@0 521 nssDecodedCert *rvDC = nss_ZNEW(arenaOpt, nssDecodedCert);
michael@0 522 if (rvDC) {
michael@0 523 rvDC->type = NSSCertificateType_PKIX;
michael@0 524 rvDC->data = (void *)cc;
michael@0 525 rvDC->getIdentifier = nss3certificate_getIdentifier;
michael@0 526 rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier;
michael@0 527 rvDC->matchIdentifier = nss3certificate_matchIdentifier;
michael@0 528 rvDC->isValidIssuer = nss3certificate_isValidIssuer;
michael@0 529 rvDC->getUsage = nss3certificate_getUsage;
michael@0 530 rvDC->isValidAtTime = nss3certificate_isValidAtTime;
michael@0 531 rvDC->isNewerThan = nss3certificate_isNewerThan;
michael@0 532 rvDC->matchUsage = nss3certificate_matchUsage;
michael@0 533 rvDC->isTrustedForUsage = nss3certificate_isTrustedForUsage;
michael@0 534 rvDC->getEmailAddress = nss3certificate_getEmailAddress;
michael@0 535 rvDC->getDERSerialNumber = nss3certificate_getDERSerialNumber;
michael@0 536 }
michael@0 537 return rvDC;
michael@0 538 }
michael@0 539
michael@0 540 NSS_IMPLEMENT PRStatus
michael@0 541 nssDecodedPKIXCertificate_Destroy (
michael@0 542 nssDecodedCert *dc
michael@0 543 )
michael@0 544 {
michael@0 545 CERTCertificate *cert = (CERTCertificate *)dc->data;
michael@0 546
michael@0 547 /* The decoder may only be half initialized (the case where we find we
michael@0 548 * could not decode the certificate). In this case, there is not cert to
michael@0 549 * free, just free the dc structure. */
michael@0 550 if (cert) {
michael@0 551 PRBool freeSlot = cert->ownSlot;
michael@0 552 PK11SlotInfo *slot = cert->slot;
michael@0 553 PLArenaPool *arena = cert->arena;
michael@0 554 /* zero cert before freeing. Any stale references to this cert
michael@0 555 * after this point will probably cause an exception. */
michael@0 556 PORT_Memset(cert, 0, sizeof *cert);
michael@0 557 /* free the arena that contains the cert. */
michael@0 558 PORT_FreeArena(arena, PR_FALSE);
michael@0 559 if (slot && freeSlot) {
michael@0 560 PK11_FreeSlot(slot);
michael@0 561 }
michael@0 562 }
michael@0 563 nss_ZFreeIf(dc);
michael@0 564 return PR_SUCCESS;
michael@0 565 }
michael@0 566
michael@0 567 /* see pk11cert.c:pk11_HandleTrustObject */
michael@0 568 static unsigned int
michael@0 569 get_nss3trust_from_nss4trust(nssTrustLevel t)
michael@0 570 {
michael@0 571 unsigned int rt = 0;
michael@0 572 if (t == nssTrustLevel_Trusted) {
michael@0 573 rt |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED;
michael@0 574 }
michael@0 575 if (t == nssTrustLevel_TrustedDelegator) {
michael@0 576 rt |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA;
michael@0 577 }
michael@0 578 if (t == nssTrustLevel_NotTrusted) {
michael@0 579 rt |= CERTDB_TERMINAL_RECORD;
michael@0 580 }
michael@0 581 if (t == nssTrustLevel_ValidDelegator) {
michael@0 582 rt |= CERTDB_VALID_CA;
michael@0 583 }
michael@0 584 return rt;
michael@0 585 }
michael@0 586
michael@0 587 static CERTCertTrust *
michael@0 588 cert_trust_from_stan_trust(NSSTrust *t, PLArenaPool *arena)
michael@0 589 {
michael@0 590 CERTCertTrust *rvTrust;
michael@0 591 unsigned int client;
michael@0 592 if (!t) {
michael@0 593 return NULL;
michael@0 594 }
michael@0 595 rvTrust = PORT_ArenaAlloc(arena, sizeof(CERTCertTrust));
michael@0 596 if (!rvTrust) return NULL;
michael@0 597 rvTrust->sslFlags = get_nss3trust_from_nss4trust(t->serverAuth);
michael@0 598 client = get_nss3trust_from_nss4trust(t->clientAuth);
michael@0 599 if (client & (CERTDB_TRUSTED_CA|CERTDB_NS_TRUSTED_CA)) {
michael@0 600 client &= ~(CERTDB_TRUSTED_CA|CERTDB_NS_TRUSTED_CA);
michael@0 601 rvTrust->sslFlags |= CERTDB_TRUSTED_CLIENT_CA;
michael@0 602 }
michael@0 603 rvTrust->sslFlags |= client;
michael@0 604 rvTrust->emailFlags = get_nss3trust_from_nss4trust(t->emailProtection);
michael@0 605 rvTrust->objectSigningFlags = get_nss3trust_from_nss4trust(t->codeSigning);
michael@0 606 return rvTrust;
michael@0 607 }
michael@0 608
michael@0 609 CERTCertTrust *
michael@0 610 nssTrust_GetCERTCertTrustForCert(NSSCertificate *c, CERTCertificate *cc)
michael@0 611 {
michael@0 612 CERTCertTrust *rvTrust = NULL;
michael@0 613 NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
michael@0 614 NSSTrust *t;
michael@0 615 t = nssTrustDomain_FindTrustForCertificate(td, c);
michael@0 616 if (t) {
michael@0 617 rvTrust = cert_trust_from_stan_trust(t, cc->arena);
michael@0 618 if (!rvTrust) {
michael@0 619 nssTrust_Destroy(t);
michael@0 620 return NULL;
michael@0 621 }
michael@0 622 nssTrust_Destroy(t);
michael@0 623 } else {
michael@0 624 rvTrust = PORT_ArenaAlloc(cc->arena, sizeof(CERTCertTrust));
michael@0 625 if (!rvTrust) {
michael@0 626 return NULL;
michael@0 627 }
michael@0 628 memset(rvTrust, 0, sizeof(*rvTrust));
michael@0 629 }
michael@0 630 if (NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL)) {
michael@0 631 rvTrust->sslFlags |= CERTDB_USER;
michael@0 632 rvTrust->emailFlags |= CERTDB_USER;
michael@0 633 rvTrust->objectSigningFlags |= CERTDB_USER;
michael@0 634 }
michael@0 635 return rvTrust;
michael@0 636 }
michael@0 637
michael@0 638 static nssCryptokiInstance *
michael@0 639 get_cert_instance(NSSCertificate *c)
michael@0 640 {
michael@0 641 nssCryptokiObject *instance, **ci;
michael@0 642 nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
michael@0 643 if (!instances) {
michael@0 644 return NULL;
michael@0 645 }
michael@0 646 instance = NULL;
michael@0 647 for (ci = instances; *ci; ci++) {
michael@0 648 if (!instance) {
michael@0 649 instance = nssCryptokiObject_Clone(*ci);
michael@0 650 } else {
michael@0 651 /* This only really works for two instances... But 3.4 can't
michael@0 652 * handle more anyway. The logic is, if there are multiple
michael@0 653 * instances, prefer the one that is not internal (e.g., on
michael@0 654 * a hardware device.
michael@0 655 */
michael@0 656 if (PK11_IsInternal(instance->token->pk11slot)) {
michael@0 657 nssCryptokiObject_Destroy(instance);
michael@0 658 instance = nssCryptokiObject_Clone(*ci);
michael@0 659 }
michael@0 660 }
michael@0 661 }
michael@0 662 nssCryptokiObjectArray_Destroy(instances);
michael@0 663 return instance;
michael@0 664 }
michael@0 665
michael@0 666 char *
michael@0 667 STAN_GetCERTCertificateNameForInstance (
michael@0 668 PLArenaPool *arenaOpt,
michael@0 669 NSSCertificate *c,
michael@0 670 nssCryptokiInstance *instance
michael@0 671 )
michael@0 672 {
michael@0 673 NSSCryptoContext *context = c->object.cryptoContext;
michael@0 674 PRStatus nssrv;
michael@0 675 int nicklen, tokenlen, len;
michael@0 676 NSSUTF8 *tokenName = NULL;
michael@0 677 NSSUTF8 *stanNick = NULL;
michael@0 678 char *nickname = NULL;
michael@0 679 char *nick;
michael@0 680
michael@0 681 if (instance) {
michael@0 682 stanNick = instance->label;
michael@0 683 } else if (context) {
michael@0 684 stanNick = c->object.tempName;
michael@0 685 }
michael@0 686 if (stanNick) {
michael@0 687 /* fill other fields needed by NSS3 functions using CERTCertificate */
michael@0 688 if (instance && (!PK11_IsInternalKeySlot(instance->token->pk11slot) ||
michael@0 689 PORT_Strchr(stanNick, ':') != NULL) ) {
michael@0 690 tokenName = nssToken_GetName(instance->token);
michael@0 691 tokenlen = nssUTF8_Size(tokenName, &nssrv);
michael@0 692 } else {
michael@0 693 /* don't use token name for internal slot; 3.3 didn't */
michael@0 694 tokenlen = 0;
michael@0 695 }
michael@0 696 nicklen = nssUTF8_Size(stanNick, &nssrv);
michael@0 697 len = tokenlen + nicklen;
michael@0 698 if (arenaOpt) {
michael@0 699 nickname = PORT_ArenaAlloc(arenaOpt, len);
michael@0 700 } else {
michael@0 701 nickname = PORT_Alloc(len);
michael@0 702 }
michael@0 703 nick = nickname;
michael@0 704 if (tokenName) {
michael@0 705 memcpy(nick, tokenName, tokenlen-1);
michael@0 706 nick += tokenlen-1;
michael@0 707 *nick++ = ':';
michael@0 708 }
michael@0 709 memcpy(nick, stanNick, nicklen-1);
michael@0 710 nickname[len-1] = '\0';
michael@0 711 }
michael@0 712 return nickname;
michael@0 713 }
michael@0 714
michael@0 715 char *
michael@0 716 STAN_GetCERTCertificateName(PLArenaPool *arenaOpt, NSSCertificate *c)
michael@0 717 {
michael@0 718 char * result;
michael@0 719 nssCryptokiInstance *instance = get_cert_instance(c);
michael@0 720 /* It's OK to call this function, even if instance is NULL */
michael@0 721 result = STAN_GetCERTCertificateNameForInstance(arenaOpt, c, instance);
michael@0 722 if (instance)
michael@0 723 nssCryptokiObject_Destroy(instance);
michael@0 724 return result;
michael@0 725 }
michael@0 726
michael@0 727 static void
michael@0 728 fill_CERTCertificateFields(NSSCertificate *c, CERTCertificate *cc, PRBool forced)
michael@0 729 {
michael@0 730 CERTCertTrust* trust = NULL;
michael@0 731 NSSTrust *nssTrust;
michael@0 732 NSSCryptoContext *context = c->object.cryptoContext;
michael@0 733 nssCryptokiInstance *instance;
michael@0 734 NSSUTF8 *stanNick = NULL;
michael@0 735
michael@0 736 /* We are holding the base class object's lock on entry of this function
michael@0 737 * This lock protects writes to fields of the CERTCertificate .
michael@0 738 * It is also needed by some functions to compute values such as trust.
michael@0 739 */
michael@0 740 instance = get_cert_instance(c);
michael@0 741
michael@0 742 if (instance) {
michael@0 743 stanNick = instance->label;
michael@0 744 } else if (context) {
michael@0 745 stanNick = c->object.tempName;
michael@0 746 }
michael@0 747 /* fill other fields needed by NSS3 functions using CERTCertificate */
michael@0 748 if ((!cc->nickname && stanNick) || forced) {
michael@0 749 PRStatus nssrv;
michael@0 750 int nicklen, tokenlen, len;
michael@0 751 NSSUTF8 *tokenName = NULL;
michael@0 752 char *nick;
michael@0 753 if (instance &&
michael@0 754 (!PK11_IsInternalKeySlot(instance->token->pk11slot) ||
michael@0 755 (stanNick && PORT_Strchr(stanNick, ':') != NULL))) {
michael@0 756 tokenName = nssToken_GetName(instance->token);
michael@0 757 tokenlen = nssUTF8_Size(tokenName, &nssrv);
michael@0 758 } else {
michael@0 759 /* don't use token name for internal slot; 3.3 didn't */
michael@0 760 tokenlen = 0;
michael@0 761 }
michael@0 762 if (stanNick) {
michael@0 763 nicklen = nssUTF8_Size(stanNick, &nssrv);
michael@0 764 len = tokenlen + nicklen;
michael@0 765 nick = PORT_ArenaAlloc(cc->arena, len);
michael@0 766 if (tokenName) {
michael@0 767 memcpy(nick, tokenName, tokenlen-1);
michael@0 768 nick[tokenlen-1] = ':';
michael@0 769 memcpy(nick+tokenlen, stanNick, nicklen-1);
michael@0 770 } else {
michael@0 771 memcpy(nick, stanNick, nicklen-1);
michael@0 772 }
michael@0 773 nick[len-1] = '\0';
michael@0 774 cc->nickname = nick;
michael@0 775 } else {
michael@0 776 cc->nickname = NULL;
michael@0 777 }
michael@0 778 }
michael@0 779 if (context) {
michael@0 780 /* trust */
michael@0 781 nssTrust = nssCryptoContext_FindTrustForCertificate(context, c);
michael@0 782 if (!nssTrust) {
michael@0 783 /* chicken and egg issue:
michael@0 784 *
michael@0 785 * c->issuer and c->serial are empty at this point, but
michael@0 786 * nssTrustDomain_FindTrustForCertificate use them to look up
michael@0 787 * up the trust object, so we point them to cc->derIssuer and
michael@0 788 * cc->serialNumber.
michael@0 789 *
michael@0 790 * Our caller will fill these in with proper arena copies when we
michael@0 791 * return. */
michael@0 792 c->issuer.data = cc->derIssuer.data;
michael@0 793 c->issuer.size = cc->derIssuer.len;
michael@0 794 c->serial.data = cc->serialNumber.data;
michael@0 795 c->serial.size = cc->serialNumber.len;
michael@0 796 nssTrust = nssTrustDomain_FindTrustForCertificate(context->td, c);
michael@0 797 }
michael@0 798 if (nssTrust) {
michael@0 799 trust = cert_trust_from_stan_trust(nssTrust, cc->arena);
michael@0 800 if (trust) {
michael@0 801 /* we should destroy cc->trust before replacing it, but it's
michael@0 802 allocated in cc->arena, so memory growth will occur on each
michael@0 803 refresh */
michael@0 804 CERT_LockCertTrust(cc);
michael@0 805 cc->trust = trust;
michael@0 806 CERT_UnlockCertTrust(cc);
michael@0 807 }
michael@0 808 nssTrust_Destroy(nssTrust);
michael@0 809 }
michael@0 810 } else if (instance) {
michael@0 811 /* slot */
michael@0 812 if (cc->slot != instance->token->pk11slot) {
michael@0 813 if (cc->slot) {
michael@0 814 PK11_FreeSlot(cc->slot);
michael@0 815 }
michael@0 816 cc->slot = PK11_ReferenceSlot(instance->token->pk11slot);
michael@0 817 }
michael@0 818 cc->ownSlot = PR_TRUE;
michael@0 819 /* pkcs11ID */
michael@0 820 cc->pkcs11ID = instance->handle;
michael@0 821 /* trust */
michael@0 822 trust = nssTrust_GetCERTCertTrustForCert(c, cc);
michael@0 823 if (trust) {
michael@0 824 /* we should destroy cc->trust before replacing it, but it's
michael@0 825 allocated in cc->arena, so memory growth will occur on each
michael@0 826 refresh */
michael@0 827 CERT_LockCertTrust(cc);
michael@0 828 cc->trust = trust;
michael@0 829 CERT_UnlockCertTrust(cc);
michael@0 830 }
michael@0 831 nssCryptokiObject_Destroy(instance);
michael@0 832 }
michael@0 833 /* database handle is now the trust domain */
michael@0 834 cc->dbhandle = c->object.trustDomain;
michael@0 835 /* subjectList ? */
michael@0 836 /* istemp and isperm are supported in NSS 3.4 */
michael@0 837 cc->istemp = PR_FALSE; /* CERT_NewTemp will override this */
michael@0 838 cc->isperm = PR_TRUE; /* by default */
michael@0 839 /* pointer back */
michael@0 840 cc->nssCertificate = c;
michael@0 841 if (trust) {
michael@0 842 /* force the cert type to be recomputed to include trust info */
michael@0 843 PRUint32 nsCertType = cert_ComputeCertType(cc);
michael@0 844
michael@0 845 /* Assert that it is safe to cast &cc->nsCertType to "PRInt32 *" */
michael@0 846 PORT_Assert(sizeof(cc->nsCertType) == sizeof(PRInt32));
michael@0 847 PR_ATOMIC_SET((PRInt32 *)&cc->nsCertType, nsCertType);
michael@0 848 }
michael@0 849 }
michael@0 850
michael@0 851 static CERTCertificate *
michael@0 852 stan_GetCERTCertificate(NSSCertificate *c, PRBool forceUpdate)
michael@0 853 {
michael@0 854 nssDecodedCert *dc = NULL;
michael@0 855 CERTCertificate *cc = NULL;
michael@0 856 CERTCertTrust certTrust;
michael@0 857
michael@0 858 nssPKIObject_Lock(&c->object);
michael@0 859
michael@0 860 dc = c->decoding;
michael@0 861 if (!dc) {
michael@0 862 dc = nssDecodedPKIXCertificate_Create(NULL, &c->encoding);
michael@0 863 if (!dc) {
michael@0 864 goto loser;
michael@0 865 }
michael@0 866 cc = (CERTCertificate *)dc->data;
michael@0 867 PORT_Assert(cc); /* software error */
michael@0 868 if (!cc) {
michael@0 869 nssDecodedPKIXCertificate_Destroy(dc);
michael@0 870 nss_SetError(NSS_ERROR_INTERNAL_ERROR);
michael@0 871 goto loser;
michael@0 872 }
michael@0 873 PORT_Assert(!c->decoding);
michael@0 874 if (!c->decoding) {
michael@0 875 c->decoding = dc;
michael@0 876 } else {
michael@0 877 /* this should never happen. Fail. */
michael@0 878 nssDecodedPKIXCertificate_Destroy(dc);
michael@0 879 nss_SetError(NSS_ERROR_INTERNAL_ERROR);
michael@0 880 goto loser;
michael@0 881 }
michael@0 882 }
michael@0 883 cc = (CERTCertificate *)dc->data;
michael@0 884 PORT_Assert(cc);
michael@0 885 if (!cc) {
michael@0 886 nss_SetError(NSS_ERROR_INTERNAL_ERROR);
michael@0 887 goto loser;
michael@0 888 }
michael@0 889 if (!cc->nssCertificate || forceUpdate) {
michael@0 890 fill_CERTCertificateFields(c, cc, forceUpdate);
michael@0 891 } else if (CERT_GetCertTrust(cc, &certTrust) != SECSuccess &&
michael@0 892 !c->object.cryptoContext) {
michael@0 893 /* if it's a perm cert, it might have been stored before the
michael@0 894 * trust, so look for the trust again. But a temp cert can be
michael@0 895 * ignored.
michael@0 896 */
michael@0 897 CERTCertTrust* trust = NULL;
michael@0 898 trust = nssTrust_GetCERTCertTrustForCert(c, cc);
michael@0 899
michael@0 900 CERT_LockCertTrust(cc);
michael@0 901 cc->trust = trust;
michael@0 902 CERT_UnlockCertTrust(cc);
michael@0 903 }
michael@0 904
michael@0 905 loser:
michael@0 906 nssPKIObject_Unlock(&c->object);
michael@0 907 return cc;
michael@0 908 }
michael@0 909
michael@0 910 NSS_IMPLEMENT CERTCertificate *
michael@0 911 STAN_ForceCERTCertificateUpdate(NSSCertificate *c)
michael@0 912 {
michael@0 913 if (c->decoding) {
michael@0 914 return stan_GetCERTCertificate(c, PR_TRUE);
michael@0 915 }
michael@0 916 return NULL;
michael@0 917 }
michael@0 918
michael@0 919 NSS_IMPLEMENT CERTCertificate *
michael@0 920 STAN_GetCERTCertificate(NSSCertificate *c)
michael@0 921 {
michael@0 922 return stan_GetCERTCertificate(c, PR_FALSE);
michael@0 923 }
michael@0 924 /*
michael@0 925 * many callers of STAN_GetCERTCertificate() intend that
michael@0 926 * the CERTCertificate returned inherits the reference to the
michael@0 927 * NSSCertificate. For these callers it's convenient to have
michael@0 928 * this function 'own' the reference and either return a valid
michael@0 929 * CERTCertificate structure which inherits the reference or
michael@0 930 * destroy the reference to NSSCertificate and returns NULL.
michael@0 931 */
michael@0 932 NSS_IMPLEMENT CERTCertificate *
michael@0 933 STAN_GetCERTCertificateOrRelease(NSSCertificate *c)
michael@0 934 {
michael@0 935 CERTCertificate *nss3cert = stan_GetCERTCertificate(c, PR_FALSE);
michael@0 936 if (!nss3cert) {
michael@0 937 nssCertificate_Destroy(c);
michael@0 938 }
michael@0 939 return nss3cert;
michael@0 940 }
michael@0 941
michael@0 942 static nssTrustLevel
michael@0 943 get_stan_trust(unsigned int t, PRBool isClientAuth)
michael@0 944 {
michael@0 945 if (isClientAuth) {
michael@0 946 if (t & CERTDB_TRUSTED_CLIENT_CA) {
michael@0 947 return nssTrustLevel_TrustedDelegator;
michael@0 948 }
michael@0 949 } else {
michael@0 950 if (t & CERTDB_TRUSTED_CA || t & CERTDB_NS_TRUSTED_CA) {
michael@0 951 return nssTrustLevel_TrustedDelegator;
michael@0 952 }
michael@0 953 }
michael@0 954 if (t & CERTDB_TRUSTED) {
michael@0 955 return nssTrustLevel_Trusted;
michael@0 956 }
michael@0 957 if (t & CERTDB_TERMINAL_RECORD) {
michael@0 958 return nssTrustLevel_NotTrusted;
michael@0 959 }
michael@0 960 if (t & CERTDB_VALID_CA) {
michael@0 961 return nssTrustLevel_ValidDelegator;
michael@0 962 }
michael@0 963 return nssTrustLevel_MustVerify;
michael@0 964 }
michael@0 965
michael@0 966 NSS_EXTERN NSSCertificate *
michael@0 967 STAN_GetNSSCertificate(CERTCertificate *cc)
michael@0 968 {
michael@0 969 NSSCertificate *c;
michael@0 970 nssCryptokiInstance *instance;
michael@0 971 nssPKIObject *pkiob;
michael@0 972 NSSArena *arena;
michael@0 973 c = cc->nssCertificate;
michael@0 974 if (c) {
michael@0 975 return c;
michael@0 976 }
michael@0 977 /* i don't think this should happen. but if it can, need to create
michael@0 978 * NSSCertificate from CERTCertificate values here. */
michael@0 979 /* Yup, it can happen. */
michael@0 980 arena = NSSArena_Create();
michael@0 981 if (!arena) {
michael@0 982 return NULL;
michael@0 983 }
michael@0 984 c = nss_ZNEW(arena, NSSCertificate);
michael@0 985 if (!c) {
michael@0 986 nssArena_Destroy(arena);
michael@0 987 return NULL;
michael@0 988 }
michael@0 989 NSSITEM_FROM_SECITEM(&c->encoding, &cc->derCert);
michael@0 990 c->type = NSSCertificateType_PKIX;
michael@0 991 pkiob = nssPKIObject_Create(arena, NULL, cc->dbhandle, NULL, nssPKIMonitor);
michael@0 992 if (!pkiob) {
michael@0 993 nssArena_Destroy(arena);
michael@0 994 return NULL;
michael@0 995 }
michael@0 996 c->object = *pkiob;
michael@0 997 nssItem_Create(arena,
michael@0 998 &c->issuer, cc->derIssuer.len, cc->derIssuer.data);
michael@0 999 nssItem_Create(arena,
michael@0 1000 &c->subject, cc->derSubject.len, cc->derSubject.data);
michael@0 1001 if (PR_TRUE) {
michael@0 1002 /* CERTCertificate stores serial numbers decoded. I need the DER
michael@0 1003 * here. sigh.
michael@0 1004 */
michael@0 1005 SECItem derSerial;
michael@0 1006 SECStatus secrv;
michael@0 1007 secrv = CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial);
michael@0 1008 if (secrv == SECFailure) {
michael@0 1009 nssArena_Destroy(arena);
michael@0 1010 return NULL;
michael@0 1011 }
michael@0 1012 nssItem_Create(arena, &c->serial, derSerial.len, derSerial.data);
michael@0 1013 PORT_Free(derSerial.data);
michael@0 1014 }
michael@0 1015 if (cc->emailAddr && cc->emailAddr[0]) {
michael@0 1016 c->email = nssUTF8_Create(arena,
michael@0 1017 nssStringType_PrintableString,
michael@0 1018 (NSSUTF8 *)cc->emailAddr,
michael@0 1019 PORT_Strlen(cc->emailAddr));
michael@0 1020 }
michael@0 1021 if (cc->slot) {
michael@0 1022 instance = nss_ZNEW(arena, nssCryptokiInstance);
michael@0 1023 if (!instance) {
michael@0 1024 nssArena_Destroy(arena);
michael@0 1025 return NULL;
michael@0 1026 }
michael@0 1027 instance->token = nssToken_AddRef(PK11Slot_GetNSSToken(cc->slot));
michael@0 1028 instance->handle = cc->pkcs11ID;
michael@0 1029 instance->isTokenObject = PR_TRUE;
michael@0 1030 if (cc->nickname) {
michael@0 1031 instance->label = nssUTF8_Create(arena,
michael@0 1032 nssStringType_UTF8String,
michael@0 1033 (NSSUTF8 *)cc->nickname,
michael@0 1034 PORT_Strlen(cc->nickname));
michael@0 1035 }
michael@0 1036 nssPKIObject_AddInstance(&c->object, instance);
michael@0 1037 }
michael@0 1038 c->decoding = create_decoded_pkix_cert_from_nss3cert(NULL, cc);
michael@0 1039 cc->nssCertificate = c;
michael@0 1040 return c;
michael@0 1041 }
michael@0 1042
michael@0 1043 static NSSToken*
michael@0 1044 stan_GetTrustToken (
michael@0 1045 NSSCertificate *c
michael@0 1046 )
michael@0 1047 {
michael@0 1048 NSSToken *ttok = NULL;
michael@0 1049 NSSToken *rtok = NULL;
michael@0 1050 NSSToken *tok = NULL;
michael@0 1051 nssCryptokiObject **ip;
michael@0 1052 nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
michael@0 1053 if (!instances) {
michael@0 1054 return PR_FALSE;
michael@0 1055 }
michael@0 1056 for (ip = instances; *ip; ip++) {
michael@0 1057 nssCryptokiObject *instance = *ip;
michael@0 1058 nssCryptokiObject *to =
michael@0 1059 nssToken_FindTrustForCertificate(instance->token, NULL,
michael@0 1060 &c->encoding, &c->issuer, &c->serial,
michael@0 1061 nssTokenSearchType_TokenOnly);
michael@0 1062 NSSToken *ctok = instance->token;
michael@0 1063 PRBool ro = PK11_IsReadOnly(ctok->pk11slot);
michael@0 1064
michael@0 1065 if (to) {
michael@0 1066 nssCryptokiObject_Destroy(to);
michael@0 1067 ttok = ctok;
michael@0 1068 if (!ro) {
michael@0 1069 break;
michael@0 1070 }
michael@0 1071 } else {
michael@0 1072 if (!rtok && ro) {
michael@0 1073 rtok = ctok;
michael@0 1074 }
michael@0 1075 if (!tok && !ro) {
michael@0 1076 tok = ctok;
michael@0 1077 }
michael@0 1078 }
michael@0 1079 }
michael@0 1080 nssCryptokiObjectArray_Destroy(instances);
michael@0 1081 return ttok ? ttok : (tok ? tok : rtok);
michael@0 1082 }
michael@0 1083
michael@0 1084 NSS_EXTERN PRStatus
michael@0 1085 STAN_ChangeCertTrust(CERTCertificate *cc, CERTCertTrust *trust)
michael@0 1086 {
michael@0 1087 PRStatus nssrv;
michael@0 1088 NSSCertificate *c = STAN_GetNSSCertificate(cc);
michael@0 1089 NSSToken *tok;
michael@0 1090 NSSTrustDomain *td;
michael@0 1091 NSSTrust *nssTrust;
michael@0 1092 NSSArena *arena;
michael@0 1093 CERTCertTrust *oldTrust;
michael@0 1094 CERTCertTrust *newTrust;
michael@0 1095 nssListIterator *tokens;
michael@0 1096 PRBool moving_object;
michael@0 1097 nssCryptokiObject *newInstance;
michael@0 1098 nssPKIObject *pkiob;
michael@0 1099
michael@0 1100 if (c == NULL) {
michael@0 1101 return PR_FAILURE;
michael@0 1102 }
michael@0 1103 oldTrust = nssTrust_GetCERTCertTrustForCert(c, cc);
michael@0 1104 if (oldTrust) {
michael@0 1105 if (memcmp(oldTrust, trust, sizeof (CERTCertTrust)) == 0) {
michael@0 1106 /* ... and the new trust is no different, done) */
michael@0 1107 return PR_SUCCESS;
michael@0 1108 } else {
michael@0 1109 /* take over memory already allocated in cc's arena */
michael@0 1110 newTrust = oldTrust;
michael@0 1111 }
michael@0 1112 } else {
michael@0 1113 newTrust = PORT_ArenaAlloc(cc->arena, sizeof(CERTCertTrust));
michael@0 1114 }
michael@0 1115 memcpy(newTrust, trust, sizeof(CERTCertTrust));
michael@0 1116 CERT_LockCertTrust(cc);
michael@0 1117 cc->trust = newTrust;
michael@0 1118 CERT_UnlockCertTrust(cc);
michael@0 1119 /* Set the NSSCerticate's trust */
michael@0 1120 arena = nssArena_Create();
michael@0 1121 if (!arena) return PR_FAILURE;
michael@0 1122 nssTrust = nss_ZNEW(arena, NSSTrust);
michael@0 1123 if (!nssTrust) {
michael@0 1124 nssArena_Destroy(arena);
michael@0 1125 return PR_FAILURE;
michael@0 1126 }
michael@0 1127 pkiob = nssPKIObject_Create(arena, NULL, cc->dbhandle, NULL, nssPKILock);
michael@0 1128 if (!pkiob) {
michael@0 1129 nssArena_Destroy(arena);
michael@0 1130 return PR_FAILURE;
michael@0 1131 }
michael@0 1132 nssTrust->object = *pkiob;
michael@0 1133 nssTrust->certificate = c;
michael@0 1134 nssTrust->serverAuth = get_stan_trust(trust->sslFlags, PR_FALSE);
michael@0 1135 nssTrust->clientAuth = get_stan_trust(trust->sslFlags, PR_TRUE);
michael@0 1136 nssTrust->emailProtection = get_stan_trust(trust->emailFlags, PR_FALSE);
michael@0 1137 nssTrust->codeSigning = get_stan_trust(trust->objectSigningFlags, PR_FALSE);
michael@0 1138 nssTrust->stepUpApproved =
michael@0 1139 (PRBool)(trust->sslFlags & CERTDB_GOVT_APPROVED_CA);
michael@0 1140 if (c->object.cryptoContext != NULL) {
michael@0 1141 /* The cert is in a context, set the trust there */
michael@0 1142 NSSCryptoContext *cc = c->object.cryptoContext;
michael@0 1143 nssrv = nssCryptoContext_ImportTrust(cc, nssTrust);
michael@0 1144 if (nssrv != PR_SUCCESS) {
michael@0 1145 goto done;
michael@0 1146 }
michael@0 1147 if (c->object.numInstances == 0) {
michael@0 1148 /* The context is the only instance, finished */
michael@0 1149 goto done;
michael@0 1150 }
michael@0 1151 }
michael@0 1152 td = STAN_GetDefaultTrustDomain();
michael@0 1153 tok = stan_GetTrustToken(c);
michael@0 1154 moving_object = PR_FALSE;
michael@0 1155 if (tok && PK11_IsReadOnly(tok->pk11slot)) {
michael@0 1156 NSSRWLock_LockRead(td->tokensLock);
michael@0 1157 tokens = nssList_CreateIterator(td->tokenList);
michael@0 1158 if (!tokens) {
michael@0 1159 nssrv = PR_FAILURE;
michael@0 1160 NSSRWLock_UnlockRead(td->tokensLock);
michael@0 1161 goto done;
michael@0 1162 }
michael@0 1163 for (tok = (NSSToken *)nssListIterator_Start(tokens);
michael@0 1164 tok != (NSSToken *)NULL;
michael@0 1165 tok = (NSSToken *)nssListIterator_Next(tokens))
michael@0 1166 {
michael@0 1167 if (!PK11_IsReadOnly(tok->pk11slot)) break;
michael@0 1168 }
michael@0 1169 nssListIterator_Finish(tokens);
michael@0 1170 nssListIterator_Destroy(tokens);
michael@0 1171 NSSRWLock_UnlockRead(td->tokensLock);
michael@0 1172 moving_object = PR_TRUE;
michael@0 1173 }
michael@0 1174 if (tok) {
michael@0 1175 if (moving_object) {
michael@0 1176 /* this is kind of hacky. the softoken needs the cert
michael@0 1177 * object in order to store trust. forcing it to be perm
michael@0 1178 */
michael@0 1179 NSSUTF8 *nickname = nssCertificate_GetNickname(c, NULL);
michael@0 1180 NSSASCII7 *email = NULL;
michael@0 1181
michael@0 1182 if (PK11_IsInternal(tok->pk11slot)) {
michael@0 1183 email = c->email;
michael@0 1184 }
michael@0 1185 newInstance = nssToken_ImportCertificate(tok, NULL,
michael@0 1186 NSSCertificateType_PKIX,
michael@0 1187 &c->id,
michael@0 1188 nickname,
michael@0 1189 &c->encoding,
michael@0 1190 &c->issuer,
michael@0 1191 &c->subject,
michael@0 1192 &c->serial,
michael@0 1193 email,
michael@0 1194 PR_TRUE);
michael@0 1195 nss_ZFreeIf(nickname);
michael@0 1196 nickname = NULL;
michael@0 1197 if (!newInstance) {
michael@0 1198 nssrv = PR_FAILURE;
michael@0 1199 goto done;
michael@0 1200 }
michael@0 1201 nssPKIObject_AddInstance(&c->object, newInstance);
michael@0 1202 }
michael@0 1203 newInstance = nssToken_ImportTrust(tok, NULL, &c->encoding,
michael@0 1204 &c->issuer, &c->serial,
michael@0 1205 nssTrust->serverAuth,
michael@0 1206 nssTrust->clientAuth,
michael@0 1207 nssTrust->codeSigning,
michael@0 1208 nssTrust->emailProtection,
michael@0 1209 nssTrust->stepUpApproved, PR_TRUE);
michael@0 1210 /* If the selected token can't handle trust, dump the trust on
michael@0 1211 * the internal token */
michael@0 1212 if (!newInstance && !PK11_IsInternalKeySlot(tok->pk11slot)) {
michael@0 1213 PK11SlotInfo *slot = PK11_GetInternalKeySlot();
michael@0 1214 NSSUTF8 *nickname = nssCertificate_GetNickname(c, NULL);
michael@0 1215 NSSASCII7 *email = c->email;
michael@0 1216 tok = PK11Slot_GetNSSToken(slot);
michael@0 1217 PK11_FreeSlot(slot);
michael@0 1218
michael@0 1219 newInstance = nssToken_ImportCertificate(tok, NULL,
michael@0 1220 NSSCertificateType_PKIX,
michael@0 1221 &c->id,
michael@0 1222 nickname,
michael@0 1223 &c->encoding,
michael@0 1224 &c->issuer,
michael@0 1225 &c->subject,
michael@0 1226 &c->serial,
michael@0 1227 email,
michael@0 1228 PR_TRUE);
michael@0 1229 nss_ZFreeIf(nickname);
michael@0 1230 nickname = NULL;
michael@0 1231 if (!newInstance) {
michael@0 1232 nssrv = PR_FAILURE;
michael@0 1233 goto done;
michael@0 1234 }
michael@0 1235 nssPKIObject_AddInstance(&c->object, newInstance);
michael@0 1236 newInstance = nssToken_ImportTrust(tok, NULL, &c->encoding,
michael@0 1237 &c->issuer, &c->serial,
michael@0 1238 nssTrust->serverAuth,
michael@0 1239 nssTrust->clientAuth,
michael@0 1240 nssTrust->codeSigning,
michael@0 1241 nssTrust->emailProtection,
michael@0 1242 nssTrust->stepUpApproved, PR_TRUE);
michael@0 1243 }
michael@0 1244 if (newInstance) {
michael@0 1245 nssCryptokiObject_Destroy(newInstance);
michael@0 1246 nssrv = PR_SUCCESS;
michael@0 1247 } else {
michael@0 1248 nssrv = PR_FAILURE;
michael@0 1249 }
michael@0 1250 } else {
michael@0 1251 nssrv = PR_FAILURE;
michael@0 1252 }
michael@0 1253 done:
michael@0 1254 (void)nssTrust_Destroy(nssTrust);
michael@0 1255 return nssrv;
michael@0 1256 }
michael@0 1257
michael@0 1258 /*
michael@0 1259 ** Delete trust objects matching the given slot.
michael@0 1260 ** Returns error if a device fails to delete.
michael@0 1261 **
michael@0 1262 ** This function has the side effect of moving the
michael@0 1263 ** surviving entries to the front of the object list
michael@0 1264 ** and nullifying the rest.
michael@0 1265 */
michael@0 1266 static PRStatus
michael@0 1267 DeleteCertTrustMatchingSlot(PK11SlotInfo *pk11slot, nssPKIObject *tObject)
michael@0 1268 {
michael@0 1269 int numNotDestroyed = 0; /* the ones skipped plus the failures */
michael@0 1270 int failureCount = 0; /* actual deletion failures by devices */
michael@0 1271 int index;
michael@0 1272
michael@0 1273 nssPKIObject_Lock(tObject);
michael@0 1274 /* Keep going even if a module fails to delete. */
michael@0 1275 for (index = 0; index < tObject->numInstances; index++) {
michael@0 1276 nssCryptokiObject *instance = tObject->instances[index];
michael@0 1277 if (!instance) {
michael@0 1278 continue;
michael@0 1279 }
michael@0 1280
michael@0 1281 /* ReadOnly and not matched treated the same */
michael@0 1282 if (PK11_IsReadOnly(instance->token->pk11slot) ||
michael@0 1283 pk11slot != instance->token->pk11slot) {
michael@0 1284 tObject->instances[numNotDestroyed++] = instance;
michael@0 1285 continue;
michael@0 1286 }
michael@0 1287
michael@0 1288 /* Here we have found a matching one */
michael@0 1289 tObject->instances[index] = NULL;
michael@0 1290 if (nssToken_DeleteStoredObject(instance) == PR_SUCCESS) {
michael@0 1291 nssCryptokiObject_Destroy(instance);
michael@0 1292 } else {
michael@0 1293 tObject->instances[numNotDestroyed++] = instance;
michael@0 1294 failureCount++;
michael@0 1295 }
michael@0 1296
michael@0 1297 }
michael@0 1298 if (numNotDestroyed == 0) {
michael@0 1299 nss_ZFreeIf(tObject->instances);
michael@0 1300 tObject->numInstances = 0;
michael@0 1301 } else {
michael@0 1302 tObject->numInstances = numNotDestroyed;
michael@0 1303 }
michael@0 1304
michael@0 1305 nssPKIObject_Unlock(tObject);
michael@0 1306
michael@0 1307 return failureCount == 0 ? PR_SUCCESS : PR_FAILURE;
michael@0 1308 }
michael@0 1309
michael@0 1310 /*
michael@0 1311 ** Delete trust objects matching the slot of the given certificate.
michael@0 1312 ** Returns an error if any device fails to delete.
michael@0 1313 */
michael@0 1314 NSS_EXTERN PRStatus
michael@0 1315 STAN_DeleteCertTrustMatchingSlot(NSSCertificate *c)
michael@0 1316 {
michael@0 1317 PRStatus nssrv = PR_SUCCESS;
michael@0 1318
michael@0 1319 NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
michael@0 1320 NSSTrust *nssTrust = nssTrustDomain_FindTrustForCertificate(td, c);
michael@0 1321 /* caller made sure nssTrust isn't NULL */
michael@0 1322 nssPKIObject *tobject = &nssTrust->object;
michael@0 1323 nssPKIObject *cobject = &c->object;
michael@0 1324 int i;
michael@0 1325
michael@0 1326 /* Iterate through the cert and trust object instances looking for
michael@0 1327 * those with matching pk11 slots to delete. Even if some device
michael@0 1328 * can't delete we keep going. Keeping a status variable for the
michael@0 1329 * loop so that once it's failed the other gets set.
michael@0 1330 */
michael@0 1331 NSSRWLock_LockRead(td->tokensLock);
michael@0 1332 nssPKIObject_Lock(cobject);
michael@0 1333 for (i = 0; i < cobject->numInstances; i++) {
michael@0 1334 nssCryptokiObject *cInstance = cobject->instances[i];
michael@0 1335 if (cInstance && !PK11_IsReadOnly(cInstance->token->pk11slot)) {
michael@0 1336 PRStatus status;
michael@0 1337 if (!tobject->numInstances || !tobject->instances) continue;
michael@0 1338 status = DeleteCertTrustMatchingSlot(cInstance->token->pk11slot, tobject);
michael@0 1339 if (status == PR_FAILURE) {
michael@0 1340 /* set the outer one but keep going */
michael@0 1341 nssrv = PR_FAILURE;
michael@0 1342 }
michael@0 1343 }
michael@0 1344 }
michael@0 1345 nssPKIObject_Unlock(cobject);
michael@0 1346 NSSRWLock_UnlockRead(td->tokensLock);
michael@0 1347 return nssrv;
michael@0 1348 }
michael@0 1349
michael@0 1350 /* CERT_TraversePermCertsForSubject */
michael@0 1351 NSS_IMPLEMENT PRStatus
michael@0 1352 nssTrustDomain_TraverseCertificatesBySubject (
michael@0 1353 NSSTrustDomain *td,
michael@0 1354 NSSDER *subject,
michael@0 1355 PRStatus (*callback)(NSSCertificate *c, void *arg),
michael@0 1356 void *arg
michael@0 1357 )
michael@0 1358 {
michael@0 1359 PRStatus nssrv = PR_SUCCESS;
michael@0 1360 NSSArena *tmpArena;
michael@0 1361 NSSCertificate **subjectCerts;
michael@0 1362 NSSCertificate *c;
michael@0 1363 PRIntn i;
michael@0 1364 tmpArena = NSSArena_Create();
michael@0 1365 if (!tmpArena) {
michael@0 1366 return PR_FAILURE;
michael@0 1367 }
michael@0 1368 subjectCerts = NSSTrustDomain_FindCertificatesBySubject(td, subject, NULL,
michael@0 1369 0, tmpArena);
michael@0 1370 if (subjectCerts) {
michael@0 1371 for (i=0, c = subjectCerts[i]; c; i++) {
michael@0 1372 nssrv = callback(c, arg);
michael@0 1373 if (nssrv != PR_SUCCESS) break;
michael@0 1374 }
michael@0 1375 }
michael@0 1376 nssArena_Destroy(tmpArena);
michael@0 1377 return nssrv;
michael@0 1378 }
michael@0 1379
michael@0 1380 /* CERT_TraversePermCertsForNickname */
michael@0 1381 NSS_IMPLEMENT PRStatus
michael@0 1382 nssTrustDomain_TraverseCertificatesByNickname (
michael@0 1383 NSSTrustDomain *td,
michael@0 1384 NSSUTF8 *nickname,
michael@0 1385 PRStatus (*callback)(NSSCertificate *c, void *arg),
michael@0 1386 void *arg
michael@0 1387 )
michael@0 1388 {
michael@0 1389 PRStatus nssrv = PR_SUCCESS;
michael@0 1390 NSSArena *tmpArena;
michael@0 1391 NSSCertificate **nickCerts;
michael@0 1392 NSSCertificate *c;
michael@0 1393 PRIntn i;
michael@0 1394 tmpArena = NSSArena_Create();
michael@0 1395 if (!tmpArena) {
michael@0 1396 return PR_FAILURE;
michael@0 1397 }
michael@0 1398 nickCerts = NSSTrustDomain_FindCertificatesByNickname(td, nickname, NULL,
michael@0 1399 0, tmpArena);
michael@0 1400 if (nickCerts) {
michael@0 1401 for (i=0, c = nickCerts[i]; c; i++) {
michael@0 1402 nssrv = callback(c, arg);
michael@0 1403 if (nssrv != PR_SUCCESS) break;
michael@0 1404 }
michael@0 1405 }
michael@0 1406 nssArena_Destroy(tmpArena);
michael@0 1407 return nssrv;
michael@0 1408 }
michael@0 1409
michael@0 1410 static void cert_dump_iter(const void *k, void *v, void *a)
michael@0 1411 {
michael@0 1412 NSSCertificate *c = (NSSCertificate *)k;
michael@0 1413 CERTCertificate *cert = STAN_GetCERTCertificate(c);
michael@0 1414 printf("[%2d] \"%s\"\n", c->object.refCount, cert->subjectName);
michael@0 1415 }
michael@0 1416
michael@0 1417 void
michael@0 1418 nss_DumpCertificateCacheInfo()
michael@0 1419 {
michael@0 1420 NSSTrustDomain *td;
michael@0 1421 NSSCryptoContext *cc;
michael@0 1422 td = STAN_GetDefaultTrustDomain();
michael@0 1423 cc = STAN_GetDefaultCryptoContext();
michael@0 1424 printf("\n\nCertificates in the cache:\n");
michael@0 1425 nssTrustDomain_DumpCacheInfo(td, cert_dump_iter, NULL);
michael@0 1426 printf("\n\nCertificates in the temporary store:\n");
michael@0 1427 if (cc->certStore) {
michael@0 1428 nssCertificateStore_DumpStoreInfo(cc->certStore, cert_dump_iter, NULL);
michael@0 1429 }
michael@0 1430 }
michael@0 1431

mercurial