pk11obj.c (74635B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 /* 5 * This file manages object type indepentent functions. 6 */ 7 #include <limits.h> 8 #include <stddef.h> 9 10 #include "seccomon.h" 11 #include "secder.h" 12 #include "secmod.h" 13 #include "secmodi.h" 14 #include "secmodti.h" 15 #include "pkcs11.h" 16 #include "pkcs11t.h" 17 #include "pk11func.h" 18 #include "keyhi.h" 19 #include "keyi.h" 20 #include "secitem.h" 21 #include "secerr.h" 22 #include "sslerr.h" 23 24 #define PK11_SEARCH_CHUNKSIZE 10 25 26 /* 27 * Build a block big enough to hold the data 28 */ 29 SECItem * 30 PK11_BlockData(SECItem *data, unsigned long size) 31 { 32 SECItem *newData; 33 34 if (size == 0u) 35 return NULL; 36 37 newData = (SECItem *)PORT_Alloc(sizeof(SECItem)); 38 if (newData == NULL) 39 return NULL; 40 41 newData->len = (data->len + (size - 1)) / size; 42 newData->len *= size; 43 44 newData->data = (unsigned char *)PORT_ZAlloc(newData->len); 45 if (newData->data == NULL) { 46 PORT_Free(newData); 47 return NULL; 48 } 49 PORT_Memset(newData->data, newData->len - data->len, newData->len); 50 PORT_Memcpy(newData->data, data->data, data->len); 51 return newData; 52 } 53 54 SECStatus 55 PK11_DestroyObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE object) 56 { 57 CK_RV crv; 58 59 PK11_EnterSlotMonitor(slot); 60 crv = PK11_GETTAB(slot)->C_DestroyObject(slot->session, object); 61 PK11_ExitSlotMonitor(slot); 62 if (crv != CKR_OK) { 63 return SECFailure; 64 } 65 return SECSuccess; 66 } 67 68 SECStatus 69 PK11_DestroyTokenObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE object) 70 { 71 CK_RV crv; 72 SECStatus rv = SECSuccess; 73 CK_SESSION_HANDLE rwsession; 74 75 rwsession = PK11_GetRWSession(slot); 76 if (rwsession == CK_INVALID_HANDLE) { 77 PORT_SetError(SEC_ERROR_BAD_DATA); 78 return SECFailure; 79 } 80 81 crv = PK11_GETTAB(slot)->C_DestroyObject(rwsession, object); 82 if (crv != CKR_OK) { 83 rv = SECFailure; 84 PORT_SetError(PK11_MapError(crv)); 85 } 86 PK11_RestoreROSession(slot, rwsession); 87 return rv; 88 } 89 90 /* 91 * Read in a single attribute into a SECItem. Allocate space for it with 92 * PORT_Alloc unless an arena is supplied. In the latter case use the arena 93 * to allocate the space. 94 * 95 * PK11_ReadAttribute sets the 'data' and 'len' fields of the SECItem but 96 * does not modify its 'type' field. 97 */ 98 SECStatus 99 PK11_ReadAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, 100 CK_ATTRIBUTE_TYPE type, PLArenaPool *arena, SECItem *result) 101 { 102 CK_ATTRIBUTE attr = { 0, NULL, 0 }; 103 CK_RV crv; 104 105 attr.type = type; 106 107 PK11_EnterSlotMonitor(slot); 108 crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, id, &attr, 1); 109 if (crv != CKR_OK) { 110 PK11_ExitSlotMonitor(slot); 111 PORT_SetError(PK11_MapError(crv)); 112 return SECFailure; 113 } 114 if (arena) { 115 attr.pValue = PORT_ArenaAlloc(arena, attr.ulValueLen); 116 } else { 117 attr.pValue = PORT_Alloc(attr.ulValueLen); 118 } 119 if (attr.pValue == NULL) { 120 PK11_ExitSlotMonitor(slot); 121 return SECFailure; 122 } 123 crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, id, &attr, 1); 124 PK11_ExitSlotMonitor(slot); 125 if (crv != CKR_OK) { 126 PORT_SetError(PK11_MapError(crv)); 127 if (!arena) 128 PORT_Free(attr.pValue); 129 return SECFailure; 130 } 131 132 result->data = (unsigned char *)attr.pValue; 133 result->len = attr.ulValueLen; 134 135 return SECSuccess; 136 } 137 138 /* 139 * Read in a single attribute into a Ulong. 140 */ 141 CK_ULONG 142 PK11_ReadULongAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, 143 CK_ATTRIBUTE_TYPE type) 144 { 145 CK_ATTRIBUTE attr; 146 CK_ULONG value = CK_UNAVAILABLE_INFORMATION; 147 CK_RV crv; 148 149 PK11_SETATTRS(&attr, type, &value, sizeof(value)); 150 151 PK11_EnterSlotMonitor(slot); 152 crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, id, &attr, 1); 153 PK11_ExitSlotMonitor(slot); 154 if (crv != CKR_OK) { 155 PORT_SetError(PK11_MapError(crv)); 156 } 157 return value; 158 } 159 160 /* 161 * check to see if a bool has been set. 162 */ 163 CK_BBOOL 164 pk11_HasAttributeSet_Lock(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, 165 CK_ATTRIBUTE_TYPE type, PRBool haslock) 166 { 167 CK_BBOOL ckvalue = CK_FALSE; 168 CK_ATTRIBUTE theTemplate; 169 CK_RV crv; 170 171 /* Prepare to retrieve the attribute. */ 172 PK11_SETATTRS(&theTemplate, type, &ckvalue, sizeof(CK_BBOOL)); 173 174 /* Retrieve attribute value. */ 175 if (!haslock) 176 PK11_EnterSlotMonitor(slot); 177 crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, id, 178 &theTemplate, 1); 179 if (!haslock) 180 PK11_ExitSlotMonitor(slot); 181 if (crv != CKR_OK) { 182 PORT_SetError(PK11_MapError(crv)); 183 return CK_FALSE; 184 } 185 186 return ckvalue; 187 } 188 189 CK_BBOOL 190 PK11_HasAttributeSet(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, 191 CK_ATTRIBUTE_TYPE type, PRBool haslock) 192 { 193 PR_ASSERT(haslock == PR_FALSE); 194 return pk11_HasAttributeSet_Lock(slot, id, type, PR_FALSE); 195 } 196 197 /* 198 * returns a full list of attributes. Allocate space for them. If an arena is 199 * provided, allocate space out of the arena. 200 */ 201 CK_RV 202 PK11_GetAttributes(PLArenaPool *arena, PK11SlotInfo *slot, 203 CK_OBJECT_HANDLE obj, CK_ATTRIBUTE *attr, int count) 204 { 205 int i; 206 /* make pedantic happy... note that it's only used arena != NULL */ 207 void *mark = NULL; 208 CK_RV crv; 209 if (slot->session == CK_INVALID_HANDLE) 210 return CKR_SESSION_HANDLE_INVALID; 211 212 /* 213 * first get all the lengths of the parameters. 214 */ 215 PK11_EnterSlotMonitor(slot); 216 crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, obj, attr, count); 217 if (crv != CKR_OK) { 218 PK11_ExitSlotMonitor(slot); 219 return crv; 220 } 221 222 if (arena) { 223 mark = PORT_ArenaMark(arena); 224 if (mark == NULL) 225 return CKR_HOST_MEMORY; 226 } 227 228 /* 229 * now allocate space to store the results. 230 */ 231 for (i = 0; i < count; i++) { 232 if (attr[i].ulValueLen == 0) 233 continue; 234 if (arena) { 235 attr[i].pValue = PORT_ArenaAlloc(arena, attr[i].ulValueLen); 236 if (attr[i].pValue == NULL) { 237 /* arena failures, just release the mark */ 238 PORT_ArenaRelease(arena, mark); 239 PK11_ExitSlotMonitor(slot); 240 return CKR_HOST_MEMORY; 241 } 242 } else { 243 attr[i].pValue = PORT_Alloc(attr[i].ulValueLen); 244 if (attr[i].pValue == NULL) { 245 /* Separate malloc failures, loop to release what we have 246 * so far */ 247 int j; 248 for (j = 0; j < i; j++) { 249 PORT_Free(attr[j].pValue); 250 /* don't give the caller pointers to freed memory */ 251 attr[j].pValue = NULL; 252 } 253 PK11_ExitSlotMonitor(slot); 254 return CKR_HOST_MEMORY; 255 } 256 } 257 } 258 259 /* 260 * finally get the results. 261 */ 262 crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, obj, attr, count); 263 PK11_ExitSlotMonitor(slot); 264 if (crv != CKR_OK) { 265 if (arena) { 266 PORT_ArenaRelease(arena, mark); 267 } else { 268 for (i = 0; i < count; i++) { 269 PORT_Free(attr[i].pValue); 270 /* don't give the caller pointers to freed memory */ 271 attr[i].pValue = NULL; 272 } 273 } 274 } else if (arena && mark) { 275 PORT_ArenaUnmark(arena, mark); 276 } 277 return crv; 278 } 279 280 PRBool 281 PK11_IsPermObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle) 282 { 283 return (PRBool)PK11_HasAttributeSet(slot, handle, CKA_TOKEN, PR_FALSE); 284 } 285 286 char * 287 PK11_GetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id) 288 { 289 char *nickname = NULL; 290 SECItem result; 291 SECStatus rv; 292 293 rv = PK11_ReadAttribute(slot, id, CKA_LABEL, NULL, &result); 294 if (rv != SECSuccess) { 295 return NULL; 296 } 297 298 nickname = PORT_ZAlloc(result.len + 1); 299 if (nickname == NULL) { 300 PORT_Free(result.data); 301 return NULL; 302 } 303 PORT_Memcpy(nickname, result.data, result.len); 304 PORT_Free(result.data); 305 return nickname; 306 } 307 308 SECStatus 309 PK11_SetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, 310 const char *nickname) 311 { 312 int len = PORT_Strlen(nickname); 313 CK_ATTRIBUTE setTemplate; 314 CK_RV crv; 315 CK_SESSION_HANDLE rwsession; 316 317 if (len < 0) { 318 return SECFailure; 319 } 320 321 PK11_SETATTRS(&setTemplate, CKA_LABEL, (CK_CHAR *)nickname, len); 322 rwsession = PK11_GetRWSession(slot); 323 if (rwsession == CK_INVALID_HANDLE) { 324 PORT_SetError(SEC_ERROR_BAD_DATA); 325 return SECFailure; 326 } 327 crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id, 328 &setTemplate, 1); 329 PK11_RestoreROSession(slot, rwsession); 330 if (crv != CKR_OK) { 331 PORT_SetError(PK11_MapError(crv)); 332 return SECFailure; 333 } 334 return SECSuccess; 335 } 336 337 /* 338 * strip leading zero's from key material 339 */ 340 void 341 pk11_SignedToUnsigned(CK_ATTRIBUTE *attrib) 342 { 343 char *ptr = (char *)attrib->pValue; 344 unsigned long len = attrib->ulValueLen; 345 346 while ((len > 1) && (*ptr == 0)) { 347 len--; 348 ptr++; 349 } 350 attrib->pValue = ptr; 351 attrib->ulValueLen = len; 352 } 353 354 /* 355 * get a new session on a slot. If we run out of session, use the slot's 356 * 'exclusive' session. In this case owner becomes false. 357 */ 358 CK_SESSION_HANDLE 359 pk11_GetNewSession(PK11SlotInfo *slot, PRBool *owner) 360 { 361 CK_SESSION_HANDLE session; 362 *owner = PR_TRUE; 363 if (!slot->isThreadSafe) 364 PK11_EnterSlotMonitor(slot); 365 if (PK11_GETTAB(slot)->C_OpenSession(slot->slotID, CKF_SERIAL_SESSION, 366 slot, pk11_notify, &session) != CKR_OK) { 367 *owner = PR_FALSE; 368 session = slot->session; 369 } 370 if (!slot->isThreadSafe) 371 PK11_ExitSlotMonitor(slot); 372 373 return session; 374 } 375 376 void 377 pk11_CloseSession(PK11SlotInfo *slot, CK_SESSION_HANDLE session, PRBool owner) 378 { 379 if (!owner) 380 return; 381 if (!slot->isThreadSafe) 382 PK11_EnterSlotMonitor(slot); 383 (void)PK11_GETTAB(slot)->C_CloseSession(session); 384 if (!slot->isThreadSafe) 385 PK11_ExitSlotMonitor(slot); 386 } 387 388 SECStatus 389 PK11_CreateNewObject(PK11SlotInfo *slot, CK_SESSION_HANDLE session, 390 const CK_ATTRIBUTE *theTemplate, int count, 391 PRBool token, CK_OBJECT_HANDLE *objectID) 392 { 393 CK_SESSION_HANDLE rwsession; 394 CK_RV crv; 395 SECStatus rv = SECSuccess; 396 397 rwsession = session; 398 if (token) { 399 rwsession = PK11_GetRWSession(slot); 400 } else if (rwsession == CK_INVALID_HANDLE) { 401 rwsession = slot->session; 402 if (rwsession != CK_INVALID_HANDLE) 403 PK11_EnterSlotMonitor(slot); 404 } 405 if (rwsession == CK_INVALID_HANDLE) { 406 PORT_SetError(SEC_ERROR_BAD_DATA); 407 return SECFailure; 408 } 409 crv = PK11_GETTAB(slot)->C_CreateObject(rwsession, 410 /* cast away const :-( */ (CK_ATTRIBUTE_PTR)theTemplate, 411 count, objectID); 412 if (crv != CKR_OK) { 413 PORT_SetError(PK11_MapError(crv)); 414 rv = SECFailure; 415 } 416 if (token) { 417 PK11_RestoreROSession(slot, rwsession); 418 } else if (session == CK_INVALID_HANDLE) { 419 PK11_ExitSlotMonitor(slot); 420 } 421 422 return rv; 423 } 424 425 /* This function may add a maximum of 9 attributes. */ 426 unsigned int 427 pk11_OpFlagsToAttributes(CK_FLAGS flags, CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue) 428 { 429 430 const static CK_ATTRIBUTE_TYPE attrTypes[12] = { 431 CKA_ENCRYPT, CKA_DECRYPT, 0 /* DIGEST */, CKA_SIGN, 432 CKA_SIGN_RECOVER, CKA_VERIFY, CKA_VERIFY_RECOVER, 0 /* GEN */, 433 0 /* GEN PAIR */, CKA_WRAP, CKA_UNWRAP, CKA_DERIVE 434 }; 435 436 const CK_ATTRIBUTE_TYPE *pType = attrTypes; 437 CK_ATTRIBUTE *attr = attrs; 438 CK_FLAGS test = CKF_ENCRYPT; 439 440 PR_ASSERT(!(flags & ~CKF_KEY_OPERATION_FLAGS)); 441 flags &= CKF_KEY_OPERATION_FLAGS; 442 443 for (; flags && test <= CKF_DERIVE; test <<= 1, ++pType) { 444 if (test & flags) { 445 flags ^= test; 446 PR_ASSERT(*pType); 447 PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue); 448 ++attr; 449 } 450 } 451 return (attr - attrs); 452 } 453 454 /* 455 * Check for conflicting flags, for example, if both PK11_ATTR_PRIVATE 456 * and PK11_ATTR_PUBLIC are set. 457 */ 458 PRBool 459 pk11_BadAttrFlags(PK11AttrFlags attrFlags) 460 { 461 PK11AttrFlags trueFlags = attrFlags & 0x55555555; 462 PK11AttrFlags falseFlags = (attrFlags >> 1) & 0x55555555; 463 return ((trueFlags & falseFlags) != 0); 464 } 465 466 /* 467 * This function may add a maximum of 5 attributes. 468 * The caller must make sure the attribute flags don't have conflicts. 469 */ 470 unsigned int 471 pk11_AttrFlagsToAttributes(PK11AttrFlags attrFlags, CK_ATTRIBUTE *attrs, 472 CK_BBOOL *ckTrue, CK_BBOOL *ckFalse) 473 { 474 const static CK_ATTRIBUTE_TYPE attrTypes[5] = { 475 CKA_TOKEN, CKA_PRIVATE, CKA_MODIFIABLE, CKA_SENSITIVE, 476 CKA_EXTRACTABLE 477 }; 478 479 const CK_ATTRIBUTE_TYPE *pType = attrTypes; 480 CK_ATTRIBUTE *attr = attrs; 481 PK11AttrFlags test = PK11_ATTR_TOKEN; 482 483 PR_ASSERT(!pk11_BadAttrFlags(attrFlags)); 484 485 /* we test two related bitflags in each iteration */ 486 for (; attrFlags && test <= PK11_ATTR_EXTRACTABLE; test <<= 2, ++pType) { 487 if (test & attrFlags) { 488 attrFlags ^= test; 489 PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue); 490 ++attr; 491 } else if ((test << 1) & attrFlags) { 492 attrFlags ^= (test << 1); 493 PK11_SETATTRS(attr, *pType, ckFalse, sizeof *ckFalse); 494 ++attr; 495 } 496 } 497 return (attr - attrs); 498 } 499 500 /* 501 * Some non-compliant PKCS #11 vendors do not give us the modulus, so actually 502 * set up a signature to get the signaure length. 503 */ 504 static int 505 pk11_backupGetSignLength(SECKEYPrivateKey *key) 506 { 507 PK11SlotInfo *slot = key->pkcs11Slot; 508 CK_MECHANISM mech = { 0, NULL, 0 }; 509 PRBool owner = PR_TRUE; 510 CK_SESSION_HANDLE session; 511 CK_ULONG len; 512 CK_RV crv; 513 unsigned char h_data[20] = { 0 }; 514 unsigned char buf[20]; /* obviously to small */ 515 CK_ULONG smallLen = sizeof(buf); 516 517 mech.mechanism = PK11_MapSignKeyType(key->keyType); 518 519 session = pk11_GetNewSession(slot, &owner); 520 if (!owner || !(slot->isThreadSafe)) 521 PK11_EnterSlotMonitor(slot); 522 crv = PK11_GETTAB(slot)->C_SignInit(session, &mech, key->pkcs11ID); 523 if (crv != CKR_OK) { 524 if (!owner || !(slot->isThreadSafe)) 525 PK11_ExitSlotMonitor(slot); 526 pk11_CloseSession(slot, session, owner); 527 PORT_SetError(PK11_MapError(crv)); 528 return -1; 529 } 530 len = 0; 531 crv = PK11_GETTAB(slot)->C_Sign(session, h_data, sizeof(h_data), 532 NULL, &len); 533 /* now call C_Sign with too small a buffer to clear the session state */ 534 (void)PK11_GETTAB(slot)->C_Sign(session, h_data, sizeof(h_data), buf, &smallLen); 535 536 if (!owner || !(slot->isThreadSafe)) 537 PK11_ExitSlotMonitor(slot); 538 pk11_CloseSession(slot, session, owner); 539 if (crv != CKR_OK) { 540 PORT_SetError(PK11_MapError(crv)); 541 return -1; 542 } 543 return len; 544 } 545 546 /* 547 * get the length of a signature object based on the key 548 */ 549 int 550 PK11_SignatureLen(SECKEYPrivateKey *key) 551 { 552 int val; 553 SECItem attributeItem = { siBuffer, NULL, 0 }; 554 SECStatus rv; 555 int length; 556 SECOidTag paramSet; 557 558 switch (key->keyType) { 559 case rsaKey: 560 case rsaPssKey: 561 val = PK11_GetPrivateModulusLen(key); 562 if (val == -1) { 563 return pk11_backupGetSignLength(key); 564 } 565 return (unsigned long)val; 566 567 case fortezzaKey: 568 return 40; 569 570 case dsaKey: 571 rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, CKA_SUBPRIME, 572 NULL, &attributeItem); 573 if (rv == SECSuccess) { 574 length = attributeItem.len; 575 if ((length > 0) && attributeItem.data[0] == 0) { 576 length--; 577 } 578 PORT_Free(attributeItem.data); 579 return length * 2; 580 } 581 return pk11_backupGetSignLength(key); 582 case ecKey: 583 case edKey: 584 rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, CKA_EC_PARAMS, 585 NULL, &attributeItem); 586 if (rv == SECSuccess) { 587 length = SECKEY_ECParamsToBasePointOrderLen(&attributeItem); 588 PORT_Free(attributeItem.data); 589 if (length != 0) { 590 length = ((length + 7) / 8) * 2; 591 return length; 592 } 593 } 594 return pk11_backupGetSignLength(key); 595 case mldsaKey: 596 paramSet = seckey_GetParameterSet(key); 597 if (paramSet == SEC_OID_UNKNOWN) { 598 break; 599 } 600 601 return SECKEY_MLDSAOidParamsToLen(paramSet, SECKEYSignatureType); 602 default: 603 break; 604 } 605 PORT_SetError(SEC_ERROR_INVALID_KEY); 606 return 0; 607 } 608 609 /* 610 * copy a key (or any other object) on a token 611 */ 612 CK_OBJECT_HANDLE 613 PK11_CopyKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE srcObject) 614 { 615 CK_OBJECT_HANDLE destObject; 616 CK_RV crv; 617 618 PK11_EnterSlotMonitor(slot); 619 crv = PK11_GETTAB(slot)->C_CopyObject(slot->session, srcObject, NULL, 0, 620 &destObject); 621 PK11_ExitSlotMonitor(slot); 622 if (crv == CKR_OK) 623 return destObject; 624 PORT_SetError(PK11_MapError(crv)); 625 return CK_INVALID_HANDLE; 626 } 627 628 PRBool 629 pk11_FindAttrInTemplate(CK_ATTRIBUTE *attr, unsigned int numAttrs, 630 CK_ATTRIBUTE_TYPE target) 631 { 632 for (; numAttrs > 0; ++attr, --numAttrs) { 633 if (attr->type == target) 634 return PR_TRUE; 635 } 636 return PR_FALSE; 637 } 638 639 /* 640 * Recover the Signed data. We need this because our old verify can't 641 * figure out which hash algorithm to use until we decryptted this. 642 */ 643 SECStatus 644 PK11_VerifyRecover(SECKEYPublicKey *key, const SECItem *sig, 645 SECItem *dsig, void *wincx) 646 { 647 PK11SlotInfo *slot = key->pkcs11Slot; 648 CK_OBJECT_HANDLE id = key->pkcs11ID; 649 CK_MECHANISM mech = { 0, NULL, 0 }; 650 PRBool owner = PR_TRUE; 651 CK_SESSION_HANDLE session; 652 CK_ULONG len; 653 CK_RV crv; 654 655 mech.mechanism = PK11_MapSignKeyType(key->keyType); 656 657 if (slot == NULL) { 658 slot = PK11_GetBestSlotWithAttributes(mech.mechanism, 659 CKF_VERIFY_RECOVER, 0, wincx); 660 if (slot == NULL) { 661 PORT_SetError(SEC_ERROR_NO_MODULE); 662 return SECFailure; 663 } 664 id = PK11_ImportPublicKey(slot, key, PR_FALSE); 665 } else { 666 PK11_ReferenceSlot(slot); 667 } 668 669 if (id == CK_INVALID_HANDLE) { 670 PK11_FreeSlot(slot); 671 PORT_SetError(SEC_ERROR_BAD_KEY); 672 return SECFailure; 673 } 674 675 session = pk11_GetNewSession(slot, &owner); 676 if (!owner || !(slot->isThreadSafe)) 677 PK11_EnterSlotMonitor(slot); 678 crv = PK11_GETTAB(slot)->C_VerifyRecoverInit(session, &mech, id); 679 if (crv != CKR_OK) { 680 if (!owner || !(slot->isThreadSafe)) 681 PK11_ExitSlotMonitor(slot); 682 pk11_CloseSession(slot, session, owner); 683 PORT_SetError(PK11_MapError(crv)); 684 PK11_FreeSlot(slot); 685 return SECFailure; 686 } 687 len = dsig->len; 688 crv = PK11_GETTAB(slot)->C_VerifyRecover(session, sig->data, 689 sig->len, dsig->data, &len); 690 if (!owner || !(slot->isThreadSafe)) 691 PK11_ExitSlotMonitor(slot); 692 pk11_CloseSession(slot, session, owner); 693 dsig->len = len; 694 if (crv != CKR_OK) { 695 PORT_SetError(PK11_MapError(crv)); 696 PK11_FreeSlot(slot); 697 return SECFailure; 698 } 699 PK11_FreeSlot(slot); 700 return SECSuccess; 701 } 702 703 /* 704 * verify a signature from its hash. 705 */ 706 SECStatus 707 PK11_Verify(SECKEYPublicKey *key, const SECItem *sig, const SECItem *hash, 708 void *wincx) 709 { 710 CK_MECHANISM_TYPE mech = PK11_MapSignKeyType(key->keyType); 711 return PK11_VerifyWithMechanism(key, mech, NULL, sig, hash, wincx); 712 } 713 714 /* 715 * Verify a signature from its hash using the given algorithm. 716 */ 717 SECStatus 718 PK11_VerifyWithMechanism(SECKEYPublicKey *key, CK_MECHANISM_TYPE mechanism, 719 const SECItem *param, const SECItem *sig, 720 const SECItem *hash, void *wincx) 721 { 722 PK11SlotInfo *slot = key->pkcs11Slot; 723 CK_OBJECT_HANDLE id = key->pkcs11ID; 724 CK_MECHANISM mech = { 0, NULL, 0 }; 725 PRBool owner = PR_TRUE; 726 CK_SESSION_HANDLE session; 727 CK_RV crv; 728 729 mech.mechanism = mechanism; 730 if (param) { 731 mech.pParameter = param->data; 732 mech.ulParameterLen = param->len; 733 } 734 735 if (slot == NULL) { 736 unsigned int length = 0; 737 if ((mech.mechanism == CKM_DSA) && 738 /* 129 is 1024 bits translated to bytes and 739 * padded with an optional '0' to maintain a 740 * positive sign */ 741 (key->u.dsa.params.prime.len > 129)) { 742 /* we need to get a slot that not only can do DSA, but can do DSA2 743 * key lengths */ 744 length = key->u.dsa.params.prime.len; 745 if (key->u.dsa.params.prime.data[0] == 0) { 746 length--; 747 } 748 /* convert keysize to bits for slot lookup */ 749 length *= 8; 750 } 751 slot = PK11_GetBestSlotWithAttributes(mech.mechanism, 752 CKF_VERIFY, length, wincx); 753 if (slot == NULL) { 754 PORT_SetError(SEC_ERROR_NO_MODULE); 755 return SECFailure; 756 } 757 id = PK11_ImportPublicKey(slot, key, PR_FALSE); 758 759 } else { 760 PK11_ReferenceSlot(slot); 761 } 762 763 if (id == CK_INVALID_HANDLE) { 764 PK11_FreeSlot(slot); 765 PORT_SetError(SEC_ERROR_BAD_KEY); 766 return SECFailure; 767 } 768 769 session = pk11_GetNewSession(slot, &owner); 770 if (!owner || !(slot->isThreadSafe)) 771 PK11_EnterSlotMonitor(slot); 772 if (PK11_CheckPKCS11Version(slot, 3, 2, PR_TRUE) >= 0) { 773 crv = PK11_GETTAB(slot)->C_VerifySignatureInit(session, &mech, id, 774 sig->data, sig->len); 775 if (crv != CKR_OK) { 776 if (!owner || !(slot->isThreadSafe)) 777 PK11_ExitSlotMonitor(slot); 778 pk11_CloseSession(slot, session, owner); 779 PK11_FreeSlot(slot); 780 PORT_SetError(PK11_MapError(crv)); 781 return SECFailure; 782 } 783 crv = PK11_GETTAB(slot)->C_VerifySignature(session, hash->data, 784 hash->len); 785 } else { 786 crv = PK11_GETTAB(slot)->C_VerifyInit(session, &mech, id); 787 if (crv != CKR_OK) { 788 if (!owner || !(slot->isThreadSafe)) 789 PK11_ExitSlotMonitor(slot); 790 pk11_CloseSession(slot, session, owner); 791 PK11_FreeSlot(slot); 792 PORT_SetError(PK11_MapError(crv)); 793 return SECFailure; 794 } 795 crv = PK11_GETTAB(slot)->C_Verify(session, hash->data, 796 hash->len, sig->data, sig->len); 797 } 798 if (!owner || !(slot->isThreadSafe)) 799 PK11_ExitSlotMonitor(slot); 800 801 pk11_CloseSession(slot, session, owner); 802 PK11_FreeSlot(slot); 803 if (crv != CKR_OK) { 804 PORT_SetError(PK11_MapError(crv)); 805 return SECFailure; 806 } 807 return SECSuccess; 808 } 809 810 /* 811 * sign a hash. The algorithm is determined by the key. 812 */ 813 SECStatus 814 PK11_Sign(SECKEYPrivateKey *key, SECItem *sig, const SECItem *hash) 815 { 816 CK_MECHANISM_TYPE mech = PK11_MapSignKeyType(key->keyType); 817 return PK11_SignWithMechanism(key, mech, NULL, sig, hash); 818 } 819 820 /* 821 * Sign a hash using the given algorithm. 822 */ 823 SECStatus 824 PK11_SignWithMechanism(SECKEYPrivateKey *key, CK_MECHANISM_TYPE mechanism, 825 const SECItem *param, SECItem *sig, const SECItem *hash) 826 { 827 PK11SlotInfo *slot = key->pkcs11Slot; 828 CK_MECHANISM mech = { 0, NULL, 0 }; 829 PRBool owner = PR_TRUE; 830 CK_SESSION_HANDLE session; 831 PRBool haslock = PR_FALSE; 832 CK_ULONG len; 833 CK_RV crv; 834 835 mech.mechanism = mechanism; 836 if (param) { 837 mech.pParameter = param->data; 838 mech.ulParameterLen = param->len; 839 } 840 841 if (SECKEY_HAS_ATTRIBUTE_SET(key, CKA_PRIVATE)) { 842 PK11_HandlePasswordCheck(slot, key->wincx); 843 } 844 845 session = pk11_GetNewSession(slot, &owner); 846 haslock = (!owner || !(slot->isThreadSafe)); 847 if (haslock) 848 PK11_EnterSlotMonitor(slot); 849 crv = PK11_GETTAB(slot)->C_SignInit(session, &mech, key->pkcs11ID); 850 if (crv != CKR_OK) { 851 if (haslock) 852 PK11_ExitSlotMonitor(slot); 853 pk11_CloseSession(slot, session, owner); 854 PORT_SetError(PK11_MapError(crv)); 855 return SECFailure; 856 } 857 858 /* PKCS11 2.20 says if CKA_ALWAYS_AUTHENTICATE then 859 * do C_Login with CKU_CONTEXT_SPECIFIC 860 * between C_SignInit and C_Sign */ 861 if (SECKEY_HAS_ATTRIBUTE_SET_LOCK(key, CKA_ALWAYS_AUTHENTICATE, haslock)) { 862 PK11_DoPassword(slot, session, PR_FALSE, key->wincx, haslock, PR_TRUE); 863 } 864 865 len = sig->len; 866 crv = PK11_GETTAB(slot)->C_Sign(session, hash->data, 867 hash->len, sig->data, &len); 868 if (haslock) 869 PK11_ExitSlotMonitor(slot); 870 pk11_CloseSession(slot, session, owner); 871 sig->len = len; 872 if (crv != CKR_OK) { 873 PORT_SetError(PK11_MapError(crv)); 874 return SECFailure; 875 } 876 return SECSuccess; 877 } 878 879 /* 880 * sign data with a MAC key. 881 */ 882 SECStatus 883 PK11_SignWithSymKey(PK11SymKey *symKey, CK_MECHANISM_TYPE mechanism, 884 SECItem *param, SECItem *sig, const SECItem *data) 885 { 886 PK11SlotInfo *slot = symKey->slot; 887 CK_MECHANISM mech = { 0, NULL, 0 }; 888 PRBool owner = PR_TRUE; 889 CK_SESSION_HANDLE session; 890 PRBool haslock = PR_FALSE; 891 CK_ULONG len; 892 CK_RV crv; 893 894 mech.mechanism = mechanism; 895 if (param) { 896 mech.pParameter = param->data; 897 mech.ulParameterLen = param->len; 898 } 899 900 session = pk11_GetNewSession(slot, &owner); 901 haslock = (!owner || !(slot->isThreadSafe)); 902 if (haslock) 903 PK11_EnterSlotMonitor(slot); 904 crv = PK11_GETTAB(slot)->C_SignInit(session, &mech, symKey->objectID); 905 if (crv != CKR_OK) { 906 if (haslock) 907 PK11_ExitSlotMonitor(slot); 908 pk11_CloseSession(slot, session, owner); 909 PORT_SetError(PK11_MapError(crv)); 910 return SECFailure; 911 } 912 913 len = sig->len; 914 crv = PK11_GETTAB(slot)->C_Sign(session, data->data, 915 data->len, sig->data, &len); 916 if (haslock) 917 PK11_ExitSlotMonitor(slot); 918 pk11_CloseSession(slot, session, owner); 919 sig->len = len; 920 if (crv != CKR_OK) { 921 PORT_SetError(PK11_MapError(crv)); 922 return SECFailure; 923 } 924 return SECSuccess; 925 } 926 927 SECStatus 928 PK11_Decrypt(PK11SymKey *symKey, 929 CK_MECHANISM_TYPE mechanism, SECItem *param, 930 unsigned char *out, unsigned int *outLen, 931 unsigned int maxLen, 932 const unsigned char *enc, unsigned encLen) 933 { 934 PK11SlotInfo *slot = symKey->slot; 935 CK_MECHANISM mech = { 0, NULL, 0 }; 936 CK_ULONG len = maxLen; 937 PRBool owner = PR_TRUE; 938 CK_SESSION_HANDLE session; 939 PRBool haslock = PR_FALSE; 940 CK_RV crv; 941 942 mech.mechanism = mechanism; 943 if (param) { 944 mech.pParameter = param->data; 945 mech.ulParameterLen = param->len; 946 } 947 948 session = pk11_GetNewSession(slot, &owner); 949 haslock = (!owner || !slot->isThreadSafe); 950 if (haslock) 951 PK11_EnterSlotMonitor(slot); 952 crv = PK11_GETTAB(slot)->C_DecryptInit(session, &mech, symKey->objectID); 953 if (crv != CKR_OK) { 954 if (haslock) 955 PK11_ExitSlotMonitor(slot); 956 pk11_CloseSession(slot, session, owner); 957 PORT_SetError(PK11_MapError(crv)); 958 return SECFailure; 959 } 960 961 crv = PK11_GETTAB(slot)->C_Decrypt(session, (unsigned char *)enc, encLen, 962 out, &len); 963 if (haslock) 964 PK11_ExitSlotMonitor(slot); 965 pk11_CloseSession(slot, session, owner); 966 if (crv != CKR_OK) { 967 PORT_SetError(PK11_MapError(crv)); 968 return SECFailure; 969 } 970 *outLen = len; 971 return SECSuccess; 972 } 973 974 SECStatus 975 PK11_Encrypt(PK11SymKey *symKey, 976 CK_MECHANISM_TYPE mechanism, SECItem *param, 977 unsigned char *out, unsigned int *outLen, 978 unsigned int maxLen, 979 const unsigned char *data, unsigned int dataLen) 980 { 981 PK11SlotInfo *slot = symKey->slot; 982 CK_MECHANISM mech = { 0, NULL, 0 }; 983 CK_ULONG len = maxLen; 984 PRBool owner = PR_TRUE; 985 CK_SESSION_HANDLE session; 986 PRBool haslock = PR_FALSE; 987 CK_RV crv; 988 989 mech.mechanism = mechanism; 990 if (param) { 991 mech.pParameter = param->data; 992 mech.ulParameterLen = param->len; 993 } 994 995 session = pk11_GetNewSession(slot, &owner); 996 haslock = (!owner || !slot->isThreadSafe); 997 if (haslock) 998 PK11_EnterSlotMonitor(slot); 999 crv = PK11_GETTAB(slot)->C_EncryptInit(session, &mech, symKey->objectID); 1000 if (crv != CKR_OK) { 1001 if (haslock) 1002 PK11_ExitSlotMonitor(slot); 1003 pk11_CloseSession(slot, session, owner); 1004 PORT_SetError(PK11_MapError(crv)); 1005 return SECFailure; 1006 } 1007 crv = PK11_GETTAB(slot)->C_Encrypt(session, (unsigned char *)data, 1008 dataLen, out, &len); 1009 if (haslock) 1010 PK11_ExitSlotMonitor(slot); 1011 pk11_CloseSession(slot, session, owner); 1012 if (crv != CKR_OK) { 1013 PORT_SetError(PK11_MapError(crv)); 1014 return SECFailure; 1015 } 1016 *outLen = len; 1017 return SECSuccess; 1018 } 1019 1020 static SECStatus 1021 pk11_PrivDecryptRaw(SECKEYPrivateKey *key, 1022 unsigned char *data, unsigned *outLen, unsigned int maxLen, 1023 const unsigned char *enc, unsigned encLen, 1024 CK_MECHANISM_PTR mech) 1025 { 1026 PK11SlotInfo *slot = key->pkcs11Slot; 1027 CK_ULONG out = maxLen; 1028 PRBool owner = PR_TRUE; 1029 CK_SESSION_HANDLE session; 1030 PRBool haslock = PR_FALSE; 1031 CK_RV crv; 1032 1033 if (key->keyType != rsaKey) { 1034 PORT_SetError(SEC_ERROR_INVALID_KEY); 1035 return SECFailure; 1036 } 1037 1038 /* Why do we do a PK11_handle check here? for simple 1039 * decryption? .. because the user may have asked for 'ask always' 1040 * and this is a private key operation. In practice, thought, it's mute 1041 * since only servers wind up using this function */ 1042 if (SECKEY_HAS_ATTRIBUTE_SET(key, CKA_PRIVATE)) { 1043 PK11_HandlePasswordCheck(slot, key->wincx); 1044 } 1045 session = pk11_GetNewSession(slot, &owner); 1046 haslock = (!owner || !(slot->isThreadSafe)); 1047 if (haslock) 1048 PK11_EnterSlotMonitor(slot); 1049 crv = PK11_GETTAB(slot)->C_DecryptInit(session, mech, key->pkcs11ID); 1050 if (crv != CKR_OK) { 1051 if (haslock) 1052 PK11_ExitSlotMonitor(slot); 1053 pk11_CloseSession(slot, session, owner); 1054 PORT_SetError(PK11_MapError(crv)); 1055 return SECFailure; 1056 } 1057 1058 /* PKCS11 2.20 says if CKA_ALWAYS_AUTHENTICATE then 1059 * do C_Login with CKU_CONTEXT_SPECIFIC 1060 * between C_DecryptInit and C_Decrypt 1061 * ... But see note above about servers */ 1062 if (SECKEY_HAS_ATTRIBUTE_SET_LOCK(key, CKA_ALWAYS_AUTHENTICATE, haslock)) { 1063 PK11_DoPassword(slot, session, PR_FALSE, key->wincx, haslock, PR_TRUE); 1064 } 1065 1066 crv = PK11_GETTAB(slot)->C_Decrypt(session, (unsigned char *)enc, encLen, 1067 data, &out); 1068 if (haslock) 1069 PK11_ExitSlotMonitor(slot); 1070 pk11_CloseSession(slot, session, owner); 1071 *outLen = out; 1072 if (crv != CKR_OK) { 1073 PORT_SetError(PK11_MapError(crv)); 1074 return SECFailure; 1075 } 1076 return SECSuccess; 1077 } 1078 1079 SECStatus 1080 PK11_PubDecryptRaw(SECKEYPrivateKey *key, 1081 unsigned char *data, unsigned *outLen, unsigned int maxLen, 1082 const unsigned char *enc, unsigned encLen) 1083 { 1084 CK_MECHANISM mech = { CKM_RSA_X_509, NULL, 0 }; 1085 return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech); 1086 } 1087 1088 SECStatus 1089 PK11_PrivDecryptPKCS1(SECKEYPrivateKey *key, 1090 unsigned char *data, unsigned *outLen, unsigned int maxLen, 1091 const unsigned char *enc, unsigned encLen) 1092 { 1093 CK_MECHANISM mech = { CKM_RSA_PKCS, NULL, 0 }; 1094 return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech); 1095 } 1096 1097 static SECStatus 1098 pk11_PubEncryptRaw(SECKEYPublicKey *key, 1099 unsigned char *out, unsigned int *outLen, 1100 unsigned int maxLen, 1101 const unsigned char *data, unsigned dataLen, 1102 CK_MECHANISM_PTR mech, void *wincx) 1103 { 1104 PK11SlotInfo *slot; 1105 CK_OBJECT_HANDLE id; 1106 CK_ULONG len = maxLen; 1107 PRBool owner = PR_TRUE; 1108 CK_SESSION_HANDLE session; 1109 CK_RV crv; 1110 1111 slot = PK11_GetBestSlotWithAttributes(mech->mechanism, CKF_ENCRYPT, 0, wincx); 1112 if (slot == NULL) { 1113 PORT_SetError(SEC_ERROR_NO_MODULE); 1114 return SECFailure; 1115 } 1116 1117 id = PK11_ImportPublicKey(slot, key, PR_FALSE); 1118 1119 if (id == CK_INVALID_HANDLE) { 1120 PK11_FreeSlot(slot); 1121 PORT_SetError(SEC_ERROR_BAD_KEY); 1122 return SECFailure; 1123 } 1124 1125 session = pk11_GetNewSession(slot, &owner); 1126 if (!owner || !(slot->isThreadSafe)) 1127 PK11_EnterSlotMonitor(slot); 1128 crv = PK11_GETTAB(slot)->C_EncryptInit(session, mech, id); 1129 if (crv != CKR_OK) { 1130 if (!owner || !(slot->isThreadSafe)) 1131 PK11_ExitSlotMonitor(slot); 1132 pk11_CloseSession(slot, session, owner); 1133 PK11_FreeSlot(slot); 1134 PORT_SetError(PK11_MapError(crv)); 1135 return SECFailure; 1136 } 1137 crv = PK11_GETTAB(slot)->C_Encrypt(session, (unsigned char *)data, dataLen, 1138 out, &len); 1139 if (!owner || !(slot->isThreadSafe)) 1140 PK11_ExitSlotMonitor(slot); 1141 pk11_CloseSession(slot, session, owner); 1142 PK11_FreeSlot(slot); 1143 *outLen = len; 1144 if (crv != CKR_OK) { 1145 PORT_SetError(PK11_MapError(crv)); 1146 return SECFailure; 1147 } 1148 return SECSuccess; 1149 } 1150 1151 SECStatus 1152 PK11_PubEncryptRaw(SECKEYPublicKey *key, 1153 unsigned char *enc, 1154 const unsigned char *data, unsigned dataLen, 1155 void *wincx) 1156 { 1157 CK_MECHANISM mech = { CKM_RSA_X_509, NULL, 0 }; 1158 unsigned int outLen; 1159 if (!key || key->keyType != rsaKey) { 1160 PORT_SetError(SEC_ERROR_BAD_KEY); 1161 return SECFailure; 1162 } 1163 outLen = SECKEY_PublicKeyStrength(key); 1164 return pk11_PubEncryptRaw(key, enc, &outLen, outLen, data, dataLen, &mech, 1165 wincx); 1166 } 1167 1168 SECStatus 1169 PK11_PubEncryptPKCS1(SECKEYPublicKey *key, 1170 unsigned char *enc, 1171 const unsigned char *data, unsigned dataLen, 1172 void *wincx) 1173 { 1174 CK_MECHANISM mech = { CKM_RSA_PKCS, NULL, 0 }; 1175 unsigned int outLen; 1176 if (!key || key->keyType != rsaKey) { 1177 PORT_SetError(SEC_ERROR_BAD_KEY); 1178 return SECFailure; 1179 } 1180 outLen = SECKEY_PublicKeyStrength(key); 1181 return pk11_PubEncryptRaw(key, enc, &outLen, outLen, data, dataLen, &mech, 1182 wincx); 1183 } 1184 1185 SECStatus 1186 PK11_PrivDecrypt(SECKEYPrivateKey *key, 1187 CK_MECHANISM_TYPE mechanism, SECItem *param, 1188 unsigned char *out, unsigned int *outLen, 1189 unsigned int maxLen, 1190 const unsigned char *enc, unsigned encLen) 1191 { 1192 CK_MECHANISM mech = { mechanism, NULL, 0 }; 1193 if (param) { 1194 mech.pParameter = param->data; 1195 mech.ulParameterLen = param->len; 1196 } 1197 return pk11_PrivDecryptRaw(key, out, outLen, maxLen, enc, encLen, &mech); 1198 } 1199 1200 SECStatus 1201 PK11_PubEncrypt(SECKEYPublicKey *key, 1202 CK_MECHANISM_TYPE mechanism, SECItem *param, 1203 unsigned char *out, unsigned int *outLen, 1204 unsigned int maxLen, 1205 const unsigned char *data, unsigned dataLen, 1206 void *wincx) 1207 { 1208 CK_MECHANISM mech = { mechanism, NULL, 0 }; 1209 if (param) { 1210 mech.pParameter = param->data; 1211 mech.ulParameterLen = param->len; 1212 } 1213 return pk11_PubEncryptRaw(key, out, outLen, maxLen, data, dataLen, &mech, 1214 wincx); 1215 } 1216 1217 SECKEYPrivateKey * 1218 PK11_UnwrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey, 1219 CK_MECHANISM_TYPE wrapType, SECItem *param, 1220 SECItem *wrappedKey, SECItem *label, 1221 const SECItem *idValue, PRBool perm, PRBool sensitive, 1222 CK_KEY_TYPE keyType, CK_ATTRIBUTE_TYPE *usage, 1223 int usageCount, void *wincx) 1224 { 1225 CK_BBOOL cktrue = CK_TRUE; 1226 CK_BBOOL ckfalse = CK_FALSE; 1227 CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; 1228 CK_ATTRIBUTE keyTemplate[15]; 1229 int templateCount = 0; 1230 CK_OBJECT_HANDLE privKeyID; 1231 CK_MECHANISM mechanism; 1232 CK_ATTRIBUTE *attrs = keyTemplate; 1233 SECItem *param_free = NULL, *ck_id = NULL; 1234 CK_RV crv; 1235 CK_SESSION_HANDLE rwsession; 1236 PK11SymKey *newKey = NULL; 1237 int i; 1238 1239 if (!slot || !wrappedKey || !idValue) { 1240 PORT_SetError(SEC_ERROR_INVALID_ARGS); 1241 return NULL; 1242 } 1243 1244 ck_id = PK11_MakeIDFromPubKey(idValue); 1245 if (!ck_id) { 1246 return NULL; 1247 } 1248 1249 PK11_SETATTRS(attrs, CKA_TOKEN, perm ? &cktrue : &ckfalse, 1250 sizeof(cktrue)); 1251 attrs++; 1252 PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass)); 1253 attrs++; 1254 PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); 1255 attrs++; 1256 PK11_SETATTRS(attrs, CKA_PRIVATE, sensitive ? &cktrue : &ckfalse, 1257 sizeof(cktrue)); 1258 attrs++; 1259 PK11_SETATTRS(attrs, CKA_SENSITIVE, sensitive ? &cktrue : &ckfalse, 1260 sizeof(cktrue)); 1261 attrs++; 1262 if (label && label->data) { 1263 PK11_SETATTRS(attrs, CKA_LABEL, label->data, label->len); 1264 attrs++; 1265 } 1266 PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len); 1267 attrs++; 1268 for (i = 0; i < usageCount; i++) { 1269 PK11_SETATTRS(attrs, usage[i], &cktrue, sizeof(cktrue)); 1270 attrs++; 1271 } 1272 1273 if (PK11_IsInternal(slot)) { 1274 PK11_SETATTRS(attrs, CKA_NSS_DB, idValue->data, 1275 idValue->len); 1276 attrs++; 1277 } 1278 1279 templateCount = attrs - keyTemplate; 1280 PR_ASSERT(templateCount <= (sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE))); 1281 1282 mechanism.mechanism = wrapType; 1283 if (!param) 1284 param = param_free = PK11_ParamFromIV(wrapType, NULL); 1285 if (param) { 1286 mechanism.pParameter = param->data; 1287 mechanism.ulParameterLen = param->len; 1288 } else { 1289 mechanism.pParameter = NULL; 1290 mechanism.ulParameterLen = 0; 1291 } 1292 1293 if (wrappingKey->slot != slot) { 1294 newKey = pk11_CopyToSlot(slot, wrapType, CKA_UNWRAP, wrappingKey); 1295 } else { 1296 newKey = PK11_ReferenceSymKey(wrappingKey); 1297 } 1298 1299 if (newKey) { 1300 if (perm) { 1301 /* Get RW Session will either lock the monitor if necessary, 1302 * or return a thread safe session handle, or fail. */ 1303 rwsession = PK11_GetRWSession(slot); 1304 } else { 1305 rwsession = slot->session; 1306 if (rwsession != CK_INVALID_HANDLE) 1307 PK11_EnterSlotMonitor(slot); 1308 } 1309 /* This is a lot a work to deal with fussy PKCS #11 modules 1310 * that can't bother to return BAD_DATA when presented with an 1311 * invalid session! */ 1312 if (rwsession == CK_INVALID_HANDLE) { 1313 PORT_SetError(SEC_ERROR_BAD_DATA); 1314 goto loser; 1315 } 1316 crv = PK11_GETTAB(slot)->C_UnwrapKey(rwsession, &mechanism, 1317 newKey->objectID, 1318 wrappedKey->data, 1319 wrappedKey->len, keyTemplate, 1320 templateCount, &privKeyID); 1321 1322 if (perm) { 1323 PK11_RestoreROSession(slot, rwsession); 1324 } else { 1325 PK11_ExitSlotMonitor(slot); 1326 } 1327 PK11_FreeSymKey(newKey); 1328 newKey = NULL; 1329 } else { 1330 crv = CKR_FUNCTION_NOT_SUPPORTED; 1331 } 1332 1333 SECITEM_FreeItem(ck_id, PR_TRUE); 1334 ck_id = NULL; 1335 1336 if (crv != CKR_OK) { 1337 /* we couldn't unwrap the key, use the internal module to do the 1338 * unwrap, then load the new key into the token */ 1339 PK11SlotInfo *int_slot = PK11_GetInternalSlot(); 1340 1341 if (int_slot && (slot != int_slot)) { 1342 SECKEYPrivateKey *privKey = PK11_UnwrapPrivKey(int_slot, 1343 wrappingKey, wrapType, param, wrappedKey, label, 1344 idValue, PR_FALSE, PR_FALSE, 1345 keyType, usage, usageCount, wincx); 1346 if (privKey) { 1347 SECKEYPrivateKey *newPrivKey = PK11_LoadPrivKey(slot, privKey, 1348 NULL, perm, sensitive); 1349 SECKEY_DestroyPrivateKey(privKey); 1350 PK11_FreeSlot(int_slot); 1351 SECITEM_FreeItem(param_free, PR_TRUE); 1352 return newPrivKey; 1353 } 1354 } 1355 if (int_slot) 1356 PK11_FreeSlot(int_slot); 1357 PORT_SetError(PK11_MapError(crv)); 1358 SECITEM_FreeItem(param_free, PR_TRUE); 1359 return NULL; 1360 } 1361 SECITEM_FreeItem(param_free, PR_TRUE); 1362 return PK11_MakePrivKey(slot, nullKey, PR_FALSE, privKeyID, wincx); 1363 1364 loser: 1365 PK11_FreeSymKey(newKey); 1366 SECITEM_FreeItem(ck_id, PR_TRUE); 1367 SECITEM_FreeItem(param_free, PR_TRUE); 1368 return NULL; 1369 } 1370 1371 /* 1372 * PK11_UnwrapPrivKeyByKeyType is like PK11_UnwrapPrivKey but uses the 1373 * keyType and the keyUsage to determine what usage attributes to set. 1374 */ 1375 #define _MAX_USAGE 6 1376 SECKEYPrivateKey * 1377 PK11_UnwrapPrivKeyByKeyType(PK11SlotInfo *slot, PK11SymKey *wrappingKey, 1378 CK_MECHANISM_TYPE wrapType, SECItem *param, 1379 SECItem *wrappedKey, SECItem *label, 1380 const SECItem *idValue, PRBool perm, PRBool sensitive, 1381 KeyType keyType, unsigned int keyUsage, void *wincx) 1382 { 1383 CK_KEY_TYPE pk11KeyType = pk11_getPKCS11KeyTypeFromKeyType(keyType); 1384 CK_ATTRIBUTE_TYPE usage[_MAX_USAGE]; 1385 int usageCount = 0; 1386 PRBool needKeyUsage = PR_FALSE; 1387 1388 /* RSA and ecKeys can be used in more than one usage, use the 1389 * key usage to determine which usage to actual set */ 1390 if ((keyType == rsaKey) || (keyType == ecKey)) { 1391 needKeyUsage = PR_TRUE; 1392 } 1393 1394 /* use the pk11_mapXXXXKeyType functions to determine what kind 1395 * of attributes to set on the key. Using these functions reduces 1396 * the number of places we need to update to add new key types */ 1397 if ((pk11_mapWrapKeyType(keyType) != CKM_INVALID_MECHANISM) && 1398 (!needKeyUsage || keyUsage & KU_KEY_ENCIPHERMENT)) { 1399 usage[usageCount++] = CKA_UNWRAP; 1400 usage[usageCount++] = CKA_DECRYPT; 1401 } 1402 if ((pk11_mapKemKeyType(keyType) != CKM_INVALID_MECHANISM) && 1403 (!needKeyUsage || keyUsage & KU_KEY_AGREEMENT)) { 1404 usage[usageCount++] = CKA_DECAPSULATE; 1405 } 1406 if ((PK11_MapSignKeyType(keyType) != CKM_INVALID_MECHANISM) && 1407 (!needKeyUsage || keyUsage & KU_DIGITAL_SIGNATURE)) { 1408 usage[usageCount++] = CKA_SIGN; 1409 if (keyType == rsaKey) { 1410 usage[usageCount++] = CKA_SIGN_RECOVER; 1411 } 1412 } 1413 if ((pk11_mapDeriveKeyType(keyType) != CKM_INVALID_MECHANISM) && 1414 (!needKeyUsage || keyUsage & KU_KEY_AGREEMENT)) { 1415 usage[usageCount++] = CKA_DERIVE; 1416 } 1417 1418 PORT_Assert(usageCount <= _MAX_USAGE); 1419 1420 if (usageCount == 0) { 1421 PORT_SetError(SEC_ERROR_INVALID_ARGS); 1422 } 1423 return PK11_UnwrapPrivKey(slot, wrappingKey, wrapType, param, wrappedKey, 1424 label, idValue, perm, sensitive, pk11KeyType, 1425 usage, usageCount, wincx); 1426 } 1427 1428 /* 1429 * Now we're going to wrap a SECKEYPrivateKey with a PK11SymKey 1430 * The strategy is to get both keys to reside in the same slot, 1431 * one that can perform the desired crypto mechanism and then 1432 * call C_WrapKey after all the setup has taken place. 1433 */ 1434 SECStatus 1435 PK11_WrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey, 1436 SECKEYPrivateKey *privKey, CK_MECHANISM_TYPE wrapType, 1437 SECItem *param, SECItem *wrappedKey, void *wincx) 1438 { 1439 PK11SlotInfo *privSlot = privKey->pkcs11Slot; /* The slot where 1440 * the private key 1441 * we are going to 1442 * wrap lives. 1443 */ 1444 PK11SymKey *newSymKey = NULL; 1445 SECKEYPrivateKey *newPrivKey = NULL; 1446 SECItem *param_free = NULL; 1447 CK_ULONG len = wrappedKey->len; 1448 CK_MECHANISM mech; 1449 CK_RV crv; 1450 1451 if (!privSlot || !PK11_DoesMechanism(privSlot, wrapType)) { 1452 /* Figure out a slot that does the mechanism and try to import 1453 * the private key onto that slot. 1454 */ 1455 PK11SlotInfo *int_slot = PK11_GetInternalSlot(); 1456 1457 privSlot = int_slot; /* The private key has a new home */ 1458 newPrivKey = PK11_LoadPrivKey(privSlot, privKey, NULL, PR_FALSE, PR_FALSE); 1459 /* newPrivKey has allocated its own reference to the slot, so it's 1460 * safe until we destroy newPrivkey. 1461 */ 1462 PK11_FreeSlot(int_slot); 1463 if (newPrivKey == NULL) { 1464 return SECFailure; 1465 } 1466 privKey = newPrivKey; 1467 } 1468 1469 if (privSlot != wrappingKey->slot) { 1470 newSymKey = pk11_CopyToSlot(privSlot, wrapType, CKA_WRAP, 1471 wrappingKey); 1472 wrappingKey = newSymKey; 1473 } 1474 1475 if (wrappingKey == NULL) { 1476 if (newPrivKey) { 1477 SECKEY_DestroyPrivateKey(newPrivKey); 1478 } 1479 return SECFailure; 1480 } 1481 mech.mechanism = wrapType; 1482 if (!param) { 1483 param = param_free = PK11_ParamFromIV(wrapType, NULL); 1484 } 1485 if (param) { 1486 mech.pParameter = param->data; 1487 mech.ulParameterLen = param->len; 1488 } else { 1489 mech.pParameter = NULL; 1490 mech.ulParameterLen = 0; 1491 } 1492 1493 PK11_EnterSlotMonitor(privSlot); 1494 crv = PK11_GETTAB(privSlot)->C_WrapKey(privSlot->session, &mech, 1495 wrappingKey->objectID, 1496 privKey->pkcs11ID, 1497 wrappedKey->data, &len); 1498 PK11_ExitSlotMonitor(privSlot); 1499 1500 if (newSymKey) { 1501 PK11_FreeSymKey(newSymKey); 1502 } 1503 if (newPrivKey) { 1504 SECKEY_DestroyPrivateKey(newPrivKey); 1505 } 1506 if (param_free) { 1507 SECITEM_FreeItem(param_free, PR_TRUE); 1508 } 1509 1510 if (crv != CKR_OK) { 1511 PORT_SetError(PK11_MapError(crv)); 1512 return SECFailure; 1513 } 1514 1515 wrappedKey->len = len; 1516 return SECSuccess; 1517 } 1518 1519 #if 0 1520 /* 1521 * Sample code relating to linked list returned by PK11_FindGenericObjects 1522 */ 1523 1524 /* 1525 * You can walk the list with the following code: 1526 */ 1527 firstObj = PK11_FindGenericObjects(slot, objClass); 1528 for (thisObj=firstObj; 1529 thisObj; 1530 thisObj=PK11_GetNextGenericObject(thisObj)) { 1531 /* operate on thisObj */ 1532 } 1533 /* 1534 * If you want a particular object from the list... 1535 */ 1536 firstObj = PK11_FindGenericObjects(slot, objClass); 1537 for (thisObj=firstObj; 1538 thisObj; 1539 thisObj=PK11_GetNextGenericObject(thisObj)) { 1540 if (isMyObj(thisObj)) { 1541 if ( thisObj == firstObj) { 1542 /* NOTE: firstObj could be NULL at this point */ 1543 firstObj = PK11_GetNextGenericObject(thsObj); 1544 } 1545 PK11_UnlinkGenericObject(thisObj); 1546 myObj = thisObj; 1547 break; 1548 } 1549 } 1550 1551 PK11_DestroyGenericObjects(firstObj); 1552 1553 /* use myObj */ 1554 1555 PK11_DestroyGenericObject(myObj); 1556 #endif /* sample code */ 1557 1558 /* 1559 * return a linked, non-circular list of generic objects. 1560 * If you are only interested 1561 * in one object, just use the first object in the list. To find the 1562 * rest of the list use PK11_GetNextGenericObject() to return the next object. 1563 */ 1564 PK11GenericObject * 1565 PK11_FindGenericObjects(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass) 1566 { 1567 CK_ATTRIBUTE template[1]; 1568 CK_ATTRIBUTE *attrs = template; 1569 CK_OBJECT_HANDLE *objectIDs = NULL; 1570 PK11GenericObject *lastObj = NULL, *obj; 1571 PK11GenericObject *firstObj = NULL; 1572 int i, count = 0; 1573 1574 PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass)); 1575 attrs++; 1576 1577 objectIDs = pk11_FindObjectsByTemplate(slot, template, 1, &count); 1578 if (objectIDs == NULL) { 1579 return NULL; 1580 } 1581 1582 /* where we connect our object once we've created it.. */ 1583 for (i = 0; i < count; i++) { 1584 obj = PORT_New(PK11GenericObject); 1585 if (!obj) { 1586 if (firstObj) { 1587 PK11_DestroyGenericObjects(firstObj); 1588 } 1589 PORT_Free(objectIDs); 1590 return NULL; 1591 } 1592 /* initialize it */ 1593 obj->slot = PK11_ReferenceSlot(slot); 1594 obj->objectID = objectIDs[i]; 1595 obj->owner = PR_FALSE; 1596 obj->next = NULL; 1597 obj->prev = NULL; 1598 1599 /* link it in */ 1600 if (firstObj == NULL) { 1601 firstObj = obj; 1602 } else { 1603 PK11_LinkGenericObject(lastObj, obj); 1604 } 1605 lastObj = obj; 1606 } 1607 PORT_Free(objectIDs); 1608 return firstObj; 1609 } 1610 1611 /* 1612 * get the Next Object in the list. 1613 */ 1614 PK11GenericObject * 1615 PK11_GetNextGenericObject(PK11GenericObject *object) 1616 { 1617 return object->next; 1618 } 1619 1620 PK11GenericObject * 1621 PK11_GetPrevGenericObject(PK11GenericObject *object) 1622 { 1623 return object->prev; 1624 } 1625 1626 /* 1627 * Link a single object into a new list. 1628 * if the object is already in another list, remove it first. 1629 */ 1630 SECStatus 1631 PK11_LinkGenericObject(PK11GenericObject *list, PK11GenericObject *object) 1632 { 1633 PK11_UnlinkGenericObject(object); 1634 object->prev = list; 1635 object->next = list->next; 1636 list->next = object; 1637 if (object->next != NULL) { 1638 object->next->prev = object; 1639 } 1640 return SECSuccess; 1641 } 1642 1643 /* 1644 * remove an object from the list. If the object isn't already in 1645 * a list unlink becomes a noop. 1646 */ 1647 SECStatus 1648 PK11_UnlinkGenericObject(PK11GenericObject *object) 1649 { 1650 if (object->prev != NULL) { 1651 object->prev->next = object->next; 1652 } 1653 if (object->next != NULL) { 1654 object->next->prev = object->prev; 1655 } 1656 1657 object->next = NULL; 1658 object->prev = NULL; 1659 return SECSuccess; 1660 } 1661 1662 /* 1663 * This function removes a single object from the list and destroys it. 1664 * For an already unlinked object there is no difference between 1665 * PK11_DestroyGenericObject and PK11_DestroyGenericObjects 1666 */ 1667 SECStatus 1668 PK11_DestroyGenericObject(PK11GenericObject *object) 1669 { 1670 if (object == NULL) { 1671 return SECSuccess; 1672 } 1673 1674 PK11_UnlinkGenericObject(object); 1675 if (object->slot) { 1676 if (object->owner) { 1677 PK11_DestroyObject(object->slot, object->objectID); 1678 } 1679 PK11_FreeSlot(object->slot); 1680 } 1681 PORT_Free(object); 1682 return SECSuccess; 1683 } 1684 1685 /* 1686 * walk down a link list of generic objects destroying them. 1687 * This will destroy all objects in a list that the object is linked into. 1688 * (the list is traversed in both directions). 1689 */ 1690 SECStatus 1691 PK11_DestroyGenericObjects(PK11GenericObject *objects) 1692 { 1693 PK11GenericObject *nextObject; 1694 PK11GenericObject *prevObject; 1695 1696 if (objects == NULL) { 1697 return SECSuccess; 1698 } 1699 1700 nextObject = objects->next; 1701 prevObject = objects->prev; 1702 1703 /* delete all the objects after it in the list */ 1704 for (; objects; objects = nextObject) { 1705 nextObject = objects->next; 1706 PK11_DestroyGenericObject(objects); 1707 } 1708 /* delete all the objects before it in the list */ 1709 for (objects = prevObject; objects; objects = prevObject) { 1710 prevObject = objects->prev; 1711 PK11_DestroyGenericObject(objects); 1712 } 1713 return SECSuccess; 1714 } 1715 1716 /* 1717 * Hand Create a new object and return the Generic object for our new object. 1718 */ 1719 PK11GenericObject * 1720 pk11_CreateGenericObjectHelper(PK11SlotInfo *slot, 1721 const CK_ATTRIBUTE *pTemplate, 1722 int count, PRBool token, PRBool owner) 1723 { 1724 CK_OBJECT_HANDLE objectID; 1725 PK11GenericObject *obj; 1726 CK_RV crv; 1727 1728 PK11_EnterSlotMonitor(slot); 1729 crv = PK11_CreateNewObject(slot, slot->session, pTemplate, count, 1730 token, &objectID); 1731 PK11_ExitSlotMonitor(slot); 1732 if (crv != CKR_OK) { 1733 PORT_SetError(PK11_MapError(crv)); 1734 return NULL; 1735 } 1736 1737 obj = PORT_New(PK11GenericObject); 1738 if (!obj) { 1739 /* error set by PORT_New */ 1740 return NULL; 1741 } 1742 1743 /* initialize it */ 1744 obj->slot = PK11_ReferenceSlot(slot); 1745 obj->objectID = objectID; 1746 obj->owner = owner; 1747 obj->next = NULL; 1748 obj->prev = NULL; 1749 return obj; 1750 } 1751 1752 /* This is the classic interface. Applications would call this function to 1753 * create new object that would not be destroyed later. This lead to resource 1754 * leaks (and thus memory leaks in the PKCS #11 module). To solve this we have 1755 * a new interface that automatically marks objects created on the fly to be 1756 * destroyed later. 1757 * The old interface is preserved because applications like Mozilla purposefully 1758 * leak the reference to be found later with PK11_FindGenericObjects. New 1759 * applications should use the new interface PK11_CreateManagedGenericObject */ 1760 PK11GenericObject * 1761 PK11_CreateGenericObject(PK11SlotInfo *slot, const CK_ATTRIBUTE *pTemplate, 1762 int count, PRBool token) 1763 { 1764 return pk11_CreateGenericObjectHelper(slot, pTemplate, count, token, 1765 PR_FALSE); 1766 } 1767 1768 /* Use this interface. It will automatically destroy any temporary objects 1769 * (token = PR_FALSE) when the PK11GenericObject is freed. Permanent objects still 1770 * need to be destroyed by hand with PK11_DestroyTokenObject. 1771 */ 1772 PK11GenericObject * 1773 PK11_CreateManagedGenericObject(PK11SlotInfo *slot, 1774 const CK_ATTRIBUTE *pTemplate, int count, PRBool token) 1775 { 1776 return pk11_CreateGenericObjectHelper(slot, pTemplate, count, token, 1777 !token); 1778 } 1779 1780 CK_OBJECT_HANDLE 1781 PK11_GetObjectHandle(PK11ObjectType objType, void *objSpec, 1782 PK11SlotInfo **slotp) 1783 { 1784 CK_OBJECT_HANDLE handle = CK_INVALID_HANDLE; 1785 PK11SlotInfo *slot = NULL; 1786 1787 switch (objType) { 1788 case PK11_TypeGeneric: 1789 slot = ((PK11GenericObject *)objSpec)->slot; 1790 handle = ((PK11GenericObject *)objSpec)->objectID; 1791 break; 1792 case PK11_TypePrivKey: 1793 slot = ((SECKEYPrivateKey *)objSpec)->pkcs11Slot; 1794 handle = ((SECKEYPrivateKey *)objSpec)->pkcs11ID; 1795 break; 1796 case PK11_TypePubKey: 1797 slot = ((SECKEYPublicKey *)objSpec)->pkcs11Slot; 1798 handle = ((SECKEYPublicKey *)objSpec)->pkcs11ID; 1799 break; 1800 case PK11_TypeSymKey: 1801 slot = ((PK11SymKey *)objSpec)->slot; 1802 handle = ((PK11SymKey *)objSpec)->objectID; 1803 break; 1804 case PK11_TypeCert: 1805 handle = PK11_FindObjectForCert((CERTCertificate *)objSpec, NULL, 1806 &slot); 1807 break; 1808 default: 1809 PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE); 1810 break; 1811 } 1812 if (slotp) { 1813 *slotp = slot; 1814 } 1815 /* paranoia. If the object doesn't have a slot, then it's handle isn't 1816 * valid either */ 1817 if (slot == NULL) { 1818 handle = CK_INVALID_HANDLE; 1819 } 1820 return handle; 1821 } 1822 1823 /* 1824 * Change an attribute on a raw object 1825 */ 1826 SECStatus 1827 PK11_WriteRawAttribute(PK11ObjectType objType, void *objSpec, 1828 CK_ATTRIBUTE_TYPE attrType, SECItem *item) 1829 { 1830 PK11SlotInfo *slot = NULL; 1831 CK_OBJECT_HANDLE handle = 0; 1832 CK_ATTRIBUTE setTemplate; 1833 CK_RV crv; 1834 CK_SESSION_HANDLE rwsession; 1835 1836 handle = PK11_GetObjectHandle(objType, objSpec, &slot); 1837 if (handle == CK_INVALID_HANDLE) { 1838 PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE); 1839 return SECFailure; 1840 } 1841 1842 PK11_SETATTRS(&setTemplate, attrType, (CK_CHAR *)item->data, item->len); 1843 rwsession = PK11_GetRWSession(slot); 1844 if (rwsession == CK_INVALID_HANDLE) { 1845 PORT_SetError(SEC_ERROR_BAD_DATA); 1846 return SECFailure; 1847 } 1848 crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, handle, 1849 &setTemplate, 1); 1850 PK11_RestoreROSession(slot, rwsession); 1851 if (crv != CKR_OK) { 1852 PORT_SetError(PK11_MapError(crv)); 1853 return SECFailure; 1854 } 1855 return SECSuccess; 1856 } 1857 1858 SECStatus 1859 PK11_ReadRawAttribute(PK11ObjectType objType, void *objSpec, 1860 CK_ATTRIBUTE_TYPE attrType, SECItem *item) 1861 { 1862 PK11SlotInfo *slot = NULL; 1863 CK_OBJECT_HANDLE handle = 0; 1864 1865 handle = PK11_GetObjectHandle(objType, objSpec, &slot); 1866 if (handle == CK_INVALID_HANDLE) { 1867 PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE); 1868 return SECFailure; 1869 } 1870 1871 return PK11_ReadAttribute(slot, handle, attrType, NULL, item); 1872 } 1873 1874 SECStatus 1875 PK11_ReadRawAttributes(PLArenaPool *arena, PK11ObjectType objType, void *objSpec, 1876 CK_ATTRIBUTE *pTemplate, unsigned int count) 1877 { 1878 PK11SlotInfo *slot = NULL; 1879 CK_OBJECT_HANDLE handle = 0; 1880 1881 handle = PK11_GetObjectHandle(objType, objSpec, &slot); 1882 if (handle == CK_INVALID_HANDLE) { 1883 PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE); 1884 return SECFailure; 1885 } 1886 CK_RV crv = PK11_GetAttributes(arena, slot, handle, pTemplate, count); 1887 if (crv != CKR_OK) { 1888 PORT_SetError(PK11_MapError(crv)); 1889 return SECFailure; 1890 } 1891 return SECSuccess; 1892 } 1893 1894 SECStatus 1895 PK11_ReadDistrustAfterAttribute(PK11SlotInfo *slot, 1896 CK_OBJECT_HANDLE object, 1897 CK_ATTRIBUTE_TYPE type, 1898 /* out */ PRBool *distrusted, 1899 /* out */ PRTime *time) 1900 { 1901 if (!slot || !distrusted || !time) { 1902 PORT_SetError(SEC_ERROR_INVALID_ARGS); 1903 return SECFailure; 1904 } 1905 1906 if (type != CKA_NSS_SERVER_DISTRUST_AFTER && type != CKA_NSS_EMAIL_DISTRUST_AFTER) { 1907 PORT_SetError(SEC_ERROR_INVALID_ARGS); 1908 return SECFailure; 1909 } 1910 1911 // The CKA_NSS_SERVER_DISTRUST_AFTER and CKA_NSS_EMAIL_DISTRUST_AFTER 1912 // attributes have either a 13 byte UTCTime value or a 1 byte value 1913 // (equal to 0) indicating that no distrust after date is set. 1914 unsigned char buf[13] = { 0 }; 1915 CK_ATTRIBUTE attr = { .type = type, .pValue = buf, .ulValueLen = sizeof buf }; 1916 CK_RV crv; 1917 1918 PK11_EnterSlotMonitor(slot); 1919 crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, object, &attr, 1); 1920 PK11_ExitSlotMonitor(slot); 1921 if (crv != CKR_OK) { 1922 PORT_SetError(PK11_MapError(crv)); 1923 return SECFailure; 1924 } 1925 1926 if (attr.ulValueLen == 1 && buf[0] == 0) { 1927 // The distrust after date is not set. 1928 *distrusted = PR_FALSE; 1929 return SECSuccess; 1930 } 1931 1932 if (attr.ulValueLen != sizeof buf) { 1933 // Ensure the date is encoded in the expected 13 byte format. 1934 PORT_SetError(SEC_ERROR_INVALID_TIME); 1935 return SECFailure; 1936 } 1937 1938 *distrusted = PR_TRUE; 1939 SECItem item = { siUTCTime, buf, sizeof buf }; 1940 return DER_UTCTimeToTime(time, &item); 1941 } 1942 1943 /* 1944 * return the object handle that matches the template 1945 */ 1946 CK_OBJECT_HANDLE 1947 pk11_FindObjectByTemplate(PK11SlotInfo *slot, CK_ATTRIBUTE *theTemplate, size_t tsize) 1948 { 1949 CK_OBJECT_HANDLE object; 1950 CK_RV crv = CKR_SESSION_HANDLE_INVALID; 1951 CK_ULONG objectCount; 1952 1953 /* 1954 * issue the find 1955 */ 1956 PK11_EnterSlotMonitor(slot); 1957 if (slot->session != CK_INVALID_HANDLE) { 1958 crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, 1959 theTemplate, tsize); 1960 } 1961 if (crv != CKR_OK) { 1962 PK11_ExitSlotMonitor(slot); 1963 PORT_SetError(PK11_MapError(crv)); 1964 return CK_INVALID_HANDLE; 1965 } 1966 1967 crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, &object, 1, &objectCount); 1968 PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); 1969 PK11_ExitSlotMonitor(slot); 1970 if ((crv != CKR_OK) || (objectCount < 1)) { 1971 /* shouldn't use SSL_ERROR... here */ 1972 PORT_SetError(crv != CKR_OK ? PK11_MapError(crv) : SSL_ERROR_NO_CERTIFICATE); 1973 return CK_INVALID_HANDLE; 1974 } 1975 1976 /* blow up if the PKCS #11 module returns us and invalid object handle */ 1977 PORT_Assert(object != CK_INVALID_HANDLE); 1978 return object; 1979 } 1980 1981 /* 1982 * return all the object handles that matches the template 1983 */ 1984 CK_OBJECT_HANDLE * 1985 pk11_FindObjectsByTemplate(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate, 1986 size_t templCount, int *object_count) 1987 { 1988 CK_OBJECT_HANDLE *objID = NULL; 1989 CK_ULONG returned_count = 0; 1990 PRBool owner = PR_TRUE; 1991 CK_SESSION_HANDLE session; 1992 PRBool haslock = PR_FALSE; 1993 CK_RV crv = CKR_SESSION_HANDLE_INVALID; 1994 1995 session = pk11_GetNewSession(slot, &owner); 1996 haslock = (!owner || !(slot->isThreadSafe)); 1997 if (haslock) { 1998 PK11_EnterSlotMonitor(slot); 1999 } 2000 if (session != CK_INVALID_HANDLE) { 2001 crv = PK11_GETTAB(slot)->C_FindObjectsInit(session, 2002 findTemplate, templCount); 2003 } 2004 if (crv != CKR_OK) { 2005 if (haslock) 2006 PK11_ExitSlotMonitor(slot); 2007 pk11_CloseSession(slot, session, owner); 2008 PORT_SetError(PK11_MapError(crv)); 2009 *object_count = -1; 2010 return NULL; 2011 } 2012 2013 /* 2014 * collect all the Matching Objects 2015 */ 2016 do { 2017 CK_OBJECT_HANDLE *oldObjID = objID; 2018 2019 if (objID == NULL) { 2020 objID = (CK_OBJECT_HANDLE *)PORT_Alloc(sizeof(CK_OBJECT_HANDLE) * 2021 (*object_count + PK11_SEARCH_CHUNKSIZE)); 2022 } else { 2023 objID = (CK_OBJECT_HANDLE *)PORT_Realloc(objID, 2024 sizeof(CK_OBJECT_HANDLE) * (*object_count + PK11_SEARCH_CHUNKSIZE)); 2025 } 2026 2027 if (objID == NULL) { 2028 if (oldObjID) 2029 PORT_Free(oldObjID); 2030 break; 2031 } 2032 crv = PK11_GETTAB(slot)->C_FindObjects(session, 2033 &objID[*object_count], PK11_SEARCH_CHUNKSIZE, &returned_count); 2034 if (crv != CKR_OK) { 2035 PORT_SetError(PK11_MapError(crv)); 2036 PORT_Free(objID); 2037 objID = NULL; 2038 break; 2039 } 2040 *object_count += returned_count; 2041 } while (returned_count == PK11_SEARCH_CHUNKSIZE); 2042 2043 PK11_GETTAB(slot)->C_FindObjectsFinal(session); 2044 if (haslock) { 2045 PK11_ExitSlotMonitor(slot); 2046 } 2047 pk11_CloseSession(slot, session, owner); 2048 2049 if (objID && (*object_count == 0)) { 2050 PORT_Free(objID); 2051 return NULL; 2052 } 2053 if (objID == NULL) 2054 *object_count = -1; 2055 return objID; 2056 } 2057 2058 SECStatus 2059 PK11_FindRawCertsWithSubject(PK11SlotInfo *slot, SECItem *derSubject, 2060 CERTCertificateList **results) 2061 { 2062 if (!slot || !derSubject || !results) { 2063 PORT_SetError(SEC_ERROR_INVALID_ARGS); 2064 return SECFailure; 2065 } 2066 *results = NULL; 2067 2068 // derSubject->data may be null. If so, derSubject->len must be 0. 2069 if (!derSubject->data && derSubject->len != 0) { 2070 PORT_SetError(SEC_ERROR_INVALID_ARGS); 2071 return SECFailure; 2072 } 2073 2074 CK_CERTIFICATE_TYPE ckc_x_509 = CKC_X_509; 2075 CK_OBJECT_CLASS cko_certificate = CKO_CERTIFICATE; 2076 CK_ATTRIBUTE subjectTemplate[] = { 2077 { CKA_CERTIFICATE_TYPE, &ckc_x_509, sizeof(ckc_x_509) }, 2078 { CKA_CLASS, &cko_certificate, sizeof(cko_certificate) }, 2079 { CKA_SUBJECT, derSubject->data, derSubject->len }, 2080 }; 2081 const size_t templateCount = sizeof(subjectTemplate) / sizeof(subjectTemplate[0]); 2082 int handleCount = 0; 2083 CK_OBJECT_HANDLE *handles = 2084 pk11_FindObjectsByTemplate(slot, subjectTemplate, templateCount, 2085 &handleCount); 2086 if (!handles) { 2087 // pk11_FindObjectsByTemplate indicates there was an error by setting 2088 // handleCount to -1 (and it has set an error with PORT_SetError). 2089 if (handleCount == -1) { 2090 return SECFailure; 2091 } 2092 return SECSuccess; 2093 } 2094 PORT_Assert(handleCount > 0); 2095 if (handleCount <= 0) { 2096 PORT_Free(handles); 2097 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2098 return SECFailure; 2099 } 2100 if (handleCount > INT_MAX / sizeof(SECItem)) { 2101 PORT_Free(handles); 2102 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2103 return SECFailure; 2104 } 2105 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2106 if (!arena) { 2107 PORT_Free(handles); 2108 return SECFailure; 2109 } 2110 CERTCertificateList *rawCertificates = 2111 PORT_ArenaNew(arena, CERTCertificateList); 2112 if (!rawCertificates) { 2113 PORT_Free(handles); 2114 PORT_FreeArena(arena, PR_FALSE); 2115 return SECFailure; 2116 } 2117 rawCertificates->arena = arena; 2118 rawCertificates->certs = PORT_ArenaNewArray(arena, SECItem, handleCount); 2119 if (!rawCertificates->certs) { 2120 PORT_Free(handles); 2121 PORT_FreeArena(arena, PR_FALSE); 2122 return SECFailure; 2123 } 2124 rawCertificates->len = handleCount; 2125 int handleIndex; 2126 for (handleIndex = 0; handleIndex < handleCount; handleIndex++) { 2127 SECStatus rv = 2128 PK11_ReadAttribute(slot, handles[handleIndex], CKA_VALUE, arena, 2129 &rawCertificates->certs[handleIndex]); 2130 if (rv != SECSuccess) { 2131 PORT_Free(handles); 2132 PORT_FreeArena(arena, PR_FALSE); 2133 return SECFailure; 2134 } 2135 if (!rawCertificates->certs[handleIndex].data) { 2136 PORT_Free(handles); 2137 PORT_FreeArena(arena, PR_FALSE); 2138 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 2139 return SECFailure; 2140 } 2141 } 2142 PORT_Free(handles); 2143 *results = rawCertificates; 2144 return SECSuccess; 2145 } 2146 2147 /* 2148 * given a PKCS #11 object, match it's peer based on the KeyID. searchID 2149 * is typically a privateKey or a certificate while the peer is the opposite 2150 */ 2151 CK_OBJECT_HANDLE 2152 PK11_MatchItem(PK11SlotInfo *slot, CK_OBJECT_HANDLE searchID, 2153 CK_OBJECT_CLASS matchclass) 2154 { 2155 CK_ATTRIBUTE theTemplate[] = { 2156 { CKA_ID, NULL, 0 }, 2157 { CKA_CLASS, NULL, 0 } 2158 }; 2159 /* if you change the array, change the variable below as well */ 2160 CK_ATTRIBUTE *keyclass = &theTemplate[1]; 2161 const size_t tsize = sizeof(theTemplate) / sizeof(theTemplate[0]); 2162 /* if you change the array, change the variable below as well */ 2163 CK_OBJECT_HANDLE peerID; 2164 PORTCheapArenaPool tmpArena; 2165 CK_RV crv; 2166 2167 /* now we need to create space for the public key */ 2168 PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE); 2169 2170 crv = PK11_GetAttributes(&tmpArena.arena, slot, searchID, theTemplate, tsize); 2171 if (crv != CKR_OK) { 2172 PORT_DestroyCheapArena(&tmpArena); 2173 PORT_SetError(PK11_MapError(crv)); 2174 return CK_INVALID_HANDLE; 2175 } 2176 2177 if ((theTemplate[0].ulValueLen == 0) || (theTemplate[0].ulValueLen == -1)) { 2178 PORT_DestroyCheapArena(&tmpArena); 2179 if (matchclass == CKO_CERTIFICATE) { 2180 PORT_SetError(SEC_ERROR_BAD_KEY); 2181 } else { 2182 PORT_SetError(SEC_ERROR_NO_KEY); 2183 } 2184 return CK_INVALID_HANDLE; 2185 } 2186 2187 /* 2188 * issue the find 2189 */ 2190 *(CK_OBJECT_CLASS *)(keyclass->pValue) = matchclass; 2191 2192 peerID = pk11_FindObjectByTemplate(slot, theTemplate, tsize); 2193 PORT_DestroyCheapArena(&tmpArena); 2194 2195 return peerID; 2196 } 2197 2198 /* 2199 * count the number of objects that match the template. 2200 */ 2201 int 2202 PK11_NumberObjectsFor(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate, 2203 int templCount) 2204 { 2205 CK_OBJECT_HANDLE objID[PK11_SEARCH_CHUNKSIZE]; 2206 int object_count = 0; 2207 CK_ULONG returned_count = 0; 2208 CK_RV crv = CKR_SESSION_HANDLE_INVALID; 2209 2210 PK11_EnterSlotMonitor(slot); 2211 if (slot->session != CK_INVALID_HANDLE) { 2212 crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, 2213 findTemplate, templCount); 2214 } 2215 if (crv != CKR_OK) { 2216 PK11_ExitSlotMonitor(slot); 2217 PORT_SetError(PK11_MapError(crv)); 2218 return object_count; 2219 } 2220 2221 /* 2222 * collect all the Matching Objects 2223 */ 2224 do { 2225 crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, objID, 2226 PK11_SEARCH_CHUNKSIZE, 2227 &returned_count); 2228 if (crv != CKR_OK) { 2229 PORT_SetError(PK11_MapError(crv)); 2230 break; 2231 } 2232 object_count += returned_count; 2233 } while (returned_count == PK11_SEARCH_CHUNKSIZE); 2234 2235 PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); 2236 PK11_ExitSlotMonitor(slot); 2237 return object_count; 2238 } 2239 2240 /* 2241 * Traverse all the objects in a given slot. 2242 */ 2243 SECStatus 2244 PK11_TraverseSlot(PK11SlotInfo *slot, void *arg) 2245 { 2246 int i; 2247 CK_OBJECT_HANDLE *objID = NULL; 2248 int object_count = 0; 2249 pk11TraverseSlot *slotcb = (pk11TraverseSlot *)arg; 2250 2251 objID = pk11_FindObjectsByTemplate(slot, slotcb->findTemplate, 2252 slotcb->templateCount, &object_count); 2253 2254 /*Actually this isn't a failure... there just were no objs to be found*/ 2255 if (object_count == 0) { 2256 return SECSuccess; 2257 } 2258 2259 if (objID == NULL) { 2260 return SECFailure; 2261 } 2262 2263 for (i = 0; i < object_count; i++) { 2264 (*slotcb->callback)(slot, objID[i], slotcb->callbackArg); 2265 } 2266 PORT_Free(objID); 2267 return SECSuccess; 2268 } 2269 2270 /* 2271 * Traverse all the objects in all slots. 2272 */ 2273 SECStatus 2274 pk11_TraverseAllSlots(SECStatus (*callback)(PK11SlotInfo *, void *), 2275 void *arg, PRBool forceLogin, void *wincx) 2276 { 2277 PK11SlotList *list; 2278 PK11SlotListElement *le; 2279 SECStatus rv; 2280 2281 /* get them all! */ 2282 list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, wincx); 2283 if (list == NULL) 2284 return SECFailure; 2285 2286 /* look at each slot and authenticate as necessary */ 2287 for (le = list->head; le; le = le->next) { 2288 if (forceLogin) { 2289 rv = pk11_AuthenticateUnfriendly(le->slot, PR_FALSE, wincx); 2290 if (rv != SECSuccess) { 2291 continue; 2292 } 2293 } 2294 if (callback) { 2295 (*callback)(le->slot, arg); 2296 } 2297 } 2298 2299 PK11_FreeSlotList(list); 2300 2301 return SECSuccess; 2302 } 2303 2304 CK_OBJECT_HANDLE * 2305 PK11_FindObjectsFromNickname(char *nickname, PK11SlotInfo **slotptr, 2306 CK_OBJECT_CLASS objclass, int *returnCount, void *wincx) 2307 { 2308 char *tokenName; 2309 char *delimit; 2310 PK11SlotInfo *slot; 2311 CK_OBJECT_HANDLE *objID; 2312 CK_ATTRIBUTE findTemplate[] = { 2313 { CKA_LABEL, NULL, 0 }, 2314 { CKA_CLASS, NULL, 0 }, 2315 }; 2316 const size_t findCount = sizeof(findTemplate) / sizeof(findTemplate[0]); 2317 SECStatus rv; 2318 PK11_SETATTRS(&findTemplate[1], CKA_CLASS, &objclass, sizeof(objclass)); 2319 2320 *slotptr = slot = NULL; 2321 *returnCount = 0; 2322 /* first find the slot associated with this nickname */ 2323 if ((delimit = PORT_Strchr(nickname, ':')) != NULL) { 2324 int len = delimit - nickname; 2325 tokenName = (char *)PORT_Alloc(len + 1); 2326 if (!tokenName) { 2327 return CK_INVALID_HANDLE; 2328 } 2329 PORT_Memcpy(tokenName, nickname, len); 2330 tokenName[len] = 0; 2331 2332 slot = *slotptr = PK11_FindSlotByName(tokenName); 2333 PORT_Free(tokenName); 2334 /* if we couldn't find a slot, assume the nickname is an internal cert 2335 * with no proceding slot name */ 2336 if (slot == NULL) { 2337 slot = *slotptr = PK11_GetInternalKeySlot(); 2338 } else { 2339 nickname = delimit + 1; 2340 } 2341 } else { 2342 *slotptr = slot = PK11_GetInternalKeySlot(); 2343 } 2344 if (slot == NULL) { 2345 return CK_INVALID_HANDLE; 2346 } 2347 2348 rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx); 2349 if (rv != SECSuccess) { 2350 PK11_FreeSlot(slot); 2351 *slotptr = NULL; 2352 return CK_INVALID_HANDLE; 2353 } 2354 2355 findTemplate[0].pValue = nickname; 2356 findTemplate[0].ulValueLen = PORT_Strlen(nickname); 2357 objID = pk11_FindObjectsByTemplate(slot, findTemplate, findCount, returnCount); 2358 if (objID == NULL) { 2359 /* PKCS #11 isn't clear on whether or not the NULL is 2360 * stored in the template.... try the find again with the 2361 * full null terminated string. */ 2362 findTemplate[0].ulValueLen += 1; 2363 objID = pk11_FindObjectsByTemplate(slot, findTemplate, findCount, 2364 returnCount); 2365 if (objID == NULL) { 2366 /* Well that's the best we can do. It's just not here */ 2367 /* what about faked nicknames? */ 2368 PK11_FreeSlot(slot); 2369 *slotptr = NULL; 2370 *returnCount = 0; 2371 } 2372 } 2373 2374 return objID; 2375 } 2376 2377 SECItem * 2378 pk11_GetLowLevelKeyFromHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle) 2379 { 2380 CK_ATTRIBUTE theTemplate[] = { 2381 { CKA_ID, NULL, 0 }, 2382 }; 2383 int tsize = sizeof(theTemplate) / sizeof(theTemplate[0]); 2384 CK_RV crv; 2385 SECItem *item; 2386 2387 item = SECITEM_AllocItem(NULL, NULL, 0); 2388 2389 if (item == NULL) { 2390 return NULL; 2391 } 2392 2393 crv = PK11_GetAttributes(NULL, slot, handle, theTemplate, tsize); 2394 if (crv != CKR_OK) { 2395 SECITEM_FreeItem(item, PR_TRUE); 2396 PORT_SetError(PK11_MapError(crv)); 2397 return NULL; 2398 } 2399 2400 item->data = (unsigned char *)theTemplate[0].pValue; 2401 item->len = theTemplate[0].ulValueLen; 2402 2403 return item; 2404 } 2405 2406 PRBool 2407 PK11_ObjectGetFIPSStatus(PK11ObjectType objType, void *objSpec) 2408 { 2409 PK11SlotInfo *slot = NULL; 2410 CK_OBJECT_HANDLE handle = 0; 2411 2412 handle = PK11_GetObjectHandle(objType, objSpec, &slot); 2413 if (handle == CK_INVALID_HANDLE) { 2414 PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE); 2415 return PR_FALSE; 2416 } 2417 return pk11slot_GetFIPSStatus(slot, slot->session, handle, 2418 CKT_NSS_OBJECT_CHECK); 2419 }