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