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, ¶m);
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