Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / security / nss / lib / pk11wrap / pk11cxt.c
blob6b18370283052a25bf16767de4714d78465b606c
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 PORT_SetError(SEC_ERROR_INVALID_ARGS);
295 context->param = NULL;
297 context->init = PR_FALSE;
298 context->sessionLock = PZ_NewLock(nssILockPK11cxt);
299 if ((context->param == NULL) || (context->sessionLock == NULL)) {
300 PK11_DestroyContext(context,PR_TRUE);
301 return NULL;
304 mech_info.mechanism = type;
305 mech_info.pParameter = param->data;
306 mech_info.ulParameterLen = param->len;
307 PK11_EnterContextMonitor(context);
308 rv = pk11_context_init(context,&mech_info);
309 PK11_ExitContextMonitor(context);
311 if (rv != SECSuccess) {
312 PK11_DestroyContext(context,PR_TRUE);
313 return NULL;
315 context->init = PR_TRUE;
316 return context;
321 * put together the various PK11_Create_Context calls used by different
322 * parts of libsec.
324 PK11Context *
325 __PK11_CreateContextByRawKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
326 PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key,
327 SECItem *param, void *wincx)
329 PK11SymKey *symKey = NULL;
330 PK11Context *context = NULL;
332 /* first get a slot */
333 if (slot == NULL) {
334 slot = PK11_GetBestSlot(type,wincx);
335 if (slot == NULL) {
336 PORT_SetError( SEC_ERROR_NO_MODULE );
337 goto loser;
339 } else {
340 PK11_ReferenceSlot(slot);
343 /* now import the key */
344 symKey = PK11_ImportSymKey(slot, type, origin, operation, key, wincx);
345 if (symKey == NULL) goto loser;
347 context = PK11_CreateContextBySymKey(type, operation, symKey, param);
349 loser:
350 if (symKey) {
351 PK11_FreeSymKey(symKey);
353 if (slot) {
354 PK11_FreeSlot(slot);
357 return context;
360 PK11Context *
361 PK11_CreateContextByRawKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
362 PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key,
363 SECItem *param, void *wincx)
365 return __PK11_CreateContextByRawKey(slot, type, origin, operation,
366 key, param, wincx);
371 * Create a context from a key. We really should make sure we aren't using
372 * the same key in multiple session!
374 PK11Context *
375 PK11_CreateContextBySymKey(CK_MECHANISM_TYPE type,CK_ATTRIBUTE_TYPE operation,
376 PK11SymKey *symKey, SECItem *param)
378 PK11SymKey *newKey;
379 PK11Context *context;
381 /* if this slot doesn't support the mechanism, go to a slot that does */
382 newKey = pk11_ForceSlot(symKey,type,operation);
383 if (newKey == NULL) {
384 PK11_ReferenceSymKey(symKey);
385 } else {
386 symKey = newKey;
390 /* Context Adopts the symKey.... */
391 context = pk11_CreateNewContextInSlot(type, symKey->slot, operation, symKey,
392 param);
393 PK11_FreeSymKey(symKey);
394 return context;
398 * Digest contexts don't need keys, but the do need to find a slot.
399 * Macing should use PK11_CreateContextBySymKey.
401 PK11Context *
402 PK11_CreateDigestContext(SECOidTag hashAlg)
404 /* digesting has to work without authentication to the slot */
405 CK_MECHANISM_TYPE type;
406 PK11SlotInfo *slot;
407 PK11Context *context;
408 SECItem param;
410 type = PK11_AlgtagToMechanism(hashAlg);
411 slot = PK11_GetBestSlot(type, NULL);
412 if (slot == NULL) {
413 PORT_SetError( SEC_ERROR_NO_MODULE );
414 return NULL;
417 /* maybe should really be PK11_GenerateNewParam?? */
418 param.data = NULL;
419 param.len = 0;
420 param.type = 0;
422 context = pk11_CreateNewContextInSlot(type, slot, CKA_DIGEST, NULL, &param);
423 PK11_FreeSlot(slot);
424 return context;
428 * create a new context which is the clone of the state of old context.
430 PK11Context * PK11_CloneContext(PK11Context *old)
432 PK11Context *newcx;
433 PRBool needFree = PR_FALSE;
434 SECStatus rv = SECSuccess;
435 void *data;
436 unsigned long len;
438 newcx = pk11_CreateNewContextInSlot(old->type, old->slot, old->operation,
439 old->key, old->param);
440 if (newcx == NULL) return NULL;
442 /* now clone the save state. First we need to find the save state
443 * of the old session. If the old context owns it's session,
444 * the state needs to be saved, otherwise the state is in saveData. */
445 if (old->ownSession) {
446 PK11_EnterContextMonitor(old);
447 data=pk11_saveContext(old,NULL,&len);
448 PK11_ExitContextMonitor(old);
449 needFree = PR_TRUE;
450 } else {
451 data = old->savedData;
452 len = old->savedLength;
455 if (data == NULL) {
456 PK11_DestroyContext(newcx,PR_TRUE);
457 return NULL;
460 /* now copy that state into our new context. Again we have different
461 * work if the new context owns it's own session. If it does, we
462 * restore the state gathered above. If it doesn't, we copy the
463 * saveData pointer... */
464 if (newcx->ownSession) {
465 PK11_EnterContextMonitor(newcx);
466 rv = pk11_restoreContext(newcx,data,len);
467 PK11_ExitContextMonitor(newcx);
468 } else {
469 PORT_Assert(newcx->savedData != NULL);
470 if ((newcx->savedData == NULL) || (newcx->savedLength < len)) {
471 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
472 rv = SECFailure;
473 } else {
474 PORT_Memcpy(newcx->savedData,data,len);
475 newcx->savedLength = len;
479 if (needFree) PORT_Free(data);
481 if (rv != SECSuccess) {
482 PK11_DestroyContext(newcx,PR_TRUE);
483 return NULL;
485 return newcx;
489 * save the current context state into a variable. Required to make FORTEZZA
490 * work.
492 SECStatus
493 PK11_SaveContext(PK11Context *cx,unsigned char *save,int *len, int saveLength)
495 unsigned char * data = NULL;
496 CK_ULONG length = saveLength;
498 if (cx->ownSession) {
499 PK11_EnterContextMonitor(cx);
500 data = pk11_saveContextHelper(cx, save, &length);
501 PK11_ExitContextMonitor(cx);
502 if (data) *len = length;
503 } else if ((unsigned) saveLength >= cx->savedLength) {
504 data = (unsigned char*)cx->savedData;
505 if (cx->savedData) {
506 PORT_Memcpy(save,cx->savedData,cx->savedLength);
508 *len = cx->savedLength;
510 if (data != NULL) {
511 if (cx->ownSession) {
512 PORT_ZFree(data, length);
514 return SECSuccess;
515 } else {
516 return SECFailure;
520 /* same as above, but may allocate the return buffer. */
521 unsigned char *
522 PK11_SaveContextAlloc(PK11Context *cx,
523 unsigned char *preAllocBuf, unsigned int pabLen,
524 unsigned int *stateLen)
526 unsigned char *stateBuf = NULL;
527 unsigned long length = (unsigned long)pabLen;
529 if (cx->ownSession) {
530 PK11_EnterContextMonitor(cx);
531 stateBuf = pk11_saveContextHelper(cx, preAllocBuf, &length);
532 PK11_ExitContextMonitor(cx);
533 *stateLen = (stateBuf != NULL) ? length : 0;
534 } else {
535 if (pabLen < cx->savedLength) {
536 stateBuf = (unsigned char *)PORT_Alloc(cx->savedLength);
537 if (!stateBuf) {
538 return (unsigned char *)NULL;
540 } else {
541 stateBuf = preAllocBuf;
543 if (cx->savedData) {
544 PORT_Memcpy(stateBuf, cx->savedData, cx->savedLength);
546 *stateLen = cx->savedLength;
548 return stateBuf;
552 * restore the context state into a new running context. Also required for
553 * FORTEZZA .
555 SECStatus
556 PK11_RestoreContext(PK11Context *cx,unsigned char *save,int len)
558 SECStatus rv = SECSuccess;
559 if (cx->ownSession) {
560 PK11_EnterContextMonitor(cx);
561 pk11_Finalize(cx);
562 rv = pk11_restoreContext(cx,save,len);
563 PK11_ExitContextMonitor(cx);
564 } else {
565 PORT_Assert(cx->savedData != NULL);
566 if ((cx->savedData == NULL) || (cx->savedLength < (unsigned) len)) {
567 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
568 rv = SECFailure;
569 } else {
570 PORT_Memcpy(cx->savedData,save,len);
571 cx->savedLength = len;
574 return rv;
578 * This is to get FIPS compliance until we can convert
579 * libjar to use PK11_ hashing functions. It returns PR_FALSE
580 * if we can't get a PK11 Context.
582 PRBool
583 PK11_HashOK(SECOidTag algID) {
584 PK11Context *cx;
586 cx = PK11_CreateDigestContext(algID);
587 if (cx == NULL) return PR_FALSE;
588 PK11_DestroyContext(cx, PR_TRUE);
589 return PR_TRUE;
595 * start a new digesting or Mac'ing operation on this context
597 SECStatus PK11_DigestBegin(PK11Context *cx)
599 CK_MECHANISM mech_info;
600 SECStatus rv;
602 if (cx->init == PR_TRUE) {
603 return SECSuccess;
607 * make sure the old context is clear first
609 PK11_EnterContextMonitor(cx);
610 pk11_Finalize(cx);
612 mech_info.mechanism = cx->type;
613 mech_info.pParameter = cx->param->data;
614 mech_info.ulParameterLen = cx->param->len;
615 rv = pk11_context_init(cx,&mech_info);
616 PK11_ExitContextMonitor(cx);
618 if (rv != SECSuccess) {
619 return SECFailure;
621 cx->init = PR_TRUE;
622 return SECSuccess;
625 SECStatus
626 PK11_HashBuf(SECOidTag hashAlg, unsigned char *out, unsigned char *in,
627 PRInt32 len) {
628 PK11Context *context;
629 unsigned int max_length;
630 unsigned int out_length;
631 SECStatus rv;
633 /* len will be passed to PK11_DigestOp as unsigned. */
634 if (len < 0) {
635 PORT_SetError(SEC_ERROR_INVALID_ARGS);
636 return SECFailure;
639 context = PK11_CreateDigestContext(hashAlg);
640 if (context == NULL) return SECFailure;
642 rv = PK11_DigestBegin(context);
643 if (rv != SECSuccess) {
644 PK11_DestroyContext(context, PR_TRUE);
645 return rv;
648 rv = PK11_DigestOp(context, in, len);
649 if (rv != SECSuccess) {
650 PK11_DestroyContext(context, PR_TRUE);
651 return rv;
654 /* XXX This really should have been an argument to this function! */
655 max_length = HASH_ResultLenByOidTag(hashAlg);
656 PORT_Assert(max_length);
657 if (!max_length)
658 max_length = HASH_LENGTH_MAX;
660 rv = PK11_DigestFinal(context,out,&out_length,max_length);
661 PK11_DestroyContext(context, PR_TRUE);
662 return rv;
667 * execute a bulk encryption operation
669 SECStatus
670 PK11_CipherOp(PK11Context *context, unsigned char * out, int *outlen,
671 int maxout, unsigned char *in, int inlen)
673 CK_RV crv = CKR_OK;
674 CK_ULONG length = maxout;
675 CK_ULONG offset =0;
676 SECStatus rv = SECSuccess;
677 unsigned char *saveOut = out;
678 unsigned char *allocOut = NULL;
680 /* if we ran out of session, we need to restore our previously stored
681 * state.
683 PK11_EnterContextMonitor(context);
684 if (!context->ownSession) {
685 rv = pk11_restoreContext(context,context->savedData,
686 context->savedLength);
687 if (rv != SECSuccess) {
688 PK11_ExitContextMonitor(context);
689 return rv;
694 * The fortezza hack is to send 8 extra bytes on the first encrypted and
695 * loose them on the first decrypt.
697 if (context->fortezzaHack) {
698 unsigned char random[8];
699 if (context->operation == CKA_ENCRYPT) {
700 PK11_ExitContextMonitor(context);
701 rv = PK11_GenerateRandom(random,sizeof(random));
702 PK11_EnterContextMonitor(context);
704 /* since we are offseting the output, we can't encrypt back into
705 * the same buffer... allocate a temporary buffer just for this
706 * call. */
707 allocOut = out = (unsigned char*)PORT_Alloc(maxout);
708 if (out == NULL) {
709 PK11_ExitContextMonitor(context);
710 return SECFailure;
712 crv = PK11_GETTAB(context->slot)->C_EncryptUpdate(context->session,
713 random,sizeof(random),out,&length);
715 out += length;
716 maxout -= length;
717 offset = length;
718 } else if (context->operation == CKA_DECRYPT) {
719 length = sizeof(random);
720 crv = PK11_GETTAB(context->slot)->C_DecryptUpdate(context->session,
721 in,sizeof(random),random,&length);
722 inlen -= length;
723 in += length;
724 context->fortezzaHack = PR_FALSE;
728 switch (context->operation) {
729 case CKA_ENCRYPT:
730 length = maxout;
731 crv=PK11_GETTAB(context->slot)->C_EncryptUpdate(context->session,
732 in, inlen, out, &length);
733 length += offset;
734 break;
735 case CKA_DECRYPT:
736 length = maxout;
737 crv=PK11_GETTAB(context->slot)->C_DecryptUpdate(context->session,
738 in, inlen, out, &length);
739 break;
740 default:
741 crv = CKR_OPERATION_NOT_INITIALIZED;
742 break;
745 if (crv != CKR_OK) {
746 PORT_SetError( PK11_MapError(crv) );
747 *outlen = 0;
748 rv = SECFailure;
749 } else {
750 *outlen = length;
753 if (context->fortezzaHack) {
754 if (context->operation == CKA_ENCRYPT) {
755 PORT_Assert(allocOut);
756 PORT_Memcpy(saveOut, allocOut, length);
757 PORT_Free(allocOut);
759 context->fortezzaHack = PR_FALSE;
763 * handle session starvation case.. use our last session to multiplex
765 if (!context->ownSession) {
766 context->savedData = pk11_saveContext(context,context->savedData,
767 &context->savedLength);
768 if (context->savedData == NULL) rv = SECFailure;
770 /* clear out out session for others to use */
771 pk11_Finalize(context);
773 PK11_ExitContextMonitor(context);
774 return rv;
778 * execute a digest/signature operation
780 SECStatus
781 PK11_DigestOp(PK11Context *context, const unsigned char * in, unsigned inLen)
783 CK_RV crv = CKR_OK;
784 SECStatus rv = SECSuccess;
786 if (!in) {
787 PORT_SetError(SEC_ERROR_INVALID_ARGS);
788 return SECFailure;
791 /* if we ran out of session, we need to restore our previously stored
792 * state.
794 context->init = PR_FALSE;
795 PK11_EnterContextMonitor(context);
796 if (!context->ownSession) {
797 rv = pk11_restoreContext(context,context->savedData,
798 context->savedLength);
799 if (rv != SECSuccess) {
800 PK11_ExitContextMonitor(context);
801 return rv;
805 switch (context->operation) {
806 /* also for MAC'ing */
807 case CKA_SIGN:
808 crv=PK11_GETTAB(context->slot)->C_SignUpdate(context->session,
809 (unsigned char *)in,
810 inLen);
811 break;
812 case CKA_VERIFY:
813 crv=PK11_GETTAB(context->slot)->C_VerifyUpdate(context->session,
814 (unsigned char *)in,
815 inLen);
816 break;
817 case CKA_DIGEST:
818 crv=PK11_GETTAB(context->slot)->C_DigestUpdate(context->session,
819 (unsigned char *)in,
820 inLen);
821 break;
822 default:
823 crv = CKR_OPERATION_NOT_INITIALIZED;
824 break;
827 if (crv != CKR_OK) {
828 PORT_SetError( PK11_MapError(crv) );
829 rv = SECFailure;
833 * handle session starvation case.. use our last session to multiplex
835 if (!context->ownSession) {
836 context->savedData = pk11_saveContext(context,context->savedData,
837 &context->savedLength);
838 if (context->savedData == NULL) rv = SECFailure;
840 /* clear out out session for others to use */
841 pk11_Finalize(context);
843 PK11_ExitContextMonitor(context);
844 return rv;
848 * Digest a key if possible./
850 SECStatus
851 PK11_DigestKey(PK11Context *context, PK11SymKey *key)
853 CK_RV crv = CKR_OK;
854 SECStatus rv = SECSuccess;
855 PK11SymKey *newKey = NULL;
857 if (!context || !key) {
858 PORT_SetError(SEC_ERROR_INVALID_ARGS);
859 return SECFailure;
862 /* if we ran out of session, we need to restore our previously stored
863 * state.
865 if (context->slot != key->slot) {
866 newKey = pk11_CopyToSlot(context->slot,CKM_SSL3_SHA1_MAC,CKA_SIGN,key);
867 } else {
868 newKey = PK11_ReferenceSymKey(key);
871 context->init = PR_FALSE;
872 PK11_EnterContextMonitor(context);
873 if (!context->ownSession) {
874 rv = pk11_restoreContext(context,context->savedData,
875 context->savedLength);
876 if (rv != SECSuccess) {
877 PK11_ExitContextMonitor(context);
878 PK11_FreeSymKey(newKey);
879 return rv;
884 if (newKey == NULL) {
885 crv = CKR_KEY_TYPE_INCONSISTENT;
886 if (key->data.data) {
887 crv=PK11_GETTAB(context->slot)->C_DigestUpdate(context->session,
888 key->data.data,key->data.len);
890 } else {
891 crv=PK11_GETTAB(context->slot)->C_DigestKey(context->session,
892 newKey->objectID);
895 if (crv != CKR_OK) {
896 PORT_SetError( PK11_MapError(crv) );
897 rv = SECFailure;
901 * handle session starvation case.. use our last session to multiplex
903 if (!context->ownSession) {
904 context->savedData = pk11_saveContext(context,context->savedData,
905 &context->savedLength);
906 if (context->savedData == NULL) rv = SECFailure;
908 /* clear out out session for others to use */
909 pk11_Finalize(context);
911 PK11_ExitContextMonitor(context);
912 if (newKey) PK11_FreeSymKey(newKey);
913 return rv;
917 * externally callable version of the lowercase pk11_finalize().
919 SECStatus
920 PK11_Finalize(PK11Context *context) {
921 SECStatus rv;
923 PK11_EnterContextMonitor(context);
924 rv = pk11_Finalize(context);
925 PK11_ExitContextMonitor(context);
926 return rv;
930 * clean up a cipher operation, so the session can be used by
931 * someone new.
933 SECStatus
934 pk11_Finalize(PK11Context *context)
936 CK_ULONG count = 0;
937 CK_RV crv;
938 unsigned char stackBuf[256];
939 unsigned char *buffer = NULL;
941 if (!context->ownSession) {
942 return SECSuccess;
945 finalize:
946 switch (context->operation) {
947 case CKA_ENCRYPT:
948 crv=PK11_GETTAB(context->slot)->C_EncryptFinal(context->session,
949 buffer, &count);
950 break;
951 case CKA_DECRYPT:
952 crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session,
953 buffer, &count);
954 break;
955 case CKA_SIGN:
956 crv=PK11_GETTAB(context->slot)->C_SignFinal(context->session,
957 buffer, &count);
958 break;
959 case CKA_VERIFY:
960 crv=PK11_GETTAB(context->slot)->C_VerifyFinal(context->session,
961 buffer, count);
962 break;
963 case CKA_DIGEST:
964 crv=PK11_GETTAB(context->slot)->C_DigestFinal(context->session,
965 buffer, &count);
966 break;
967 default:
968 crv = CKR_OPERATION_NOT_INITIALIZED;
969 break;
972 if (crv != CKR_OK) {
973 if (buffer != stackBuf) {
974 PORT_Free(buffer);
976 if (crv == CKR_OPERATION_NOT_INITIALIZED) {
977 /* if there's no operation, it is finalized */
978 return SECSuccess;
980 PORT_SetError( PK11_MapError(crv) );
981 return SECFailure;
984 /* try to finalize the session with a buffer */
985 if (buffer == NULL) {
986 if (count <= sizeof stackBuf) {
987 buffer = stackBuf;
988 } else {
989 buffer = PORT_Alloc(count);
990 if (buffer == NULL) {
991 PORT_SetError(SEC_ERROR_NO_MEMORY);
992 return SECFailure;
995 goto finalize;
997 if (buffer != stackBuf) {
998 PORT_Free(buffer);
1000 return SECSuccess;
1004 * Return the final digested or signed data...
1005 * this routine can either take pre initialized data, or allocate data
1006 * either out of an arena or out of the standard heap.
1008 SECStatus
1009 PK11_DigestFinal(PK11Context *context,unsigned char *data,
1010 unsigned int *outLen, unsigned int length)
1012 CK_ULONG len;
1013 CK_RV crv;
1014 SECStatus rv;
1017 /* if we ran out of session, we need to restore our previously stored
1018 * state.
1020 PK11_EnterContextMonitor(context);
1021 if (!context->ownSession) {
1022 rv = pk11_restoreContext(context,context->savedData,
1023 context->savedLength);
1024 if (rv != SECSuccess) {
1025 PK11_ExitContextMonitor(context);
1026 return rv;
1030 len = length;
1031 switch (context->operation) {
1032 case CKA_SIGN:
1033 crv=PK11_GETTAB(context->slot)->C_SignFinal(context->session,
1034 data,&len);
1035 break;
1036 case CKA_VERIFY:
1037 crv=PK11_GETTAB(context->slot)->C_VerifyFinal(context->session,
1038 data,len);
1039 break;
1040 case CKA_DIGEST:
1041 crv=PK11_GETTAB(context->slot)->C_DigestFinal(context->session,
1042 data,&len);
1043 break;
1044 case CKA_ENCRYPT:
1045 crv=PK11_GETTAB(context->slot)->C_EncryptFinal(context->session,
1046 data, &len);
1047 break;
1048 case CKA_DECRYPT:
1049 crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session,
1050 data, &len);
1051 break;
1052 default:
1053 crv = CKR_OPERATION_NOT_INITIALIZED;
1054 break;
1056 PK11_ExitContextMonitor(context);
1058 *outLen = (unsigned int) len;
1059 context->init = PR_FALSE; /* allow Begin to start up again */
1062 if (crv != CKR_OK) {
1063 PORT_SetError( PK11_MapError(crv) );
1064 return SECFailure;
1066 return SECSuccess;