Mercurial > trustbridge > nss-cmake-static
comparison nss/lib/pk11wrap/pk11cxt.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1e5118fa0cb1 |
---|---|
1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
4 /* | |
5 * This file PK11Contexts which are used in multipart hashing, | |
6 * encryption/decryption, and signing/verication operations. | |
7 */ | |
8 | |
9 #include "seccomon.h" | |
10 #include "secmod.h" | |
11 #include "nssilock.h" | |
12 #include "secmodi.h" | |
13 #include "secmodti.h" | |
14 #include "pkcs11.h" | |
15 #include "pk11func.h" | |
16 #include "secitem.h" | |
17 #include "secoid.h" | |
18 #include "sechash.h" | |
19 #include "secerr.h" | |
20 | |
21 static const SECItem pk11_null_params = { 0 }; | |
22 | |
23 /********************************************************************** | |
24 * | |
25 * Now Deal with Crypto Contexts | |
26 * | |
27 **********************************************************************/ | |
28 | |
29 /* | |
30 * the monitors... | |
31 */ | |
32 void | |
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 } | |
43 | |
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 } | |
55 | |
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 } | |
72 | |
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; | |
81 | |
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 } | |
110 | |
111 void * | |
112 pk11_saveContext(PK11Context *context, void *space, unsigned long *savedLength) | |
113 { | |
114 return pk11_saveContextHelper(context, | |
115 (unsigned char *)space, savedLength); | |
116 } | |
117 | |
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; | |
127 | |
128 PORT_Assert(space != NULL); | |
129 if (space == NULL) { | |
130 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | |
131 return SECFailure; | |
132 } | |
133 crv = PK11_GETTAB(context->slot)->C_SetOperationState(context->session, | |
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 } | |
141 | |
142 SECStatus pk11_Finalize(PK11Context *context); | |
143 | |
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; | |
153 | |
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 } | |
188 | |
189 if (crv != CKR_OK) { | |
190 PORT_SetError( PK11_MapError(crv) ); | |
191 return SECFailure; | |
192 } | |
193 | |
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 } | |
206 | |
207 | |
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; | |
218 | |
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 } | |
229 | |
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 } | |
243 | |
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; | |
252 | |
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 } | |
272 | |
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); | |
279 | |
280 if (rv != SECSuccess) { | |
281 PK11_DestroyContext(context,PR_TRUE); | |
282 return NULL; | |
283 } | |
284 context->init = PR_TRUE; | |
285 return context; | |
286 } | |
287 | |
288 | |
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; | |
300 | |
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 } | |
311 | |
312 /* now import the key */ | |
313 symKey = PK11_ImportSymKey(slot, type, origin, operation, key, wincx); | |
314 if (symKey == NULL) goto loser; | |
315 | |
316 context = PK11_CreateContextBySymKey(type, operation, symKey, param); | |
317 | |
318 loser: | |
319 if (symKey) { | |
320 PK11_FreeSymKey(symKey); | |
321 } | |
322 if (slot) { | |
323 PK11_FreeSlot(slot); | |
324 } | |
325 | |
326 return context; | |
327 } | |
328 | |
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 } | |
337 | |
338 | |
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; | |
349 | |
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 } | |
357 | |
358 | |
359 /* Context Adopts the symKey.... */ | |
360 context = pk11_CreateNewContextInSlot(type, symKey->slot, operation, symKey, | |
361 param); | |
362 PK11_FreeSymKey(symKey); | |
363 return context; | |
364 } | |
365 | |
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; | |
378 | |
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 } | |
385 | |
386 /* maybe should really be PK11_GenerateNewParam?? */ | |
387 param.data = NULL; | |
388 param.len = 0; | |
389 param.type = 0; | |
390 | |
391 context = pk11_CreateNewContextInSlot(type, slot, CKA_DIGEST, NULL, ¶m); | |
392 PK11_FreeSlot(slot); | |
393 return context; | |
394 } | |
395 | |
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; | |
406 | |
407 newcx = pk11_CreateNewContextInSlot(old->type, old->slot, old->operation, | |
408 old->key, old->param); | |
409 if (newcx == NULL) return NULL; | |
410 | |
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 } | |
423 | |
424 if (data == NULL) { | |
425 PK11_DestroyContext(newcx,PR_TRUE); | |
426 return NULL; | |
427 } | |
428 | |
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 } | |
447 | |
448 if (needFree) PORT_Free(data); | |
449 | |
450 if (rv != SECSuccess) { | |
451 PK11_DestroyContext(newcx,PR_TRUE); | |
452 return NULL; | |
453 } | |
454 return newcx; | |
455 } | |
456 | |
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; | |
466 | |
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 } | |
488 | |
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; | |
497 | |
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 } | |
519 | |
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 } | |
545 | |
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; | |
554 | |
555 cx = PK11_CreateDigestContext(algID); | |
556 if (cx == NULL) return PR_FALSE; | |
557 PK11_DestroyContext(cx, PR_TRUE); | |
558 return PR_TRUE; | |
559 } | |
560 | |
561 | |
562 | |
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; | |
570 | |
571 if (cx->init == PR_TRUE) { | |
572 return SECSuccess; | |
573 } | |
574 | |
575 /* | |
576 * make sure the old context is clear first | |
577 */ | |
578 PK11_EnterContextMonitor(cx); | |
579 pk11_Finalize(cx); | |
580 | |
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); | |
586 | |
587 if (rv != SECSuccess) { | |
588 return SECFailure; | |
589 } | |
590 cx->init = PR_TRUE; | |
591 return SECSuccess; | |
592 } | |
593 | |
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; | |
601 | |
602 /* len will be passed to PK11_DigestOp as unsigned. */ | |
603 if (len < 0) { | |
604 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
605 return SECFailure; | |
606 } | |
607 | |
608 context = PK11_CreateDigestContext(hashAlg); | |
609 if (context == NULL) return SECFailure; | |
610 | |
611 rv = PK11_DigestBegin(context); | |
612 if (rv != SECSuccess) { | |
613 PK11_DestroyContext(context, PR_TRUE); | |
614 return rv; | |
615 } | |
616 | |
617 rv = PK11_DigestOp(context, in, len); | |
618 if (rv != SECSuccess) { | |
619 PK11_DestroyContext(context, PR_TRUE); | |
620 return rv; | |
621 } | |
622 | |
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; | |
628 | |
629 rv = PK11_DigestFinal(context,out,&out_length,max_length); | |
630 PK11_DestroyContext(context, PR_TRUE); | |
631 return rv; | |
632 } | |
633 | |
634 | |
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; | |
648 | |
649 /* if we ran out of session, we need to restore our previously stored | |
650 * state. | |
651 */ | |
652 PK11_EnterContextMonitor(context); | |
653 if (!context->ownSession) { | |
654 rv = pk11_restoreContext(context,context->savedData, | |
655 context->savedLength); | |
656 if (rv != SECSuccess) { | |
657 PK11_ExitContextMonitor(context); | |
658 return rv; | |
659 } | |
660 } | |
661 | |
662 /* | |
663 * The fortezza hack is to send 8 extra bytes on the first encrypted and | |
664 * lose them on the first decrypt. | |
665 */ | |
666 if (context->fortezzaHack) { | |
667 unsigned char random[8]; | |
668 if (context->operation == CKA_ENCRYPT) { | |
669 PK11_ExitContextMonitor(context); | |
670 rv = PK11_GenerateRandom(random,sizeof(random)); | |
671 PK11_EnterContextMonitor(context); | |
672 | |
673 /* since we are offseting the output, we can't encrypt back into | |
674 * the same buffer... allocate a temporary buffer just for this | |
675 * call. */ | |
676 allocOut = out = (unsigned char*)PORT_Alloc(maxout); | |
677 if (out == NULL) { | |
678 PK11_ExitContextMonitor(context); | |
679 return SECFailure; | |
680 } | |
681 crv = PK11_GETTAB(context->slot)->C_EncryptUpdate(context->session, | |
682 random,sizeof(random),out,&length); | |
683 | |
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 } | |
696 | |
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 } | |
715 | |
716 if (crv != CKR_OK) { | |
717 PORT_SetError( PK11_MapError(crv) ); | |
718 *outlen = 0; | |
719 rv = SECFailure; | |
720 } else { | |
721 *outlen = length; | |
722 } | |
723 | |
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 } | |
732 | |
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; | |
740 | |
741 /* clear out out session for others to use */ | |
742 pk11_Finalize(context); | |
743 } | |
744 PK11_ExitContextMonitor(context); | |
745 return rv; | |
746 } | |
747 | |
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; | |
756 | |
757 if (inLen == 0) { | |
758 return SECSuccess; | |
759 } | |
760 if (!in) { | |
761 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
762 return SECFailure; | |
763 } | |
764 | |
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 } | |
778 | |
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 } | |
800 | |
801 if (crv != CKR_OK) { | |
802 PORT_SetError( PK11_MapError(crv) ); | |
803 rv = SECFailure; | |
804 } | |
805 | |
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; | |
813 | |
814 /* clear out out session for others to use */ | |
815 pk11_Finalize(context); | |
816 } | |
817 PK11_ExitContextMonitor(context); | |
818 return rv; | |
819 } | |
820 | |
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; | |
830 | |
831 if (!context || !key) { | |
832 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
833 return SECFailure; | |
834 } | |
835 | |
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 } | |
844 | |
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 } | |
856 | |
857 | |
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 } | |
868 | |
869 if (crv != CKR_OK) { | |
870 PORT_SetError( PK11_MapError(crv) ); | |
871 rv = SECFailure; | |
872 } | |
873 | |
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; | |
881 | |
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 } | |
889 | |
890 /* | |
891 * externally callable version of the lowercase pk11_finalize(). | |
892 */ | |
893 SECStatus | |
894 PK11_Finalize(PK11Context *context) { | |
895 SECStatus rv; | |
896 | |
897 PK11_EnterContextMonitor(context); | |
898 rv = pk11_Finalize(context); | |
899 PK11_ExitContextMonitor(context); | |
900 return rv; | |
901 } | |
902 | |
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; | |
914 | |
915 if (!context->ownSession) { | |
916 return SECSuccess; | |
917 } | |
918 | |
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 } | |
945 | |
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 } | |
957 | |
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 } | |
976 | |
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; | |
989 | |
990 | |
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; | |
1001 } | |
1002 } | |
1003 | |
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; | |
1029 } | |
1030 PK11_ExitContextMonitor(context); | |
1031 | |
1032 *outLen = (unsigned int) len; | |
1033 context->init = PR_FALSE; /* allow Begin to start up again */ | |
1034 | |
1035 | |
1036 if (crv != CKR_OK) { | |
1037 PORT_SetError( PK11_MapError(crv) ); | |
1038 return SECFailure; | |
1039 } | |
1040 return SECSuccess; | |
1041 } | |
1042 |