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