Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(717)

Side by Side Diff: nss/lib/pk11wrap/pk11cert.c

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

Powered by Google App Engine
This is Rietveld 408576698