Import 1.9b4 NSS tag from cvs
[mozilla-nss.git] / security / nss / lib / pk11wrap / pk11cxt.c
blobea74d194a0e5cc7eec072149dbc86196737b3212
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 * This file PK11Contexts which are used in multipart hashing,
38 * encryption/decryption, and signing/verication operations.
41 #include "seccomon.h"
42 #include "secmod.h"
43 #include "nssilock.h"
44 #include "secmodi.h"
45 #include "secmodti.h"
46 #include "pkcs11.h"
47 #include "pk11func.h"
48 #include "secitem.h"
49 #include "secoid.h"
50 #include "sechash.h"
51 #include "secerr.h"
53 static const SECItem pk11_null_params = { 0 };
55 /**********************************************************************
57 * Now Deal with Crypto Contexts
59 **********************************************************************/
62 * the monitors...
64 void
65 PK11_EnterContextMonitor(PK11Context *cx) {
66 /* if we own the session and our slot is ThreadSafe, only monitor
67 * the Context */
68 if ((cx->ownSession) && (cx->slot->isThreadSafe)) {
69 /* Should this use monitors instead? */
70 PZ_Lock(cx->sessionLock);
71 } else {
72 PK11_EnterSlotMonitor(cx->slot);
76 void
77 PK11_ExitContextMonitor(PK11Context *cx) {
78 /* if we own the session and our slot is ThreadSafe, only monitor
79 * the Context */
80 if ((cx->ownSession) && (cx->slot->isThreadSafe)) {
81 /* Should this use monitors instead? */
82 PZ_Unlock(cx->sessionLock);
83 } else {
84 PK11_ExitSlotMonitor(cx->slot);
89 * Free up a Cipher Context
91 void
92 PK11_DestroyContext(PK11Context *context, PRBool freeit)
94 pk11_CloseSession(context->slot,context->session,context->ownSession);
95 /* initialize the critical fields of the context */
96 if (context->savedData != NULL ) PORT_Free(context->savedData);
97 if (context->key) PK11_FreeSymKey(context->key);
98 if (context->param && context->param != &pk11_null_params)
99 SECITEM_FreeItem(context->param, PR_TRUE);
100 if (context->sessionLock) PZ_DestroyLock(context->sessionLock);
101 PK11_FreeSlot(context->slot);
102 if (freeit) PORT_Free(context);
106 * save the current context. Allocate Space if necessary.
108 static unsigned char *
109 pk11_saveContextHelper(PK11Context *context, unsigned char *buffer,
110 unsigned long *savedLength)
112 CK_RV crv;
114 /* If buffer is NULL, this will get the length */
115 crv = PK11_GETTAB(context->slot)->C_GetOperationState(context->session,
116 (CK_BYTE_PTR)buffer,
117 savedLength);
118 if (!buffer || (crv == CKR_BUFFER_TOO_SMALL)) {
119 /* the given buffer wasn't big enough (or was NULL), but we
120 * have the length, so try again with a new buffer and the
121 * correct length
123 unsigned long bufLen = *savedLength;
124 buffer = PORT_Alloc(bufLen);
125 if (buffer == NULL) {
126 return (unsigned char *)NULL;
128 crv = PK11_GETTAB(context->slot)->C_GetOperationState(
129 context->session,
130 (CK_BYTE_PTR)buffer,
131 savedLength);
132 if (crv != CKR_OK) {
133 PORT_ZFree(buffer, bufLen);
136 if (crv != CKR_OK) {
137 PORT_SetError( PK11_MapError(crv) );
138 return (unsigned char *)NULL;
140 return buffer;
143 void *
144 pk11_saveContext(PK11Context *context, void *space, unsigned long *savedLength)
146 return pk11_saveContextHelper(context,
147 (unsigned char *)space, savedLength);
151 * restore the current context
153 SECStatus
154 pk11_restoreContext(PK11Context *context,void *space, unsigned long savedLength)
156 CK_RV crv;
157 CK_OBJECT_HANDLE objectID = (context->key) ? context->key->objectID:
158 CK_INVALID_HANDLE;
160 PORT_Assert(space != NULL);
161 if (space == NULL) {
162 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
163 return SECFailure;
165 crv = PK11_GETTAB(context->slot)->C_SetOperationState(context->session,
166 (CK_BYTE_PTR)space, savedLength, objectID, 0);
167 if (crv != CKR_OK) {
168 PORT_SetError( PK11_MapError(crv));
169 return SECFailure;
171 return SECSuccess;
174 SECStatus pk11_Finalize(PK11Context *context);
177 * Context initialization. Used by all flavors of CreateContext
179 static SECStatus
180 pk11_context_init(PK11Context *context, CK_MECHANISM *mech_info)
182 CK_RV crv;
183 PK11SymKey *symKey = context->key;
184 SECStatus rv = SECSuccess;
186 switch (context->operation) {
187 case CKA_ENCRYPT:
188 crv=PK11_GETTAB(context->slot)->C_EncryptInit(context->session,
189 mech_info, symKey->objectID);
190 break;
191 case CKA_DECRYPT:
192 if (context->fortezzaHack) {
193 CK_ULONG count = 0;;
194 /* generate the IV for fortezza */
195 crv=PK11_GETTAB(context->slot)->C_EncryptInit(context->session,
196 mech_info, symKey->objectID);
197 if (crv != CKR_OK) break;
198 PK11_GETTAB(context->slot)->C_EncryptFinal(context->session,
199 NULL, &count);
201 crv=PK11_GETTAB(context->slot)->C_DecryptInit(context->session,
202 mech_info, symKey->objectID);
203 break;
204 case CKA_SIGN:
205 crv=PK11_GETTAB(context->slot)->C_SignInit(context->session,
206 mech_info, symKey->objectID);
207 break;
208 case CKA_VERIFY:
209 crv=PK11_GETTAB(context->slot)->C_SignInit(context->session,
210 mech_info, symKey->objectID);
211 break;
212 case CKA_DIGEST:
213 crv=PK11_GETTAB(context->slot)->C_DigestInit(context->session,
214 mech_info);
215 break;
216 default:
217 crv = CKR_OPERATION_NOT_INITIALIZED;
218 break;
221 if (crv != CKR_OK) {
222 PORT_SetError( PK11_MapError(crv) );
223 return SECFailure;
227 * handle session starvation case.. use our last session to multiplex
229 if (!context->ownSession) {
230 context->savedData = pk11_saveContext(context,context->savedData,
231 &context->savedLength);
232 if (context->savedData == NULL) rv = SECFailure;
233 /* clear out out session for others to use */
234 pk11_Finalize(context);
236 return rv;
241 * Common Helper Function do come up with a new context.
243 static PK11Context *pk11_CreateNewContextInSlot(CK_MECHANISM_TYPE type,
244 PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey,
245 SECItem *param)
247 CK_MECHANISM mech_info;
248 PK11Context *context;
249 SECStatus rv;
251 PORT_Assert(slot != NULL);
252 if (!slot || (!symKey && operation != CKA_DIGEST)) {
253 PORT_SetError(SEC_ERROR_INVALID_ARGS);
254 return NULL;
256 context = (PK11Context *) PORT_Alloc(sizeof(PK11Context));
257 if (context == NULL) {
258 return NULL;
261 /* now deal with the fortezza hack... the fortezza hack is an attempt
262 * to get around the issue of the card not allowing you to do a FORTEZZA
263 * LoadIV/Encrypt, which was added because such a combination could be
264 * use to circumvent the key escrow system. Unfortunately SSL needs to
265 * do this kind of operation, so in SSL we do a loadIV (to verify it),
266 * Then GenerateIV, and through away the first 8 bytes on either side
267 * of the connection.*/
268 context->fortezzaHack = PR_FALSE;
269 if (type == CKM_SKIPJACK_CBC64) {
270 if (symKey->origin == PK11_OriginFortezzaHack) {
271 context->fortezzaHack = PR_TRUE;
275 /* initialize the critical fields of the context */
276 context->operation = operation;
277 context->key = symKey ? PK11_ReferenceSymKey(symKey) : NULL;
278 context->slot = PK11_ReferenceSlot(slot);
279 context->session = pk11_GetNewSession(slot,&context->ownSession);
280 context->cx = symKey ? symKey->cx : NULL;
281 /* get our session */
282 context->savedData = NULL;
284 /* save the parameters so that some digesting stuff can do multiple
285 * begins on a single context */
286 context->type = type;
287 if (param) {
288 if (param->len > 0) {
289 context->param = SECITEM_DupItem(param);
290 } else {
291 context->param = (SECItem *)&pk11_null_params;
293 } else {
294 context->param = NULL;
296 context->init = PR_FALSE;
297 context->sessionLock = PZ_NewLock(nssILockPK11cxt);
298 if ((context->param == NULL) || (context->sessionLock == NULL)) {
299 PK11_DestroyContext(context,PR_TRUE);
300 return NULL;
303 mech_info.mechanism = type;
304 mech_info.pParameter = param->data;
305 mech_info.ulParameterLen = param->len;
306 PK11_EnterContextMonitor(context);
307 rv = pk11_context_init(context,&mech_info);
308 PK11_ExitContextMonitor(context);
310 if (rv != SECSuccess) {
311 PK11_DestroyContext(context,PR_TRUE);
312 return NULL;
314 context->init = PR_TRUE;
315 return context;
320 * put together the various PK11_Create_Context calls used by different
321 * parts of libsec.
323 PK11Context *
324 __PK11_CreateContextByRawKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
325 PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key,
326 SECItem *param, void *wincx)
328 PK11SymKey *symKey = NULL;
329 PK11Context *context = NULL;
331 /* first get a slot */
332 if (slot == NULL) {
333 slot = PK11_GetBestSlot(type,wincx);
334 if (slot == NULL) {
335 PORT_SetError( SEC_ERROR_NO_MODULE );
336 goto loser;
338 } else {
339 PK11_ReferenceSlot(slot);
342 /* now import the key */
343 symKey = PK11_ImportSymKey(slot, type, origin, operation, key, wincx);
344 if (symKey == NULL) goto loser;
346 context = PK11_CreateContextBySymKey(type, operation, symKey, param);
348 loser:
349 if (symKey) {
350 PK11_FreeSymKey(symKey);
352 if (slot) {
353 PK11_FreeSlot(slot);
356 return context;
359 PK11Context *
360 PK11_CreateContextByRawKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
361 PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key,
362 SECItem *param, void *wincx)
364 return __PK11_CreateContextByRawKey(slot, type, origin, operation,
365 key, param, wincx);
370 * Create a context from a key. We really should make sure we aren't using
371 * the same key in multiple session!
373 PK11Context *
374 PK11_CreateContextBySymKey(CK_MECHANISM_TYPE type,CK_ATTRIBUTE_TYPE operation,
375 PK11SymKey *symKey, SECItem *param)
377 PK11SymKey *newKey;
378 PK11Context *context;
380 /* if this slot doesn't support the mechanism, go to a slot that does */
381 newKey = pk11_ForceSlot(symKey,type,operation);
382 if (newKey == NULL) {
383 PK11_ReferenceSymKey(symKey);
384 } else {
385 symKey = newKey;
389 /* Context Adopts the symKey.... */
390 context = pk11_CreateNewContextInSlot(type, symKey->slot, operation, symKey,
391 param);
392 PK11_FreeSymKey(symKey);
393 return context;
397 * Digest contexts don't need keys, but the do need to find a slot.
398 * Macing should use PK11_CreateContextBySymKey.
400 PK11Context *
401 PK11_CreateDigestContext(SECOidTag hashAlg)
403 /* digesting has to work without authentication to the slot */
404 CK_MECHANISM_TYPE type;
405 PK11SlotInfo *slot;
406 PK11Context *context;
407 SECItem param;
409 type = PK11_AlgtagToMechanism(hashAlg);
410 slot = PK11_GetBestSlot(type, NULL);
411 if (slot == NULL) {
412 PORT_SetError( SEC_ERROR_NO_MODULE );
413 return NULL;
416 /* maybe should really be PK11_GenerateNewParam?? */
417 param.data = NULL;
418 param.len = 0;
419 param.type = 0;
421 context = pk11_CreateNewContextInSlot(type, slot, CKA_DIGEST, NULL, &param);
422 PK11_FreeSlot(slot);
423 return context;
427 * create a new context which is the clone of the state of old context.
429 PK11Context * PK11_CloneContext(PK11Context *old)
431 PK11Context *newcx;
432 PRBool needFree = PR_FALSE;
433 SECStatus rv = SECSuccess;
434 void *data;
435 unsigned long len;
437 newcx = pk11_CreateNewContextInSlot(old->type, old->slot, old->operation,
438 old->key, old->param);
439 if (newcx == NULL) return NULL;
441 /* now clone the save state. First we need to find the save state
442 * of the old session. If the old context owns it's session,
443 * the state needs to be saved, otherwise the state is in saveData. */
444 if (old->ownSession) {
445 PK11_EnterContextMonitor(old);
446 data=pk11_saveContext(old,NULL,&len);
447 PK11_ExitContextMonitor(old);
448 needFree = PR_TRUE;
449 } else {
450 data = old->savedData;
451 len = old->savedLength;
454 if (data == NULL) {
455 PK11_DestroyContext(newcx,PR_TRUE);
456 return NULL;
459 /* now copy that state into our new context. Again we have different
460 * work if the new context owns it's own session. If it does, we
461 * restore the state gathered above. If it doesn't, we copy the
462 * saveData pointer... */
463 if (newcx->ownSession) {
464 PK11_EnterContextMonitor(newcx);
465 rv = pk11_restoreContext(newcx,data,len);
466 PK11_ExitContextMonitor(newcx);
467 } else {
468 PORT_Assert(newcx->savedData != NULL);
469 if ((newcx->savedData == NULL) || (newcx->savedLength < len)) {
470 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
471 rv = SECFailure;
472 } else {
473 PORT_Memcpy(newcx->savedData,data,len);
474 newcx->savedLength = len;
478 if (needFree) PORT_Free(data);
480 if (rv != SECSuccess) {
481 PK11_DestroyContext(newcx,PR_TRUE);
482 return NULL;
484 return newcx;
488 * save the current context state into a variable. Required to make FORTEZZA
489 * work.
491 SECStatus
492 PK11_SaveContext(PK11Context *cx,unsigned char *save,int *len, int saveLength)
494 unsigned char * data = NULL;
495 CK_ULONG length = saveLength;
497 if (cx->ownSession) {
498 PK11_EnterContextMonitor(cx);
499 data = pk11_saveContextHelper(cx, save, &length);
500 PK11_ExitContextMonitor(cx);
501 if (data) *len = length;
502 } else if ((unsigned) saveLength >= cx->savedLength) {
503 data = (unsigned char*)cx->savedData;
504 if (cx->savedData) {
505 PORT_Memcpy(save,cx->savedData,cx->savedLength);
507 *len = cx->savedLength;
509 if (data != NULL) {
510 if (cx->ownSession) {
511 PORT_ZFree(data, length);
513 return SECSuccess;
514 } else {
515 return SECFailure;
519 /* same as above, but may allocate the return buffer. */
520 unsigned char *
521 PK11_SaveContextAlloc(PK11Context *cx,
522 unsigned char *preAllocBuf, unsigned int pabLen,
523 unsigned int *stateLen)
525 unsigned char *stateBuf = NULL;
526 unsigned long length = (unsigned long)pabLen;
528 if (cx->ownSession) {
529 PK11_EnterContextMonitor(cx);
530 stateBuf = pk11_saveContextHelper(cx, preAllocBuf, &length);
531 PK11_ExitContextMonitor(cx);
532 *stateLen = (stateBuf != NULL) ? length : 0;
533 } else {
534 if (pabLen < cx->savedLength) {
535 stateBuf = (unsigned char *)PORT_Alloc(cx->savedLength);
536 if (!stateBuf) {
537 return (unsigned char *)NULL;
539 } else {
540 stateBuf = preAllocBuf;
542 if (cx->savedData) {
543 PORT_Memcpy(stateBuf, cx->savedData, cx->savedLength);
545 *stateLen = cx->savedLength;
547 return stateBuf;
551 * restore the context state into a new running context. Also required for
552 * FORTEZZA .
554 SECStatus
555 PK11_RestoreContext(PK11Context *cx,unsigned char *save,int len)
557 SECStatus rv = SECSuccess;
558 if (cx->ownSession) {
559 PK11_EnterContextMonitor(cx);
560 pk11_Finalize(cx);
561 rv = pk11_restoreContext(cx,save,len);
562 PK11_ExitContextMonitor(cx);
563 } else {
564 PORT_Assert(cx->savedData != NULL);
565 if ((cx->savedData == NULL) || (cx->savedLength < (unsigned) len)) {
566 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
567 rv = SECFailure;
568 } else {
569 PORT_Memcpy(cx->savedData,save,len);
570 cx->savedLength = len;
573 return rv;
577 * This is to get FIPS compliance until we can convert
578 * libjar to use PK11_ hashing functions. It returns PR_FALSE
579 * if we can't get a PK11 Context.
581 PRBool
582 PK11_HashOK(SECOidTag algID) {
583 PK11Context *cx;
585 cx = PK11_CreateDigestContext(algID);
586 if (cx == NULL) return PR_FALSE;
587 PK11_DestroyContext(cx, PR_TRUE);
588 return PR_TRUE;
594 * start a new digesting or Mac'ing operation on this context
596 SECStatus PK11_DigestBegin(PK11Context *cx)
598 CK_MECHANISM mech_info;
599 SECStatus rv;
601 if (cx->init == PR_TRUE) {
602 return SECSuccess;
606 * make sure the old context is clear first
608 PK11_EnterContextMonitor(cx);
609 pk11_Finalize(cx);
611 mech_info.mechanism = cx->type;
612 mech_info.pParameter = cx->param->data;
613 mech_info.ulParameterLen = cx->param->len;
614 rv = pk11_context_init(cx,&mech_info);
615 PK11_ExitContextMonitor(cx);
617 if (rv != SECSuccess) {
618 return SECFailure;
620 cx->init = PR_TRUE;
621 return SECSuccess;
624 SECStatus
625 PK11_HashBuf(SECOidTag hashAlg, unsigned char *out, unsigned char *in,
626 PRInt32 len) {
627 PK11Context *context;
628 unsigned int max_length;
629 unsigned int out_length;
630 SECStatus rv;
632 /* len will be passed to PK11_DigestOp as unsigned. */
633 if (len < 0) {
634 PORT_SetError(SEC_ERROR_INVALID_ARGS);
635 return SECFailure;
638 context = PK11_CreateDigestContext(hashAlg);
639 if (context == NULL) return SECFailure;
641 rv = PK11_DigestBegin(context);
642 if (rv != SECSuccess) {
643 PK11_DestroyContext(context, PR_TRUE);
644 return rv;
647 rv = PK11_DigestOp(context, in, len);
648 if (rv != SECSuccess) {
649 PK11_DestroyContext(context, PR_TRUE);
650 return rv;
653 /* XXX This really should have been an argument to this function! */
654 max_length = HASH_ResultLenByOidTag(hashAlg);
655 PORT_Assert(max_length);
656 if (!max_length)
657 max_length = HASH_LENGTH_MAX;
659 rv = PK11_DigestFinal(context,out,&out_length,max_length);
660 PK11_DestroyContext(context, PR_TRUE);
661 return rv;
666 * execute a bulk encryption operation
668 SECStatus
669 PK11_CipherOp(PK11Context *context, unsigned char * out, int *outlen,
670 int maxout, unsigned char *in, int inlen)
672 CK_RV crv = CKR_OK;
673 CK_ULONG length = maxout;
674 CK_ULONG offset =0;
675 SECStatus rv = SECSuccess;
676 unsigned char *saveOut = out;
677 unsigned char *allocOut = NULL;
679 /* if we ran out of session, we need to restore our previously stored
680 * state.
682 PK11_EnterContextMonitor(context);
683 if (!context->ownSession) {
684 rv = pk11_restoreContext(context,context->savedData,
685 context->savedLength);
686 if (rv != SECSuccess) {
687 PK11_ExitContextMonitor(context);
688 return rv;
693 * The fortezza hack is to send 8 extra bytes on the first encrypted and
694 * loose them on the first decrypt.
696 if (context->fortezzaHack) {
697 unsigned char random[8];
698 if (context->operation == CKA_ENCRYPT) {
699 PK11_ExitContextMonitor(context);
700 rv = PK11_GenerateRandom(random,sizeof(random));
701 PK11_EnterContextMonitor(context);
703 /* since we are offseting the output, we can't encrypt back into
704 * the same buffer... allocate a temporary buffer just for this
705 * call. */
706 allocOut = out = (unsigned char*)PORT_Alloc(maxout);
707 if (out == NULL) {
708 PK11_ExitContextMonitor(context);
709 return SECFailure;
711 crv = PK11_GETTAB(context->slot)->C_EncryptUpdate(context->session,
712 random,sizeof(random),out,&length);
714 out += length;
715 maxout -= length;
716 offset = length;
717 } else if (context->operation == CKA_DECRYPT) {
718 length = sizeof(random);
719 crv = PK11_GETTAB(context->slot)->C_DecryptUpdate(context->session,
720 in,sizeof(random),random,&length);
721 inlen -= length;
722 in += length;
723 context->fortezzaHack = PR_FALSE;
727 switch (context->operation) {
728 case CKA_ENCRYPT:
729 length = maxout;
730 crv=PK11_GETTAB(context->slot)->C_EncryptUpdate(context->session,
731 in, inlen, out, &length);
732 length += offset;
733 break;
734 case CKA_DECRYPT:
735 length = maxout;
736 crv=PK11_GETTAB(context->slot)->C_DecryptUpdate(context->session,
737 in, inlen, out, &length);
738 break;
739 default:
740 crv = CKR_OPERATION_NOT_INITIALIZED;
741 break;
744 if (crv != CKR_OK) {
745 PORT_SetError( PK11_MapError(crv) );
746 *outlen = 0;
747 rv = SECFailure;
748 } else {
749 *outlen = length;
752 if (context->fortezzaHack) {
753 if (context->operation == CKA_ENCRYPT) {
754 PORT_Assert(allocOut);
755 PORT_Memcpy(saveOut, allocOut, length);
756 PORT_Free(allocOut);
758 context->fortezzaHack = PR_FALSE;
762 * handle session starvation case.. use our last session to multiplex
764 if (!context->ownSession) {
765 context->savedData = pk11_saveContext(context,context->savedData,
766 &context->savedLength);
767 if (context->savedData == NULL) rv = SECFailure;
769 /* clear out out session for others to use */
770 pk11_Finalize(context);
772 PK11_ExitContextMonitor(context);
773 return rv;
777 * execute a digest/signature operation
779 SECStatus
780 PK11_DigestOp(PK11Context *context, const unsigned char * in, unsigned inLen)
782 CK_RV crv = CKR_OK;
783 SECStatus rv = SECSuccess;
785 if (!in) {
786 PORT_SetError(SEC_ERROR_INVALID_ARGS);
787 return SECFailure;
790 /* if we ran out of session, we need to restore our previously stored
791 * state.
793 context->init = PR_FALSE;
794 PK11_EnterContextMonitor(context);
795 if (!context->ownSession) {
796 rv = pk11_restoreContext(context,context->savedData,
797 context->savedLength);
798 if (rv != SECSuccess) {
799 PK11_ExitContextMonitor(context);
800 return rv;
804 switch (context->operation) {
805 /* also for MAC'ing */
806 case CKA_SIGN:
807 crv=PK11_GETTAB(context->slot)->C_SignUpdate(context->session,
808 (unsigned char *)in,
809 inLen);
810 break;
811 case CKA_VERIFY:
812 crv=PK11_GETTAB(context->slot)->C_VerifyUpdate(context->session,
813 (unsigned char *)in,
814 inLen);
815 break;
816 case CKA_DIGEST:
817 crv=PK11_GETTAB(context->slot)->C_DigestUpdate(context->session,
818 (unsigned char *)in,
819 inLen);
820 break;
821 default:
822 crv = CKR_OPERATION_NOT_INITIALIZED;
823 break;
826 if (crv != CKR_OK) {
827 PORT_SetError( PK11_MapError(crv) );
828 rv = SECFailure;
832 * handle session starvation case.. use our last session to multiplex
834 if (!context->ownSession) {
835 context->savedData = pk11_saveContext(context,context->savedData,
836 &context->savedLength);
837 if (context->savedData == NULL) rv = SECFailure;
839 /* clear out out session for others to use */
840 pk11_Finalize(context);
842 PK11_ExitContextMonitor(context);
843 return rv;
847 * Digest a key if possible./
849 SECStatus
850 PK11_DigestKey(PK11Context *context, PK11SymKey *key)
852 CK_RV crv = CKR_OK;
853 SECStatus rv = SECSuccess;
854 PK11SymKey *newKey = NULL;
856 if (!context || !key) {
857 PORT_SetError(SEC_ERROR_INVALID_ARGS);
858 return SECFailure;
861 /* if we ran out of session, we need to restore our previously stored
862 * state.
864 if (context->slot != key->slot) {
865 newKey = pk11_CopyToSlot(context->slot,CKM_SSL3_SHA1_MAC,CKA_SIGN,key);
866 } else {
867 newKey = PK11_ReferenceSymKey(key);
870 context->init = PR_FALSE;
871 PK11_EnterContextMonitor(context);
872 if (!context->ownSession) {
873 rv = pk11_restoreContext(context,context->savedData,
874 context->savedLength);
875 if (rv != SECSuccess) {
876 PK11_ExitContextMonitor(context);
877 PK11_FreeSymKey(newKey);
878 return rv;
883 if (newKey == NULL) {
884 crv = CKR_KEY_TYPE_INCONSISTENT;
885 if (key->data.data) {
886 crv=PK11_GETTAB(context->slot)->C_DigestUpdate(context->session,
887 key->data.data,key->data.len);
889 } else {
890 crv=PK11_GETTAB(context->slot)->C_DigestKey(context->session,
891 newKey->objectID);
894 if (crv != CKR_OK) {
895 PORT_SetError( PK11_MapError(crv) );
896 rv = SECFailure;
900 * handle session starvation case.. use our last session to multiplex
902 if (!context->ownSession) {
903 context->savedData = pk11_saveContext(context,context->savedData,
904 &context->savedLength);
905 if (context->savedData == NULL) rv = SECFailure;
907 /* clear out out session for others to use */
908 pk11_Finalize(context);
910 PK11_ExitContextMonitor(context);
911 if (newKey) PK11_FreeSymKey(newKey);
912 return rv;
916 * externally callable version of the lowercase pk11_finalize().
918 SECStatus
919 PK11_Finalize(PK11Context *context) {
920 SECStatus rv;
922 PK11_EnterContextMonitor(context);
923 rv = pk11_Finalize(context);
924 PK11_ExitContextMonitor(context);
925 return rv;
929 * clean up a cipher operation, so the session can be used by
930 * someone new.
932 SECStatus
933 pk11_Finalize(PK11Context *context)
935 CK_ULONG count = 0;
936 CK_RV crv;
937 unsigned char stackBuf[256];
938 unsigned char *buffer = NULL;
940 if (!context->ownSession) {
941 return SECSuccess;
944 finalize:
945 switch (context->operation) {
946 case CKA_ENCRYPT:
947 crv=PK11_GETTAB(context->slot)->C_EncryptFinal(context->session,
948 buffer, &count);
949 break;
950 case CKA_DECRYPT:
951 crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session,
952 buffer, &count);
953 break;
954 case CKA_SIGN:
955 crv=PK11_GETTAB(context->slot)->C_SignFinal(context->session,
956 buffer, &count);
957 break;
958 case CKA_VERIFY:
959 crv=PK11_GETTAB(context->slot)->C_VerifyFinal(context->session,
960 buffer, count);
961 break;
962 case CKA_DIGEST:
963 crv=PK11_GETTAB(context->slot)->C_DigestFinal(context->session,
964 buffer, &count);
965 break;
966 default:
967 crv = CKR_OPERATION_NOT_INITIALIZED;
968 break;
971 if (crv != CKR_OK) {
972 if (buffer != stackBuf) {
973 PORT_Free(buffer);
975 if (crv == CKR_OPERATION_NOT_INITIALIZED) {
976 /* if there's no operation, it is finalized */
977 return SECSuccess;
979 PORT_SetError( PK11_MapError(crv) );
980 return SECFailure;
983 /* try to finalize the session with a buffer */
984 if (buffer == NULL) {
985 if (count <= sizeof stackBuf) {
986 buffer = stackBuf;
987 } else {
988 buffer = PORT_Alloc(count);
989 if (buffer == NULL) {
990 PORT_SetError(SEC_ERROR_NO_MEMORY);
991 return SECFailure;
994 goto finalize;
996 if (buffer != stackBuf) {
997 PORT_Free(buffer);
999 return SECSuccess;
1003 * Return the final digested or signed data...
1004 * this routine can either take pre initialized data, or allocate data
1005 * either out of an arena or out of the standard heap.
1007 SECStatus
1008 PK11_DigestFinal(PK11Context *context,unsigned char *data,
1009 unsigned int *outLen, unsigned int length)
1011 CK_ULONG len;
1012 CK_RV crv;
1013 SECStatus rv;
1016 /* if we ran out of session, we need to restore our previously stored
1017 * state.
1019 PK11_EnterContextMonitor(context);
1020 if (!context->ownSession) {
1021 rv = pk11_restoreContext(context,context->savedData,
1022 context->savedLength);
1023 if (rv != SECSuccess) {
1024 PK11_ExitContextMonitor(context);
1025 return rv;
1029 len = length;
1030 switch (context->operation) {
1031 case CKA_SIGN:
1032 crv=PK11_GETTAB(context->slot)->C_SignFinal(context->session,
1033 data,&len);
1034 break;
1035 case CKA_VERIFY:
1036 crv=PK11_GETTAB(context->slot)->C_VerifyFinal(context->session,
1037 data,len);
1038 break;
1039 case CKA_DIGEST:
1040 crv=PK11_GETTAB(context->slot)->C_DigestFinal(context->session,
1041 data,&len);
1042 break;
1043 case CKA_ENCRYPT:
1044 crv=PK11_GETTAB(context->slot)->C_EncryptFinal(context->session,
1045 data, &len);
1046 break;
1047 case CKA_DECRYPT:
1048 crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session,
1049 data, &len);
1050 break;
1051 default:
1052 crv = CKR_OPERATION_NOT_INITIALIZED;
1053 break;
1055 PK11_ExitContextMonitor(context);
1057 *outLen = (unsigned int) len;
1058 context->init = PR_FALSE; /* allow Begin to start up again */
1061 if (crv != CKR_OK) {
1062 PORT_SetError( PK11_MapError(crv) );
1063 return SECFailure;
1065 return SECSuccess;