security/nss/lib/pk11wrap/pk11cert.c

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

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

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

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

mercurial