pk11merge.c (52656B)
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 /* 6 * Merge the source token into the target token. 7 */ 8 9 #include "secmod.h" 10 #include "secmodi.h" 11 #include "secmodti.h" 12 #include "pk11pub.h" 13 #include "pk11priv.h" 14 #include "pkcs11.h" 15 #include "seccomon.h" 16 #include "secerr.h" 17 #include "keyhi.h" 18 #include "hasht.h" 19 #include "cert.h" 20 #include "certdb.h" 21 22 /************************************************************************* 23 * 24 * short utilities to aid in the merge 25 * 26 *************************************************************************/ 27 28 /* 29 * write a bunch of attributes out to an existing object. 30 */ 31 static SECStatus 32 pk11_setAttributes(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, 33 CK_ATTRIBUTE *setTemplate, CK_ULONG setTemplCount) 34 { 35 CK_RV crv; 36 CK_SESSION_HANDLE rwsession; 37 38 rwsession = PK11_GetRWSession(slot); 39 if (rwsession == CK_INVALID_HANDLE) { 40 PORT_SetError(SEC_ERROR_BAD_DATA); 41 return SECFailure; 42 } 43 crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id, 44 setTemplate, setTemplCount); 45 PK11_RestoreROSession(slot, rwsession); 46 if (crv != CKR_OK) { 47 PORT_SetError(PK11_MapError(crv)); 48 return SECFailure; 49 } 50 return SECSuccess; 51 } 52 53 /* 54 * copy a template of attributes from a source object to a target object. 55 * if target object is not given, create it. 56 */ 57 static SECStatus 58 pk11_copyAttributes(PLArenaPool *arena, 59 PK11SlotInfo *targetSlot, CK_OBJECT_HANDLE targetID, 60 PK11SlotInfo *sourceSlot, CK_OBJECT_HANDLE sourceID, 61 CK_ATTRIBUTE *copyTemplate, CK_ULONG copyTemplateCount) 62 { 63 SECStatus rv; 64 CK_ATTRIBUTE *newTemplate = NULL; 65 CK_RV crv; 66 67 crv = PK11_GetAttributes(arena, sourceSlot, sourceID, 68 copyTemplate, copyTemplateCount); 69 /* if we have missing attributes, just skip them and create the object */ 70 if (crv == CKR_ATTRIBUTE_TYPE_INVALID) { 71 CK_ULONG i, j; 72 newTemplate = PORT_NewArray(CK_ATTRIBUTE, copyTemplateCount); 73 if (!newTemplate) { 74 return SECFailure; 75 } 76 /* remove the unknown attributes. If we don't have enough attributes 77 * PK11_CreateNewObject() will fail */ 78 for (i = 0, j = 0; i < copyTemplateCount; i++) { 79 if (copyTemplate[i].ulValueLen != -1) { 80 newTemplate[j] = copyTemplate[i]; 81 j++; 82 } 83 } 84 copyTemplate = newTemplate; 85 copyTemplateCount = j; 86 crv = PK11_GetAttributes(arena, sourceSlot, sourceID, 87 copyTemplate, copyTemplateCount); 88 } 89 if (crv != CKR_OK) { 90 PORT_SetError(PK11_MapError(crv)); 91 PORT_Free(newTemplate); 92 return SECFailure; 93 } 94 if (targetID == CK_INVALID_HANDLE) { 95 /* we need to create the object */ 96 rv = PK11_CreateNewObject(targetSlot, CK_INVALID_HANDLE, 97 copyTemplate, copyTemplateCount, PR_TRUE, &targetID); 98 } else { 99 /* update the existing object with the new attributes */ 100 rv = pk11_setAttributes(targetSlot, targetID, 101 copyTemplate, copyTemplateCount); 102 } 103 if (newTemplate) { 104 PORT_Free(newTemplate); 105 } 106 return rv; 107 } 108 109 static CK_OBJECT_CLASS 110 pk11_getClassFromTemplate(CK_ATTRIBUTE *template, CK_ULONG tsize) 111 { 112 CK_ULONG i; 113 for (i = 0; i < tsize; i++) { 114 if ((template[i].type == CKA_CLASS) && 115 template[i].ulValueLen == sizeof(CK_OBJECT_CLASS)) { 116 return *(CK_OBJECT_CLASS *)template[i].pValue; 117 } 118 } 119 return CK_INVALID_HANDLE; 120 } 121 122 static void 123 pk11_setClassInTemplate(CK_ATTRIBUTE *template, CK_ULONG tsize, 124 CK_OBJECT_CLASS objClass) 125 { 126 CK_ULONG i; 127 for (i = 0; i < tsize; i++) { 128 if ((template[i].type == CKA_CLASS) && 129 template[i].ulValueLen == sizeof(objClass)) { 130 PORT_Memcpy(template[i].pValue, &objClass, sizeof(objClass)); 131 } 132 } 133 } 134 135 /* 136 * look for a matching object across tokens. 137 */ 138 static SECStatus 139 pk11_matchAcrossTokens(PLArenaPool *arena, PK11SlotInfo *targetSlot, 140 PK11SlotInfo *sourceSlot, 141 CK_ATTRIBUTE *template, CK_ULONG tsize, 142 CK_OBJECT_HANDLE id, CK_OBJECT_HANDLE *peer) 143 { 144 145 CK_RV crv; 146 CK_OBJECT_CLASS objclass = CK_INVALID_HANDLE; 147 *peer = CK_INVALID_HANDLE; 148 149 crv = PK11_GetAttributes(arena, sourceSlot, id, template, tsize); 150 if (crv != CKR_OK) { 151 PORT_SetError(PK11_MapError(crv)); 152 goto loser; 153 } 154 155 if (template[0].ulValueLen == -1) { 156 crv = CKR_ATTRIBUTE_TYPE_INVALID; 157 PORT_SetError(PK11_MapError(crv)); 158 goto loser; 159 } 160 161 /* if the source is a CKO_NSS_TRUST, first look to see if the target 162 * has a CKO_TRUST object */ 163 objclass = pk11_getClassFromTemplate(template, tsize); 164 if (objclass == CKO_NSS_TRUST) { 165 pk11_setClassInTemplate(template, tsize, CKO_TRUST); 166 objclass = CKO_TRUST; 167 } 168 169 *peer = pk11_FindObjectByTemplate(targetSlot, template, tsize); 170 /* if we coun't find a CKO_TRUST object, look for a CKO_NSS_TRUST object */ 171 if ((*peer == CK_INVALID_HANDLE && objclass == CKO_TRUST)) { 172 pk11_setClassInTemplate(template, tsize, CKO_NSS_TRUST); 173 *peer = pk11_FindObjectByTemplate(targetSlot, template, tsize); 174 } 175 return SECSuccess; 176 177 loser: 178 return SECFailure; 179 } 180 181 /* 182 * Encrypt using key and parameters 183 */ 184 SECStatus 185 pk11_encrypt(PK11SymKey *symKey, CK_MECHANISM_TYPE mechType, SECItem *param, 186 SECItem *input, SECItem **output) 187 { 188 PK11Context *ctxt = NULL; 189 SECStatus rv = SECSuccess; 190 191 if (*output) { 192 SECITEM_FreeItem(*output, PR_TRUE); 193 } 194 *output = SECITEM_AllocItem(NULL, NULL, input->len + 20 /*slop*/); 195 if (!*output) { 196 rv = SECFailure; 197 goto done; 198 } 199 200 ctxt = PK11_CreateContextBySymKey(mechType, CKA_ENCRYPT, symKey, param); 201 if (ctxt == NULL) { 202 rv = SECFailure; 203 goto done; 204 } 205 206 rv = PK11_CipherOp(ctxt, (*output)->data, 207 (int *)&((*output)->len), 208 (*output)->len, input->data, input->len); 209 210 done: 211 if (ctxt) { 212 PK11_Finalize(ctxt); 213 PK11_DestroyContext(ctxt, PR_TRUE); 214 } 215 if (rv != SECSuccess) { 216 if (*output) { 217 SECITEM_FreeItem(*output, PR_TRUE); 218 *output = NULL; 219 } 220 } 221 return rv; 222 } 223 224 /************************************************************************* 225 * 226 * Private Keys 227 * 228 *************************************************************************/ 229 230 /* 231 * Fetch the key usage based on the pkcs #11 flags 232 */ 233 unsigned int 234 pk11_getPrivateKeyUsage(PK11SlotInfo *slot, CK_OBJECT_HANDLE id) 235 { 236 unsigned int usage = 0; 237 238 if ((PK11_HasAttributeSet(slot, id, CKA_UNWRAP, PR_FALSE) || 239 PK11_HasAttributeSet(slot, id, CKA_DECRYPT, PR_FALSE))) { 240 usage |= KU_KEY_ENCIPHERMENT; 241 } 242 if (PK11_HasAttributeSet(slot, id, CKA_DERIVE, PR_FALSE)) { 243 usage |= KU_KEY_AGREEMENT; 244 } 245 if ((PK11_HasAttributeSet(slot, id, CKA_SIGN_RECOVER, PR_FALSE) || 246 PK11_HasAttributeSet(slot, id, CKA_SIGN, PR_FALSE))) { 247 usage |= KU_DIGITAL_SIGNATURE; 248 } 249 return usage; 250 } 251 252 /* 253 * merge a private key, 254 * 255 * Private keys are merged using PBE wrapped keys with a random 256 * value as the 'password'. Once the base key is moved, The remaining 257 * attributes (SUBJECT) is copied. 258 */ 259 static SECStatus 260 pk11_mergePrivateKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 261 CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) 262 { 263 SECKEYPrivateKey *sourceKey = NULL; 264 CK_OBJECT_HANDLE targetKeyID; 265 SECKEYEncryptedPrivateKeyInfo *epki = NULL; 266 char *nickname = NULL; 267 SECItem nickItem; 268 SECItem pwitem; 269 SECItem publicValue; 270 PLArenaPool *arena = NULL; 271 SECStatus rv = SECSuccess; 272 unsigned int keyUsage; 273 unsigned char randomData[SHA1_LENGTH]; 274 SECOidTag algTag = SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC; 275 CK_ATTRIBUTE privTemplate[] = { 276 { CKA_ID, NULL, 0 }, 277 { CKA_CLASS, NULL, 0 } 278 }; 279 CK_ULONG privTemplateCount = sizeof(privTemplate) / sizeof(privTemplate[0]); 280 CK_ATTRIBUTE privCopyTemplate[] = { 281 { CKA_SUBJECT, NULL, 0 } 282 }; 283 CK_ULONG privCopyTemplateCount = 284 sizeof(privCopyTemplate) / sizeof(privCopyTemplate[0]); 285 286 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 287 if (arena == NULL) { 288 rv = SECFailure; 289 goto done; 290 } 291 292 /* check to see if the key is already in the target slot */ 293 rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, privTemplate, 294 privTemplateCount, id, &targetKeyID); 295 if (rv != SECSuccess) { 296 goto done; 297 } 298 299 if (targetKeyID != CK_INVALID_HANDLE) { 300 /* match found, not an error ... */ 301 goto done; 302 } 303 304 /* get an NSS representation of our source key */ 305 sourceKey = PK11_MakePrivKey(sourceSlot, nullKey, PR_FALSE, 306 id, sourcePwArg); 307 if (sourceKey == NULL) { 308 rv = SECFailure; 309 goto done; 310 } 311 312 /* Load the private key */ 313 /* generate a random pwitem */ 314 rv = PK11_GenerateRandom(randomData, sizeof(randomData)); 315 if (rv != SECSuccess) { 316 goto done; 317 } 318 pwitem.data = randomData; 319 pwitem.len = sizeof(randomData); 320 /* fetch the private key encrypted */ 321 epki = PK11_ExportEncryptedPrivKeyInfo(sourceSlot, algTag, &pwitem, 322 sourceKey, 1, sourcePwArg); 323 if (epki == NULL) { 324 rv = SECFailure; 325 goto done; 326 } 327 nickname = PK11_GetObjectNickname(sourceSlot, id); 328 /* NULL nickanme is fine (in fact is often normal) */ 329 if (nickname) { 330 nickItem.data = (unsigned char *)nickname; 331 nickItem.len = PORT_Strlen(nickname); 332 } 333 keyUsage = pk11_getPrivateKeyUsage(sourceSlot, id); 334 /* pass in the CKA_ID */ 335 publicValue.data = privTemplate[0].pValue; 336 publicValue.len = privTemplate[0].ulValueLen; 337 rv = PK11_ImportEncryptedPrivateKeyInfo(targetSlot, epki, &pwitem, 338 nickname ? &nickItem : NULL, &publicValue, 339 PR_TRUE, PR_TRUE, sourceKey->keyType, keyUsage, 340 targetPwArg); 341 if (rv != SECSuccess) { 342 goto done; 343 } 344 345 /* make sure it made it */ 346 rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, privTemplate, 347 privTemplateCount, id, &targetKeyID); 348 if (rv != SECSuccess) { 349 goto done; 350 } 351 352 if (targetKeyID == CK_INVALID_HANDLE) { 353 /* this time the key should exist */ 354 rv = SECFailure; 355 goto done; 356 } 357 358 /* fill in remaining attributes */ 359 rv = pk11_copyAttributes(arena, targetSlot, targetKeyID, sourceSlot, id, 360 privCopyTemplate, privCopyTemplateCount); 361 done: 362 /* make sure the 'key' is cleared */ 363 PORT_Memset(randomData, 0, sizeof(randomData)); 364 if (nickname) { 365 PORT_Free(nickname); 366 } 367 if (sourceKey) { 368 SECKEY_DestroyPrivateKey(sourceKey); 369 } 370 if (epki) { 371 SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE); 372 } 373 if (arena) { 374 PORT_FreeArena(arena, PR_FALSE); 375 } 376 return rv; 377 } 378 379 /************************************************************************* 380 * 381 * Secret Keys 382 * 383 *************************************************************************/ 384 385 /* 386 * we need to find a unique CKA_ID. 387 * The basic idea is to just increment the lowest byte. 388 * This code also handles the following corner cases: 389 * 1) the single byte overflows. On overflow we increment the next byte up 390 * and so forth until we have overflowed the entire CKA_ID. 391 * 2) If we overflow the entire CKA_ID we expand it by one byte. 392 * 3) the CKA_ID is non-existent, we create a new one with one byte. 393 * This means no matter what CKA_ID is passed, the result of this function 394 * is always a new CKA_ID, and this function will never return the same 395 * CKA_ID the it has returned in the passed. 396 */ 397 static SECStatus 398 pk11_incrementID(PLArenaPool *arena, CK_ATTRIBUTE *ptemplate) 399 { 400 unsigned char *buf = ptemplate->pValue; 401 CK_ULONG len = ptemplate->ulValueLen; 402 403 if (buf == NULL || len == (CK_ULONG)-1) { 404 /* we have no valid CKAID, we'll create a basic one byte CKA_ID below */ 405 len = 0; 406 } else { 407 CK_ULONG i; 408 409 /* walk from the back to front, incrementing 410 * the CKA_ID until we no longer have a carry, 411 * or have hit the front of the id. */ 412 for (i = len; i != 0; i--) { 413 buf[i - 1]++; 414 if (buf[i - 1] != 0) { 415 /* no more carries, the increment is complete */ 416 return SECSuccess; 417 } 418 } 419 /* we've now overflowed, fall through and expand the CKA_ID by 420 * one byte */ 421 } 422 /* if we are here we've run the counter to zero (indicating an overflow). 423 * create an CKA_ID that is all zeros, but has one more zero than 424 * the previous CKA_ID */ 425 buf = PORT_ArenaZAlloc(arena, len + 1); 426 if (buf == NULL) { 427 return SECFailure; 428 } 429 ptemplate->pValue = buf; 430 ptemplate->ulValueLen = len + 1; 431 return SECSuccess; 432 } 433 434 static CK_FLAGS 435 pk11_getSecretKeyFlags(PK11SlotInfo *slot, CK_OBJECT_HANDLE id) 436 { 437 CK_FLAGS flags = 0; 438 439 if (PK11_HasAttributeSet(slot, id, CKA_UNWRAP, PR_FALSE)) { 440 flags |= CKF_UNWRAP; 441 } 442 if (PK11_HasAttributeSet(slot, id, CKA_WRAP, PR_FALSE)) { 443 flags |= CKF_WRAP; 444 } 445 if (PK11_HasAttributeSet(slot, id, CKA_ENCRYPT, PR_FALSE)) { 446 flags |= CKF_ENCRYPT; 447 } 448 if (PK11_HasAttributeSet(slot, id, CKA_DECRYPT, PR_FALSE)) { 449 flags |= CKF_DECRYPT; 450 } 451 if (PK11_HasAttributeSet(slot, id, CKA_DERIVE, PR_FALSE)) { 452 flags |= CKF_DERIVE; 453 } 454 if (PK11_HasAttributeSet(slot, id, CKA_SIGN, PR_FALSE)) { 455 flags |= CKF_SIGN; 456 } 457 if (PK11_HasAttributeSet(slot, id, CKA_SIGN_RECOVER, PR_FALSE)) { 458 flags |= CKF_SIGN_RECOVER; 459 } 460 if (PK11_HasAttributeSet(slot, id, CKA_VERIFY, PR_FALSE)) { 461 flags |= CKF_VERIFY; 462 } 463 if (PK11_HasAttributeSet(slot, id, CKA_VERIFY_RECOVER, PR_FALSE)) { 464 flags |= CKF_VERIFY_RECOVER; 465 } 466 return flags; 467 } 468 469 static const char testString[] = 470 "My Encrytion Test Data (should be at least 32 bytes long)"; 471 /* 472 * merge a secret key, 473 * 474 * Secret keys may collide by CKA_ID as we merge 2 token. If we collide 475 * on the CKA_ID, we need to make sure we are dealing with different keys. 476 * The reason for this is it is possible that we've merged this database 477 * before, and this key could have been merged already. If the keys are 478 * the same, we are done. If they are not, we need to update the CKA_ID of 479 * the source key and try again. 480 * 481 * Once we know we have a unique key to merge in, we use NSS's underlying 482 * key Move function which will do a key exchange if necessary to move 483 * the key from one token to another. Then we set the CKA_ID and additional 484 * pkcs #11 attributes. 485 */ 486 static SECStatus 487 pk11_mergeSecretKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 488 CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) 489 { 490 PK11SymKey *sourceKey = NULL; 491 PK11SymKey *targetKey = NULL; 492 SECItem *sourceOutput = NULL; 493 SECItem *targetOutput = NULL; 494 SECItem *param = NULL; 495 int blockSize; 496 SECItem input; 497 CK_OBJECT_HANDLE targetKeyID; 498 CK_FLAGS flags; 499 PLArenaPool *arena = NULL; 500 SECStatus rv = SECSuccess; 501 CK_MECHANISM_TYPE keyMechType, cryptoMechType; 502 CK_KEY_TYPE sourceKeyType, targetKeyType; 503 CK_ATTRIBUTE symTemplate[] = { 504 { CKA_ID, NULL, 0 }, 505 { CKA_CLASS, NULL, 0 } 506 }; 507 const CK_ULONG symTemplateCount = sizeof(symTemplate) / sizeof(symTemplate[0]); 508 CK_ATTRIBUTE symCopyTemplate[] = { 509 { CKA_LABEL, NULL, 0 } 510 }; 511 CK_ULONG symCopyTemplateCount = 512 sizeof(symCopyTemplate) / sizeof(symCopyTemplate[0]); 513 514 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 515 if (arena == NULL) { 516 rv = SECFailure; 517 goto done; 518 } 519 520 sourceKeyType = PK11_ReadULongAttribute(sourceSlot, id, CKA_KEY_TYPE); 521 if (sourceKeyType == (CK_ULONG)-1) { 522 rv = SECFailure; 523 goto done; 524 } 525 526 /* get the key mechanism */ 527 keyMechType = PK11_GetKeyMechanism(sourceKeyType); 528 /* get a mechanism suitable to encryption. 529 * PK11_GetKeyMechanism returns a mechanism that is unique to the key 530 * type. It tries to return encryption/decryption mechanisms, however 531 * CKM_DES3_CBC uses and abmiguous keyType, so keyMechType is returned as 532 * 'keygen' mechanism. Detect that case here */ 533 cryptoMechType = keyMechType; 534 if ((keyMechType == CKM_DES3_KEY_GEN) || 535 (keyMechType == CKM_DES2_KEY_GEN)) { 536 cryptoMechType = CKM_DES3_CBC; 537 } 538 539 sourceKey = PK11_SymKeyFromHandle(sourceSlot, NULL, PK11_OriginDerive, 540 keyMechType, id, PR_FALSE, sourcePwArg); 541 if (sourceKey == NULL) { 542 rv = SECFailure; 543 goto done; 544 } 545 546 /* check to see a key with the same CKA_ID already exists in 547 * the target slot. If it does, then we need to verify if the keys 548 * really matches. If they don't import the key with a new CKA_ID 549 * value. */ 550 rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, 551 symTemplate, symTemplateCount, id, &targetKeyID); 552 if (rv != SECSuccess) { 553 goto done; 554 } 555 556 /* set up the input test */ 557 input.data = (unsigned char *)testString; 558 blockSize = PK11_GetBlockSize(cryptoMechType, NULL); 559 if (blockSize < 0) { 560 rv = SECFailure; 561 goto done; 562 } 563 input.len = blockSize; 564 if (input.len == 0) { 565 input.len = sizeof(testString); 566 } 567 while (targetKeyID != CK_INVALID_HANDLE) { 568 /* test to see if the keys are identical */ 569 targetKeyType = PK11_ReadULongAttribute(sourceSlot, id, CKA_KEY_TYPE); 570 if (targetKeyType == sourceKeyType) { 571 /* same keyType - see if it's the same key */ 572 targetKey = PK11_SymKeyFromHandle(targetSlot, NULL, 573 PK11_OriginDerive, keyMechType, targetKeyID, PR_FALSE, 574 targetPwArg); 575 /* get a parameter if we don't already have one */ 576 if (!param) { 577 param = PK11_GenerateNewParam(cryptoMechType, sourceKey); 578 if (param == NULL) { 579 rv = SECFailure; 580 goto done; 581 } 582 } 583 /* use the source key to encrypt a reference */ 584 if (!sourceOutput) { 585 rv = pk11_encrypt(sourceKey, cryptoMechType, param, &input, 586 &sourceOutput); 587 if (rv != SECSuccess) { 588 goto done; 589 } 590 } 591 /* encrypt the reference with the target key */ 592 rv = pk11_encrypt(targetKey, cryptoMechType, param, &input, 593 &targetOutput); 594 if (rv == SECSuccess) { 595 if (SECITEM_ItemsAreEqual(sourceOutput, targetOutput)) { 596 /* they produce the same output, they must be the 597 * same key */ 598 goto done; 599 } 600 SECITEM_FreeItem(targetOutput, PR_TRUE); 601 targetOutput = NULL; 602 } 603 PK11_FreeSymKey(targetKey); 604 targetKey = NULL; 605 } 606 /* keys aren't equal, update the KEY_ID and look again */ 607 rv = pk11_incrementID(arena, &symTemplate[0]); 608 if (rv != SECSuccess) { 609 goto done; 610 } 611 targetKeyID = pk11_FindObjectByTemplate(targetSlot, 612 symTemplate, symTemplateCount); 613 } 614 615 /* we didn't find a matching key, import this one with the new 616 * CKAID */ 617 flags = pk11_getSecretKeyFlags(sourceSlot, id); 618 targetKey = PK11_MoveSymKey(targetSlot, PK11_OriginDerive, flags, PR_TRUE, 619 sourceKey); 620 if (targetKey == NULL) { 621 rv = SECFailure; 622 goto done; 623 } 624 /* set the key new CKAID */ 625 rv = pk11_setAttributes(targetSlot, targetKey->objectID, symTemplate, 1); 626 if (rv != SECSuccess) { 627 goto done; 628 } 629 630 /* fill in remaining attributes */ 631 rv = pk11_copyAttributes(arena, targetSlot, targetKey->objectID, 632 sourceSlot, id, symCopyTemplate, symCopyTemplateCount); 633 done: 634 if (sourceKey) { 635 PK11_FreeSymKey(sourceKey); 636 } 637 if (targetKey) { 638 PK11_FreeSymKey(targetKey); 639 } 640 if (sourceOutput) { 641 SECITEM_FreeItem(sourceOutput, PR_TRUE); 642 } 643 if (targetOutput) { 644 SECITEM_FreeItem(targetOutput, PR_TRUE); 645 } 646 if (param) { 647 SECITEM_FreeItem(param, PR_TRUE); 648 } 649 if (arena) { 650 PORT_FreeArena(arena, PR_FALSE); 651 } 652 return rv; 653 } 654 655 /************************************************************************* 656 * 657 * Public Keys 658 * 659 *************************************************************************/ 660 661 /* 662 * Merge public key 663 * 664 * Use the high level NSS calls to extract the public key and import it 665 * into the token. Extra attributes are then copied to the new token. 666 */ 667 static SECStatus 668 pk11_mergePublicKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 669 CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) 670 { 671 SECKEYPublicKey *sourceKey = NULL; 672 CK_OBJECT_HANDLE targetKeyID; 673 PLArenaPool *arena = NULL; 674 SECStatus rv = SECSuccess; 675 CK_ATTRIBUTE pubTemplate[] = { 676 { CKA_ID, NULL, 0 }, 677 { CKA_CLASS, NULL, 0 } 678 }; 679 CK_ULONG pubTemplateCount = sizeof(pubTemplate) / sizeof(pubTemplate[0]); 680 CK_ATTRIBUTE pubCopyTemplate[] = { 681 { CKA_ID, NULL, 0 }, 682 { CKA_LABEL, NULL, 0 }, 683 { CKA_SUBJECT, NULL, 0 } 684 }; 685 CK_ULONG pubCopyTemplateCount = 686 sizeof(pubCopyTemplate) / sizeof(pubCopyTemplate[0]); 687 688 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 689 if (arena == NULL) { 690 rv = SECFailure; 691 goto done; 692 } 693 694 /* check to see if the key is already in the target slot */ 695 rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, pubTemplate, 696 pubTemplateCount, id, &targetKeyID); 697 if (rv != SECSuccess) { 698 goto done; 699 } 700 701 /* Key is already in the target slot */ 702 if (targetKeyID != CK_INVALID_HANDLE) { 703 /* not an error ... */ 704 goto done; 705 } 706 707 /* fetch an NSS representation of the public key */ 708 sourceKey = PK11_ExtractPublicKey(sourceSlot, nullKey, id); 709 if (sourceKey == NULL) { 710 rv = SECFailure; 711 goto done; 712 } 713 714 /* load the public key into the target token. */ 715 targetKeyID = PK11_ImportPublicKey(targetSlot, sourceKey, PR_TRUE); 716 if (targetKeyID == CK_INVALID_HANDLE) { 717 rv = SECFailure; 718 goto done; 719 } 720 721 /* fill in remaining attributes */ 722 rv = pk11_copyAttributes(arena, targetSlot, targetKeyID, sourceSlot, id, 723 pubCopyTemplate, pubCopyTemplateCount); 724 725 done: 726 if (sourceKey) { 727 SECKEY_DestroyPublicKey(sourceKey); 728 } 729 if (arena) { 730 PORT_FreeArena(arena, PR_FALSE); 731 } 732 return rv; 733 } 734 735 /************************************************************************* 736 * 737 * Certificates 738 * 739 *************************************************************************/ 740 741 /* 742 * Two copies of the source code for this algorithm exist in NSS. 743 * Changes must be made in both copies. 744 * The other copy is in sftkdb_resolveConflicts() in softoken/sftkdb.c. 745 */ 746 static char * 747 pk11_IncrementNickname(char *nickname) 748 { 749 char *newNickname = NULL; 750 int end; 751 int digit; 752 int len = strlen(nickname); 753 754 /* does nickname end with " #n*" ? */ 755 for (end = len - 1; 756 end >= 2 && (digit = nickname[end]) <= '9' && digit >= '0'; 757 end--) /* just scan */ 758 ; 759 if (len >= 3 && 760 end < (len - 1) /* at least one digit */ && 761 nickname[end] == '#' && 762 nickname[end - 1] == ' ') { 763 /* Already has a suitable suffix string */ 764 } else { 765 /* ... append " #2" to the name */ 766 static const char num2[] = " #2"; 767 newNickname = PORT_Realloc(nickname, len + sizeof(num2)); 768 if (newNickname) { 769 PORT_Strcat(newNickname, num2); 770 } else { 771 PORT_Free(nickname); 772 } 773 return newNickname; 774 } 775 776 for (end = len - 1; 777 end >= 0 && (digit = nickname[end]) <= '9' && digit >= '0'; 778 end--) { 779 if (digit < '9') { 780 nickname[end]++; 781 return nickname; 782 } 783 nickname[end] = '0'; 784 } 785 786 /* we overflowed, insert a new '1' for a carry in front of the number */ 787 newNickname = PORT_Realloc(nickname, len + 2); 788 if (newNickname) { 789 newNickname[++end] = '1'; 790 PORT_Memset(&newNickname[end + 1], '0', len - end); 791 newNickname[len + 1] = 0; 792 } else { 793 PORT_Free(nickname); 794 } 795 return newNickname; 796 } 797 798 /* 799 * merge a certificate object 800 * 801 * Use the high level NSS calls to extract and import the certificate. 802 */ 803 static SECStatus 804 pk11_mergeCert(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 805 CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) 806 { 807 CERTCertificate *sourceCert = NULL; 808 CK_OBJECT_HANDLE targetCertID = CK_INVALID_HANDLE; 809 char *nickname = NULL; 810 SECStatus rv = SECSuccess; 811 PLArenaPool *arena = NULL; 812 CK_ATTRIBUTE sourceCKAID = { CKA_ID, NULL, 0 }; 813 CK_ATTRIBUTE targetCKAID = { CKA_ID, NULL, 0 }; 814 SECStatus lrv = SECSuccess; 815 int error = SEC_ERROR_LIBRARY_FAILURE; 816 817 sourceCert = PK11_MakeCertFromHandle(sourceSlot, id, NULL); 818 if (sourceCert == NULL) { 819 rv = SECFailure; 820 goto done; 821 } 822 823 nickname = PK11_GetObjectNickname(sourceSlot, id); 824 825 /* The database code will prevent nickname collisions for certs with 826 * different subjects. This code will prevent us from getting 827 * actual import errors */ 828 if (nickname) { 829 const char *tokenName = PK11_GetTokenName(targetSlot); 830 char *tokenNickname = NULL; 831 832 do { 833 tokenNickname = PR_smprintf("%s:%s", tokenName, nickname); 834 if (!tokenNickname) { 835 break; 836 } 837 if (!SEC_CertNicknameConflict(tokenNickname, 838 &sourceCert->derSubject, CERT_GetDefaultCertDB())) { 839 break; 840 } 841 nickname = pk11_IncrementNickname(nickname); 842 if (!nickname) { 843 break; 844 } 845 PR_smprintf_free(tokenNickname); 846 } while (1); 847 if (tokenNickname) { 848 PR_smprintf_free(tokenNickname); 849 } 850 } 851 852 /* see if the cert is already there */ 853 targetCertID = PK11_FindCertInSlot(targetSlot, sourceCert, targetPwArg); 854 if (targetCertID == CK_INVALID_HANDLE) { 855 /* cert doesn't exist load the cert in. */ 856 /* OK for the nickname to be NULL, not all certs have nicknames */ 857 rv = PK11_ImportCert(targetSlot, sourceCert, CK_INVALID_HANDLE, 858 nickname, PR_FALSE); 859 goto done; 860 } 861 862 /* the cert already exists, see if the nickname and/or CKA_ID need 863 * to be updated */ 864 865 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 866 if (arena == NULL) { 867 rv = SECFailure; 868 goto done; 869 } 870 871 /* does our source have a CKA_ID ? */ 872 rv = PK11_GetAttributes(arena, sourceSlot, id, &sourceCKAID, 1); 873 if (rv != SECSuccess) { 874 sourceCKAID.ulValueLen = 0; 875 } 876 877 /* if we have a source CKA_ID, see of we need to update the 878 * target's CKA_ID */ 879 if (sourceCKAID.ulValueLen != 0) { 880 rv = PK11_GetAttributes(arena, targetSlot, targetCertID, 881 &targetCKAID, 1); 882 if (rv != SECSuccess) { 883 targetCKAID.ulValueLen = 0; 884 } 885 /* if the target has no CKA_ID, update it from the source */ 886 if (targetCKAID.ulValueLen == 0) { 887 lrv = pk11_setAttributes(targetSlot, targetCertID, &sourceCKAID, 1); 888 if (lrv != SECSuccess) { 889 error = PORT_GetError(); 890 } 891 } 892 } 893 rv = SECSuccess; 894 895 /* now check if we need to update the nickname */ 896 if (nickname && *nickname) { 897 char *targetname; 898 targetname = PK11_GetObjectNickname(targetSlot, targetCertID); 899 if (!targetname || !*targetname) { 900 /* target has no nickname, or it's empty, update it */ 901 rv = PK11_SetObjectNickname(targetSlot, targetCertID, nickname); 902 } 903 if (targetname) { 904 PORT_Free(targetname); 905 } 906 } 907 908 /* restore the error code if CKA_ID failed, but nickname didn't */ 909 if ((rv == SECSuccess) && (lrv != SECSuccess)) { 910 rv = lrv; 911 PORT_SetError(error); 912 } 913 914 done: 915 if (nickname) { 916 PORT_Free(nickname); 917 } 918 if (sourceCert) { 919 CERT_DestroyCertificate(sourceCert); 920 } 921 if (arena) { 922 PORT_FreeArena(arena, PR_FALSE); 923 } 924 return rv; 925 } 926 927 /************************************************************************* 928 * 929 * Crls 930 * 931 *************************************************************************/ 932 933 /* 934 * Use the raw PKCS #11 interface to merge the CRLs. 935 * 936 * In the case where of collision, choose the newest CRL that is valid. 937 */ 938 static SECStatus 939 pk11_mergeCrl(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 940 CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) 941 { 942 CK_OBJECT_HANDLE targetCrlID; 943 PLArenaPool *arena = NULL; 944 SECStatus rv = SECSuccess; 945 CK_ATTRIBUTE crlTemplate[] = { 946 { CKA_SUBJECT, NULL, 0 }, 947 { CKA_CLASS, NULL, 0 }, 948 { CKA_NSS_KRL, NULL, 0 } 949 }; 950 CK_ULONG crlTemplateCount = sizeof(crlTemplate) / sizeof(crlTemplate[0]); 951 CK_ATTRIBUTE crlCopyTemplate[] = { 952 { CKA_CLASS, NULL, 0 }, 953 { CKA_TOKEN, NULL, 0 }, 954 { CKA_LABEL, NULL, 0 }, 955 { CKA_PRIVATE, NULL, 0 }, 956 { CKA_MODIFIABLE, NULL, 0 }, 957 { CKA_SUBJECT, NULL, 0 }, 958 { CKA_NSS_KRL, NULL, 0 }, 959 { CKA_NSS_URL, NULL, 0 }, 960 { CKA_VALUE, NULL, 0 } 961 }; 962 CK_ULONG crlCopyTemplateCount = 963 sizeof(crlCopyTemplate) / sizeof(crlCopyTemplate[0]); 964 965 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 966 if (arena == NULL) { 967 rv = SECFailure; 968 goto done; 969 } 970 /* check to see if the crl is already in the target slot */ 971 rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, crlTemplate, 972 crlTemplateCount, id, &targetCrlID); 973 if (rv != SECSuccess) { 974 goto done; 975 } 976 if (targetCrlID != CK_INVALID_HANDLE) { 977 /* we already have a CRL, check to see which is more up-to-date. */ 978 goto done; 979 } 980 981 /* load the CRL into the target token. */ 982 rv = pk11_copyAttributes(arena, targetSlot, targetCrlID, sourceSlot, id, 983 crlCopyTemplate, crlCopyTemplateCount); 984 done: 985 if (arena) { 986 PORT_FreeArena(arena, PR_FALSE); 987 } 988 return rv; 989 } 990 991 /************************************************************************* 992 * 993 * SMIME objects 994 * 995 *************************************************************************/ 996 997 /* 998 * use the raw PKCS #11 interface to merge the S/MIME records 999 */ 1000 static SECStatus 1001 pk11_mergeSmime(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 1002 CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) 1003 { 1004 CK_OBJECT_HANDLE targetSmimeID; 1005 PLArenaPool *arena = NULL; 1006 SECStatus rv = SECSuccess; 1007 CK_ATTRIBUTE smimeTemplate[] = { 1008 { CKA_SUBJECT, NULL, 0 }, 1009 { CKA_NSS_EMAIL, NULL, 0 }, 1010 { CKA_CLASS, NULL, 0 }, 1011 }; 1012 CK_ULONG smimeTemplateCount = 1013 sizeof(smimeTemplate) / sizeof(smimeTemplate[0]); 1014 CK_ATTRIBUTE smimeCopyTemplate[] = { 1015 { CKA_CLASS, NULL, 0 }, 1016 { CKA_TOKEN, NULL, 0 }, 1017 { CKA_LABEL, NULL, 0 }, 1018 { CKA_PRIVATE, NULL, 0 }, 1019 { CKA_MODIFIABLE, NULL, 0 }, 1020 { CKA_SUBJECT, NULL, 0 }, 1021 { CKA_NSS_EMAIL, NULL, 0 }, 1022 { CKA_NSS_SMIME_TIMESTAMP, NULL, 0 }, 1023 { CKA_VALUE, NULL, 0 } 1024 }; 1025 CK_ULONG smimeCopyTemplateCount = 1026 sizeof(smimeCopyTemplate) / sizeof(smimeCopyTemplate[0]); 1027 1028 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1029 if (arena == NULL) { 1030 rv = SECFailure; 1031 goto done; 1032 } 1033 /* check to see if the crl is already in the target slot */ 1034 rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, smimeTemplate, 1035 smimeTemplateCount, id, &targetSmimeID); 1036 if (rv != SECSuccess) { 1037 goto done; 1038 } 1039 if (targetSmimeID != CK_INVALID_HANDLE) { 1040 /* we already have a SMIME record */ 1041 goto done; 1042 } 1043 1044 /* load the SMime Record into the target token. */ 1045 rv = pk11_copyAttributes(arena, targetSlot, targetSmimeID, sourceSlot, id, 1046 smimeCopyTemplate, smimeCopyTemplateCount); 1047 done: 1048 if (arena) { 1049 PORT_FreeArena(arena, PR_FALSE); 1050 } 1051 return rv; 1052 } 1053 1054 /************************************************************************* 1055 * 1056 * Trust Objects 1057 * 1058 *************************************************************************/ 1059 1060 /* 1061 * decide which trust record entry wins. PR_TRUE (source) or PR_FALSE (target) 1062 */ 1063 #define USE_TARGET PR_FALSE 1064 #define USE_SOURCE PR_TRUE 1065 PRBool 1066 pk11_mergeTrustEntry(CK_ATTRIBUTE *target, CK_ATTRIBUTE *source) 1067 { 1068 CK_TRUST targetTrust = (target->ulValueLen == sizeof(CK_TRUST)) ? *(CK_TRUST *)target->pValue : CKT_TRUST_UNKNOWN; 1069 CK_TRUST sourceTrust = (source->ulValueLen == sizeof(CK_TRUST)) ? *(CK_TRUST *)source->pValue : CKT_TRUST_UNKNOWN; 1070 1071 /* 1072 * Examine a single entry and deside if the source or target version 1073 * should win out. When all the entries have been checked, if there is 1074 * any case we need to update, we will write the whole source record 1075 * to the target database. That means for each individual record. 1076 */ 1077 /* if they are identical, short cut the rest of the tests. NOTE: 1078 * if sourceTrust and targetTrust are different types, but 'identical' 1079 * then we will continue down these lists, but always select the 1080 * target anyway because we check the weak source versions first */ 1081 if (sourceTrust == targetTrust) { 1082 return USE_TARGET; /* which equates to 'do nothing' */ 1083 } 1084 1085 /* source has no idea, use the target's idea of the trust value */ 1086 if ((sourceTrust == CKT_TRUST_UNKNOWN) || (sourceTrust == CKT_NSS_TRUST_UNKNOWN)) { 1087 return USE_TARGET; 1088 } 1089 1090 /* target has no idea, use the source's idea of the trust value */ 1091 if ((targetTrust == CKT_TRUST_UNKNOWN) || (targetTrust == CKT_NSS_TRUST_UNKNOWN)) { 1092 /* source overwrites the target */ 1093 return USE_SOURCE; 1094 } 1095 1096 /* so both the target and the source have some idea of what this 1097 * trust attribute should be, and neither agree exactly. 1098 * At this point, we prefer 'hard' attributes over 'soft' ones. 1099 * 'hard' ones are CKT_TRUSTED, CKT_TRUST_ANCHOR, CKT_UNTRUTED and 1100 * their CKT_NSS equivalents. Soft ones are ones which don't change the 1101 * actual trust of the cert (CKT_TRUST_MUST_VERIFY_TRUST, 1102 * CKT_NSS_MUST_VERIFY_TRUST, and CKT_NSS_VALID_DELEGATOR). 1103 */ 1104 if ((sourceTrust == CKT_TRUST_MUST_VERIFY_TRUST) || 1105 (sourceTrust == CKT_NSS_MUST_VERIFY_TRUST) || 1106 (sourceTrust == CKT_NSS_VALID_DELEGATOR)) { 1107 1108 return USE_TARGET; 1109 } 1110 if ((targetTrust == CKT_TRUST_MUST_VERIFY_TRUST) || 1111 (targetTrust == CKT_NSS_MUST_VERIFY_TRUST) || 1112 (targetTrust == CKT_NSS_VALID_DELEGATOR)) { 1113 /* source overrites the target */ 1114 return USE_SOURCE; 1115 } 1116 1117 /* both have hard attributes, we have a conflict, let the target win. */ 1118 return USE_TARGET; 1119 } 1120 1121 /* 1122 * map the template trust value to the target class value. 1123 */ 1124 void 1125 pk11_map_trust_entry(CK_OBJECT_CLASS targetClass, CK_ATTRIBUTE *template) 1126 { 1127 CK_TRUST trust; 1128 CK_TRUST newTrust; 1129 1130 if (template->ulValueLen != sizeof(CK_TRUST)) { 1131 return; 1132 } 1133 trust = *(CK_TRUST *)template->pValue; 1134 newTrust = (targetClass == CKO_TRUST) ? CKT_TRUST_UNKNOWN 1135 : CKT_NSS_TRUST_UNKNOWN; 1136 1137 switch (trust) { 1138 case CKT_NSS_TRUSTED: 1139 case CKT_TRUSTED: 1140 newTrust = (targetClass == CKO_TRUST) ? CKT_TRUSTED 1141 : CKT_NSS_TRUSTED; 1142 break; 1143 case CKT_NSS_TRUSTED_DELEGATOR: 1144 case CKT_TRUST_ANCHOR: 1145 newTrust = (targetClass == CKO_TRUST) ? CKT_TRUST_ANCHOR 1146 : CKT_NSS_TRUSTED_DELEGATOR; 1147 break; 1148 case CKT_NSS_VALID_DELEGATOR: 1149 newTrust = (targetClass == CKO_TRUST) ? CKT_TRUST_MUST_VERIFY_TRUST 1150 : CKT_NSS_VALID_DELEGATOR; 1151 break; 1152 case CKT_NSS_MUST_VERIFY_TRUST: 1153 case CKT_TRUST_MUST_VERIFY_TRUST: 1154 newTrust = (targetClass == CKO_TRUST) ? CKT_TRUST_MUST_VERIFY_TRUST 1155 : CKT_NSS_MUST_VERIFY_TRUST; 1156 break; 1157 case CKT_NSS_NOT_TRUSTED: 1158 case CKT_NOT_TRUSTED: 1159 newTrust = (targetClass == CKO_TRUST) ? CKT_NOT_TRUSTED 1160 : CKT_NSS_NOT_TRUSTED; 1161 break; 1162 default: /* everything else is trust unknown, which we've already set */ 1163 break; 1164 } 1165 PORT_Memcpy(template->pValue, &newTrust, sizeof(newTrust)); 1166 return; 1167 } 1168 1169 /* 1170 * use the raw PKCS #11 interface to merge the S/MIME records 1171 */ 1172 static SECStatus 1173 pk11_mergeTrust(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 1174 CK_OBJECT_HANDLE id, CK_OBJECT_CLASS sourceClass, 1175 void *targetPwArg, void *sourcePwArg) 1176 { 1177 CK_OBJECT_HANDLE targetTrustID; 1178 PLArenaPool *arena = NULL; 1179 SECStatus rv = SECSuccess; 1180 int error = 0; 1181 CK_ATTRIBUTE trustTemplate[] = { 1182 { CKA_ISSUER, NULL, 0 }, 1183 { CKA_SERIAL_NUMBER, NULL, 0 }, 1184 { CKA_CLASS, NULL, 0 }, 1185 }; 1186 CK_ULONG trustTemplateCount = 1187 sizeof(trustTemplate) / sizeof(trustTemplate[0]); 1188 CK_ATTRIBUTE *trustCopyTemplate = NULL; 1189 CK_ULONG trustCopyTemplateCount = 0; 1190 CK_ATTRIBUTE nssTrustCopyTemplate[] = { 1191 { CKA_CLASS, NULL, 0 }, 1192 { CKA_TOKEN, NULL, 0 }, 1193 { CKA_LABEL, NULL, 0 }, 1194 { CKA_PRIVATE, NULL, 0 }, 1195 { CKA_MODIFIABLE, NULL, 0 }, 1196 { CKA_ISSUER, NULL, 0 }, 1197 { CKA_SERIAL_NUMBER, NULL, 0 }, 1198 { CKA_NSS_CERT_SHA1_HASH, NULL, 0 }, 1199 { CKA_NSS_CERT_MD5_HASH, NULL, 0 }, 1200 { CKA_NSS_TRUST_SERVER_AUTH, NULL, 0 }, 1201 { CKA_NSS_TRUST_CLIENT_AUTH, NULL, 0 }, 1202 { CKA_NSS_TRUST_CODE_SIGNING, NULL, 0 }, 1203 { CKA_NSS_TRUST_EMAIL_PROTECTION, NULL, 0 }, 1204 { CKA_NSS_TRUST_STEP_UP_APPROVED, NULL, 0 } 1205 }; 1206 CK_ULONG nssTrustCopyTemplateCount = PR_ARRAY_SIZE(nssTrustCopyTemplate); 1207 CK_ATTRIBUTE pkcsTrustCopyTemplate[] = { 1208 { CKA_CLASS, NULL, 0 }, 1209 { CKA_TOKEN, NULL, 0 }, 1210 { CKA_LABEL, NULL, 0 }, 1211 { CKA_PRIVATE, NULL, 0 }, 1212 { CKA_MODIFIABLE, NULL, 0 }, 1213 { CKA_ISSUER, NULL, 0 }, 1214 { CKA_SERIAL_NUMBER, NULL, 0 }, 1215 { CKA_HASH_OF_CERTIFICATE, NULL, 0 }, 1216 { CKA_NAME_HASH_ALGORITHM, NULL, 0 }, 1217 { CKA_PKCS_TRUST_SERVER_AUTH, NULL, 0 }, 1218 { CKA_PKCS_TRUST_CLIENT_AUTH, NULL, 0 }, 1219 { CKA_PKCS_TRUST_CODE_SIGNING, NULL, 0 }, 1220 { CKA_PKCS_TRUST_EMAIL_PROTECTION, NULL, 0 }, 1221 }; 1222 CK_ULONG pkcsTrustCopyTemplateCount = PR_ARRAY_SIZE(pkcsTrustCopyTemplate); 1223 CK_OBJECT_CLASS targetClass; 1224 1225 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1226 if (arena == NULL) { 1227 rv = SECFailure; 1228 goto done; 1229 } 1230 /* check to see if the trust object is already in the target slot */ 1231 rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, trustTemplate, 1232 trustTemplateCount, id, &targetTrustID); 1233 if (rv != SECSuccess) { 1234 goto done; 1235 } 1236 targetClass = pk11_getClassFromTemplate(trustTemplate, trustTemplateCount); 1237 if (targetTrustID != CK_INVALID_HANDLE) { 1238 /* a matching trust record already exists, merge it in */ 1239 CK_ATTRIBUTE_TYPE nssTrustAttrs[] = { 1240 CKA_NSS_TRUST_SERVER_AUTH, CKA_NSS_TRUST_CLIENT_AUTH, 1241 CKA_NSS_TRUST_CODE_SIGNING, CKA_NSS_TRUST_EMAIL_PROTECTION, 1242 CKA_NSS_TRUST_IPSEC_TUNNEL, CKA_NSS_TRUST_TIME_STAMPING 1243 }; 1244 CK_ATTRIBUTE_TYPE pkcsTrustAttrs[] = { 1245 CKA_PKCS_TRUST_SERVER_AUTH, CKA_PKCS_TRUST_CLIENT_AUTH, 1246 CKA_PKCS_TRUST_CODE_SIGNING, CKA_PKCS_TRUST_EMAIL_PROTECTION, 1247 CKA_TRUST_IPSEC_IKE, CKA_PKCS_TRUST_TIME_STAMPING 1248 }; 1249 CK_ULONG trustAttrsCount = PR_ARRAY_SIZE(pkcsTrustAttrs); 1250 1251 CK_ULONG i; 1252 CK_ATTRIBUTE targetTemplate, sourceTemplate; 1253 1254 PORT_Assert(trustAttrsCount == PR_ARRAY_SIZE(nssTrustAttrs)); 1255 1256 /* existing trust record, merge the two together */ 1257 for (i = 0; i < trustAttrsCount; i++) { 1258 targetTemplate.type = (targetClass == CKO_TRUST) 1259 ? nssTrustAttrs[i] 1260 : pkcsTrustAttrs[i]; 1261 sourceTemplate.type = (sourceClass == CKO_TRUST) 1262 ? nssTrustAttrs[i] 1263 : pkcsTrustAttrs[i]; 1264 1265 targetTemplate.pValue = sourceTemplate.pValue = NULL; 1266 targetTemplate.ulValueLen = sourceTemplate.ulValueLen = 0; 1267 PK11_GetAttributes(arena, sourceSlot, id, &sourceTemplate, 1); 1268 PK11_GetAttributes(arena, targetSlot, targetTrustID, 1269 &targetTemplate, 1); 1270 if (pk11_mergeTrustEntry(&targetTemplate, &sourceTemplate)) { 1271 /* source wins, write out the source attribute to the target */ 1272 SECStatus lrv; 1273 1274 /* store the trust value in the target's object format */ 1275 if (sourceClass != targetClass) { 1276 pk11_map_trust_entry(targetClass, &sourceTemplate); 1277 } 1278 1279 lrv = pk11_setAttributes(targetSlot, targetTrustID, 1280 &sourceTemplate, 1); 1281 if (lrv != SECSuccess) { 1282 rv = SECFailure; 1283 error = PORT_GetError(); 1284 } 1285 } 1286 } 1287 1288 /* Only handle step up if both source and target are NSS Trust 1289 * objects */ 1290 if ((sourceClass == CKO_NSS_TRUST) && (targetClass == CKO_NSS_TRUST)) { 1291 /* handle step */ 1292 sourceTemplate.type = CKA_NSS_TRUST_STEP_UP_APPROVED; 1293 sourceTemplate.pValue = NULL; 1294 sourceTemplate.ulValueLen = 0; 1295 1296 /* if the source has steup set, then set it in the target */ 1297 PK11_GetAttributes(arena, sourceSlot, id, &sourceTemplate, 1); 1298 if ((sourceTemplate.ulValueLen == sizeof(CK_BBOOL)) && 1299 (sourceTemplate.pValue) && 1300 (*(CK_BBOOL *)sourceTemplate.pValue == CK_TRUE)) { 1301 SECStatus lrv = pk11_setAttributes(targetSlot, targetTrustID, 1302 &sourceTemplate, 1); 1303 if (lrv != SECSuccess) { 1304 rv = SECFailure; 1305 error = PORT_GetError(); 1306 } 1307 } 1308 } 1309 1310 goto done; 1311 } 1312 1313 /* load the new trust Record into the target token. */ 1314 trustCopyTemplate = (sourceClass == CKO_TRUST) ? pkcsTrustCopyTemplate 1315 : nssTrustCopyTemplate; 1316 trustCopyTemplateCount = (sourceClass == CKO_TRUST) 1317 ? pkcsTrustCopyTemplateCount 1318 : nssTrustCopyTemplateCount; 1319 rv = pk11_copyAttributes(arena, targetSlot, targetTrustID, sourceSlot, id, 1320 trustCopyTemplate, trustCopyTemplateCount); 1321 done: 1322 if (arena) { 1323 PORT_FreeArena(arena, PR_FALSE); 1324 } 1325 1326 /* restore the error code */ 1327 if (rv == SECFailure && error) { 1328 PORT_SetError(error); 1329 } 1330 1331 return rv; 1332 } 1333 1334 /************************************************************************* 1335 * 1336 * Central merge code 1337 * 1338 *************************************************************************/ 1339 /* 1340 * merge a single object from sourceToken to targetToken 1341 */ 1342 static SECStatus 1343 pk11_mergeObject(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 1344 CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) 1345 { 1346 1347 CK_OBJECT_CLASS objClass; 1348 1349 objClass = PK11_ReadULongAttribute(sourceSlot, id, CKA_CLASS); 1350 if (objClass == (CK_ULONG)-1) { 1351 PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE); 1352 return SECFailure; 1353 } 1354 1355 switch (objClass) { 1356 case CKO_CERTIFICATE: 1357 return pk11_mergeCert(targetSlot, sourceSlot, id, 1358 targetPwArg, sourcePwArg); 1359 case CKO_NSS_TRUST: 1360 case CKO_TRUST: 1361 return pk11_mergeTrust(targetSlot, sourceSlot, id, 1362 objClass, targetPwArg, sourcePwArg); 1363 case CKO_PUBLIC_KEY: 1364 return pk11_mergePublicKey(targetSlot, sourceSlot, id, 1365 targetPwArg, sourcePwArg); 1366 case CKO_PRIVATE_KEY: 1367 return pk11_mergePrivateKey(targetSlot, sourceSlot, id, 1368 targetPwArg, sourcePwArg); 1369 case CKO_SECRET_KEY: 1370 return pk11_mergeSecretKey(targetSlot, sourceSlot, id, 1371 targetPwArg, sourcePwArg); 1372 case CKO_NSS_CRL: 1373 return pk11_mergeCrl(targetSlot, sourceSlot, id, 1374 targetPwArg, sourcePwArg); 1375 case CKO_NSS_SMIME: 1376 return pk11_mergeSmime(targetSlot, sourceSlot, id, 1377 targetPwArg, sourcePwArg); 1378 default: 1379 break; 1380 } 1381 1382 PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE); 1383 return SECFailure; 1384 } 1385 1386 PK11MergeLogNode * 1387 pk11_newMergeLogNode(PLArenaPool *arena, 1388 PK11SlotInfo *slot, CK_OBJECT_HANDLE id, int error) 1389 { 1390 PK11MergeLogNode *newLog; 1391 PK11GenericObject *obj; 1392 1393 newLog = PORT_ArenaZNew(arena, PK11MergeLogNode); 1394 if (newLog == NULL) { 1395 return NULL; 1396 } 1397 1398 obj = PORT_ArenaZNew(arena, PK11GenericObject); 1399 if (!obj) { 1400 return NULL; 1401 } 1402 1403 /* initialize it */ 1404 obj->slot = slot; 1405 obj->objectID = id; 1406 obj->owner = PR_FALSE; 1407 1408 newLog->object = obj; 1409 newLog->error = error; 1410 return newLog; 1411 } 1412 1413 /* 1414 * walk down each entry and merge it. keep track of the errors in the log 1415 */ 1416 static SECStatus 1417 pk11_mergeByObjectIDs(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 1418 CK_OBJECT_HANDLE *objectIDs, int count, 1419 PK11MergeLog *log, void *targetPwArg, void *sourcePwArg) 1420 { 1421 SECStatus rv = SECSuccess; 1422 int error = SEC_ERROR_LIBRARY_FAILURE; 1423 int i; 1424 1425 for (i = 0; i < count; i++) { 1426 /* try to update the entire database. On failure, keep going, 1427 * but remember the error to report back to the caller */ 1428 SECStatus lrv; 1429 PK11MergeLogNode *newLog; 1430 1431 lrv = pk11_mergeObject(targetSlot, sourceSlot, objectIDs[i], 1432 targetPwArg, sourcePwArg); 1433 if (lrv == SECSuccess) { 1434 /* merged with no problem, go to next object */ 1435 continue; 1436 } 1437 1438 /* remember that we failed and why */ 1439 rv = SECFailure; 1440 error = PORT_GetError(); 1441 1442 /* log the errors */ 1443 if (!log) { 1444 /* not logging, go to next entry */ 1445 continue; 1446 } 1447 newLog = pk11_newMergeLogNode(log->arena, sourceSlot, 1448 objectIDs[i], error); 1449 if (!newLog) { 1450 /* failed to allocate entry, just keep going */ 1451 continue; 1452 } 1453 1454 /* link in the errorlog entry */ 1455 newLog->next = NULL; 1456 if (log->tail) { 1457 log->tail->next = newLog; 1458 } else { 1459 log->head = newLog; 1460 } 1461 newLog->prev = log->tail; 1462 log->tail = newLog; 1463 } 1464 1465 /* restore the last error code */ 1466 if (rv != SECSuccess) { 1467 PORT_SetError(error); 1468 } 1469 return rv; 1470 } 1471 1472 /* 1473 * Merge all the records in sourceSlot that aren't in targetSlot 1474 * 1475 * This function will return failure if not all the objects 1476 * successfully merged. 1477 * 1478 * Applications can pass in an optional error log which will record 1479 * each failing object and why it failed to import. PK11MergeLog 1480 * is modelled after the CERTVerifyLog. 1481 */ 1482 SECStatus 1483 PK11_MergeTokens(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 1484 PK11MergeLog *log, void *targetPwArg, void *sourcePwArg) 1485 { 1486 SECStatus rv = SECSuccess, lrv = SECSuccess; 1487 int error = SEC_ERROR_LIBRARY_FAILURE; 1488 int count = 0; 1489 CK_ATTRIBUTE search[2]; 1490 CK_OBJECT_HANDLE *objectIDs = NULL; 1491 CK_BBOOL ck_true = CK_TRUE; 1492 CK_OBJECT_CLASS privKey = CKO_PRIVATE_KEY; 1493 1494 PK11_SETATTRS(&search[0], CKA_TOKEN, &ck_true, sizeof(ck_true)); 1495 PK11_SETATTRS(&search[1], CKA_CLASS, &privKey, sizeof(privKey)); 1496 /* 1497 * make sure both tokens are already authenticated if need be. 1498 */ 1499 rv = PK11_Authenticate(targetSlot, PR_TRUE, targetPwArg); 1500 if (rv != SECSuccess) { 1501 goto loser; 1502 } 1503 rv = PK11_Authenticate(sourceSlot, PR_TRUE, sourcePwArg); 1504 if (rv != SECSuccess) { 1505 goto loser; 1506 } 1507 1508 /* turns out the old DB's are rather fragile if the private keys aren't 1509 * merged in first, so do the private keys explicity. */ 1510 objectIDs = pk11_FindObjectsByTemplate(sourceSlot, search, 2, &count); 1511 if (objectIDs) { 1512 lrv = pk11_mergeByObjectIDs(targetSlot, sourceSlot, 1513 objectIDs, count, log, 1514 targetPwArg, sourcePwArg); 1515 if (lrv != SECSuccess) { 1516 error = PORT_GetError(); 1517 } 1518 PORT_Free(objectIDs); 1519 count = 0; 1520 } 1521 1522 /* now do the rest (NOTE: this will repeat the private keys, but 1523 * that shouldnt' be an issue as we will notice they are already 1524 * merged in */ 1525 objectIDs = pk11_FindObjectsByTemplate(sourceSlot, search, 1, &count); 1526 if (!objectIDs) { 1527 rv = SECFailure; 1528 goto loser; 1529 } 1530 1531 rv = pk11_mergeByObjectIDs(targetSlot, sourceSlot, objectIDs, count, log, 1532 targetPwArg, sourcePwArg); 1533 if (rv == SECSuccess) { 1534 /* if private keys failed, but the rest succeeded, be sure to let 1535 * the caller know that private keys failed and why. 1536 * NOTE: this is highly unlikely since the same keys that failed 1537 * in the previous merge call will most likely fail in this one */ 1538 if (lrv != SECSuccess) { 1539 rv = lrv; 1540 PORT_SetError(error); 1541 } 1542 } 1543 1544 loser: 1545 if (objectIDs) { 1546 PORT_Free(objectIDs); 1547 } 1548 return rv; 1549 } 1550 1551 PK11MergeLog * 1552 PK11_CreateMergeLog(void) 1553 { 1554 PLArenaPool *arena; 1555 PK11MergeLog *log; 1556 1557 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1558 if (arena == NULL) { 1559 return NULL; 1560 } 1561 1562 log = PORT_ArenaZNew(arena, PK11MergeLog); 1563 if (log == NULL) { 1564 PORT_FreeArena(arena, PR_FALSE); 1565 return NULL; 1566 } 1567 log->arena = arena; 1568 log->version = 1; 1569 return log; 1570 } 1571 1572 void 1573 PK11_DestroyMergeLog(PK11MergeLog *log) 1574 { 1575 if (log && log->arena) { 1576 PORT_FreeArena(log->arena, PR_FALSE); 1577 } 1578 }