security/nss/lib/pk11wrap/pk11skey.c

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

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

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

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

mercurial