pk11cert.c (94274B)
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 * This file manages PKCS #11 instances of certificates. 6 */ 7 8 #include <stddef.h> 9 10 #include "secport.h" 11 #include "seccomon.h" 12 #include "secmod.h" 13 #include "secmodi.h" 14 #include "secmodti.h" 15 #include "pkcs11.h" 16 #include "pk11func.h" 17 #include "cert.h" 18 #include "certi.h" 19 #include "secitem.h" 20 #include "keyhi.h" 21 #include "secoid.h" 22 #include "pkcs7t.h" 23 #include "cmsreclist.h" 24 25 #include "certdb.h" 26 #include "secerr.h" 27 #include "sslerr.h" 28 29 #include "pki3hack.h" 30 #include "dev3hack.h" 31 32 #include "devm.h" 33 #include "nsspki.h" 34 #include "pki.h" 35 #include "pkim.h" 36 #include "pkitm.h" 37 #include "pkistore.h" /* to remove temp cert */ 38 #include "devt.h" 39 #include "ckhelper.h" 40 #include "pkcs11uri.h" 41 42 extern const NSSError NSS_ERROR_NOT_FOUND; 43 extern const NSSError NSS_ERROR_INVALID_CERTIFICATE; 44 45 struct nss3_cert_cbstr { 46 SECStatus (*callback)(CERTCertificate *, void *); 47 nssList *cached; 48 void *arg; 49 }; 50 51 /* Translate from NSSCertificate to CERTCertificate, then pass the latter 52 * to a callback. 53 */ 54 static PRStatus 55 convert_cert(NSSCertificate *c, void *arg) 56 { 57 CERTCertificate *nss3cert; 58 SECStatus secrv; 59 struct nss3_cert_cbstr *nss3cb = (struct nss3_cert_cbstr *)arg; 60 /* 'c' is not adopted. caller will free it */ 61 nss3cert = STAN_GetCERTCertificate(c); 62 if (!nss3cert) 63 return PR_FAILURE; 64 secrv = (*nss3cb->callback)(nss3cert, nss3cb->arg); 65 return (secrv) ? PR_FAILURE : PR_SUCCESS; 66 } 67 68 /* 69 * build a cert nickname based on the token name and the label of the 70 * certificate If the label in NULL, build a label based on the ID. 71 */ 72 static int 73 toHex(int x) 74 { 75 return (x < 10) ? (x + '0') : (x + 'a' - 10); 76 } 77 #define MAX_CERT_ID 4 78 #define DEFAULT_STRING "Cert ID " 79 static char * 80 pk11_buildNickname(PK11SlotInfo *slot, CK_ATTRIBUTE *cert_label, 81 CK_ATTRIBUTE *key_label, CK_ATTRIBUTE *cert_id) 82 { 83 int prefixLen = PORT_Strlen(slot->token_name); 84 int suffixLen = 0; 85 char *suffix = NULL; 86 char buildNew[sizeof(DEFAULT_STRING) + MAX_CERT_ID * 2]; 87 char *next, *nickname; 88 89 if (cert_label && (cert_label->ulValueLen)) { 90 suffixLen = cert_label->ulValueLen; 91 suffix = (char *)cert_label->pValue; 92 } else if (key_label && (key_label->ulValueLen)) { 93 suffixLen = key_label->ulValueLen; 94 suffix = (char *)key_label->pValue; 95 } else if (cert_id && cert_id->ulValueLen > 0) { 96 int i, first = cert_id->ulValueLen - MAX_CERT_ID; 97 int offset = sizeof(DEFAULT_STRING); 98 char *idValue = (char *)cert_id->pValue; 99 100 PORT_Memcpy(buildNew, DEFAULT_STRING, sizeof(DEFAULT_STRING) - 1); 101 next = buildNew + offset; 102 if (first < 0) 103 first = 0; 104 for (i = first; i < (int)cert_id->ulValueLen; i++) { 105 *next++ = toHex((idValue[i] >> 4) & 0xf); 106 *next++ = toHex(idValue[i] & 0xf); 107 } 108 *next++ = 0; 109 suffix = buildNew; 110 suffixLen = PORT_Strlen(buildNew); 111 } else { 112 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 113 return NULL; 114 } 115 116 /* if is internal key slot, add code to skip the prefix!! */ 117 next = nickname = (char *)PORT_Alloc(prefixLen + 1 + suffixLen + 1); 118 if (nickname == NULL) 119 return NULL; 120 121 PORT_Memcpy(next, slot->token_name, prefixLen); 122 next += prefixLen; 123 *next++ = ':'; 124 PORT_Memcpy(next, suffix, suffixLen); 125 next += suffixLen; 126 *next++ = 0; 127 return nickname; 128 } 129 130 PRBool 131 PK11_IsUserCert(PK11SlotInfo *slot, CERTCertificate *cert, 132 CK_OBJECT_HANDLE certID) 133 { 134 CK_OBJECT_CLASS theClass; 135 136 if (slot == NULL) 137 return PR_FALSE; 138 if (cert == NULL) 139 return PR_FALSE; 140 141 theClass = CKO_PRIVATE_KEY; 142 if (pk11_LoginStillRequired(slot, NULL)) { 143 theClass = CKO_PUBLIC_KEY; 144 } 145 if (PK11_MatchItem(slot, certID, theClass) != CK_INVALID_HANDLE) { 146 return PR_TRUE; 147 } 148 149 if (theClass == CKO_PUBLIC_KEY) { 150 SECKEYPublicKey *pubKey = CERT_ExtractPublicKey(cert); 151 CK_ATTRIBUTE theTemplate; 152 153 if (pubKey == NULL) { 154 return PR_FALSE; 155 } 156 157 PK11_SETATTRS(&theTemplate, 0, NULL, 0); 158 switch (pubKey->keyType) { 159 case rsaKey: 160 case rsaPssKey: 161 case rsaOaepKey: 162 PK11_SETATTRS(&theTemplate, CKA_MODULUS, pubKey->u.rsa.modulus.data, 163 pubKey->u.rsa.modulus.len); 164 break; 165 case dsaKey: 166 PK11_SETATTRS(&theTemplate, CKA_VALUE, pubKey->u.dsa.publicValue.data, 167 pubKey->u.dsa.publicValue.len); 168 break; 169 case dhKey: 170 PK11_SETATTRS(&theTemplate, CKA_VALUE, pubKey->u.dh.publicValue.data, 171 pubKey->u.dh.publicValue.len); 172 break; 173 case ecKey: 174 case edKey: 175 case ecMontKey: 176 PK11_SETATTRS(&theTemplate, CKA_EC_POINT, 177 pubKey->u.ec.publicValue.data, 178 pubKey->u.ec.publicValue.len); 179 break; 180 case mldsaKey: 181 PK11_SETATTRS(&theTemplate, CKA_VALUE, 182 pubKey->u.mldsa.publicValue.data, 183 pubKey->u.mldsa.publicValue.len); 184 break; 185 case keaKey: 186 case fortezzaKey: 187 case kyberKey: 188 case nullKey: 189 /* fall through and return false */ 190 break; 191 } 192 193 if (theTemplate.ulValueLen == 0) { 194 SECKEY_DestroyPublicKey(pubKey); 195 return PR_FALSE; 196 } 197 if (pubKey->keyType != ecKey && pubKey->keyType != edKey && 198 pubKey->keyType != ecMontKey && pubKey->keyType != mldsaKey) { 199 pk11_SignedToUnsigned(&theTemplate); 200 } 201 if (pk11_FindObjectByTemplate(slot, &theTemplate, 1) != CK_INVALID_HANDLE) { 202 SECKEY_DestroyPublicKey(pubKey); 203 return PR_TRUE; 204 } 205 SECKEY_DestroyPublicKey(pubKey); 206 } 207 return PR_FALSE; 208 } 209 210 /* 211 * Check out if a cert has ID of zero. This is a magic ID that tells 212 * NSS that this cert may be an automagically trusted cert. 213 * The Cert has to be self signed as well. That check is done elsewhere. 214 * 215 */ 216 PRBool 217 pk11_isID0(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID) 218 { 219 CK_ATTRIBUTE keyID = { CKA_ID, NULL, 0 }; 220 PRBool isZero = PR_FALSE; 221 int i; 222 CK_RV crv; 223 224 crv = PK11_GetAttributes(NULL, slot, certID, &keyID, 1); 225 if (crv != CKR_OK) { 226 return isZero; 227 } 228 229 if (keyID.ulValueLen != 0) { 230 char *value = (char *)keyID.pValue; 231 isZero = PR_TRUE; /* ID exists, may be zero */ 232 for (i = 0; i < (int)keyID.ulValueLen; i++) { 233 if (value[i] != 0) { 234 isZero = PR_FALSE; /* nope */ 235 break; 236 } 237 } 238 } 239 PORT_Free(keyID.pValue); 240 return isZero; 241 } 242 243 /* 244 * Create an NSSCertificate from a slot/certID pair, return it as a 245 * CERTCertificate. Optionally, output the nickname string. 246 */ 247 static CERTCertificate * 248 pk11_fastCert(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID, 249 CK_ATTRIBUTE *privateLabel, char **nickptr) 250 { 251 NSSCertificate *c; 252 nssCryptokiObject *co = NULL; 253 nssPKIObject *pkio; 254 NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); 255 256 /* Get the cryptoki object from the handle */ 257 NSSToken *token = PK11Slot_GetNSSToken(slot); 258 if (!token || !token->defaultSession) { 259 (void)nssToken_Destroy(token); /* null token is ok */ 260 PORT_SetError(SEC_ERROR_NO_TOKEN); 261 return NULL; 262 } 263 co = nssCryptokiObject_Create(token, token->defaultSession, certID); 264 (void)nssToken_Destroy(token); 265 if (!co) { 266 return NULL; 267 } 268 269 /* Create a PKI object from the cryptoki instance */ 270 pkio = nssPKIObject_Create(NULL, co, td, NULL, nssPKIMonitor); 271 if (!pkio) { 272 nssCryptokiObject_Destroy(co); 273 return NULL; 274 } 275 276 /* Create a certificate */ 277 c = nssCertificate_Create(pkio); 278 if (!c) { 279 nssPKIObject_Destroy(pkio); 280 return NULL; 281 } 282 283 /* Build and output a nickname, if desired. 284 * This must be done before calling nssTrustDomain_AddCertsToCache 285 * because that function may destroy c, pkio and co! 286 */ 287 if ((nickptr) && (co->label)) { 288 CK_ATTRIBUTE label, id; 289 290 label.type = CKA_LABEL; 291 label.pValue = co->label; 292 label.ulValueLen = PORT_Strlen(co->label); 293 294 id.type = CKA_ID; 295 id.pValue = c->id.data; 296 id.ulValueLen = c->id.size; 297 298 *nickptr = pk11_buildNickname(slot, &label, privateLabel, &id); 299 } 300 301 /* This function may destroy the cert in "c" and all its subordinate 302 * structures, and replace the value in "c" with the address of a 303 * different NSSCertificate that it found in the cache. 304 * Presumably, the nickname which we just output above remains valid. :) 305 */ 306 (void)nssTrustDomain_AddCertsToCache(td, &c, 1); 307 return STAN_GetCERTCertificateOrRelease(c); 308 } 309 310 /* 311 * Build an CERTCertificate structure from a PKCS#11 object ID.... certID 312 * Must be a CertObject. This code does not explicitly checks that. 313 */ 314 CERTCertificate * 315 PK11_MakeCertFromHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID, 316 CK_ATTRIBUTE *privateLabel) 317 { 318 char *nickname = NULL; 319 CERTCertificate *cert = NULL; 320 CERTCertTrust *trust; 321 322 if (slot == NULL || certID == CK_INVALID_HANDLE) { 323 PORT_SetError(SEC_ERROR_INVALID_ARGS); 324 return NULL; 325 } 326 327 cert = pk11_fastCert(slot, certID, privateLabel, &nickname); 328 if (cert == NULL) { 329 goto loser; 330 } 331 332 if (nickname) { 333 if (cert->nickname != NULL) { 334 cert->dbnickname = cert->nickname; 335 } 336 cert->nickname = PORT_ArenaStrdup(cert->arena, nickname); 337 PORT_Free(nickname); 338 nickname = NULL; 339 } 340 341 /* remember where this cert came from.... If we have just looked 342 * it up from the database and it already has a slot, don't add a new 343 * one. */ 344 if (cert->slot == NULL) { 345 cert->slot = PK11_ReferenceSlot(slot); 346 cert->pkcs11ID = certID; 347 cert->ownSlot = PR_TRUE; 348 cert->series = slot->series; 349 } 350 351 trust = (CERTCertTrust *)PORT_ArenaAlloc(cert->arena, sizeof(CERTCertTrust)); 352 if (trust == NULL) 353 goto loser; 354 PORT_Memset(trust, 0, sizeof(CERTCertTrust)); 355 356 if (!pk11_HandleTrustObject(slot, cert, trust)) { 357 unsigned int type; 358 359 /* build some cert trust flags */ 360 if (CERT_IsCACert(cert, &type)) { 361 unsigned int trustflags = CERTDB_VALID_CA; 362 363 /* Allow PKCS #11 modules to give us trusted CA's. We only accept 364 * valid CA's which are self-signed here. They must have an object 365 * ID of '0'. */ 366 if (pk11_isID0(slot, certID) && 367 cert->isRoot) { 368 trustflags |= CERTDB_TRUSTED_CA; 369 /* is the slot a fortezza card? allow the user or 370 * admin to turn on objectSigning, but don't turn 371 * full trust on explicitly */ 372 if (PK11_DoesMechanism(slot, CKM_KEA_KEY_DERIVE)) { 373 trust->objectSigningFlags |= CERTDB_VALID_CA; 374 } 375 } 376 if ((type & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) { 377 trust->sslFlags |= trustflags; 378 } 379 if ((type & NS_CERT_TYPE_EMAIL_CA) == NS_CERT_TYPE_EMAIL_CA) { 380 trust->emailFlags |= trustflags; 381 } 382 if ((type & NS_CERT_TYPE_OBJECT_SIGNING_CA) == NS_CERT_TYPE_OBJECT_SIGNING_CA) { 383 trust->objectSigningFlags |= trustflags; 384 } 385 } 386 } 387 388 if (PK11_IsUserCert(slot, cert, certID)) { 389 trust->sslFlags |= CERTDB_USER; 390 trust->emailFlags |= CERTDB_USER; 391 /* trust->objectSigningFlags |= CERTDB_USER; */ 392 } 393 CERT_LockCertTrust(cert); 394 cert->trust = trust; 395 CERT_UnlockCertTrust(cert); 396 397 return cert; 398 399 loser: 400 if (nickname) 401 PORT_Free(nickname); 402 if (cert) 403 CERT_DestroyCertificate(cert); 404 return NULL; 405 } 406 407 /* 408 * Build get a certificate from a private key 409 */ 410 CERTCertificate * 411 PK11_GetCertFromPrivateKey(SECKEYPrivateKey *privKey) 412 { 413 PK11SlotInfo *slot = privKey->pkcs11Slot; 414 CK_OBJECT_HANDLE handle = privKey->pkcs11ID; 415 CK_OBJECT_HANDLE certID = 416 PK11_MatchItem(slot, handle, CKO_CERTIFICATE); 417 CERTCertificate *cert; 418 419 if (certID == CK_INVALID_HANDLE) { 420 PORT_SetError(SSL_ERROR_NO_CERTIFICATE); 421 return NULL; 422 } 423 cert = PK11_MakeCertFromHandle(slot, certID, NULL); 424 return (cert); 425 } 426 427 CK_OBJECT_HANDLE * 428 PK11_FindCertHandlesForKeyHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE keyHandle, 429 int *certHandleCountOut) 430 { 431 if (!slot || !certHandleCountOut || keyHandle == CK_INVALID_HANDLE) { 432 PORT_SetError(SEC_ERROR_INVALID_ARGS); 433 return NULL; 434 } 435 436 PORTCheapArenaPool arena; 437 PORT_InitCheapArena(&arena, DER_DEFAULT_CHUNKSIZE); 438 CK_ATTRIBUTE idTemplate[] = { 439 { CKA_ID, NULL, 0 }, 440 }; 441 const int idAttrCount = sizeof(idTemplate) / sizeof(idTemplate[0]); 442 CK_RV crv = PK11_GetAttributes(&arena.arena, slot, keyHandle, idTemplate, idAttrCount); 443 if (crv != CKR_OK) { 444 PORT_DestroyCheapArena(&arena); 445 PORT_SetError(PK11_MapError(crv)); 446 return NULL; 447 } 448 449 if ((idTemplate[0].ulValueLen == 0) || (idTemplate[0].ulValueLen == -1)) { 450 PORT_DestroyCheapArena(&arena); 451 PORT_SetError(SEC_ERROR_BAD_KEY); 452 return NULL; 453 } 454 455 CK_OBJECT_CLASS searchClass = CKO_CERTIFICATE; 456 CK_ATTRIBUTE searchTemplate[] = { 457 idTemplate[0], 458 { CKA_CLASS, &searchClass, sizeof(searchClass) } 459 }; 460 const size_t searchAttrCount = sizeof(searchTemplate) / sizeof(searchTemplate[0]); 461 CK_OBJECT_HANDLE *ids = pk11_FindObjectsByTemplate(slot, searchTemplate, searchAttrCount, certHandleCountOut); 462 463 PORT_DestroyCheapArena(&arena); 464 return ids; 465 } 466 467 CERTCertList * 468 PK11_GetCertsMatchingPrivateKey(SECKEYPrivateKey *privKey) 469 { 470 if (!privKey) { 471 PORT_SetError(SEC_ERROR_INVALID_ARGS); 472 return NULL; 473 } 474 CERTCertList *certs = CERT_NewCertList(); 475 if (!certs) { 476 PORT_SetError(SEC_ERROR_NO_MEMORY); 477 return NULL; 478 } 479 PK11SlotInfo *slot = privKey->pkcs11Slot; 480 CK_OBJECT_HANDLE handle = privKey->pkcs11ID; 481 CK_OBJECT_HANDLE certID = PK11_MatchItem(slot, handle, CKO_CERTIFICATE); 482 /* If we can't get a matching certID, there are no matching certificates, 483 * which is not an error. */ 484 if (certID == CK_INVALID_HANDLE) { 485 return certs; 486 } 487 int certHandleCount = 0; 488 CK_OBJECT_HANDLE *certHandles = PK11_FindCertHandlesForKeyHandle(slot, handle, &certHandleCount); 489 if (!certHandles) { 490 /* If certHandleCount is 0, there are no matching certificates, which is 491 * not an error. */ 492 if (certHandleCount == 0) { 493 return certs; 494 } 495 CERT_DestroyCertList(certs); 496 return NULL; 497 } 498 int i; 499 for (i = 0; i < certHandleCount; i++) { 500 CERTCertificate *cert = PK11_MakeCertFromHandle(slot, certHandles[i], NULL); 501 /* If PK11_MakeCertFromHandle fails for one handle, optimistically 502 assume other handles may succeed (i.e. this is best-effort). */ 503 if (!cert) { 504 continue; 505 } 506 if (CERT_AddCertToListTail(certs, cert) != SECSuccess) { 507 CERT_DestroyCertificate(cert); 508 } 509 } 510 PORT_Free(certHandles); 511 return certs; 512 } 513 514 /* 515 * delete a cert and it's private key (if no other certs are pointing to the 516 * private key. 517 */ 518 SECStatus 519 PK11_DeleteTokenCertAndKey(CERTCertificate *cert, void *wincx) 520 { 521 SECKEYPrivateKey *privKey = PK11_FindKeyByAnyCert(cert, wincx); 522 CK_OBJECT_HANDLE pubKey; 523 PK11SlotInfo *slot = NULL; 524 525 pubKey = pk11_FindPubKeyByAnyCert(cert, &slot, wincx); 526 if (privKey) { 527 /* For 3.4, utilize the generic cert delete function */ 528 SEC_DeletePermCertificate(cert); 529 PK11_DeleteTokenPrivateKey(privKey, PR_FALSE); 530 } 531 if ((pubKey != CK_INVALID_HANDLE) && (slot != NULL)) { 532 PK11_DestroyTokenObject(slot, pubKey); 533 PK11_FreeSlot(slot); 534 } 535 return SECSuccess; 536 } 537 538 /* 539 * cert callback structure 540 */ 541 typedef struct pk11DoCertCallbackStr { 542 SECStatus (*callback)(PK11SlotInfo *slot, CERTCertificate *, void *); 543 SECStatus (*noslotcallback)(CERTCertificate *, void *); 544 SECStatus (*itemcallback)(CERTCertificate *, SECItem *, void *); 545 void *callbackArg; 546 } pk11DoCertCallback; 547 548 typedef struct pk11CertCallbackStr { 549 SECStatus (*callback)(CERTCertificate *, SECItem *, void *); 550 void *callbackArg; 551 } pk11CertCallback; 552 553 struct fake_der_cb_argstr { 554 SECStatus (*callback)(CERTCertificate *, SECItem *, void *); 555 void *arg; 556 }; 557 558 static SECStatus 559 fake_der_cb(CERTCertificate *c, void *a) 560 { 561 struct fake_der_cb_argstr *fda = (struct fake_der_cb_argstr *)a; 562 return (*fda->callback)(c, &c->derCert, fda->arg); 563 } 564 565 /* 566 * Extract all the certs on a card from a slot. 567 */ 568 SECStatus 569 PK11_TraverseSlotCerts(SECStatus (*callback)(CERTCertificate *, SECItem *, void *), 570 void *arg, void *wincx) 571 { 572 NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain(); 573 struct fake_der_cb_argstr fda; 574 struct nss3_cert_cbstr pk11cb; 575 576 /* authenticate to the tokens first */ 577 (void)pk11_TraverseAllSlots(NULL, NULL, PR_TRUE, wincx); 578 579 fda.callback = callback; 580 fda.arg = arg; 581 pk11cb.callback = fake_der_cb; 582 pk11cb.arg = &fda; 583 NSSTrustDomain_TraverseCertificates(defaultTD, convert_cert, &pk11cb); 584 return SECSuccess; 585 } 586 587 static void 588 transfer_token_certs_to_collection(nssList *certList, NSSToken *token, 589 nssPKIObjectCollection *collection) 590 { 591 NSSCertificate **certs; 592 PRUint32 i, count; 593 NSSToken **tokens, **tp; 594 count = nssList_Count(certList); 595 if (count == 0) { 596 return; 597 } 598 certs = nss_ZNEWARRAY(NULL, NSSCertificate *, count); 599 if (!certs) { 600 return; 601 } 602 nssList_GetArray(certList, (void **)certs, count); 603 for (i = 0; i < count; i++) { 604 tokens = nssPKIObject_GetTokens(&certs[i]->object, NULL); 605 if (tokens) { 606 for (tp = tokens; *tp; tp++) { 607 if (*tp == token) { 608 nssPKIObjectCollection_AddObject(collection, 609 (nssPKIObject *)certs[i]); 610 } 611 } 612 nssTokenArray_Destroy(tokens); 613 } 614 CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(certs[i])); 615 } 616 nss_ZFreeIf(certs); 617 } 618 619 static void 620 transfer_uri_certs_to_collection(nssList *certList, PK11URI *uri, 621 nssPKIObjectCollection *collection) 622 { 623 624 NSSCertificate **certs; 625 PRUint32 i, count; 626 NSSToken **tokens, **tp; 627 PK11SlotInfo *slot; 628 const SECItem *id; 629 630 count = nssList_Count(certList); 631 if (count == 0) { 632 return; 633 } 634 certs = nss_ZNEWARRAY(NULL, NSSCertificate *, count); 635 if (!certs) { 636 return; 637 } 638 id = PK11URI_GetPathAttributeItem(uri, PK11URI_PATTR_ID); 639 nssList_GetArray(certList, (void **)certs, count); 640 for (i = 0; i < count; i++) { 641 /* 642 * Filter the subject matched certs based on the 643 * CKA_ID from the URI 644 */ 645 if (id && (id->len != certs[i]->id.size || 646 memcmp(id, certs[i]->id.data, certs[i]->id.size))) 647 continue; 648 tokens = nssPKIObject_GetTokens(&certs[i]->object, NULL); 649 if (tokens) { 650 for (tp = tokens; *tp; tp++) { 651 const char *value; 652 slot = (*tp)->pk11slot; 653 654 value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_TOKEN); 655 if (value && 656 !pk11_MatchString(value, 657 (char *)slot->tokenInfo.label, 658 sizeof(slot->tokenInfo.label))) { 659 continue; 660 } 661 662 value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_MANUFACTURER); 663 if (value && 664 !pk11_MatchString(value, 665 (char *)slot->tokenInfo.manufacturerID, 666 sizeof(slot->tokenInfo.manufacturerID))) { 667 continue; 668 } 669 670 value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_MODEL); 671 if (value && 672 !pk11_MatchString(value, 673 (char *)slot->tokenInfo.model, 674 sizeof(slot->tokenInfo.model))) { 675 continue; 676 } 677 678 value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_SERIAL); 679 if (value && 680 !pk11_MatchString(value, 681 (char *)slot->tokenInfo.serialNumber, 682 sizeof(slot->tokenInfo.serialNumber))) { 683 continue; 684 } 685 686 nssPKIObjectCollection_AddObject(collection, 687 (nssPKIObject *)certs[i]); 688 break; 689 } 690 nssTokenArray_Destroy(tokens); 691 } 692 CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(certs[i])); 693 } 694 nss_ZFreeIf(certs); 695 } 696 697 static NSSCertificate ** 698 find_certs_from_uri(const char *uriString, void *wincx) 699 { 700 PK11URI *uri = NULL; 701 CK_ATTRIBUTE attributes[10]; 702 CK_ULONG nattributes = 0; 703 const SECItem *id; 704 const char *label, *type; 705 PK11SlotInfo *slotinfo; 706 nssCryptokiObject **instances; 707 PRStatus status; 708 nssPKIObjectCollection *collection = NULL; 709 NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain(); 710 NSSCertificate **certs = NULL; 711 nssList *certList = NULL; 712 SECStatus rv; 713 CK_OBJECT_CLASS s_class = CKO_CERTIFICATE; 714 static const CK_BBOOL s_true = CK_TRUE; 715 NSSToken **tokens, **tok; 716 717 uri = PK11URI_ParseURI(uriString); 718 if (uri == NULL) { 719 goto loser; 720 } 721 722 collection = nssCertificateCollection_Create(defaultTD, NULL); 723 if (!collection) { 724 goto loser; 725 } 726 certList = nssList_Create(NULL, PR_FALSE); 727 if (!certList) { 728 goto loser; 729 } 730 731 /* if the "type" attribute is specified its value must be "cert" */ 732 type = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_TYPE); 733 if (type && strcmp(type, "cert")) { 734 goto loser; 735 } 736 737 label = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_OBJECT); 738 if (label) { 739 (void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD, 740 label, 741 certList); 742 } else { 743 (void)nssTrustDomain_GetCertsFromCache(defaultTD, certList); 744 } 745 746 transfer_uri_certs_to_collection(certList, uri, collection); 747 748 /* add the CKA_CLASS and CKA_TOKEN attributes manually */ 749 attributes[nattributes].type = CKA_CLASS; 750 attributes[nattributes].pValue = (void *)&s_class; 751 attributes[nattributes].ulValueLen = sizeof(s_class); 752 nattributes++; 753 754 attributes[nattributes].type = CKA_TOKEN; 755 attributes[nattributes].pValue = (void *)&s_true; 756 attributes[nattributes].ulValueLen = sizeof(s_true); 757 nattributes++; 758 759 if (label) { 760 attributes[nattributes].type = CKA_LABEL; 761 attributes[nattributes].pValue = (void *)label; 762 attributes[nattributes].ulValueLen = strlen(label); 763 nattributes++; 764 } 765 766 id = PK11URI_GetPathAttributeItem(uri, PK11URI_PATTR_ID); 767 if (id) { 768 attributes[nattributes].type = CKA_ID; 769 attributes[nattributes].pValue = (void *)id->data; 770 attributes[nattributes].ulValueLen = id->len; 771 nattributes++; 772 } 773 774 tokens = NSSTrustDomain_FindTokensByURI(defaultTD, uri); 775 for (tok = tokens; tok && *tok; tok++) { 776 if (nssToken_IsPresent(*tok)) { 777 slotinfo = (*tok)->pk11slot; 778 779 rv = pk11_AuthenticateUnfriendly(slotinfo, PR_TRUE, wincx); 780 if (rv != SECSuccess) { 781 continue; 782 } 783 instances = nssToken_FindObjectsByTemplate(*tok, NULL, 784 attributes, 785 nattributes, 786 0, &status); 787 nssPKIObjectCollection_AddInstances(collection, instances, 0); 788 nss_ZFreeIf(instances); 789 } 790 (void)nssToken_Destroy(*tok); 791 } 792 nss_ZFreeIf(tokens); 793 nssList_Destroy(certList); 794 certs = nssPKIObjectCollection_GetCertificates(collection, NULL, 0, NULL); 795 796 loser: 797 if (collection) { 798 nssPKIObjectCollection_Destroy(collection); 799 } 800 if (uri) { 801 PK11URI_DestroyURI(uri); 802 } 803 return certs; 804 } 805 806 CERTCertificate * 807 PK11_FindCertFromURI(const char *uri, void *wincx) 808 { 809 static const NSSUsage usage = { PR_TRUE /* ... */ }; 810 NSSCertificate *cert = NULL; 811 NSSCertificate **certs = NULL; 812 CERTCertificate *rvCert = NULL; 813 814 certs = find_certs_from_uri(uri, wincx); 815 if (certs) { 816 cert = nssCertificateArray_FindBestCertificate(certs, NULL, 817 &usage, NULL); 818 if (cert) { 819 rvCert = STAN_GetCERTCertificateOrRelease(cert); 820 } 821 nssCertificateArray_Destroy(certs); 822 } 823 return rvCert; 824 } 825 826 CERTCertList * 827 PK11_FindCertsFromURI(const char *uri, void *wincx) 828 { 829 int i; 830 CERTCertList *certList = NULL; 831 NSSCertificate **foundCerts; 832 NSSCertificate *c; 833 834 foundCerts = find_certs_from_uri(uri, wincx); 835 if (foundCerts) { 836 PRTime now = PR_Now(); 837 certList = CERT_NewCertList(); 838 for (i = 0, c = *foundCerts; c; c = foundCerts[++i]) { 839 if (certList) { 840 CERTCertificate *certCert = STAN_GetCERTCertificateOrRelease(c); 841 /* c may be invalid after this, don't reference it */ 842 if (certCert) { 843 /* CERT_AddCertToListSorted adopts certCert */ 844 CERT_AddCertToListSorted(certList, certCert, 845 CERT_SortCBValidity, &now); 846 } 847 } else { 848 nssCertificate_Destroy(c); 849 } 850 } 851 if (certList && CERT_LIST_HEAD(certList) == NULL) { 852 CERT_DestroyCertList(certList); 853 certList = NULL; 854 } 855 /* all the certs have been adopted or freed, free the raw array */ 856 nss_ZFreeIf(foundCerts); 857 } 858 return certList; 859 } 860 861 static NSSCertificate ** 862 find_certs_from_nickname(const char *nickname, void *wincx) 863 { 864 PRStatus status; 865 NSSCertificate **certs = NULL; 866 NSSToken *token = NULL; 867 NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain(); 868 PK11SlotInfo *slot = NULL; 869 SECStatus rv; 870 char *nickCopy; 871 char *delimit = NULL; 872 char *tokenName; 873 874 if (!PORT_Strncasecmp(nickname, "pkcs11:", strlen("pkcs11:"))) { 875 certs = find_certs_from_uri(nickname, wincx); 876 if (certs) 877 return certs; 878 } 879 nickCopy = PORT_Strdup(nickname); 880 if (!nickCopy) { 881 /* error code is set */ 882 return NULL; 883 } 884 if ((delimit = PORT_Strchr(nickCopy, ':')) != NULL) { 885 tokenName = nickCopy; 886 nickname = delimit + 1; 887 *delimit = '\0'; 888 /* find token by name */ 889 token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName); 890 if (token) { 891 slot = PK11_ReferenceSlot(token->pk11slot); 892 } else { 893 PORT_SetError(SEC_ERROR_NO_TOKEN); 894 } 895 *delimit = ':'; 896 } else { 897 slot = PK11_GetInternalKeySlot(); 898 token = PK11Slot_GetNSSToken(slot); 899 if (!token) { 900 PORT_SetError(SEC_ERROR_NO_TOKEN); 901 } 902 } 903 if (token) { 904 nssList *certList; 905 nssCryptokiObject **instances; 906 nssPKIObjectCollection *collection; 907 nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly; 908 if (!PK11_IsPresent(slot)) { 909 goto loser; 910 } 911 rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx); 912 if (rv != SECSuccess) { 913 goto loser; 914 } 915 collection = nssCertificateCollection_Create(defaultTD, NULL); 916 if (!collection) { 917 goto loser; 918 } 919 certList = nssList_Create(NULL, PR_FALSE); 920 if (!certList) { 921 nssPKIObjectCollection_Destroy(collection); 922 goto loser; 923 } 924 (void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD, 925 nickname, 926 certList); 927 transfer_token_certs_to_collection(certList, token, collection); 928 instances = nssToken_FindCertificatesByNickname(token, 929 NULL, 930 nickname, 931 tokenOnly, 932 0, 933 &status); 934 nssPKIObjectCollection_AddInstances(collection, instances, 0); 935 nss_ZFreeIf(instances); 936 /* if it wasn't found, repeat the process for email address */ 937 if (nssPKIObjectCollection_Count(collection) == 0 && 938 PORT_Strchr(nickname, '@') != NULL) { 939 char *lowercaseName = CERT_FixupEmailAddr(nickname); 940 if (lowercaseName) { 941 (void)nssTrustDomain_GetCertsForEmailAddressFromCache(defaultTD, 942 lowercaseName, 943 certList); 944 transfer_token_certs_to_collection(certList, token, collection); 945 instances = nssToken_FindCertificatesByEmail(token, 946 NULL, 947 lowercaseName, 948 tokenOnly, 949 0, 950 &status); 951 nssPKIObjectCollection_AddInstances(collection, instances, 0); 952 nss_ZFreeIf(instances); 953 PORT_Free(lowercaseName); 954 } 955 } 956 certs = nssPKIObjectCollection_GetCertificates(collection, 957 NULL, 0, NULL); 958 nssPKIObjectCollection_Destroy(collection); 959 nssList_Destroy(certList); 960 } 961 loser: 962 if (token) { 963 (void)nssToken_Destroy(token); 964 } 965 if (slot) { 966 PK11_FreeSlot(slot); 967 } 968 if (nickCopy) 969 PORT_Free(nickCopy); 970 return certs; 971 } 972 973 CERTCertificate * 974 PK11_FindCertFromNickname(const char *nickname, void *wincx) 975 { 976 CERTCertificate *rvCert = NULL; 977 NSSCertificate *cert = NULL; 978 NSSCertificate **certs = NULL; 979 static const NSSUsage usage = { PR_TRUE /* ... */ }; 980 981 certs = find_certs_from_nickname(nickname, wincx); 982 if (certs) { 983 cert = nssCertificateArray_FindBestCertificate(certs, NULL, 984 &usage, NULL); 985 if (cert) { 986 rvCert = STAN_GetCERTCertificateOrRelease(cert); 987 } 988 nssCertificateArray_Destroy(certs); 989 } 990 return rvCert; 991 } 992 993 /* Traverse slots callback */ 994 typedef struct FindCertsEmailArgStr { 995 char *email; 996 CERTCertList *certList; 997 } FindCertsEmailArg; 998 999 SECStatus 1000 FindCertsEmailCallback(CERTCertificate *cert, SECItem *item, void *arg) 1001 { 1002 FindCertsEmailArg *cbparam = (FindCertsEmailArg *)arg; 1003 const char *cert_email = CERT_GetFirstEmailAddress(cert); 1004 PRBool found = PR_FALSE; 1005 1006 /* Email address present in certificate? */ 1007 if (cert_email == NULL) { 1008 return SECSuccess; 1009 } 1010 1011 /* Parameter correctly set? */ 1012 if (cbparam->email == NULL) { 1013 return SECFailure; 1014 } 1015 1016 /* Loop over all email addresses */ 1017 do { 1018 if (!strcmp(cert_email, cbparam->email)) { 1019 /* found one matching email address */ 1020 PRTime now = PR_Now(); 1021 found = PR_TRUE; 1022 CERT_AddCertToListSorted(cbparam->certList, 1023 CERT_DupCertificate(cert), 1024 CERT_SortCBValidity, &now); 1025 } 1026 cert_email = CERT_GetNextEmailAddress(cert, cert_email); 1027 } while (cert_email && !found); 1028 1029 return SECSuccess; 1030 } 1031 1032 /* Find all certificates with matching email address */ 1033 CERTCertList * 1034 PK11_FindCertsFromEmailAddress(const char *email, void *wincx) 1035 { 1036 FindCertsEmailArg cbparam; 1037 SECStatus rv; 1038 1039 cbparam.certList = CERT_NewCertList(); 1040 if (cbparam.certList == NULL) { 1041 return NULL; 1042 } 1043 1044 cbparam.email = CERT_FixupEmailAddr(email); 1045 if (cbparam.email == NULL) { 1046 CERT_DestroyCertList(cbparam.certList); 1047 return NULL; 1048 } 1049 1050 rv = PK11_TraverseSlotCerts(FindCertsEmailCallback, &cbparam, NULL); 1051 if (rv != SECSuccess) { 1052 CERT_DestroyCertList(cbparam.certList); 1053 PORT_Free(cbparam.email); 1054 return NULL; 1055 } 1056 1057 /* empty list? */ 1058 if (CERT_LIST_EMPTY(cbparam.certList)) { 1059 CERT_DestroyCertList(cbparam.certList); 1060 cbparam.certList = NULL; 1061 } 1062 1063 PORT_Free(cbparam.email); 1064 return cbparam.certList; 1065 } 1066 1067 CERTCertList * 1068 PK11_FindCertsFromNickname(const char *nickname, void *wincx) 1069 { 1070 int i; 1071 CERTCertList *certList = NULL; 1072 NSSCertificate **foundCerts = NULL; 1073 NSSCertificate *c; 1074 1075 foundCerts = find_certs_from_nickname(nickname, wincx); 1076 if (foundCerts) { 1077 PRTime now = PR_Now(); 1078 certList = CERT_NewCertList(); 1079 for (i = 0, c = *foundCerts; c; c = foundCerts[++i]) { 1080 if (certList) { 1081 CERTCertificate *certCert = STAN_GetCERTCertificateOrRelease(c); 1082 /* c may be invalid after this, don't reference it */ 1083 if (certCert) { 1084 /* CERT_AddCertToListSorted adopts certCert */ 1085 CERT_AddCertToListSorted(certList, certCert, 1086 CERT_SortCBValidity, &now); 1087 } 1088 } else { 1089 nssCertificate_Destroy(c); 1090 } 1091 } 1092 /* all the certs have been adopted or freed, free the raw array */ 1093 nss_ZFreeIf(foundCerts); 1094 } 1095 return certList; 1096 } 1097 1098 /* 1099 * extract a key ID for a certificate... 1100 * NOTE: We call this function from PKCS11.c If we ever use 1101 * pkcs11 to extract the public key (we currently do not), this will break. 1102 */ 1103 SECItem * 1104 PK11_GetPubIndexKeyID(CERTCertificate *cert) 1105 { 1106 SECKEYPublicKey *pubk; 1107 SECItem *newItem = NULL; 1108 1109 pubk = CERT_ExtractPublicKey(cert); 1110 if (pubk == NULL) 1111 return NULL; 1112 1113 const SECItem *oldItem = PK11_GetPublicValueFromPublicKey(pubk); 1114 if (oldItem) { 1115 newItem = SECITEM_DupItem(oldItem); 1116 } 1117 1118 SECKEY_DestroyPublicKey(pubk); 1119 /* make hash of it */ 1120 return newItem; 1121 } 1122 1123 /* 1124 * generate a CKA_ID from a certificate. 1125 */ 1126 SECItem * 1127 pk11_mkcertKeyID(CERTCertificate *cert) 1128 { 1129 SECItem *pubKeyData = PK11_GetPubIndexKeyID(cert); 1130 SECItem *certCKA_ID; 1131 1132 if (pubKeyData == NULL) 1133 return NULL; 1134 1135 certCKA_ID = PK11_MakeIDFromPubKey(pubKeyData); 1136 SECITEM_FreeItem(pubKeyData, PR_TRUE); 1137 return certCKA_ID; 1138 } 1139 1140 /* 1141 * Write the cert into the token. 1142 */ 1143 SECStatus 1144 PK11_ImportCert(PK11SlotInfo *slot, CERTCertificate *cert, 1145 CK_OBJECT_HANDLE key, const char *nickname, 1146 PRBool includeTrust) 1147 { 1148 PRStatus status; 1149 NSSCertificate *c; 1150 nssCryptokiObject *keyobj, *certobj; 1151 NSSToken *token = NULL; 1152 char *emailAddr = NULL; 1153 nssCertificateStoreTrace lockTrace = { NULL, NULL, PR_FALSE, PR_FALSE }; 1154 nssCertificateStoreTrace unlockTrace = { NULL, NULL, PR_FALSE, PR_FALSE }; 1155 SECItem *keyID = pk11_mkcertKeyID(cert); 1156 if (keyID == NULL) { 1157 goto loser; /* error code should be set already */ 1158 } 1159 token = PK11Slot_GetNSSToken(slot); 1160 if (!token) { 1161 PORT_SetError(SEC_ERROR_NO_TOKEN); 1162 goto loser; 1163 } 1164 1165 if (PK11_IsInternal(slot) && cert->emailAddr && cert->emailAddr[0]) { 1166 emailAddr = cert->emailAddr; 1167 } 1168 1169 /* need to get the cert as a stan cert */ 1170 CERT_LockCertTempPerm(cert); 1171 NSSCertificate *nssCert = cert->nssCertificate; 1172 CERT_UnlockCertTempPerm(cert); 1173 if (nssCert) { 1174 c = nssCert; 1175 } else { 1176 c = STAN_GetNSSCertificate(cert); 1177 if (c == NULL) { 1178 goto loser; 1179 } 1180 } 1181 1182 /* set the id for the cert */ 1183 nssItem_Create(c->object.arena, &c->id, keyID->len, keyID->data); 1184 if (!c->id.data) { 1185 goto loser; 1186 } 1187 1188 if (key != CK_INVALID_HANDLE) { 1189 /* create an object for the key, ... */ 1190 keyobj = nss_ZNEW(NULL, nssCryptokiObject); 1191 if (!keyobj) { 1192 goto loser; 1193 } 1194 keyobj->token = nssToken_AddRef(token); 1195 keyobj->handle = key; 1196 keyobj->isTokenObject = PR_TRUE; 1197 1198 /* ... in order to set matching attributes for the key */ 1199 status = nssCryptokiPrivateKey_SetCertificate(keyobj, NULL, nickname, 1200 &c->id, &c->subject); 1201 nssCryptokiObject_Destroy(keyobj); 1202 if (status != PR_SUCCESS) { 1203 goto loser; 1204 } 1205 } 1206 1207 /* do the token import */ 1208 certobj = nssToken_ImportCertificate(token, NULL, 1209 NSSCertificateType_PKIX, 1210 &c->id, 1211 nickname, 1212 &c->encoding, 1213 &c->issuer, 1214 &c->subject, 1215 &c->serial, 1216 emailAddr, 1217 PR_TRUE); 1218 if (!certobj) { 1219 if (NSS_GetError() == NSS_ERROR_INVALID_CERTIFICATE) { 1220 PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL); 1221 SECITEM_FreeItem(keyID, PR_TRUE); 1222 return SECFailure; 1223 } 1224 goto loser; 1225 } 1226 1227 if (c->object.cryptoContext) { 1228 /* Delete the temp instance */ 1229 NSSCryptoContext *cc = c->object.cryptoContext; 1230 nssCertificateStore_Lock(cc->certStore, &lockTrace); 1231 nssCertificateStore_RemoveCertLOCKED(cc->certStore, c); 1232 nssCertificateStore_Unlock(cc->certStore, &lockTrace, &unlockTrace); 1233 c->object.cryptoContext = NULL; 1234 CERT_LockCertTempPerm(cert); 1235 cert->istemp = PR_FALSE; 1236 cert->isperm = PR_TRUE; 1237 CERT_UnlockCertTempPerm(cert); 1238 } 1239 1240 /* add the new instance to the cert, force an update of the 1241 * CERTCertificate, and finish 1242 */ 1243 nssPKIObject_AddInstance(&c->object, certobj); 1244 /* nssTrustDomain_AddCertsToCache may release a reference to 'c' and 1245 * replace 'c' with a different value. So we add a reference to 'c' to 1246 * prevent 'c' from being destroyed. */ 1247 nssCertificate_AddRef(c); 1248 nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1); 1249 (void)STAN_ForceCERTCertificateUpdate(c); 1250 nssCertificate_Destroy(c); 1251 SECITEM_FreeItem(keyID, PR_TRUE); 1252 (void)nssToken_Destroy(token); 1253 return SECSuccess; 1254 loser: 1255 if (token) { 1256 (void)nssToken_Destroy(token); 1257 } 1258 CERT_MapStanError(); 1259 SECITEM_FreeItem(keyID, PR_TRUE); 1260 if (PORT_GetError() != SEC_ERROR_TOKEN_NOT_LOGGED_IN) { 1261 PORT_SetError(SEC_ERROR_ADDING_CERT); 1262 } 1263 return SECFailure; 1264 } 1265 1266 SECStatus 1267 PK11_ImportDERCert(PK11SlotInfo *slot, SECItem *derCert, 1268 CK_OBJECT_HANDLE key, char *nickname, PRBool includeTrust) 1269 { 1270 CERTCertificate *cert; 1271 SECStatus rv; 1272 1273 cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), 1274 derCert, NULL, PR_FALSE, PR_TRUE); 1275 if (cert == NULL) 1276 return SECFailure; 1277 1278 rv = PK11_ImportCert(slot, cert, key, nickname, includeTrust); 1279 CERT_DestroyCertificate(cert); 1280 return rv; 1281 } 1282 1283 /* 1284 * return the private key From a given Cert 1285 */ 1286 SECKEYPrivateKey * 1287 PK11_FindPrivateKeyFromCert(PK11SlotInfo *slot, CERTCertificate *cert, 1288 void *wincx) 1289 { 1290 int err; 1291 CK_OBJECT_HANDLE certh; 1292 CK_OBJECT_HANDLE keyh; 1293 PRBool needLogin; 1294 SECStatus rv; 1295 1296 certh = PK11_FindCertInSlot(slot, cert, wincx); 1297 if (certh == CK_INVALID_HANDLE) { 1298 return NULL; 1299 } 1300 /* 1301 * prevent a login race condition. If slot is logged in between 1302 * our call to pk11_LoginStillRequired and the 1303 * PK11_MatchItem. The matchItem call will either succeed, or 1304 * we will call it one more time after calling PK11_Authenticate 1305 * (which is a noop on an authenticated token). 1306 */ 1307 needLogin = pk11_LoginStillRequired(slot, wincx); 1308 keyh = PK11_MatchItem(slot, certh, CKO_PRIVATE_KEY); 1309 if ((keyh == CK_INVALID_HANDLE) && needLogin && 1310 (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) || 1311 SEC_ERROR_TOKEN_NOT_LOGGED_IN == err)) { 1312 /* try it again authenticated */ 1313 rv = PK11_Authenticate(slot, PR_TRUE, wincx); 1314 if (rv != SECSuccess) { 1315 return NULL; 1316 } 1317 keyh = PK11_MatchItem(slot, certh, CKO_PRIVATE_KEY); 1318 } 1319 if (keyh == CK_INVALID_HANDLE) { 1320 return NULL; 1321 } 1322 return PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyh, wincx); 1323 } 1324 1325 /* 1326 * import a cert for a private key we have already generated. Set the label 1327 * on both to be the nickname. This is for the Key Gen, orphaned key case. 1328 */ 1329 PK11SlotInfo * 1330 PK11_KeyForCertExists(CERTCertificate *cert, CK_OBJECT_HANDLE *keyPtr, 1331 void *wincx) 1332 { 1333 PK11SlotList *list; 1334 PK11SlotListElement *le; 1335 SECItem *keyID; 1336 CK_OBJECT_HANDLE key; 1337 PK11SlotInfo *slot = NULL; 1338 SECStatus rv; 1339 int err; 1340 1341 keyID = pk11_mkcertKeyID(cert); 1342 /* get them all! */ 1343 list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, wincx); 1344 if ((keyID == NULL) || (list == NULL)) { 1345 if (keyID) 1346 SECITEM_FreeItem(keyID, PR_TRUE); 1347 if (list) 1348 PK11_FreeSlotList(list); 1349 return NULL; 1350 } 1351 1352 /* Look for the slot that holds the Key */ 1353 for (le = list->head; le; le = le->next) { 1354 /* 1355 * prevent a login race condition. If le->slot is logged in between 1356 * our call to pk11_LoginStillRequired and the 1357 * pk11_FindPrivateKeyFromCertID, the find will either succeed, or 1358 * we will call it one more time after calling PK11_Authenticate 1359 * (which is a noop on an authenticated token). 1360 */ 1361 PRBool needLogin = pk11_LoginStillRequired(le->slot, wincx); 1362 key = pk11_FindPrivateKeyFromCertID(le->slot, keyID); 1363 if ((key == CK_INVALID_HANDLE) && needLogin && 1364 (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) || 1365 SEC_ERROR_TOKEN_NOT_LOGGED_IN == err)) { 1366 /* authenticate and try again */ 1367 rv = PK11_Authenticate(le->slot, PR_TRUE, wincx); 1368 if (rv != SECSuccess) 1369 continue; 1370 key = pk11_FindPrivateKeyFromCertID(le->slot, keyID); 1371 } 1372 if (key != CK_INVALID_HANDLE) { 1373 slot = PK11_ReferenceSlot(le->slot); 1374 if (keyPtr) 1375 *keyPtr = key; 1376 break; 1377 } 1378 } 1379 1380 SECITEM_FreeItem(keyID, PR_TRUE); 1381 PK11_FreeSlotList(list); 1382 return slot; 1383 } 1384 /* 1385 * import a cert for a private key we have already generated. Set the label 1386 * on both to be the nickname. This is for the Key Gen, orphaned key case. 1387 */ 1388 PK11SlotInfo * 1389 PK11_KeyForDERCertExists(SECItem *derCert, CK_OBJECT_HANDLE *keyPtr, 1390 void *wincx) 1391 { 1392 CERTCertificate *cert; 1393 PK11SlotInfo *slot = NULL; 1394 1395 /* letting this use go -- the only thing that the cert is used for is 1396 * to get the ID attribute. 1397 */ 1398 cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL); 1399 if (cert == NULL) 1400 return NULL; 1401 1402 slot = PK11_KeyForCertExists(cert, keyPtr, wincx); 1403 CERT_DestroyCertificate(cert); 1404 return slot; 1405 } 1406 1407 PK11SlotInfo * 1408 PK11_ImportCertForKey(CERTCertificate *cert, const char *nickname, 1409 void *wincx) 1410 { 1411 PK11SlotInfo *slot = NULL; 1412 CK_OBJECT_HANDLE key; 1413 1414 slot = PK11_KeyForCertExists(cert, &key, wincx); 1415 1416 if (slot) { 1417 if (PK11_ImportCert(slot, cert, key, nickname, PR_FALSE) != SECSuccess) { 1418 PK11_FreeSlot(slot); 1419 slot = NULL; 1420 } 1421 } else { 1422 PORT_SetError(SEC_ERROR_ADDING_CERT); 1423 } 1424 1425 return slot; 1426 } 1427 1428 PK11SlotInfo * 1429 PK11_ImportDERCertForKey(SECItem *derCert, char *nickname, void *wincx) 1430 { 1431 CERTCertificate *cert; 1432 PK11SlotInfo *slot = NULL; 1433 1434 cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), 1435 derCert, NULL, PR_FALSE, PR_TRUE); 1436 if (cert == NULL) 1437 return NULL; 1438 1439 slot = PK11_ImportCertForKey(cert, nickname, wincx); 1440 CERT_DestroyCertificate(cert); 1441 return slot; 1442 } 1443 1444 static CK_OBJECT_HANDLE 1445 pk11_FindCertObjectByTemplate(PK11SlotInfo **slotPtr, 1446 CK_ATTRIBUTE *searchTemplate, size_t count, void *wincx) 1447 { 1448 PK11SlotList *list; 1449 PK11SlotListElement *le; 1450 CK_OBJECT_HANDLE certHandle = CK_INVALID_HANDLE; 1451 PK11SlotInfo *slot = NULL; 1452 SECStatus rv; 1453 1454 *slotPtr = NULL; 1455 1456 /* get them all! */ 1457 list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, wincx); 1458 if (list == NULL) { 1459 return CK_INVALID_HANDLE; 1460 } 1461 1462 /* Look for the slot that holds the Key */ 1463 for (le = list->head; le; le = le->next) { 1464 rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx); 1465 if (rv != SECSuccess) 1466 continue; 1467 1468 certHandle = pk11_FindObjectByTemplate(le->slot, searchTemplate, count); 1469 if (certHandle != CK_INVALID_HANDLE) { 1470 slot = PK11_ReferenceSlot(le->slot); 1471 break; 1472 } 1473 } 1474 1475 PK11_FreeSlotList(list); 1476 1477 if (slot == NULL) { 1478 return CK_INVALID_HANDLE; 1479 } 1480 *slotPtr = slot; 1481 return certHandle; 1482 } 1483 1484 CERTCertificate * 1485 PK11_FindCertByIssuerAndSNOnToken(PK11SlotInfo *slot, 1486 CERTIssuerAndSN *issuerSN, void *wincx) 1487 { 1488 CERTCertificate *rvCert = NULL; 1489 NSSCertificate *cert = NULL; 1490 NSSDER issuer, serial; 1491 NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); 1492 NSSToken *token = NULL; 1493 nssSession *session; 1494 nssCryptokiObject *instance = NULL; 1495 nssPKIObject *object = NULL; 1496 SECItem *derSerial; 1497 PRStatus status; 1498 1499 if (!issuerSN || !issuerSN->derIssuer.data || !issuerSN->derIssuer.len || 1500 !issuerSN->serialNumber.data || !issuerSN->serialNumber.len || 1501 issuerSN->derIssuer.len > CERT_MAX_DN_BYTES || 1502 issuerSN->serialNumber.len > CERT_MAX_SERIAL_NUMBER_BYTES) { 1503 PORT_SetError(SEC_ERROR_INVALID_ARGS); 1504 return NULL; 1505 } 1506 1507 token = PK11Slot_GetNSSToken(slot); 1508 if (!token) { 1509 PORT_SetError(SEC_ERROR_NO_TOKEN); 1510 return NULL; 1511 } 1512 1513 session = nssToken_GetDefaultSession(token); /* non-owning */ 1514 if (!session) { 1515 (void)nssToken_Destroy(token); 1516 return NULL; 1517 } 1518 1519 /* PKCS#11 needs to use DER-encoded serial numbers. Create a 1520 * CERTIssuerAndSN that actually has the encoded value and pass that 1521 * to PKCS#11 (and the crypto context). 1522 */ 1523 derSerial = SEC_ASN1EncodeItem(NULL, NULL, 1524 &issuerSN->serialNumber, 1525 SEC_ASN1_GET(SEC_IntegerTemplate)); 1526 if (!derSerial) { 1527 (void)nssToken_Destroy(token); 1528 return NULL; 1529 } 1530 1531 NSSITEM_FROM_SECITEM(&issuer, &issuerSN->derIssuer); 1532 NSSITEM_FROM_SECITEM(&serial, derSerial); 1533 1534 instance = nssToken_FindCertificateByIssuerAndSerialNumber(token, session, 1535 &issuer, &serial, nssTokenSearchType_TokenForced, &status); 1536 1537 (void)nssToken_Destroy(token); 1538 SECITEM_FreeItem(derSerial, PR_TRUE); 1539 1540 if (!instance) { 1541 goto loser; 1542 } 1543 object = nssPKIObject_Create(NULL, instance, td, NULL, nssPKIMonitor); 1544 if (!object) { 1545 goto loser; 1546 } 1547 instance = NULL; /* adopted by the previous call */ 1548 cert = nssCertificate_Create(object); 1549 if (!cert) { 1550 goto loser; 1551 } 1552 object = NULL; /* adopted by the previous call */ 1553 nssTrustDomain_AddCertsToCache(td, &cert, 1); 1554 /* on failure, cert is freed below */ 1555 rvCert = STAN_GetCERTCertificate(cert); 1556 if (!rvCert) { 1557 goto loser; 1558 } 1559 return rvCert; 1560 1561 loser: 1562 if (instance) { 1563 nssCryptokiObject_Destroy(instance); 1564 } 1565 if (object) { 1566 nssPKIObject_Destroy(object); 1567 } 1568 if (cert) { 1569 nssCertificate_Destroy(cert); 1570 } 1571 return NULL; 1572 } 1573 1574 static PRCallOnceType keyIDHashCallOnce; 1575 1576 static PRStatus PR_CALLBACK 1577 pk11_keyIDHash_populate(void *wincx) 1578 { 1579 CERTCertList *certList; 1580 CERTCertListNode *node = NULL; 1581 SECItem subjKeyID = { siBuffer, NULL, 0 }; 1582 SECItem *slotid = NULL; 1583 SECMODModuleList *modules, *mlp; 1584 SECMODListLock *moduleLock; 1585 int i; 1586 1587 certList = PK11_ListCerts(PK11CertListUser, wincx); 1588 if (!certList) { 1589 return PR_FAILURE; 1590 } 1591 1592 for (node = CERT_LIST_HEAD(certList); 1593 !CERT_LIST_END(node, certList); 1594 node = CERT_LIST_NEXT(node)) { 1595 if (CERT_FindSubjectKeyIDExtension(node->cert, 1596 &subjKeyID) == SECSuccess && 1597 subjKeyID.data != NULL) { 1598 cert_AddSubjectKeyIDMapping(&subjKeyID, node->cert); 1599 SECITEM_FreeItem(&subjKeyID, PR_FALSE); 1600 } 1601 } 1602 CERT_DestroyCertList(certList); 1603 1604 /* 1605 * Record the state of each slot in a hash. The concatenation of slotID 1606 * and moduleID is used as its key, with the slot series as its value. 1607 */ 1608 slotid = SECITEM_AllocItem(NULL, NULL, 1609 sizeof(CK_SLOT_ID) + sizeof(SECMODModuleID)); 1610 if (!slotid) { 1611 PORT_SetError(SEC_ERROR_NO_MEMORY); 1612 return PR_FAILURE; 1613 } 1614 moduleLock = SECMOD_GetDefaultModuleListLock(); 1615 if (!moduleLock) { 1616 SECITEM_FreeItem(slotid, PR_TRUE); 1617 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1618 return PR_FAILURE; 1619 } 1620 SECMOD_GetReadLock(moduleLock); 1621 modules = SECMOD_GetDefaultModuleList(); 1622 for (mlp = modules; mlp; mlp = mlp->next) { 1623 for (i = 0; i < mlp->module->slotCount; i++) { 1624 memcpy(slotid->data, &mlp->module->slots[i]->slotID, 1625 sizeof(CK_SLOT_ID)); 1626 memcpy(&slotid->data[sizeof(CK_SLOT_ID)], &mlp->module->moduleID, 1627 sizeof(SECMODModuleID)); 1628 cert_UpdateSubjectKeyIDSlotCheck(slotid, 1629 mlp->module->slots[i]->series); 1630 } 1631 } 1632 SECMOD_ReleaseReadLock(moduleLock); 1633 SECITEM_FreeItem(slotid, PR_TRUE); 1634 1635 return PR_SUCCESS; 1636 } 1637 1638 /* 1639 * We're looking for a cert which we have the private key for that's on the 1640 * list of recipients. This searches one slot. 1641 * this is the new version for NSS SMIME code 1642 * this stuff should REALLY be in the SMIME code, but some things in here are not public 1643 * (they should be!) 1644 */ 1645 static CERTCertificate * 1646 pk11_FindCertObjectByRecipientNew(PK11SlotInfo *slot, NSSCMSRecipient **recipientlist, 1647 int *rlIndex, void *pwarg) 1648 { 1649 NSSCMSRecipient *ri = NULL; 1650 int i; 1651 PRBool tokenRescanDone = PR_FALSE; 1652 CERTCertTrust trust; 1653 1654 for (i = 0; (ri = recipientlist[i]) != NULL; i++) { 1655 CERTCertificate *cert = NULL; 1656 if (ri->kind == RLSubjKeyID) { 1657 SECItem *derCert = cert_FindDERCertBySubjectKeyID(ri->id.subjectKeyID); 1658 if (!derCert && !tokenRescanDone) { 1659 /* 1660 * We didn't find the cert by its key ID. If we have slots 1661 * with removable tokens, a failure from 1662 * cert_FindDERCertBySubjectKeyID doesn't necessarily imply 1663 * that the cert is unavailable - the token might simply 1664 * have been inserted after the initial run of 1665 * pk11_keyIDHash_populate (wrapped by PR_CallOnceWithArg), 1666 * or a different token might have been present in that 1667 * slot, initially. Let's check for new tokens... 1668 */ 1669 PK11SlotList *sl = PK11_GetAllTokens(CKM_INVALID_MECHANISM, 1670 PR_FALSE, PR_FALSE, pwarg); 1671 if (sl) { 1672 PK11SlotListElement *le; 1673 SECItem *slotid = SECITEM_AllocItem(NULL, NULL, 1674 sizeof(CK_SLOT_ID) + sizeof(SECMODModuleID)); 1675 if (!slotid) { 1676 PORT_SetError(SEC_ERROR_NO_MEMORY); 1677 PK11_FreeSlotList(sl); 1678 return NULL; 1679 } 1680 for (le = sl->head; le; le = le->next) { 1681 memcpy(slotid->data, &le->slot->slotID, 1682 sizeof(CK_SLOT_ID)); 1683 memcpy(&slotid->data[sizeof(CK_SLOT_ID)], 1684 &le->slot->module->moduleID, 1685 sizeof(SECMODModuleID)); 1686 /* 1687 * Any changes with the slot since our last check? 1688 * If so, re-read the certs in that specific slot. 1689 */ 1690 if (cert_SubjectKeyIDSlotCheckSeries(slotid) != PK11_GetSlotSeries(le->slot)) { 1691 CERTCertListNode *node = NULL; 1692 SECItem subjKeyID = { siBuffer, NULL, 0 }; 1693 CERTCertList *cl = PK11_ListCertsInSlot(le->slot); 1694 if (!cl) { 1695 continue; 1696 } 1697 for (node = CERT_LIST_HEAD(cl); 1698 !CERT_LIST_END(node, cl); 1699 node = CERT_LIST_NEXT(node)) { 1700 if (CERT_IsUserCert(node->cert) && 1701 CERT_FindSubjectKeyIDExtension(node->cert, 1702 &subjKeyID) == SECSuccess) { 1703 if (subjKeyID.data) { 1704 cert_AddSubjectKeyIDMapping(&subjKeyID, 1705 node->cert); 1706 cert_UpdateSubjectKeyIDSlotCheck(slotid, 1707 PK11_GetSlotSeries(le->slot)); 1708 } 1709 SECITEM_FreeItem(&subjKeyID, PR_FALSE); 1710 } 1711 } 1712 CERT_DestroyCertList(cl); 1713 } 1714 } 1715 PK11_FreeSlotList(sl); 1716 SECITEM_FreeItem(slotid, PR_TRUE); 1717 } 1718 /* only check once per message/recipientlist */ 1719 tokenRescanDone = PR_TRUE; 1720 /* do another lookup (hopefully we found that cert...) */ 1721 derCert = cert_FindDERCertBySubjectKeyID(ri->id.subjectKeyID); 1722 } 1723 if (derCert) { 1724 cert = PK11_FindCertFromDERCertItem(slot, derCert, pwarg); 1725 SECITEM_FreeItem(derCert, PR_TRUE); 1726 } 1727 } else { 1728 cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->id.issuerAndSN, 1729 pwarg); 1730 } 1731 if (cert) { 1732 /* this isn't our cert */ 1733 if (CERT_GetCertTrust(cert, &trust) != SECSuccess || 1734 ((trust.emailFlags & CERTDB_USER) != CERTDB_USER)) { 1735 CERT_DestroyCertificate(cert); 1736 continue; 1737 } 1738 ri->slot = PK11_ReferenceSlot(slot); 1739 *rlIndex = i; 1740 return cert; 1741 } 1742 } 1743 *rlIndex = -1; 1744 return NULL; 1745 } 1746 1747 /* 1748 * This function is the same as above, but it searches all the slots. 1749 * this is the new version for NSS SMIME code 1750 * this stuff should REALLY be in the SMIME code, but some things in here are not public 1751 * (they should be!) 1752 */ 1753 static CERTCertificate * 1754 pk11_AllFindCertObjectByRecipientNew(NSSCMSRecipient **recipientlist, void *wincx, int *rlIndex) 1755 { 1756 PK11SlotList *list; 1757 PK11SlotListElement *le; 1758 CERTCertificate *cert = NULL; 1759 SECStatus rv; 1760 1761 /* get them all! */ 1762 list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, wincx); 1763 if (list == NULL) { 1764 return CK_INVALID_HANDLE; 1765 } 1766 1767 /* Look for the slot that holds the Key */ 1768 for (le = list->head; le; le = le->next) { 1769 rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx); 1770 if (rv != SECSuccess) 1771 continue; 1772 1773 cert = pk11_FindCertObjectByRecipientNew(le->slot, 1774 recipientlist, rlIndex, wincx); 1775 if (cert) 1776 break; 1777 } 1778 1779 PK11_FreeSlotList(list); 1780 1781 return cert; 1782 } 1783 1784 /* 1785 * We're looking for a cert which we have the private key for that's on the 1786 * list of recipients. This searches one slot. 1787 */ 1788 static CERTCertificate * 1789 pk11_FindCertObjectByRecipient(PK11SlotInfo *slot, 1790 SEC_PKCS7RecipientInfo **recipientArray, 1791 SEC_PKCS7RecipientInfo **rip, void *pwarg) 1792 { 1793 SEC_PKCS7RecipientInfo *ri = NULL; 1794 CERTCertTrust trust; 1795 int i; 1796 1797 for (i = 0; (ri = recipientArray[i]) != NULL; i++) { 1798 CERTCertificate *cert; 1799 1800 cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->issuerAndSN, 1801 pwarg); 1802 if (cert) { 1803 /* this isn't our cert */ 1804 if (CERT_GetCertTrust(cert, &trust) != SECSuccess || 1805 ((trust.emailFlags & CERTDB_USER) != CERTDB_USER)) { 1806 CERT_DestroyCertificate(cert); 1807 continue; 1808 } 1809 *rip = ri; 1810 return cert; 1811 } 1812 } 1813 *rip = NULL; 1814 return NULL; 1815 } 1816 1817 /* 1818 * This function is the same as above, but it searches all the slots. 1819 */ 1820 static CERTCertificate * 1821 pk11_AllFindCertObjectByRecipient(PK11SlotInfo **slotPtr, 1822 SEC_PKCS7RecipientInfo **recipientArray, 1823 SEC_PKCS7RecipientInfo **rip, 1824 void *wincx) 1825 { 1826 PK11SlotList *list; 1827 PK11SlotListElement *le; 1828 CERTCertificate *cert = NULL; 1829 PK11SlotInfo *slot = NULL; 1830 SECStatus rv; 1831 1832 *slotPtr = NULL; 1833 1834 /* get them all! */ 1835 list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, wincx); 1836 if (list == NULL) { 1837 return CK_INVALID_HANDLE; 1838 } 1839 1840 *rip = NULL; 1841 1842 /* Look for the slot that holds the Key */ 1843 for (le = list->head; le; le = le->next) { 1844 rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx); 1845 if (rv != SECSuccess) 1846 continue; 1847 1848 cert = pk11_FindCertObjectByRecipient(le->slot, recipientArray, 1849 rip, wincx); 1850 if (cert) { 1851 slot = PK11_ReferenceSlot(le->slot); 1852 break; 1853 } 1854 } 1855 1856 PK11_FreeSlotList(list); 1857 1858 if (slot == NULL) { 1859 return NULL; 1860 } 1861 *slotPtr = slot; 1862 PORT_Assert(cert != NULL); 1863 return cert; 1864 } 1865 1866 /* 1867 * We need to invert the search logic for PKCS 7 because if we search for 1868 * each cert on the list over all the slots, we wind up with lots of spurious 1869 * password prompts. This way we get only one password prompt per slot, at 1870 * the max, and most of the time we can find the cert, and only prompt for 1871 * the key... 1872 */ 1873 CERTCertificate * 1874 PK11_FindCertAndKeyByRecipientList(PK11SlotInfo **slotPtr, 1875 SEC_PKCS7RecipientInfo **array, 1876 SEC_PKCS7RecipientInfo **rip, 1877 SECKEYPrivateKey **privKey, void *wincx) 1878 { 1879 CERTCertificate *cert = NULL; 1880 1881 *privKey = NULL; 1882 *slotPtr = NULL; 1883 cert = pk11_AllFindCertObjectByRecipient(slotPtr, array, rip, wincx); 1884 if (!cert) { 1885 return NULL; 1886 } 1887 1888 *privKey = PK11_FindKeyByAnyCert(cert, wincx); 1889 if (*privKey == NULL) { 1890 goto loser; 1891 } 1892 1893 return cert; 1894 loser: 1895 if (cert) 1896 CERT_DestroyCertificate(cert); 1897 if (*slotPtr) 1898 PK11_FreeSlot(*slotPtr); 1899 *slotPtr = NULL; 1900 return NULL; 1901 } 1902 1903 /* 1904 * This is the new version of the above function for NSS SMIME code 1905 * this stuff should REALLY be in the SMIME code, but some things in here are not public 1906 * (they should be!) 1907 */ 1908 int 1909 PK11_FindCertAndKeyByRecipientListNew(NSSCMSRecipient **recipientlist, void *wincx) 1910 { 1911 CERTCertificate *cert; 1912 NSSCMSRecipient *rl; 1913 PRStatus rv; 1914 int rlIndex; 1915 1916 rv = PR_CallOnceWithArg(&keyIDHashCallOnce, pk11_keyIDHash_populate, wincx); 1917 if (rv != PR_SUCCESS) 1918 return -1; 1919 1920 cert = pk11_AllFindCertObjectByRecipientNew(recipientlist, wincx, &rlIndex); 1921 if (!cert) { 1922 return -1; 1923 } 1924 1925 rl = recipientlist[rlIndex]; 1926 1927 /* at this point, rl->slot is set */ 1928 1929 rl->privkey = PK11_FindKeyByAnyCert(cert, wincx); 1930 if (rl->privkey == NULL) { 1931 goto loser; 1932 } 1933 1934 /* make a cert from the cert handle */ 1935 rl->cert = cert; 1936 return rlIndex; 1937 1938 loser: 1939 if (cert) 1940 CERT_DestroyCertificate(cert); 1941 if (rl->slot) 1942 PK11_FreeSlot(rl->slot); 1943 rl->slot = NULL; 1944 return -1; 1945 } 1946 1947 CERTCertificate * 1948 PK11_FindCertByIssuerAndSN(PK11SlotInfo **slotPtr, CERTIssuerAndSN *issuerSN, 1949 void *wincx) 1950 { 1951 CERTCertificate *rvCert = NULL; 1952 NSSCertificate *cert; 1953 NSSDER issuer, serial; 1954 NSSCryptoContext *cc; 1955 SECItem *derSerial; 1956 1957 if (!issuerSN || !issuerSN->derIssuer.data || !issuerSN->derIssuer.len || 1958 !issuerSN->serialNumber.data || !issuerSN->serialNumber.len || 1959 issuerSN->derIssuer.len > CERT_MAX_DN_BYTES || 1960 issuerSN->serialNumber.len > CERT_MAX_SERIAL_NUMBER_BYTES) { 1961 PORT_SetError(SEC_ERROR_INVALID_ARGS); 1962 return NULL; 1963 } 1964 1965 if (slotPtr) 1966 *slotPtr = NULL; 1967 1968 /* PKCS#11 needs to use DER-encoded serial numbers. Create a 1969 * CERTIssuerAndSN that actually has the encoded value and pass that 1970 * to PKCS#11 (and the crypto context). 1971 */ 1972 derSerial = SEC_ASN1EncodeItem(NULL, NULL, 1973 &issuerSN->serialNumber, 1974 SEC_ASN1_GET(SEC_IntegerTemplate)); 1975 if (!derSerial) { 1976 return NULL; 1977 } 1978 1979 NSSITEM_FROM_SECITEM(&issuer, &issuerSN->derIssuer); 1980 NSSITEM_FROM_SECITEM(&serial, derSerial); 1981 1982 cc = STAN_GetDefaultCryptoContext(); 1983 cert = NSSCryptoContext_FindCertificateByIssuerAndSerialNumber(cc, 1984 &issuer, 1985 &serial); 1986 if (cert) { 1987 SECITEM_FreeItem(derSerial, PR_TRUE); 1988 return STAN_GetCERTCertificateOrRelease(cert); 1989 } 1990 1991 do { 1992 /* free the old cert on retry. Associated slot was not present */ 1993 if (rvCert) { 1994 CERT_DestroyCertificate(rvCert); 1995 rvCert = NULL; 1996 } 1997 1998 cert = NSSTrustDomain_FindCertificateByIssuerAndSerialNumber( 1999 STAN_GetDefaultTrustDomain(), 2000 &issuer, 2001 &serial); 2002 if (!cert) { 2003 break; 2004 } 2005 2006 rvCert = STAN_GetCERTCertificateOrRelease(cert); 2007 if (rvCert == NULL) { 2008 break; 2009 } 2010 2011 /* Check to see if the cert's token is still there */ 2012 } while (!PK11_IsPresent(rvCert->slot)); 2013 2014 if (rvCert && slotPtr) 2015 *slotPtr = PK11_ReferenceSlot(rvCert->slot); 2016 2017 SECITEM_FreeItem(derSerial, PR_TRUE); 2018 return rvCert; 2019 } 2020 2021 CK_OBJECT_HANDLE 2022 PK11_FindObjectForCert(CERTCertificate *cert, void *wincx, PK11SlotInfo **pSlot) 2023 { 2024 CK_OBJECT_HANDLE certHandle; 2025 CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; 2026 CK_ATTRIBUTE *attr; 2027 CK_ATTRIBUTE searchTemplate[] = { 2028 { CKA_CLASS, NULL, 0 }, 2029 { CKA_VALUE, NULL, 0 }, 2030 }; 2031 const size_t templateSize = sizeof(searchTemplate) / sizeof(searchTemplate[0]); 2032 2033 attr = searchTemplate; 2034 PK11_SETATTRS(attr, CKA_CLASS, &certClass, sizeof(certClass)); 2035 attr++; 2036 PK11_SETATTRS(attr, CKA_VALUE, cert->derCert.data, cert->derCert.len); 2037 2038 if (cert->slot) { 2039 certHandle = PK11_FindCertInSlot(cert->slot, cert, wincx); 2040 if (certHandle != CK_INVALID_HANDLE) { 2041 *pSlot = PK11_ReferenceSlot(cert->slot); 2042 return certHandle; 2043 } 2044 } 2045 2046 certHandle = pk11_FindCertObjectByTemplate(pSlot, searchTemplate, 2047 templateSize, wincx); 2048 if (certHandle != CK_INVALID_HANDLE) { 2049 if (cert->slot == NULL) { 2050 cert->slot = PK11_ReferenceSlot(*pSlot); 2051 cert->pkcs11ID = certHandle; 2052 cert->ownSlot = PR_TRUE; 2053 cert->series = cert->slot->series; 2054 } 2055 } 2056 2057 return (certHandle); 2058 } 2059 2060 SECKEYPrivateKey * 2061 PK11_FindKeyByAnyCert(CERTCertificate *cert, void *wincx) 2062 { 2063 CK_OBJECT_HANDLE certHandle; 2064 CK_OBJECT_HANDLE keyHandle; 2065 PK11SlotInfo *slot = NULL; 2066 SECKEYPrivateKey *privKey = NULL; 2067 PRBool needLogin; 2068 SECStatus rv; 2069 int err; 2070 2071 certHandle = PK11_FindObjectForCert(cert, wincx, &slot); 2072 if (certHandle == CK_INVALID_HANDLE) { 2073 return NULL; 2074 } 2075 /* 2076 * prevent a login race condition. If slot is logged in between 2077 * our call to pk11_LoginStillRequired and the 2078 * PK11_MatchItem. The matchItem call will either succeed, or 2079 * we will call it one more time after calling PK11_Authenticate 2080 * (which is a noop on an authenticated token). 2081 */ 2082 needLogin = pk11_LoginStillRequired(slot, wincx); 2083 keyHandle = PK11_MatchItem(slot, certHandle, CKO_PRIVATE_KEY); 2084 if ((keyHandle == CK_INVALID_HANDLE) && needLogin && 2085 (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) || 2086 SEC_ERROR_TOKEN_NOT_LOGGED_IN == err)) { 2087 /* authenticate and try again */ 2088 rv = PK11_Authenticate(slot, PR_TRUE, wincx); 2089 if (rv == SECSuccess) { 2090 keyHandle = PK11_MatchItem(slot, certHandle, CKO_PRIVATE_KEY); 2091 } 2092 } 2093 if (keyHandle != CK_INVALID_HANDLE) { 2094 privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx); 2095 } 2096 if (slot) { 2097 PK11_FreeSlot(slot); 2098 } 2099 return privKey; 2100 } 2101 2102 CK_OBJECT_HANDLE 2103 pk11_FindPubKeyByAnyCert(CERTCertificate *cert, PK11SlotInfo **slot, void *wincx) 2104 { 2105 CK_OBJECT_HANDLE certHandle; 2106 CK_OBJECT_HANDLE keyHandle; 2107 2108 certHandle = PK11_FindObjectForCert(cert, wincx, slot); 2109 if (certHandle == CK_INVALID_HANDLE) { 2110 return CK_INVALID_HANDLE; 2111 } 2112 keyHandle = PK11_MatchItem(*slot, certHandle, CKO_PUBLIC_KEY); 2113 if (keyHandle == CK_INVALID_HANDLE) { 2114 PK11_FreeSlot(*slot); 2115 return CK_INVALID_HANDLE; 2116 } 2117 return keyHandle; 2118 } 2119 2120 /* 2121 * find the number of certs in the slot with the same subject name 2122 */ 2123 int 2124 PK11_NumberCertsForCertSubject(CERTCertificate *cert) 2125 { 2126 CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; 2127 CK_ATTRIBUTE theTemplate[] = { 2128 { CKA_CLASS, NULL, 0 }, 2129 { CKA_SUBJECT, NULL, 0 }, 2130 }; 2131 CK_ATTRIBUTE *attr = theTemplate; 2132 int templateSize = sizeof(theTemplate) / sizeof(theTemplate[0]); 2133 2134 PK11_SETATTRS(attr, CKA_CLASS, &certClass, sizeof(certClass)); 2135 attr++; 2136 PK11_SETATTRS(attr, CKA_SUBJECT, cert->derSubject.data, cert->derSubject.len); 2137 2138 if (cert->slot == NULL) { 2139 PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, 2140 PR_FALSE, PR_TRUE, NULL); 2141 PK11SlotListElement *le; 2142 int count = 0; 2143 2144 if (!list) { 2145 /* error code is set */ 2146 return 0; 2147 } 2148 2149 /* loop through all the fortezza tokens */ 2150 for (le = list->head; le; le = le->next) { 2151 count += PK11_NumberObjectsFor(le->slot, theTemplate, templateSize); 2152 } 2153 PK11_FreeSlotList(list); 2154 return count; 2155 } 2156 2157 return PK11_NumberObjectsFor(cert->slot, theTemplate, templateSize); 2158 } 2159 2160 /* 2161 * Walk all the certs with the same subject 2162 */ 2163 SECStatus 2164 PK11_TraverseCertsForSubject(CERTCertificate *cert, 2165 SECStatus (*callback)(CERTCertificate *, void *), void *arg) 2166 { 2167 if (!cert) { 2168 return SECFailure; 2169 } 2170 if (cert->slot == NULL) { 2171 PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, 2172 PR_FALSE, PR_TRUE, NULL); 2173 PK11SlotListElement *le; 2174 2175 if (!list) { 2176 /* error code is set */ 2177 return SECFailure; 2178 } 2179 /* loop through all the tokens */ 2180 for (le = list->head; le; le = le->next) { 2181 PK11_TraverseCertsForSubjectInSlot(cert, le->slot, callback, arg); 2182 } 2183 PK11_FreeSlotList(list); 2184 return SECSuccess; 2185 } 2186 2187 return PK11_TraverseCertsForSubjectInSlot(cert, cert->slot, callback, arg); 2188 } 2189 2190 SECStatus 2191 PK11_TraverseCertsForSubjectInSlot(CERTCertificate *cert, PK11SlotInfo *slot, 2192 SECStatus (*callback)(CERTCertificate *, void *), void *arg) 2193 { 2194 PRStatus nssrv = PR_SUCCESS; 2195 NSSToken *token; 2196 NSSDER subject; 2197 NSSTrustDomain *td; 2198 nssList *subjectList; 2199 nssPKIObjectCollection *collection; 2200 nssCryptokiObject **instances; 2201 NSSCertificate **certs; 2202 nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly; 2203 td = STAN_GetDefaultTrustDomain(); 2204 NSSITEM_FROM_SECITEM(&subject, &cert->derSubject); 2205 token = PK11Slot_GetNSSToken(slot); 2206 if (!token) { 2207 return SECSuccess; 2208 } 2209 if (!nssToken_IsPresent(token)) { 2210 (void)nssToken_Destroy(token); 2211 return SECSuccess; 2212 } 2213 collection = nssCertificateCollection_Create(td, NULL); 2214 if (!collection) { 2215 (void)nssToken_Destroy(token); 2216 return SECFailure; 2217 } 2218 subjectList = nssList_Create(NULL, PR_FALSE); 2219 if (!subjectList) { 2220 nssPKIObjectCollection_Destroy(collection); 2221 (void)nssToken_Destroy(token); 2222 return SECFailure; 2223 } 2224 (void)nssTrustDomain_GetCertsForSubjectFromCache(td, &subject, 2225 subjectList); 2226 transfer_token_certs_to_collection(subjectList, token, collection); 2227 instances = nssToken_FindCertificatesBySubject(token, NULL, 2228 &subject, 2229 tokenOnly, 0, &nssrv); 2230 nssPKIObjectCollection_AddInstances(collection, instances, 0); 2231 nss_ZFreeIf(instances); 2232 nssList_Destroy(subjectList); 2233 certs = nssPKIObjectCollection_GetCertificates(collection, 2234 NULL, 0, NULL); 2235 nssPKIObjectCollection_Destroy(collection); 2236 (void)nssToken_Destroy(token); 2237 if (certs) { 2238 CERTCertificate *oldie; 2239 NSSCertificate **cp; 2240 for (cp = certs; *cp; cp++) { 2241 oldie = STAN_GetCERTCertificate(*cp); 2242 if (!oldie) { 2243 continue; 2244 } 2245 if ((*callback)(oldie, arg) != SECSuccess) { 2246 nssrv = PR_FAILURE; 2247 break; 2248 } 2249 } 2250 nssCertificateArray_Destroy(certs); 2251 } 2252 return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure; 2253 } 2254 2255 SECStatus 2256 PK11_TraverseCertsForNicknameInSlot(SECItem *nickname, PK11SlotInfo *slot, 2257 SECStatus (*callback)(CERTCertificate *, void *), void *arg) 2258 { 2259 PRStatus nssrv = PR_SUCCESS; 2260 NSSToken *token; 2261 NSSTrustDomain *td; 2262 NSSUTF8 *nick; 2263 PRBool created = PR_FALSE; 2264 nssCryptokiObject **instances; 2265 nssPKIObjectCollection *collection = NULL; 2266 NSSCertificate **certs; 2267 nssList *nameList = NULL; 2268 nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly; 2269 token = PK11Slot_GetNSSToken(slot); 2270 if (!token || !nssToken_IsPresent(token)) { 2271 (void)nssToken_Destroy(token); 2272 return SECSuccess; 2273 } 2274 if (nickname->data[nickname->len - 1] != '\0') { 2275 nick = nssUTF8_Create(NULL, nssStringType_UTF8String, 2276 nickname->data, nickname->len); 2277 created = PR_TRUE; 2278 } else { 2279 nick = (NSSUTF8 *)nickname->data; 2280 } 2281 td = STAN_GetDefaultTrustDomain(); 2282 collection = nssCertificateCollection_Create(td, NULL); 2283 if (!collection) { 2284 goto loser; 2285 } 2286 nameList = nssList_Create(NULL, PR_FALSE); 2287 if (!nameList) { 2288 goto loser; 2289 } 2290 (void)nssTrustDomain_GetCertsForNicknameFromCache(td, nick, nameList); 2291 transfer_token_certs_to_collection(nameList, token, collection); 2292 instances = nssToken_FindCertificatesByNickname(token, NULL, 2293 nick, 2294 tokenOnly, 0, &nssrv); 2295 nssPKIObjectCollection_AddInstances(collection, instances, 0); 2296 nss_ZFreeIf(instances); 2297 nssList_Destroy(nameList); 2298 certs = nssPKIObjectCollection_GetCertificates(collection, 2299 NULL, 0, NULL); 2300 nssPKIObjectCollection_Destroy(collection); 2301 (void)nssToken_Destroy(token); 2302 if (certs) { 2303 CERTCertificate *oldie; 2304 NSSCertificate **cp; 2305 for (cp = certs; *cp; cp++) { 2306 oldie = STAN_GetCERTCertificate(*cp); 2307 if (!oldie) { 2308 continue; 2309 } 2310 if ((*callback)(oldie, arg) != SECSuccess) { 2311 nssrv = PR_FAILURE; 2312 break; 2313 } 2314 } 2315 nssCertificateArray_Destroy(certs); 2316 } 2317 if (created) 2318 nss_ZFreeIf(nick); 2319 return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure; 2320 loser: 2321 (void)nssToken_Destroy(token); 2322 if (created) { 2323 nss_ZFreeIf(nick); 2324 } 2325 if (collection) { 2326 nssPKIObjectCollection_Destroy(collection); 2327 } 2328 if (nameList) { 2329 nssList_Destroy(nameList); 2330 } 2331 return SECFailure; 2332 } 2333 2334 SECStatus 2335 PK11_TraverseCertsInSlot(PK11SlotInfo *slot, 2336 SECStatus (*callback)(CERTCertificate *, void *), void *arg) 2337 { 2338 PRStatus nssrv; 2339 NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); 2340 NSSToken *tok; 2341 nssList *certList = NULL; 2342 nssCryptokiObject **instances; 2343 nssPKIObjectCollection *collection; 2344 NSSCertificate **certs; 2345 nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly; 2346 tok = PK11Slot_GetNSSToken(slot); 2347 if (!tok) { 2348 return SECSuccess; 2349 } 2350 if (!nssToken_IsPresent(tok)) { 2351 (void)nssToken_Destroy(tok); 2352 return SECSuccess; 2353 } 2354 collection = nssCertificateCollection_Create(td, NULL); 2355 if (!collection) { 2356 (void)nssToken_Destroy(tok); 2357 return SECFailure; 2358 } 2359 certList = nssList_Create(NULL, PR_FALSE); 2360 if (!certList) { 2361 nssPKIObjectCollection_Destroy(collection); 2362 (void)nssToken_Destroy(tok); 2363 return SECFailure; 2364 } 2365 (void)nssTrustDomain_GetCertsFromCache(td, certList); 2366 transfer_token_certs_to_collection(certList, tok, collection); 2367 instances = nssToken_FindObjects(tok, NULL, CKO_CERTIFICATE, 2368 tokenOnly, 0, &nssrv); 2369 nssPKIObjectCollection_AddInstances(collection, instances, 0); 2370 nss_ZFreeIf(instances); 2371 nssList_Destroy(certList); 2372 certs = nssPKIObjectCollection_GetCertificates(collection, 2373 NULL, 0, NULL); 2374 nssPKIObjectCollection_Destroy(collection); 2375 (void)nssToken_Destroy(tok); 2376 if (certs) { 2377 CERTCertificate *oldie; 2378 NSSCertificate **cp; 2379 for (cp = certs; *cp; cp++) { 2380 oldie = STAN_GetCERTCertificate(*cp); 2381 if (!oldie) { 2382 continue; 2383 } 2384 if ((*callback)(oldie, arg) != SECSuccess) { 2385 nssrv = PR_FAILURE; 2386 break; 2387 } 2388 } 2389 nssCertificateArray_Destroy(certs); 2390 } 2391 return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure; 2392 } 2393 2394 /* 2395 * return the certificate associated with a derCert 2396 */ 2397 CERTCertificate * 2398 PK11_FindCertFromDERCert(PK11SlotInfo *slot, CERTCertificate *cert, 2399 void *wincx) 2400 { 2401 return PK11_FindCertFromDERCertItem(slot, &cert->derCert, wincx); 2402 } 2403 2404 CERTCertificate * 2405 PK11_FindCertFromDERCertItem(PK11SlotInfo *slot, const SECItem *inDerCert, 2406 void *wincx) 2407 2408 { 2409 NSSDER derCert; 2410 NSSToken *tok; 2411 nssCryptokiObject *co = NULL; 2412 SECStatus rv; 2413 CERTCertificate *cert = NULL; 2414 2415 NSSITEM_FROM_SECITEM(&derCert, inDerCert); 2416 rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx); 2417 if (rv != SECSuccess) { 2418 PK11_FreeSlot(slot); 2419 return NULL; 2420 } 2421 2422 tok = PK11Slot_GetNSSToken(slot); 2423 if (!tok) { 2424 PK11_FreeSlot(slot); 2425 return NULL; 2426 } 2427 co = nssToken_FindCertificateByEncodedCertificate(tok, NULL, &derCert, 2428 nssTokenSearchType_TokenOnly, NULL); 2429 (void)nssToken_Destroy(tok); 2430 2431 if (co) { 2432 cert = PK11_MakeCertFromHandle(slot, co->handle, NULL); 2433 nssCryptokiObject_Destroy(co); 2434 } 2435 2436 return cert; 2437 } 2438 2439 /* 2440 * import a cert for a private key we have already generated. Set the label 2441 * on both to be the nickname. 2442 */ 2443 static CK_OBJECT_HANDLE 2444 pk11_findKeyObjectByDERCert(PK11SlotInfo *slot, CERTCertificate *cert, 2445 void *wincx) 2446 { 2447 SECItem *keyID; 2448 CK_OBJECT_HANDLE key; 2449 SECStatus rv; 2450 PRBool needLogin; 2451 int err; 2452 2453 if ((slot == NULL) || (cert == NULL)) { 2454 return CK_INVALID_HANDLE; 2455 } 2456 2457 keyID = pk11_mkcertKeyID(cert); 2458 if (keyID == NULL) { 2459 return CK_INVALID_HANDLE; 2460 } 2461 2462 /* 2463 * prevent a login race condition. If slot is logged in between 2464 * our call to pk11_LoginStillRequired and the 2465 * pk11_FindPrivateKeyFromCerID. The matchItem call will either succeed, or 2466 * we will call it one more time after calling PK11_Authenticate 2467 * (which is a noop on an authenticated token). 2468 */ 2469 needLogin = pk11_LoginStillRequired(slot, wincx); 2470 key = pk11_FindPrivateKeyFromCertID(slot, keyID); 2471 if ((key == CK_INVALID_HANDLE) && needLogin && 2472 (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) || 2473 SEC_ERROR_TOKEN_NOT_LOGGED_IN == err)) { 2474 /* authenticate and try again */ 2475 rv = PK11_Authenticate(slot, PR_TRUE, wincx); 2476 if (rv != SECSuccess) 2477 goto loser; 2478 key = pk11_FindPrivateKeyFromCertID(slot, keyID); 2479 } 2480 2481 loser: 2482 SECITEM_ZfreeItem(keyID, PR_TRUE); 2483 return key; 2484 } 2485 2486 SECKEYPrivateKey * 2487 PK11_FindKeyByDERCert(PK11SlotInfo *slot, CERTCertificate *cert, 2488 void *wincx) 2489 { 2490 CK_OBJECT_HANDLE keyHandle; 2491 2492 if ((slot == NULL) || (cert == NULL)) { 2493 return NULL; 2494 } 2495 2496 keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx); 2497 if (keyHandle == CK_INVALID_HANDLE) { 2498 return NULL; 2499 } 2500 2501 return PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx); 2502 } 2503 2504 SECStatus 2505 PK11_ImportCertForKeyToSlot(PK11SlotInfo *slot, CERTCertificate *cert, 2506 char *nickname, 2507 PRBool addCertUsage, void *wincx) 2508 { 2509 CK_OBJECT_HANDLE keyHandle; 2510 2511 if ((slot == NULL) || (cert == NULL) || (nickname == NULL)) { 2512 return SECFailure; 2513 } 2514 2515 keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx); 2516 if (keyHandle == CK_INVALID_HANDLE) { 2517 return SECFailure; 2518 } 2519 2520 return PK11_ImportCert(slot, cert, keyHandle, nickname, addCertUsage); 2521 } 2522 2523 /* remove when the real version comes out */ 2524 #define SEC_OID_MISSI_KEA 300 /* until we have v3 stuff merged */ 2525 PRBool 2526 KEAPQGCompare(CERTCertificate *server, CERTCertificate *cert) 2527 { 2528 2529 /* not implemented */ 2530 return PR_FALSE; 2531 } 2532 2533 PRBool 2534 PK11_FortezzaHasKEA(CERTCertificate *cert) 2535 { 2536 /* look at the subject and see if it is a KEA for MISSI key */ 2537 SECOidData *oid; 2538 CERTCertTrust trust; 2539 2540 if (CERT_GetCertTrust(cert, &trust) != SECSuccess || 2541 ((trust.sslFlags & CERTDB_USER) != CERTDB_USER)) { 2542 return PR_FALSE; 2543 } 2544 2545 oid = SECOID_FindOID(&cert->subjectPublicKeyInfo.algorithm.algorithm); 2546 if (!oid) { 2547 return PR_FALSE; 2548 } 2549 2550 return (PRBool)((oid->offset == SEC_OID_MISSI_KEA_DSS_OLD) || 2551 (oid->offset == SEC_OID_MISSI_KEA_DSS) || 2552 (oid->offset == SEC_OID_MISSI_KEA)); 2553 } 2554 2555 /* 2556 * Find a kea cert on this slot that matches the domain of it's peer 2557 */ 2558 static CERTCertificate 2559 * 2560 pk11_GetKEAMate(PK11SlotInfo *slot, CERTCertificate *peer) 2561 { 2562 int i; 2563 CERTCertificate *returnedCert = NULL; 2564 2565 for (i = 0; i < slot->cert_count; i++) { 2566 CERTCertificate *cert = slot->cert_array[i]; 2567 2568 if (PK11_FortezzaHasKEA(cert) && KEAPQGCompare(peer, cert)) { 2569 returnedCert = CERT_DupCertificate(cert); 2570 break; 2571 } 2572 } 2573 return returnedCert; 2574 } 2575 2576 /* 2577 * The following is a FORTEZZA only Certificate request. We call this when we 2578 * are doing a non-client auth SSL connection. We are only interested in the 2579 * fortezza slots, and we are only interested in certs that share the same root 2580 * key as the server. 2581 */ 2582 CERTCertificate * 2583 PK11_FindBestKEAMatch(CERTCertificate *server, void *wincx) 2584 { 2585 PK11SlotList *keaList = PK11_GetAllTokens(CKM_KEA_KEY_DERIVE, 2586 PR_FALSE, PR_TRUE, wincx); 2587 PK11SlotListElement *le; 2588 CERTCertificate *returnedCert = NULL; 2589 SECStatus rv; 2590 2591 if (!keaList) { 2592 /* error code is set */ 2593 return NULL; 2594 } 2595 2596 /* loop through all the fortezza tokens */ 2597 for (le = keaList->head; le; le = le->next) { 2598 rv = PK11_Authenticate(le->slot, PR_TRUE, wincx); 2599 if (rv != SECSuccess) 2600 continue; 2601 if (le->slot->session == CK_INVALID_HANDLE) { 2602 continue; 2603 } 2604 returnedCert = pk11_GetKEAMate(le->slot, server); 2605 if (returnedCert) 2606 break; 2607 } 2608 PK11_FreeSlotList(keaList); 2609 2610 return returnedCert; 2611 } 2612 2613 /* 2614 * find a matched pair of kea certs to key exchange parameters from one 2615 * fortezza card to another as necessary. 2616 */ 2617 SECStatus 2618 PK11_GetKEAMatchedCerts(PK11SlotInfo *slot1, PK11SlotInfo *slot2, 2619 CERTCertificate **cert1, CERTCertificate **cert2) 2620 { 2621 CERTCertificate *returnedCert = NULL; 2622 int i; 2623 2624 for (i = 0; i < slot1->cert_count; i++) { 2625 CERTCertificate *cert = slot1->cert_array[i]; 2626 2627 if (PK11_FortezzaHasKEA(cert)) { 2628 returnedCert = pk11_GetKEAMate(slot2, cert); 2629 if (returnedCert != NULL) { 2630 *cert2 = returnedCert; 2631 *cert1 = CERT_DupCertificate(cert); 2632 return SECSuccess; 2633 } 2634 } 2635 } 2636 return SECFailure; 2637 } 2638 2639 CK_OBJECT_HANDLE 2640 PK11_FindEncodedCertInSlot(PK11SlotInfo *slot, SECItem *derCert, void *wincx) 2641 { 2642 if (!slot || !derCert) { 2643 PORT_SetError(SEC_ERROR_INVALID_ARGS); 2644 return SECFailure; 2645 } 2646 2647 CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; 2648 CK_ATTRIBUTE theTemplate[] = { 2649 { CKA_VALUE, NULL, 0 }, 2650 { CKA_CLASS, NULL, 0 } 2651 }; 2652 const size_t tsize = sizeof(theTemplate) / sizeof(theTemplate[0]); 2653 CK_ATTRIBUTE *attrs = theTemplate; 2654 2655 PK11_SETATTRS(attrs, CKA_VALUE, derCert->data, derCert->len); 2656 attrs++; 2657 PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass)); 2658 2659 SECStatus rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx); 2660 if (rv != SECSuccess) { 2661 return CK_INVALID_HANDLE; 2662 } 2663 2664 return pk11_FindObjectByTemplate(slot, theTemplate, tsize); 2665 } 2666 2667 CK_OBJECT_HANDLE 2668 PK11_FindCertInSlot(PK11SlotInfo *slot, CERTCertificate *cert, void *wincx) 2669 { 2670 CK_OBJECT_HANDLE certh; 2671 2672 if (cert->slot == slot) { 2673 certh = cert->pkcs11ID; 2674 if ((certh == CK_INVALID_HANDLE) || 2675 (cert->series != slot->series)) { 2676 certh = PK11_FindEncodedCertInSlot(slot, &cert->derCert, wincx); 2677 cert->pkcs11ID = certh; 2678 cert->series = slot->series; 2679 } 2680 } else { 2681 certh = PK11_FindEncodedCertInSlot(slot, &cert->derCert, wincx); 2682 } 2683 return certh; 2684 } 2685 2686 /* Looking for PK11_GetKeyIDFromCert? 2687 * Use PK11_GetLowLevelKeyIDForCert instead. 2688 */ 2689 2690 struct listCertsStr { 2691 PK11CertListType type; 2692 CERTCertList *certList; 2693 }; 2694 2695 static PRStatus 2696 pk11ListCertCallback(NSSCertificate *c, void *arg) 2697 { 2698 struct listCertsStr *listCertP = (struct listCertsStr *)arg; 2699 CERTCertificate *newCert = NULL; 2700 PK11CertListType type = listCertP->type; 2701 CERTCertList *certList = listCertP->certList; 2702 PRBool isUnique = PR_FALSE; 2703 PRBool isCA = PR_FALSE; 2704 char *nickname = NULL; 2705 unsigned int certType; 2706 SECStatus rv; 2707 2708 if ((type == PK11CertListUnique) || (type == PK11CertListRootUnique) || 2709 (type == PK11CertListCAUnique) || (type == PK11CertListUserUnique)) { 2710 /* only list one instance of each certificate, even if several exist */ 2711 isUnique = PR_TRUE; 2712 } 2713 if ((type == PK11CertListCA) || (type == PK11CertListRootUnique) || 2714 (type == PK11CertListCAUnique)) { 2715 isCA = PR_TRUE; 2716 } 2717 2718 /* if we want user certs and we don't have one skip this cert */ 2719 if (((type == PK11CertListUser) || (type == PK11CertListUserUnique)) && 2720 !NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL)) { 2721 return PR_SUCCESS; 2722 } 2723 2724 /* PK11CertListRootUnique means we want CA certs without a private key. 2725 * This is for legacy app support . PK11CertListCAUnique should be used 2726 * instead to get all CA certs, regardless of private key 2727 */ 2728 if ((type == PK11CertListRootUnique) && 2729 NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL)) { 2730 return PR_SUCCESS; 2731 } 2732 2733 /* caller still owns the reference to 'c' */ 2734 newCert = STAN_GetCERTCertificate(c); 2735 if (!newCert) { 2736 return PR_SUCCESS; 2737 } 2738 /* if we want CA certs and it ain't one, skip it */ 2739 if (isCA && (!CERT_IsCACert(newCert, &certType))) { 2740 return PR_SUCCESS; 2741 } 2742 if (isUnique) { 2743 CERT_DupCertificate(newCert); 2744 2745 nickname = STAN_GetCERTCertificateName(certList->arena, c); 2746 2747 /* put slot certs at the end */ 2748 if (newCert->slot && !PK11_IsInternal(newCert->slot)) { 2749 rv = CERT_AddCertToListTailWithData(certList, newCert, nickname); 2750 } else { 2751 rv = CERT_AddCertToListHeadWithData(certList, newCert, nickname); 2752 } 2753 /* if we didn't add the cert to the list, don't leak it */ 2754 if (rv != SECSuccess) { 2755 CERT_DestroyCertificate(newCert); 2756 } 2757 } else { 2758 /* add multiple instances to the cert list */ 2759 nssCryptokiObject **ip; 2760 nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object); 2761 if (!instances) { 2762 return PR_SUCCESS; 2763 } 2764 for (ip = instances; *ip; ip++) { 2765 nssCryptokiObject *instance = *ip; 2766 PK11SlotInfo *slot = instance->token->pk11slot; 2767 2768 /* put the same CERTCertificate in the list for all instances */ 2769 CERT_DupCertificate(newCert); 2770 2771 nickname = STAN_GetCERTCertificateNameForInstance( 2772 certList->arena, c, instance); 2773 2774 /* put slot certs at the end */ 2775 if (slot && !PK11_IsInternal(slot)) { 2776 rv = CERT_AddCertToListTailWithData(certList, newCert, nickname); 2777 } else { 2778 rv = CERT_AddCertToListHeadWithData(certList, newCert, nickname); 2779 } 2780 /* if we didn't add the cert to the list, don't leak it */ 2781 if (rv != SECSuccess) { 2782 CERT_DestroyCertificate(newCert); 2783 } 2784 } 2785 nssCryptokiObjectArray_Destroy(instances); 2786 } 2787 return PR_SUCCESS; 2788 } 2789 2790 CERTCertList * 2791 PK11_ListCerts(PK11CertListType type, void *pwarg) 2792 { 2793 NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain(); 2794 CERTCertList *certList = NULL; 2795 struct listCertsStr listCerts; 2796 certList = CERT_NewCertList(); 2797 listCerts.type = type; 2798 listCerts.certList = certList; 2799 2800 /* authenticate to the slots */ 2801 (void)pk11_TraverseAllSlots(NULL, NULL, PR_TRUE, pwarg); 2802 NSSTrustDomain_TraverseCertificates(defaultTD, pk11ListCertCallback, 2803 &listCerts); 2804 return certList; 2805 } 2806 2807 SECItem * 2808 PK11_GetLowLevelKeyIDForCert(PK11SlotInfo *slot, 2809 CERTCertificate *cert, void *wincx) 2810 { 2811 CK_OBJECT_HANDLE certHandle; 2812 PK11SlotInfo *slotRef = NULL; 2813 SECItem *item; 2814 2815 if (slot) { 2816 certHandle = PK11_FindCertInSlot(slot, cert, wincx); 2817 } else { 2818 certHandle = PK11_FindObjectForCert(cert, wincx, &slotRef); 2819 if (certHandle == CK_INVALID_HANDLE) { 2820 return pk11_mkcertKeyID(cert); 2821 } 2822 slot = slotRef; 2823 } 2824 2825 if (certHandle == CK_INVALID_HANDLE) { 2826 return NULL; 2827 } 2828 2829 item = pk11_GetLowLevelKeyFromHandle(slot, certHandle); 2830 if (slotRef) 2831 PK11_FreeSlot(slotRef); 2832 return item; 2833 } 2834 2835 /* argument type for listCertsCallback */ 2836 typedef struct { 2837 CERTCertList *list; 2838 PK11SlotInfo *slot; 2839 } ListCertsArg; 2840 2841 static SECStatus 2842 listCertsCallback(CERTCertificate *cert, void *arg) 2843 { 2844 ListCertsArg *cdata = (ListCertsArg *)arg; 2845 char *nickname = NULL; 2846 nssCryptokiObject *instance, **ci; 2847 nssCryptokiObject **instances; 2848 NSSCertificate *c = STAN_GetNSSCertificate(cert); 2849 SECStatus rv; 2850 2851 if (c == NULL) { 2852 return SECFailure; 2853 } 2854 instances = nssPKIObject_GetInstances(&c->object); 2855 if (!instances) { 2856 return SECFailure; 2857 } 2858 instance = NULL; 2859 for (ci = instances; *ci; ci++) { 2860 if ((*ci)->token->pk11slot == cdata->slot) { 2861 instance = *ci; 2862 break; 2863 } 2864 } 2865 PORT_Assert(instance != NULL); 2866 if (!instance) { 2867 nssCryptokiObjectArray_Destroy(instances); 2868 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2869 return SECFailure; 2870 } 2871 nickname = STAN_GetCERTCertificateNameForInstance(cdata->list->arena, 2872 c, instance); 2873 nssCryptokiObjectArray_Destroy(instances); 2874 2875 CERT_DupCertificate(cert); 2876 rv = CERT_AddCertToListTailWithData(cdata->list, cert, nickname); 2877 if (rv != SECSuccess) { 2878 CERT_DestroyCertificate(cert); 2879 } 2880 return rv; 2881 } 2882 2883 CERTCertList * 2884 PK11_ListCertsInSlot(PK11SlotInfo *slot) 2885 { 2886 SECStatus status; 2887 CERTCertList *certs; 2888 ListCertsArg cdata; 2889 2890 certs = CERT_NewCertList(); 2891 if (certs == NULL) 2892 return NULL; 2893 cdata.list = certs; 2894 cdata.slot = slot; 2895 2896 status = PK11_TraverseCertsInSlot(slot, listCertsCallback, 2897 &cdata); 2898 2899 if (status != SECSuccess) { 2900 CERT_DestroyCertList(certs); 2901 certs = NULL; 2902 } 2903 2904 return certs; 2905 } 2906 2907 PK11SlotList * 2908 PK11_GetAllSlotsForCert(CERTCertificate *cert, void *arg) 2909 { 2910 nssCryptokiObject **ip; 2911 PK11SlotList *slotList; 2912 NSSCertificate *c; 2913 nssCryptokiObject **instances; 2914 PRBool found = PR_FALSE; 2915 2916 if (!cert) { 2917 PORT_SetError(SEC_ERROR_INVALID_ARGS); 2918 return NULL; 2919 } 2920 2921 c = STAN_GetNSSCertificate(cert); 2922 if (!c) { 2923 CERT_MapStanError(); 2924 return NULL; 2925 } 2926 2927 /* add multiple instances to the cert list */ 2928 instances = nssPKIObject_GetInstances(&c->object); 2929 if (!instances) { 2930 PORT_SetError(SEC_ERROR_NO_TOKEN); 2931 return NULL; 2932 } 2933 2934 slotList = PK11_NewSlotList(); 2935 if (!slotList) { 2936 nssCryptokiObjectArray_Destroy(instances); 2937 return NULL; 2938 } 2939 2940 for (ip = instances; *ip; ip++) { 2941 nssCryptokiObject *instance = *ip; 2942 PK11SlotInfo *slot = instance->token->pk11slot; 2943 if (slot) { 2944 PK11_AddSlotToList(slotList, slot, PR_TRUE); 2945 found = PR_TRUE; 2946 } 2947 } 2948 if (!found) { 2949 PK11_FreeSlotList(slotList); 2950 PORT_SetError(SEC_ERROR_NO_TOKEN); 2951 slotList = NULL; 2952 } 2953 2954 nssCryptokiObjectArray_Destroy(instances); 2955 return slotList; 2956 } 2957 2958 /* 2959 * Using __PK11_SetCertificateNickname is *DANGEROUS*. 2960 * 2961 * The API will update the NSS database, but it *will NOT* update the in-memory data. 2962 * As a result, after calling this API, there will be INCONSISTENCY between 2963 * in-memory data and the database. 2964 * 2965 * Use of the API should be limited to short-lived tools, which will exit immediately 2966 * after using this API. 2967 * 2968 * If you ignore this warning, your process is TAINTED and will most likely misbehave. 2969 */ 2970 SECStatus 2971 __PK11_SetCertificateNickname(CERTCertificate *cert, const char *nickname) 2972 { 2973 /* Can't set nickname of temp cert. */ 2974 if (!cert->slot || cert->pkcs11ID == CK_INVALID_HANDLE) { 2975 PORT_SetError(SEC_ERROR_INVALID_ARGS); 2976 return SECFailure; 2977 } 2978 return PK11_SetObjectNickname(cert->slot, cert->pkcs11ID, nickname); 2979 }