1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/pk11wrap/pk11cxt.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1042 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +/* 1.8 + * This file PK11Contexts which are used in multipart hashing, 1.9 + * encryption/decryption, and signing/verication operations. 1.10 + */ 1.11 + 1.12 +#include "seccomon.h" 1.13 +#include "secmod.h" 1.14 +#include "nssilock.h" 1.15 +#include "secmodi.h" 1.16 +#include "secmodti.h" 1.17 +#include "pkcs11.h" 1.18 +#include "pk11func.h" 1.19 +#include "secitem.h" 1.20 +#include "secoid.h" 1.21 +#include "sechash.h" 1.22 +#include "secerr.h" 1.23 + 1.24 +static const SECItem pk11_null_params = { 0 }; 1.25 + 1.26 +/********************************************************************** 1.27 + * 1.28 + * Now Deal with Crypto Contexts 1.29 + * 1.30 + **********************************************************************/ 1.31 + 1.32 +/* 1.33 + * the monitors... 1.34 + */ 1.35 +void 1.36 +PK11_EnterContextMonitor(PK11Context *cx) { 1.37 + /* if we own the session and our slot is ThreadSafe, only monitor 1.38 + * the Context */ 1.39 + if ((cx->ownSession) && (cx->slot->isThreadSafe)) { 1.40 + /* Should this use monitors instead? */ 1.41 + PZ_Lock(cx->sessionLock); 1.42 + } else { 1.43 + PK11_EnterSlotMonitor(cx->slot); 1.44 + } 1.45 +} 1.46 + 1.47 +void 1.48 +PK11_ExitContextMonitor(PK11Context *cx) { 1.49 + /* if we own the session and our slot is ThreadSafe, only monitor 1.50 + * the Context */ 1.51 + if ((cx->ownSession) && (cx->slot->isThreadSafe)) { 1.52 + /* Should this use monitors instead? */ 1.53 + PZ_Unlock(cx->sessionLock); 1.54 + } else { 1.55 + PK11_ExitSlotMonitor(cx->slot); 1.56 + } 1.57 +} 1.58 + 1.59 +/* 1.60 + * Free up a Cipher Context 1.61 + */ 1.62 +void 1.63 +PK11_DestroyContext(PK11Context *context, PRBool freeit) 1.64 +{ 1.65 + pk11_CloseSession(context->slot,context->session,context->ownSession); 1.66 + /* initialize the critical fields of the context */ 1.67 + if (context->savedData != NULL ) PORT_Free(context->savedData); 1.68 + if (context->key) PK11_FreeSymKey(context->key); 1.69 + if (context->param && context->param != &pk11_null_params) 1.70 + SECITEM_FreeItem(context->param, PR_TRUE); 1.71 + if (context->sessionLock) PZ_DestroyLock(context->sessionLock); 1.72 + PK11_FreeSlot(context->slot); 1.73 + if (freeit) PORT_Free(context); 1.74 +} 1.75 + 1.76 +/* 1.77 + * save the current context. Allocate Space if necessary. 1.78 + */ 1.79 +static unsigned char * 1.80 +pk11_saveContextHelper(PK11Context *context, unsigned char *buffer, 1.81 + unsigned long *savedLength) 1.82 +{ 1.83 + CK_RV crv; 1.84 + 1.85 + /* If buffer is NULL, this will get the length */ 1.86 + crv = PK11_GETTAB(context->slot)->C_GetOperationState(context->session, 1.87 + (CK_BYTE_PTR)buffer, 1.88 + savedLength); 1.89 + if (!buffer || (crv == CKR_BUFFER_TOO_SMALL)) { 1.90 + /* the given buffer wasn't big enough (or was NULL), but we 1.91 + * have the length, so try again with a new buffer and the 1.92 + * correct length 1.93 + */ 1.94 + unsigned long bufLen = *savedLength; 1.95 + buffer = PORT_Alloc(bufLen); 1.96 + if (buffer == NULL) { 1.97 + return (unsigned char *)NULL; 1.98 + } 1.99 + crv = PK11_GETTAB(context->slot)->C_GetOperationState( 1.100 + context->session, 1.101 + (CK_BYTE_PTR)buffer, 1.102 + savedLength); 1.103 + if (crv != CKR_OK) { 1.104 + PORT_ZFree(buffer, bufLen); 1.105 + } 1.106 + } 1.107 + if (crv != CKR_OK) { 1.108 + PORT_SetError( PK11_MapError(crv) ); 1.109 + return (unsigned char *)NULL; 1.110 + } 1.111 + return buffer; 1.112 +} 1.113 + 1.114 +void * 1.115 +pk11_saveContext(PK11Context *context, void *space, unsigned long *savedLength) 1.116 +{ 1.117 + return pk11_saveContextHelper(context, 1.118 + (unsigned char *)space, savedLength); 1.119 +} 1.120 + 1.121 +/* 1.122 + * restore the current context 1.123 + */ 1.124 +SECStatus 1.125 +pk11_restoreContext(PK11Context *context,void *space, unsigned long savedLength) 1.126 +{ 1.127 + CK_RV crv; 1.128 + CK_OBJECT_HANDLE objectID = (context->key) ? context->key->objectID: 1.129 + CK_INVALID_HANDLE; 1.130 + 1.131 + PORT_Assert(space != NULL); 1.132 + if (space == NULL) { 1.133 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.134 + return SECFailure; 1.135 + } 1.136 + crv = PK11_GETTAB(context->slot)->C_SetOperationState(context->session, 1.137 + (CK_BYTE_PTR)space, savedLength, objectID, 0); 1.138 + if (crv != CKR_OK) { 1.139 + PORT_SetError( PK11_MapError(crv)); 1.140 + return SECFailure; 1.141 + } 1.142 + return SECSuccess; 1.143 +} 1.144 + 1.145 +SECStatus pk11_Finalize(PK11Context *context); 1.146 + 1.147 +/* 1.148 + * Context initialization. Used by all flavors of CreateContext 1.149 + */ 1.150 +static SECStatus 1.151 +pk11_context_init(PK11Context *context, CK_MECHANISM *mech_info) 1.152 +{ 1.153 + CK_RV crv; 1.154 + PK11SymKey *symKey = context->key; 1.155 + SECStatus rv = SECSuccess; 1.156 + 1.157 + switch (context->operation) { 1.158 + case CKA_ENCRYPT: 1.159 + crv=PK11_GETTAB(context->slot)->C_EncryptInit(context->session, 1.160 + mech_info, symKey->objectID); 1.161 + break; 1.162 + case CKA_DECRYPT: 1.163 + if (context->fortezzaHack) { 1.164 + CK_ULONG count = 0;; 1.165 + /* generate the IV for fortezza */ 1.166 + crv=PK11_GETTAB(context->slot)->C_EncryptInit(context->session, 1.167 + mech_info, symKey->objectID); 1.168 + if (crv != CKR_OK) break; 1.169 + PK11_GETTAB(context->slot)->C_EncryptFinal(context->session, 1.170 + NULL, &count); 1.171 + } 1.172 + crv=PK11_GETTAB(context->slot)->C_DecryptInit(context->session, 1.173 + mech_info, symKey->objectID); 1.174 + break; 1.175 + case CKA_SIGN: 1.176 + crv=PK11_GETTAB(context->slot)->C_SignInit(context->session, 1.177 + mech_info, symKey->objectID); 1.178 + break; 1.179 + case CKA_VERIFY: 1.180 + crv=PK11_GETTAB(context->slot)->C_SignInit(context->session, 1.181 + mech_info, symKey->objectID); 1.182 + break; 1.183 + case CKA_DIGEST: 1.184 + crv=PK11_GETTAB(context->slot)->C_DigestInit(context->session, 1.185 + mech_info); 1.186 + break; 1.187 + default: 1.188 + crv = CKR_OPERATION_NOT_INITIALIZED; 1.189 + break; 1.190 + } 1.191 + 1.192 + if (crv != CKR_OK) { 1.193 + PORT_SetError( PK11_MapError(crv) ); 1.194 + return SECFailure; 1.195 + } 1.196 + 1.197 + /* 1.198 + * handle session starvation case.. use our last session to multiplex 1.199 + */ 1.200 + if (!context->ownSession) { 1.201 + context->savedData = pk11_saveContext(context,context->savedData, 1.202 + &context->savedLength); 1.203 + if (context->savedData == NULL) rv = SECFailure; 1.204 + /* clear out out session for others to use */ 1.205 + pk11_Finalize(context); 1.206 + } 1.207 + return rv; 1.208 +} 1.209 + 1.210 + 1.211 +/* 1.212 + * Common Helper Function do come up with a new context. 1.213 + */ 1.214 +static PK11Context *pk11_CreateNewContextInSlot(CK_MECHANISM_TYPE type, 1.215 + PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey, 1.216 + SECItem *param) 1.217 +{ 1.218 + CK_MECHANISM mech_info; 1.219 + PK11Context *context; 1.220 + SECStatus rv; 1.221 + 1.222 + PORT_Assert(slot != NULL); 1.223 + if (!slot || (!symKey && ((operation != CKA_DIGEST) || 1.224 + (type == CKM_SKIPJACK_CBC64)))) { 1.225 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.226 + return NULL; 1.227 + } 1.228 + context = (PK11Context *) PORT_Alloc(sizeof(PK11Context)); 1.229 + if (context == NULL) { 1.230 + return NULL; 1.231 + } 1.232 + 1.233 + /* now deal with the fortezza hack... the fortezza hack is an attempt 1.234 + * to get around the issue of the card not allowing you to do a FORTEZZA 1.235 + * LoadIV/Encrypt, which was added because such a combination could be 1.236 + * use to circumvent the key escrow system. Unfortunately SSL needs to 1.237 + * do this kind of operation, so in SSL we do a loadIV (to verify it), 1.238 + * Then GenerateIV, and through away the first 8 bytes on either side 1.239 + * of the connection.*/ 1.240 + context->fortezzaHack = PR_FALSE; 1.241 + if (type == CKM_SKIPJACK_CBC64) { 1.242 + if (symKey->origin == PK11_OriginFortezzaHack) { 1.243 + context->fortezzaHack = PR_TRUE; 1.244 + } 1.245 + } 1.246 + 1.247 + /* initialize the critical fields of the context */ 1.248 + context->operation = operation; 1.249 + context->key = symKey ? PK11_ReferenceSymKey(symKey) : NULL; 1.250 + context->slot = PK11_ReferenceSlot(slot); 1.251 + context->session = pk11_GetNewSession(slot,&context->ownSession); 1.252 + context->cx = symKey ? symKey->cx : NULL; 1.253 + /* get our session */ 1.254 + context->savedData = NULL; 1.255 + 1.256 + /* save the parameters so that some digesting stuff can do multiple 1.257 + * begins on a single context */ 1.258 + context->type = type; 1.259 + if (param) { 1.260 + if (param->len > 0) { 1.261 + context->param = SECITEM_DupItem(param); 1.262 + } else { 1.263 + context->param = (SECItem *)&pk11_null_params; 1.264 + } 1.265 + } else { 1.266 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.267 + context->param = NULL; 1.268 + } 1.269 + context->init = PR_FALSE; 1.270 + context->sessionLock = PZ_NewLock(nssILockPK11cxt); 1.271 + if ((context->param == NULL) || (context->sessionLock == NULL)) { 1.272 + PK11_DestroyContext(context,PR_TRUE); 1.273 + return NULL; 1.274 + } 1.275 + 1.276 + mech_info.mechanism = type; 1.277 + mech_info.pParameter = param->data; 1.278 + mech_info.ulParameterLen = param->len; 1.279 + PK11_EnterContextMonitor(context); 1.280 + rv = pk11_context_init(context,&mech_info); 1.281 + PK11_ExitContextMonitor(context); 1.282 + 1.283 + if (rv != SECSuccess) { 1.284 + PK11_DestroyContext(context,PR_TRUE); 1.285 + return NULL; 1.286 + } 1.287 + context->init = PR_TRUE; 1.288 + return context; 1.289 +} 1.290 + 1.291 + 1.292 +/* 1.293 + * put together the various PK11_Create_Context calls used by different 1.294 + * parts of libsec. 1.295 + */ 1.296 +PK11Context * 1.297 +__PK11_CreateContextByRawKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, 1.298 + PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key, 1.299 + SECItem *param, void *wincx) 1.300 +{ 1.301 + PK11SymKey *symKey = NULL; 1.302 + PK11Context *context = NULL; 1.303 + 1.304 + /* first get a slot */ 1.305 + if (slot == NULL) { 1.306 + slot = PK11_GetBestSlot(type,wincx); 1.307 + if (slot == NULL) { 1.308 + PORT_SetError( SEC_ERROR_NO_MODULE ); 1.309 + goto loser; 1.310 + } 1.311 + } else { 1.312 + PK11_ReferenceSlot(slot); 1.313 + } 1.314 + 1.315 + /* now import the key */ 1.316 + symKey = PK11_ImportSymKey(slot, type, origin, operation, key, wincx); 1.317 + if (symKey == NULL) goto loser; 1.318 + 1.319 + context = PK11_CreateContextBySymKey(type, operation, symKey, param); 1.320 + 1.321 +loser: 1.322 + if (symKey) { 1.323 + PK11_FreeSymKey(symKey); 1.324 + } 1.325 + if (slot) { 1.326 + PK11_FreeSlot(slot); 1.327 + } 1.328 + 1.329 + return context; 1.330 +} 1.331 + 1.332 +PK11Context * 1.333 +PK11_CreateContextByRawKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, 1.334 + PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key, 1.335 + SECItem *param, void *wincx) 1.336 +{ 1.337 + return __PK11_CreateContextByRawKey(slot, type, origin, operation, 1.338 + key, param, wincx); 1.339 +} 1.340 + 1.341 + 1.342 +/* 1.343 + * Create a context from a key. We really should make sure we aren't using 1.344 + * the same key in multiple session! 1.345 + */ 1.346 +PK11Context * 1.347 +PK11_CreateContextBySymKey(CK_MECHANISM_TYPE type,CK_ATTRIBUTE_TYPE operation, 1.348 + PK11SymKey *symKey, SECItem *param) 1.349 +{ 1.350 + PK11SymKey *newKey; 1.351 + PK11Context *context; 1.352 + 1.353 + /* if this slot doesn't support the mechanism, go to a slot that does */ 1.354 + newKey = pk11_ForceSlot(symKey,type,operation); 1.355 + if (newKey == NULL) { 1.356 + PK11_ReferenceSymKey(symKey); 1.357 + } else { 1.358 + symKey = newKey; 1.359 + } 1.360 + 1.361 + 1.362 + /* Context Adopts the symKey.... */ 1.363 + context = pk11_CreateNewContextInSlot(type, symKey->slot, operation, symKey, 1.364 + param); 1.365 + PK11_FreeSymKey(symKey); 1.366 + return context; 1.367 +} 1.368 + 1.369 +/* 1.370 + * Digest contexts don't need keys, but the do need to find a slot. 1.371 + * Macing should use PK11_CreateContextBySymKey. 1.372 + */ 1.373 +PK11Context * 1.374 +PK11_CreateDigestContext(SECOidTag hashAlg) 1.375 +{ 1.376 + /* digesting has to work without authentication to the slot */ 1.377 + CK_MECHANISM_TYPE type; 1.378 + PK11SlotInfo *slot; 1.379 + PK11Context *context; 1.380 + SECItem param; 1.381 + 1.382 + type = PK11_AlgtagToMechanism(hashAlg); 1.383 + slot = PK11_GetBestSlot(type, NULL); 1.384 + if (slot == NULL) { 1.385 + PORT_SetError( SEC_ERROR_NO_MODULE ); 1.386 + return NULL; 1.387 + } 1.388 + 1.389 + /* maybe should really be PK11_GenerateNewParam?? */ 1.390 + param.data = NULL; 1.391 + param.len = 0; 1.392 + param.type = 0; 1.393 + 1.394 + context = pk11_CreateNewContextInSlot(type, slot, CKA_DIGEST, NULL, ¶m); 1.395 + PK11_FreeSlot(slot); 1.396 + return context; 1.397 +} 1.398 + 1.399 +/* 1.400 + * create a new context which is the clone of the state of old context. 1.401 + */ 1.402 +PK11Context * PK11_CloneContext(PK11Context *old) 1.403 +{ 1.404 + PK11Context *newcx; 1.405 + PRBool needFree = PR_FALSE; 1.406 + SECStatus rv = SECSuccess; 1.407 + void *data; 1.408 + unsigned long len; 1.409 + 1.410 + newcx = pk11_CreateNewContextInSlot(old->type, old->slot, old->operation, 1.411 + old->key, old->param); 1.412 + if (newcx == NULL) return NULL; 1.413 + 1.414 + /* now clone the save state. First we need to find the save state 1.415 + * of the old session. If the old context owns it's session, 1.416 + * the state needs to be saved, otherwise the state is in saveData. */ 1.417 + if (old->ownSession) { 1.418 + PK11_EnterContextMonitor(old); 1.419 + data=pk11_saveContext(old,NULL,&len); 1.420 + PK11_ExitContextMonitor(old); 1.421 + needFree = PR_TRUE; 1.422 + } else { 1.423 + data = old->savedData; 1.424 + len = old->savedLength; 1.425 + } 1.426 + 1.427 + if (data == NULL) { 1.428 + PK11_DestroyContext(newcx,PR_TRUE); 1.429 + return NULL; 1.430 + } 1.431 + 1.432 + /* now copy that state into our new context. Again we have different 1.433 + * work if the new context owns it's own session. If it does, we 1.434 + * restore the state gathered above. If it doesn't, we copy the 1.435 + * saveData pointer... */ 1.436 + if (newcx->ownSession) { 1.437 + PK11_EnterContextMonitor(newcx); 1.438 + rv = pk11_restoreContext(newcx,data,len); 1.439 + PK11_ExitContextMonitor(newcx); 1.440 + } else { 1.441 + PORT_Assert(newcx->savedData != NULL); 1.442 + if ((newcx->savedData == NULL) || (newcx->savedLength < len)) { 1.443 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.444 + rv = SECFailure; 1.445 + } else { 1.446 + PORT_Memcpy(newcx->savedData,data,len); 1.447 + newcx->savedLength = len; 1.448 + } 1.449 + } 1.450 + 1.451 + if (needFree) PORT_Free(data); 1.452 + 1.453 + if (rv != SECSuccess) { 1.454 + PK11_DestroyContext(newcx,PR_TRUE); 1.455 + return NULL; 1.456 + } 1.457 + return newcx; 1.458 +} 1.459 + 1.460 +/* 1.461 + * save the current context state into a variable. Required to make FORTEZZA 1.462 + * work. 1.463 + */ 1.464 +SECStatus 1.465 +PK11_SaveContext(PK11Context *cx,unsigned char *save,int *len, int saveLength) 1.466 +{ 1.467 + unsigned char * data = NULL; 1.468 + CK_ULONG length = saveLength; 1.469 + 1.470 + if (cx->ownSession) { 1.471 + PK11_EnterContextMonitor(cx); 1.472 + data = pk11_saveContextHelper(cx, save, &length); 1.473 + PK11_ExitContextMonitor(cx); 1.474 + if (data) *len = length; 1.475 + } else if ((unsigned) saveLength >= cx->savedLength) { 1.476 + data = (unsigned char*)cx->savedData; 1.477 + if (cx->savedData) { 1.478 + PORT_Memcpy(save,cx->savedData,cx->savedLength); 1.479 + } 1.480 + *len = cx->savedLength; 1.481 + } 1.482 + if (data != NULL) { 1.483 + if (cx->ownSession) { 1.484 + PORT_ZFree(data, length); 1.485 + } 1.486 + return SECSuccess; 1.487 + } else { 1.488 + return SECFailure; 1.489 + } 1.490 +} 1.491 + 1.492 +/* same as above, but may allocate the return buffer. */ 1.493 +unsigned char * 1.494 +PK11_SaveContextAlloc(PK11Context *cx, 1.495 + unsigned char *preAllocBuf, unsigned int pabLen, 1.496 + unsigned int *stateLen) 1.497 +{ 1.498 + unsigned char *stateBuf = NULL; 1.499 + unsigned long length = (unsigned long)pabLen; 1.500 + 1.501 + if (cx->ownSession) { 1.502 + PK11_EnterContextMonitor(cx); 1.503 + stateBuf = pk11_saveContextHelper(cx, preAllocBuf, &length); 1.504 + PK11_ExitContextMonitor(cx); 1.505 + *stateLen = (stateBuf != NULL) ? length : 0; 1.506 + } else { 1.507 + if (pabLen < cx->savedLength) { 1.508 + stateBuf = (unsigned char *)PORT_Alloc(cx->savedLength); 1.509 + if (!stateBuf) { 1.510 + return (unsigned char *)NULL; 1.511 + } 1.512 + } else { 1.513 + stateBuf = preAllocBuf; 1.514 + } 1.515 + if (cx->savedData) { 1.516 + PORT_Memcpy(stateBuf, cx->savedData, cx->savedLength); 1.517 + } 1.518 + *stateLen = cx->savedLength; 1.519 + } 1.520 + return stateBuf; 1.521 +} 1.522 + 1.523 +/* 1.524 + * restore the context state into a new running context. Also required for 1.525 + * FORTEZZA . 1.526 + */ 1.527 +SECStatus 1.528 +PK11_RestoreContext(PK11Context *cx,unsigned char *save,int len) 1.529 +{ 1.530 + SECStatus rv = SECSuccess; 1.531 + if (cx->ownSession) { 1.532 + PK11_EnterContextMonitor(cx); 1.533 + pk11_Finalize(cx); 1.534 + rv = pk11_restoreContext(cx,save,len); 1.535 + PK11_ExitContextMonitor(cx); 1.536 + } else { 1.537 + PORT_Assert(cx->savedData != NULL); 1.538 + if ((cx->savedData == NULL) || (cx->savedLength < (unsigned) len)) { 1.539 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.540 + rv = SECFailure; 1.541 + } else { 1.542 + PORT_Memcpy(cx->savedData,save,len); 1.543 + cx->savedLength = len; 1.544 + } 1.545 + } 1.546 + return rv; 1.547 +} 1.548 + 1.549 +/* 1.550 + * This is to get FIPS compliance until we can convert 1.551 + * libjar to use PK11_ hashing functions. It returns PR_FALSE 1.552 + * if we can't get a PK11 Context. 1.553 + */ 1.554 +PRBool 1.555 +PK11_HashOK(SECOidTag algID) { 1.556 + PK11Context *cx; 1.557 + 1.558 + cx = PK11_CreateDigestContext(algID); 1.559 + if (cx == NULL) return PR_FALSE; 1.560 + PK11_DestroyContext(cx, PR_TRUE); 1.561 + return PR_TRUE; 1.562 +} 1.563 + 1.564 + 1.565 + 1.566 +/* 1.567 + * start a new digesting or Mac'ing operation on this context 1.568 + */ 1.569 +SECStatus PK11_DigestBegin(PK11Context *cx) 1.570 +{ 1.571 + CK_MECHANISM mech_info; 1.572 + SECStatus rv; 1.573 + 1.574 + if (cx->init == PR_TRUE) { 1.575 + return SECSuccess; 1.576 + } 1.577 + 1.578 + /* 1.579 + * make sure the old context is clear first 1.580 + */ 1.581 + PK11_EnterContextMonitor(cx); 1.582 + pk11_Finalize(cx); 1.583 + 1.584 + mech_info.mechanism = cx->type; 1.585 + mech_info.pParameter = cx->param->data; 1.586 + mech_info.ulParameterLen = cx->param->len; 1.587 + rv = pk11_context_init(cx,&mech_info); 1.588 + PK11_ExitContextMonitor(cx); 1.589 + 1.590 + if (rv != SECSuccess) { 1.591 + return SECFailure; 1.592 + } 1.593 + cx->init = PR_TRUE; 1.594 + return SECSuccess; 1.595 +} 1.596 + 1.597 +SECStatus 1.598 +PK11_HashBuf(SECOidTag hashAlg, unsigned char *out, const unsigned char *in, 1.599 + PRInt32 len) { 1.600 + PK11Context *context; 1.601 + unsigned int max_length; 1.602 + unsigned int out_length; 1.603 + SECStatus rv; 1.604 + 1.605 + /* len will be passed to PK11_DigestOp as unsigned. */ 1.606 + if (len < 0) { 1.607 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.608 + return SECFailure; 1.609 + } 1.610 + 1.611 + context = PK11_CreateDigestContext(hashAlg); 1.612 + if (context == NULL) return SECFailure; 1.613 + 1.614 + rv = PK11_DigestBegin(context); 1.615 + if (rv != SECSuccess) { 1.616 + PK11_DestroyContext(context, PR_TRUE); 1.617 + return rv; 1.618 + } 1.619 + 1.620 + rv = PK11_DigestOp(context, in, len); 1.621 + if (rv != SECSuccess) { 1.622 + PK11_DestroyContext(context, PR_TRUE); 1.623 + return rv; 1.624 + } 1.625 + 1.626 + /* XXX This really should have been an argument to this function! */ 1.627 + max_length = HASH_ResultLenByOidTag(hashAlg); 1.628 + PORT_Assert(max_length); 1.629 + if (!max_length) 1.630 + max_length = HASH_LENGTH_MAX; 1.631 + 1.632 + rv = PK11_DigestFinal(context,out,&out_length,max_length); 1.633 + PK11_DestroyContext(context, PR_TRUE); 1.634 + return rv; 1.635 +} 1.636 + 1.637 + 1.638 +/* 1.639 + * execute a bulk encryption operation 1.640 + */ 1.641 +SECStatus 1.642 +PK11_CipherOp(PK11Context *context, unsigned char * out, int *outlen, 1.643 + int maxout, const unsigned char *in, int inlen) 1.644 +{ 1.645 + CK_RV crv = CKR_OK; 1.646 + CK_ULONG length = maxout; 1.647 + CK_ULONG offset =0; 1.648 + SECStatus rv = SECSuccess; 1.649 + unsigned char *saveOut = out; 1.650 + unsigned char *allocOut = NULL; 1.651 + 1.652 + /* if we ran out of session, we need to restore our previously stored 1.653 + * state. 1.654 + */ 1.655 + PK11_EnterContextMonitor(context); 1.656 + if (!context->ownSession) { 1.657 + rv = pk11_restoreContext(context,context->savedData, 1.658 + context->savedLength); 1.659 + if (rv != SECSuccess) { 1.660 + PK11_ExitContextMonitor(context); 1.661 + return rv; 1.662 + } 1.663 + } 1.664 + 1.665 + /* 1.666 + * The fortezza hack is to send 8 extra bytes on the first encrypted and 1.667 + * lose them on the first decrypt. 1.668 + */ 1.669 + if (context->fortezzaHack) { 1.670 + unsigned char random[8]; 1.671 + if (context->operation == CKA_ENCRYPT) { 1.672 + PK11_ExitContextMonitor(context); 1.673 + rv = PK11_GenerateRandom(random,sizeof(random)); 1.674 + PK11_EnterContextMonitor(context); 1.675 + 1.676 + /* since we are offseting the output, we can't encrypt back into 1.677 + * the same buffer... allocate a temporary buffer just for this 1.678 + * call. */ 1.679 + allocOut = out = (unsigned char*)PORT_Alloc(maxout); 1.680 + if (out == NULL) { 1.681 + PK11_ExitContextMonitor(context); 1.682 + return SECFailure; 1.683 + } 1.684 + crv = PK11_GETTAB(context->slot)->C_EncryptUpdate(context->session, 1.685 + random,sizeof(random),out,&length); 1.686 + 1.687 + out += length; 1.688 + maxout -= length; 1.689 + offset = length; 1.690 + } else if (context->operation == CKA_DECRYPT) { 1.691 + length = sizeof(random); 1.692 + crv = PK11_GETTAB(context->slot)->C_DecryptUpdate(context->session, 1.693 + (CK_BYTE_PTR)in,sizeof(random),random,&length); 1.694 + inlen -= length; 1.695 + in += length; 1.696 + context->fortezzaHack = PR_FALSE; 1.697 + } 1.698 + } 1.699 + 1.700 + switch (context->operation) { 1.701 + case CKA_ENCRYPT: 1.702 + length = maxout; 1.703 + crv=PK11_GETTAB(context->slot)->C_EncryptUpdate(context->session, 1.704 + (CK_BYTE_PTR)in, inlen, 1.705 + out, &length); 1.706 + length += offset; 1.707 + break; 1.708 + case CKA_DECRYPT: 1.709 + length = maxout; 1.710 + crv=PK11_GETTAB(context->slot)->C_DecryptUpdate(context->session, 1.711 + (CK_BYTE_PTR)in, inlen, 1.712 + out, &length); 1.713 + break; 1.714 + default: 1.715 + crv = CKR_OPERATION_NOT_INITIALIZED; 1.716 + break; 1.717 + } 1.718 + 1.719 + if (crv != CKR_OK) { 1.720 + PORT_SetError( PK11_MapError(crv) ); 1.721 + *outlen = 0; 1.722 + rv = SECFailure; 1.723 + } else { 1.724 + *outlen = length; 1.725 + } 1.726 + 1.727 + if (context->fortezzaHack) { 1.728 + if (context->operation == CKA_ENCRYPT) { 1.729 + PORT_Assert(allocOut); 1.730 + PORT_Memcpy(saveOut, allocOut, length); 1.731 + PORT_Free(allocOut); 1.732 + } 1.733 + context->fortezzaHack = PR_FALSE; 1.734 + } 1.735 + 1.736 + /* 1.737 + * handle session starvation case.. use our last session to multiplex 1.738 + */ 1.739 + if (!context->ownSession) { 1.740 + context->savedData = pk11_saveContext(context,context->savedData, 1.741 + &context->savedLength); 1.742 + if (context->savedData == NULL) rv = SECFailure; 1.743 + 1.744 + /* clear out out session for others to use */ 1.745 + pk11_Finalize(context); 1.746 + } 1.747 + PK11_ExitContextMonitor(context); 1.748 + return rv; 1.749 +} 1.750 + 1.751 +/* 1.752 + * execute a digest/signature operation 1.753 + */ 1.754 +SECStatus 1.755 +PK11_DigestOp(PK11Context *context, const unsigned char * in, unsigned inLen) 1.756 +{ 1.757 + CK_RV crv = CKR_OK; 1.758 + SECStatus rv = SECSuccess; 1.759 + 1.760 + if (inLen == 0) { 1.761 + return SECSuccess; 1.762 + } 1.763 + if (!in) { 1.764 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.765 + return SECFailure; 1.766 + } 1.767 + 1.768 + /* if we ran out of session, we need to restore our previously stored 1.769 + * state. 1.770 + */ 1.771 + context->init = PR_FALSE; 1.772 + PK11_EnterContextMonitor(context); 1.773 + if (!context->ownSession) { 1.774 + rv = pk11_restoreContext(context,context->savedData, 1.775 + context->savedLength); 1.776 + if (rv != SECSuccess) { 1.777 + PK11_ExitContextMonitor(context); 1.778 + return rv; 1.779 + } 1.780 + } 1.781 + 1.782 + switch (context->operation) { 1.783 + /* also for MAC'ing */ 1.784 + case CKA_SIGN: 1.785 + crv=PK11_GETTAB(context->slot)->C_SignUpdate(context->session, 1.786 + (unsigned char *)in, 1.787 + inLen); 1.788 + break; 1.789 + case CKA_VERIFY: 1.790 + crv=PK11_GETTAB(context->slot)->C_VerifyUpdate(context->session, 1.791 + (unsigned char *)in, 1.792 + inLen); 1.793 + break; 1.794 + case CKA_DIGEST: 1.795 + crv=PK11_GETTAB(context->slot)->C_DigestUpdate(context->session, 1.796 + (unsigned char *)in, 1.797 + inLen); 1.798 + break; 1.799 + default: 1.800 + crv = CKR_OPERATION_NOT_INITIALIZED; 1.801 + break; 1.802 + } 1.803 + 1.804 + if (crv != CKR_OK) { 1.805 + PORT_SetError( PK11_MapError(crv) ); 1.806 + rv = SECFailure; 1.807 + } 1.808 + 1.809 + /* 1.810 + * handle session starvation case.. use our last session to multiplex 1.811 + */ 1.812 + if (!context->ownSession) { 1.813 + context->savedData = pk11_saveContext(context,context->savedData, 1.814 + &context->savedLength); 1.815 + if (context->savedData == NULL) rv = SECFailure; 1.816 + 1.817 + /* clear out out session for others to use */ 1.818 + pk11_Finalize(context); 1.819 + } 1.820 + PK11_ExitContextMonitor(context); 1.821 + return rv; 1.822 +} 1.823 + 1.824 +/* 1.825 + * Digest a key if possible./ 1.826 + */ 1.827 +SECStatus 1.828 +PK11_DigestKey(PK11Context *context, PK11SymKey *key) 1.829 +{ 1.830 + CK_RV crv = CKR_OK; 1.831 + SECStatus rv = SECSuccess; 1.832 + PK11SymKey *newKey = NULL; 1.833 + 1.834 + if (!context || !key) { 1.835 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.836 + return SECFailure; 1.837 + } 1.838 + 1.839 + /* if we ran out of session, we need to restore our previously stored 1.840 + * state. 1.841 + */ 1.842 + if (context->slot != key->slot) { 1.843 + newKey = pk11_CopyToSlot(context->slot,CKM_SSL3_SHA1_MAC,CKA_SIGN,key); 1.844 + } else { 1.845 + newKey = PK11_ReferenceSymKey(key); 1.846 + } 1.847 + 1.848 + context->init = PR_FALSE; 1.849 + PK11_EnterContextMonitor(context); 1.850 + if (!context->ownSession) { 1.851 + rv = pk11_restoreContext(context,context->savedData, 1.852 + context->savedLength); 1.853 + if (rv != SECSuccess) { 1.854 + PK11_ExitContextMonitor(context); 1.855 + PK11_FreeSymKey(newKey); 1.856 + return rv; 1.857 + } 1.858 + } 1.859 + 1.860 + 1.861 + if (newKey == NULL) { 1.862 + crv = CKR_KEY_TYPE_INCONSISTENT; 1.863 + if (key->data.data) { 1.864 + crv=PK11_GETTAB(context->slot)->C_DigestUpdate(context->session, 1.865 + key->data.data,key->data.len); 1.866 + } 1.867 + } else { 1.868 + crv=PK11_GETTAB(context->slot)->C_DigestKey(context->session, 1.869 + newKey->objectID); 1.870 + } 1.871 + 1.872 + if (crv != CKR_OK) { 1.873 + PORT_SetError( PK11_MapError(crv) ); 1.874 + rv = SECFailure; 1.875 + } 1.876 + 1.877 + /* 1.878 + * handle session starvation case.. use our last session to multiplex 1.879 + */ 1.880 + if (!context->ownSession) { 1.881 + context->savedData = pk11_saveContext(context,context->savedData, 1.882 + &context->savedLength); 1.883 + if (context->savedData == NULL) rv = SECFailure; 1.884 + 1.885 + /* clear out out session for others to use */ 1.886 + pk11_Finalize(context); 1.887 + } 1.888 + PK11_ExitContextMonitor(context); 1.889 + if (newKey) PK11_FreeSymKey(newKey); 1.890 + return rv; 1.891 +} 1.892 + 1.893 +/* 1.894 + * externally callable version of the lowercase pk11_finalize(). 1.895 + */ 1.896 +SECStatus 1.897 +PK11_Finalize(PK11Context *context) { 1.898 + SECStatus rv; 1.899 + 1.900 + PK11_EnterContextMonitor(context); 1.901 + rv = pk11_Finalize(context); 1.902 + PK11_ExitContextMonitor(context); 1.903 + return rv; 1.904 +} 1.905 + 1.906 +/* 1.907 + * clean up a cipher operation, so the session can be used by 1.908 + * someone new. 1.909 + */ 1.910 +SECStatus 1.911 +pk11_Finalize(PK11Context *context) 1.912 +{ 1.913 + CK_ULONG count = 0; 1.914 + CK_RV crv; 1.915 + unsigned char stackBuf[256]; 1.916 + unsigned char *buffer = NULL; 1.917 + 1.918 + if (!context->ownSession) { 1.919 + return SECSuccess; 1.920 + } 1.921 + 1.922 +finalize: 1.923 + switch (context->operation) { 1.924 + case CKA_ENCRYPT: 1.925 + crv=PK11_GETTAB(context->slot)->C_EncryptFinal(context->session, 1.926 + buffer, &count); 1.927 + break; 1.928 + case CKA_DECRYPT: 1.929 + crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session, 1.930 + buffer, &count); 1.931 + break; 1.932 + case CKA_SIGN: 1.933 + crv=PK11_GETTAB(context->slot)->C_SignFinal(context->session, 1.934 + buffer, &count); 1.935 + break; 1.936 + case CKA_VERIFY: 1.937 + crv=PK11_GETTAB(context->slot)->C_VerifyFinal(context->session, 1.938 + buffer, count); 1.939 + break; 1.940 + case CKA_DIGEST: 1.941 + crv=PK11_GETTAB(context->slot)->C_DigestFinal(context->session, 1.942 + buffer, &count); 1.943 + break; 1.944 + default: 1.945 + crv = CKR_OPERATION_NOT_INITIALIZED; 1.946 + break; 1.947 + } 1.948 + 1.949 + if (crv != CKR_OK) { 1.950 + if (buffer != stackBuf) { 1.951 + PORT_Free(buffer); 1.952 + } 1.953 + if (crv == CKR_OPERATION_NOT_INITIALIZED) { 1.954 + /* if there's no operation, it is finalized */ 1.955 + return SECSuccess; 1.956 + } 1.957 + PORT_SetError( PK11_MapError(crv) ); 1.958 + return SECFailure; 1.959 + } 1.960 + 1.961 + /* try to finalize the session with a buffer */ 1.962 + if (buffer == NULL) { 1.963 + if (count <= sizeof stackBuf) { 1.964 + buffer = stackBuf; 1.965 + } else { 1.966 + buffer = PORT_Alloc(count); 1.967 + if (buffer == NULL) { 1.968 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.969 + return SECFailure; 1.970 + } 1.971 + } 1.972 + goto finalize; 1.973 + } 1.974 + if (buffer != stackBuf) { 1.975 + PORT_Free(buffer); 1.976 + } 1.977 + return SECSuccess; 1.978 +} 1.979 + 1.980 +/* 1.981 + * Return the final digested or signed data... 1.982 + * this routine can either take pre initialized data, or allocate data 1.983 + * either out of an arena or out of the standard heap. 1.984 + */ 1.985 +SECStatus 1.986 +PK11_DigestFinal(PK11Context *context,unsigned char *data, 1.987 + unsigned int *outLen, unsigned int length) 1.988 +{ 1.989 + CK_ULONG len; 1.990 + CK_RV crv; 1.991 + SECStatus rv; 1.992 + 1.993 + 1.994 + /* if we ran out of session, we need to restore our previously stored 1.995 + * state. 1.996 + */ 1.997 + PK11_EnterContextMonitor(context); 1.998 + if (!context->ownSession) { 1.999 + rv = pk11_restoreContext(context,context->savedData, 1.1000 + context->savedLength); 1.1001 + if (rv != SECSuccess) { 1.1002 + PK11_ExitContextMonitor(context); 1.1003 + return rv; 1.1004 + } 1.1005 + } 1.1006 + 1.1007 + len = length; 1.1008 + switch (context->operation) { 1.1009 + case CKA_SIGN: 1.1010 + crv=PK11_GETTAB(context->slot)->C_SignFinal(context->session, 1.1011 + data,&len); 1.1012 + break; 1.1013 + case CKA_VERIFY: 1.1014 + crv=PK11_GETTAB(context->slot)->C_VerifyFinal(context->session, 1.1015 + data,len); 1.1016 + break; 1.1017 + case CKA_DIGEST: 1.1018 + crv=PK11_GETTAB(context->slot)->C_DigestFinal(context->session, 1.1019 + data,&len); 1.1020 + break; 1.1021 + case CKA_ENCRYPT: 1.1022 + crv=PK11_GETTAB(context->slot)->C_EncryptFinal(context->session, 1.1023 + data, &len); 1.1024 + break; 1.1025 + case CKA_DECRYPT: 1.1026 + crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session, 1.1027 + data, &len); 1.1028 + break; 1.1029 + default: 1.1030 + crv = CKR_OPERATION_NOT_INITIALIZED; 1.1031 + break; 1.1032 + } 1.1033 + PK11_ExitContextMonitor(context); 1.1034 + 1.1035 + *outLen = (unsigned int) len; 1.1036 + context->init = PR_FALSE; /* allow Begin to start up again */ 1.1037 + 1.1038 + 1.1039 + if (crv != CKR_OK) { 1.1040 + PORT_SetError( PK11_MapError(crv) ); 1.1041 + return SECFailure; 1.1042 + } 1.1043 + return SECSuccess; 1.1044 +} 1.1045 +