Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(250)

Side by Side Diff: nss/lib/pk11wrap/pk11skey.c

Issue 2078763002: Delete bundled copy of NSS and replace with README. (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/nss@master
Patch Set: Delete bundled copy of NSS and replace with README. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « nss/lib/pk11wrap/pk11sdr.c ('k') | nss/lib/pk11wrap/pk11slot.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 implements the Symkey wrapper and the PKCS context
6 * Interfaces.
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 "secerr.h"
19 #include "hasht.h"
20
21 static void
22 pk11_EnterKeyMonitor(PK11SymKey *symKey) {
23 if (!symKey->sessionOwner || !(symKey->slot->isThreadSafe))
24 PK11_EnterSlotMonitor(symKey->slot);
25 }
26
27 static void
28 pk11_ExitKeyMonitor(PK11SymKey *symKey) {
29 if (!symKey->sessionOwner || !(symKey->slot->isThreadSafe))
30 PK11_ExitSlotMonitor(symKey->slot);
31 }
32
33 /*
34 * pk11_getKeyFromList returns a symKey that has a session (if needSession
35 * was specified), or explicitly does not have a session (if needSession
36 * was not specified).
37 */
38 static PK11SymKey *
39 pk11_getKeyFromList(PK11SlotInfo *slot, PRBool needSession) {
40 PK11SymKey *symKey = NULL;
41
42 PZ_Lock(slot->freeListLock);
43 /* own session list are symkeys with sessions that the symkey owns.
44 * 'most' symkeys will own their own session. */
45 if (needSession) {
46 if (slot->freeSymKeysWithSessionHead) {
47 symKey = slot->freeSymKeysWithSessionHead;
48 slot->freeSymKeysWithSessionHead = symKey->next;
49 slot->keyCount--;
50 }
51 }
52 /* if we don't need a symkey with its own session, or we couldn't find
53 * one on the owner list, get one from the non-owner free list. */
54 if (!symKey) {
55 if (slot->freeSymKeysHead) {
56 symKey = slot->freeSymKeysHead;
57 slot->freeSymKeysHead = symKey->next;
58 slot->keyCount--;
59 }
60 }
61 PZ_Unlock(slot->freeListLock);
62 if (symKey) {
63 symKey->next = NULL;
64 if (!needSession) {
65 return symKey;
66 }
67 /* if we are getting an owner key, make sure we have a valid session.
68 * session could be invalid if the token has been removed or because
69 * we got it from the non-owner free list */
70 if ((symKey->series != slot->series) ||
71 (symKey->session == CK_INVALID_SESSION)) {
72 symKey->session = pk11_GetNewSession(slot, &symKey->sessionOwner);
73 }
74 PORT_Assert(symKey->session != CK_INVALID_SESSION);
75 if (symKey->session != CK_INVALID_SESSION)
76 return symKey;
77 PK11_FreeSymKey(symKey);
78 /* if we are here, we need a session, but couldn't get one, it's
79 * unlikely we pk11_GetNewSession will succeed if we call it a second
80 * time. */
81 return NULL;
82 }
83
84 symKey = PORT_New(PK11SymKey);
85 if (symKey == NULL) {
86 return NULL;
87 }
88
89 symKey->next = NULL;
90 if (needSession) {
91 symKey->session = pk11_GetNewSession(slot,&symKey->sessionOwner);
92 PORT_Assert(symKey->session != CK_INVALID_SESSION);
93 if (symKey->session == CK_INVALID_SESSION) {
94 PK11_FreeSymKey(symKey);
95 symKey = NULL;
96 }
97 } else {
98 symKey->session = CK_INVALID_SESSION;
99 }
100 return symKey;
101 }
102
103 /* Caller MUST hold slot->freeListLock (or ref count == 0?) !! */
104 void
105 PK11_CleanKeyList(PK11SlotInfo *slot)
106 {
107 PK11SymKey *symKey = NULL;
108
109 while (slot->freeSymKeysWithSessionHead) {
110 symKey = slot->freeSymKeysWithSessionHead;
111 slot->freeSymKeysWithSessionHead = symKey->next;
112 pk11_CloseSession(slot, symKey->session, symKey->sessionOwner);
113 PORT_Free(symKey);
114 }
115 while (slot->freeSymKeysHead) {
116 symKey = slot->freeSymKeysHead;
117 slot->freeSymKeysHead = symKey->next;
118 pk11_CloseSession(slot, symKey->session, symKey->sessionOwner);
119 PORT_Free(symKey);
120 }
121 return;
122 }
123
124 /*
125 * create a symetric key:
126 * Slot is the slot to create the key in.
127 * type is the mechanism type
128 * owner is does this symKey structure own it's object handle (rare
129 * that this is false).
130 * needSession means the returned symKey will return with a valid session
131 * allocated already.
132 */
133 static PK11SymKey *
134 pk11_CreateSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
135 PRBool owner, PRBool needSession, void *wincx)
136 {
137
138 PK11SymKey *symKey = pk11_getKeyFromList(slot, needSession);
139
140 if (symKey == NULL) {
141 return NULL;
142 }
143 /* if needSession was specified, make sure we have a valid session.
144 * callers which specify needSession as false should do their own
145 * check of the session before returning the symKey */
146 if (needSession && symKey->session == CK_INVALID_SESSION) {
147 PK11_FreeSymKey(symKey);
148 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
149 return NULL;
150 }
151
152 symKey->type = type;
153 symKey->data.type = siBuffer;
154 symKey->data.data = NULL;
155 symKey->data.len = 0;
156 symKey->owner = owner;
157 symKey->objectID = CK_INVALID_HANDLE;
158 symKey->slot = slot;
159 symKey->series = slot->series;
160 symKey->cx = wincx;
161 symKey->size = 0;
162 symKey->refCount = 1;
163 symKey->origin = PK11_OriginNULL;
164 symKey->parent = NULL;
165 symKey->freeFunc = NULL;
166 symKey->userData = NULL;
167 PK11_ReferenceSlot(slot);
168 return symKey;
169 }
170
171 /*
172 * destroy a symetric key
173 */
174 void
175 PK11_FreeSymKey(PK11SymKey *symKey)
176 {
177 PK11SlotInfo *slot;
178 PRBool freeit = PR_TRUE;
179
180 if (PR_ATOMIC_DECREMENT(&symKey->refCount) == 0) {
181 PK11SymKey *parent = symKey->parent;
182
183 symKey->parent = NULL;
184 if ((symKey->owner) && symKey->objectID != CK_INVALID_HANDLE) {
185 pk11_EnterKeyMonitor(symKey);
186 (void) PK11_GETTAB(symKey->slot)->
187 C_DestroyObject(symKey->session, symKey->objectID);
188 pk11_ExitKeyMonitor(symKey);
189 }
190 if (symKey->data.data) {
191 PORT_Memset(symKey->data.data, 0, symKey->data.len);
192 PORT_Free(symKey->data.data);
193 }
194 /* free any existing data */
195 if (symKey->userData && symKey->freeFunc) {
196 (*symKey->freeFunc)(symKey->userData);
197 }
198 slot = symKey->slot;
199 PZ_Lock(slot->freeListLock);
200 if (slot->keyCount < slot->maxKeyCount) {
201 /*
202 * freeSymkeysWithSessionHead contain a list of reusable
203 * SymKey structures with valid sessions.
204 * sessionOwner must be true.
205 * session must be valid.
206 * freeSymKeysHead contain a list of SymKey structures without
207 * valid session.
208 * session must be CK_INVALID_SESSION.
209 * though sessionOwner is false, callers should not depend on
210 * this fact.
211 */
212 if (symKey->sessionOwner) {
213 PORT_Assert (symKey->session != CK_INVALID_SESSION);
214 symKey->next = slot->freeSymKeysWithSessionHead;
215 slot->freeSymKeysWithSessionHead = symKey;
216 } else {
217 symKey->session = CK_INVALID_SESSION;
218 symKey->next = slot->freeSymKeysHead;
219 slot->freeSymKeysHead = symKey;
220 }
221 slot->keyCount++;
222 symKey->slot = NULL;
223 freeit = PR_FALSE;
224 }
225 PZ_Unlock(slot->freeListLock);
226 if (freeit) {
227 pk11_CloseSession(symKey->slot, symKey->session,
228 symKey->sessionOwner);
229 PORT_Free(symKey);
230 }
231 PK11_FreeSlot(slot);
232
233 if (parent) {
234 PK11_FreeSymKey(parent);
235 }
236 }
237 }
238
239 PK11SymKey *
240 PK11_ReferenceSymKey(PK11SymKey *symKey)
241 {
242 PR_ATOMIC_INCREMENT(&symKey->refCount);
243 return symKey;
244 }
245
246 /*
247 * Accessors
248 */
249 CK_MECHANISM_TYPE
250 PK11_GetMechanism(PK11SymKey *symKey)
251 {
252 return symKey->type;
253 }
254
255 /*
256 * return the slot associated with a symetric key
257 */
258 PK11SlotInfo *
259 PK11_GetSlotFromKey(PK11SymKey *symKey)
260 {
261 return PK11_ReferenceSlot(symKey->slot);
262 }
263
264 CK_KEY_TYPE PK11_GetSymKeyType(PK11SymKey *symKey)
265 {
266 return PK11_GetKeyType(symKey->type,symKey->size);
267 }
268
269 PK11SymKey *
270 PK11_GetNextSymKey(PK11SymKey *symKey)
271 {
272 return symKey ? symKey->next : NULL;
273 }
274
275 char *
276 PK11_GetSymKeyNickname(PK11SymKey *symKey)
277 {
278 return PK11_GetObjectNickname(symKey->slot,symKey->objectID);
279 }
280
281 SECStatus
282 PK11_SetSymKeyNickname(PK11SymKey *symKey, const char *nickname)
283 {
284 return PK11_SetObjectNickname(symKey->slot,symKey->objectID,nickname);
285 }
286
287 void *
288 PK11_GetSymKeyUserData(PK11SymKey *symKey)
289 {
290 return symKey->userData;
291 }
292
293 void
294 PK11_SetSymKeyUserData(PK11SymKey *symKey, void *userData,
295 PK11FreeDataFunc freeFunc)
296 {
297 /* free any existing data */
298 if (symKey->userData && symKey->freeFunc) {
299 (*symKey->freeFunc)(symKey->userData);
300 }
301 symKey->userData = userData;
302 symKey->freeFunc = freeFunc;
303 return;
304 }
305
306 /*
307 * turn key handle into an appropriate key object
308 */
309 PK11SymKey *
310 PK11_SymKeyFromHandle(PK11SlotInfo *slot, PK11SymKey *parent, PK11Origin origin,
311 CK_MECHANISM_TYPE type, CK_OBJECT_HANDLE keyID, PRBool owner, void *wincx)
312 {
313 PK11SymKey *symKey;
314 PRBool needSession = !(owner && parent);
315
316 if (keyID == CK_INVALID_HANDLE) {
317 return NULL;
318 }
319
320 symKey = pk11_CreateSymKey(slot, type, owner, needSession, wincx);
321 if (symKey == NULL) {
322 return NULL;
323 }
324
325 symKey->objectID = keyID;
326 symKey->origin = origin;
327
328 /* adopt the parent's session */
329 /* This is only used by SSL. What we really want here is a session
330 * structure with a ref count so the session goes away only after all the
331 * keys do. */
332 if (!needSession) {
333 symKey->sessionOwner = PR_FALSE;
334 symKey->session = parent->session;
335 symKey->parent = PK11_ReferenceSymKey(parent);
336 /* This is the only case where pk11_CreateSymKey does not explicitly
337 * check symKey->session. We need to assert here to make sure.
338 * the session isn't invalid. */
339 PORT_Assert(parent->session != CK_INVALID_SESSION);
340 if (parent->session == CK_INVALID_SESSION) {
341 PK11_FreeSymKey(symKey);
342 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
343 return NULL;
344 }
345 }
346
347 return symKey;
348 }
349
350 /*
351 * turn key handle into an appropriate key object
352 */
353 PK11SymKey *
354 PK11_GetWrapKey(PK11SlotInfo *slot, int wrap, CK_MECHANISM_TYPE type,
355 int series, void *wincx)
356 {
357 PK11SymKey *symKey = NULL;
358
359 if (slot->series != series) return NULL;
360 if (slot->refKeys[wrap] == CK_INVALID_HANDLE) return NULL;
361 if (type == CKM_INVALID_MECHANISM) type = slot->wrapMechanism;
362
363 symKey = PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive,
364 slot->wrapMechanism, slot->refKeys[wrap], PR_FALSE, wincx);
365 return symKey;
366 }
367
368 /*
369 * This function is not thread-safe because it sets wrapKey->sessionOwner
370 * without using a lock or atomic routine. It can only be called when
371 * only one thread has a reference to wrapKey.
372 */
373 void
374 PK11_SetWrapKey(PK11SlotInfo *slot, int wrap, PK11SymKey *wrapKey)
375 {
376 /* save the handle and mechanism for the wrapping key */
377 /* mark the key and session as not owned by us to they don't get freed
378 * when the key goes way... that lets us reuse the key later */
379 slot->refKeys[wrap] = wrapKey->objectID;
380 wrapKey->owner = PR_FALSE;
381 wrapKey->sessionOwner = PR_FALSE;
382 slot->wrapMechanism = wrapKey->type;
383 }
384
385
386 /*
387 * figure out if a key is still valid or if it is stale.
388 */
389 PRBool
390 PK11_VerifyKeyOK(PK11SymKey *key) {
391 if (!PK11_IsPresent(key->slot)) {
392 return PR_FALSE;
393 }
394 return (PRBool)(key->series == key->slot->series);
395 }
396
397 static PK11SymKey *
398 pk11_ImportSymKeyWithTempl(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
399 PK11Origin origin, PRBool isToken, CK_ATTRIBUTE *keyTemplate,
400 unsigned int templateCount, SECItem *key, void *wincx)
401 {
402 PK11SymKey * symKey;
403 SECStatus rv;
404
405 symKey = pk11_CreateSymKey(slot, type, !isToken, PR_TRUE, wincx);
406 if (symKey == NULL) {
407 return NULL;
408 }
409
410 symKey->size = key->len;
411
412 PK11_SETATTRS(&keyTemplate[templateCount], CKA_VALUE, key->data, key->len);
413 templateCount++;
414
415 if (SECITEM_CopyItem(NULL,&symKey->data,key) != SECSuccess) {
416 PK11_FreeSymKey(symKey);
417 return NULL;
418 }
419
420 symKey->origin = origin;
421
422 /* import the keys */
423 rv = PK11_CreateNewObject(slot, symKey->session, keyTemplate,
424 templateCount, isToken, &symKey->objectID);
425 if ( rv != SECSuccess) {
426 PK11_FreeSymKey(symKey);
427 return NULL;
428 }
429
430 return symKey;
431 }
432
433 /*
434 * turn key bits into an appropriate key object
435 */
436 PK11SymKey *
437 PK11_ImportSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
438 PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key,void *wincx)
439 {
440 PK11SymKey * symKey;
441 unsigned int templateCount = 0;
442 CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
443 CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
444 CK_BBOOL cktrue = CK_TRUE; /* sigh */
445 CK_ATTRIBUTE keyTemplate[5];
446 CK_ATTRIBUTE * attrs = keyTemplate;
447
448 PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++;
449 PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++;
450 PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
451 templateCount = attrs - keyTemplate;
452 PR_ASSERT(templateCount+1 <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
453
454 keyType = PK11_GetKeyType(type,key->len);
455 symKey = pk11_ImportSymKeyWithTempl(slot, type, origin, PR_FALSE,
456 keyTemplate, templateCount, key, wincx);
457 return symKey;
458 }
459
460
461 /*
462 * turn key bits into an appropriate key object
463 */
464 PK11SymKey *
465 PK11_ImportSymKeyWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
466 PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key,
467 CK_FLAGS flags, PRBool isPerm, void *wincx)
468 {
469 PK11SymKey * symKey;
470 unsigned int templateCount = 0;
471 CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
472 CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
473 CK_BBOOL cktrue = CK_TRUE; /* sigh */
474 CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
475 CK_ATTRIBUTE * attrs = keyTemplate;
476
477 PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++;
478 PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++;
479 if (isPerm) {
480 PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue) ); attrs++;
481 /* sigh some tokens think CKA_PRIVATE = false is a reasonable
482 * default for secret keys */
483 PK11_SETATTRS(attrs, CKA_PRIVATE, &cktrue, sizeof(cktrue) ); attrs++;
484 }
485 attrs += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
486 if ((operation != CKA_FLAGS_ONLY) &&
487 !pk11_FindAttrInTemplate(keyTemplate, attrs-keyTemplate, operation)) {
488 PK11_SETATTRS(attrs, operation, &cktrue, sizeof(cktrue)); attrs++;
489 }
490 templateCount = attrs - keyTemplate;
491 PR_ASSERT(templateCount+1 <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
492
493 keyType = PK11_GetKeyType(type,key->len);
494 symKey = pk11_ImportSymKeyWithTempl(slot, type, origin, isPerm,
495 keyTemplate, templateCount, key, wincx);
496 if (symKey && isPerm) {
497 symKey->owner = PR_FALSE;
498 }
499 return symKey;
500 }
501
502
503 PK11SymKey *
504 PK11_FindFixedKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *keyID,
505 void *wincx)
506 {
507 CK_ATTRIBUTE findTemp[4];
508 CK_ATTRIBUTE *attrs;
509 CK_BBOOL ckTrue = CK_TRUE;
510 CK_OBJECT_CLASS keyclass = CKO_SECRET_KEY;
511 int tsize = 0;
512 CK_OBJECT_HANDLE key_id;
513
514 attrs = findTemp;
515 PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++;
516 PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++;
517 if (keyID) {
518 PK11_SETATTRS(attrs, CKA_ID, keyID->data, keyID->len); attrs++;
519 }
520 tsize = attrs - findTemp;
521 PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
522
523 key_id = pk11_FindObjectByTemplate(slot,findTemp,tsize);
524 if (key_id == CK_INVALID_HANDLE) {
525 return NULL;
526 }
527 return PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive, type, key_id,
528 PR_FALSE, wincx);
529 }
530
531 PK11SymKey *
532 PK11_ListFixedKeysInSlot(PK11SlotInfo *slot, char *nickname, void *wincx)
533 {
534 CK_ATTRIBUTE findTemp[4];
535 CK_ATTRIBUTE *attrs;
536 CK_BBOOL ckTrue = CK_TRUE;
537 CK_OBJECT_CLASS keyclass = CKO_SECRET_KEY;
538 int tsize = 0;
539 int objCount = 0;
540 CK_OBJECT_HANDLE *key_ids;
541 PK11SymKey *nextKey = NULL;
542 PK11SymKey *topKey = NULL;
543 int i,len;
544
545 attrs = findTemp;
546 PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++;
547 PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++;
548 if (nickname) {
549 len = PORT_Strlen(nickname);
550 PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++;
551 }
552 tsize = attrs - findTemp;
553 PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
554
555 key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount);
556 if (key_ids == NULL) {
557 return NULL;
558 }
559
560 for (i=0; i < objCount ; i++) {
561 SECItem typeData;
562 CK_KEY_TYPE type = CKK_GENERIC_SECRET;
563 SECStatus rv = PK11_ReadAttribute(slot, key_ids[i],
564 CKA_KEY_TYPE, NULL, &typeData);
565 if (rv == SECSuccess) {
566 if (typeData.len == sizeof(CK_KEY_TYPE)) {
567 type = *(CK_KEY_TYPE *)typeData.data;
568 }
569 PORT_Free(typeData.data);
570 }
571 nextKey = PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive,
572 PK11_GetKeyMechanism(type), key_ids[i], PR_FALSE, wincx);
573 if (nextKey) {
574 nextKey->next = topKey;
575 topKey = nextKey;
576 }
577 }
578 PORT_Free(key_ids);
579 return topKey;
580 }
581
582 void *
583 PK11_GetWindow(PK11SymKey *key)
584 {
585 return key->cx;
586 }
587
588
589 /*
590 * extract a symetric key value. NOTE: if the key is sensitive, we will
591 * not be able to do this operation. This function is used to move
592 * keys from one token to another */
593 SECStatus
594 PK11_ExtractKeyValue(PK11SymKey *symKey)
595 {
596 SECStatus rv;
597
598 if (symKey->data.data != NULL) {
599 if (symKey->size == 0) {
600 symKey->size = symKey->data.len;
601 }
602 return SECSuccess;
603 }
604
605 if (symKey->slot == NULL) {
606 PORT_SetError( SEC_ERROR_INVALID_KEY );
607 return SECFailure;
608 }
609
610 rv = PK11_ReadAttribute(symKey->slot,symKey->objectID,CKA_VALUE,NULL,
611 &symKey->data);
612 if (rv == SECSuccess) {
613 symKey->size = symKey->data.len;
614 }
615 return rv;
616 }
617
618 SECStatus
619 PK11_DeleteTokenSymKey(PK11SymKey *symKey)
620 {
621 if (!PK11_IsPermObject(symKey->slot, symKey->objectID)) {
622 return SECFailure;
623 }
624 PK11_DestroyTokenObject(symKey->slot,symKey->objectID);
625 symKey->objectID = CK_INVALID_HANDLE;
626 return SECSuccess;
627 }
628
629 SECItem *
630 PK11_GetKeyData(PK11SymKey *symKey)
631 {
632 return &symKey->data;
633 }
634
635 /* This symbol is exported for backward compatibility. */
636 SECItem *
637 __PK11_GetKeyData(PK11SymKey *symKey)
638 {
639 return PK11_GetKeyData(symKey);
640 }
641
642
643 /*
644 * PKCS #11 key Types with predefined length
645 */
646 unsigned int
647 pk11_GetPredefinedKeyLength(CK_KEY_TYPE keyType)
648 {
649 int length = 0;
650 switch (keyType) {
651 case CKK_DES: length = 8; break;
652 case CKK_DES2: length = 16; break;
653 case CKK_DES3: length = 24; break;
654 case CKK_SKIPJACK: length = 10; break;
655 case CKK_BATON: length = 20; break;
656 case CKK_JUNIPER: length = 20; break;
657 default: break;
658 }
659 return length;
660 }
661
662 /* return the keylength if possible. '0' if not */
663 unsigned int
664 PK11_GetKeyLength(PK11SymKey *key)
665 {
666 CK_KEY_TYPE keyType;
667
668 if (key->size != 0) return key->size;
669
670 /* First try to figure out the key length from its type */
671 keyType = PK11_ReadULongAttribute(key->slot,key->objectID,CKA_KEY_TYPE);
672 key->size = pk11_GetPredefinedKeyLength(keyType);
673 if ((keyType == CKK_GENERIC_SECRET) &&
674 (key->type == CKM_SSL3_PRE_MASTER_KEY_GEN)) {
675 key->size=48;
676 }
677
678 if( key->size != 0 ) return key->size;
679
680 if (key->data.data == NULL) {
681 PK11_ExtractKeyValue(key);
682 }
683 /* key is probably secret. Look up its length */
684 /* this is new PKCS #11 version 2.0 functionality. */
685 if (key->size == 0) {
686 CK_ULONG keyLength;
687
688 keyLength = PK11_ReadULongAttribute(key->slot,key->objectID,CKA_VALUE_LE N);
689 if (keyLength != CK_UNAVAILABLE_INFORMATION) {
690 key->size = (unsigned int)keyLength;
691 }
692 }
693
694 return key->size;
695 }
696
697 /* return the strength of a key. This is different from length in that
698 * 1) it returns the size in bits, and 2) it returns only the secret portions
699 * of the key minus any checksums or parity.
700 */
701 unsigned int
702 PK11_GetKeyStrength(PK11SymKey *key, SECAlgorithmID *algid)
703 {
704 int size=0;
705 CK_MECHANISM_TYPE mechanism= CKM_INVALID_MECHANISM; /* RC2 only */
706 SECItem *param = NULL; /* RC2 only */
707 CK_RC2_CBC_PARAMS *rc2_params = NULL; /* RC2 ONLY */
708 unsigned int effectiveBits = 0; /* RC2 ONLY */
709
710 switch (PK11_GetKeyType(key->type,0)) {
711 case CKK_CDMF:
712 return 40;
713 case CKK_DES:
714 return 56;
715 case CKK_DES3:
716 case CKK_DES2:
717 size = PK11_GetKeyLength(key);
718 if (size == 16) {
719 /* double des */
720 return 112; /* 16*7 */
721 }
722 return 168;
723 /*
724 * RC2 has is different than other ciphers in that it allows the user
725 * to deprecating keysize while still requiring all the bits for the
726 * original key. The info
727 * on what the effective key strength is in the parameter for the key.
728 * In S/MIME this parameter is stored in the DER encoded algid. In Our
729 * other uses of RC2, effectiveBits == keyBits, so this code functions
730 * correctly without an algid.
731 */
732 case CKK_RC2:
733 /* if no algid was provided, fall through to default */
734 if (!algid) {
735 break;
736 }
737 /* verify that the algid is for RC2 */
738 mechanism = PK11_AlgtagToMechanism(SECOID_GetAlgorithmTag(algid));
739 if ((mechanism != CKM_RC2_CBC) && (mechanism != CKM_RC2_ECB)) {
740 break;
741 }
742
743 /* now get effective bits from the algorithm ID. */
744 param = PK11_ParamFromAlgid(algid);
745 /* if we couldn't get memory just use key length */
746 if (param == NULL) {
747 break;
748 }
749
750 rc2_params = (CK_RC2_CBC_PARAMS *) param->data;
751 /* paranoia... shouldn't happen */
752 PORT_Assert(param->data != NULL);
753 if (param->data == NULL) {
754 SECITEM_FreeItem(param,PR_TRUE);
755 break;
756 }
757 effectiveBits = (unsigned int)rc2_params->ulEffectiveBits;
758 SECITEM_FreeItem(param,PR_TRUE);
759 param = NULL; rc2_params=NULL; /* paranoia */
760
761 /* we have effective bits, is and allocated memory is free, now
762 * we need to return the smaller of effective bits and keysize */
763 size = PK11_GetKeyLength(key);
764 if ((unsigned int)size*8 > effectiveBits) {
765 return effectiveBits;
766 }
767
768 return size*8; /* the actual key is smaller, the strength can't be
769 * greater than the actual key size */
770
771 default:
772 break;
773 }
774 return PK11_GetKeyLength(key) * 8;
775 }
776
777 /*
778 * The next three utilities are to deal with the fact that a given operation
779 * may be a multi-slot affair. This creates a new key object that is copied
780 * into the new slot.
781 */
782 PK11SymKey *
783 pk11_CopyToSlotPerm(PK11SlotInfo *slot,CK_MECHANISM_TYPE type,
784 CK_ATTRIBUTE_TYPE operation, CK_FLAGS flags,
785 PRBool isPerm, PK11SymKey *symKey)
786 {
787 SECStatus rv;
788 PK11SymKey *newKey = NULL;
789
790 /* Extract the raw key data if possible */
791 if (symKey->data.data == NULL) {
792 rv = PK11_ExtractKeyValue(symKey);
793 /* KEY is sensitive, we're try key exchanging it. */
794 if (rv != SECSuccess) {
795 return pk11_KeyExchange(slot, type, operation,
796 flags, isPerm, symKey);
797 }
798 }
799
800 newKey = PK11_ImportSymKeyWithFlags(slot, type, symKey->origin,
801 operation, &symKey->data, flags, isPerm, symKey->cx);
802 if (newKey == NULL) {
803 newKey = pk11_KeyExchange(slot, type, operation, flags, isPerm, symKey);
804 }
805 return newKey;
806 }
807
808 PK11SymKey *
809 pk11_CopyToSlot(PK11SlotInfo *slot,CK_MECHANISM_TYPE type,
810 CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey)
811 {
812 return pk11_CopyToSlotPerm(slot, type, operation, 0, PR_FALSE, symKey);
813 }
814
815 /*
816 * Make sure the slot we are in is the correct slot for the operation
817 * by verifying that it supports all of the specified mechanism types.
818 */
819 PK11SymKey *
820 pk11_ForceSlotMultiple(PK11SymKey *symKey, CK_MECHANISM_TYPE *type,
821 int mechCount, CK_ATTRIBUTE_TYPE operation)
822 {
823 PK11SlotInfo *slot = symKey->slot;
824 PK11SymKey *newKey = NULL;
825 PRBool needToCopy = PR_FALSE;
826 int i;
827
828 if (slot == NULL) {
829 needToCopy = PR_TRUE;
830 } else {
831 i = 0;
832 while ((i < mechCount) && (needToCopy == PR_FALSE)) {
833 if (!PK11_DoesMechanism(slot,type[i])) {
834 needToCopy = PR_TRUE;
835 }
836 i++;
837 }
838 }
839
840 if (needToCopy == PR_TRUE) {
841 slot = PK11_GetBestSlotMultiple(type,mechCount,symKey->cx);
842 if (slot == NULL) {
843 PORT_SetError( SEC_ERROR_NO_MODULE );
844 return NULL;
845 }
846 newKey = pk11_CopyToSlot(slot, type[0], operation, symKey);
847 PK11_FreeSlot(slot);
848 }
849 return newKey;
850 }
851
852 /*
853 * Make sure the slot we are in is the correct slot for the operation
854 */
855 PK11SymKey *
856 pk11_ForceSlot(PK11SymKey *symKey,CK_MECHANISM_TYPE type,
857 CK_ATTRIBUTE_TYPE operation)
858 {
859 return pk11_ForceSlotMultiple(symKey, &type, 1, operation);
860 }
861
862 PK11SymKey *
863 PK11_MoveSymKey(PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation,
864 CK_FLAGS flags, PRBool perm, PK11SymKey *symKey)
865 {
866 if (symKey->slot == slot) {
867 if (perm) {
868 return PK11_ConvertSessionSymKeyToTokenSymKey(symKey,symKey->cx);
869 } else {
870 return PK11_ReferenceSymKey(symKey);
871 }
872 }
873
874 return pk11_CopyToSlotPerm(slot, symKey->type,
875 operation, flags, perm, symKey);
876 }
877
878 /*
879 * Use the token to generate a key.
880 *
881 * keySize must be 'zero' for fixed key length algorithms. A nonzero
882 * keySize causes the CKA_VALUE_LEN attribute to be added to the template
883 * for the key. Most PKCS #11 modules fail if you specify the CKA_VALUE_LEN
884 * attribute for keys with fixed length. The exception is DES2. If you
885 * select a CKM_DES3_CBC mechanism, this code will not add the CKA_VALUE_LEN
886 * parameter and use the key size to determine which underlying DES keygen
887 * function to use (CKM_DES2_KEY_GEN or CKM_DES3_KEY_GEN).
888 *
889 * keyType must be -1 for most algorithms. Some PBE algorthims cannot
890 * determine the correct key type from the mechanism or the parameters,
891 * so key type must be specified. Other PKCS #11 mechanisms may do so in
892 * the future. Currently there is no need to export this publically.
893 * Keep it private until there is a need in case we need to expand the
894 * keygen parameters again...
895 *
896 * CK_FLAGS flags: key operation flags
897 * PK11AttrFlags attrFlags: PK11_ATTR_XXX key attribute flags
898 */
899 PK11SymKey *
900 pk11_TokenKeyGenWithFlagsAndKeyType(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
901 SECItem *param, CK_KEY_TYPE keyType, int keySize, SECItem *keyid,
902 CK_FLAGS opFlags, PK11AttrFlags attrFlags, void *wincx)
903 {
904 PK11SymKey *symKey;
905 CK_ATTRIBUTE genTemplate[MAX_TEMPL_ATTRS];
906 CK_ATTRIBUTE *attrs = genTemplate;
907 int count = sizeof(genTemplate)/sizeof(genTemplate[0]);
908 CK_MECHANISM_TYPE keyGenType;
909 CK_BBOOL cktrue = CK_TRUE;
910 CK_BBOOL ckfalse = CK_FALSE;
911 CK_ULONG ck_key_size; /* only used for variable-length keys */
912
913 if (pk11_BadAttrFlags(attrFlags)) {
914 PORT_SetError( SEC_ERROR_INVALID_ARGS );
915 return NULL;
916 }
917
918 if ((keySize != 0) && (type != CKM_DES3_CBC) &&
919 (type !=CKM_DES3_CBC_PAD) && (type != CKM_DES3_ECB)) {
920 ck_key_size = keySize; /* Convert to PK11 type */
921
922 PK11_SETATTRS(attrs, CKA_VALUE_LEN, &ck_key_size, sizeof(ck_key_size));
923 attrs++;
924 }
925
926 if (keyType != -1) {
927 PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(CK_KEY_TYPE));
928 attrs++;
929 }
930
931 /* Include key id value if provided */
932 if (keyid) {
933 PK11_SETATTRS(attrs, CKA_ID, keyid->data, keyid->len); attrs++;
934 }
935
936 attrs += pk11_AttrFlagsToAttributes(attrFlags, attrs, &cktrue, &ckfalse);
937 attrs += pk11_OpFlagsToAttributes(opFlags, attrs, &cktrue);
938
939 count = attrs - genTemplate;
940 PR_ASSERT(count <= sizeof(genTemplate)/sizeof(CK_ATTRIBUTE));
941
942 keyGenType = PK11_GetKeyGenWithSize(type, keySize);
943 if (keyGenType == CKM_FAKE_RANDOM) {
944 PORT_SetError( SEC_ERROR_NO_MODULE );
945 return NULL;
946 }
947 symKey = PK11_KeyGenWithTemplate(slot, type, keyGenType,
948 param, genTemplate, count, wincx);
949 if (symKey != NULL) {
950 symKey->size = keySize;
951 }
952 return symKey;
953 }
954
955 /*
956 * Use the token to generate a key. - Public
957 *
958 * keySize must be 'zero' for fixed key length algorithms. A nonzero
959 * keySize causes the CKA_VALUE_LEN attribute to be added to the template
960 * for the key. Most PKCS #11 modules fail if you specify the CKA_VALUE_LEN
961 * attribute for keys with fixed length. The exception is DES2. If you
962 * select a CKM_DES3_CBC mechanism, this code will not add the CKA_VALUE_LEN
963 * parameter and use the key size to determine which underlying DES keygen
964 * function to use (CKM_DES2_KEY_GEN or CKM_DES3_KEY_GEN).
965 *
966 * CK_FLAGS flags: key operation flags
967 * PK11AttrFlags attrFlags: PK11_ATTR_XXX key attribute flags
968 */
969 PK11SymKey *
970 PK11_TokenKeyGenWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
971 SECItem *param, int keySize, SECItem *keyid, CK_FLAGS opFlags,
972 PK11AttrFlags attrFlags, void *wincx)
973 {
974 return pk11_TokenKeyGenWithFlagsAndKeyType(slot, type, param, -1, keySize,
975 keyid, opFlags, attrFlags, wincx);
976 }
977
978 /*
979 * Use the token to generate a key. keySize must be 'zero' for fixed key
980 * length algorithms. A nonzero keySize causes the CKA_VALUE_LEN attribute
981 * to be added to the template for the key. PKCS #11 modules fail if you
982 * specify the CKA_VALUE_LEN attribute for keys with fixed length.
983 * NOTE: this means to generate a DES2 key from this interface you must
984 * specify CKM_DES2_KEY_GEN as the mechanism directly; specifying
985 * CKM_DES3_CBC as the mechanism and 16 as keySize currently doesn't work.
986 */
987 PK11SymKey *
988 PK11_TokenKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param,
989 int keySize, SECItem *keyid, PRBool isToken, void *wincx)
990 {
991 PK11SymKey *symKey;
992 PRBool weird = PR_FALSE; /* hack for fortezza */
993 CK_FLAGS opFlags = CKF_SIGN;
994 PK11AttrFlags attrFlags = 0;
995
996 if ((keySize == -1) && (type == CKM_SKIPJACK_CBC64)) {
997 weird = PR_TRUE;
998 keySize = 0;
999 }
1000
1001 opFlags |= weird ? CKF_DECRYPT : CKF_ENCRYPT;
1002
1003 if (isToken) {
1004 attrFlags |= (PK11_ATTR_TOKEN | PK11_ATTR_PRIVATE);
1005 }
1006
1007 symKey = pk11_TokenKeyGenWithFlagsAndKeyType(slot, type, param,
1008 -1, keySize, keyid, opFlags, attrFlags, wincx);
1009 if (symKey && weird) {
1010 PK11_SetFortezzaHack(symKey);
1011 }
1012
1013 return symKey;
1014 }
1015
1016 PK11SymKey *
1017 PK11_KeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param,
1018 int keySize, void *wincx)
1019 {
1020 return PK11_TokenKeyGen(slot, type, param, keySize, 0, PR_FALSE, wincx);
1021 }
1022
1023 PK11SymKey *
1024 PK11_KeyGenWithTemplate(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
1025 CK_MECHANISM_TYPE keyGenType,
1026 SECItem *param, CK_ATTRIBUTE * attrs,
1027 unsigned int attrsCount, void *wincx)
1028 {
1029 PK11SymKey *symKey;
1030 CK_SESSION_HANDLE session;
1031 CK_MECHANISM mechanism;
1032 CK_RV crv;
1033 PRBool isToken = CK_FALSE;
1034 CK_ULONG keySize = 0;
1035 unsigned i;
1036
1037 /* Extract the template's CKA_VALUE_LEN into keySize and CKA_TOKEN into
1038 isToken. */
1039 for (i = 0; i < attrsCount; ++i) {
1040 switch (attrs[i].type) {
1041 case CKA_VALUE_LEN:
1042 if (attrs[i].pValue == NULL ||
1043 attrs[i].ulValueLen != sizeof(CK_ULONG)) {
1044 PORT_SetError(PK11_MapError(CKR_TEMPLATE_INCONSISTENT));
1045 return NULL;
1046 }
1047 keySize = * (CK_ULONG *) attrs[i].pValue;
1048 break;
1049 case CKA_TOKEN:
1050 if (attrs[i].pValue == NULL ||
1051 attrs[i].ulValueLen != sizeof(CK_BBOOL)) {
1052 PORT_SetError(PK11_MapError(CKR_TEMPLATE_INCONSISTENT));
1053 return NULL;
1054 }
1055 isToken = (*(CK_BBOOL*)attrs[i].pValue) ? PR_TRUE : PR_FALSE;
1056 break;
1057 }
1058 }
1059
1060 /* find a slot to generate the key into */
1061 /* Only do slot management if this is not a token key */
1062 if (!isToken && (slot == NULL || !PK11_DoesMechanism(slot,type))) {
1063 PK11SlotInfo *bestSlot = PK11_GetBestSlot(type,wincx);
1064 if (bestSlot == NULL) {
1065 PORT_SetError( SEC_ERROR_NO_MODULE );
1066 return NULL;
1067 }
1068 symKey = pk11_CreateSymKey(bestSlot, type, !isToken, PR_TRUE, wincx);
1069 PK11_FreeSlot(bestSlot);
1070 } else {
1071 symKey = pk11_CreateSymKey(slot, type, !isToken, PR_TRUE, wincx);
1072 }
1073 if (symKey == NULL) return NULL;
1074
1075 symKey->size = keySize;
1076 symKey->origin = PK11_OriginGenerated;
1077
1078 /* Set the parameters for the key gen if provided */
1079 mechanism.mechanism = keyGenType;
1080 mechanism.pParameter = NULL;
1081 mechanism.ulParameterLen = 0;
1082 if (param) {
1083 mechanism.pParameter = param->data;
1084 mechanism.ulParameterLen = param->len;
1085 }
1086
1087 /* Get session and perform locking */
1088 if (isToken) {
1089 PK11_Authenticate(symKey->slot,PR_TRUE,wincx);
1090 /* Should always be original slot */
1091 session = PK11_GetRWSession(symKey->slot);
1092 symKey->owner = PR_FALSE;
1093 } else {
1094 session = symKey->session;
1095 if (session != CK_INVALID_SESSION)
1096 pk11_EnterKeyMonitor(symKey);
1097 }
1098 if (session == CK_INVALID_SESSION) {
1099 PK11_FreeSymKey(symKey);
1100 PORT_SetError(SEC_ERROR_BAD_DATA);
1101 return NULL;
1102 }
1103
1104 crv = PK11_GETTAB(symKey->slot)->C_GenerateKey(session,
1105 &mechanism, attrs, attrsCount, &symKey->objectID);
1106
1107 /* Release lock and session */
1108 if (isToken) {
1109 PK11_RestoreROSession(symKey->slot, session);
1110 } else {
1111 pk11_ExitKeyMonitor(symKey);
1112 }
1113
1114 if (crv != CKR_OK) {
1115 PK11_FreeSymKey(symKey);
1116 PORT_SetError( PK11_MapError(crv) );
1117 return NULL;
1118 }
1119
1120 return symKey;
1121 }
1122
1123
1124 /* --- */
1125 PK11SymKey *
1126 PK11_GenDES3TokenKey(PK11SlotInfo *slot, SECItem *keyid, void *cx)
1127 {
1128 return PK11_TokenKeyGen(slot, CKM_DES3_CBC, 0, 0, keyid, PR_TRUE, cx);
1129 }
1130
1131 PK11SymKey*
1132 PK11_ConvertSessionSymKeyToTokenSymKey(PK11SymKey *symk, void *wincx)
1133 {
1134 PK11SlotInfo* slot = symk->slot;
1135 CK_ATTRIBUTE template[1];
1136 CK_ATTRIBUTE *attrs = template;
1137 CK_BBOOL cktrue = CK_TRUE;
1138 CK_RV crv;
1139 CK_OBJECT_HANDLE newKeyID;
1140 CK_SESSION_HANDLE rwsession;
1141
1142 PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue)); attrs++;
1143
1144 PK11_Authenticate(slot, PR_TRUE, wincx);
1145 rwsession = PK11_GetRWSession(slot);
1146 if (rwsession == CK_INVALID_SESSION) {
1147 PORT_SetError(SEC_ERROR_BAD_DATA);
1148 return NULL;
1149 }
1150 crv = PK11_GETTAB(slot)->C_CopyObject(rwsession, symk->objectID,
1151 template, 1, &newKeyID);
1152 PK11_RestoreROSession(slot, rwsession);
1153
1154 if (crv != CKR_OK) {
1155 PORT_SetError( PK11_MapError(crv) );
1156 return NULL;
1157 }
1158
1159 return PK11_SymKeyFromHandle(slot, NULL /*parent*/, symk->origin,
1160 symk->type, newKeyID, PR_FALSE /*owner*/, NULL /*wincx*/);
1161 }
1162
1163 /*
1164 * This function does a straight public key wrap (which only RSA can do).
1165 * Use PK11_PubGenKey and PK11_WrapSymKey to implement the FORTEZZA and
1166 * Diffie-Hellman Ciphers. */
1167 SECStatus
1168 PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
1169 PK11SymKey *symKey, SECItem *wrappedKey)
1170 {
1171 PK11SlotInfo *slot;
1172 CK_ULONG len = wrappedKey->len;
1173 PK11SymKey *newKey = NULL;
1174 CK_OBJECT_HANDLE id;
1175 CK_MECHANISM mechanism;
1176 PRBool owner = PR_TRUE;
1177 CK_SESSION_HANDLE session;
1178 CK_RV crv;
1179
1180 if (symKey == NULL) {
1181 PORT_SetError( SEC_ERROR_INVALID_ARGS );
1182 return SECFailure;
1183 }
1184
1185 /* if this slot doesn't support the mechanism, go to a slot that does */
1186 newKey = pk11_ForceSlot(symKey,type,CKA_ENCRYPT);
1187 if (newKey != NULL) {
1188 symKey = newKey;
1189 }
1190
1191 if (symKey->slot == NULL) {
1192 PORT_SetError( SEC_ERROR_NO_MODULE );
1193 return SECFailure;
1194 }
1195
1196 slot = symKey->slot;
1197 mechanism.mechanism = pk11_mapWrapKeyType(pubKey->keyType);
1198 mechanism.pParameter = NULL;
1199 mechanism.ulParameterLen = 0;
1200
1201 id = PK11_ImportPublicKey(slot,pubKey,PR_FALSE);
1202 if (id == CK_INVALID_HANDLE) {
1203 if (newKey) {
1204 PK11_FreeSymKey(newKey);
1205 }
1206 return SECFailure; /* Error code has been set. */
1207 }
1208
1209 session = pk11_GetNewSession(slot,&owner);
1210 if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
1211 crv = PK11_GETTAB(slot)->C_WrapKey(session,&mechanism,
1212 id,symKey->objectID,wrappedKey->data,&len);
1213 if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
1214 pk11_CloseSession(slot,session,owner);
1215 if (newKey) {
1216 PK11_FreeSymKey(newKey);
1217 }
1218
1219 if (crv != CKR_OK) {
1220 PORT_SetError( PK11_MapError(crv) );
1221 return SECFailure;
1222 }
1223 wrappedKey->len = len;
1224 return SECSuccess;
1225 }
1226
1227 /*
1228 * this little function uses the Encrypt function to wrap a key, just in
1229 * case we have problems with the wrap implementation for a token.
1230 */
1231 static SECStatus
1232 pk11_HandWrap(PK11SymKey *wrappingKey, SECItem *param, CK_MECHANISM_TYPE type,
1233 SECItem *inKey, SECItem *outKey)
1234 {
1235 PK11SlotInfo *slot;
1236 CK_ULONG len;
1237 SECItem *data;
1238 CK_MECHANISM mech;
1239 PRBool owner = PR_TRUE;
1240 CK_SESSION_HANDLE session;
1241 CK_RV crv;
1242
1243 slot = wrappingKey->slot;
1244 /* use NULL IV's for wrapping */
1245 mech.mechanism = type;
1246 if (param) {
1247 mech.pParameter = param->data;
1248 mech.ulParameterLen = param->len;
1249 } else {
1250 mech.pParameter = NULL;
1251 mech.ulParameterLen = 0;
1252 }
1253 session = pk11_GetNewSession(slot,&owner);
1254 if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
1255 crv = PK11_GETTAB(slot)->C_EncryptInit(session,&mech,
1256 wrappingKey->objectID);
1257 if (crv != CKR_OK) {
1258 if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
1259 pk11_CloseSession(slot,session,owner);
1260 PORT_SetError( PK11_MapError(crv) );
1261 return SECFailure;
1262 }
1263
1264 /* keys are almost always aligned, but if we get this far,
1265 * we've gone above and beyond anyway... */
1266 data = PK11_BlockData(inKey,PK11_GetBlockSize(type,param));
1267 if (data == NULL) {
1268 if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
1269 pk11_CloseSession(slot,session,owner);
1270 PORT_SetError(SEC_ERROR_NO_MEMORY);
1271 return SECFailure;
1272 }
1273 len = outKey->len;
1274 crv = PK11_GETTAB(slot)->C_Encrypt(session,data->data,data->len,
1275 outKey->data, &len);
1276 if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
1277 pk11_CloseSession(slot,session,owner);
1278 SECITEM_FreeItem(data,PR_TRUE);
1279 outKey->len = len;
1280 if (crv != CKR_OK) {
1281 PORT_SetError( PK11_MapError(crv) );
1282 return SECFailure;
1283 }
1284 return SECSuccess;
1285 }
1286
1287 /*
1288 * This function does a symetric based wrap.
1289 */
1290 SECStatus
1291 PK11_WrapSymKey(CK_MECHANISM_TYPE type, SECItem *param,
1292 PK11SymKey *wrappingKey, PK11SymKey *symKey, SECItem *wrappedKey)
1293 {
1294 PK11SlotInfo *slot;
1295 CK_ULONG len = wrappedKey->len;
1296 PK11SymKey *newKey = NULL;
1297 SECItem *param_save = NULL;
1298 CK_MECHANISM mechanism;
1299 PRBool owner = PR_TRUE;
1300 CK_SESSION_HANDLE session;
1301 CK_RV crv;
1302 SECStatus rv;
1303
1304 /* if this slot doesn't support the mechanism, go to a slot that does */
1305 /* Force symKey and wrappingKey into the same slot */
1306 if ((wrappingKey->slot == NULL) || (symKey->slot != wrappingKey->slot)) {
1307 /* first try copying the wrapping Key to the symKey slot */
1308 if (symKey->slot && PK11_DoesMechanism(symKey->slot,type)) {
1309 newKey = pk11_CopyToSlot(symKey->slot,type,CKA_WRAP,wrappingKey);
1310 }
1311 /* Nope, try it the other way */
1312 if (newKey == NULL) {
1313 if (wrappingKey->slot) {
1314 newKey = pk11_CopyToSlot(wrappingKey->slot,
1315 symKey->type, CKA_ENCRYPT, symKey);
1316 }
1317 /* just not playing... one last thing, can we get symKey's data?
1318 * If it's possible, we it should already be in the
1319 * symKey->data.data pointer because pk11_CopyToSlot would have
1320 * tried to put it there. */
1321 if (newKey == NULL) {
1322 /* Can't get symKey's data: Game Over */
1323 if (symKey->data.data == NULL) {
1324 PORT_SetError( SEC_ERROR_NO_MODULE );
1325 return SECFailure;
1326 }
1327 if (param == NULL) {
1328 param_save = param = PK11_ParamFromIV(type,NULL);
1329 }
1330 rv = pk11_HandWrap(wrappingKey, param, type,
1331 &symKey->data,wrappedKey);
1332 if (param_save) SECITEM_FreeItem(param_save,PR_TRUE);
1333 return rv;
1334 }
1335 /* we successfully moved the sym Key */
1336 symKey = newKey;
1337 } else {
1338 /* we successfully moved the wrapping Key */
1339 wrappingKey = newKey;
1340 }
1341 }
1342
1343 /* at this point both keys are in the same token */
1344 slot = wrappingKey->slot;
1345 mechanism.mechanism = type;
1346 /* use NULL IV's for wrapping */
1347 if (param == NULL) {
1348 param_save = param = PK11_ParamFromIV(type,NULL);
1349 }
1350 if (param) {
1351 mechanism.pParameter = param->data;
1352 mechanism.ulParameterLen = param->len;
1353 } else {
1354 mechanism.pParameter = NULL;
1355 mechanism.ulParameterLen = 0;
1356 }
1357
1358 len = wrappedKey->len;
1359
1360 session = pk11_GetNewSession(slot,&owner);
1361 if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
1362 crv = PK11_GETTAB(slot)->C_WrapKey(session, &mechanism,
1363 wrappingKey->objectID, symKey->objectID,
1364 wrappedKey->data, &len);
1365 if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
1366 pk11_CloseSession(slot,session,owner);
1367 rv = SECSuccess;
1368 if (crv != CKR_OK) {
1369 /* can't wrap it? try hand wrapping it... */
1370 do {
1371 if (symKey->data.data == NULL) {
1372 rv = PK11_ExtractKeyValue(symKey);
1373 if (rv != SECSuccess) break;
1374 }
1375 rv = pk11_HandWrap(wrappingKey, param, type, &symKey->data,
1376 wrappedKey);
1377 } while (PR_FALSE);
1378 } else {
1379 wrappedKey->len = len;
1380 }
1381 if (newKey) PK11_FreeSymKey(newKey);
1382 if (param_save) SECITEM_FreeItem(param_save,PR_TRUE);
1383 return rv;
1384 }
1385
1386 /*
1387 * This Generates a new key based on a symetricKey
1388 */
1389 PK11SymKey *
1390 PK11_Derive( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, SECItem *param,
1391 CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
1392 int keySize)
1393 {
1394 return PK11_DeriveWithTemplate(baseKey, derive, param, target, operation,
1395 keySize, NULL, 0, PR_FALSE);
1396 }
1397
1398
1399 PK11SymKey *
1400 PK11_DeriveWithFlags( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive,
1401 SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
1402 int keySize, CK_FLAGS flags)
1403 {
1404 CK_BBOOL ckTrue = CK_TRUE;
1405 CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
1406 unsigned int templateCount;
1407
1408 templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
1409 return PK11_DeriveWithTemplate(baseKey, derive, param, target, operation,
1410 keySize, keyTemplate, templateCount, PR_FALSE);
1411 }
1412
1413 PK11SymKey *
1414 PK11_DeriveWithFlagsPerm( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive,
1415 SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
1416 int keySize, CK_FLAGS flags, PRBool isPerm)
1417 {
1418 CK_BBOOL cktrue = CK_TRUE;
1419 CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
1420 CK_ATTRIBUTE *attrs;
1421 unsigned int templateCount = 0;
1422
1423 attrs = keyTemplate;
1424 if (isPerm) {
1425 PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); attrs++;
1426 }
1427 templateCount = attrs - keyTemplate;
1428 templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
1429 return PK11_DeriveWithTemplate(baseKey, derive, param, target, operation,
1430 keySize, keyTemplate, templateCount, isPerm);
1431 }
1432
1433 PK11SymKey *
1434 PK11_DeriveWithTemplate( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive,
1435 SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
1436 int keySize, CK_ATTRIBUTE *userAttr, unsigned int numAttrs,
1437 PRBool isPerm)
1438 {
1439 PK11SlotInfo * slot = baseKey->slot;
1440 PK11SymKey * symKey;
1441 PK11SymKey * newBaseKey = NULL;
1442 CK_BBOOL cktrue = CK_TRUE;
1443 CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
1444 CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
1445 CK_ULONG valueLen = 0;
1446 CK_MECHANISM mechanism;
1447 CK_RV crv;
1448 #define MAX_ADD_ATTRS 4
1449 CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS + MAX_ADD_ATTRS];
1450 #undef MAX_ADD_ATTRS
1451 CK_ATTRIBUTE * attrs = keyTemplate;
1452 CK_SESSION_HANDLE session;
1453 unsigned int templateCount;
1454
1455 if (numAttrs > MAX_TEMPL_ATTRS) {
1456 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1457 return NULL;
1458 }
1459
1460 /* first copy caller attributes in. */
1461 for (templateCount = 0; templateCount < numAttrs; ++templateCount) {
1462 *attrs++ = *userAttr++;
1463 }
1464
1465 /* We only add the following attributes to the template if the caller
1466 ** didn't already supply them.
1467 */
1468 if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_CLASS)) {
1469 PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof keyClass);
1470 attrs++;
1471 }
1472 if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_KEY_TYPE)) {
1473 keyType = PK11_GetKeyType(target, keySize);
1474 PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof keyType );
1475 attrs++;
1476 }
1477 if (keySize > 0 &&
1478 !pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_VALUE_LEN)) {
1479 valueLen = (CK_ULONG)keySize;
1480 PK11_SETATTRS(attrs, CKA_VALUE_LEN, &valueLen, sizeof valueLen);
1481 attrs++;
1482 }
1483 if ((operation != CKA_FLAGS_ONLY) &&
1484 !pk11_FindAttrInTemplate(keyTemplate, numAttrs, operation)) {
1485 PK11_SETATTRS(attrs, operation, &cktrue, sizeof cktrue); attrs++;
1486 }
1487
1488 templateCount = attrs - keyTemplate;
1489 PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
1490
1491 /* move the key to a slot that can do the function */
1492 if (!PK11_DoesMechanism(slot,derive)) {
1493 /* get a new base key & slot */
1494 PK11SlotInfo *newSlot = PK11_GetBestSlot(derive, baseKey->cx);
1495
1496 if (newSlot == NULL) return NULL;
1497
1498 newBaseKey = pk11_CopyToSlot (newSlot, derive, CKA_DERIVE,
1499 baseKey);
1500 PK11_FreeSlot(newSlot);
1501 if (newBaseKey == NULL)
1502 return NULL;
1503 baseKey = newBaseKey;
1504 slot = baseKey->slot;
1505 }
1506
1507
1508 /* get our key Structure */
1509 symKey = pk11_CreateSymKey(slot, target, !isPerm, PR_TRUE, baseKey->cx);
1510 if (symKey == NULL) {
1511 return NULL;
1512 }
1513
1514 symKey->size = keySize;
1515
1516 mechanism.mechanism = derive;
1517 if (param) {
1518 mechanism.pParameter = param->data;
1519 mechanism.ulParameterLen = param->len;
1520 } else {
1521 mechanism.pParameter = NULL;
1522 mechanism.ulParameterLen = 0;
1523 }
1524 symKey->origin=PK11_OriginDerive;
1525
1526 if (isPerm) {
1527 session = PK11_GetRWSession(slot);
1528 } else {
1529 pk11_EnterKeyMonitor(symKey);
1530 session = symKey->session;
1531 }
1532 if (session == CK_INVALID_SESSION) {
1533 if (!isPerm)
1534 pk11_ExitKeyMonitor(symKey);
1535 crv = CKR_SESSION_HANDLE_INVALID;
1536 } else {
1537 crv = PK11_GETTAB(slot)->C_DeriveKey(session, &mechanism,
1538 baseKey->objectID, keyTemplate, templateCount, &symKey->objectID);
1539 if (isPerm) {
1540 PK11_RestoreROSession(slot, session);
1541 } else {
1542 pk11_ExitKeyMonitor(symKey);
1543 }
1544 }
1545 if (newBaseKey)
1546 PK11_FreeSymKey(newBaseKey);
1547 if (crv != CKR_OK) {
1548 PK11_FreeSymKey(symKey);
1549 return NULL;
1550 }
1551 return symKey;
1552 }
1553
1554 /* Create a new key by concatenating base and data
1555 */
1556 static PK11SymKey *pk11_ConcatenateBaseAndData(PK11SymKey *base,
1557 CK_BYTE *data, CK_ULONG dataLen, CK_MECHANISM_TYPE target,
1558 CK_ATTRIBUTE_TYPE operation)
1559 {
1560 CK_KEY_DERIVATION_STRING_DATA mechParams;
1561 SECItem param;
1562
1563 if (base == NULL) {
1564 PORT_SetError( SEC_ERROR_INVALID_ARGS );
1565 return NULL;
1566 }
1567
1568 mechParams.pData = data;
1569 mechParams.ulLen = dataLen;
1570 param.data = (unsigned char *)&mechParams;
1571 param.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
1572
1573 return PK11_Derive(base, CKM_CONCATENATE_BASE_AND_DATA,
1574 &param, target, operation, 0);
1575 }
1576
1577 /* Create a new key by concatenating base and key
1578 */
1579 static PK11SymKey *pk11_ConcatenateBaseAndKey(PK11SymKey *base,
1580 PK11SymKey *key, CK_MECHANISM_TYPE target,
1581 CK_ATTRIBUTE_TYPE operation, CK_ULONG keySize)
1582 {
1583 SECItem param;
1584
1585 if ((base == NULL) || (key == NULL)) {
1586 PORT_SetError( SEC_ERROR_INVALID_ARGS );
1587 return NULL;
1588 }
1589
1590 param.data = (unsigned char *)&(key->objectID);
1591 param.len = sizeof(CK_OBJECT_HANDLE);
1592
1593 return PK11_Derive(base, CKM_CONCATENATE_BASE_AND_KEY,
1594 &param, target, operation, keySize);
1595 }
1596
1597 /* Create a new key whose value is the hash of tobehashed.
1598 * type is the mechanism for the derived key.
1599 */
1600 static PK11SymKey *pk11_HashKeyDerivation(PK11SymKey *toBeHashed,
1601 CK_MECHANISM_TYPE hashMechanism, CK_MECHANISM_TYPE target,
1602 CK_ATTRIBUTE_TYPE operation, CK_ULONG keySize)
1603 {
1604 return PK11_Derive(toBeHashed, hashMechanism, NULL, target, operation, keySi ze);
1605 }
1606
1607 /* This function implements the ANSI X9.63 key derivation function
1608 */
1609 static PK11SymKey *pk11_ANSIX963Derive(PK11SymKey *sharedSecret,
1610 CK_EC_KDF_TYPE kdf, SECItem *sharedData,
1611 CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
1612 CK_ULONG keySize)
1613 {
1614 CK_KEY_TYPE keyType;
1615 CK_MECHANISM_TYPE hashMechanism, mechanismArray[4];
1616 CK_ULONG derivedKeySize, HashLen, counter, maxCounter, bufferLen;
1617 CK_ULONG SharedInfoLen;
1618 CK_BYTE *buffer = NULL;
1619 PK11SymKey *toBeHashed, *hashOutput;
1620 PK11SymKey *newSharedSecret = NULL;
1621 PK11SymKey *oldIntermediateResult, *intermediateResult = NULL;
1622
1623 if (sharedSecret == NULL) {
1624 PORT_SetError( SEC_ERROR_INVALID_ARGS );
1625 return NULL;
1626 }
1627
1628 switch (kdf) {
1629 case CKD_SHA1_KDF:
1630 HashLen = SHA1_LENGTH;
1631 hashMechanism = CKM_SHA1_KEY_DERIVATION;
1632 break;
1633 case CKD_SHA224_KDF:
1634 HashLen = SHA224_LENGTH;
1635 hashMechanism = CKM_SHA224_KEY_DERIVATION;
1636 break;
1637 case CKD_SHA256_KDF:
1638 HashLen = SHA256_LENGTH;
1639 hashMechanism = CKM_SHA256_KEY_DERIVATION;
1640 break;
1641 case CKD_SHA384_KDF:
1642 HashLen = SHA384_LENGTH;
1643 hashMechanism = CKM_SHA384_KEY_DERIVATION;
1644 break;
1645 case CKD_SHA512_KDF:
1646 HashLen = SHA512_LENGTH;
1647 hashMechanism = CKM_SHA512_KEY_DERIVATION;
1648 break;
1649 default:
1650 PORT_SetError( SEC_ERROR_INVALID_ARGS );
1651 return NULL;
1652 }
1653
1654 derivedKeySize = keySize;
1655 if (derivedKeySize == 0) {
1656 keyType = PK11_GetKeyType(target,keySize);
1657 derivedKeySize = pk11_GetPredefinedKeyLength(keyType);
1658 if (derivedKeySize == 0) {
1659 derivedKeySize = HashLen;
1660 }
1661 }
1662
1663 /* Check that key_len isn't too long. The maximum key length could be
1664 * greatly increased if the code below did not limit the 4-byte counter
1665 * to a maximum value of 255. */
1666 if (derivedKeySize > 254 * HashLen) {
1667 PORT_SetError( SEC_ERROR_INVALID_ARGS );
1668 return NULL;
1669 }
1670
1671 maxCounter = derivedKeySize / HashLen;
1672 if (derivedKeySize > maxCounter * HashLen)
1673 maxCounter++;
1674
1675 if ((sharedData == NULL) || (sharedData->data == NULL))
1676 SharedInfoLen = 0;
1677 else
1678 SharedInfoLen = sharedData->len;
1679
1680 bufferLen = SharedInfoLen + 4;
1681
1682 /* Populate buffer with Counter || sharedData
1683 * where Counter is 0x00000001. */
1684 buffer = (unsigned char *)PORT_Alloc(bufferLen);
1685 if (buffer == NULL) {
1686 PORT_SetError(SEC_ERROR_NO_MEMORY);
1687 return NULL;
1688 }
1689
1690 buffer[0] = 0;
1691 buffer[1] = 0;
1692 buffer[2] = 0;
1693 buffer[3] = 1;
1694 if (SharedInfoLen > 0) {
1695 PORT_Memcpy(&buffer[4], sharedData->data, SharedInfoLen);
1696 }
1697
1698 /* Look for a slot that supports the mechanisms needed
1699 * to implement the ANSI X9.63 KDF as well as the
1700 * target mechanism.
1701 */
1702 mechanismArray[0] = CKM_CONCATENATE_BASE_AND_DATA;
1703 mechanismArray[1] = hashMechanism;
1704 mechanismArray[2] = CKM_CONCATENATE_BASE_AND_KEY;
1705 mechanismArray[3] = target;
1706
1707 newSharedSecret = pk11_ForceSlotMultiple(sharedSecret,
1708 mechanismArray, 4, operation);
1709 if (newSharedSecret != NULL) {
1710 sharedSecret = newSharedSecret;
1711 }
1712
1713 for(counter=1; counter <= maxCounter; counter++) {
1714 /* Concatenate shared_secret and buffer */
1715 toBeHashed = pk11_ConcatenateBaseAndData(sharedSecret, buffer,
1716 bufferLen, hashMechanism, operation);
1717 if (toBeHashed == NULL) {
1718 goto loser;
1719 }
1720
1721 /* Hash value */
1722 if (maxCounter == 1) {
1723 /* In this case the length of the key to be derived is
1724 * less than or equal to the length of the hash output.
1725 * So, the output of the hash operation will be the
1726 * dervied key. */
1727 hashOutput = pk11_HashKeyDerivation(toBeHashed, hashMechanism,
1728 target, operation, keySize);
1729 } else {
1730 /* In this case, the output of the hash operation will be
1731 * concatenated with other data to create the derived key. */
1732 hashOutput = pk11_HashKeyDerivation(toBeHashed, hashMechanism,
1733 CKM_CONCATENATE_BASE_AND_KEY, operation, 0);
1734 }
1735 PK11_FreeSymKey(toBeHashed);
1736 if (hashOutput == NULL) {
1737 goto loser;
1738 }
1739
1740 /* Append result to intermediate result, if necessary */
1741 oldIntermediateResult = intermediateResult;
1742
1743 if (oldIntermediateResult == NULL) {
1744 intermediateResult = hashOutput;
1745 } else {
1746 if (counter == maxCounter) {
1747 /* This is the final concatenation, and so the output
1748 * will be the derived key. */
1749 intermediateResult =
1750 pk11_ConcatenateBaseAndKey(oldIntermediateResult,
1751 hashOutput, target, operation, keySize);
1752 } else {
1753 /* The output of this concatenation will be concatenated
1754 * with other data to create the derived key. */
1755 intermediateResult =
1756 pk11_ConcatenateBaseAndKey(oldIntermediateResult,
1757 hashOutput, CKM_CONCATENATE_BASE_AND_KEY,
1758 operation, 0);
1759 }
1760
1761 PK11_FreeSymKey(hashOutput);
1762 PK11_FreeSymKey(oldIntermediateResult);
1763 if (intermediateResult == NULL) {
1764 goto loser;
1765 }
1766 }
1767
1768 /* Increment counter (assumes maxCounter < 255) */
1769 buffer[3]++;
1770 }
1771
1772 PORT_ZFree(buffer, bufferLen);
1773 if (newSharedSecret != NULL)
1774 PK11_FreeSymKey(newSharedSecret);
1775 return intermediateResult;
1776
1777 loser:
1778 if (buffer != NULL)
1779 PORT_ZFree(buffer, bufferLen);
1780 if (newSharedSecret != NULL)
1781 PK11_FreeSymKey(newSharedSecret);
1782 if (intermediateResult != NULL)
1783 PK11_FreeSymKey(intermediateResult);
1784 return NULL;
1785 }
1786
1787 /*
1788 * This Generates a wrapping key based on a privateKey, publicKey, and two
1789 * random numbers. For Mail usage RandomB should be NULL. In the Sender's
1790 * case RandomA is generate, outherwize it is passed.
1791 */
1792 static unsigned char *rb_email = NULL;
1793
1794 PK11SymKey *
1795 PK11_PubDerive(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
1796 PRBool isSender, SECItem *randomA, SECItem *randomB,
1797 CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
1798 CK_ATTRIBUTE_TYPE operation, int keySize,void *wincx)
1799 {
1800 PK11SlotInfo *slot = privKey->pkcs11Slot;
1801 CK_MECHANISM mechanism;
1802 PK11SymKey *symKey;
1803 CK_RV crv;
1804
1805
1806 if (rb_email == NULL) {
1807 rb_email = PORT_ZAlloc(128);
1808 if (rb_email == NULL) {
1809 return NULL;
1810 }
1811 rb_email[127] = 1;
1812 }
1813
1814 /* get our key Structure */
1815 symKey = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, wincx);
1816 if (symKey == NULL) {
1817 return NULL;
1818 }
1819
1820 symKey->origin = PK11_OriginDerive;
1821
1822 switch (privKey->keyType) {
1823 case rsaKey:
1824 case rsaPssKey:
1825 case rsaOaepKey:
1826 case nullKey:
1827 PORT_SetError(SEC_ERROR_BAD_KEY);
1828 break;
1829 case dsaKey:
1830 case keaKey:
1831 case fortezzaKey:
1832 {
1833 CK_KEA_DERIVE_PARAMS param;
1834 param.isSender = (CK_BBOOL) isSender;
1835 param.ulRandomLen = randomA->len;
1836 param.pRandomA = randomA->data;
1837 param.pRandomB = rb_email;
1838 if (randomB)
1839 param.pRandomB = randomB->data;
1840 if (pubKey->keyType == fortezzaKey) {
1841 param.ulPublicDataLen = pubKey->u.fortezza.KEAKey.len;
1842 param.pPublicData = pubKey->u.fortezza.KEAKey.data;
1843 } else {
1844 /* assert type == keaKey */
1845 /* XXX change to match key key types */
1846 param.ulPublicDataLen = pubKey->u.fortezza.KEAKey.len;
1847 param.pPublicData = pubKey->u.fortezza.KEAKey.data;
1848 }
1849
1850 mechanism.mechanism = derive;
1851 mechanism.pParameter = &param;
1852 mechanism.ulParameterLen = sizeof(param);
1853
1854 /* get a new symKey structure */
1855 pk11_EnterKeyMonitor(symKey);
1856 crv=PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism,
1857 privKey->pkcs11ID, NULL, 0, &symKey->objectID);
1858 pk11_ExitKeyMonitor(symKey);
1859 if (crv == CKR_OK) return symKey;
1860 PORT_SetError( PK11_MapError(crv) );
1861 }
1862 break;
1863 case dhKey:
1864 {
1865 CK_BBOOL cktrue = CK_TRUE;
1866 CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
1867 CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
1868 CK_ULONG key_size = 0;
1869 CK_ATTRIBUTE keyTemplate[4];
1870 int templateCount;
1871 CK_ATTRIBUTE *attrs = keyTemplate;
1872
1873 if (pubKey->keyType != dhKey) {
1874 PORT_SetError(SEC_ERROR_BAD_KEY);
1875 break;
1876 }
1877
1878 PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
1879 attrs++;
1880 PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
1881 attrs++;
1882 PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
1883 PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size));
1884 attrs++;
1885 templateCount = attrs - keyTemplate;
1886 PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE)) ;
1887
1888 keyType = PK11_GetKeyType(target,keySize);
1889 key_size = keySize;
1890 symKey->size = keySize;
1891 if (key_size == 0) templateCount--;
1892
1893 mechanism.mechanism = derive;
1894
1895 /* we can undefine these when we define diffie-helman keys */
1896
1897 mechanism.pParameter = pubKey->u.dh.publicValue.data;
1898 mechanism.ulParameterLen = pubKey->u.dh.publicValue.len;
1899
1900 pk11_EnterKeyMonitor(symKey);
1901 crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism,
1902 privKey->pkcs11ID, keyTemplate, templateCount, &symKey->objectID);
1903 pk11_ExitKeyMonitor(symKey);
1904 if (crv == CKR_OK) return symKey;
1905 PORT_SetError( PK11_MapError(crv) );
1906 }
1907 break;
1908 case ecKey:
1909 {
1910 CK_BBOOL cktrue = CK_TRUE;
1911 CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
1912 CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
1913 CK_ULONG key_size = 0;
1914 CK_ATTRIBUTE keyTemplate[4];
1915 int templateCount;
1916 CK_ATTRIBUTE *attrs = keyTemplate;
1917 CK_ECDH1_DERIVE_PARAMS *mechParams = NULL;
1918
1919 if (pubKey->keyType != ecKey) {
1920 PORT_SetError(SEC_ERROR_BAD_KEY);
1921 break;
1922 }
1923
1924 PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
1925 attrs++;
1926 PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
1927 attrs++;
1928 PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
1929 PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size));
1930 attrs++;
1931 templateCount = attrs - keyTemplate;
1932 PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE)) ;
1933
1934 keyType = PK11_GetKeyType(target,keySize);
1935 key_size = keySize;
1936 if (key_size == 0) {
1937 if ((key_size = pk11_GetPredefinedKeyLength(keyType))) {
1938 templateCount --;
1939 } else {
1940 /* sigh, some tokens can't figure this out and require
1941 * CKA_VALUE_LEN to be set */
1942 key_size = SHA1_LENGTH;
1943 }
1944 }
1945 symKey->size = key_size;
1946
1947 mechParams = PORT_ZNew(CK_ECDH1_DERIVE_PARAMS);
1948 mechParams->kdf = CKD_SHA1_KDF;
1949 mechParams->ulSharedDataLen = 0;
1950 mechParams->pSharedData = NULL;
1951 mechParams->ulPublicDataLen = pubKey->u.ec.publicValue.len;
1952 mechParams->pPublicData = pubKey->u.ec.publicValue.data;
1953
1954 mechanism.mechanism = derive;
1955 mechanism.pParameter = mechParams;
1956 mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
1957
1958 pk11_EnterKeyMonitor(symKey);
1959 crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session,
1960 &mechanism, privKey->pkcs11ID, keyTemplate,
1961 templateCount, &symKey->objectID);
1962 pk11_ExitKeyMonitor(symKey);
1963
1964 /* old PKCS #11 spec was ambiguous on what needed to be passed,
1965 * try this again with and encoded public key */
1966 if (crv != CKR_OK) {
1967 SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL,
1968 &pubKey->u.ec.publicValue,
1969 SEC_ASN1_GET(SEC_OctetStringTemplate));
1970 if (pubValue == NULL) {
1971 PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
1972 break;
1973 }
1974 mechParams->ulPublicDataLen = pubValue->len;
1975 mechParams->pPublicData = pubValue->data;
1976
1977 pk11_EnterKeyMonitor(symKey);
1978 crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session,
1979 &mechanism, privKey->pkcs11ID, keyTemplate,
1980 templateCount, &symKey->objectID);
1981 pk11_ExitKeyMonitor(symKey);
1982
1983 SECITEM_FreeItem(pubValue,PR_TRUE);
1984 }
1985
1986 PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
1987
1988 if (crv == CKR_OK) return symKey;
1989 PORT_SetError( PK11_MapError(crv) );
1990 }
1991 }
1992
1993 PK11_FreeSymKey(symKey);
1994 return NULL;
1995 }
1996
1997 /* Returns the size of the public key, or 0 if there
1998 * is an error. */
1999 static CK_ULONG
2000 pk11_ECPubKeySize(SECItem *publicValue)
2001 {
2002 if (publicValue->data[0] == 0x04) {
2003 /* key encoded in uncompressed form */
2004 return((publicValue->len - 1)/2);
2005 } else if ( (publicValue->data[0] == 0x02) ||
2006 (publicValue->data[0] == 0x03)) {
2007 /* key encoded in compressed form */
2008 return(publicValue->len - 1);
2009 }
2010 /* key encoding not recognized */
2011 return(0);
2012 }
2013
2014 static PK11SymKey *
2015 pk11_PubDeriveECKeyWithKDF(
2016 SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
2017 PRBool isSender, SECItem *randomA, SECItem *randomB,
2018 CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
2019 CK_ATTRIBUTE_TYPE operation, int keySize,
2020 CK_ULONG kdf, SECItem *sharedData, void *wincx)
2021 {
2022 PK11SlotInfo *slot = privKey->pkcs11Slot;
2023 PK11SymKey *symKey;
2024 PK11SymKey *SharedSecret;
2025 CK_MECHANISM mechanism;
2026 CK_RV crv;
2027 CK_BBOOL cktrue = CK_TRUE;
2028 CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
2029 CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
2030 CK_ULONG key_size = 0;
2031 CK_ATTRIBUTE keyTemplate[4];
2032 int templateCount;
2033 CK_ATTRIBUTE *attrs = keyTemplate;
2034 CK_ECDH1_DERIVE_PARAMS *mechParams = NULL;
2035
2036 if (pubKey->keyType != ecKey) {
2037 PORT_SetError(SEC_ERROR_BAD_KEY);
2038 return NULL;
2039 }
2040 if ((kdf != CKD_NULL) && (kdf != CKD_SHA1_KDF) &&
2041 (kdf != CKD_SHA224_KDF) && (kdf != CKD_SHA256_KDF) &&
2042 (kdf != CKD_SHA384_KDF) && (kdf != CKD_SHA512_KDF)) {
2043 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
2044 return NULL;
2045 }
2046
2047 /* get our key Structure */
2048 symKey = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, wincx);
2049 if (symKey == NULL) {
2050 return NULL;
2051 }
2052
2053 symKey->origin = PK11_OriginDerive;
2054
2055 PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass)); attrs++;
2056 PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); attrs++;
2057 PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
2058 PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size)); attrs++;
2059 templateCount = attrs - keyTemplate;
2060 PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
2061
2062 keyType = PK11_GetKeyType(target,keySize);
2063 key_size = keySize;
2064 if (key_size == 0) {
2065 if ((key_size = pk11_GetPredefinedKeyLength(keyType))) {
2066 templateCount --;
2067 } else {
2068 /* sigh, some tokens can't figure this out and require
2069 * CKA_VALUE_LEN to be set */
2070 switch (kdf) {
2071 case CKD_NULL:
2072 key_size = pk11_ECPubKeySize(&pubKey->u.ec.publicValue);
2073 if (key_size == 0) {
2074 PK11_FreeSymKey(symKey);
2075 return NULL;
2076 }
2077 break;
2078 case CKD_SHA1_KDF:
2079 key_size = SHA1_LENGTH;
2080 break;
2081 case CKD_SHA224_KDF:
2082 key_size = SHA224_LENGTH;
2083 break;
2084 case CKD_SHA256_KDF:
2085 key_size = SHA256_LENGTH;
2086 break;
2087 case CKD_SHA384_KDF:
2088 key_size = SHA384_LENGTH;
2089 break;
2090 case CKD_SHA512_KDF:
2091 key_size = SHA512_LENGTH;
2092 break;
2093 default:
2094 PORT_Assert(!"Invalid CKD");
2095 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
2096 return NULL;
2097 }
2098 }
2099 }
2100 symKey->size = key_size;
2101
2102 mechParams = PORT_ZNew(CK_ECDH1_DERIVE_PARAMS);
2103 if (!mechParams) {
2104 PK11_FreeSymKey(symKey);
2105 return NULL;
2106 }
2107 mechParams->kdf = kdf;
2108 if (sharedData == NULL) {
2109 mechParams->ulSharedDataLen = 0;
2110 mechParams->pSharedData = NULL;
2111 } else {
2112 mechParams->ulSharedDataLen = sharedData->len;
2113 mechParams->pSharedData = sharedData->data;
2114 }
2115 mechParams->ulPublicDataLen = pubKey->u.ec.publicValue.len;
2116 mechParams->pPublicData = pubKey->u.ec.publicValue.data;
2117
2118 mechanism.mechanism = derive;
2119 mechanism.pParameter = mechParams;
2120 mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
2121
2122 pk11_EnterKeyMonitor(symKey);
2123 crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism,
2124 privKey->pkcs11ID, keyTemplate, templateCount, &symKey->objectID);
2125 pk11_ExitKeyMonitor(symKey);
2126
2127 /* old PKCS #11 spec was ambiguous on what needed to be passed,
2128 * try this again with an encoded public key */
2129 if (crv != CKR_OK) {
2130 SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL,
2131 &pubKey->u.ec.publicValue,
2132 SEC_ASN1_GET(SEC_OctetStringTemplate));
2133 if (pubValue == NULL) {
2134 goto loser;
2135 }
2136 mechParams->ulPublicDataLen = pubValue->len;
2137 mechParams->pPublicData = pubValue->data;
2138
2139 pk11_EnterKeyMonitor(symKey);
2140 crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session,
2141 &mechanism, privKey->pkcs11ID, keyTemplate,
2142 templateCount, &symKey->objectID);
2143 pk11_ExitKeyMonitor(symKey);
2144
2145 if ((crv != CKR_OK) && (kdf != CKD_NULL)) {
2146 /* Some PKCS #11 libraries cannot perform the key derivation
2147 * function. So, try calling C_DeriveKey with CKD_NULL and then
2148 * performing the KDF separately.
2149 */
2150 CK_ULONG derivedKeySize = key_size;
2151
2152 keyType = CKK_GENERIC_SECRET;
2153 key_size = pk11_ECPubKeySize(&pubKey->u.ec.publicValue);
2154 if (key_size == 0) {
2155 SECITEM_FreeItem(pubValue,PR_TRUE);
2156 goto loser;
2157 }
2158 SharedSecret = symKey;
2159 SharedSecret->size = key_size;
2160
2161 mechParams->kdf = CKD_NULL;
2162 mechParams->ulSharedDataLen = 0;
2163 mechParams->pSharedData = NULL;
2164 mechParams->ulPublicDataLen = pubKey->u.ec.publicValue.len;
2165 mechParams->pPublicData = pubKey->u.ec.publicValue.data;
2166
2167 pk11_EnterKeyMonitor(SharedSecret);
2168 crv = PK11_GETTAB(slot)->C_DeriveKey(SharedSecret->session,
2169 &mechanism, privKey->pkcs11ID, keyTemplate,
2170 templateCount, &SharedSecret->objectID);
2171 pk11_ExitKeyMonitor(SharedSecret);
2172
2173 if (crv != CKR_OK) {
2174 /* old PKCS #11 spec was ambiguous on what needed to be passed,
2175 * try this one final time with an encoded public key */
2176 mechParams->ulPublicDataLen = pubValue->len;
2177 mechParams->pPublicData = pubValue->data;
2178
2179 pk11_EnterKeyMonitor(SharedSecret);
2180 crv = PK11_GETTAB(slot)->C_DeriveKey(SharedSecret->session,
2181 &mechanism, privKey->pkcs11ID, keyTemplate,
2182 templateCount, &SharedSecret->objectID);
2183 pk11_ExitKeyMonitor(SharedSecret);
2184 }
2185
2186 /* Perform KDF. */
2187 if (crv == CKR_OK) {
2188 symKey = pk11_ANSIX963Derive(SharedSecret, kdf,
2189 sharedData, target, operation,
2190 derivedKeySize);
2191 PK11_FreeSymKey(SharedSecret);
2192 if (symKey == NULL) {
2193 SECITEM_FreeItem(pubValue,PR_TRUE);
2194 PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
2195 return NULL;
2196 }
2197 }
2198 }
2199 SECITEM_FreeItem(pubValue,PR_TRUE);
2200 }
2201
2202 loser:
2203 PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
2204
2205 if (crv != CKR_OK) {
2206 PK11_FreeSymKey(symKey);
2207 symKey = NULL;
2208 PORT_SetError( PK11_MapError(crv) );
2209 }
2210 return symKey;
2211 }
2212
2213 PK11SymKey *
2214 PK11_PubDeriveWithKDF(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
2215 PRBool isSender, SECItem *randomA, SECItem *randomB,
2216 CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
2217 CK_ATTRIBUTE_TYPE operation, int keySize,
2218 CK_ULONG kdf, SECItem *sharedData, void *wincx)
2219 {
2220
2221 switch (privKey->keyType) {
2222 case rsaKey:
2223 case nullKey:
2224 case dsaKey:
2225 case keaKey:
2226 case fortezzaKey:
2227 case dhKey:
2228 return PK11_PubDerive(privKey, pubKey, isSender, randomA, randomB,
2229 derive, target, operation, keySize, wincx);
2230 case ecKey:
2231 return pk11_PubDeriveECKeyWithKDF( privKey, pubKey, isSender,
2232 randomA, randomB, derive, target, operation, keySize,
2233 kdf, sharedData, wincx);
2234 default:
2235 PORT_SetError(SEC_ERROR_BAD_KEY);
2236 break;
2237 }
2238
2239 return NULL;
2240 }
2241
2242 /*
2243 * this little function uses the Decrypt function to unwrap a key, just in
2244 * case we are having problem with unwrap. NOTE: The key size may
2245 * not be preserved properly for some algorithms!
2246 */
2247 static PK11SymKey *
2248 pk11_HandUnwrap(PK11SlotInfo *slot, CK_OBJECT_HANDLE wrappingKey,
2249 CK_MECHANISM *mech, SECItem *inKey, CK_MECHANISM_TYPE target,
2250 CK_ATTRIBUTE *keyTemplate, unsigned int templateCount,
2251 int key_size, void * wincx, CK_RV *crvp, PRBool isPerm)
2252 {
2253 CK_ULONG len;
2254 SECItem outKey;
2255 PK11SymKey *symKey;
2256 CK_RV crv;
2257 PRBool owner = PR_TRUE;
2258 CK_SESSION_HANDLE session;
2259
2260 /* remove any VALUE_LEN parameters */
2261 if (keyTemplate[templateCount-1].type == CKA_VALUE_LEN) {
2262 templateCount--;
2263 }
2264
2265 /* keys are almost always aligned, but if we get this far,
2266 * we've gone above and beyond anyway... */
2267 outKey.data = (unsigned char*)PORT_Alloc(inKey->len);
2268 if (outKey.data == NULL) {
2269 PORT_SetError( SEC_ERROR_NO_MEMORY );
2270 if (crvp) *crvp = CKR_HOST_MEMORY;
2271 return NULL;
2272 }
2273 len = inKey->len;
2274
2275 /* use NULL IV's for wrapping */
2276 session = pk11_GetNewSession(slot,&owner);
2277 if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
2278 crv = PK11_GETTAB(slot)->C_DecryptInit(session,mech,wrappingKey);
2279 if (crv != CKR_OK) {
2280 if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
2281 pk11_CloseSession(slot,session,owner);
2282 PORT_Free(outKey.data);
2283 PORT_SetError( PK11_MapError(crv) );
2284 if (crvp) *crvp =crv;
2285 return NULL;
2286 }
2287 crv = PK11_GETTAB(slot)->C_Decrypt(session,inKey->data,inKey->len,
2288 outKey.data, &len);
2289 if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
2290 pk11_CloseSession(slot,session,owner);
2291 if (crv != CKR_OK) {
2292 PORT_Free(outKey.data);
2293 PORT_SetError( PK11_MapError(crv) );
2294 if (crvp) *crvp =crv;
2295 return NULL;
2296 }
2297
2298 outKey.len = (key_size == 0) ? len : key_size;
2299 outKey.type = siBuffer;
2300
2301 if (PK11_DoesMechanism(slot,target)) {
2302 symKey = pk11_ImportSymKeyWithTempl(slot, target, PK11_OriginUnwrap,
2303 isPerm, keyTemplate,
2304 templateCount, &outKey, wincx);
2305 } else {
2306 slot = PK11_GetBestSlot(target,wincx);
2307 if (slot == NULL) {
2308 PORT_SetError( SEC_ERROR_NO_MODULE );
2309 PORT_Free(outKey.data);
2310 if (crvp) *crvp = CKR_DEVICE_ERROR;
2311 return NULL;
2312 }
2313 symKey = pk11_ImportSymKeyWithTempl(slot, target, PK11_OriginUnwrap,
2314 isPerm, keyTemplate,
2315 templateCount, &outKey, wincx);
2316 PK11_FreeSlot(slot);
2317 }
2318 PORT_Free(outKey.data);
2319
2320 if (crvp) *crvp = symKey? CKR_OK : CKR_DEVICE_ERROR;
2321 return symKey;
2322 }
2323
2324 /*
2325 * The wrap/unwrap function is pretty much the same for private and
2326 * public keys. It's just getting the Object ID and slot right. This is
2327 * the combined unwrap function.
2328 */
2329 static PK11SymKey *
2330 pk11_AnyUnwrapKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE wrappingKey,
2331 CK_MECHANISM_TYPE wrapType, SECItem *param, SECItem *wrappedKey,
2332 CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize,
2333 void *wincx, CK_ATTRIBUTE *userAttr, unsigned int numAttrs, PRBool isPerm)
2334 {
2335 PK11SymKey * symKey;
2336 SECItem * param_free = NULL;
2337 CK_BBOOL cktrue = CK_TRUE;
2338 CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
2339 CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
2340 CK_ULONG valueLen = 0;
2341 CK_MECHANISM mechanism;
2342 CK_SESSION_HANDLE rwsession;
2343 CK_RV crv;
2344 CK_MECHANISM_INFO mechanism_info;
2345 #define MAX_ADD_ATTRS 4
2346 CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS + MAX_ADD_ATTRS];
2347 #undef MAX_ADD_ATTRS
2348 CK_ATTRIBUTE * attrs = keyTemplate;
2349 unsigned int templateCount;
2350
2351 if (numAttrs > MAX_TEMPL_ATTRS) {
2352 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2353 return NULL;
2354 }
2355
2356 /* first copy caller attributes in. */
2357 for (templateCount = 0; templateCount < numAttrs; ++templateCount) {
2358 *attrs++ = *userAttr++;
2359 }
2360
2361 /* We only add the following attributes to the template if the caller
2362 ** didn't already supply them.
2363 */
2364 if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_CLASS)) {
2365 PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof keyClass);
2366 attrs++;
2367 }
2368 if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_KEY_TYPE)) {
2369 keyType = PK11_GetKeyType(target, keySize);
2370 PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof keyType );
2371 attrs++;
2372 }
2373 if ((operation != CKA_FLAGS_ONLY) &&
2374 !pk11_FindAttrInTemplate(keyTemplate, numAttrs, operation)) {
2375 PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
2376 }
2377
2378 /*
2379 * must be last in case we need to use this template to import the key
2380 */
2381 if (keySize > 0 &&
2382 !pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_VALUE_LEN)) {
2383 valueLen = (CK_ULONG)keySize;
2384 PK11_SETATTRS(attrs, CKA_VALUE_LEN, &valueLen, sizeof valueLen);
2385 attrs++;
2386 }
2387
2388 templateCount = attrs - keyTemplate;
2389 PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
2390
2391
2392 /* find out if we can do wrap directly. Because the RSA case if *very*
2393 * common, cache the results for it. */
2394 if ((wrapType == CKM_RSA_PKCS) && (slot->hasRSAInfo)) {
2395 mechanism_info.flags = slot->RSAInfoFlags;
2396 } else {
2397 if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
2398 crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,wrapType,
2399 &mechanism_info);
2400 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
2401 if (crv != CKR_OK) {
2402 mechanism_info.flags = 0;
2403 }
2404 if (wrapType == CKM_RSA_PKCS) {
2405 slot->RSAInfoFlags = mechanism_info.flags;
2406 slot->hasRSAInfo = PR_TRUE;
2407 }
2408 }
2409
2410 /* initialize the mechanism structure */
2411 mechanism.mechanism = wrapType;
2412 /* use NULL IV's for wrapping */
2413 if (param == NULL)
2414 param = param_free = PK11_ParamFromIV(wrapType,NULL);
2415 if (param) {
2416 mechanism.pParameter = param->data;
2417 mechanism.ulParameterLen = param->len;
2418 } else {
2419 mechanism.pParameter = NULL;
2420 mechanism.ulParameterLen = 0;
2421 }
2422
2423 if ((mechanism_info.flags & CKF_DECRYPT)
2424 && !PK11_DoesMechanism(slot,target)) {
2425 symKey = pk11_HandUnwrap(slot, wrappingKey, &mechanism, wrappedKey,
2426 target, keyTemplate, templateCount, keySize,
2427 wincx, &crv, isPerm);
2428 if (symKey) {
2429 if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
2430 return symKey;
2431 }
2432 /*
2433 * if the RSA OP simply failed, don't try to unwrap again
2434 * with this module.
2435 */
2436 if (crv == CKR_DEVICE_ERROR){
2437 if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
2438 return NULL;
2439 }
2440 /* fall through, maybe they incorrectly set CKF_DECRYPT */
2441 }
2442
2443 /* get our key Structure */
2444 symKey = pk11_CreateSymKey(slot, target, !isPerm, PR_TRUE, wincx);
2445 if (symKey == NULL) {
2446 if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
2447 return NULL;
2448 }
2449
2450 symKey->size = keySize;
2451 symKey->origin = PK11_OriginUnwrap;
2452
2453 if (isPerm) {
2454 rwsession = PK11_GetRWSession(slot);
2455 } else {
2456 pk11_EnterKeyMonitor(symKey);
2457 rwsession = symKey->session;
2458 }
2459 PORT_Assert(rwsession != CK_INVALID_SESSION);
2460 if (rwsession == CK_INVALID_SESSION)
2461 crv = CKR_SESSION_HANDLE_INVALID;
2462 else
2463 crv = PK11_GETTAB(slot)->C_UnwrapKey(rwsession,&mechanism,wrappingKey,
2464 wrappedKey->data, wrappedKey->len, keyTemplate, templateCount,
2465 &symKey->objectID);
2466 if (isPerm) {
2467 if (rwsession != CK_INVALID_SESSION)
2468 PK11_RestoreROSession(slot, rwsession);
2469 } else {
2470 pk11_ExitKeyMonitor(symKey);
2471 }
2472 if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
2473 if (crv != CKR_OK) {
2474 PK11_FreeSymKey(symKey);
2475 symKey = NULL;
2476 if (crv != CKR_DEVICE_ERROR) {
2477 /* try hand Unwrapping */
2478 symKey = pk11_HandUnwrap(slot, wrappingKey, &mechanism, wrappedKey,
2479 target, keyTemplate, templateCount,
2480 keySize, wincx, NULL, isPerm);
2481 }
2482 }
2483
2484 return symKey;
2485 }
2486
2487 /* use a symetric key to unwrap another symetric key */
2488 PK11SymKey *
2489 PK11_UnwrapSymKey( PK11SymKey *wrappingKey, CK_MECHANISM_TYPE wrapType,
2490 SECItem *param, SECItem *wrappedKey,
2491 CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
2492 int keySize)
2493 {
2494 return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
2495 wrapType, param, wrappedKey, target, operation, keySize,
2496 wrappingKey->cx, NULL, 0, PR_FALSE);
2497 }
2498
2499 /* use a symetric key to unwrap another symetric key */
2500 PK11SymKey *
2501 PK11_UnwrapSymKeyWithFlags(PK11SymKey *wrappingKey, CK_MECHANISM_TYPE wrapType,
2502 SECItem *param, SECItem *wrappedKey,
2503 CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
2504 int keySize, CK_FLAGS flags)
2505 {
2506 CK_BBOOL ckTrue = CK_TRUE;
2507 CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
2508 unsigned int templateCount;
2509
2510 templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
2511 return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
2512 wrapType, param, wrappedKey, target, operation, keySize,
2513 wrappingKey->cx, keyTemplate, templateCount, PR_FALSE);
2514 }
2515
2516 PK11SymKey *
2517 PK11_UnwrapSymKeyWithFlagsPerm(PK11SymKey *wrappingKey,
2518 CK_MECHANISM_TYPE wrapType,
2519 SECItem *param, SECItem *wrappedKey,
2520 CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
2521 int keySize, CK_FLAGS flags, PRBool isPerm)
2522 {
2523 CK_BBOOL cktrue = CK_TRUE;
2524 CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
2525 CK_ATTRIBUTE *attrs;
2526 unsigned int templateCount;
2527
2528 attrs = keyTemplate;
2529 if (isPerm) {
2530 PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); attrs++;
2531 }
2532 templateCount = attrs-keyTemplate;
2533 templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
2534
2535 return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
2536 wrapType, param, wrappedKey, target, operation, keySize,
2537 wrappingKey->cx, keyTemplate, templateCount, isPerm);
2538 }
2539
2540
2541 /* unwrap a symetric key with a private key. */
2542 PK11SymKey *
2543 PK11_PubUnwrapSymKey(SECKEYPrivateKey *wrappingKey, SECItem *wrappedKey,
2544 CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize)
2545 {
2546 CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
2547 PK11SlotInfo *slot = wrappingKey->pkcs11Slot;
2548
2549 if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey,CKA_PRIVATE)) {
2550 PK11_HandlePasswordCheck(slot,wrappingKey->wincx);
2551 }
2552
2553 return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
2554 wrapType, NULL, wrappedKey, target, operation, keySize,
2555 wrappingKey->wincx, NULL, 0, PR_FALSE);
2556 }
2557
2558 /* unwrap a symetric key with a private key. */
2559 PK11SymKey *
2560 PK11_PubUnwrapSymKeyWithFlags(SECKEYPrivateKey *wrappingKey,
2561 SECItem *wrappedKey, CK_MECHANISM_TYPE target,
2562 CK_ATTRIBUTE_TYPE operation, int keySize, CK_FLAGS flags)
2563 {
2564 CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
2565 CK_BBOOL ckTrue = CK_TRUE;
2566 CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
2567 unsigned int templateCount;
2568 PK11SlotInfo *slot = wrappingKey->pkcs11Slot;
2569
2570 templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
2571
2572 if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey,CKA_PRIVATE)) {
2573 PK11_HandlePasswordCheck(slot,wrappingKey->wincx);
2574 }
2575
2576 return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
2577 wrapType, NULL, wrappedKey, target, operation, keySize,
2578 wrappingKey->wincx, keyTemplate, templateCount, PR_FALSE);
2579 }
2580
2581 PK11SymKey *
2582 PK11_PubUnwrapSymKeyWithFlagsPerm(SECKEYPrivateKey *wrappingKey,
2583 SECItem *wrappedKey, CK_MECHANISM_TYPE target,
2584 CK_ATTRIBUTE_TYPE operation, int keySize,
2585 CK_FLAGS flags, PRBool isPerm)
2586 {
2587 CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
2588 CK_BBOOL cktrue = CK_TRUE;
2589 CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
2590 CK_ATTRIBUTE *attrs;
2591 unsigned int templateCount;
2592 PK11SlotInfo *slot = wrappingKey->pkcs11Slot;
2593
2594 attrs = keyTemplate;
2595 if (isPerm) {
2596 PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); attrs++;
2597 }
2598 templateCount = attrs-keyTemplate;
2599
2600 templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
2601
2602 if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey,CKA_PRIVATE)) {
2603 PK11_HandlePasswordCheck(slot,wrappingKey->wincx);
2604 }
2605
2606 return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
2607 wrapType, NULL, wrappedKey, target, operation, keySize,
2608 wrappingKey->wincx, keyTemplate, templateCount, isPerm);
2609 }
2610
2611 PK11SymKey*
2612 PK11_CopySymKeyForSigning(PK11SymKey *originalKey, CK_MECHANISM_TYPE mech)
2613 {
2614 CK_RV crv;
2615 CK_ATTRIBUTE setTemplate;
2616 CK_BBOOL ckTrue = CK_TRUE;
2617 PK11SlotInfo *slot = originalKey->slot;
2618
2619 /* first just try to set this key up for signing */
2620 PK11_SETATTRS(&setTemplate, CKA_SIGN, &ckTrue, sizeof(ckTrue));
2621 pk11_EnterKeyMonitor(originalKey);
2622 crv = PK11_GETTAB(slot)-> C_SetAttributeValue(originalKey->session,
2623 originalKey->objectID, &setTemplate, 1);
2624 pk11_ExitKeyMonitor(originalKey);
2625 if (crv == CKR_OK) {
2626 return PK11_ReferenceSymKey(originalKey);
2627 }
2628
2629 /* nope, doesn't like it, use the pk11 copy object command */
2630 return pk11_CopyToSlot(slot, mech, CKA_SIGN, originalKey);
2631 }
2632
2633 void
2634 PK11_SetFortezzaHack(PK11SymKey *symKey) {
2635 symKey->origin = PK11_OriginFortezzaHack;
2636 }
2637
2638 /*
2639 * This is required to allow FORTEZZA_NULL and FORTEZZA_RC4
2640 * working. This function simply gets a valid IV for the keys.
2641 */
2642 SECStatus
2643 PK11_GenerateFortezzaIV(PK11SymKey *symKey,unsigned char *iv,int len)
2644 {
2645 CK_MECHANISM mech_info;
2646 CK_ULONG count = 0;
2647 CK_RV crv;
2648 SECStatus rv = SECFailure;
2649
2650 mech_info.mechanism = CKM_SKIPJACK_CBC64;
2651 mech_info.pParameter = iv;
2652 mech_info.ulParameterLen = len;
2653
2654 /* generate the IV for fortezza */
2655 PK11_EnterSlotMonitor(symKey->slot);
2656 crv=PK11_GETTAB(symKey->slot)->C_EncryptInit(symKey->slot->session,
2657 &mech_info, symKey->objectID);
2658 if (crv == CKR_OK) {
2659 PK11_GETTAB(symKey->slot)->C_EncryptFinal(symKey->slot->session,
2660 NULL, &count);
2661 rv = SECSuccess;
2662 }
2663 PK11_ExitSlotMonitor(symKey->slot);
2664 return rv;
2665 }
2666
2667 CK_OBJECT_HANDLE
2668 PK11_GetSymKeyHandle(PK11SymKey *symKey)
2669 {
2670 return symKey->objectID;
2671 }
2672
OLDNEW
« no previous file with comments | « nss/lib/pk11wrap/pk11sdr.c ('k') | nss/lib/pk11wrap/pk11slot.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698