1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "pkcs11.h"
6
7 #ifndef DEVM_H
8 #include "devm.h"
9 #endif /* DEVM_H */
10
11 #ifndef CKHELPER_H
12 #include "ckhelper.h"
13 #endif /* CKHELPER_H */
14
15 #include "pk11func.h"
16 #include "dev3hack.h"
17 #include "secerr.h"
18
19 extern const NSSError NSS_ERROR_NOT_FOUND;
20 extern const NSSError NSS_ERROR_INVALID_ARGUMENT;
21 extern const NSSError NSS_ERROR_PKCS11;
22
23 /* The number of object handles to grab during each call to C_FindObjects */
24 #define OBJECT_STACK_SIZE 16
25
26 NSS_IMPLEMENT PRStatus
nssToken_Destroy(NSSToken * tok)27 nssToken_Destroy(
28 NSSToken *tok)
29 {
30 if (tok) {
31 if (PR_ATOMIC_DECREMENT(&tok->base.refCount) == 0) {
32 PK11_FreeSlot(tok->pk11slot);
33 PZ_DestroyLock(tok->base.lock);
34 nssTokenObjectCache_Destroy(tok->cache);
35
36 /* We're going away, let the nssSlot know in case it's held
37 * alive by someone else. Usually we should hold the last ref. */
38 nssSlot_EnterMonitor(tok->slot);
39 tok->slot->token = NULL;
40 nssSlot_ExitMonitor(tok->slot);
41
42 (void)nssSlot_Destroy(tok->slot);
43 return nssArena_Destroy(tok->base.arena);
44 }
45 }
46 return PR_SUCCESS;
47 }
48
49 NSS_IMPLEMENT void
nssToken_Remove(NSSToken * tok)50 nssToken_Remove(
51 NSSToken *tok)
52 {
53 nssTokenObjectCache_Clear(tok->cache);
54 }
55
56 NSS_IMPLEMENT void
NSSToken_Destroy(NSSToken * tok)57 NSSToken_Destroy(
58 NSSToken *tok)
59 {
60 (void)nssToken_Destroy(tok);
61 }
62
63 NSS_IMPLEMENT NSSToken *
nssToken_AddRef(NSSToken * tok)64 nssToken_AddRef(
65 NSSToken *tok)
66 {
67 PR_ATOMIC_INCREMENT(&tok->base.refCount);
68 return tok;
69 }
70
71 NSS_IMPLEMENT NSSSlot *
nssToken_GetSlot(NSSToken * tok)72 nssToken_GetSlot(
73 NSSToken *tok)
74 {
75 return nssSlot_AddRef(tok->slot);
76 }
77
78 NSS_IMPLEMENT void *
nssToken_GetCryptokiEPV(NSSToken * token)79 nssToken_GetCryptokiEPV(
80 NSSToken *token)
81 {
82 return nssSlot_GetCryptokiEPV(token->slot);
83 }
84
85 NSS_IMPLEMENT nssSession *
nssToken_GetDefaultSession(NSSToken * token)86 nssToken_GetDefaultSession(
87 NSSToken *token)
88 {
89 return token->defaultSession;
90 }
91
92 NSS_IMPLEMENT NSSUTF8 *
nssToken_GetName(NSSToken * tok)93 nssToken_GetName(
94 NSSToken *tok)
95 {
96 if (tok == NULL) {
97 return "";
98 }
99 if (tok->base.name[0] == 0) {
100 (void)nssSlot_IsTokenPresent(tok->slot);
101 }
102 return tok->base.name;
103 }
104
105 NSS_IMPLEMENT NSSUTF8 *
NSSToken_GetName(NSSToken * token)106 NSSToken_GetName(
107 NSSToken *token)
108 {
109 return nssToken_GetName(token);
110 }
111
112 NSS_IMPLEMENT PRBool
nssToken_IsLoginRequired(NSSToken * token)113 nssToken_IsLoginRequired(
114 NSSToken *token)
115 {
116 return (token->ckFlags & CKF_LOGIN_REQUIRED);
117 }
118
119 NSS_IMPLEMENT PRBool
nssToken_NeedsPINInitialization(NSSToken * token)120 nssToken_NeedsPINInitialization(
121 NSSToken *token)
122 {
123 return (!(token->ckFlags & CKF_USER_PIN_INITIALIZED));
124 }
125
126 NSS_IMPLEMENT PRStatus
nssToken_DeleteStoredObject(nssCryptokiObject * instance)127 nssToken_DeleteStoredObject(
128 nssCryptokiObject *instance)
129 {
130 CK_RV ckrv;
131 PRStatus status;
132 PRBool createdSession = PR_FALSE;
133 NSSToken *token = instance->token;
134 nssSession *session = NULL;
135 void *epv = nssToken_GetCryptokiEPV(instance->token);
136 if (token->cache) {
137 nssTokenObjectCache_RemoveObject(token->cache, instance);
138 }
139 if (instance->isTokenObject) {
140 if (token->defaultSession &&
141 nssSession_IsReadWrite(token->defaultSession)) {
142 session = token->defaultSession;
143 } else {
144 session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE);
145 createdSession = PR_TRUE;
146 }
147 }
148 if (session == NULL) {
149 return PR_FAILURE;
150 }
151 nssSession_EnterMonitor(session);
152 ckrv = CKAPI(epv)->C_DestroyObject(session->handle, instance->handle);
153 nssSession_ExitMonitor(session);
154 if (createdSession) {
155 nssSession_Destroy(session);
156 }
157 status = PR_SUCCESS;
158 if (ckrv != CKR_OK) {
159 status = PR_FAILURE;
160 /* use the error stack to pass the PKCS #11 error out */
161 nss_SetError(ckrv);
162 nss_SetError(NSS_ERROR_PKCS11);
163 }
164 return status;
165 }
166
167 static nssCryptokiObject *
import_object(NSSToken * tok,nssSession * sessionOpt,CK_ATTRIBUTE_PTR objectTemplate,CK_ULONG otsize)168 import_object(
169 NSSToken *tok,
170 nssSession *sessionOpt,
171 CK_ATTRIBUTE_PTR objectTemplate,
172 CK_ULONG otsize)
173 {
174 nssSession *session = NULL;
175 PRBool createdSession = PR_FALSE;
176 nssCryptokiObject *object = NULL;
177 CK_OBJECT_HANDLE handle;
178 CK_RV ckrv;
179 void *epv = nssToken_GetCryptokiEPV(tok);
180 if (nssCKObject_IsTokenObjectTemplate(objectTemplate, otsize)) {
181 if (sessionOpt) {
182 if (!nssSession_IsReadWrite(sessionOpt)) {
183 nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
184 return NULL;
185 }
186 session = sessionOpt;
187 } else if (tok->defaultSession &&
188 nssSession_IsReadWrite(tok->defaultSession)) {
189 session = tok->defaultSession;
190 } else {
191 session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE);
192 createdSession = PR_TRUE;
193 }
194 } else {
195 session = (sessionOpt) ? sessionOpt : tok->defaultSession;
196 }
197 if (session == NULL) {
198 nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
199 return NULL;
200 }
201 nssSession_EnterMonitor(session);
202 ckrv = CKAPI(epv)->C_CreateObject(session->handle,
203 objectTemplate, otsize,
204 &handle);
205 nssSession_ExitMonitor(session);
206 if (ckrv == CKR_OK) {
207 object = nssCryptokiObject_Create(tok, session, handle);
208 } else {
209 nss_SetError(ckrv);
210 nss_SetError(NSS_ERROR_PKCS11);
211 }
212 if (createdSession) {
213 nssSession_Destroy(session);
214 }
215 return object;
216 }
217
218 static nssCryptokiObject **
create_objects_from_handles(NSSToken * tok,nssSession * session,CK_OBJECT_HANDLE * handles,PRUint32 numH)219 create_objects_from_handles(
220 NSSToken *tok,
221 nssSession *session,
222 CK_OBJECT_HANDLE *handles,
223 PRUint32 numH)
224 {
225 nssCryptokiObject **objects;
226 objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numH + 1);
227 if (objects) {
228 PRInt32 i;
229 for (i = 0; i < (PRInt32)numH; i++) {
230 objects[i] = nssCryptokiObject_Create(tok, session, handles[i]);
231 if (!objects[i]) {
232 for (--i; i > 0; --i) {
233 nssCryptokiObject_Destroy(objects[i]);
234 }
235 nss_ZFreeIf(objects);
236 objects = NULL;
237 break;
238 }
239 }
240 }
241 return objects;
242 }
243
244 static nssCryptokiObject **
find_objects(NSSToken * tok,nssSession * sessionOpt,CK_ATTRIBUTE_PTR obj_template,CK_ULONG otsize,PRUint32 maximumOpt,PRStatus * statusOpt)245 find_objects(
246 NSSToken *tok,
247 nssSession *sessionOpt,
248 CK_ATTRIBUTE_PTR obj_template,
249 CK_ULONG otsize,
250 PRUint32 maximumOpt,
251 PRStatus *statusOpt)
252 {
253 CK_RV ckrv = CKR_OK;
254 CK_ULONG count;
255 CK_OBJECT_HANDLE *objectHandles = NULL;
256 CK_OBJECT_HANDLE staticObjects[OBJECT_STACK_SIZE];
257 PRUint32 arraySize, numHandles;
258 void *epv = nssToken_GetCryptokiEPV(tok);
259 nssCryptokiObject **objects;
260 nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
261
262 /* Don't ask the module to use an invalid session handle. */
263 if (!session || session->handle == CK_INVALID_HANDLE) {
264 ckrv = CKR_SESSION_HANDLE_INVALID;
265 goto loser;
266 }
267
268 /* the arena is only for the array of object handles */
269 if (maximumOpt > 0) {
270 arraySize = maximumOpt;
271 } else {
272 arraySize = OBJECT_STACK_SIZE;
273 }
274 numHandles = 0;
275 if (arraySize <= OBJECT_STACK_SIZE) {
276 objectHandles = staticObjects;
277 } else {
278 objectHandles = nss_ZNEWARRAY(NULL, CK_OBJECT_HANDLE, arraySize);
279 }
280 if (!objectHandles) {
281 ckrv = CKR_HOST_MEMORY;
282 goto loser;
283 }
284 nssSession_EnterMonitor(session); /* ==== session lock === */
285 /* Initialize the find with the template */
286 ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle,
287 obj_template, otsize);
288 if (ckrv != CKR_OK) {
289 nssSession_ExitMonitor(session);
290 goto loser;
291 }
292 while (PR_TRUE) {
293 /* Issue the find for up to arraySize - numHandles objects */
294 ckrv = CKAPI(epv)->C_FindObjects(session->handle,
295 objectHandles + numHandles,
296 arraySize - numHandles,
297 &count);
298 if (ckrv != CKR_OK) {
299 nssSession_ExitMonitor(session);
300 goto loser;
301 }
302 /* bump the number of found objects */
303 numHandles += count;
304 if (maximumOpt > 0 || numHandles < arraySize) {
305 /* When a maximum is provided, the search is done all at once,
306 * so the search is finished. If the number returned was less
307 * than the number sought, the search is finished.
308 */
309 break;
310 }
311 /* the array is filled, double it and continue */
312 arraySize *= 2;
313 if (objectHandles == staticObjects) {
314 objectHandles = nss_ZNEWARRAY(NULL, CK_OBJECT_HANDLE, arraySize);
315 if (objectHandles) {
316 PORT_Memcpy(objectHandles, staticObjects,
317 OBJECT_STACK_SIZE * sizeof(objectHandles[1]));
318 }
319 } else {
320 objectHandles = nss_ZREALLOCARRAY(objectHandles,
321 CK_OBJECT_HANDLE,
322 arraySize);
323 }
324 if (!objectHandles) {
325 nssSession_ExitMonitor(session);
326 ckrv = CKR_HOST_MEMORY;
327 goto loser;
328 }
329 }
330 ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
331 nssSession_ExitMonitor(session); /* ==== end session lock === */
332 if (ckrv != CKR_OK) {
333 goto loser;
334 }
335 if (numHandles > 0) {
336 objects = create_objects_from_handles(tok, session,
337 objectHandles, numHandles);
338 } else {
339 nss_SetError(NSS_ERROR_NOT_FOUND);
340 objects = NULL;
341 }
342 if (objectHandles && objectHandles != staticObjects) {
343 nss_ZFreeIf(objectHandles);
344 }
345 if (statusOpt)
346 *statusOpt = PR_SUCCESS;
347 return objects;
348 loser:
349 if (objectHandles && objectHandles != staticObjects) {
350 nss_ZFreeIf(objectHandles);
351 }
352 /*
353 * These errors should be treated the same as if the objects just weren't
354 * found..
355 */
356 if ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) ||
357 (ckrv == CKR_ATTRIBUTE_VALUE_INVALID) ||
358 (ckrv == CKR_DATA_INVALID) ||
359 (ckrv == CKR_DATA_LEN_RANGE) ||
360 (ckrv == CKR_FUNCTION_NOT_SUPPORTED) ||
361 (ckrv == CKR_TEMPLATE_INCOMPLETE) ||
362 (ckrv == CKR_TEMPLATE_INCONSISTENT)) {
363
364 nss_SetError(NSS_ERROR_NOT_FOUND);
365 if (statusOpt)
366 *statusOpt = PR_SUCCESS;
367 } else {
368 nss_SetError(ckrv);
369 nss_SetError(NSS_ERROR_PKCS11);
370 if (statusOpt)
371 *statusOpt = PR_FAILURE;
372 }
373 return (nssCryptokiObject **)NULL;
374 }
375
376 NSS_IMPLEMENT nssCryptokiObject **
nssToken_FindObjectsByTemplate(NSSToken * token,nssSession * sessionOpt,CK_ATTRIBUTE_PTR obj_template,CK_ULONG otsize,PRUint32 maximumOpt,PRStatus * statusOpt)377 nssToken_FindObjectsByTemplate(
378 NSSToken *token,
379 nssSession *sessionOpt,
380 CK_ATTRIBUTE_PTR obj_template,
381 CK_ULONG otsize,
382 PRUint32 maximumOpt,
383 PRStatus *statusOpt)
384 {
385 CK_OBJECT_CLASS objclass = (CK_OBJECT_CLASS)-1;
386 nssCryptokiObject **objects = NULL;
387 PRUint32 i;
388
389 if (!token) {
390 PORT_SetError(SEC_ERROR_NO_TOKEN);
391 if (statusOpt)
392 *statusOpt = PR_FAILURE;
393 return NULL;
394 }
395 for (i = 0; i < otsize; i++) {
396 if (obj_template[i].type == CKA_CLASS) {
397 objclass = *(CK_OBJECT_CLASS *)obj_template[i].pValue;
398 break;
399 }
400 }
401 PR_ASSERT(i < otsize);
402 if (i == otsize) {
403 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
404 if (statusOpt)
405 *statusOpt = PR_FAILURE;
406 return NULL;
407 }
408 /* If these objects are being cached, try looking there first */
409 if (token->cache &&
410 nssTokenObjectCache_HaveObjectClass(token->cache, objclass)) {
411 PRStatus status;
412 objects = nssTokenObjectCache_FindObjectsByTemplate(token->cache,
413 objclass,
414 obj_template,
415 otsize,
416 maximumOpt,
417 &status);
418 if (status == PR_SUCCESS) {
419 if (statusOpt)
420 *statusOpt = status;
421 return objects;
422 }
423 }
424 /* Either they are not cached, or cache failed; look on token. */
425 objects = find_objects(token, sessionOpt,
426 obj_template, otsize,
427 maximumOpt, statusOpt);
428 return objects;
429 }
430
431 extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
432
433 NSS_IMPLEMENT nssCryptokiObject *
nssToken_ImportCertificate(NSSToken * tok,nssSession * sessionOpt,NSSCertificateType certType,NSSItem * id,const NSSUTF8 * nickname,NSSDER * encoding,NSSDER * issuer,NSSDER * subject,NSSDER * serial,NSSASCII7 * email,PRBool asTokenObject)434 nssToken_ImportCertificate(
435 NSSToken *tok,
436 nssSession *sessionOpt,
437 NSSCertificateType certType,
438 NSSItem *id,
439 const NSSUTF8 *nickname,
440 NSSDER *encoding,
441 NSSDER *issuer,
442 NSSDER *subject,
443 NSSDER *serial,
444 NSSASCII7 *email,
445 PRBool asTokenObject)
446 {
447 PRStatus status;
448 CK_CERTIFICATE_TYPE cert_type;
449 CK_ATTRIBUTE_PTR attr;
450 CK_ATTRIBUTE cert_tmpl[10];
451 CK_ULONG ctsize;
452 nssTokenSearchType searchType;
453 nssCryptokiObject *rvObject = NULL;
454
455 if (!tok) {
456 PORT_SetError(SEC_ERROR_NO_TOKEN);
457 return NULL;
458 }
459 if (certType == NSSCertificateType_PKIX) {
460 cert_type = CKC_X_509;
461 } else {
462 return (nssCryptokiObject *)NULL;
463 }
464 NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
465 if (asTokenObject) {
466 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
467 searchType = nssTokenSearchType_TokenOnly;
468 } else {
469 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
470 searchType = nssTokenSearchType_SessionOnly;
471 }
472 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
473 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CERTIFICATE_TYPE, cert_type);
474 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
475 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
476 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encoding);
477 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, issuer);
478 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
479 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, serial);
480 if (email) {
481 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL, email);
482 }
483 NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
484 /* see if the cert is already there */
485 rvObject = nssToken_FindCertificateByIssuerAndSerialNumber(tok,
486 sessionOpt,
487 issuer,
488 serial,
489 searchType,
490 NULL);
491 if (rvObject) {
492 NSSItem existingDER;
493 NSSSlot *slot = nssToken_GetSlot(tok);
494 nssSession *session = nssSlot_CreateSession(slot, NULL, PR_TRUE);
495 if (!session) {
496 nssCryptokiObject_Destroy(rvObject);
497 nssSlot_Destroy(slot);
498 return (nssCryptokiObject *)NULL;
499 }
500 /* Reject any attempt to import a new cert that has the same
501 * issuer/serial as an existing cert, but does not have the
502 * same encoding
503 */
504 NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
505 NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE);
506 NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
507 status = nssCKObject_GetAttributes(rvObject->handle,
508 cert_tmpl, ctsize, NULL,
509 session, slot);
510 NSS_CK_ATTRIBUTE_TO_ITEM(cert_tmpl, &existingDER);
511 if (status == PR_SUCCESS) {
512 if (!nssItem_Equal(encoding, &existingDER, NULL)) {
513 nss_SetError(NSS_ERROR_INVALID_CERTIFICATE);
514 status = PR_FAILURE;
515 }
516 nss_ZFreeIf(existingDER.data);
517 }
518 if (status == PR_FAILURE) {
519 nssCryptokiObject_Destroy(rvObject);
520 nssSession_Destroy(session);
521 nssSlot_Destroy(slot);
522 return (nssCryptokiObject *)NULL;
523 }
524 /* according to PKCS#11, label, ID, issuer, and serial number
525 * may change after the object has been created. For PKIX, the
526 * last two attributes can't change, so for now we'll only worry
527 * about the first two.
528 */
529 NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
530 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
531 if (!rvObject->label && nickname) {
532 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
533 }
534 NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
535 /* reset the mutable attributes on the token */
536 nssCKObject_SetAttributes(rvObject->handle,
537 cert_tmpl, ctsize,
538 session, slot);
539 if (!rvObject->label && nickname) {
540 rvObject->label = nssUTF8_Duplicate(nickname, NULL);
541 }
542 nssSession_Destroy(session);
543 nssSlot_Destroy(slot);
544 } else {
545 /* Import the certificate onto the token */
546 rvObject = import_object(tok, sessionOpt, cert_tmpl, ctsize);
547 }
548 if (rvObject && tok->cache) {
549 /* The cache will overwrite the attributes if the object already
550 * exists.
551 */
552 nssTokenObjectCache_ImportObject(tok->cache, rvObject,
553 CKO_CERTIFICATE,
554 cert_tmpl, ctsize);
555 }
556 return rvObject;
557 }
558
559 /* traverse all objects of the given class - this should only happen
560 * if the token has been marked as "traversable"
561 */
562 NSS_IMPLEMENT nssCryptokiObject **
nssToken_FindObjects(NSSToken * token,nssSession * sessionOpt,CK_OBJECT_CLASS objclass,nssTokenSearchType searchType,PRUint32 maximumOpt,PRStatus * statusOpt)563 nssToken_FindObjects(
564 NSSToken *token,
565 nssSession *sessionOpt,
566 CK_OBJECT_CLASS objclass,
567 nssTokenSearchType searchType,
568 PRUint32 maximumOpt,
569 PRStatus *statusOpt)
570 {
571 CK_ATTRIBUTE_PTR attr;
572 CK_ATTRIBUTE obj_template[2];
573 CK_ULONG obj_size;
574 nssCryptokiObject **objects;
575 NSS_CK_TEMPLATE_START(obj_template, attr, obj_size);
576 /* Set the search to token/session only if provided */
577 if (searchType == nssTokenSearchType_SessionOnly) {
578 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
579 } else if (searchType == nssTokenSearchType_TokenOnly ||
580 searchType == nssTokenSearchType_TokenForced) {
581 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
582 }
583 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, objclass);
584 NSS_CK_TEMPLATE_FINISH(obj_template, attr, obj_size);
585
586 if (searchType == nssTokenSearchType_TokenForced) {
587 objects = find_objects(token, sessionOpt,
588 obj_template, obj_size,
589 maximumOpt, statusOpt);
590 } else {
591 objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
592 obj_template, obj_size,
593 maximumOpt, statusOpt);
594 }
595 return objects;
596 }
597
598 NSS_IMPLEMENT nssCryptokiObject **
nssToken_FindCertificatesBySubject(NSSToken * token,nssSession * sessionOpt,NSSDER * subject,nssTokenSearchType searchType,PRUint32 maximumOpt,PRStatus * statusOpt)599 nssToken_FindCertificatesBySubject(
600 NSSToken *token,
601 nssSession *sessionOpt,
602 NSSDER *subject,
603 nssTokenSearchType searchType,
604 PRUint32 maximumOpt,
605 PRStatus *statusOpt)
606 {
607 CK_ATTRIBUTE_PTR attr;
608 CK_ATTRIBUTE subj_template[3];
609 CK_ULONG stsize;
610 nssCryptokiObject **objects;
611 NSS_CK_TEMPLATE_START(subj_template, attr, stsize);
612 /* Set the search to token/session only if provided */
613 if (searchType == nssTokenSearchType_SessionOnly) {
614 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
615 } else if (searchType == nssTokenSearchType_TokenOnly) {
616 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
617 }
618 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
619 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
620 NSS_CK_TEMPLATE_FINISH(subj_template, attr, stsize);
621 /* now locate the token certs matching this template */
622 objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
623 subj_template, stsize,
624 maximumOpt, statusOpt);
625 return objects;
626 }
627
628 NSS_IMPLEMENT nssCryptokiObject **
nssToken_FindCertificatesByNickname(NSSToken * token,nssSession * sessionOpt,const NSSUTF8 * name,nssTokenSearchType searchType,PRUint32 maximumOpt,PRStatus * statusOpt)629 nssToken_FindCertificatesByNickname(
630 NSSToken *token,
631 nssSession *sessionOpt,
632 const NSSUTF8 *name,
633 nssTokenSearchType searchType,
634 PRUint32 maximumOpt,
635 PRStatus *statusOpt)
636 {
637 CK_ATTRIBUTE_PTR attr;
638 CK_ATTRIBUTE nick_template[3];
639 CK_ULONG ntsize;
640 nssCryptokiObject **objects;
641 NSS_CK_TEMPLATE_START(nick_template, attr, ntsize);
642 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, name);
643 /* Set the search to token/session only if provided */
644 if (searchType == nssTokenSearchType_SessionOnly) {
645 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
646 } else if (searchType == nssTokenSearchType_TokenOnly) {
647 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
648 }
649 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
650 NSS_CK_TEMPLATE_FINISH(nick_template, attr, ntsize);
651 /* now locate the token certs matching this template */
652 objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
653 nick_template, ntsize,
654 maximumOpt, statusOpt);
655 if (!objects) {
656 /* This is to workaround the fact that PKCS#11 doesn't specify
657 * whether the '\0' should be included. XXX Is that still true?
658 * im - this is not needed by the current softoken. However, I'm
659 * leaving it in until I have surveyed more tokens to see if it needed.
660 * well, its needed by the builtin token...
661 */
662 nick_template[0].ulValueLen++;
663 objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
664 nick_template, ntsize,
665 maximumOpt, statusOpt);
666 }
667 return objects;
668 }
669
670 /* XXX
671 * This function *does not* use the token object cache, because not even
672 * the softoken will return a value for CKA_NSS_EMAIL from a call
673 * to GetAttributes. The softoken does allow searches with that attribute,
674 * it just won't return a value for it.
675 */
676 NSS_IMPLEMENT nssCryptokiObject **
nssToken_FindCertificatesByEmail(NSSToken * token,nssSession * sessionOpt,NSSASCII7 * email,nssTokenSearchType searchType,PRUint32 maximumOpt,PRStatus * statusOpt)677 nssToken_FindCertificatesByEmail(
678 NSSToken *token,
679 nssSession *sessionOpt,
680 NSSASCII7 *email,
681 nssTokenSearchType searchType,
682 PRUint32 maximumOpt,
683 PRStatus *statusOpt)
684 {
685 CK_ATTRIBUTE_PTR attr;
686 CK_ATTRIBUTE email_template[3];
687 CK_ULONG etsize;
688 nssCryptokiObject **objects;
689 NSS_CK_TEMPLATE_START(email_template, attr, etsize);
690 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL, email);
691 /* Set the search to token/session only if provided */
692 if (searchType == nssTokenSearchType_SessionOnly) {
693 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
694 } else if (searchType == nssTokenSearchType_TokenOnly) {
695 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
696 }
697 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
698 NSS_CK_TEMPLATE_FINISH(email_template, attr, etsize);
699 /* now locate the token certs matching this template */
700 objects = find_objects(token, sessionOpt,
701 email_template, etsize,
702 maximumOpt, statusOpt);
703 if (!objects) {
704 /* This is to workaround the fact that PKCS#11 doesn't specify
705 * whether the '\0' should be included. XXX Is that still true?
706 * im - this is not needed by the current softoken. However, I'm
707 * leaving it in until I have surveyed more tokens to see if it needed.
708 * well, its needed by the builtin token...
709 */
710 email_template[0].ulValueLen++;
711 objects = find_objects(token, sessionOpt,
712 email_template, etsize,
713 maximumOpt, statusOpt);
714 }
715 return objects;
716 }
717
718 NSS_IMPLEMENT nssCryptokiObject **
nssToken_FindCertificatesByID(NSSToken * token,nssSession * sessionOpt,NSSItem * id,nssTokenSearchType searchType,PRUint32 maximumOpt,PRStatus * statusOpt)719 nssToken_FindCertificatesByID(
720 NSSToken *token,
721 nssSession *sessionOpt,
722 NSSItem *id,
723 nssTokenSearchType searchType,
724 PRUint32 maximumOpt,
725 PRStatus *statusOpt)
726 {
727 CK_ATTRIBUTE_PTR attr;
728 CK_ATTRIBUTE id_template[3];
729 CK_ULONG idtsize;
730 nssCryptokiObject **objects;
731 NSS_CK_TEMPLATE_START(id_template, attr, idtsize);
732 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
733 /* Set the search to token/session only if provided */
734 if (searchType == nssTokenSearchType_SessionOnly) {
735 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
736 } else if (searchType == nssTokenSearchType_TokenOnly) {
737 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
738 }
739 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
740 NSS_CK_TEMPLATE_FINISH(id_template, attr, idtsize);
741 /* now locate the token certs matching this template */
742 objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
743 id_template, idtsize,
744 maximumOpt, statusOpt);
745 return objects;
746 }
747
748 /*
749 * decode the serial item and return our result.
750 * NOTE serialDecode's data is really stored in serial. Don't free it.
751 */
752 static PRStatus
nssToken_decodeSerialItem(NSSItem * serial,NSSItem * serialDecode)753 nssToken_decodeSerialItem(NSSItem *serial, NSSItem *serialDecode)
754 {
755 unsigned char *data = (unsigned char *)serial->data;
756 int data_left, data_len, index;
757
758 if ((serial->size >= 3) && (data[0] == 0x2)) {
759 /* remove the der encoding of the serial number before generating the
760 * key.. */
761 data_left = serial->size - 2;
762 data_len = data[1];
763 index = 2;
764
765 /* extended length ? (not very likely for a serial number) */
766 if (data_len & 0x80) {
767 int len_count = data_len & 0x7f;
768
769 data_len = 0;
770 data_left -= len_count;
771 if (data_left > 0) {
772 while (len_count--) {
773 data_len = (data_len << 8) | data[index++];
774 }
775 }
776 }
777 /* XXX leaving any leading zeros on the serial number for backwards
778 * compatibility
779 */
780 /* not a valid der, must be just an unlucky serial number value */
781 if (data_len == data_left) {
782 serialDecode->size = data_len;
783 serialDecode->data = &data[index];
784 return PR_SUCCESS;
785 }
786 }
787 return PR_FAILURE;
788 }
789
790 NSS_IMPLEMENT nssCryptokiObject *
nssToken_FindCertificateByIssuerAndSerialNumber(NSSToken * token,nssSession * sessionOpt,NSSDER * issuer,NSSDER * serial,nssTokenSearchType searchType,PRStatus * statusOpt)791 nssToken_FindCertificateByIssuerAndSerialNumber(
792 NSSToken *token,
793 nssSession *sessionOpt,
794 NSSDER *issuer,
795 NSSDER *serial,
796 nssTokenSearchType searchType,
797 PRStatus *statusOpt)
798 {
799 CK_ATTRIBUTE_PTR attr;
800 CK_ATTRIBUTE_PTR serialAttr;
801 CK_ATTRIBUTE cert_template[4];
802 CK_ULONG ctsize;
803 nssCryptokiObject **objects;
804 nssCryptokiObject *rvObject = NULL;
805 NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
806
807 if (!token) {
808 PORT_SetError(SEC_ERROR_NO_TOKEN);
809 if (statusOpt)
810 *statusOpt = PR_FAILURE;
811 return NULL;
812 }
813 /* Set the search to token/session only if provided */
814 if (searchType == nssTokenSearchType_SessionOnly) {
815 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
816 } else if ((searchType == nssTokenSearchType_TokenOnly) ||
817 (searchType == nssTokenSearchType_TokenForced)) {
818 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
819 }
820 /* Set the unique id */
821 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
822 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, issuer);
823 serialAttr = attr;
824 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, serial);
825 NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
826 /* get the object handle */
827 if (searchType == nssTokenSearchType_TokenForced) {
828 objects = find_objects(token, sessionOpt,
829 cert_template, ctsize,
830 1, statusOpt);
831 } else {
832 objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
833 cert_template, ctsize,
834 1, statusOpt);
835 }
836 if (objects) {
837 rvObject = objects[0];
838 nss_ZFreeIf(objects);
839 }
840
841 /*
842 * NSS used to incorrectly store serial numbers in their decoded form.
843 * because of this old tokens have decoded serial numbers.
844 */
845 if (!objects) {
846 NSSItem serialDecode;
847 PRStatus status;
848
849 status = nssToken_decodeSerialItem(serial, &serialDecode);
850 if (status != PR_SUCCESS) {
851 return NULL;
852 }
853 NSS_CK_SET_ATTRIBUTE_ITEM(serialAttr, CKA_SERIAL_NUMBER, &serialDecode);
854 if (searchType == nssTokenSearchType_TokenForced) {
855 objects = find_objects(token, sessionOpt,
856 cert_template, ctsize,
857 1, statusOpt);
858 } else {
859 objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
860 cert_template, ctsize,
861 1, statusOpt);
862 }
863 if (objects) {
864 rvObject = objects[0];
865 nss_ZFreeIf(objects);
866 }
867 }
868 return rvObject;
869 }
870
871 NSS_IMPLEMENT nssCryptokiObject *
nssToken_FindCertificateByEncodedCertificate(NSSToken * token,nssSession * sessionOpt,NSSBER * encodedCertificate,nssTokenSearchType searchType,PRStatus * statusOpt)872 nssToken_FindCertificateByEncodedCertificate(
873 NSSToken *token,
874 nssSession *sessionOpt,
875 NSSBER *encodedCertificate,
876 nssTokenSearchType searchType,
877 PRStatus *statusOpt)
878 {
879 CK_ATTRIBUTE_PTR attr;
880 CK_ATTRIBUTE cert_template[3];
881 CK_ULONG ctsize;
882 nssCryptokiObject **objects;
883 nssCryptokiObject *rvObject = NULL;
884 NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
885 /* Set the search to token/session only if provided */
886 if (searchType == nssTokenSearchType_SessionOnly) {
887 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
888 } else if (searchType == nssTokenSearchType_TokenOnly) {
889 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
890 }
891 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
892 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encodedCertificate);
893 NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
894 /* get the object handle */
895 objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
896 cert_template, ctsize,
897 1, statusOpt);
898 if (objects) {
899 rvObject = objects[0];
900 nss_ZFreeIf(objects);
901 }
902 return rvObject;
903 }
904
905 NSS_IMPLEMENT nssCryptokiObject **
nssToken_FindPrivateKeys(NSSToken * token,nssSession * sessionOpt,nssTokenSearchType searchType,PRUint32 maximumOpt,PRStatus * statusOpt)906 nssToken_FindPrivateKeys(
907 NSSToken *token,
908 nssSession *sessionOpt,
909 nssTokenSearchType searchType,
910 PRUint32 maximumOpt,
911 PRStatus *statusOpt)
912 {
913 CK_ATTRIBUTE_PTR attr;
914 CK_ATTRIBUTE key_template[2];
915 CK_ULONG ktsize;
916 nssCryptokiObject **objects;
917
918 NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
919 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
920 if (searchType == nssTokenSearchType_SessionOnly) {
921 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
922 } else if (searchType == nssTokenSearchType_TokenOnly) {
923 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
924 }
925 NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
926
927 objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
928 key_template, ktsize,
929 maximumOpt, statusOpt);
930 return objects;
931 }
932
933 /* XXX ?there are no session cert objects, so only search token objects */
934 NSS_IMPLEMENT nssCryptokiObject *
nssToken_FindPrivateKeyByID(NSSToken * token,nssSession * sessionOpt,NSSItem * keyID)935 nssToken_FindPrivateKeyByID(
936 NSSToken *token,
937 nssSession *sessionOpt,
938 NSSItem *keyID)
939 {
940 CK_ATTRIBUTE_PTR attr;
941 CK_ATTRIBUTE key_template[3];
942 CK_ULONG ktsize;
943 nssCryptokiObject **objects;
944 nssCryptokiObject *rvKey = NULL;
945
946 NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
947 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
948 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
949 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
950 NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
951
952 objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
953 key_template, ktsize,
954 1, NULL);
955 if (objects) {
956 rvKey = objects[0];
957 nss_ZFreeIf(objects);
958 }
959 return rvKey;
960 }
961
962 /* XXX ?there are no session cert objects, so only search token objects */
963 NSS_IMPLEMENT nssCryptokiObject *
nssToken_FindPublicKeyByID(NSSToken * token,nssSession * sessionOpt,NSSItem * keyID)964 nssToken_FindPublicKeyByID(
965 NSSToken *token,
966 nssSession *sessionOpt,
967 NSSItem *keyID)
968 {
969 CK_ATTRIBUTE_PTR attr;
970 CK_ATTRIBUTE key_template[3];
971 CK_ULONG ktsize;
972 nssCryptokiObject **objects;
973 nssCryptokiObject *rvKey = NULL;
974
975 NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
976 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_pubkey);
977 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
978 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
979 NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
980
981 objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
982 key_template, ktsize,
983 1, NULL);
984 if (objects) {
985 rvKey = objects[0];
986 nss_ZFreeIf(objects);
987 }
988 return rvKey;
989 }
990
991 static void
sha1_hash(NSSItem * input,NSSItem * output)992 sha1_hash(NSSItem *input, NSSItem *output)
993 {
994 NSSAlgorithmAndParameters *ap;
995 PK11SlotInfo *internal = PK11_GetInternalSlot();
996 NSSToken *token = PK11Slot_GetNSSToken(internal);
997 ap = NSSAlgorithmAndParameters_CreateSHA1Digest(NULL);
998 (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
999 PK11_FreeSlot(token->pk11slot);
1000 nss_ZFreeIf(ap);
1001 }
1002
1003 static void
md5_hash(NSSItem * input,NSSItem * output)1004 md5_hash(NSSItem *input, NSSItem *output)
1005 {
1006 NSSAlgorithmAndParameters *ap;
1007 PK11SlotInfo *internal = PK11_GetInternalSlot();
1008 NSSToken *token = PK11Slot_GetNSSToken(internal);
1009 ap = NSSAlgorithmAndParameters_CreateMD5Digest(NULL);
1010 (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
1011 PK11_FreeSlot(token->pk11slot);
1012 nss_ZFreeIf(ap);
1013 }
1014
1015 static CK_TRUST
get_ck_trust(nssTrustLevel nssTrust)1016 get_ck_trust(
1017 nssTrustLevel nssTrust)
1018 {
1019 CK_TRUST t;
1020 switch (nssTrust) {
1021 case nssTrustLevel_NotTrusted:
1022 t = CKT_NSS_NOT_TRUSTED;
1023 break;
1024 case nssTrustLevel_TrustedDelegator:
1025 t = CKT_NSS_TRUSTED_DELEGATOR;
1026 break;
1027 case nssTrustLevel_ValidDelegator:
1028 t = CKT_NSS_VALID_DELEGATOR;
1029 break;
1030 case nssTrustLevel_Trusted:
1031 t = CKT_NSS_TRUSTED;
1032 break;
1033 case nssTrustLevel_MustVerify:
1034 t = CKT_NSS_MUST_VERIFY_TRUST;
1035 break;
1036 case nssTrustLevel_Unknown:
1037 default:
1038 t = CKT_NSS_TRUST_UNKNOWN;
1039 break;
1040 }
1041 return t;
1042 }
1043
1044 NSS_IMPLEMENT nssCryptokiObject *
nssToken_ImportTrust(NSSToken * tok,nssSession * sessionOpt,NSSDER * certEncoding,NSSDER * certIssuer,NSSDER * certSerial,nssTrustLevel serverAuth,nssTrustLevel clientAuth,nssTrustLevel codeSigning,nssTrustLevel emailProtection,PRBool stepUpApproved,PRBool asTokenObject)1045 nssToken_ImportTrust(
1046 NSSToken *tok,
1047 nssSession *sessionOpt,
1048 NSSDER *certEncoding,
1049 NSSDER *certIssuer,
1050 NSSDER *certSerial,
1051 nssTrustLevel serverAuth,
1052 nssTrustLevel clientAuth,
1053 nssTrustLevel codeSigning,
1054 nssTrustLevel emailProtection,
1055 PRBool stepUpApproved,
1056 PRBool asTokenObject)
1057 {
1058 nssCryptokiObject *object;
1059 CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
1060 CK_TRUST ckSA, ckCA, ckCS, ckEP;
1061 CK_ATTRIBUTE_PTR attr;
1062 CK_ATTRIBUTE trust_tmpl[11];
1063 CK_ULONG tsize;
1064 PRUint8 sha1[20]; /* this is cheating... */
1065 PRUint8 md5[16];
1066 NSSItem sha1_result, md5_result;
1067 sha1_result.data = sha1;
1068 sha1_result.size = sizeof sha1;
1069 md5_result.data = md5;
1070 md5_result.size = sizeof md5;
1071 sha1_hash(certEncoding, &sha1_result);
1072 md5_hash(certEncoding, &md5_result);
1073 ckSA = get_ck_trust(serverAuth);
1074 ckCA = get_ck_trust(clientAuth);
1075 ckCS = get_ck_trust(codeSigning);
1076 ckEP = get_ck_trust(emailProtection);
1077 NSS_CK_TEMPLATE_START(trust_tmpl, attr, tsize);
1078 if (asTokenObject) {
1079 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1080 } else {
1081 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1082 }
1083 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, tobjc);
1084 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, certIssuer);
1085 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, certSerial);
1086 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_SHA1_HASH, &sha1_result);
1087 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_MD5_HASH, &md5_result);
1088 /* now set the trust values */
1089 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_SERVER_AUTH, ckSA);
1090 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CLIENT_AUTH, ckCA);
1091 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CODE_SIGNING, ckCS);
1092 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_EMAIL_PROTECTION, ckEP);
1093 if (stepUpApproved) {
1094 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED,
1095 &g_ck_true);
1096 } else {
1097 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED,
1098 &g_ck_false);
1099 }
1100 NSS_CK_TEMPLATE_FINISH(trust_tmpl, attr, tsize);
1101 /* import the trust object onto the token */
1102 object = import_object(tok, sessionOpt, trust_tmpl, tsize);
1103 if (object && tok->cache) {
1104 nssTokenObjectCache_ImportObject(tok->cache, object, tobjc,
1105 trust_tmpl, tsize);
1106 }
1107 return object;
1108 }
1109
1110 NSS_IMPLEMENT nssCryptokiObject *
nssToken_FindTrustForCertificate(NSSToken * token,nssSession * sessionOpt,NSSDER * certEncoding,NSSDER * certIssuer,NSSDER * certSerial,nssTokenSearchType searchType)1111 nssToken_FindTrustForCertificate(
1112 NSSToken *token,
1113 nssSession *sessionOpt,
1114 NSSDER *certEncoding,
1115 NSSDER *certIssuer,
1116 NSSDER *certSerial,
1117 nssTokenSearchType searchType)
1118 {
1119 CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
1120 CK_ATTRIBUTE_PTR attr;
1121 CK_ATTRIBUTE tobj_template[5];
1122 CK_ULONG tobj_size;
1123 nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
1124 nssCryptokiObject *object = NULL, **objects;
1125
1126 /* Don't ask the module to use an invalid session handle. */
1127 if (!session || session->handle == CK_INVALID_HANDLE) {
1128 PORT_SetError(SEC_ERROR_NO_TOKEN);
1129 return object;
1130 }
1131
1132 NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size);
1133 if (searchType == nssTokenSearchType_TokenOnly) {
1134 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1135 }
1136 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, tobjc);
1137 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, certIssuer);
1138 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, certSerial);
1139 NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size);
1140 objects = nssToken_FindObjectsByTemplate(token, session,
1141 tobj_template, tobj_size,
1142 1, NULL);
1143 if (objects) {
1144 object = objects[0];
1145 nss_ZFreeIf(objects);
1146 }
1147 return object;
1148 }
1149
1150 NSS_IMPLEMENT nssCryptokiObject *
nssToken_ImportCRL(NSSToken * token,nssSession * sessionOpt,NSSDER * subject,NSSDER * encoding,PRBool isKRL,NSSUTF8 * url,PRBool asTokenObject)1151 nssToken_ImportCRL(
1152 NSSToken *token,
1153 nssSession *sessionOpt,
1154 NSSDER *subject,
1155 NSSDER *encoding,
1156 PRBool isKRL,
1157 NSSUTF8 *url,
1158 PRBool asTokenObject)
1159 {
1160 nssCryptokiObject *object;
1161 CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
1162 CK_ATTRIBUTE_PTR attr;
1163 CK_ATTRIBUTE crl_tmpl[6];
1164 CK_ULONG crlsize;
1165
1166 NSS_CK_TEMPLATE_START(crl_tmpl, attr, crlsize);
1167 if (asTokenObject) {
1168 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1169 } else {
1170 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1171 }
1172 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, crlobjc);
1173 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
1174 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encoding);
1175 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_URL, url);
1176 if (isKRL) {
1177 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_true);
1178 } else {
1179 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_false);
1180 }
1181 NSS_CK_TEMPLATE_FINISH(crl_tmpl, attr, crlsize);
1182
1183 /* import the crl object onto the token */
1184 object = import_object(token, sessionOpt, crl_tmpl, crlsize);
1185 if (object && token->cache) {
1186 nssTokenObjectCache_ImportObject(token->cache, object, crlobjc,
1187 crl_tmpl, crlsize);
1188 }
1189 return object;
1190 }
1191
1192 NSS_IMPLEMENT nssCryptokiObject **
nssToken_FindCRLsBySubject(NSSToken * token,nssSession * sessionOpt,NSSDER * subject,nssTokenSearchType searchType,PRUint32 maximumOpt,PRStatus * statusOpt)1193 nssToken_FindCRLsBySubject(
1194 NSSToken *token,
1195 nssSession *sessionOpt,
1196 NSSDER *subject,
1197 nssTokenSearchType searchType,
1198 PRUint32 maximumOpt,
1199 PRStatus *statusOpt)
1200 {
1201 CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
1202 CK_ATTRIBUTE_PTR attr;
1203 CK_ATTRIBUTE crlobj_template[3];
1204 CK_ULONG crlobj_size;
1205 nssCryptokiObject **objects = NULL;
1206 nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
1207
1208 /* Don't ask the module to use an invalid session handle. */
1209 if (!session || session->handle == CK_INVALID_HANDLE) {
1210 PORT_SetError(SEC_ERROR_NO_TOKEN);
1211 return objects;
1212 }
1213
1214 NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size);
1215 if (searchType == nssTokenSearchType_SessionOnly) {
1216 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1217 } else if (searchType == nssTokenSearchType_TokenOnly ||
1218 searchType == nssTokenSearchType_TokenForced) {
1219 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1220 }
1221 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, crlobjc);
1222 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
1223 NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size);
1224
1225 objects = nssToken_FindObjectsByTemplate(token, session,
1226 crlobj_template, crlobj_size,
1227 maximumOpt, statusOpt);
1228 return objects;
1229 }
1230
1231 NSS_IMPLEMENT PRStatus
nssToken_GetCachedObjectAttributes(NSSToken * token,NSSArena * arenaOpt,nssCryptokiObject * object,CK_OBJECT_CLASS objclass,CK_ATTRIBUTE_PTR atemplate,CK_ULONG atlen)1232 nssToken_GetCachedObjectAttributes(
1233 NSSToken *token,
1234 NSSArena *arenaOpt,
1235 nssCryptokiObject *object,
1236 CK_OBJECT_CLASS objclass,
1237 CK_ATTRIBUTE_PTR atemplate,
1238 CK_ULONG atlen)
1239 {
1240 if (!token->cache) {
1241 return PR_FAILURE;
1242 }
1243 return nssTokenObjectCache_GetObjectAttributes(token->cache, arenaOpt,
1244 object, objclass,
1245 atemplate, atlen);
1246 }
1247
1248 NSS_IMPLEMENT NSSItem *
nssToken_Digest(NSSToken * tok,nssSession * sessionOpt,NSSAlgorithmAndParameters * ap,NSSItem * data,NSSItem * rvOpt,NSSArena * arenaOpt)1249 nssToken_Digest(
1250 NSSToken *tok,
1251 nssSession *sessionOpt,
1252 NSSAlgorithmAndParameters *ap,
1253 NSSItem *data,
1254 NSSItem *rvOpt,
1255 NSSArena *arenaOpt)
1256 {
1257 CK_RV ckrv;
1258 CK_ULONG digestLen;
1259 CK_BYTE_PTR digest;
1260 NSSItem *rvItem = NULL;
1261 void *epv = nssToken_GetCryptokiEPV(tok);
1262 nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1263
1264 /* Don't ask the module to use an invalid session handle. */
1265 if (!session || session->handle == CK_INVALID_HANDLE) {
1266 PORT_SetError(SEC_ERROR_NO_TOKEN);
1267 return rvItem;
1268 }
1269
1270 nssSession_EnterMonitor(session);
1271 ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
1272 if (ckrv != CKR_OK) {
1273 nssSession_ExitMonitor(session);
1274 return NULL;
1275 }
1276 #if 0
1277 /* XXX the standard says this should work, but it doesn't */
1278 ckrv = CKAPI(epv)->C_Digest(session->handle, NULL, 0, NULL, &digestLen);
1279 if (ckrv != CKR_OK) {
1280 nssSession_ExitMonitor(session);
1281 return NULL;
1282 }
1283 #endif
1284 digestLen = 0; /* XXX for now */
1285 digest = NULL;
1286 if (rvOpt) {
1287 if (rvOpt->size > 0 && rvOpt->size < digestLen) {
1288 nssSession_ExitMonitor(session);
1289 /* the error should be bad args */
1290 return NULL;
1291 }
1292 if (rvOpt->data) {
1293 digest = rvOpt->data;
1294 }
1295 digestLen = rvOpt->size;
1296 }
1297 if (!digest) {
1298 digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
1299 if (!digest) {
1300 nssSession_ExitMonitor(session);
1301 return NULL;
1302 }
1303 }
1304 ckrv = CKAPI(epv)->C_Digest(session->handle,
1305 (CK_BYTE_PTR)data->data,
1306 (CK_ULONG)data->size,
1307 (CK_BYTE_PTR)digest,
1308 &digestLen);
1309 nssSession_ExitMonitor(session);
1310 if (ckrv != CKR_OK) {
1311 nss_ZFreeIf(digest);
1312 return NULL;
1313 }
1314 if (!rvOpt) {
1315 rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
1316 }
1317 return rvItem;
1318 }
1319
1320 NSS_IMPLEMENT PRStatus
nssToken_BeginDigest(NSSToken * tok,nssSession * sessionOpt,NSSAlgorithmAndParameters * ap)1321 nssToken_BeginDigest(
1322 NSSToken *tok,
1323 nssSession *sessionOpt,
1324 NSSAlgorithmAndParameters *ap)
1325 {
1326 CK_RV ckrv;
1327 void *epv = nssToken_GetCryptokiEPV(tok);
1328 nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1329
1330 /* Don't ask the module to use an invalid session handle. */
1331 if (!session || session->handle == CK_INVALID_HANDLE) {
1332 PORT_SetError(SEC_ERROR_NO_TOKEN);
1333 return PR_FAILURE;
1334 }
1335
1336 nssSession_EnterMonitor(session);
1337 ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
1338 nssSession_ExitMonitor(session);
1339 return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
1340 }
1341
1342 NSS_IMPLEMENT PRStatus
nssToken_ContinueDigest(NSSToken * tok,nssSession * sessionOpt,NSSItem * item)1343 nssToken_ContinueDigest(
1344 NSSToken *tok,
1345 nssSession *sessionOpt,
1346 NSSItem *item)
1347 {
1348 CK_RV ckrv;
1349 void *epv = nssToken_GetCryptokiEPV(tok);
1350 nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1351
1352 /* Don't ask the module to use an invalid session handle. */
1353 if (!session || session->handle == CK_INVALID_HANDLE) {
1354 PORT_SetError(SEC_ERROR_NO_TOKEN);
1355 return PR_FAILURE;
1356 }
1357
1358 nssSession_EnterMonitor(session);
1359 ckrv = CKAPI(epv)->C_DigestUpdate(session->handle,
1360 (CK_BYTE_PTR)item->data,
1361 (CK_ULONG)item->size);
1362 nssSession_ExitMonitor(session);
1363 return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
1364 }
1365
1366 NSS_IMPLEMENT NSSItem *
nssToken_FinishDigest(NSSToken * tok,nssSession * sessionOpt,NSSItem * rvOpt,NSSArena * arenaOpt)1367 nssToken_FinishDigest(
1368 NSSToken *tok,
1369 nssSession *sessionOpt,
1370 NSSItem *rvOpt,
1371 NSSArena *arenaOpt)
1372 {
1373 CK_RV ckrv;
1374 CK_ULONG digestLen;
1375 CK_BYTE_PTR digest;
1376 NSSItem *rvItem = NULL;
1377 void *epv = nssToken_GetCryptokiEPV(tok);
1378 nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1379
1380 /* Don't ask the module to use an invalid session handle. */
1381 if (!session || session->handle == CK_INVALID_HANDLE) {
1382 PORT_SetError(SEC_ERROR_NO_TOKEN);
1383 return NULL;
1384 }
1385
1386 nssSession_EnterMonitor(session);
1387 ckrv = CKAPI(epv)->C_DigestFinal(session->handle, NULL, &digestLen);
1388 if (ckrv != CKR_OK || digestLen == 0) {
1389 nssSession_ExitMonitor(session);
1390 return NULL;
1391 }
1392 digest = NULL;
1393 if (rvOpt) {
1394 if (rvOpt->size > 0 && rvOpt->size < digestLen) {
1395 nssSession_ExitMonitor(session);
1396 /* the error should be bad args */
1397 return NULL;
1398 }
1399 if (rvOpt->data) {
1400 digest = rvOpt->data;
1401 }
1402 digestLen = rvOpt->size;
1403 }
1404 if (!digest) {
1405 digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
1406 if (!digest) {
1407 nssSession_ExitMonitor(session);
1408 return NULL;
1409 }
1410 }
1411 ckrv = CKAPI(epv)->C_DigestFinal(session->handle, digest, &digestLen);
1412 nssSession_ExitMonitor(session);
1413 if (ckrv != CKR_OK) {
1414 nss_ZFreeIf(digest);
1415 return NULL;
1416 }
1417 if (!rvOpt) {
1418 rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
1419 }
1420 return rvItem;
1421 }
1422
1423 NSS_IMPLEMENT PRBool
nssToken_IsPresent(NSSToken * token)1424 nssToken_IsPresent(
1425 NSSToken *token)
1426 {
1427 return nssSlot_IsTokenPresent(token->slot);
1428 }
1429
1430 /* Sigh. The methods to find objects declared above cause problems with
1431 * the low-level object cache in the softoken -- the objects are found in
1432 * toto, then one wave of GetAttributes is done, then another. Having a
1433 * large number of objects causes the cache to be thrashed, as the objects
1434 * are gone before there's any chance to ask for their attributes.
1435 * So, for now, bringing back traversal methods for certs. This way all of
1436 * the cert's attributes can be grabbed immediately after finding it,
1437 * increasing the likelihood that the cache takes care of it.
1438 */
1439 NSS_IMPLEMENT PRStatus
nssToken_TraverseCertificates(NSSToken * token,nssSession * sessionOpt,nssTokenSearchType searchType,PRStatus (* callback)(nssCryptokiObject * instance,void * arg),void * arg)1440 nssToken_TraverseCertificates(
1441 NSSToken *token,
1442 nssSession *sessionOpt,
1443 nssTokenSearchType searchType,
1444 PRStatus (*callback)(nssCryptokiObject *instance, void *arg),
1445 void *arg)
1446 {
1447 CK_RV ckrv;
1448 CK_ULONG count;
1449 CK_OBJECT_HANDLE *objectHandles;
1450 CK_ATTRIBUTE_PTR attr;
1451 CK_ATTRIBUTE cert_template[2];
1452 CK_ULONG ctsize;
1453 NSSArena *arena;
1454 PRUint32 arraySize, numHandles;
1455 nssCryptokiObject **objects;
1456 void *epv = nssToken_GetCryptokiEPV(token);
1457 nssSession *session = (sessionOpt) ? sessionOpt : token->defaultSession;
1458
1459 /* Don't ask the module to use an invalid session handle. */
1460 if (!session || session->handle == CK_INVALID_HANDLE) {
1461 PORT_SetError(SEC_ERROR_NO_TOKEN);
1462 return PR_FAILURE;
1463 }
1464
1465 /* template for all certs */
1466 NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
1467 if (searchType == nssTokenSearchType_SessionOnly) {
1468 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1469 } else if (searchType == nssTokenSearchType_TokenOnly ||
1470 searchType == nssTokenSearchType_TokenForced) {
1471 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1472 }
1473 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
1474 NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
1475
1476 /* the arena is only for the array of object handles */
1477 arena = nssArena_Create();
1478 if (!arena) {
1479 return PR_FAILURE;
1480 }
1481 arraySize = OBJECT_STACK_SIZE;
1482 numHandles = 0;
1483 objectHandles = nss_ZNEWARRAY(arena, CK_OBJECT_HANDLE, arraySize);
1484 if (!objectHandles) {
1485 goto loser;
1486 }
1487 nssSession_EnterMonitor(session); /* ==== session lock === */
1488 /* Initialize the find with the template */
1489 ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle,
1490 cert_template, ctsize);
1491 if (ckrv != CKR_OK) {
1492 nssSession_ExitMonitor(session);
1493 goto loser;
1494 }
1495 while (PR_TRUE) {
1496 /* Issue the find for up to arraySize - numHandles objects */
1497 ckrv = CKAPI(epv)->C_FindObjects(session->handle,
1498 objectHandles + numHandles,
1499 arraySize - numHandles,
1500 &count);
1501 if (ckrv != CKR_OK) {
1502 nssSession_ExitMonitor(session);
1503 goto loser;
1504 }
1505 /* bump the number of found objects */
1506 numHandles += count;
1507 if (numHandles < arraySize) {
1508 break;
1509 }
1510 /* the array is filled, double it and continue */
1511 arraySize *= 2;
1512 objectHandles = nss_ZREALLOCARRAY(objectHandles,
1513 CK_OBJECT_HANDLE,
1514 arraySize);
1515 if (!objectHandles) {
1516 nssSession_ExitMonitor(session);
1517 goto loser;
1518 }
1519 }
1520 ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
1521 nssSession_ExitMonitor(session); /* ==== end session lock === */
1522 if (ckrv != CKR_OK) {
1523 goto loser;
1524 }
1525 if (numHandles > 0) {
1526 objects = create_objects_from_handles(token, session,
1527 objectHandles, numHandles);
1528 if (objects) {
1529 nssCryptokiObject **op;
1530 for (op = objects; *op; op++) {
1531 (void)(*callback)(*op, arg);
1532 }
1533 nss_ZFreeIf(objects);
1534 }
1535 }
1536 nssArena_Destroy(arena);
1537 return PR_SUCCESS;
1538 loser:
1539 nssArena_Destroy(arena);
1540 return PR_FAILURE;
1541 }
1542
1543 NSS_IMPLEMENT PRBool
nssToken_IsPrivateKeyAvailable(NSSToken * token,NSSCertificate * c,nssCryptokiObject * instance)1544 nssToken_IsPrivateKeyAvailable(
1545 NSSToken *token,
1546 NSSCertificate *c,
1547 nssCryptokiObject *instance)
1548 {
1549 CK_OBJECT_CLASS theClass;
1550
1551 if (token == NULL)
1552 return PR_FALSE;
1553 if (c == NULL)
1554 return PR_FALSE;
1555
1556 theClass = CKO_PRIVATE_KEY;
1557 if (!nssSlot_IsLoggedIn(token->slot)) {
1558 theClass = CKO_PUBLIC_KEY;
1559 }
1560 if (PK11_MatchItem(token->pk11slot, instance->handle, theClass) !=
1561 CK_INVALID_HANDLE) {
1562 return PR_TRUE;
1563 }
1564 return PR_FALSE;
1565 }
1566