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