OLD | NEW |
| (Empty) |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
4 /* | |
5 * This file manages object type indepentent functions. | |
6 */ | |
7 #include "seccomon.h" | |
8 #include "secmod.h" | |
9 #include "secmodi.h" | |
10 #include "secmodti.h" | |
11 #include "pkcs11.h" | |
12 #include "pkcs11t.h" | |
13 #include "pk11func.h" | |
14 #include "key.h" | |
15 #include "secitem.h" | |
16 #include "secerr.h" | |
17 #include "sslerr.h" | |
18 | |
19 #define PK11_SEARCH_CHUNKSIZE 10 | |
20 | |
21 /* | |
22 * Build a block big enough to hold the data | |
23 */ | |
24 SECItem * | |
25 PK11_BlockData(SECItem *data,unsigned long size) { | |
26 SECItem *newData; | |
27 | |
28 if (size == 0u) return NULL; | |
29 | |
30 newData = (SECItem *)PORT_Alloc(sizeof(SECItem)); | |
31 if (newData == NULL) return NULL; | |
32 | |
33 newData->len = (data->len + (size-1))/size; | |
34 newData->len *= size; | |
35 | |
36 newData->data = (unsigned char *) PORT_ZAlloc(newData->len); | |
37 if (newData->data == NULL) { | |
38 PORT_Free(newData); | |
39 return NULL; | |
40 } | |
41 PORT_Memset(newData->data,newData->len-data->len,newData->len); | |
42 PORT_Memcpy(newData->data,data->data,data->len); | |
43 return newData; | |
44 } | |
45 | |
46 | |
47 SECStatus | |
48 PK11_DestroyObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object) { | |
49 CK_RV crv; | |
50 | |
51 PK11_EnterSlotMonitor(slot); | |
52 crv = PK11_GETTAB(slot)->C_DestroyObject(slot->session,object); | |
53 PK11_ExitSlotMonitor(slot); | |
54 if (crv != CKR_OK) { | |
55 return SECFailure; | |
56 } | |
57 return SECSuccess; | |
58 } | |
59 | |
60 SECStatus | |
61 PK11_DestroyTokenObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object) { | |
62 CK_RV crv; | |
63 SECStatus rv = SECSuccess; | |
64 CK_SESSION_HANDLE rwsession; | |
65 | |
66 | |
67 rwsession = PK11_GetRWSession(slot); | |
68 if (rwsession == CK_INVALID_SESSION) { | |
69 PORT_SetError(SEC_ERROR_BAD_DATA); | |
70 return SECFailure; | |
71 } | |
72 | |
73 crv = PK11_GETTAB(slot)->C_DestroyObject(rwsession,object); | |
74 if (crv != CKR_OK) { | |
75 rv = SECFailure; | |
76 PORT_SetError(PK11_MapError(crv)); | |
77 } | |
78 PK11_RestoreROSession(slot,rwsession); | |
79 return rv; | |
80 } | |
81 | |
82 /* | |
83 * Read in a single attribute into a SECItem. Allocate space for it with | |
84 * PORT_Alloc unless an arena is supplied. In the latter case use the arena | |
85 * to allocate the space. | |
86 * | |
87 * PK11_ReadAttribute sets the 'data' and 'len' fields of the SECItem but | |
88 * does not modify its 'type' field. | |
89 */ | |
90 SECStatus | |
91 PK11_ReadAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, | |
92 CK_ATTRIBUTE_TYPE type, PLArenaPool *arena, SECItem *result) { | |
93 CK_ATTRIBUTE attr = { 0, NULL, 0 }; | |
94 CK_RV crv; | |
95 | |
96 attr.type = type; | |
97 | |
98 PK11_EnterSlotMonitor(slot); | |
99 crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1); | |
100 if (crv != CKR_OK) { | |
101 PK11_ExitSlotMonitor(slot); | |
102 PORT_SetError(PK11_MapError(crv)); | |
103 return SECFailure; | |
104 } | |
105 if (arena) { | |
106 attr.pValue = PORT_ArenaAlloc(arena,attr.ulValueLen); | |
107 } else { | |
108 attr.pValue = PORT_Alloc(attr.ulValueLen); | |
109 } | |
110 if (attr.pValue == NULL) { | |
111 PK11_ExitSlotMonitor(slot); | |
112 return SECFailure; | |
113 } | |
114 crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1); | |
115 PK11_ExitSlotMonitor(slot); | |
116 if (crv != CKR_OK) { | |
117 PORT_SetError(PK11_MapError(crv)); | |
118 if (!arena) PORT_Free(attr.pValue); | |
119 return SECFailure; | |
120 } | |
121 | |
122 result->data = (unsigned char*)attr.pValue; | |
123 result->len = attr.ulValueLen; | |
124 | |
125 return SECSuccess; | |
126 } | |
127 | |
128 /* | |
129 * Read in a single attribute into As a Ulong. | |
130 */ | |
131 CK_ULONG | |
132 PK11_ReadULongAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, | |
133 CK_ATTRIBUTE_TYPE type) { | |
134 CK_ATTRIBUTE attr; | |
135 CK_ULONG value = CK_UNAVAILABLE_INFORMATION; | |
136 CK_RV crv; | |
137 | |
138 PK11_SETATTRS(&attr,type,&value,sizeof(value)); | |
139 | |
140 PK11_EnterSlotMonitor(slot); | |
141 crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1); | |
142 PK11_ExitSlotMonitor(slot); | |
143 if (crv != CKR_OK) { | |
144 PORT_SetError(PK11_MapError(crv)); | |
145 } | |
146 return value; | |
147 } | |
148 | |
149 /* | |
150 * check to see if a bool has been set. | |
151 */ | |
152 CK_BBOOL | |
153 PK11_HasAttributeSet( PK11SlotInfo *slot, CK_OBJECT_HANDLE id, | |
154 CK_ATTRIBUTE_TYPE type, PRBool haslock ) | |
155 { | |
156 CK_BBOOL ckvalue = CK_FALSE; | |
157 CK_ATTRIBUTE theTemplate; | |
158 CK_RV crv; | |
159 | |
160 /* Prepare to retrieve the attribute. */ | |
161 PK11_SETATTRS( &theTemplate, type, &ckvalue, sizeof( CK_BBOOL ) ); | |
162 | |
163 /* Retrieve attribute value. */ | |
164 if (!haslock) PK11_EnterSlotMonitor(slot); | |
165 crv = PK11_GETTAB( slot )->C_GetAttributeValue( slot->session, id, | |
166 &theTemplate, 1 ); | |
167 if (!haslock) PK11_ExitSlotMonitor(slot); | |
168 if( crv != CKR_OK ) { | |
169 PORT_SetError( PK11_MapError( crv ) ); | |
170 return CK_FALSE; | |
171 } | |
172 | |
173 return ckvalue; | |
174 } | |
175 | |
176 /* | |
177 * returns a full list of attributes. Allocate space for them. If an arena is | |
178 * provided, allocate space out of the arena. | |
179 */ | |
180 CK_RV | |
181 PK11_GetAttributes(PLArenaPool *arena,PK11SlotInfo *slot, | |
182 CK_OBJECT_HANDLE obj,CK_ATTRIBUTE *attr, int count) | |
183 { | |
184 int i; | |
185 /* make pedantic happy... note that it's only used arena != NULL */ | |
186 void *mark = NULL; | |
187 CK_RV crv; | |
188 PORT_Assert(slot->session != CK_INVALID_SESSION); | |
189 if (slot->session == CK_INVALID_SESSION) | |
190 return CKR_SESSION_HANDLE_INVALID; | |
191 | |
192 /* | |
193 * first get all the lengths of the parameters. | |
194 */ | |
195 PK11_EnterSlotMonitor(slot); | |
196 crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,obj,attr,count); | |
197 if (crv != CKR_OK) { | |
198 PK11_ExitSlotMonitor(slot); | |
199 return crv; | |
200 } | |
201 | |
202 if (arena) { | |
203 mark = PORT_ArenaMark(arena); | |
204 if (mark == NULL) return CKR_HOST_MEMORY; | |
205 } | |
206 | |
207 /* | |
208 * now allocate space to store the results. | |
209 */ | |
210 for (i=0; i < count; i++) { | |
211 if (attr[i].ulValueLen == 0) | |
212 continue; | |
213 if (arena) { | |
214 attr[i].pValue = PORT_ArenaAlloc(arena,attr[i].ulValueLen); | |
215 if (attr[i].pValue == NULL) { | |
216 /* arena failures, just release the mark */ | |
217 PORT_ArenaRelease(arena,mark); | |
218 PK11_ExitSlotMonitor(slot); | |
219 return CKR_HOST_MEMORY; | |
220 } | |
221 } else { | |
222 attr[i].pValue = PORT_Alloc(attr[i].ulValueLen); | |
223 if (attr[i].pValue == NULL) { | |
224 /* Separate malloc failures, loop to release what we have | |
225 * so far */ | |
226 int j; | |
227 for (j= 0; j < i; j++) { | |
228 PORT_Free(attr[j].pValue); | |
229 /* don't give the caller pointers to freed memory */ | |
230 attr[j].pValue = NULL; | |
231 } | |
232 PK11_ExitSlotMonitor(slot); | |
233 return CKR_HOST_MEMORY; | |
234 } | |
235 } | |
236 } | |
237 | |
238 /* | |
239 * finally get the results. | |
240 */ | |
241 crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,obj,attr,count); | |
242 PK11_ExitSlotMonitor(slot); | |
243 if (crv != CKR_OK) { | |
244 if (arena) { | |
245 PORT_ArenaRelease(arena,mark); | |
246 } else { | |
247 for (i= 0; i < count; i++) { | |
248 PORT_Free(attr[i].pValue); | |
249 /* don't give the caller pointers to freed memory */ | |
250 attr[i].pValue = NULL; | |
251 } | |
252 } | |
253 } else if (arena && mark) { | |
254 PORT_ArenaUnmark(arena,mark); | |
255 } | |
256 return crv; | |
257 } | |
258 | |
259 PRBool | |
260 PK11_IsPermObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle) | |
261 { | |
262 return (PRBool) PK11_HasAttributeSet(slot, handle, CKA_TOKEN, PR_FALSE); | |
263 } | |
264 | |
265 char * | |
266 PK11_GetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id) | |
267 { | |
268 char *nickname = NULL; | |
269 SECItem result; | |
270 SECStatus rv; | |
271 | |
272 rv = PK11_ReadAttribute(slot,id,CKA_LABEL,NULL,&result); | |
273 if (rv != SECSuccess) { | |
274 return NULL; | |
275 } | |
276 | |
277 nickname = PORT_ZAlloc(result.len+1); | |
278 if (nickname == NULL) { | |
279 PORT_Free(result.data); | |
280 return NULL; | |
281 } | |
282 PORT_Memcpy(nickname, result.data, result.len); | |
283 PORT_Free(result.data); | |
284 return nickname; | |
285 } | |
286 | |
287 SECStatus | |
288 PK11_SetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, | |
289 const char *nickname) | |
290 { | |
291 int len = PORT_Strlen(nickname); | |
292 CK_ATTRIBUTE setTemplate; | |
293 CK_RV crv; | |
294 CK_SESSION_HANDLE rwsession; | |
295 | |
296 if (len < 0) { | |
297 return SECFailure; | |
298 } | |
299 | |
300 PK11_SETATTRS(&setTemplate, CKA_LABEL, (CK_CHAR *) nickname, len); | |
301 rwsession = PK11_GetRWSession(slot); | |
302 if (rwsession == CK_INVALID_SESSION) { | |
303 PORT_SetError(SEC_ERROR_BAD_DATA); | |
304 return SECFailure; | |
305 } | |
306 crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id, | |
307 &setTemplate, 1); | |
308 PK11_RestoreROSession(slot, rwsession); | |
309 if (crv != CKR_OK) { | |
310 PORT_SetError(PK11_MapError(crv)); | |
311 return SECFailure; | |
312 } | |
313 return SECSuccess; | |
314 } | |
315 | |
316 /* | |
317 * strip leading zero's from key material | |
318 */ | |
319 void | |
320 pk11_SignedToUnsigned(CK_ATTRIBUTE *attrib) { | |
321 char *ptr = (char *)attrib->pValue; | |
322 unsigned long len = attrib->ulValueLen; | |
323 | |
324 while ((len > 1) && (*ptr == 0)) { | |
325 len--; | |
326 ptr++; | |
327 } | |
328 attrib->pValue = ptr; | |
329 attrib->ulValueLen = len; | |
330 } | |
331 | |
332 /* | |
333 * get a new session on a slot. If we run out of session, use the slot's | |
334 * 'exclusive' session. In this case owner becomes false. | |
335 */ | |
336 CK_SESSION_HANDLE | |
337 pk11_GetNewSession(PK11SlotInfo *slot,PRBool *owner) | |
338 { | |
339 CK_SESSION_HANDLE session; | |
340 *owner = PR_TRUE; | |
341 if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot); | |
342 if ( PK11_GETTAB(slot)->C_OpenSession(slot->slotID,CKF_SERIAL_SESSION, | |
343 slot,pk11_notify,&session) != CKR_OK) { | |
344 *owner = PR_FALSE; | |
345 session = slot->session; | |
346 } | |
347 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot); | |
348 | |
349 return session; | |
350 } | |
351 | |
352 void | |
353 pk11_CloseSession(PK11SlotInfo *slot,CK_SESSION_HANDLE session,PRBool owner) | |
354 { | |
355 if (!owner) return; | |
356 if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot); | |
357 (void) PK11_GETTAB(slot)->C_CloseSession(session); | |
358 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot); | |
359 } | |
360 | |
361 | |
362 SECStatus | |
363 PK11_CreateNewObject(PK11SlotInfo *slot, CK_SESSION_HANDLE session, | |
364 const CK_ATTRIBUTE *theTemplate, int count, | |
365 PRBool token, CK_OBJECT_HANDLE *objectID) | |
366 { | |
367 CK_SESSION_HANDLE rwsession; | |
368 CK_RV crv; | |
369 SECStatus rv = SECSuccess; | |
370 | |
371 rwsession = session; | |
372 if (token) { | |
373 rwsession = PK11_GetRWSession(slot); | |
374 } else if (rwsession == CK_INVALID_SESSION) { | |
375 rwsession = slot->session; | |
376 if (rwsession != CK_INVALID_SESSION) | |
377 PK11_EnterSlotMonitor(slot); | |
378 } | |
379 if (rwsession == CK_INVALID_SESSION) { | |
380 PORT_SetError(SEC_ERROR_BAD_DATA); | |
381 return SECFailure; | |
382 } | |
383 crv = PK11_GETTAB(slot)->C_CreateObject(rwsession, | |
384 /* cast away const :-( */ (CK_ATTRIBUTE_PTR)theTemplate, | |
385 count, objectID); | |
386 if(crv != CKR_OK) { | |
387 PORT_SetError( PK11_MapError(crv) ); | |
388 rv = SECFailure; | |
389 } | |
390 if (token) { | |
391 PK11_RestoreROSession(slot, rwsession); | |
392 } else if (session == CK_INVALID_SESSION) { | |
393 PK11_ExitSlotMonitor(slot); | |
394 } | |
395 | |
396 return rv; | |
397 } | |
398 | |
399 | |
400 /* This function may add a maximum of 9 attributes. */ | |
401 unsigned int | |
402 pk11_OpFlagsToAttributes(CK_FLAGS flags, CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue) | |
403 { | |
404 | |
405 const static CK_ATTRIBUTE_TYPE attrTypes[12] = { | |
406 CKA_ENCRYPT, CKA_DECRYPT, 0 /* DIGEST */, CKA_SIGN, | |
407 CKA_SIGN_RECOVER, CKA_VERIFY, CKA_VERIFY_RECOVER, 0 /* GEN */, | |
408 0 /* GEN PAIR */, CKA_WRAP, CKA_UNWRAP, CKA_DERIVE | |
409 }; | |
410 | |
411 const CK_ATTRIBUTE_TYPE *pType = attrTypes; | |
412 CK_ATTRIBUTE *attr = attrs; | |
413 CK_FLAGS test = CKF_ENCRYPT; | |
414 | |
415 | |
416 PR_ASSERT(!(flags & ~CKF_KEY_OPERATION_FLAGS)); | |
417 flags &= CKF_KEY_OPERATION_FLAGS; | |
418 | |
419 for (; flags && test <= CKF_DERIVE; test <<= 1, ++pType) { | |
420 if (test & flags) { | |
421 flags ^= test; | |
422 PR_ASSERT(*pType); | |
423 PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue); | |
424 ++attr; | |
425 } | |
426 } | |
427 return (attr - attrs); | |
428 } | |
429 | |
430 /* | |
431 * Check for conflicting flags, for example, if both PK11_ATTR_PRIVATE | |
432 * and PK11_ATTR_PUBLIC are set. | |
433 */ | |
434 PRBool | |
435 pk11_BadAttrFlags(PK11AttrFlags attrFlags) | |
436 { | |
437 PK11AttrFlags trueFlags = attrFlags & 0x55555555; | |
438 PK11AttrFlags falseFlags = (attrFlags >> 1) & 0x55555555; | |
439 return ((trueFlags & falseFlags) != 0); | |
440 } | |
441 | |
442 /* | |
443 * This function may add a maximum of 5 attributes. | |
444 * The caller must make sure the attribute flags don't have conflicts. | |
445 */ | |
446 unsigned int | |
447 pk11_AttrFlagsToAttributes(PK11AttrFlags attrFlags, CK_ATTRIBUTE *attrs, | |
448 CK_BBOOL *ckTrue, CK_BBOOL *ckFalse) | |
449 { | |
450 const static CK_ATTRIBUTE_TYPE attrTypes[5] = { | |
451 CKA_TOKEN, CKA_PRIVATE, CKA_MODIFIABLE, CKA_SENSITIVE, | |
452 CKA_EXTRACTABLE | |
453 }; | |
454 | |
455 const CK_ATTRIBUTE_TYPE *pType = attrTypes; | |
456 CK_ATTRIBUTE *attr = attrs; | |
457 PK11AttrFlags test = PK11_ATTR_TOKEN; | |
458 | |
459 PR_ASSERT(!pk11_BadAttrFlags(attrFlags)); | |
460 | |
461 /* we test two related bitflags in each iteration */ | |
462 for (; attrFlags && test <= PK11_ATTR_EXTRACTABLE; test <<= 2, ++pType) { | |
463 if (test & attrFlags) { | |
464 attrFlags ^= test; | |
465 PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue); | |
466 ++attr; | |
467 } else if ((test << 1) & attrFlags) { | |
468 attrFlags ^= (test << 1); | |
469 PK11_SETATTRS(attr, *pType, ckFalse, sizeof *ckFalse); | |
470 ++attr; | |
471 } | |
472 } | |
473 return (attr - attrs); | |
474 } | |
475 | |
476 /* | |
477 * Some non-compliant PKCS #11 vendors do not give us the modulus, so actually | |
478 * set up a signature to get the signaure length. | |
479 */ | |
480 static int | |
481 pk11_backupGetSignLength(SECKEYPrivateKey *key) | |
482 { | |
483 PK11SlotInfo *slot = key->pkcs11Slot; | |
484 CK_MECHANISM mech = {0, NULL, 0 }; | |
485 PRBool owner = PR_TRUE; | |
486 CK_SESSION_HANDLE session; | |
487 CK_ULONG len; | |
488 CK_RV crv; | |
489 unsigned char h_data[20] = { 0 }; | |
490 unsigned char buf[20]; /* obviously to small */ | |
491 CK_ULONG smallLen = sizeof(buf); | |
492 | |
493 mech.mechanism = PK11_MapSignKeyType(key->keyType); | |
494 | |
495 session = pk11_GetNewSession(slot,&owner); | |
496 if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); | |
497 crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,key->pkcs11ID); | |
498 if (crv != CKR_OK) { | |
499 if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); | |
500 pk11_CloseSession(slot,session,owner); | |
501 PORT_SetError( PK11_MapError(crv) ); | |
502 return -1; | |
503 } | |
504 len = 0; | |
505 crv = PK11_GETTAB(slot)->C_Sign(session,h_data,sizeof(h_data), | |
506 NULL, &len); | |
507 /* now call C_Sign with too small a buffer to clear the session state */ | |
508 (void) PK11_GETTAB(slot)-> | |
509 C_Sign(session,h_data,sizeof(h_data),buf,&smallLen); | |
510 | |
511 if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); | |
512 pk11_CloseSession(slot,session,owner); | |
513 if (crv != CKR_OK) { | |
514 PORT_SetError( PK11_MapError(crv) ); | |
515 return -1; | |
516 } | |
517 return len; | |
518 } | |
519 | |
520 /* | |
521 * get the length of a signature object based on the key | |
522 */ | |
523 int | |
524 PK11_SignatureLen(SECKEYPrivateKey *key) | |
525 { | |
526 int val; | |
527 SECItem attributeItem = {siBuffer, NULL, 0}; | |
528 SECStatus rv; | |
529 int length; | |
530 | |
531 switch (key->keyType) { | |
532 case rsaKey: | |
533 val = PK11_GetPrivateModulusLen(key); | |
534 if (val == -1) { | |
535 return pk11_backupGetSignLength(key); | |
536 } | |
537 return (unsigned long) val; | |
538 | |
539 case fortezzaKey: | |
540 return 40; | |
541 | |
542 case dsaKey: | |
543 rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, CKA_SUBPRIME, | |
544 NULL, &attributeItem); | |
545 if (rv == SECSuccess) { | |
546 length = attributeItem.len; | |
547 if ((length > 0) && attributeItem.data[0] == 0) { | |
548 length--; | |
549 } | |
550 PORT_Free(attributeItem.data); | |
551 return length*2; | |
552 } | |
553 return pk11_backupGetSignLength(key); | |
554 | |
555 case ecKey: | |
556 rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, CKA_EC_PARAMS, | |
557 NULL, &attributeItem); | |
558 if (rv == SECSuccess) { | |
559 length = SECKEY_ECParamsToBasePointOrderLen(&attributeItem); | |
560 PORT_Free(attributeItem.data); | |
561 if (length != 0) { | |
562 length = ((length + 7)/8) * 2; | |
563 return length; | |
564 } | |
565 } | |
566 return pk11_backupGetSignLength(key); | |
567 default: | |
568 break; | |
569 } | |
570 PORT_SetError( SEC_ERROR_INVALID_KEY ); | |
571 return 0; | |
572 } | |
573 | |
574 /* | |
575 * copy a key (or any other object) on a token | |
576 */ | |
577 CK_OBJECT_HANDLE | |
578 PK11_CopyKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE srcObject) | |
579 { | |
580 CK_OBJECT_HANDLE destObject; | |
581 CK_RV crv; | |
582 | |
583 PK11_EnterSlotMonitor(slot); | |
584 crv = PK11_GETTAB(slot)->C_CopyObject(slot->session,srcObject,NULL,0, | |
585 &destObject); | |
586 PK11_ExitSlotMonitor(slot); | |
587 if (crv == CKR_OK) return destObject; | |
588 PORT_SetError( PK11_MapError(crv) ); | |
589 return CK_INVALID_HANDLE; | |
590 } | |
591 | |
592 PRBool | |
593 pk11_FindAttrInTemplate(CK_ATTRIBUTE *attr, unsigned int numAttrs, | |
594 CK_ATTRIBUTE_TYPE target) | |
595 { | |
596 for (; numAttrs > 0; ++attr, --numAttrs) { | |
597 if (attr->type == target) | |
598 return PR_TRUE; | |
599 } | |
600 return PR_FALSE; | |
601 } | |
602 | |
603 /* | |
604 * Recover the Signed data. We need this because our old verify can't | |
605 * figure out which hash algorithm to use until we decryptted this. | |
606 */ | |
607 SECStatus | |
608 PK11_VerifyRecover(SECKEYPublicKey *key, const SECItem *sig, | |
609 SECItem *dsig, void *wincx) | |
610 { | |
611 PK11SlotInfo *slot = key->pkcs11Slot; | |
612 CK_OBJECT_HANDLE id = key->pkcs11ID; | |
613 CK_MECHANISM mech = {0, NULL, 0 }; | |
614 PRBool owner = PR_TRUE; | |
615 CK_SESSION_HANDLE session; | |
616 CK_ULONG len; | |
617 CK_RV crv; | |
618 | |
619 mech.mechanism = PK11_MapSignKeyType(key->keyType); | |
620 | |
621 if (slot == NULL) { | |
622 slot = PK11_GetBestSlotWithAttributes(mech.mechanism, | |
623 CKF_VERIFY_RECOVER,0,wincx); | |
624 if (slot == NULL) { | |
625 PORT_SetError( SEC_ERROR_NO_MODULE ); | |
626 return SECFailure; | |
627 } | |
628 id = PK11_ImportPublicKey(slot,key,PR_FALSE); | |
629 } else { | |
630 PK11_ReferenceSlot(slot); | |
631 } | |
632 | |
633 if (id == CK_INVALID_HANDLE) { | |
634 PK11_FreeSlot(slot); | |
635 PORT_SetError( SEC_ERROR_BAD_KEY ); | |
636 return SECFailure; | |
637 } | |
638 | |
639 session = pk11_GetNewSession(slot,&owner); | |
640 if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); | |
641 crv = PK11_GETTAB(slot)->C_VerifyRecoverInit(session,&mech,id); | |
642 if (crv != CKR_OK) { | |
643 if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); | |
644 pk11_CloseSession(slot,session,owner); | |
645 PORT_SetError( PK11_MapError(crv) ); | |
646 PK11_FreeSlot(slot); | |
647 return SECFailure; | |
648 } | |
649 len = dsig->len; | |
650 crv = PK11_GETTAB(slot)->C_VerifyRecover(session,sig->data, | |
651 sig->len, dsig->data, &len); | |
652 if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); | |
653 pk11_CloseSession(slot,session,owner); | |
654 dsig->len = len; | |
655 if (crv != CKR_OK) { | |
656 PORT_SetError( PK11_MapError(crv) ); | |
657 PK11_FreeSlot(slot); | |
658 return SECFailure; | |
659 } | |
660 PK11_FreeSlot(slot); | |
661 return SECSuccess; | |
662 } | |
663 | |
664 /* | |
665 * verify a signature from its hash. | |
666 */ | |
667 SECStatus | |
668 PK11_Verify(SECKEYPublicKey *key, const SECItem *sig, const SECItem *hash, | |
669 void *wincx) | |
670 { | |
671 CK_MECHANISM_TYPE mech = PK11_MapSignKeyType(key->keyType); | |
672 return PK11_VerifyWithMechanism(key, mech, NULL, sig, hash, wincx); | |
673 } | |
674 | |
675 /* | |
676 * Verify a signature from its hash using the given algorithm. | |
677 */ | |
678 SECStatus | |
679 PK11_VerifyWithMechanism(SECKEYPublicKey *key, CK_MECHANISM_TYPE mechanism, | |
680 const SECItem *param, const SECItem *sig, | |
681 const SECItem *hash, void *wincx) | |
682 { | |
683 PK11SlotInfo *slot = key->pkcs11Slot; | |
684 CK_OBJECT_HANDLE id = key->pkcs11ID; | |
685 CK_MECHANISM mech = {0, NULL, 0 }; | |
686 PRBool owner = PR_TRUE; | |
687 CK_SESSION_HANDLE session; | |
688 CK_RV crv; | |
689 | |
690 mech.mechanism = mechanism; | |
691 if (param) { | |
692 mech.pParameter = param->data; | |
693 mech.ulParameterLen = param->len; | |
694 } | |
695 | |
696 if (slot == NULL) { | |
697 unsigned int length = 0; | |
698 if ((mech.mechanism == CKM_DSA) && | |
699 /* 129 is 1024 bits translated to bytes and | |
700 * padded with an optional '0' to maintain a | |
701 * positive sign */ | |
702 (key->u.dsa.params.prime.len > 129)) { | |
703 /* we need to get a slot that not only can do DSA, but can do DSA2 | |
704 * key lengths */ | |
705 length = key->u.dsa.params.prime.len; | |
706 if (key->u.dsa.params.prime.data[0] == 0) { | |
707 length --; | |
708 } | |
709 /* convert keysize to bits for slot lookup */ | |
710 length *= 8; | |
711 } | |
712 slot = PK11_GetBestSlotWithAttributes(mech.mechanism, | |
713 CKF_VERIFY,length,wincx); | |
714 if (slot == NULL) { | |
715 PORT_SetError( SEC_ERROR_NO_MODULE ); | |
716 return SECFailure; | |
717 } | |
718 id = PK11_ImportPublicKey(slot,key,PR_FALSE); | |
719 | |
720 } else { | |
721 PK11_ReferenceSlot(slot); | |
722 } | |
723 | |
724 if (id == CK_INVALID_HANDLE) { | |
725 PK11_FreeSlot(slot); | |
726 PORT_SetError( SEC_ERROR_BAD_KEY ); | |
727 return SECFailure; | |
728 } | |
729 | |
730 session = pk11_GetNewSession(slot,&owner); | |
731 if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); | |
732 crv = PK11_GETTAB(slot)->C_VerifyInit(session,&mech,id); | |
733 if (crv != CKR_OK) { | |
734 if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); | |
735 pk11_CloseSession(slot,session,owner); | |
736 PK11_FreeSlot(slot); | |
737 PORT_SetError( PK11_MapError(crv) ); | |
738 return SECFailure; | |
739 } | |
740 crv = PK11_GETTAB(slot)->C_Verify(session,hash->data, | |
741 hash->len, sig->data, sig->len); | |
742 if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); | |
743 pk11_CloseSession(slot,session,owner); | |
744 PK11_FreeSlot(slot); | |
745 if (crv != CKR_OK) { | |
746 PORT_SetError( PK11_MapError(crv) ); | |
747 return SECFailure; | |
748 } | |
749 return SECSuccess; | |
750 } | |
751 | |
752 /* | |
753 * sign a hash. The algorithm is determined by the key. | |
754 */ | |
755 SECStatus | |
756 PK11_Sign(SECKEYPrivateKey *key, SECItem *sig, const SECItem *hash) | |
757 { | |
758 CK_MECHANISM_TYPE mech = PK11_MapSignKeyType(key->keyType); | |
759 return PK11_SignWithMechanism(key, mech, NULL, sig, hash); | |
760 } | |
761 | |
762 /* | |
763 * Sign a hash using the given algorithm. | |
764 */ | |
765 SECStatus | |
766 PK11_SignWithMechanism(SECKEYPrivateKey *key, CK_MECHANISM_TYPE mechanism, | |
767 const SECItem *param, SECItem *sig, const SECItem *hash) | |
768 { | |
769 PK11SlotInfo *slot = key->pkcs11Slot; | |
770 CK_MECHANISM mech = {0, NULL, 0 }; | |
771 PRBool owner = PR_TRUE; | |
772 CK_SESSION_HANDLE session; | |
773 PRBool haslock = PR_FALSE; | |
774 CK_ULONG len; | |
775 CK_RV crv; | |
776 | |
777 mech.mechanism = mechanism; | |
778 if (param) { | |
779 mech.pParameter = param->data; | |
780 mech.ulParameterLen = param->len; | |
781 } | |
782 | |
783 if (SECKEY_HAS_ATTRIBUTE_SET(key,CKA_PRIVATE)) { | |
784 PK11_HandlePasswordCheck(slot, key->wincx); | |
785 } | |
786 | |
787 session = pk11_GetNewSession(slot,&owner); | |
788 haslock = (!owner || !(slot->isThreadSafe)); | |
789 if (haslock) PK11_EnterSlotMonitor(slot); | |
790 crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,key->pkcs11ID); | |
791 if (crv != CKR_OK) { | |
792 if (haslock) PK11_ExitSlotMonitor(slot); | |
793 pk11_CloseSession(slot,session,owner); | |
794 PORT_SetError( PK11_MapError(crv) ); | |
795 return SECFailure; | |
796 } | |
797 | |
798 /* PKCS11 2.20 says if CKA_ALWAYS_AUTHENTICATE then | |
799 * do C_Login with CKU_CONTEXT_SPECIFIC | |
800 * between C_SignInit and C_Sign */ | |
801 if (SECKEY_HAS_ATTRIBUTE_SET_LOCK(key, CKA_ALWAYS_AUTHENTICATE, haslock)) { | |
802 PK11_DoPassword(slot, session, PR_FALSE, key->wincx, haslock, PR_TRUE); | |
803 } | |
804 | |
805 len = sig->len; | |
806 crv = PK11_GETTAB(slot)->C_Sign(session,hash->data, | |
807 hash->len, sig->data, &len); | |
808 if (haslock) PK11_ExitSlotMonitor(slot); | |
809 pk11_CloseSession(slot,session,owner); | |
810 sig->len = len; | |
811 if (crv != CKR_OK) { | |
812 PORT_SetError( PK11_MapError(crv) ); | |
813 return SECFailure; | |
814 } | |
815 return SECSuccess; | |
816 } | |
817 | |
818 /* | |
819 * sign data with a MAC key. | |
820 */ | |
821 SECStatus | |
822 PK11_SignWithSymKey(PK11SymKey *symKey, CK_MECHANISM_TYPE mechanism, | |
823 SECItem *param, SECItem *sig, const SECItem *data) | |
824 { | |
825 PK11SlotInfo *slot = symKey->slot; | |
826 CK_MECHANISM mech = {0, NULL, 0 }; | |
827 PRBool owner = PR_TRUE; | |
828 CK_SESSION_HANDLE session; | |
829 PRBool haslock = PR_FALSE; | |
830 CK_ULONG len; | |
831 CK_RV crv; | |
832 | |
833 mech.mechanism = mechanism; | |
834 if (param) { | |
835 mech.pParameter = param->data; | |
836 mech.ulParameterLen = param->len; | |
837 } | |
838 | |
839 session = pk11_GetNewSession(slot,&owner); | |
840 haslock = (!owner || !(slot->isThreadSafe)); | |
841 if (haslock) PK11_EnterSlotMonitor(slot); | |
842 crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,symKey->objectID); | |
843 if (crv != CKR_OK) { | |
844 if (haslock) PK11_ExitSlotMonitor(slot); | |
845 pk11_CloseSession(slot,session,owner); | |
846 PORT_SetError( PK11_MapError(crv) ); | |
847 return SECFailure; | |
848 } | |
849 | |
850 len = sig->len; | |
851 crv = PK11_GETTAB(slot)->C_Sign(session,data->data, | |
852 data->len, sig->data, &len); | |
853 if (haslock) PK11_ExitSlotMonitor(slot); | |
854 pk11_CloseSession(slot,session,owner); | |
855 sig->len = len; | |
856 if (crv != CKR_OK) { | |
857 PORT_SetError( PK11_MapError(crv) ); | |
858 return SECFailure; | |
859 } | |
860 return SECSuccess; | |
861 } | |
862 | |
863 SECStatus | |
864 PK11_Decrypt(PK11SymKey *symKey, | |
865 CK_MECHANISM_TYPE mechanism, SECItem *param, | |
866 unsigned char *out, unsigned int *outLen, | |
867 unsigned int maxLen, | |
868 const unsigned char *enc, unsigned encLen) | |
869 { | |
870 PK11SlotInfo *slot = symKey->slot; | |
871 CK_MECHANISM mech = {0, NULL, 0 }; | |
872 CK_ULONG len = maxLen; | |
873 PRBool owner = PR_TRUE; | |
874 CK_SESSION_HANDLE session; | |
875 PRBool haslock = PR_FALSE; | |
876 CK_RV crv; | |
877 | |
878 mech.mechanism = mechanism; | |
879 if (param) { | |
880 mech.pParameter = param->data; | |
881 mech.ulParameterLen = param->len; | |
882 } | |
883 | |
884 session = pk11_GetNewSession(slot, &owner); | |
885 haslock = (!owner || !slot->isThreadSafe); | |
886 if (haslock) PK11_EnterSlotMonitor(slot); | |
887 crv = PK11_GETTAB(slot)->C_DecryptInit(session, &mech, symKey->objectID); | |
888 if (crv != CKR_OK) { | |
889 if (haslock) PK11_ExitSlotMonitor(slot); | |
890 pk11_CloseSession(slot, session, owner); | |
891 PORT_SetError( PK11_MapError(crv) ); | |
892 return SECFailure; | |
893 } | |
894 | |
895 crv = PK11_GETTAB(slot)->C_Decrypt(session, (unsigned char *)enc, encLen, | |
896 out, &len); | |
897 if (haslock) PK11_ExitSlotMonitor(slot); | |
898 pk11_CloseSession(slot, session, owner); | |
899 *outLen = len; | |
900 if (crv != CKR_OK) { | |
901 PORT_SetError( PK11_MapError(crv) ); | |
902 return SECFailure; | |
903 } | |
904 return SECSuccess; | |
905 } | |
906 | |
907 SECStatus | |
908 PK11_Encrypt(PK11SymKey *symKey, | |
909 CK_MECHANISM_TYPE mechanism, SECItem *param, | |
910 unsigned char *out, unsigned int *outLen, | |
911 unsigned int maxLen, | |
912 const unsigned char *data, unsigned int dataLen) | |
913 { | |
914 PK11SlotInfo *slot = symKey->slot; | |
915 CK_MECHANISM mech = {0, NULL, 0 }; | |
916 CK_ULONG len = maxLen; | |
917 PRBool owner = PR_TRUE; | |
918 CK_SESSION_HANDLE session; | |
919 PRBool haslock = PR_FALSE; | |
920 CK_RV crv; | |
921 | |
922 mech.mechanism = mechanism; | |
923 if (param) { | |
924 mech.pParameter = param->data; | |
925 mech.ulParameterLen = param->len; | |
926 } | |
927 | |
928 session = pk11_GetNewSession(slot, &owner); | |
929 haslock = (!owner || !slot->isThreadSafe); | |
930 if (haslock) PK11_EnterSlotMonitor(slot); | |
931 crv = PK11_GETTAB(slot)->C_EncryptInit(session, &mech, symKey->objectID); | |
932 if (crv != CKR_OK) { | |
933 if (haslock) PK11_ExitSlotMonitor(slot); | |
934 pk11_CloseSession(slot,session,owner); | |
935 PORT_SetError( PK11_MapError(crv) ); | |
936 return SECFailure; | |
937 } | |
938 crv = PK11_GETTAB(slot)->C_Encrypt(session, (unsigned char *)data, | |
939 dataLen, out, &len); | |
940 if (haslock) PK11_ExitSlotMonitor(slot); | |
941 pk11_CloseSession(slot,session,owner); | |
942 *outLen = len; | |
943 if (crv != CKR_OK) { | |
944 PORT_SetError( PK11_MapError(crv) ); | |
945 return SECFailure; | |
946 } | |
947 return SECSuccess; | |
948 } | |
949 | |
950 static SECStatus | |
951 pk11_PrivDecryptRaw(SECKEYPrivateKey *key, | |
952 unsigned char *data, unsigned *outLen, unsigned int maxLen, | |
953 const unsigned char *enc, unsigned encLen, | |
954 CK_MECHANISM_PTR mech) | |
955 { | |
956 PK11SlotInfo *slot = key->pkcs11Slot; | |
957 CK_ULONG out = maxLen; | |
958 PRBool owner = PR_TRUE; | |
959 CK_SESSION_HANDLE session; | |
960 PRBool haslock = PR_FALSE; | |
961 CK_RV crv; | |
962 | |
963 if (key->keyType != rsaKey) { | |
964 PORT_SetError( SEC_ERROR_INVALID_KEY ); | |
965 return SECFailure; | |
966 } | |
967 | |
968 /* Why do we do a PK11_handle check here? for simple | |
969 * decryption? .. because the user may have asked for 'ask always' | |
970 * and this is a private key operation. In practice, thought, it's mute | |
971 * since only servers wind up using this function */ | |
972 if (SECKEY_HAS_ATTRIBUTE_SET(key,CKA_PRIVATE)) { | |
973 PK11_HandlePasswordCheck(slot, key->wincx); | |
974 } | |
975 session = pk11_GetNewSession(slot,&owner); | |
976 haslock = (!owner || !(slot->isThreadSafe)); | |
977 if (haslock) PK11_EnterSlotMonitor(slot); | |
978 crv = PK11_GETTAB(slot)->C_DecryptInit(session, mech, key->pkcs11ID); | |
979 if (crv != CKR_OK) { | |
980 if (haslock) PK11_ExitSlotMonitor(slot); | |
981 pk11_CloseSession(slot,session,owner); | |
982 PORT_SetError( PK11_MapError(crv) ); | |
983 return SECFailure; | |
984 } | |
985 | |
986 /* PKCS11 2.20 says if CKA_ALWAYS_AUTHENTICATE then | |
987 * do C_Login with CKU_CONTEXT_SPECIFIC | |
988 * between C_DecryptInit and C_Decrypt | |
989 * ... But see note above about servers */ | |
990 if (SECKEY_HAS_ATTRIBUTE_SET_LOCK(key, CKA_ALWAYS_AUTHENTICATE, haslock)) { | |
991 PK11_DoPassword(slot, session, PR_FALSE, key->wincx, haslock, PR_TRUE); | |
992 } | |
993 | |
994 crv = PK11_GETTAB(slot)->C_Decrypt(session, (unsigned char *)enc, encLen, | |
995 data, &out); | |
996 if (haslock) PK11_ExitSlotMonitor(slot); | |
997 pk11_CloseSession(slot,session,owner); | |
998 *outLen = out; | |
999 if (crv != CKR_OK) { | |
1000 PORT_SetError( PK11_MapError(crv) ); | |
1001 return SECFailure; | |
1002 } | |
1003 return SECSuccess; | |
1004 } | |
1005 | |
1006 SECStatus | |
1007 PK11_PubDecryptRaw(SECKEYPrivateKey *key, | |
1008 unsigned char *data, unsigned *outLen, unsigned int maxLen, | |
1009 const unsigned char *enc, unsigned encLen) | |
1010 { | |
1011 CK_MECHANISM mech = {CKM_RSA_X_509, NULL, 0 }; | |
1012 return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech); | |
1013 } | |
1014 | |
1015 SECStatus | |
1016 PK11_PrivDecryptPKCS1(SECKEYPrivateKey *key, | |
1017 unsigned char *data, unsigned *outLen, unsigned int maxLen
, | |
1018 const unsigned char *enc, unsigned encLen) | |
1019 { | |
1020 CK_MECHANISM mech = {CKM_RSA_PKCS, NULL, 0 }; | |
1021 return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech); | |
1022 } | |
1023 | |
1024 static SECStatus | |
1025 pk11_PubEncryptRaw(SECKEYPublicKey *key, | |
1026 unsigned char *out, unsigned int *outLen, | |
1027 unsigned int maxLen, | |
1028 const unsigned char *data, unsigned dataLen, | |
1029 CK_MECHANISM_PTR mech, void *wincx) | |
1030 { | |
1031 PK11SlotInfo *slot; | |
1032 CK_OBJECT_HANDLE id; | |
1033 CK_ULONG len = maxLen; | |
1034 PRBool owner = PR_TRUE; | |
1035 CK_SESSION_HANDLE session; | |
1036 CK_RV crv; | |
1037 | |
1038 slot = PK11_GetBestSlotWithAttributes(mech->mechanism,CKF_ENCRYPT,0,wincx); | |
1039 if (slot == NULL) { | |
1040 PORT_SetError( SEC_ERROR_NO_MODULE ); | |
1041 return SECFailure; | |
1042 } | |
1043 | |
1044 id = PK11_ImportPublicKey(slot,key,PR_FALSE); | |
1045 | |
1046 if (id == CK_INVALID_HANDLE) { | |
1047 PK11_FreeSlot(slot); | |
1048 PORT_SetError( SEC_ERROR_BAD_KEY ); | |
1049 return SECFailure; | |
1050 } | |
1051 | |
1052 session = pk11_GetNewSession(slot,&owner); | |
1053 if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); | |
1054 crv = PK11_GETTAB(slot)->C_EncryptInit(session, mech, id); | |
1055 if (crv != CKR_OK) { | |
1056 if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); | |
1057 pk11_CloseSession(slot,session,owner); | |
1058 PK11_FreeSlot(slot); | |
1059 PORT_SetError( PK11_MapError(crv) ); | |
1060 return SECFailure; | |
1061 } | |
1062 crv = PK11_GETTAB(slot)->C_Encrypt(session,(unsigned char *)data,dataLen, | |
1063 out,&len); | |
1064 if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); | |
1065 pk11_CloseSession(slot,session,owner); | |
1066 PK11_FreeSlot(slot); | |
1067 *outLen = len; | |
1068 if (crv != CKR_OK) { | |
1069 PORT_SetError( PK11_MapError(crv) ); | |
1070 return SECFailure; | |
1071 } | |
1072 return SECSuccess; | |
1073 } | |
1074 | |
1075 SECStatus | |
1076 PK11_PubEncryptRaw(SECKEYPublicKey *key, | |
1077 unsigned char *enc, | |
1078 const unsigned char *data, unsigned dataLen, | |
1079 void *wincx) | |
1080 { | |
1081 CK_MECHANISM mech = {CKM_RSA_X_509, NULL, 0 }; | |
1082 unsigned int outLen; | |
1083 if (!key || key->keyType != rsaKey) { | |
1084 PORT_SetError(SEC_ERROR_BAD_KEY); | |
1085 return SECFailure; | |
1086 } | |
1087 outLen = SECKEY_PublicKeyStrength(key); | |
1088 return pk11_PubEncryptRaw(key, enc, &outLen, outLen, data, dataLen, &mech, | |
1089 wincx); | |
1090 } | |
1091 | |
1092 SECStatus | |
1093 PK11_PubEncryptPKCS1(SECKEYPublicKey *key, | |
1094 unsigned char *enc, | |
1095 const unsigned char *data, unsigned dataLen, | |
1096 void *wincx) | |
1097 { | |
1098 CK_MECHANISM mech = {CKM_RSA_PKCS, NULL, 0 }; | |
1099 unsigned int outLen; | |
1100 if (!key || key->keyType != rsaKey) { | |
1101 PORT_SetError(SEC_ERROR_BAD_KEY); | |
1102 return SECFailure; | |
1103 } | |
1104 outLen = SECKEY_PublicKeyStrength(key); | |
1105 return pk11_PubEncryptRaw(key, enc, &outLen, outLen, data, dataLen, &mech, | |
1106 wincx); | |
1107 } | |
1108 | |
1109 SECStatus | |
1110 PK11_PrivDecrypt(SECKEYPrivateKey *key, | |
1111 CK_MECHANISM_TYPE mechanism, SECItem *param, | |
1112 unsigned char *out, unsigned int *outLen, | |
1113 unsigned int maxLen, | |
1114 const unsigned char *enc, unsigned encLen) | |
1115 { | |
1116 CK_MECHANISM mech = { mechanism, NULL, 0 }; | |
1117 if (param) { | |
1118 mech.pParameter = param->data; | |
1119 mech.ulParameterLen = param->len; | |
1120 } | |
1121 return pk11_PrivDecryptRaw(key, out, outLen, maxLen, enc, encLen, &mech); | |
1122 } | |
1123 | |
1124 SECStatus | |
1125 PK11_PubEncrypt(SECKEYPublicKey *key, | |
1126 CK_MECHANISM_TYPE mechanism, SECItem *param, | |
1127 unsigned char *out, unsigned int *outLen, | |
1128 unsigned int maxLen, | |
1129 const unsigned char *data, unsigned dataLen, | |
1130 void *wincx) | |
1131 { | |
1132 CK_MECHANISM mech = { mechanism, NULL, 0 }; | |
1133 if (param) { | |
1134 mech.pParameter = param->data; | |
1135 mech.ulParameterLen = param->len; | |
1136 } | |
1137 return pk11_PubEncryptRaw(key, out, outLen, maxLen, data, dataLen, &mech, | |
1138 wincx); | |
1139 } | |
1140 | |
1141 SECKEYPrivateKey * | |
1142 PK11_UnwrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey, | |
1143 CK_MECHANISM_TYPE wrapType, SECItem *param, | |
1144 SECItem *wrappedKey, SECItem *label, | |
1145 SECItem *idValue, PRBool perm, PRBool sensitive, | |
1146 CK_KEY_TYPE keyType, CK_ATTRIBUTE_TYPE *usage, | |
1147 int usageCount, void *wincx) | |
1148 { | |
1149 CK_BBOOL cktrue = CK_TRUE; | |
1150 CK_BBOOL ckfalse = CK_FALSE; | |
1151 CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; | |
1152 CK_ATTRIBUTE keyTemplate[15] ; | |
1153 int templateCount = 0; | |
1154 CK_OBJECT_HANDLE privKeyID; | |
1155 CK_MECHANISM mechanism; | |
1156 CK_ATTRIBUTE *attrs = keyTemplate; | |
1157 SECItem *param_free = NULL, *ck_id = NULL; | |
1158 CK_RV crv; | |
1159 CK_SESSION_HANDLE rwsession; | |
1160 PK11SymKey *newKey = NULL; | |
1161 int i; | |
1162 | |
1163 if(!slot || !wrappedKey || !idValue) { | |
1164 /* SET AN ERROR!!! */ | |
1165 return NULL; | |
1166 } | |
1167 | |
1168 ck_id = PK11_MakeIDFromPubKey(idValue); | |
1169 if(!ck_id) { | |
1170 return NULL; | |
1171 } | |
1172 | |
1173 PK11_SETATTRS(attrs, CKA_TOKEN, perm ? &cktrue : &ckfalse, | |
1174 sizeof(cktrue)); attrs++; | |
1175 PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass)); attrs++; | |
1176 PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); attrs++; | |
1177 PK11_SETATTRS(attrs, CKA_PRIVATE, sensitive ? &cktrue : &ckfalse, | |
1178 sizeof(cktrue)); attrs++; | |
1179 PK11_SETATTRS(attrs, CKA_SENSITIVE, sensitive ? &cktrue : &ckfalse, | |
1180 sizeof(cktrue)); attrs++; | |
1181 if (label && label->data) { | |
1182 PK11_SETATTRS(attrs, CKA_LABEL, label->data, label->len); attrs++; | |
1183 } | |
1184 PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len); attrs++; | |
1185 for (i=0; i < usageCount; i++) { | |
1186 PK11_SETATTRS(attrs, usage[i], &cktrue, sizeof(cktrue)); attrs++; | |
1187 } | |
1188 | |
1189 if (PK11_IsInternal(slot)) { | |
1190 PK11_SETATTRS(attrs, CKA_NETSCAPE_DB, idValue->data, | |
1191 idValue->len); attrs++; | |
1192 } | |
1193 | |
1194 templateCount = attrs - keyTemplate; | |
1195 PR_ASSERT(templateCount <= (sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE)) ); | |
1196 | |
1197 mechanism.mechanism = wrapType; | |
1198 if(!param) param = param_free= PK11_ParamFromIV(wrapType, NULL); | |
1199 if(param) { | |
1200 mechanism.pParameter = param->data; | |
1201 mechanism.ulParameterLen = param->len; | |
1202 } else { | |
1203 mechanism.pParameter = NULL; | |
1204 mechanism.ulParameterLen = 0; | |
1205 } | |
1206 | |
1207 if (wrappingKey->slot != slot) { | |
1208 newKey = pk11_CopyToSlot(slot,wrapType,CKA_UNWRAP,wrappingKey); | |
1209 } else { | |
1210 newKey = PK11_ReferenceSymKey(wrappingKey); | |
1211 } | |
1212 | |
1213 if (newKey) { | |
1214 if (perm) { | |
1215 /* Get RW Session will either lock the monitor if necessary, | |
1216 * or return a thread safe session handle, or fail. */ | |
1217 rwsession = PK11_GetRWSession(slot); | |
1218 } else { | |
1219 rwsession = slot->session; | |
1220 if (rwsession != CK_INVALID_SESSION) | |
1221 PK11_EnterSlotMonitor(slot); | |
1222 } | |
1223 /* This is a lot a work to deal with fussy PKCS #11 modules | |
1224 * that can't bother to return BAD_DATA when presented with an | |
1225 * invalid session! */ | |
1226 if (rwsession == CK_INVALID_SESSION) { | |
1227 PORT_SetError(SEC_ERROR_BAD_DATA); | |
1228 goto loser; | |
1229 } | |
1230 crv = PK11_GETTAB(slot)->C_UnwrapKey(rwsession, &mechanism, | |
1231 newKey->objectID, | |
1232 wrappedKey->data, | |
1233 wrappedKey->len, keyTemplate, | |
1234 templateCount, &privKeyID); | |
1235 | |
1236 if (perm) { | |
1237 PK11_RestoreROSession(slot, rwsession); | |
1238 } else { | |
1239 PK11_ExitSlotMonitor(slot); | |
1240 } | |
1241 PK11_FreeSymKey(newKey); | |
1242 newKey = NULL; | |
1243 } else { | |
1244 crv = CKR_FUNCTION_NOT_SUPPORTED; | |
1245 } | |
1246 | |
1247 if (ck_id) { | |
1248 SECITEM_FreeItem(ck_id, PR_TRUE); | |
1249 ck_id = NULL; | |
1250 } | |
1251 | |
1252 if (crv != CKR_OK) { | |
1253 /* we couldn't unwrap the key, use the internal module to do the | |
1254 * unwrap, then load the new key into the token */ | |
1255 PK11SlotInfo *int_slot = PK11_GetInternalSlot(); | |
1256 | |
1257 if (int_slot && (slot != int_slot)) { | |
1258 SECKEYPrivateKey *privKey = PK11_UnwrapPrivKey(int_slot, | |
1259 wrappingKey, wrapType, param, wrappedKey, label, | |
1260 idValue, PR_FALSE, PR_FALSE, | |
1261 keyType, usage, usageCount, wincx); | |
1262 if (privKey) { | |
1263 SECKEYPrivateKey *newPrivKey = PK11_LoadPrivKey(slot,privKey, | |
1264 NULL,perm,sensitive); | |
1265 SECKEY_DestroyPrivateKey(privKey); | |
1266 PK11_FreeSlot(int_slot); | |
1267 return newPrivKey; | |
1268 } | |
1269 } | |
1270 if (int_slot) PK11_FreeSlot(int_slot); | |
1271 PORT_SetError( PK11_MapError(crv) ); | |
1272 return NULL; | |
1273 } | |
1274 return PK11_MakePrivKey(slot, nullKey, PR_FALSE, privKeyID, wincx); | |
1275 | |
1276 loser: | |
1277 if (newKey) { | |
1278 PK11_FreeSymKey(newKey); | |
1279 } | |
1280 if (ck_id) { | |
1281 SECITEM_FreeItem(ck_id, PR_TRUE); | |
1282 } | |
1283 return NULL; | |
1284 } | |
1285 | |
1286 /* | |
1287 * Now we're going to wrap a SECKEYPrivateKey with a PK11SymKey | |
1288 * The strategy is to get both keys to reside in the same slot, | |
1289 * one that can perform the desired crypto mechanism and then | |
1290 * call C_WrapKey after all the setup has taken place. | |
1291 */ | |
1292 SECStatus | |
1293 PK11_WrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey, | |
1294 SECKEYPrivateKey *privKey, CK_MECHANISM_TYPE wrapType, | |
1295 SECItem *param, SECItem *wrappedKey, void *wincx) | |
1296 { | |
1297 PK11SlotInfo *privSlot = privKey->pkcs11Slot; /* The slot where | |
1298 * the private key | |
1299 * we are going to | |
1300 * wrap lives. | |
1301 */ | |
1302 PK11SymKey *newSymKey = NULL; | |
1303 SECKEYPrivateKey *newPrivKey = NULL; | |
1304 SECItem *param_free = NULL; | |
1305 CK_ULONG len = wrappedKey->len; | |
1306 CK_MECHANISM mech; | |
1307 CK_RV crv; | |
1308 | |
1309 if (!privSlot || !PK11_DoesMechanism(privSlot, wrapType)) { | |
1310 /* Figure out a slot that does the mechanism and try to import | |
1311 * the private key onto that slot. | |
1312 */ | |
1313 PK11SlotInfo *int_slot = PK11_GetInternalSlot(); | |
1314 | |
1315 privSlot = int_slot; /* The private key has a new home */ | |
1316 newPrivKey = PK11_LoadPrivKey(privSlot,privKey,NULL,PR_FALSE,PR_FALSE); | |
1317 /* newPrivKey has allocated its own reference to the slot, so it's | |
1318 * safe until we destroy newPrivkey. | |
1319 */ | |
1320 PK11_FreeSlot(int_slot); | |
1321 if (newPrivKey == NULL) { | |
1322 return SECFailure; | |
1323 } | |
1324 privKey = newPrivKey; | |
1325 } | |
1326 | |
1327 if (privSlot != wrappingKey->slot) { | |
1328 newSymKey = pk11_CopyToSlot (privSlot, wrapType, CKA_WRAP, | |
1329 wrappingKey); | |
1330 wrappingKey = newSymKey; | |
1331 } | |
1332 | |
1333 if (wrappingKey == NULL) { | |
1334 if (newPrivKey) { | |
1335 SECKEY_DestroyPrivateKey(newPrivKey); | |
1336 } | |
1337 return SECFailure; | |
1338 } | |
1339 mech.mechanism = wrapType; | |
1340 if (!param) { | |
1341 param = param_free = PK11_ParamFromIV(wrapType, NULL); | |
1342 } | |
1343 if (param) { | |
1344 mech.pParameter = param->data; | |
1345 mech.ulParameterLen = param->len; | |
1346 } else { | |
1347 mech.pParameter = NULL; | |
1348 mech.ulParameterLen = 0; | |
1349 } | |
1350 | |
1351 PK11_EnterSlotMonitor(privSlot); | |
1352 crv = PK11_GETTAB(privSlot)->C_WrapKey(privSlot->session, &mech, | |
1353 wrappingKey->objectID, | |
1354 privKey->pkcs11ID, | |
1355 wrappedKey->data, &len); | |
1356 PK11_ExitSlotMonitor(privSlot); | |
1357 | |
1358 if (newSymKey) { | |
1359 PK11_FreeSymKey(newSymKey); | |
1360 } | |
1361 if (newPrivKey) { | |
1362 SECKEY_DestroyPrivateKey(newPrivKey); | |
1363 } | |
1364 if (param_free) { | |
1365 SECITEM_FreeItem(param_free,PR_TRUE); | |
1366 } | |
1367 | |
1368 if (crv != CKR_OK) { | |
1369 PORT_SetError( PK11_MapError(crv) ); | |
1370 return SECFailure; | |
1371 } | |
1372 | |
1373 wrappedKey->len = len; | |
1374 return SECSuccess; | |
1375 } | |
1376 | |
1377 #if 0 | |
1378 /* | |
1379 * Sample code relating to linked list returned by PK11_FindGenericObjects | |
1380 */ | |
1381 | |
1382 /* | |
1383 * You can walk the list with the following code: | |
1384 */ | |
1385 firstObj = PK11_FindGenericObjects(slot, objClass); | |
1386 for (thisObj=firstObj; | |
1387 thisObj; | |
1388 thisObj=PK11_GetNextGenericObject(thisObj)) { | |
1389 /* operate on thisObj */ | |
1390 } | |
1391 /* | |
1392 * If you want a particular object from the list... | |
1393 */ | |
1394 firstObj = PK11_FindGenericObjects(slot, objClass); | |
1395 for (thisObj=firstObj; | |
1396 thisObj; | |
1397 thisObj=PK11_GetNextGenericObject(thisObj)) { | |
1398 if (isMyObj(thisObj)) { | |
1399 if ( thisObj == firstObj) { | |
1400 /* NOTE: firstObj could be NULL at this point */ | |
1401 firstObj = PK11_GetNextGenericObject(thsObj); | |
1402 } | |
1403 PK11_UnlinkGenericObject(thisObj); | |
1404 myObj = thisObj; | |
1405 break; | |
1406 } | |
1407 } | |
1408 | |
1409 PK11_DestroyGenericObjects(firstObj); | |
1410 | |
1411 /* use myObj */ | |
1412 | |
1413 PK11_DestroyGenericObject(myObj); | |
1414 #endif /* sample code */ | |
1415 | |
1416 /* | |
1417 * return a linked, non-circular list of generic objects. | |
1418 * If you are only interested | |
1419 * in one object, just use the first object in the list. To find the | |
1420 * rest of the list use PK11_GetNextGenericObject() to return the next object. | |
1421 */ | |
1422 PK11GenericObject * | |
1423 PK11_FindGenericObjects(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass) | |
1424 { | |
1425 CK_ATTRIBUTE template[1]; | |
1426 CK_ATTRIBUTE *attrs = template; | |
1427 CK_OBJECT_HANDLE *objectIDs = NULL; | |
1428 PK11GenericObject *lastObj = NULL, *obj; | |
1429 PK11GenericObject *firstObj = NULL; | |
1430 int i, count = 0; | |
1431 | |
1432 | |
1433 PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass)); attrs++; | |
1434 | |
1435 objectIDs = pk11_FindObjectsByTemplate(slot,template,1,&count); | |
1436 if (objectIDs == NULL) { | |
1437 return NULL; | |
1438 } | |
1439 | |
1440 /* where we connect our object once we've created it.. */ | |
1441 for (i=0; i < count; i++) { | |
1442 obj = PORT_New(PK11GenericObject); | |
1443 if ( !obj ) { | |
1444 if (firstObj) { | |
1445 PK11_DestroyGenericObjects(firstObj); | |
1446 } | |
1447 PORT_Free(objectIDs); | |
1448 return NULL; | |
1449 } | |
1450 /* initialize it */ | |
1451 obj->slot = PK11_ReferenceSlot(slot); | |
1452 obj->objectID = objectIDs[i]; | |
1453 obj->next = NULL; | |
1454 obj->prev = NULL; | |
1455 | |
1456 /* link it in */ | |
1457 if (firstObj == NULL) { | |
1458 firstObj = obj; | |
1459 } else { | |
1460 PK11_LinkGenericObject(lastObj, obj); | |
1461 } | |
1462 lastObj = obj; | |
1463 } | |
1464 PORT_Free(objectIDs); | |
1465 return firstObj; | |
1466 } | |
1467 | |
1468 /* | |
1469 * get the Next Object in the list. | |
1470 */ | |
1471 PK11GenericObject * | |
1472 PK11_GetNextGenericObject(PK11GenericObject *object) | |
1473 { | |
1474 return object->next; | |
1475 } | |
1476 | |
1477 PK11GenericObject * | |
1478 PK11_GetPrevGenericObject(PK11GenericObject *object) | |
1479 { | |
1480 return object->prev; | |
1481 } | |
1482 | |
1483 /* | |
1484 * Link a single object into a new list. | |
1485 * if the object is already in another list, remove it first. | |
1486 */ | |
1487 SECStatus | |
1488 PK11_LinkGenericObject(PK11GenericObject *list, PK11GenericObject *object) | |
1489 { | |
1490 PK11_UnlinkGenericObject(object); | |
1491 object->prev = list; | |
1492 object->next = list->next; | |
1493 list->next = object; | |
1494 if (object->next != NULL) { | |
1495 object->next->prev = object; | |
1496 } | |
1497 return SECSuccess; | |
1498 } | |
1499 | |
1500 /* | |
1501 * remove an object from the list. If the object isn't already in | |
1502 * a list unlink becomes a noop. | |
1503 */ | |
1504 SECStatus | |
1505 PK11_UnlinkGenericObject(PK11GenericObject *object) | |
1506 { | |
1507 if (object->prev != NULL) { | |
1508 object->prev->next = object->next; | |
1509 } | |
1510 if (object->next != NULL) { | |
1511 object->next->prev = object->prev; | |
1512 } | |
1513 | |
1514 object->next = NULL; | |
1515 object->prev = NULL; | |
1516 return SECSuccess; | |
1517 } | |
1518 | |
1519 /* | |
1520 * This function removes a single object from the list and destroys it. | |
1521 * For an already unlinked object there is no difference between | |
1522 * PK11_DestroyGenericObject and PK11_DestroyGenericObjects | |
1523 */ | |
1524 SECStatus | |
1525 PK11_DestroyGenericObject(PK11GenericObject *object) | |
1526 { | |
1527 if (object == NULL) { | |
1528 return SECSuccess; | |
1529 } | |
1530 | |
1531 PK11_UnlinkGenericObject(object); | |
1532 if (object->slot) { | |
1533 PK11_FreeSlot(object->slot); | |
1534 } | |
1535 PORT_Free(object); | |
1536 return SECSuccess; | |
1537 } | |
1538 | |
1539 /* | |
1540 * walk down a link list of generic objects destroying them. | |
1541 * This will destroy all objects in a list that the object is linked into. | |
1542 * (the list is traversed in both directions). | |
1543 */ | |
1544 SECStatus | |
1545 PK11_DestroyGenericObjects(PK11GenericObject *objects) | |
1546 { | |
1547 PK11GenericObject *nextObject; | |
1548 PK11GenericObject *prevObject; | |
1549 | |
1550 if (objects == NULL) { | |
1551 return SECSuccess; | |
1552 } | |
1553 | |
1554 nextObject = objects->next; | |
1555 prevObject = objects->prev; | |
1556 | |
1557 /* delete all the objects after it in the list */ | |
1558 for (; objects; objects = nextObject) { | |
1559 nextObject = objects->next; | |
1560 PK11_DestroyGenericObject(objects); | |
1561 } | |
1562 /* delete all the objects before it in the list */ | |
1563 for (objects = prevObject; objects; objects = prevObject) { | |
1564 prevObject = objects->prev; | |
1565 PK11_DestroyGenericObject(objects); | |
1566 } | |
1567 return SECSuccess; | |
1568 } | |
1569 | |
1570 | |
1571 /* | |
1572 * Hand Create a new object and return the Generic object for our new object. | |
1573 */ | |
1574 PK11GenericObject * | |
1575 PK11_CreateGenericObject(PK11SlotInfo *slot, const CK_ATTRIBUTE *pTemplate, | |
1576 int count, PRBool token) | |
1577 { | |
1578 CK_OBJECT_HANDLE objectID; | |
1579 PK11GenericObject *obj; | |
1580 CK_RV crv; | |
1581 | |
1582 PK11_EnterSlotMonitor(slot); | |
1583 crv = PK11_CreateNewObject(slot, slot->session, pTemplate, count, | |
1584 token, &objectID); | |
1585 PK11_ExitSlotMonitor(slot); | |
1586 if (crv != CKR_OK) { | |
1587 PORT_SetError(PK11_MapError(crv)); | |
1588 return NULL; | |
1589 } | |
1590 | |
1591 obj = PORT_New(PK11GenericObject); | |
1592 if ( !obj ) { | |
1593 /* error set by PORT_New */ | |
1594 return NULL; | |
1595 } | |
1596 | |
1597 /* initialize it */ | |
1598 obj->slot = PK11_ReferenceSlot(slot); | |
1599 obj->objectID = objectID; | |
1600 obj->next = NULL; | |
1601 obj->prev = NULL; | |
1602 return obj; | |
1603 } | |
1604 | |
1605 /* | |
1606 * Change an attribute on a raw object | |
1607 */ | |
1608 SECStatus | |
1609 PK11_WriteRawAttribute(PK11ObjectType objType, void *objSpec, | |
1610 CK_ATTRIBUTE_TYPE attrType, SECItem *item) | |
1611 { | |
1612 PK11SlotInfo *slot = NULL; | |
1613 CK_OBJECT_HANDLE handle = 0; | |
1614 CK_ATTRIBUTE setTemplate; | |
1615 CK_RV crv; | |
1616 CK_SESSION_HANDLE rwsession; | |
1617 | |
1618 switch (objType) { | |
1619 case PK11_TypeGeneric: | |
1620 slot = ((PK11GenericObject *)objSpec)->slot; | |
1621 handle = ((PK11GenericObject *)objSpec)->objectID; | |
1622 break; | |
1623 case PK11_TypePrivKey: | |
1624 slot = ((SECKEYPrivateKey *)objSpec)->pkcs11Slot; | |
1625 handle = ((SECKEYPrivateKey *)objSpec)->pkcs11ID; | |
1626 break; | |
1627 case PK11_TypePubKey: | |
1628 slot = ((SECKEYPublicKey *)objSpec)->pkcs11Slot; | |
1629 handle = ((SECKEYPublicKey *)objSpec)->pkcs11ID; | |
1630 break; | |
1631 case PK11_TypeSymKey: | |
1632 slot = ((PK11SymKey *)objSpec)->slot; | |
1633 handle = ((PK11SymKey *)objSpec)->objectID; | |
1634 break; | |
1635 case PK11_TypeCert: /* don't handle cert case for now */ | |
1636 default: | |
1637 break; | |
1638 } | |
1639 if (slot == NULL) { | |
1640 PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE); | |
1641 return SECFailure; | |
1642 } | |
1643 | |
1644 PK11_SETATTRS(&setTemplate, attrType, (CK_CHAR *) item->data, item->len); | |
1645 rwsession = PK11_GetRWSession(slot); | |
1646 if (rwsession == CK_INVALID_SESSION) { | |
1647 PORT_SetError(SEC_ERROR_BAD_DATA); | |
1648 return SECFailure; | |
1649 } | |
1650 crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, handle, | |
1651 &setTemplate, 1); | |
1652 PK11_RestoreROSession(slot, rwsession); | |
1653 if (crv != CKR_OK) { | |
1654 PORT_SetError(PK11_MapError(crv)); | |
1655 return SECFailure; | |
1656 } | |
1657 return SECSuccess; | |
1658 } | |
1659 | |
1660 | |
1661 SECStatus | |
1662 PK11_ReadRawAttribute(PK11ObjectType objType, void *objSpec, | |
1663 CK_ATTRIBUTE_TYPE attrType, SECItem *item) | |
1664 { | |
1665 PK11SlotInfo *slot = NULL; | |
1666 CK_OBJECT_HANDLE handle = 0; | |
1667 | |
1668 switch (objType) { | |
1669 case PK11_TypeGeneric: | |
1670 slot = ((PK11GenericObject *)objSpec)->slot; | |
1671 handle = ((PK11GenericObject *)objSpec)->objectID; | |
1672 break; | |
1673 case PK11_TypePrivKey: | |
1674 slot = ((SECKEYPrivateKey *)objSpec)->pkcs11Slot; | |
1675 handle = ((SECKEYPrivateKey *)objSpec)->pkcs11ID; | |
1676 break; | |
1677 case PK11_TypePubKey: | |
1678 slot = ((SECKEYPublicKey *)objSpec)->pkcs11Slot; | |
1679 handle = ((SECKEYPublicKey *)objSpec)->pkcs11ID; | |
1680 break; | |
1681 case PK11_TypeSymKey: | |
1682 slot = ((PK11SymKey *)objSpec)->slot; | |
1683 handle = ((PK11SymKey *)objSpec)->objectID; | |
1684 break; | |
1685 case PK11_TypeCert: /* don't handle cert case for now */ | |
1686 default: | |
1687 break; | |
1688 } | |
1689 if (slot == NULL) { | |
1690 PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE); | |
1691 return SECFailure; | |
1692 } | |
1693 | |
1694 return PK11_ReadAttribute(slot, handle, attrType, NULL, item); | |
1695 } | |
1696 | |
1697 | |
1698 /* | |
1699 * return the object handle that matches the template | |
1700 */ | |
1701 CK_OBJECT_HANDLE | |
1702 pk11_FindObjectByTemplate(PK11SlotInfo *slot,CK_ATTRIBUTE *theTemplate,int tsize
) | |
1703 { | |
1704 CK_OBJECT_HANDLE object; | |
1705 CK_RV crv = CKR_SESSION_HANDLE_INVALID; | |
1706 CK_ULONG objectCount; | |
1707 | |
1708 /* | |
1709 * issue the find | |
1710 */ | |
1711 PK11_EnterSlotMonitor(slot); | |
1712 if (slot->session != CK_INVALID_SESSION) { | |
1713 crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, | |
1714 theTemplate, tsize); | |
1715 } | |
1716 if (crv != CKR_OK) { | |
1717 PK11_ExitSlotMonitor(slot); | |
1718 PORT_SetError( PK11_MapError(crv) ); | |
1719 return CK_INVALID_HANDLE; | |
1720 } | |
1721 | |
1722 crv=PK11_GETTAB(slot)->C_FindObjects(slot->session,&object,1,&objectCount); | |
1723 PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); | |
1724 PK11_ExitSlotMonitor(slot); | |
1725 if ((crv != CKR_OK) || (objectCount < 1)) { | |
1726 /* shouldn't use SSL_ERROR... here */ | |
1727 PORT_SetError( crv != CKR_OK ? PK11_MapError(crv) : | |
1728 SSL_ERROR_NO_CERTIFICATE); | |
1729 return CK_INVALID_HANDLE; | |
1730 } | |
1731 | |
1732 /* blow up if the PKCS #11 module returns us and invalid object handle */ | |
1733 PORT_Assert(object != CK_INVALID_HANDLE); | |
1734 return object; | |
1735 } | |
1736 | |
1737 /* | |
1738 * return all the object handles that matches the template | |
1739 */ | |
1740 CK_OBJECT_HANDLE * | |
1741 pk11_FindObjectsByTemplate(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate, | |
1742 int templCount, int *object_count) | |
1743 { | |
1744 CK_OBJECT_HANDLE *objID = NULL; | |
1745 CK_ULONG returned_count = 0; | |
1746 CK_RV crv = CKR_SESSION_HANDLE_INVALID; | |
1747 | |
1748 PK11_EnterSlotMonitor(slot); | |
1749 if (slot->session != CK_INVALID_SESSION) { | |
1750 crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, | |
1751 findTemplate, templCount); | |
1752 } | |
1753 if (crv != CKR_OK) { | |
1754 PK11_ExitSlotMonitor(slot); | |
1755 PORT_SetError( PK11_MapError(crv) ); | |
1756 *object_count = -1; | |
1757 return NULL; | |
1758 } | |
1759 | |
1760 | |
1761 /* | |
1762 * collect all the Matching Objects | |
1763 */ | |
1764 do { | |
1765 CK_OBJECT_HANDLE *oldObjID = objID; | |
1766 | |
1767 if (objID == NULL) { | |
1768 objID = (CK_OBJECT_HANDLE *) PORT_Alloc(sizeof(CK_OBJECT_HANDLE)* | |
1769 (*object_count+ PK11_SEARCH_CHUNKSIZE)); | |
1770 } else { | |
1771 objID = (CK_OBJECT_HANDLE *) PORT_Realloc(objID, | |
1772 sizeof(CK_OBJECT_HANDLE)*(*object_count+PK11_SEARCH_CHUNKSIZE)); | |
1773 } | |
1774 | |
1775 if (objID == NULL) { | |
1776 if (oldObjID) PORT_Free(oldObjID); | |
1777 break; | |
1778 } | |
1779 crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, | |
1780 &objID[*object_count],PK11_SEARCH_CHUNKSIZE,&returned_count); | |
1781 if (crv != CKR_OK) { | |
1782 PORT_SetError( PK11_MapError(crv) ); | |
1783 PORT_Free(objID); | |
1784 objID = NULL; | |
1785 break; | |
1786 } | |
1787 *object_count += returned_count; | |
1788 } while (returned_count == PK11_SEARCH_CHUNKSIZE); | |
1789 | |
1790 PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); | |
1791 PK11_ExitSlotMonitor(slot); | |
1792 | |
1793 if (objID && (*object_count == 0)) { | |
1794 PORT_Free(objID); | |
1795 return NULL; | |
1796 } | |
1797 if (objID == NULL) *object_count = -1; | |
1798 return objID; | |
1799 } | |
1800 /* | |
1801 * given a PKCS #11 object, match it's peer based on the KeyID. searchID | |
1802 * is typically a privateKey or a certificate while the peer is the opposite | |
1803 */ | |
1804 CK_OBJECT_HANDLE | |
1805 PK11_MatchItem(PK11SlotInfo *slot, CK_OBJECT_HANDLE searchID, | |
1806 CK_OBJECT_CLASS matchclass) | |
1807 { | |
1808 CK_ATTRIBUTE theTemplate[] = { | |
1809 { CKA_ID, NULL, 0 }, | |
1810 { CKA_CLASS, NULL, 0 } | |
1811 }; | |
1812 /* if you change the array, change the variable below as well */ | |
1813 CK_ATTRIBUTE *keyclass = &theTemplate[1]; | |
1814 int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); | |
1815 /* if you change the array, change the variable below as well */ | |
1816 CK_OBJECT_HANDLE peerID; | |
1817 PLArenaPool *arena; | |
1818 CK_RV crv; | |
1819 | |
1820 /* now we need to create space for the public key */ | |
1821 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); | |
1822 if (arena == NULL) return CK_INVALID_HANDLE; | |
1823 | |
1824 crv = PK11_GetAttributes(arena,slot,searchID,theTemplate,tsize); | |
1825 if (crv != CKR_OK) { | |
1826 PORT_FreeArena(arena,PR_FALSE); | |
1827 PORT_SetError( PK11_MapError(crv) ); | |
1828 return CK_INVALID_HANDLE; | |
1829 } | |
1830 | |
1831 if ((theTemplate[0].ulValueLen == 0) || (theTemplate[0].ulValueLen == -1)) { | |
1832 PORT_FreeArena(arena,PR_FALSE); | |
1833 if (matchclass == CKO_CERTIFICATE) | |
1834 PORT_SetError(SEC_ERROR_BAD_KEY); | |
1835 else | |
1836 PORT_SetError(SEC_ERROR_NO_KEY); | |
1837 return CK_INVALID_HANDLE; | |
1838 } | |
1839 | |
1840 | |
1841 | |
1842 /* | |
1843 * issue the find | |
1844 */ | |
1845 *(CK_OBJECT_CLASS *)(keyclass->pValue) = matchclass; | |
1846 | |
1847 peerID = pk11_FindObjectByTemplate(slot,theTemplate,tsize); | |
1848 PORT_FreeArena(arena,PR_FALSE); | |
1849 | |
1850 return peerID; | |
1851 } | |
1852 | |
1853 /* | |
1854 * count the number of objects that match the template. | |
1855 */ | |
1856 int | |
1857 PK11_NumberObjectsFor(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate, | |
1858 int templCount) | |
1859 { | |
1860 CK_OBJECT_HANDLE objID[PK11_SEARCH_CHUNKSIZE]; | |
1861 int object_count = 0; | |
1862 CK_ULONG returned_count = 0; | |
1863 CK_RV crv = CKR_SESSION_HANDLE_INVALID; | |
1864 | |
1865 PK11_EnterSlotMonitor(slot); | |
1866 if (slot->session != CK_INVALID_SESSION) { | |
1867 crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, | |
1868 findTemplate, templCount); | |
1869 } | |
1870 if (crv != CKR_OK) { | |
1871 PK11_ExitSlotMonitor(slot); | |
1872 PORT_SetError( PK11_MapError(crv) ); | |
1873 return object_count; | |
1874 } | |
1875 | |
1876 /* | |
1877 * collect all the Matching Objects | |
1878 */ | |
1879 do { | |
1880 crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, objID, | |
1881 PK11_SEARCH_CHUNKSIZE, | |
1882 &returned_count); | |
1883 if (crv != CKR_OK) { | |
1884 PORT_SetError( PK11_MapError(crv) ); | |
1885 break; | |
1886 } | |
1887 object_count += returned_count; | |
1888 } while (returned_count == PK11_SEARCH_CHUNKSIZE); | |
1889 | |
1890 PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); | |
1891 PK11_ExitSlotMonitor(slot); | |
1892 return object_count; | |
1893 } | |
1894 | |
1895 /* | |
1896 * Traverse all the objects in a given slot. | |
1897 */ | |
1898 SECStatus | |
1899 PK11_TraverseSlot(PK11SlotInfo *slot, void *arg) | |
1900 { | |
1901 int i; | |
1902 CK_OBJECT_HANDLE *objID = NULL; | |
1903 int object_count = 0; | |
1904 pk11TraverseSlot *slotcb = (pk11TraverseSlot*) arg; | |
1905 | |
1906 objID = pk11_FindObjectsByTemplate(slot,slotcb->findTemplate, | |
1907 slotcb->templateCount,&object_count); | |
1908 | |
1909 /*Actually this isn't a failure... there just were no objs to be found*/ | |
1910 if (object_count == 0) { | |
1911 return SECSuccess; | |
1912 } | |
1913 | |
1914 if (objID == NULL) { | |
1915 return SECFailure; | |
1916 } | |
1917 | |
1918 for (i=0; i < object_count; i++) { | |
1919 (*slotcb->callback)(slot,objID[i],slotcb->callbackArg); | |
1920 } | |
1921 PORT_Free(objID); | |
1922 return SECSuccess; | |
1923 } | |
1924 | |
1925 /* | |
1926 * Traverse all the objects in all slots. | |
1927 */ | |
1928 SECStatus | |
1929 pk11_TraverseAllSlots( SECStatus (*callback)(PK11SlotInfo *,void *), | |
1930 void *arg, PRBool forceLogin, void *wincx) { | |
1931 PK11SlotList *list; | |
1932 PK11SlotListElement *le; | |
1933 SECStatus rv; | |
1934 | |
1935 /* get them all! */ | |
1936 list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,wincx); | |
1937 if (list == NULL) return SECFailure; | |
1938 | |
1939 /* look at each slot and authenticate as necessary */ | |
1940 for (le = list->head ; le; le = le->next) { | |
1941 if (forceLogin) { | |
1942 rv = pk11_AuthenticateUnfriendly(le->slot, PR_FALSE, wincx); | |
1943 if (rv != SECSuccess) { | |
1944 continue; | |
1945 } | |
1946 } | |
1947 if (callback) { | |
1948 (*callback)(le->slot,arg); | |
1949 } | |
1950 } | |
1951 | |
1952 PK11_FreeSlotList(list); | |
1953 | |
1954 return SECSuccess; | |
1955 } | |
1956 | |
1957 CK_OBJECT_HANDLE * | |
1958 PK11_FindObjectsFromNickname(char *nickname,PK11SlotInfo **slotptr, | |
1959 CK_OBJECT_CLASS objclass, int *returnCount, void *wincx) | |
1960 { | |
1961 char *tokenName; | |
1962 char *delimit; | |
1963 PK11SlotInfo *slot; | |
1964 CK_OBJECT_HANDLE *objID; | |
1965 CK_ATTRIBUTE findTemplate[] = { | |
1966 { CKA_LABEL, NULL, 0}, | |
1967 { CKA_CLASS, NULL, 0}, | |
1968 }; | |
1969 int findCount = sizeof(findTemplate)/sizeof(findTemplate[0]); | |
1970 SECStatus rv; | |
1971 PK11_SETATTRS(&findTemplate[1], CKA_CLASS, &objclass, sizeof(objclass)); | |
1972 | |
1973 *slotptr = slot = NULL; | |
1974 *returnCount = 0; | |
1975 /* first find the slot associated with this nickname */ | |
1976 if ((delimit = PORT_Strchr(nickname,':')) != NULL) { | |
1977 int len = delimit - nickname; | |
1978 tokenName = (char*)PORT_Alloc(len+1); | |
1979 PORT_Memcpy(tokenName,nickname,len); | |
1980 tokenName[len] = 0; | |
1981 | |
1982 slot = *slotptr = PK11_FindSlotByName(tokenName); | |
1983 PORT_Free(tokenName); | |
1984 /* if we couldn't find a slot, assume the nickname is an internal cert | |
1985 * with no proceding slot name */ | |
1986 if (slot == NULL) { | |
1987 slot = *slotptr = PK11_GetInternalKeySlot(); | |
1988 } else { | |
1989 nickname = delimit+1; | |
1990 } | |
1991 } else { | |
1992 *slotptr = slot = PK11_GetInternalKeySlot(); | |
1993 } | |
1994 if (slot == NULL) { | |
1995 return CK_INVALID_HANDLE; | |
1996 } | |
1997 | |
1998 rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx); | |
1999 if (rv != SECSuccess) { | |
2000 PK11_FreeSlot(slot); | |
2001 *slotptr = NULL; | |
2002 return CK_INVALID_HANDLE; | |
2003 } | |
2004 | |
2005 findTemplate[0].pValue = nickname; | |
2006 findTemplate[0].ulValueLen = PORT_Strlen(nickname); | |
2007 objID = pk11_FindObjectsByTemplate(slot,findTemplate,findCount,returnCount); | |
2008 if (objID == NULL) { | |
2009 /* PKCS #11 isn't clear on whether or not the NULL is | |
2010 * stored in the template.... try the find again with the | |
2011 * full null terminated string. */ | |
2012 findTemplate[0].ulValueLen += 1; | |
2013 objID = pk11_FindObjectsByTemplate(slot,findTemplate,findCount, | |
2014 returnCount); | |
2015 if (objID == NULL) { | |
2016 /* Well that's the best we can do. It's just not here */ | |
2017 /* what about faked nicknames? */ | |
2018 PK11_FreeSlot(slot); | |
2019 *slotptr = NULL; | |
2020 *returnCount = 0; | |
2021 } | |
2022 } | |
2023 | |
2024 return objID; | |
2025 } | |
2026 | |
2027 SECItem * | |
2028 pk11_GetLowLevelKeyFromHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle) | |
2029 { | |
2030 CK_ATTRIBUTE theTemplate[] = { | |
2031 { CKA_ID, NULL, 0 }, | |
2032 }; | |
2033 int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); | |
2034 CK_RV crv; | |
2035 SECItem *item; | |
2036 | |
2037 item = SECITEM_AllocItem(NULL, NULL, 0); | |
2038 | |
2039 if (item == NULL) { | |
2040 return NULL; | |
2041 } | |
2042 | |
2043 crv = PK11_GetAttributes(NULL,slot,handle,theTemplate,tsize); | |
2044 if (crv != CKR_OK) { | |
2045 SECITEM_FreeItem(item,PR_TRUE); | |
2046 PORT_SetError( PK11_MapError(crv) ); | |
2047 return NULL; | |
2048 } | |
2049 | |
2050 item->data = (unsigned char*) theTemplate[0].pValue; | |
2051 item->len =theTemplate[0].ulValueLen; | |
2052 | |
2053 return item; | |
2054 } | |
2055 | |
OLD | NEW |