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