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