comparison nss/lib/pk11wrap/pk11cert.c @ 0:1e5118fa0cb1

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