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