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 PK11Contexts which are  used in multipart hashing,
6  * encryption/decryption, and signing/verication operations.
7  */
8 
9 #include "seccomon.h"
10 #include "secmod.h"
11 #include "nssilock.h"
12 #include "secmodi.h"
13 #include "secmodti.h"
14 #include "pkcs11.h"
15 #include "pk11func.h"
16 #include "secitem.h"
17 #include "secoid.h"
18 #include "sechash.h"
19 #include "secerr.h"
20 
21 static const SECItem pk11_null_params = { 0 };
22 
23 /**********************************************************************
24  *
25  *                   Now Deal with Crypto Contexts
26  *
27  **********************************************************************/
28 
29 /*
30  * the monitors...
31  */
32 void
PK11_EnterContextMonitor(PK11Context * cx)33 PK11_EnterContextMonitor(PK11Context *cx)
34 {
35     /* if we own the session and our slot is ThreadSafe, only monitor
36      * the Context */
37     if ((cx->ownSession) && (cx->slot->isThreadSafe)) {
38         /* Should this use monitors instead? */
39         PZ_Lock(cx->sessionLock);
40     } else {
41         PK11_EnterSlotMonitor(cx->slot);
42     }
43 }
44 
45 void
PK11_ExitContextMonitor(PK11Context * cx)46 PK11_ExitContextMonitor(PK11Context *cx)
47 {
48     /* if we own the session and our slot is ThreadSafe, only monitor
49      * the Context */
50     if ((cx->ownSession) && (cx->slot->isThreadSafe)) {
51         /* Should this use monitors instead? */
52         PZ_Unlock(cx->sessionLock);
53     } else {
54         PK11_ExitSlotMonitor(cx->slot);
55     }
56 }
57 
58 /*
59  * Free up a Cipher Context
60  */
61 void
PK11_DestroyContext(PK11Context * context,PRBool freeit)62 PK11_DestroyContext(PK11Context *context, PRBool freeit)
63 {
64     pk11_CloseSession(context->slot, context->session, context->ownSession);
65     /* initialize the critical fields of the context */
66     if (context->savedData != NULL)
67         PORT_Free(context->savedData);
68     if (context->key)
69         PK11_FreeSymKey(context->key);
70     if (context->param && context->param != &pk11_null_params)
71         SECITEM_FreeItem(context->param, PR_TRUE);
72     if (context->sessionLock)
73         PZ_DestroyLock(context->sessionLock);
74     PK11_FreeSlot(context->slot);
75     if (freeit)
76         PORT_Free(context);
77 }
78 
79 /*
80  * save the current context. Allocate Space if necessary.
81  */
82 static unsigned char *
pk11_saveContextHelper(PK11Context * context,unsigned char * buffer,unsigned long * savedLength)83 pk11_saveContextHelper(PK11Context *context, unsigned char *buffer,
84                        unsigned long *savedLength)
85 {
86     CK_RV crv;
87 
88     /* If buffer is NULL, this will get the length */
89     crv = PK11_GETTAB(context->slot)->C_GetOperationState(context->session, (CK_BYTE_PTR)buffer, savedLength);
90     if (!buffer || (crv == CKR_BUFFER_TOO_SMALL)) {
91         /* the given buffer wasn't big enough (or was NULL), but we
92          * have the length, so try again with a new buffer and the
93          * correct length
94          */
95         unsigned long bufLen = *savedLength;
96         buffer = PORT_Alloc(bufLen);
97         if (buffer == NULL) {
98             return (unsigned char *)NULL;
99         }
100         crv = PK11_GETTAB(context->slot)->C_GetOperationState(context->session, (CK_BYTE_PTR)buffer, savedLength);
101         if (crv != CKR_OK) {
102             PORT_ZFree(buffer, bufLen);
103         }
104     }
105     if (crv != CKR_OK) {
106         PORT_SetError(PK11_MapError(crv));
107         return (unsigned char *)NULL;
108     }
109     return buffer;
110 }
111 
112 void *
pk11_saveContext(PK11Context * context,void * space,unsigned long * savedLength)113 pk11_saveContext(PK11Context *context, void *space, unsigned long *savedLength)
114 {
115     return pk11_saveContextHelper(context,
116                                   (unsigned char *)space, savedLength);
117 }
118 
119 /*
120  * restore the current context
121  */
122 SECStatus
pk11_restoreContext(PK11Context * context,void * space,unsigned long savedLength)123 pk11_restoreContext(PK11Context *context, void *space, unsigned long savedLength)
124 {
125     CK_RV crv;
126     CK_OBJECT_HANDLE objectID = (context->key) ? context->key->objectID : CK_INVALID_HANDLE;
127 
128     PORT_Assert(space != NULL);
129     if (space == NULL) {
130         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
131         return SECFailure;
132     }
133     crv = PK11_GETTAB(context->slot)->C_SetOperationState(context->session, (CK_BYTE_PTR)space, savedLength, objectID, 0);
134     if (crv != CKR_OK) {
135         PORT_SetError(PK11_MapError(crv));
136         return SECFailure;
137     }
138     return SECSuccess;
139 }
140 
141 SECStatus pk11_Finalize(PK11Context *context);
142 
143 /*
144  * Context initialization. Used by all flavors of CreateContext
145  */
146 static SECStatus
pk11_context_init(PK11Context * context,CK_MECHANISM * mech_info)147 pk11_context_init(PK11Context *context, CK_MECHANISM *mech_info)
148 {
149     CK_RV crv;
150     PK11SymKey *symKey = context->key;
151     SECStatus rv = SECSuccess;
152 
153     switch (context->operation) {
154         case CKA_ENCRYPT:
155             crv = PK11_GETTAB(context->slot)->C_EncryptInit(context->session, mech_info, symKey->objectID);
156             break;
157         case CKA_DECRYPT:
158             if (context->fortezzaHack) {
159                 CK_ULONG count = 0;
160                 /* generate the IV for fortezza */
161                 crv = PK11_GETTAB(context->slot)->C_EncryptInit(context->session, mech_info, symKey->objectID);
162                 if (crv != CKR_OK)
163                     break;
164                 PK11_GETTAB(context->slot)
165                     ->C_EncryptFinal(context->session,
166                                      NULL, &count);
167             }
168             crv = PK11_GETTAB(context->slot)->C_DecryptInit(context->session, mech_info, symKey->objectID);
169             break;
170         case CKA_SIGN:
171             crv = PK11_GETTAB(context->slot)->C_SignInit(context->session, mech_info, symKey->objectID);
172             break;
173         case CKA_VERIFY:
174             crv = PK11_GETTAB(context->slot)->C_SignInit(context->session, mech_info, symKey->objectID);
175             break;
176         case CKA_DIGEST:
177             crv = PK11_GETTAB(context->slot)->C_DigestInit(context->session, mech_info);
178             break;
179         default:
180             crv = CKR_OPERATION_NOT_INITIALIZED;
181             break;
182     }
183 
184     if (crv != CKR_OK) {
185         PORT_SetError(PK11_MapError(crv));
186         return SECFailure;
187     }
188 
189     /*
190      * handle session starvation case.. use our last session to multiplex
191      */
192     if (!context->ownSession) {
193         context->savedData = pk11_saveContext(context, context->savedData,
194                                               &context->savedLength);
195         if (context->savedData == NULL)
196             rv = SECFailure;
197         /* clear out out session for others to use */
198         pk11_Finalize(context);
199     }
200     return rv;
201 }
202 
203 /*
204  * Common Helper Function do come up with a new context.
205  */
206 static PK11Context *
pk11_CreateNewContextInSlot(CK_MECHANISM_TYPE type,PK11SlotInfo * slot,CK_ATTRIBUTE_TYPE operation,PK11SymKey * symKey,SECItem * param)207 pk11_CreateNewContextInSlot(CK_MECHANISM_TYPE type,
208                             PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey,
209                             SECItem *param)
210 {
211     CK_MECHANISM mech_info;
212     PK11Context *context;
213     SECStatus rv;
214 
215     PORT_Assert(slot != NULL);
216     if (!slot || (!symKey && ((operation != CKA_DIGEST) ||
217                               (type == CKM_SKIPJACK_CBC64)))) {
218         PORT_SetError(SEC_ERROR_INVALID_ARGS);
219         return NULL;
220     }
221     context = (PK11Context *)PORT_Alloc(sizeof(PK11Context));
222     if (context == NULL) {
223         return NULL;
224     }
225 
226     /* now deal with the fortezza hack... the fortezza hack is an attempt
227      * to get around the issue of the card not allowing you to do a FORTEZZA
228      * LoadIV/Encrypt, which was added because such a combination could be
229      * use to circumvent the key escrow system. Unfortunately SSL needs to
230      * do this kind of operation, so in SSL we do a loadIV (to verify it),
231      * Then GenerateIV, and through away the first 8 bytes on either side
232      * of the connection.*/
233     context->fortezzaHack = PR_FALSE;
234     if (type == CKM_SKIPJACK_CBC64) {
235         if (symKey->origin == PK11_OriginFortezzaHack) {
236             context->fortezzaHack = PR_TRUE;
237         }
238     }
239 
240     /* initialize the critical fields of the context */
241     context->operation = operation;
242     context->key = symKey ? PK11_ReferenceSymKey(symKey) : NULL;
243     context->slot = PK11_ReferenceSlot(slot);
244     context->session = pk11_GetNewSession(slot, &context->ownSession);
245     context->cx = symKey ? symKey->cx : NULL;
246     /* get our session */
247     context->savedData = NULL;
248 
249     /* save the parameters so that some digesting stuff can do multiple
250      * begins on a single context */
251     context->type = type;
252     if (param) {
253         if (param->len > 0) {
254             context->param = SECITEM_DupItem(param);
255         } else {
256             context->param = (SECItem *)&pk11_null_params;
257         }
258     } else {
259         PORT_SetError(SEC_ERROR_INVALID_ARGS);
260         context->param = NULL;
261     }
262     context->init = PR_FALSE;
263     context->sessionLock = PZ_NewLock(nssILockPK11cxt);
264     if ((context->param == NULL) || (context->sessionLock == NULL)) {
265         PK11_DestroyContext(context, PR_TRUE);
266         return NULL;
267     }
268 
269     mech_info.mechanism = type;
270     mech_info.pParameter = param->data;
271     mech_info.ulParameterLen = param->len;
272     PK11_EnterContextMonitor(context);
273     rv = pk11_context_init(context, &mech_info);
274     PK11_ExitContextMonitor(context);
275 
276     if (rv != SECSuccess) {
277         PK11_DestroyContext(context, PR_TRUE);
278         return NULL;
279     }
280     context->init = PR_TRUE;
281     return context;
282 }
283 
284 /*
285  * put together the various PK11_Create_Context calls used by different
286  * parts of libsec.
287  */
288 PK11Context *
__PK11_CreateContextByRawKey(PK11SlotInfo * slot,CK_MECHANISM_TYPE type,PK11Origin origin,CK_ATTRIBUTE_TYPE operation,SECItem * key,SECItem * param,void * wincx)289 __PK11_CreateContextByRawKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
290                              PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key,
291                              SECItem *param, void *wincx)
292 {
293     PK11SymKey *symKey = NULL;
294     PK11Context *context = NULL;
295 
296     /* first get a slot */
297     if (slot == NULL) {
298         slot = PK11_GetBestSlot(type, wincx);
299         if (slot == NULL) {
300             PORT_SetError(SEC_ERROR_NO_MODULE);
301             goto loser;
302         }
303     } else {
304         PK11_ReferenceSlot(slot);
305     }
306 
307     /* now import the key */
308     symKey = PK11_ImportSymKey(slot, type, origin, operation, key, wincx);
309     if (symKey == NULL)
310         goto loser;
311 
312     context = PK11_CreateContextBySymKey(type, operation, symKey, param);
313 
314 loser:
315     if (symKey) {
316         PK11_FreeSymKey(symKey);
317     }
318     if (slot) {
319         PK11_FreeSlot(slot);
320     }
321 
322     return context;
323 }
324 
325 PK11Context *
PK11_CreateContextByRawKey(PK11SlotInfo * slot,CK_MECHANISM_TYPE type,PK11Origin origin,CK_ATTRIBUTE_TYPE operation,SECItem * key,SECItem * param,void * wincx)326 PK11_CreateContextByRawKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
327                            PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key,
328                            SECItem *param, void *wincx)
329 {
330     return __PK11_CreateContextByRawKey(slot, type, origin, operation,
331                                         key, param, wincx);
332 }
333 
334 /*
335  * Create a context from a key. We really should make sure we aren't using
336  * the same key in multiple session!
337  */
338 PK11Context *
PK11_CreateContextBySymKey(CK_MECHANISM_TYPE type,CK_ATTRIBUTE_TYPE operation,PK11SymKey * symKey,SECItem * param)339 PK11_CreateContextBySymKey(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE operation,
340                            PK11SymKey *symKey, SECItem *param)
341 {
342     PK11SymKey *newKey;
343     PK11Context *context;
344 
345     /* if this slot doesn't support the mechanism, go to a slot that does */
346     newKey = pk11_ForceSlot(symKey, type, operation);
347     if (newKey == NULL) {
348         PK11_ReferenceSymKey(symKey);
349     } else {
350         symKey = newKey;
351     }
352 
353     /* Context Adopts the symKey.... */
354     context = pk11_CreateNewContextInSlot(type, symKey->slot, operation, symKey,
355                                           param);
356     PK11_FreeSymKey(symKey);
357     return context;
358 }
359 
360 /*
361  * Digest contexts don't need keys, but the do need to find a slot.
362  * Macing should use PK11_CreateContextBySymKey.
363  */
364 PK11Context *
PK11_CreateDigestContext(SECOidTag hashAlg)365 PK11_CreateDigestContext(SECOidTag hashAlg)
366 {
367     /* digesting has to work without authentication to the slot */
368     CK_MECHANISM_TYPE type;
369     PK11SlotInfo *slot;
370     PK11Context *context;
371     SECItem param;
372 
373     type = PK11_AlgtagToMechanism(hashAlg);
374     slot = PK11_GetBestSlot(type, NULL);
375     if (slot == NULL) {
376         PORT_SetError(SEC_ERROR_NO_MODULE);
377         return NULL;
378     }
379 
380     /* maybe should really be PK11_GenerateNewParam?? */
381     param.data = NULL;
382     param.len = 0;
383     param.type = 0;
384 
385     context = pk11_CreateNewContextInSlot(type, slot, CKA_DIGEST, NULL, &param);
386     PK11_FreeSlot(slot);
387     return context;
388 }
389 
390 /*
391  * create a new context which is the clone of the state of old context.
392  */
393 PK11Context *
PK11_CloneContext(PK11Context * old)394 PK11_CloneContext(PK11Context *old)
395 {
396     PK11Context *newcx;
397     PRBool needFree = PR_FALSE;
398     SECStatus rv = SECSuccess;
399     void *data;
400     unsigned long len;
401 
402     newcx = pk11_CreateNewContextInSlot(old->type, old->slot, old->operation,
403                                         old->key, old->param);
404     if (newcx == NULL)
405         return NULL;
406 
407     /* now clone the save state. First we need to find the save state
408       * of the old session. If the old context owns it's session,
409       * the state needs to be saved, otherwise the state is in saveData. */
410     if (old->ownSession) {
411         PK11_EnterContextMonitor(old);
412         data = pk11_saveContext(old, NULL, &len);
413         PK11_ExitContextMonitor(old);
414         needFree = PR_TRUE;
415     } else {
416         data = old->savedData;
417         len = old->savedLength;
418     }
419 
420     if (data == NULL) {
421         PK11_DestroyContext(newcx, PR_TRUE);
422         return NULL;
423     }
424 
425     /* now copy that state into our new context. Again we have different
426       * work if the new context owns it's own session. If it does, we
427       * restore the state gathered above. If it doesn't, we copy the
428       * saveData pointer... */
429     if (newcx->ownSession) {
430         PK11_EnterContextMonitor(newcx);
431         rv = pk11_restoreContext(newcx, data, len);
432         PK11_ExitContextMonitor(newcx);
433     } else {
434         PORT_Assert(newcx->savedData != NULL);
435         if ((newcx->savedData == NULL) || (newcx->savedLength < len)) {
436             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
437             rv = SECFailure;
438         } else {
439             PORT_Memcpy(newcx->savedData, data, len);
440             newcx->savedLength = len;
441         }
442     }
443 
444     if (needFree)
445         PORT_Free(data);
446 
447     if (rv != SECSuccess) {
448         PK11_DestroyContext(newcx, PR_TRUE);
449         return NULL;
450     }
451     return newcx;
452 }
453 
454 /*
455  * save the current context state into a variable. Required to make FORTEZZA
456  * work.
457  */
458 SECStatus
PK11_SaveContext(PK11Context * cx,unsigned char * save,int * len,int saveLength)459 PK11_SaveContext(PK11Context *cx, unsigned char *save, int *len, int saveLength)
460 {
461     unsigned char *data = NULL;
462     CK_ULONG length = saveLength;
463 
464     if (cx->ownSession) {
465         PK11_EnterContextMonitor(cx);
466         data = pk11_saveContextHelper(cx, save, &length);
467         PK11_ExitContextMonitor(cx);
468         if (data)
469             *len = length;
470     } else if ((unsigned)saveLength >= cx->savedLength) {
471         data = (unsigned char *)cx->savedData;
472         if (cx->savedData) {
473             PORT_Memcpy(save, cx->savedData, cx->savedLength);
474         }
475         *len = cx->savedLength;
476     }
477     if (data != NULL) {
478         if (cx->ownSession) {
479             PORT_ZFree(data, length);
480         }
481         return SECSuccess;
482     } else {
483         return SECFailure;
484     }
485 }
486 
487 /* same as above, but may allocate the return buffer. */
488 unsigned char *
PK11_SaveContextAlloc(PK11Context * cx,unsigned char * preAllocBuf,unsigned int pabLen,unsigned int * stateLen)489 PK11_SaveContextAlloc(PK11Context *cx,
490                       unsigned char *preAllocBuf, unsigned int pabLen,
491                       unsigned int *stateLen)
492 {
493     unsigned char *stateBuf = NULL;
494     unsigned long length = (unsigned long)pabLen;
495 
496     if (cx->ownSession) {
497         PK11_EnterContextMonitor(cx);
498         stateBuf = pk11_saveContextHelper(cx, preAllocBuf, &length);
499         PK11_ExitContextMonitor(cx);
500         *stateLen = (stateBuf != NULL) ? length : 0;
501     } else {
502         if (pabLen < cx->savedLength) {
503             stateBuf = (unsigned char *)PORT_Alloc(cx->savedLength);
504             if (!stateBuf) {
505                 return (unsigned char *)NULL;
506             }
507         } else {
508             stateBuf = preAllocBuf;
509         }
510         if (cx->savedData) {
511             PORT_Memcpy(stateBuf, cx->savedData, cx->savedLength);
512         }
513         *stateLen = cx->savedLength;
514     }
515     return stateBuf;
516 }
517 
518 /*
519  * restore the context state into a new running context. Also required for
520  * FORTEZZA .
521  */
522 SECStatus
PK11_RestoreContext(PK11Context * cx,unsigned char * save,int len)523 PK11_RestoreContext(PK11Context *cx, unsigned char *save, int len)
524 {
525     SECStatus rv = SECSuccess;
526     if (cx->ownSession) {
527         PK11_EnterContextMonitor(cx);
528         pk11_Finalize(cx);
529         rv = pk11_restoreContext(cx, save, len);
530         PK11_ExitContextMonitor(cx);
531     } else {
532         PORT_Assert(cx->savedData != NULL);
533         if ((cx->savedData == NULL) || (cx->savedLength < (unsigned)len)) {
534             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
535             rv = SECFailure;
536         } else {
537             PORT_Memcpy(cx->savedData, save, len);
538             cx->savedLength = len;
539         }
540     }
541     return rv;
542 }
543 
544 /*
545  * This is  to get FIPS compliance until we can convert
546  * libjar to use PK11_ hashing functions. It returns PR_FALSE
547  * if we can't get a PK11 Context.
548  */
549 PRBool
PK11_HashOK(SECOidTag algID)550 PK11_HashOK(SECOidTag algID)
551 {
552     PK11Context *cx;
553 
554     cx = PK11_CreateDigestContext(algID);
555     if (cx == NULL)
556         return PR_FALSE;
557     PK11_DestroyContext(cx, PR_TRUE);
558     return PR_TRUE;
559 }
560 
561 /*
562  * start a new digesting or Mac'ing operation on this context
563  */
564 SECStatus
PK11_DigestBegin(PK11Context * cx)565 PK11_DigestBegin(PK11Context *cx)
566 {
567     CK_MECHANISM mech_info;
568     SECStatus rv;
569 
570     if (cx->init == PR_TRUE) {
571         return SECSuccess;
572     }
573 
574     /*
575      * make sure the old context is clear first
576      */
577     PK11_EnterContextMonitor(cx);
578     pk11_Finalize(cx);
579 
580     mech_info.mechanism = cx->type;
581     mech_info.pParameter = cx->param->data;
582     mech_info.ulParameterLen = cx->param->len;
583     rv = pk11_context_init(cx, &mech_info);
584     PK11_ExitContextMonitor(cx);
585 
586     if (rv != SECSuccess) {
587         return SECFailure;
588     }
589     cx->init = PR_TRUE;
590     return SECSuccess;
591 }
592 
593 SECStatus
PK11_HashBuf(SECOidTag hashAlg,unsigned char * out,const unsigned char * in,PRInt32 len)594 PK11_HashBuf(SECOidTag hashAlg, unsigned char *out, const unsigned char *in,
595              PRInt32 len)
596 {
597     PK11Context *context;
598     unsigned int max_length;
599     unsigned int out_length;
600     SECStatus rv;
601 
602     /* len will be passed to PK11_DigestOp as unsigned. */
603     if (len < 0) {
604         PORT_SetError(SEC_ERROR_INVALID_ARGS);
605         return SECFailure;
606     }
607 
608     context = PK11_CreateDigestContext(hashAlg);
609     if (context == NULL)
610         return SECFailure;
611 
612     rv = PK11_DigestBegin(context);
613     if (rv != SECSuccess) {
614         PK11_DestroyContext(context, PR_TRUE);
615         return rv;
616     }
617 
618     rv = PK11_DigestOp(context, in, len);
619     if (rv != SECSuccess) {
620         PK11_DestroyContext(context, PR_TRUE);
621         return rv;
622     }
623 
624     /* XXX This really should have been an argument to this function! */
625     max_length = HASH_ResultLenByOidTag(hashAlg);
626     PORT_Assert(max_length);
627     if (!max_length)
628         max_length = HASH_LENGTH_MAX;
629 
630     rv = PK11_DigestFinal(context, out, &out_length, max_length);
631     PK11_DestroyContext(context, PR_TRUE);
632     return rv;
633 }
634 
635 /*
636  * execute a bulk encryption operation
637  */
638 SECStatus
PK11_CipherOp(PK11Context * context,unsigned char * out,int * outlen,int maxout,const unsigned char * in,int inlen)639 PK11_CipherOp(PK11Context *context, unsigned char *out, int *outlen,
640               int maxout, const unsigned char *in, int inlen)
641 {
642     CK_RV crv = CKR_OK;
643     CK_ULONG length = maxout;
644     CK_ULONG offset = 0;
645     SECStatus rv = SECSuccess;
646     unsigned char *saveOut = out;
647     unsigned char *allocOut = NULL;
648 
649     /* if we ran out of session, we need to restore our previously stored
650      * state.
651      */
652     PK11_EnterContextMonitor(context);
653     if (!context->ownSession) {
654         rv = pk11_restoreContext(context, context->savedData,
655                                  context->savedLength);
656         if (rv != SECSuccess) {
657             PK11_ExitContextMonitor(context);
658             return rv;
659         }
660     }
661 
662     /*
663      * The fortezza hack is to send 8 extra bytes on the first encrypted and
664      * lose them on the first decrypt.
665      */
666     if (context->fortezzaHack) {
667         unsigned char random[8];
668         if (context->operation == CKA_ENCRYPT) {
669             PK11_ExitContextMonitor(context);
670             rv = PK11_GenerateRandom(random, sizeof(random));
671             PK11_EnterContextMonitor(context);
672 
673             /* since we are offseting the output, we can't encrypt back into
674              * the same buffer... allocate a temporary buffer just for this
675              * call. */
676             allocOut = out = (unsigned char *)PORT_Alloc(maxout);
677             if (out == NULL) {
678                 PK11_ExitContextMonitor(context);
679                 return SECFailure;
680             }
681             crv = PK11_GETTAB(context->slot)->C_EncryptUpdate(context->session, random, sizeof(random), out, &length);
682 
683             out += length;
684             maxout -= length;
685             offset = length;
686         } else if (context->operation == CKA_DECRYPT) {
687             length = sizeof(random);
688             crv = PK11_GETTAB(context->slot)->C_DecryptUpdate(context->session, (CK_BYTE_PTR)in, sizeof(random), random, &length);
689             inlen -= length;
690             in += length;
691             context->fortezzaHack = PR_FALSE;
692         }
693     }
694 
695     switch (context->operation) {
696         case CKA_ENCRYPT:
697             length = maxout;
698             crv = PK11_GETTAB(context->slot)->C_EncryptUpdate(context->session, (CK_BYTE_PTR)in, inlen, out, &length);
699             length += offset;
700             break;
701         case CKA_DECRYPT:
702             length = maxout;
703             crv = PK11_GETTAB(context->slot)->C_DecryptUpdate(context->session, (CK_BYTE_PTR)in, inlen, out, &length);
704             break;
705         default:
706             crv = CKR_OPERATION_NOT_INITIALIZED;
707             break;
708     }
709 
710     if (crv != CKR_OK) {
711         PORT_SetError(PK11_MapError(crv));
712         *outlen = 0;
713         rv = SECFailure;
714     } else {
715         *outlen = length;
716     }
717 
718     if (context->fortezzaHack) {
719         if (context->operation == CKA_ENCRYPT) {
720             PORT_Assert(allocOut);
721             PORT_Memcpy(saveOut, allocOut, length);
722             PORT_Free(allocOut);
723         }
724         context->fortezzaHack = PR_FALSE;
725     }
726 
727     /*
728      * handle session starvation case.. use our last session to multiplex
729      */
730     if (!context->ownSession) {
731         context->savedData = pk11_saveContext(context, context->savedData,
732                                               &context->savedLength);
733         if (context->savedData == NULL)
734             rv = SECFailure;
735 
736         /* clear out out session for others to use */
737         pk11_Finalize(context);
738     }
739     PK11_ExitContextMonitor(context);
740     return rv;
741 }
742 
743 /*
744  * execute a digest/signature operation
745  */
746 SECStatus
PK11_DigestOp(PK11Context * context,const unsigned char * in,unsigned inLen)747 PK11_DigestOp(PK11Context *context, const unsigned char *in, unsigned inLen)
748 {
749     CK_RV crv = CKR_OK;
750     SECStatus rv = SECSuccess;
751 
752     if (inLen == 0) {
753         return SECSuccess;
754     }
755     if (!in) {
756         PORT_SetError(SEC_ERROR_INVALID_ARGS);
757         return SECFailure;
758     }
759 
760     /* if we ran out of session, we need to restore our previously stored
761      * state.
762      */
763     context->init = PR_FALSE;
764     PK11_EnterContextMonitor(context);
765     if (!context->ownSession) {
766         rv = pk11_restoreContext(context, context->savedData,
767                                  context->savedLength);
768         if (rv != SECSuccess) {
769             PK11_ExitContextMonitor(context);
770             return rv;
771         }
772     }
773 
774     switch (context->operation) {
775         /* also for MAC'ing */
776         case CKA_SIGN:
777             crv = PK11_GETTAB(context->slot)->C_SignUpdate(context->session, (unsigned char *)in, inLen);
778             break;
779         case CKA_VERIFY:
780             crv = PK11_GETTAB(context->slot)->C_VerifyUpdate(context->session, (unsigned char *)in, inLen);
781             break;
782         case CKA_DIGEST:
783             crv = PK11_GETTAB(context->slot)->C_DigestUpdate(context->session, (unsigned char *)in, inLen);
784             break;
785         default:
786             crv = CKR_OPERATION_NOT_INITIALIZED;
787             break;
788     }
789 
790     if (crv != CKR_OK) {
791         PORT_SetError(PK11_MapError(crv));
792         rv = SECFailure;
793     }
794 
795     /*
796      * handle session starvation case.. use our last session to multiplex
797      */
798     if (!context->ownSession) {
799         context->savedData = pk11_saveContext(context, context->savedData,
800                                               &context->savedLength);
801         if (context->savedData == NULL)
802             rv = SECFailure;
803 
804         /* clear out out session for others to use */
805         pk11_Finalize(context);
806     }
807     PK11_ExitContextMonitor(context);
808     return rv;
809 }
810 
811 /*
812  * Digest a key if possible./
813  */
814 SECStatus
PK11_DigestKey(PK11Context * context,PK11SymKey * key)815 PK11_DigestKey(PK11Context *context, PK11SymKey *key)
816 {
817     CK_RV crv = CKR_OK;
818     SECStatus rv = SECSuccess;
819     PK11SymKey *newKey = NULL;
820 
821     if (!context || !key) {
822         PORT_SetError(SEC_ERROR_INVALID_ARGS);
823         return SECFailure;
824     }
825 
826     /* if we ran out of session, we need to restore our previously stored
827      * state.
828      */
829     if (context->slot != key->slot) {
830         newKey = pk11_CopyToSlot(context->slot, CKM_SSL3_SHA1_MAC, CKA_SIGN, key);
831     } else {
832         newKey = PK11_ReferenceSymKey(key);
833     }
834 
835     context->init = PR_FALSE;
836     PK11_EnterContextMonitor(context);
837     if (!context->ownSession) {
838         rv = pk11_restoreContext(context, context->savedData,
839                                  context->savedLength);
840         if (rv != SECSuccess) {
841             PK11_ExitContextMonitor(context);
842             PK11_FreeSymKey(newKey);
843             return rv;
844         }
845     }
846 
847     if (newKey == NULL) {
848         crv = CKR_KEY_TYPE_INCONSISTENT;
849         if (key->data.data) {
850             crv = PK11_GETTAB(context->slot)->C_DigestUpdate(context->session, key->data.data, key->data.len);
851         }
852     } else {
853         crv = PK11_GETTAB(context->slot)->C_DigestKey(context->session, newKey->objectID);
854     }
855 
856     if (crv != CKR_OK) {
857         PORT_SetError(PK11_MapError(crv));
858         rv = SECFailure;
859     }
860 
861     /*
862      * handle session starvation case.. use our last session to multiplex
863      */
864     if (!context->ownSession) {
865         context->savedData = pk11_saveContext(context, context->savedData,
866                                               &context->savedLength);
867         if (context->savedData == NULL)
868             rv = SECFailure;
869 
870         /* clear out out session for others to use */
871         pk11_Finalize(context);
872     }
873     PK11_ExitContextMonitor(context);
874     if (newKey)
875         PK11_FreeSymKey(newKey);
876     return rv;
877 }
878 
879 /*
880  * externally callable version of the lowercase pk11_finalize().
881  */
882 SECStatus
PK11_Finalize(PK11Context * context)883 PK11_Finalize(PK11Context *context)
884 {
885     SECStatus rv;
886 
887     PK11_EnterContextMonitor(context);
888     rv = pk11_Finalize(context);
889     PK11_ExitContextMonitor(context);
890     return rv;
891 }
892 
893 /*
894  * clean up a cipher operation, so the session can be used by
895  * someone new.
896  */
897 SECStatus
pk11_Finalize(PK11Context * context)898 pk11_Finalize(PK11Context *context)
899 {
900     CK_ULONG count = 0;
901     CK_RV crv;
902     unsigned char stackBuf[256];
903     unsigned char *buffer = NULL;
904 
905     if (!context->ownSession) {
906         return SECSuccess;
907     }
908 
909 finalize:
910     switch (context->operation) {
911         case CKA_ENCRYPT:
912             crv = PK11_GETTAB(context->slot)->C_EncryptFinal(context->session, buffer, &count);
913             break;
914         case CKA_DECRYPT:
915             crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session, buffer, &count);
916             break;
917         case CKA_SIGN:
918             crv = PK11_GETTAB(context->slot)->C_SignFinal(context->session, buffer, &count);
919             break;
920         case CKA_VERIFY:
921             crv = PK11_GETTAB(context->slot)->C_VerifyFinal(context->session, buffer, count);
922             break;
923         case CKA_DIGEST:
924             crv = PK11_GETTAB(context->slot)->C_DigestFinal(context->session, buffer, &count);
925             break;
926         default:
927             crv = CKR_OPERATION_NOT_INITIALIZED;
928             break;
929     }
930 
931     if (crv != CKR_OK) {
932         if (buffer != stackBuf) {
933             PORT_Free(buffer);
934         }
935         if (crv == CKR_OPERATION_NOT_INITIALIZED) {
936             /* if there's no operation, it is finalized */
937             return SECSuccess;
938         }
939         PORT_SetError(PK11_MapError(crv));
940         return SECFailure;
941     }
942 
943     /* try to finalize the session with a buffer */
944     if (buffer == NULL) {
945         if (count <= sizeof stackBuf) {
946             buffer = stackBuf;
947         } else {
948             buffer = PORT_Alloc(count);
949             if (buffer == NULL) {
950                 PORT_SetError(SEC_ERROR_NO_MEMORY);
951                 return SECFailure;
952             }
953         }
954         goto finalize;
955     }
956     if (buffer != stackBuf) {
957         PORT_Free(buffer);
958     }
959     return SECSuccess;
960 }
961 
962 /*
963  *  Return the final digested or signed data...
964  *  this routine can either take pre initialized data, or allocate data
965  *  either out of an arena or out of the standard heap.
966  */
967 SECStatus
PK11_DigestFinal(PK11Context * context,unsigned char * data,unsigned int * outLen,unsigned int length)968 PK11_DigestFinal(PK11Context *context, unsigned char *data,
969                  unsigned int *outLen, unsigned int length)
970 {
971     CK_ULONG len;
972     CK_RV crv;
973     SECStatus rv;
974 
975     /* if we ran out of session, we need to restore our previously stored
976      * state.
977      */
978     PK11_EnterContextMonitor(context);
979     if (!context->ownSession) {
980         rv = pk11_restoreContext(context, context->savedData,
981                                  context->savedLength);
982         if (rv != SECSuccess) {
983             PK11_ExitContextMonitor(context);
984             return rv;
985         }
986     }
987 
988     len = length;
989     switch (context->operation) {
990         case CKA_SIGN:
991             crv = PK11_GETTAB(context->slot)->C_SignFinal(context->session, data, &len);
992             break;
993         case CKA_VERIFY:
994             crv = PK11_GETTAB(context->slot)->C_VerifyFinal(context->session, data, len);
995             break;
996         case CKA_DIGEST:
997             crv = PK11_GETTAB(context->slot)->C_DigestFinal(context->session, data, &len);
998             break;
999         case CKA_ENCRYPT:
1000             crv = PK11_GETTAB(context->slot)->C_EncryptFinal(context->session, data, &len);
1001             break;
1002         case CKA_DECRYPT:
1003             crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session, data, &len);
1004             break;
1005         default:
1006             crv = CKR_OPERATION_NOT_INITIALIZED;
1007             break;
1008     }
1009     PK11_ExitContextMonitor(context);
1010 
1011     *outLen = (unsigned int)len;
1012     context->init = PR_FALSE; /* allow Begin to start up again */
1013 
1014     if (crv != CKR_OK) {
1015         PORT_SetError(PK11_MapError(crv));
1016         return SECFailure;
1017     }
1018     return SECSuccess;
1019 }
1020