stanpcertdb.c (37554B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "prtime.h" 6 7 #include "cert.h" 8 #include "certi.h" 9 #include "certdb.h" 10 #include "secitem.h" 11 #include "secder.h" 12 13 /* Call to PK11_FreeSlot below */ 14 15 #include "secasn1.h" 16 #include "secerr.h" 17 #include "nssilock.h" 18 #include "prmon.h" 19 #include "base64.h" 20 #include "sechash.h" 21 #include "plhash.h" 22 #include "pk11func.h" /* sigh */ 23 24 #include "nsspki.h" 25 #include "pki.h" 26 #include "pkim.h" 27 #include "pki3hack.h" 28 #include "ckhelper.h" 29 #include "base.h" 30 #include "pkistore.h" 31 #include "dev3hack.h" 32 #include "dev.h" 33 #include "secmodi.h" 34 35 extern void CERT_MaybeLockCertTempPerm(const CERTCertificate *cert); 36 extern void CERT_MaybeUnlockCertTempPerm(const CERTCertificate *cert); 37 38 PRBool 39 SEC_CertNicknameConflict(const char *nickname, const SECItem *derSubject, 40 CERTCertDBHandle *handle) 41 { 42 CERTCertificate *cert; 43 PRBool conflict = PR_FALSE; 44 45 cert = CERT_FindCertByNickname(handle, nickname); 46 47 if (!cert) { 48 return conflict; 49 } 50 51 conflict = !SECITEM_ItemsAreEqual(derSubject, &cert->derSubject); 52 CERT_DestroyCertificate(cert); 53 return conflict; 54 } 55 56 SECStatus 57 SEC_DeletePermCertificate(CERTCertificate *cert) 58 { 59 PRStatus nssrv; 60 NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); 61 NSSCertificate *c = STAN_GetNSSCertificate(cert); 62 CERTCertTrust *certTrust; 63 64 if (c == NULL) { 65 /* error code is set */ 66 return SECFailure; 67 } 68 69 certTrust = nssTrust_GetCERTCertTrustForCert(c, cert); 70 if (certTrust) { 71 NSSTrust *nssTrust = nssTrustDomain_FindTrustForCertificate(td, c); 72 if (nssTrust) { 73 nssrv = STAN_DeleteCertTrustMatchingSlot(c); 74 if (nssrv != PR_SUCCESS) { 75 CERT_MapStanError(); 76 } 77 /* This call always returns PR_SUCCESS! */ 78 (void)nssTrust_Destroy(nssTrust); 79 } 80 } 81 82 /* get rid of the token instances */ 83 nssrv = NSSCertificate_DeleteStoredObject(c, NULL); 84 85 /* get rid of the cache entry */ 86 nssTrustDomain_LockCertCache(td); 87 nssTrustDomain_RemoveCertFromCacheLOCKED(td, c); 88 nssTrustDomain_UnlockCertCache(td); 89 90 return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure; 91 } 92 93 SECStatus 94 CERT_GetCertTrust(const CERTCertificate *cert, CERTCertTrust *trust) 95 { 96 SECStatus rv; 97 CERT_LockCertTrust(cert); 98 if (!cert || cert->trust == NULL) { 99 rv = SECFailure; 100 } else { 101 *trust = *cert->trust; 102 rv = SECSuccess; 103 } 104 CERT_UnlockCertTrust(cert); 105 return (rv); 106 } 107 108 extern const NSSError NSS_ERROR_NO_ERROR; 109 extern const NSSError NSS_ERROR_INTERNAL_ERROR; 110 extern const NSSError NSS_ERROR_NO_MEMORY; 111 extern const NSSError NSS_ERROR_INVALID_POINTER; 112 extern const NSSError NSS_ERROR_INVALID_ARENA; 113 extern const NSSError NSS_ERROR_INVALID_ARENA_MARK; 114 extern const NSSError NSS_ERROR_DUPLICATE_POINTER; 115 extern const NSSError NSS_ERROR_POINTER_NOT_REGISTERED; 116 extern const NSSError NSS_ERROR_TRACKER_NOT_EMPTY; 117 extern const NSSError NSS_ERROR_TRACKER_NOT_INITIALIZED; 118 extern const NSSError NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD; 119 extern const NSSError NSS_ERROR_VALUE_TOO_LARGE; 120 extern const NSSError NSS_ERROR_UNSUPPORTED_TYPE; 121 extern const NSSError NSS_ERROR_BUFFER_TOO_SHORT; 122 extern const NSSError NSS_ERROR_INVALID_ATOB_CONTEXT; 123 extern const NSSError NSS_ERROR_INVALID_BASE64; 124 extern const NSSError NSS_ERROR_INVALID_BTOA_CONTEXT; 125 extern const NSSError NSS_ERROR_INVALID_ITEM; 126 extern const NSSError NSS_ERROR_INVALID_STRING; 127 extern const NSSError NSS_ERROR_INVALID_ASN1ENCODER; 128 extern const NSSError NSS_ERROR_INVALID_ASN1DECODER; 129 extern const NSSError NSS_ERROR_INVALID_BER; 130 extern const NSSError NSS_ERROR_INVALID_ATAV; 131 extern const NSSError NSS_ERROR_INVALID_ARGUMENT; 132 extern const NSSError NSS_ERROR_INVALID_UTF8; 133 extern const NSSError NSS_ERROR_INVALID_NSSOID; 134 extern const NSSError NSS_ERROR_UNKNOWN_ATTRIBUTE; 135 extern const NSSError NSS_ERROR_NOT_FOUND; 136 extern const NSSError NSS_ERROR_INVALID_PASSWORD; 137 extern const NSSError NSS_ERROR_USER_CANCELED; 138 extern const NSSError NSS_ERROR_MAXIMUM_FOUND; 139 extern const NSSError NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND; 140 extern const NSSError NSS_ERROR_CERTIFICATE_IN_CACHE; 141 extern const NSSError NSS_ERROR_HASH_COLLISION; 142 extern const NSSError NSS_ERROR_DEVICE_ERROR; 143 extern const NSSError NSS_ERROR_INVALID_CERTIFICATE; 144 extern const NSSError NSS_ERROR_BUSY; 145 extern const NSSError NSS_ERROR_ALREADY_INITIALIZED; 146 extern const NSSError NSS_ERROR_PKCS11; 147 148 /* Look at the stan error stack and map it to NSS 3 errors */ 149 #define STAN_MAP_ERROR(x, y) \ 150 else if (error == (x)) { secError = y; } 151 152 /* 153 * map Stan errors into NSS errors 154 * This function examines the stan error stack and automatically sets 155 * PORT_SetError(); to the appropriate SEC_ERROR value. 156 */ 157 void 158 CERT_MapStanError() 159 { 160 PRInt32 *errorStack; 161 NSSError error, prevError; 162 int secError; 163 int i; 164 165 errorStack = NSS_GetErrorStack(); 166 if (errorStack == 0) { 167 PORT_SetError(0); 168 return; 169 } 170 error = prevError = CKR_GENERAL_ERROR; 171 /* get the 'top 2' error codes from the stack */ 172 for (i = 0; errorStack[i]; i++) { 173 prevError = error; 174 error = errorStack[i]; 175 } 176 if (error == NSS_ERROR_PKCS11) { 177 /* map it */ 178 secError = PK11_MapError(prevError); 179 } 180 STAN_MAP_ERROR(NSS_ERROR_NO_ERROR, 0) 181 STAN_MAP_ERROR(NSS_ERROR_NO_MEMORY, SEC_ERROR_NO_MEMORY) 182 STAN_MAP_ERROR(NSS_ERROR_INVALID_BASE64, SEC_ERROR_BAD_DATA) 183 STAN_MAP_ERROR(NSS_ERROR_INVALID_BER, SEC_ERROR_BAD_DER) 184 STAN_MAP_ERROR(NSS_ERROR_INVALID_ATAV, SEC_ERROR_INVALID_AVA) 185 STAN_MAP_ERROR(NSS_ERROR_INVALID_PASSWORD, SEC_ERROR_BAD_PASSWORD) 186 STAN_MAP_ERROR(NSS_ERROR_BUSY, SEC_ERROR_BUSY) 187 STAN_MAP_ERROR(NSS_ERROR_DEVICE_ERROR, SEC_ERROR_IO) 188 STAN_MAP_ERROR(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND, 189 SEC_ERROR_UNKNOWN_ISSUER) 190 STAN_MAP_ERROR(NSS_ERROR_INVALID_CERTIFICATE, SEC_ERROR_CERT_NOT_VALID) 191 STAN_MAP_ERROR(NSS_ERROR_INVALID_UTF8, SEC_ERROR_BAD_DATA) 192 STAN_MAP_ERROR(NSS_ERROR_INVALID_NSSOID, SEC_ERROR_BAD_DATA) 193 194 /* these are library failure for lack of a better error code */ 195 STAN_MAP_ERROR(NSS_ERROR_NOT_FOUND, SEC_ERROR_LIBRARY_FAILURE) 196 STAN_MAP_ERROR(NSS_ERROR_CERTIFICATE_IN_CACHE, SEC_ERROR_LIBRARY_FAILURE) 197 STAN_MAP_ERROR(NSS_ERROR_MAXIMUM_FOUND, SEC_ERROR_LIBRARY_FAILURE) 198 STAN_MAP_ERROR(NSS_ERROR_USER_CANCELED, SEC_ERROR_LIBRARY_FAILURE) 199 STAN_MAP_ERROR(NSS_ERROR_TRACKER_NOT_INITIALIZED, SEC_ERROR_LIBRARY_FAILURE) 200 STAN_MAP_ERROR(NSS_ERROR_ALREADY_INITIALIZED, SEC_ERROR_LIBRARY_FAILURE) 201 STAN_MAP_ERROR(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD, 202 SEC_ERROR_LIBRARY_FAILURE) 203 STAN_MAP_ERROR(NSS_ERROR_HASH_COLLISION, SEC_ERROR_LIBRARY_FAILURE) 204 205 STAN_MAP_ERROR(NSS_ERROR_INTERNAL_ERROR, SEC_ERROR_LIBRARY_FAILURE) 206 207 /* these are all invalid arguments */ 208 STAN_MAP_ERROR(NSS_ERROR_INVALID_ARGUMENT, SEC_ERROR_INVALID_ARGS) 209 STAN_MAP_ERROR(NSS_ERROR_INVALID_POINTER, SEC_ERROR_INVALID_ARGS) 210 STAN_MAP_ERROR(NSS_ERROR_INVALID_ARENA, SEC_ERROR_INVALID_ARGS) 211 STAN_MAP_ERROR(NSS_ERROR_INVALID_ARENA_MARK, SEC_ERROR_INVALID_ARGS) 212 STAN_MAP_ERROR(NSS_ERROR_DUPLICATE_POINTER, SEC_ERROR_INVALID_ARGS) 213 STAN_MAP_ERROR(NSS_ERROR_POINTER_NOT_REGISTERED, SEC_ERROR_INVALID_ARGS) 214 STAN_MAP_ERROR(NSS_ERROR_TRACKER_NOT_EMPTY, SEC_ERROR_INVALID_ARGS) 215 STAN_MAP_ERROR(NSS_ERROR_VALUE_TOO_LARGE, SEC_ERROR_INVALID_ARGS) 216 STAN_MAP_ERROR(NSS_ERROR_UNSUPPORTED_TYPE, SEC_ERROR_INVALID_ARGS) 217 STAN_MAP_ERROR(NSS_ERROR_BUFFER_TOO_SHORT, SEC_ERROR_INVALID_ARGS) 218 STAN_MAP_ERROR(NSS_ERROR_INVALID_ATOB_CONTEXT, SEC_ERROR_INVALID_ARGS) 219 STAN_MAP_ERROR(NSS_ERROR_INVALID_BTOA_CONTEXT, SEC_ERROR_INVALID_ARGS) 220 STAN_MAP_ERROR(NSS_ERROR_INVALID_ITEM, SEC_ERROR_INVALID_ARGS) 221 STAN_MAP_ERROR(NSS_ERROR_INVALID_STRING, SEC_ERROR_INVALID_ARGS) 222 STAN_MAP_ERROR(NSS_ERROR_INVALID_ASN1ENCODER, SEC_ERROR_INVALID_ARGS) 223 STAN_MAP_ERROR(NSS_ERROR_INVALID_ASN1DECODER, SEC_ERROR_INVALID_ARGS) 224 STAN_MAP_ERROR(NSS_ERROR_UNKNOWN_ATTRIBUTE, SEC_ERROR_INVALID_ARGS) 225 else { secError = SEC_ERROR_LIBRARY_FAILURE; } 226 PORT_SetError(secError); 227 } 228 229 SECStatus 230 CERT_ChangeCertTrust(CERTCertDBHandle *handle, CERTCertificate *cert, 231 CERTCertTrust *trust) 232 { 233 SECStatus rv = SECSuccess; 234 PRStatus ret; 235 236 ret = STAN_ChangeCertTrust(cert, trust); 237 if (ret != PR_SUCCESS) { 238 rv = SECFailure; 239 CERT_MapStanError(); 240 } 241 return rv; 242 } 243 244 extern const NSSError NSS_ERROR_INVALID_CERTIFICATE; 245 246 SECStatus 247 __CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname, 248 CERTCertTrust *trust) 249 { 250 NSSUTF8 *stanNick; 251 PK11SlotInfo *slot; 252 NSSToken *internal; 253 NSSCryptoContext *context; 254 nssCryptokiObject *permInstance; 255 NSSCertificate *c = STAN_GetNSSCertificate(cert); 256 nssCertificateStoreTrace lockTrace = { NULL, NULL, PR_FALSE, PR_FALSE }; 257 nssCertificateStoreTrace unlockTrace = { NULL, NULL, PR_FALSE, PR_FALSE }; 258 SECStatus rv; 259 PRStatus ret; 260 261 if (c == NULL) { 262 CERT_MapStanError(); 263 return SECFailure; 264 } 265 266 context = c->object.cryptoContext; 267 if (!context) { 268 PORT_SetError(SEC_ERROR_ADDING_CERT); 269 return SECFailure; /* wasn't a temp cert */ 270 } 271 stanNick = nssCertificate_GetNickname(c, NULL); 272 if (stanNick && nickname && strcmp(nickname, stanNick) != 0) { 273 /* different: take the new nickname */ 274 cert->nickname = NULL; 275 nss_ZFreeIf(stanNick); 276 stanNick = NULL; 277 } 278 if (!stanNick && nickname) { 279 /* Either there was no nickname yet, or we have a new nickname */ 280 stanNick = nssUTF8_Duplicate((NSSUTF8 *)nickname, NULL); 281 } /* else: old stanNick is identical to new nickname */ 282 /* Delete the temp instance */ 283 nssCertificateStore_Lock(context->certStore, &lockTrace); 284 nssCertificateStore_RemoveCertLOCKED(context->certStore, c); 285 nssCertificateStore_Unlock(context->certStore, &lockTrace, &unlockTrace); 286 c->object.cryptoContext = NULL; 287 288 /* if the id has not been set explicitly yet, create one from the public 289 * key. */ 290 if (c->id.data == NULL) { 291 SECItem *keyID = pk11_mkcertKeyID(cert); 292 if (keyID) { 293 nssItem_Create(c->object.arena, &c->id, keyID->len, keyID->data); 294 SECITEM_FreeItem(keyID, PR_TRUE); 295 } 296 /* if any of these failed, continue with our null c->id */ 297 } 298 299 /* Import the perm instance onto the internal token */ 300 slot = PK11_GetInternalKeySlot(); 301 internal = PK11Slot_GetNSSToken(slot); 302 if (!internal) { 303 PK11_FreeSlot(slot); 304 PORT_SetError(SEC_ERROR_NO_TOKEN); 305 return SECFailure; 306 } 307 permInstance = nssToken_ImportCertificate( 308 internal, NULL, NSSCertificateType_PKIX, &c->id, stanNick, &c->encoding, 309 &c->issuer, &c->subject, &c->serial, cert->emailAddr, PR_TRUE); 310 (void)nssToken_Destroy(internal); 311 nss_ZFreeIf(stanNick); 312 stanNick = NULL; 313 PK11_FreeSlot(slot); 314 if (!permInstance) { 315 if (NSS_GetError() == NSS_ERROR_INVALID_CERTIFICATE) { 316 PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL); 317 } 318 return SECFailure; 319 } 320 nssPKIObject_AddInstance(&c->object, permInstance); 321 nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1); 322 /* reset the CERTCertificate fields */ 323 CERT_LockCertTempPerm(cert); 324 cert->nssCertificate = NULL; 325 CERT_UnlockCertTempPerm(cert); 326 cert = STAN_GetCERTCertificateOrRelease(c); /* should return same pointer */ 327 if (!cert) { 328 CERT_MapStanError(); 329 return SECFailure; 330 } 331 CERT_LockCertTempPerm(cert); 332 cert->istemp = PR_FALSE; 333 cert->isperm = PR_TRUE; 334 CERT_UnlockCertTempPerm(cert); 335 if (!trust) { 336 return SECSuccess; 337 } 338 ret = STAN_ChangeCertTrust(cert, trust); 339 rv = SECSuccess; 340 if (ret != PR_SUCCESS) { 341 rv = SECFailure; 342 CERT_MapStanError(); 343 } 344 return rv; 345 } 346 347 SECStatus 348 CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname, 349 CERTCertTrust *trust) 350 { 351 return __CERT_AddTempCertToPerm(cert, nickname, trust); 352 } 353 354 CERTCertificate * 355 CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert, 356 char *nickname, PRBool isperm, PRBool copyDER) 357 { 358 NSSCertificate *c; 359 CERTCertificate *cc; 360 NSSCertificate *tempCert = NULL; 361 nssPKIObject *pkio; 362 NSSCryptoContext *gCC = STAN_GetDefaultCryptoContext(); 363 NSSTrustDomain *gTD = STAN_GetDefaultTrustDomain(); 364 if (!isperm) { 365 NSSDER encoding; 366 NSSITEM_FROM_SECITEM(&encoding, derCert); 367 /* First, see if it is already a temp cert */ 368 c = NSSCryptoContext_FindCertificateByEncodedCertificate(gCC, 369 &encoding); 370 if (!c && handle) { 371 /* Then, see if it is already a perm cert */ 372 c = NSSTrustDomain_FindCertificateByEncodedCertificate(handle, 373 &encoding); 374 } 375 if (c) { 376 /* actually, that search ends up going by issuer/serial, 377 * so it is still possible to return a cert with the same 378 * issuer/serial but a different encoding, and we're 379 * going to reject that 380 */ 381 if (!nssItem_Equal(&c->encoding, &encoding, NULL)) { 382 nssCertificate_Destroy(c); 383 PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL); 384 cc = NULL; 385 } else { 386 cc = STAN_GetCERTCertificateOrRelease(c); 387 if (cc == NULL) { 388 CERT_MapStanError(); 389 } 390 } 391 return cc; 392 } 393 } 394 pkio = nssPKIObject_Create(NULL, NULL, gTD, gCC, nssPKIMonitor); 395 if (!pkio) { 396 CERT_MapStanError(); 397 return NULL; 398 } 399 c = nss_ZNEW(pkio->arena, NSSCertificate); 400 if (!c) { 401 CERT_MapStanError(); 402 nssPKIObject_Destroy(pkio); 403 return NULL; 404 } 405 c->object = *pkio; 406 if (copyDER) { 407 nssItem_Create(c->object.arena, &c->encoding, derCert->len, 408 derCert->data); 409 } else { 410 NSSITEM_FROM_SECITEM(&c->encoding, derCert); 411 } 412 /* Forces a decoding of the cert in order to obtain the parts used 413 * below 414 */ 415 /* 'c' is not adopted here, if we fail loser frees what has been 416 * allocated so far for 'c' */ 417 cc = STAN_GetCERTCertificate(c); 418 if (!cc) { 419 CERT_MapStanError(); 420 goto loser; 421 } 422 nssItem_Create(c->object.arena, &c->issuer, cc->derIssuer.len, 423 cc->derIssuer.data); 424 nssItem_Create(c->object.arena, &c->subject, cc->derSubject.len, 425 cc->derSubject.data); 426 /* CERTCertificate stores serial numbers decoded. I need the DER 427 * here. sigh. 428 */ 429 SECItem derSerial = { 0 }; 430 CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial); 431 if (!derSerial.data) 432 goto loser; 433 nssItem_Create(c->object.arena, &c->serial, derSerial.len, 434 derSerial.data); 435 PORT_Free(derSerial.data); 436 437 if (nickname) { 438 c->object.tempName = 439 nssUTF8_Create(c->object.arena, nssStringType_UTF8String, 440 (NSSUTF8 *)nickname, PORT_Strlen(nickname)); 441 } 442 if (cc->emailAddr && cc->emailAddr[0]) { 443 c->email = nssUTF8_Create( 444 c->object.arena, nssStringType_PrintableString, 445 (NSSUTF8 *)cc->emailAddr, PORT_Strlen(cc->emailAddr)); 446 } 447 448 tempCert = NSSCryptoContext_FindOrImportCertificate(gCC, c); 449 if (!tempCert) { 450 CERT_MapStanError(); 451 goto loser; 452 } 453 /* destroy our copy */ 454 NSSCertificate_Destroy(c); 455 /* and use the stored entry */ 456 c = tempCert; 457 cc = STAN_GetCERTCertificateOrRelease(c); 458 if (!cc) { 459 /* STAN_GetCERTCertificateOrRelease destroys c on failure. */ 460 CERT_MapStanError(); 461 return NULL; 462 } 463 464 CERT_LockCertTempPerm(cc); 465 cc->istemp = PR_TRUE; 466 cc->isperm = PR_FALSE; 467 CERT_UnlockCertTempPerm(cc); 468 return cc; 469 loser: 470 /* Perhaps this should be nssCertificate_Destroy(c) */ 471 nssPKIObject_Destroy(&c->object); 472 return NULL; 473 } 474 475 /* This symbol is exported for backward compatibility. */ 476 CERTCertificate * 477 __CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert, 478 char *nickname, PRBool isperm, PRBool copyDER) 479 { 480 return CERT_NewTempCertificate(handle, derCert, nickname, isperm, copyDER); 481 } 482 483 static CERTCertificate * 484 common_FindCertByIssuerAndSN(CERTCertDBHandle *handle, 485 CERTIssuerAndSN *issuerAndSN, 486 void *wincx) 487 { 488 PK11SlotInfo *slot; 489 CERTCertificate *cert; 490 491 cert = PK11_FindCertByIssuerAndSN(&slot, issuerAndSN, wincx); 492 if (cert && slot) { 493 PK11_FreeSlot(slot); 494 } 495 496 return cert; 497 } 498 499 /* maybe all the wincx's should be some const for internal token login? */ 500 CERTCertificate * 501 CERT_FindCertByIssuerAndSN(CERTCertDBHandle *handle, 502 CERTIssuerAndSN *issuerAndSN) 503 { 504 return common_FindCertByIssuerAndSN(handle, issuerAndSN, NULL); 505 } 506 507 /* maybe all the wincx's should be some const for internal token login? */ 508 CERTCertificate * 509 CERT_FindCertByIssuerAndSNCX(CERTCertDBHandle *handle, 510 CERTIssuerAndSN *issuerAndSN, 511 void *wincx) 512 { 513 return common_FindCertByIssuerAndSN(handle, issuerAndSN, wincx); 514 } 515 516 static NSSCertificate * 517 get_best_temp_or_perm(NSSCertificate *ct, NSSCertificate *cp) 518 { 519 NSSUsage usage; 520 NSSCertificate *arr[3]; 521 if (!ct) { 522 return nssCertificate_AddRef(cp); 523 } else if (!cp) { 524 return nssCertificate_AddRef(ct); 525 } 526 arr[0] = ct; 527 arr[1] = cp; 528 arr[2] = NULL; 529 usage.anyUsage = PR_TRUE; 530 return nssCertificateArray_FindBestCertificate(arr, NULL, &usage, NULL); 531 } 532 533 CERTCertificate * 534 CERT_FindCertByName(CERTCertDBHandle *handle, SECItem *name) 535 { 536 NSSCertificate *cp, *ct, *c; 537 NSSDER subject; 538 NSSUsage usage; 539 NSSCryptoContext *cc; 540 NSSITEM_FROM_SECITEM(&subject, name); 541 usage.anyUsage = PR_TRUE; 542 cc = STAN_GetDefaultCryptoContext(); 543 ct = NSSCryptoContext_FindBestCertificateBySubject(cc, &subject, NULL, 544 &usage, NULL); 545 cp = NSSTrustDomain_FindBestCertificateBySubject(handle, &subject, NULL, 546 &usage, NULL); 547 c = get_best_temp_or_perm(ct, cp); 548 if (ct) { 549 CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct)); 550 } 551 if (cp) { 552 CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(cp)); 553 } 554 return c ? STAN_GetCERTCertificateOrRelease(c) : NULL; 555 } 556 557 CERTCertificate * 558 CERT_FindCertByKeyID(CERTCertDBHandle *handle, SECItem *name, SECItem *keyID) 559 { 560 CERTCertList *list; 561 CERTCertificate *cert = NULL; 562 CERTCertListNode *node; 563 564 list = CERT_CreateSubjectCertList(NULL, handle, name, 0, PR_FALSE); 565 if (list == NULL) 566 return NULL; 567 568 node = CERT_LIST_HEAD(list); 569 while (!CERT_LIST_END(node, list)) { 570 if (node->cert && 571 SECITEM_ItemsAreEqual(&node->cert->subjectKeyID, keyID)) { 572 cert = CERT_DupCertificate(node->cert); 573 goto done; 574 } 575 node = CERT_LIST_NEXT(node); 576 } 577 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); 578 579 done: 580 CERT_DestroyCertList(list); 581 return cert; 582 } 583 584 CERTCertificate * 585 CERT_FindCertByNickname(CERTCertDBHandle *handle, const char *nickname) 586 { 587 NSSCryptoContext *cc; 588 NSSCertificate *c, *ct; 589 CERTCertificate *cert; 590 NSSUsage usage; 591 usage.anyUsage = PR_TRUE; 592 cc = STAN_GetDefaultCryptoContext(); 593 ct = NSSCryptoContext_FindBestCertificateByNickname(cc, nickname, NULL, 594 &usage, NULL); 595 cert = PK11_FindCertFromNickname(nickname, NULL); 596 c = NULL; 597 if (cert) { 598 c = get_best_temp_or_perm(ct, STAN_GetNSSCertificate(cert)); 599 CERT_DestroyCertificate(cert); 600 if (ct) { 601 CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct)); 602 } 603 } else { 604 c = ct; 605 } 606 return c ? STAN_GetCERTCertificateOrRelease(c) : NULL; 607 } 608 609 CERTCertificate * 610 CERT_FindCertByDERCert(CERTCertDBHandle *handle, SECItem *derCert) 611 { 612 NSSCryptoContext *cc; 613 NSSCertificate *c; 614 NSSDER encoding; 615 NSSITEM_FROM_SECITEM(&encoding, derCert); 616 cc = STAN_GetDefaultCryptoContext(); 617 c = NSSCryptoContext_FindCertificateByEncodedCertificate(cc, &encoding); 618 if (!c) { 619 c = NSSTrustDomain_FindCertificateByEncodedCertificate(handle, 620 &encoding); 621 if (!c) 622 return NULL; 623 } 624 return STAN_GetCERTCertificateOrRelease(c); 625 } 626 627 static CERTCertificate * 628 common_FindCertByNicknameOrEmailAddrForUsage(CERTCertDBHandle *handle, 629 const char *name, PRBool anyUsage, 630 SECCertUsage lookingForUsage, 631 void *wincx) 632 { 633 NSSCryptoContext *cc; 634 NSSCertificate *c, *ct; 635 CERTCertificate *cert = NULL; 636 NSSUsage usage; 637 CERTCertList *certlist; 638 639 if (NULL == name) { 640 PORT_SetError(SEC_ERROR_INVALID_ARGS); 641 return NULL; 642 } 643 644 usage.anyUsage = anyUsage; 645 646 if (!anyUsage) { 647 usage.nss3lookingForCA = PR_FALSE; 648 usage.nss3usage = lookingForUsage; 649 } 650 651 cc = STAN_GetDefaultCryptoContext(); 652 ct = NSSCryptoContext_FindBestCertificateByNickname(cc, name, NULL, &usage, 653 NULL); 654 if (!ct && PORT_Strchr(name, '@') != NULL) { 655 char *lowercaseName = CERT_FixupEmailAddr(name); 656 if (lowercaseName) { 657 ct = NSSCryptoContext_FindBestCertificateByEmail( 658 cc, lowercaseName, NULL, &usage, NULL); 659 PORT_Free(lowercaseName); 660 } 661 } 662 663 if (anyUsage) { 664 cert = PK11_FindCertFromNickname(name, wincx); 665 } else { 666 if (ct) { 667 /* Does ct really have the required usage? */ 668 nssDecodedCert *dc; 669 dc = nssCertificate_GetDecoding(ct); 670 if (!dc->matchUsage(dc, &usage)) { 671 CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct)); 672 ct = NULL; 673 } 674 } 675 676 certlist = PK11_FindCertsFromNickname(name, wincx); 677 if (certlist) { 678 SECStatus rv = 679 CERT_FilterCertListByUsage(certlist, lookingForUsage, PR_FALSE); 680 if (SECSuccess == rv && !CERT_LIST_EMPTY(certlist)) { 681 cert = CERT_DupCertificate(CERT_LIST_HEAD(certlist)->cert); 682 } 683 CERT_DestroyCertList(certlist); 684 } 685 } 686 687 if (cert) { 688 c = get_best_temp_or_perm(ct, STAN_GetNSSCertificate(cert)); 689 CERT_DestroyCertificate(cert); 690 if (ct) { 691 CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct)); 692 } 693 } else { 694 c = ct; 695 } 696 return c ? STAN_GetCERTCertificateOrRelease(c) : NULL; 697 } 698 699 CERTCertificate * 700 CERT_FindCertByNicknameOrEmailAddr(CERTCertDBHandle *handle, const char *name) 701 { 702 return common_FindCertByNicknameOrEmailAddrForUsage(handle, name, PR_TRUE, 703 0, NULL); 704 } 705 706 CERTCertificate * 707 CERT_FindCertByNicknameOrEmailAddrCX(CERTCertDBHandle *handle, const char *name, 708 void *wincx) 709 { 710 return common_FindCertByNicknameOrEmailAddrForUsage(handle, name, PR_TRUE, 711 0, wincx); 712 } 713 714 CERTCertificate * 715 CERT_FindCertByNicknameOrEmailAddrForUsage(CERTCertDBHandle *handle, 716 const char *name, 717 SECCertUsage lookingForUsage) 718 { 719 return common_FindCertByNicknameOrEmailAddrForUsage(handle, name, PR_FALSE, 720 lookingForUsage, NULL); 721 } 722 723 CERTCertificate * 724 CERT_FindCertByNicknameOrEmailAddrForUsageCX(CERTCertDBHandle *handle, 725 const char *name, 726 SECCertUsage lookingForUsage, 727 void *wincx) 728 { 729 return common_FindCertByNicknameOrEmailAddrForUsage(handle, name, PR_FALSE, 730 lookingForUsage, wincx); 731 } 732 733 static void 734 add_to_subject_list(CERTCertList *certList, CERTCertificate *cert, 735 PRBool validOnly, PRTime sorttime) 736 { 737 SECStatus secrv; 738 if (!validOnly || 739 CERT_CheckCertValidTimes(cert, sorttime, PR_FALSE) == 740 secCertTimeValid) { 741 secrv = CERT_AddCertToListSorted(certList, cert, CERT_SortCBValidity, 742 (void *)&sorttime); 743 if (secrv != SECSuccess) { 744 CERT_DestroyCertificate(cert); 745 } 746 } else { 747 CERT_DestroyCertificate(cert); 748 } 749 } 750 751 CERTCertList * 752 CERT_CreateSubjectCertList(CERTCertList *certList, CERTCertDBHandle *handle, 753 const SECItem *name, PRTime sorttime, 754 PRBool validOnly) 755 { 756 NSSCryptoContext *cc; 757 NSSCertificate **tSubjectCerts, **pSubjectCerts; 758 NSSCertificate **ci; 759 CERTCertificate *cert; 760 NSSDER subject; 761 PRBool myList = PR_FALSE; 762 cc = STAN_GetDefaultCryptoContext(); 763 NSSITEM_FROM_SECITEM(&subject, name); 764 /* Collect both temp and perm certs for the subject */ 765 tSubjectCerts = 766 NSSCryptoContext_FindCertificatesBySubject(cc, &subject, NULL, 0, NULL); 767 pSubjectCerts = NSSTrustDomain_FindCertificatesBySubject(handle, &subject, 768 NULL, 0, NULL); 769 if (!tSubjectCerts && !pSubjectCerts) { 770 return NULL; 771 } 772 if (certList == NULL) { 773 certList = CERT_NewCertList(); 774 myList = PR_TRUE; 775 if (!certList) 776 goto loser; 777 } 778 /* Iterate over the matching temp certs. Add them to the list */ 779 ci = tSubjectCerts; 780 while (ci && *ci) { 781 cert = STAN_GetCERTCertificateOrRelease(*ci); 782 /* *ci may be invalid at this point, don't reference it again */ 783 if (cert) { 784 /* NOTE: add_to_subject_list adopts the incoming cert. */ 785 add_to_subject_list(certList, cert, validOnly, sorttime); 786 } 787 ci++; 788 } 789 /* Iterate over the matching perm certs. Add them to the list */ 790 ci = pSubjectCerts; 791 while (ci && *ci) { 792 cert = STAN_GetCERTCertificateOrRelease(*ci); 793 /* *ci may be invalid at this point, don't reference it again */ 794 if (cert) { 795 /* NOTE: add_to_subject_list adopts the incoming cert. */ 796 add_to_subject_list(certList, cert, validOnly, sorttime); 797 } 798 ci++; 799 } 800 /* all the references have been adopted or freed at this point, just 801 * free the arrays now */ 802 nss_ZFreeIf(tSubjectCerts); 803 nss_ZFreeIf(pSubjectCerts); 804 return certList; 805 loser: 806 /* need to free the references in tSubjectCerts and pSubjectCerts! */ 807 nssCertificateArray_Destroy(tSubjectCerts); 808 nssCertificateArray_Destroy(pSubjectCerts); 809 if (myList && certList != NULL) { 810 CERT_DestroyCertList(certList); 811 } 812 return NULL; 813 } 814 815 void 816 CERT_DestroyCertificate(CERTCertificate *cert) 817 { 818 if (cert) { 819 /* don't use STAN_GetNSSCertificate because we don't want to 820 * go to the trouble of translating the CERTCertificate into 821 * an NSSCertificate just to destroy it. If it hasn't been done 822 * yet, don't do it at all 823 * 824 * cert->nssCertificate contains its own locks and refcount, but as it 825 * may be NULL, the pointer itself must be guarded by some other lock. 826 * Rather than creating a new global lock for only this purpose, share 827 * an existing global lock that happens to be taken near the write in 828 * fill_CERTCertificateFields(). The longer-term goal is to refactor 829 * all these global locks to be certificate-scoped. */ 830 CERT_MaybeLockCertTempPerm(cert); 831 NSSCertificate *tmp = cert->nssCertificate; 832 CERT_MaybeUnlockCertTempPerm(cert); 833 if (tmp) { 834 /* delete the NSSCertificate */ 835 NSSCertificate_Destroy(tmp); 836 } else if (cert->arena) { 837 PORT_FreeArena(cert->arena, PR_FALSE); 838 } 839 } 840 return; 841 } 842 843 int 844 CERT_GetDBContentVersion(CERTCertDBHandle *handle) 845 { 846 /* should read the DB content version from the pkcs #11 device */ 847 return 0; 848 } 849 850 SECStatus 851 certdb_SaveSingleProfile(CERTCertificate *cert, const char *emailAddr, 852 SECItem *emailProfile, SECItem *profileTime) 853 { 854 PRTime oldtime; 855 PRTime newtime; 856 SECStatus rv = SECFailure; 857 PRBool saveit; 858 SECItem oldprof, oldproftime; 859 SECItem *oldProfile = NULL; 860 SECItem *oldProfileTime = NULL; 861 PK11SlotInfo *slot = NULL; 862 NSSCertificate *c; 863 NSSCryptoContext *cc; 864 nssSMIMEProfile *stanProfile = NULL; 865 PRBool freeOldProfile = PR_FALSE; 866 867 c = STAN_GetNSSCertificate(cert); 868 if (!c) 869 return SECFailure; 870 cc = c->object.cryptoContext; 871 if (cc != NULL) { 872 stanProfile = nssCryptoContext_FindSMIMEProfileForCertificate(cc, c); 873 if (stanProfile) { 874 PORT_Assert(stanProfile->profileData); 875 SECITEM_FROM_NSSITEM(&oldprof, stanProfile->profileData); 876 oldProfile = &oldprof; 877 SECITEM_FROM_NSSITEM(&oldproftime, stanProfile->profileTime); 878 oldProfileTime = &oldproftime; 879 } 880 } else { 881 oldProfile = PK11_FindSMimeProfile(&slot, (char *)emailAddr, 882 &cert->derSubject, &oldProfileTime); 883 freeOldProfile = PR_TRUE; 884 } 885 886 saveit = PR_FALSE; 887 888 /* both profileTime and emailProfile have to exist or not exist */ 889 if (emailProfile == NULL) { 890 profileTime = NULL; 891 } else if (profileTime == NULL) { 892 emailProfile = NULL; 893 } 894 895 if (oldProfileTime == NULL) { 896 saveit = PR_TRUE; 897 } else { 898 /* there was already a profile for this email addr */ 899 if (profileTime) { 900 /* we have an old and new profile - save whichever is more recent*/ 901 if (oldProfileTime->len == 0) { 902 /* always replace if old entry doesn't have a time */ 903 oldtime = LL_MININT; 904 } else { 905 rv = DER_UTCTimeToTime(&oldtime, oldProfileTime); 906 if (rv != SECSuccess) { 907 goto loser; 908 } 909 } 910 911 rv = DER_UTCTimeToTime(&newtime, profileTime); 912 if (rv != SECSuccess) { 913 goto loser; 914 } 915 916 if (LL_CMP(newtime, >, oldtime)) { 917 /* this is a newer profile, save it and cert */ 918 saveit = PR_TRUE; 919 } 920 } else { 921 saveit = PR_TRUE; 922 } 923 } 924 925 if (saveit) { 926 if (cc) { 927 if (stanProfile && profileTime && emailProfile) { 928 /* stanProfile is already stored in the crypto context, 929 * overwrite the data 930 */ 931 NSSArena *arena = stanProfile->object.arena; 932 stanProfile->profileTime = nssItem_Create( 933 arena, NULL, profileTime->len, profileTime->data); 934 stanProfile->profileData = nssItem_Create( 935 arena, NULL, emailProfile->len, emailProfile->data); 936 } else if (profileTime && emailProfile) { 937 PRStatus nssrv; 938 NSSItem profTime, profData; 939 NSSITEM_FROM_SECITEM(&profTime, profileTime); 940 NSSITEM_FROM_SECITEM(&profData, emailProfile); 941 stanProfile = nssSMIMEProfile_Create(c, &profTime, &profData); 942 if (!stanProfile) 943 goto loser; 944 nssrv = nssCryptoContext_ImportSMIMEProfile(cc, stanProfile); 945 rv = (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure; 946 } 947 } else { 948 rv = PK11_SaveSMimeProfile(slot, (char *)emailAddr, 949 &cert->derSubject, emailProfile, 950 profileTime); 951 } 952 } else { 953 rv = SECSuccess; 954 } 955 956 loser: 957 if (oldProfile && freeOldProfile) { 958 SECITEM_FreeItem(oldProfile, PR_TRUE); 959 } 960 if (oldProfileTime && freeOldProfile) { 961 SECITEM_FreeItem(oldProfileTime, PR_TRUE); 962 } 963 if (stanProfile) { 964 nssSMIMEProfile_Destroy(stanProfile); 965 } 966 if (slot) { 967 PK11_FreeSlot(slot); 968 } 969 970 return (rv); 971 } 972 973 /* 974 * 975 * Manage S/MIME profiles 976 * 977 */ 978 979 SECStatus 980 CERT_SaveSMimeProfile(CERTCertificate *cert, SECItem *emailProfile, 981 SECItem *profileTime) 982 { 983 const char *emailAddr; 984 SECStatus rv; 985 PRBool isperm = PR_FALSE; 986 987 if (!cert) { 988 return SECFailure; 989 } 990 991 if (cert->slot && !PK11_IsInternal(cert->slot)) { 992 /* this cert comes from an external source, we need to add it 993 to the cert db before creating an S/MIME profile */ 994 PK11SlotInfo *internalslot = PK11_GetInternalKeySlot(); 995 if (!internalslot) { 996 return SECFailure; 997 } 998 rv = PK11_ImportCert(internalslot, cert, CK_INVALID_HANDLE, NULL, 999 PR_FALSE); 1000 1001 PK11_FreeSlot(internalslot); 1002 if (rv != SECSuccess) { 1003 return SECFailure; 1004 } 1005 } 1006 1007 rv = CERT_GetCertIsPerm(cert, &isperm); 1008 if (rv != SECSuccess) { 1009 return SECFailure; 1010 } 1011 if (cert->slot && isperm && CERT_IsUserCert(cert) && 1012 (!emailProfile || !emailProfile->len)) { 1013 /* Don't clobber emailProfile for user certs. */ 1014 return SECSuccess; 1015 } 1016 1017 for (emailAddr = CERT_GetFirstEmailAddress(cert); emailAddr != NULL; 1018 emailAddr = CERT_GetNextEmailAddress(cert, emailAddr)) { 1019 rv = certdb_SaveSingleProfile(cert, emailAddr, emailProfile, 1020 profileTime); 1021 if (rv != SECSuccess) { 1022 return SECFailure; 1023 } 1024 } 1025 return SECSuccess; 1026 } 1027 1028 SECItem * 1029 CERT_FindSMimeProfile(CERTCertificate *cert) 1030 { 1031 PK11SlotInfo *slot = NULL; 1032 NSSCertificate *c; 1033 NSSCryptoContext *cc; 1034 SECItem *rvItem = NULL; 1035 1036 if (!cert || !cert->emailAddr || !cert->emailAddr[0]) { 1037 PORT_SetError(SEC_ERROR_INVALID_ARGS); 1038 return NULL; 1039 } 1040 c = STAN_GetNSSCertificate(cert); 1041 if (!c) 1042 return NULL; 1043 cc = c->object.cryptoContext; 1044 if (cc != NULL) { 1045 nssSMIMEProfile *stanProfile; 1046 stanProfile = nssCryptoContext_FindSMIMEProfileForCertificate(cc, c); 1047 if (stanProfile) { 1048 rvItem = 1049 SECITEM_AllocItem(NULL, NULL, stanProfile->profileData->size); 1050 if (rvItem) { 1051 rvItem->data = stanProfile->profileData->data; 1052 } 1053 nssSMIMEProfile_Destroy(stanProfile); 1054 } 1055 return rvItem; 1056 } 1057 rvItem = 1058 PK11_FindSMimeProfile(&slot, cert->emailAddr, &cert->derSubject, NULL); 1059 if (slot) { 1060 PK11_FreeSlot(slot); 1061 } 1062 return rvItem; 1063 } 1064 1065 SECStatus 1066 CERT_GetCertIsPerm(const CERTCertificate *cert, PRBool *isperm) 1067 { 1068 if (cert == NULL) { 1069 return SECFailure; 1070 } 1071 1072 CERT_LockCertTempPerm(cert); 1073 *isperm = cert->isperm; 1074 CERT_UnlockCertTempPerm(cert); 1075 return SECSuccess; 1076 } 1077 1078 SECStatus 1079 CERT_GetCertIsTemp(const CERTCertificate *cert, PRBool *istemp) 1080 { 1081 if (cert == NULL) { 1082 return SECFailure; 1083 } 1084 1085 CERT_LockCertTempPerm(cert); 1086 *istemp = cert->istemp; 1087 CERT_UnlockCertTempPerm(cert); 1088 return SECSuccess; 1089 } 1090 1091 /* 1092 * deprecated functions that are now just stubs. 1093 */ 1094 /* 1095 * Close the database 1096 */ 1097 void 1098 __CERT_ClosePermCertDB(CERTCertDBHandle *handle) 1099 { 1100 PORT_Assert("CERT_ClosePermCertDB is Deprecated" == NULL); 1101 return; 1102 } 1103 1104 SECStatus 1105 CERT_OpenCertDBFilename(CERTCertDBHandle *handle, char *certdbname, 1106 PRBool readOnly) 1107 { 1108 PORT_Assert("CERT_OpenCertDBFilename is Deprecated" == NULL); 1109 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); 1110 return SECFailure; 1111 } 1112 1113 SECItem * 1114 SECKEY_HashPassword(char *pw, SECItem *salt) 1115 { 1116 PORT_Assert("SECKEY_HashPassword is Deprecated" == NULL); 1117 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); 1118 return NULL; 1119 } 1120 1121 SECStatus 1122 __CERT_TraversePermCertsForSubject(CERTCertDBHandle *handle, 1123 SECItem *derSubject, void *cb, void *cbarg) 1124 { 1125 PORT_Assert("CERT_TraversePermCertsForSubject is Deprecated" == NULL); 1126 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); 1127 return SECFailure; 1128 } 1129 1130 SECStatus 1131 __CERT_TraversePermCertsForNickname(CERTCertDBHandle *handle, char *nickname, 1132 void *cb, void *cbarg) 1133 { 1134 PORT_Assert("CERT_TraversePermCertsForNickname is Deprecated" == NULL); 1135 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); 1136 return SECFailure; 1137 }