security/nss/lib/pk11wrap/pk11cxt.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial