1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/pk11wrap/pk11merge.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1419 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * Merge the source token into the target token. 1.10 + */ 1.11 + 1.12 +#include "secmod.h" 1.13 +#include "secmodi.h" 1.14 +#include "secmodti.h" 1.15 +#include "pk11pub.h" 1.16 +#include "pk11priv.h" 1.17 +#include "pkcs11.h" 1.18 +#include "seccomon.h" 1.19 +#include "secerr.h" 1.20 +#include "keyhi.h" 1.21 +#include "hasht.h" 1.22 +#include "cert.h" 1.23 +#include "certdb.h" 1.24 + 1.25 +/************************************************************************* 1.26 + * 1.27 + * short utilities to aid in the merge 1.28 + * 1.29 + *************************************************************************/ 1.30 + 1.31 +/* 1.32 + * write a bunch of attributes out to an existing object. 1.33 + */ 1.34 +static SECStatus 1.35 +pk11_setAttributes(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, 1.36 + CK_ATTRIBUTE *setTemplate, CK_ULONG setTemplCount) 1.37 +{ 1.38 + CK_RV crv; 1.39 + CK_SESSION_HANDLE rwsession; 1.40 + 1.41 + rwsession = PK11_GetRWSession(slot); 1.42 + if (rwsession == CK_INVALID_SESSION) { 1.43 + PORT_SetError(SEC_ERROR_BAD_DATA); 1.44 + return SECFailure; 1.45 + } 1.46 + crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id, 1.47 + setTemplate, setTemplCount); 1.48 + PK11_RestoreROSession(slot, rwsession); 1.49 + if (crv != CKR_OK) { 1.50 + PORT_SetError(PK11_MapError(crv)); 1.51 + return SECFailure; 1.52 + } 1.53 + return SECSuccess; 1.54 +} 1.55 + 1.56 + 1.57 +/* 1.58 + * copy a template of attributes from a source object to a target object. 1.59 + * if target object is not given, create it. 1.60 + */ 1.61 +static SECStatus 1.62 +pk11_copyAttributes(PLArenaPool *arena, 1.63 + PK11SlotInfo *targetSlot, CK_OBJECT_HANDLE targetID, 1.64 + PK11SlotInfo *sourceSlot, CK_OBJECT_HANDLE sourceID, 1.65 + CK_ATTRIBUTE *copyTemplate, CK_ULONG copyTemplateCount) 1.66 +{ 1.67 + SECStatus rv = PK11_GetAttributes(arena, sourceSlot, sourceID, 1.68 + copyTemplate, copyTemplateCount); 1.69 + if (rv != SECSuccess) { 1.70 + return rv; 1.71 + } 1.72 + if (targetID == CK_INVALID_HANDLE) { 1.73 + /* we need to create the object */ 1.74 + rv = PK11_CreateNewObject(targetSlot, CK_INVALID_SESSION, 1.75 + copyTemplate, copyTemplateCount, PR_TRUE, &targetID); 1.76 + } else { 1.77 + /* update the existing object with the new attributes */ 1.78 + rv = pk11_setAttributes(targetSlot, targetID, 1.79 + copyTemplate, copyTemplateCount); 1.80 + } 1.81 + return rv; 1.82 +} 1.83 + 1.84 +/* 1.85 + * look for a matching object across tokens. 1.86 + */ 1.87 +static SECStatus 1.88 +pk11_matchAcrossTokens(PLArenaPool *arena, PK11SlotInfo *targetSlot, 1.89 + PK11SlotInfo *sourceSlot, 1.90 + CK_ATTRIBUTE *template, CK_ULONG tsize, 1.91 + CK_OBJECT_HANDLE id, CK_OBJECT_HANDLE *peer) 1.92 +{ 1.93 + 1.94 + CK_RV crv; 1.95 + *peer = CK_INVALID_HANDLE; 1.96 + 1.97 + crv = PK11_GetAttributes(arena, sourceSlot, id, template, tsize); 1.98 + if (crv != CKR_OK) { 1.99 + PORT_SetError( PK11_MapError(crv) ); 1.100 + goto loser; 1.101 + } 1.102 + 1.103 + if (template[0].ulValueLen == -1) { 1.104 + crv = CKR_ATTRIBUTE_TYPE_INVALID; 1.105 + PORT_SetError( PK11_MapError(crv) ); 1.106 + goto loser; 1.107 + } 1.108 + 1.109 + *peer = pk11_FindObjectByTemplate(targetSlot, template, tsize); 1.110 + return SECSuccess; 1.111 + 1.112 +loser: 1.113 + return SECFailure; 1.114 +} 1.115 + 1.116 +/* 1.117 + * Encrypt using key and parameters 1.118 + */ 1.119 +SECStatus 1.120 +pk11_encrypt(PK11SymKey *symKey, CK_MECHANISM_TYPE mechType, SECItem *param, 1.121 + SECItem *input, SECItem **output) 1.122 +{ 1.123 + PK11Context *ctxt = NULL; 1.124 + SECStatus rv = SECSuccess; 1.125 + 1.126 + if (*output) { 1.127 + SECITEM_FreeItem(*output,PR_TRUE); 1.128 + } 1.129 + *output = SECITEM_AllocItem(NULL, NULL, input->len+20 /*slop*/); 1.130 + if (!*output) { 1.131 + rv = SECFailure; 1.132 + goto done; 1.133 + } 1.134 + 1.135 + ctxt = PK11_CreateContextBySymKey(mechType, CKA_ENCRYPT, symKey, param); 1.136 + if (ctxt == NULL) { 1.137 + rv = SECFailure; 1.138 + goto done; 1.139 + } 1.140 + 1.141 + rv = PK11_CipherOp(ctxt, (*output)->data, 1.142 + (int *)&((*output)->len), 1.143 + (*output)->len, input->data, input->len); 1.144 + 1.145 +done: 1.146 + if (ctxt) { 1.147 + PK11_Finalize(ctxt); 1.148 + PK11_DestroyContext(ctxt,PR_TRUE); 1.149 + } 1.150 + if (rv != SECSuccess) { 1.151 + if (*output) { 1.152 + SECITEM_FreeItem(*output, PR_TRUE); 1.153 + *output = NULL; 1.154 + } 1.155 + } 1.156 + return rv; 1.157 +} 1.158 + 1.159 + 1.160 + 1.161 +/************************************************************************* 1.162 + * 1.163 + * Private Keys 1.164 + * 1.165 + *************************************************************************/ 1.166 + 1.167 +/* 1.168 + * Fetch the key usage based on the pkcs #11 flags 1.169 + */ 1.170 +unsigned int 1.171 +pk11_getPrivateKeyUsage(PK11SlotInfo *slot, CK_OBJECT_HANDLE id) 1.172 +{ 1.173 + unsigned int usage = 0; 1.174 + 1.175 + if ((PK11_HasAttributeSet(slot, id, CKA_UNWRAP,PR_FALSE) || 1.176 + PK11_HasAttributeSet(slot,id, CKA_DECRYPT,PR_FALSE))) { 1.177 + usage |= KU_KEY_ENCIPHERMENT; 1.178 + } 1.179 + if (PK11_HasAttributeSet(slot, id, CKA_DERIVE, PR_FALSE)) { 1.180 + usage |= KU_KEY_AGREEMENT; 1.181 + } 1.182 + if ((PK11_HasAttributeSet(slot, id, CKA_SIGN_RECOVER, PR_FALSE) || 1.183 + PK11_HasAttributeSet(slot, id, CKA_SIGN, PR_FALSE))) { 1.184 + usage |= KU_DIGITAL_SIGNATURE; 1.185 + } 1.186 + return usage; 1.187 +} 1.188 + 1.189 + 1.190 +/* 1.191 + * merge a private key, 1.192 + * 1.193 + * Private keys are merged using PBE wrapped keys with a random 1.194 + * value as the 'password'. Once the base key is moved, The remaining 1.195 + * attributes (SUBJECT) is copied. 1.196 + */ 1.197 +static SECStatus 1.198 +pk11_mergePrivateKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 1.199 + CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) 1.200 +{ 1.201 + SECKEYPrivateKey *sourceKey = NULL; 1.202 + CK_OBJECT_HANDLE targetKeyID; 1.203 + SECKEYEncryptedPrivateKeyInfo *epki = NULL; 1.204 + char *nickname = NULL; 1.205 + SECItem nickItem; 1.206 + SECItem pwitem; 1.207 + SECItem publicValue; 1.208 + PLArenaPool *arena = NULL; 1.209 + SECStatus rv = SECSuccess; 1.210 + unsigned int keyUsage; 1.211 + unsigned char randomData[SHA1_LENGTH]; 1.212 + SECOidTag algTag = SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC; 1.213 + CK_ATTRIBUTE privTemplate[] = { 1.214 + { CKA_ID, NULL, 0 }, 1.215 + { CKA_CLASS, NULL, 0 } 1.216 + }; 1.217 + CK_ULONG privTemplateCount = sizeof(privTemplate)/sizeof(privTemplate[0]); 1.218 + CK_ATTRIBUTE privCopyTemplate[] = { 1.219 + { CKA_SUBJECT, NULL, 0 } 1.220 + }; 1.221 + CK_ULONG privCopyTemplateCount = 1.222 + sizeof(privCopyTemplate)/sizeof(privCopyTemplate[0]); 1.223 + 1.224 + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); 1.225 + if (arena == NULL) { 1.226 + rv = SECFailure; 1.227 + goto done; 1.228 + } 1.229 + 1.230 + /* check to see if the key is already in the target slot */ 1.231 + rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, privTemplate, 1.232 + privTemplateCount, id, &targetKeyID); 1.233 + if (rv != SECSuccess) { 1.234 + goto done; 1.235 + } 1.236 + 1.237 + if (targetKeyID != CK_INVALID_HANDLE) { 1.238 + /* match found, not an error ... */ 1.239 + goto done; 1.240 + } 1.241 + 1.242 + /* get an NSS representation of our source key */ 1.243 + sourceKey = PK11_MakePrivKey(sourceSlot, nullKey, PR_FALSE, 1.244 + id, sourcePwArg); 1.245 + if (sourceKey == NULL) { 1.246 + rv = SECFailure; 1.247 + goto done; 1.248 + } 1.249 + 1.250 + /* Load the private key */ 1.251 + /* generate a random pwitem */ 1.252 + rv = PK11_GenerateRandom(randomData, sizeof(randomData)); 1.253 + if (rv != SECSuccess) { 1.254 + goto done; 1.255 + } 1.256 + pwitem.data = randomData; 1.257 + pwitem.len = sizeof(randomData); 1.258 + /* fetch the private key encrypted */ 1.259 + epki = PK11_ExportEncryptedPrivKeyInfo(sourceSlot, algTag, &pwitem, 1.260 + sourceKey, 1, sourcePwArg); 1.261 + if (epki == NULL) { 1.262 + rv = SECFailure; 1.263 + goto done; 1.264 + } 1.265 + nickname = PK11_GetObjectNickname(sourceSlot, id); 1.266 + /* NULL nickanme is fine (in fact is often normal) */ 1.267 + if (nickname) { 1.268 + nickItem.data = (unsigned char *)nickname; 1.269 + nickItem.len = PORT_Strlen(nickname); 1.270 + } 1.271 + keyUsage = pk11_getPrivateKeyUsage(sourceSlot, id); 1.272 + /* pass in the CKA_ID */ 1.273 + publicValue.data = privTemplate[0].pValue; 1.274 + publicValue.len = privTemplate[0].ulValueLen; 1.275 + rv = PK11_ImportEncryptedPrivateKeyInfo(targetSlot, epki, &pwitem, 1.276 + nickname? &nickItem : NULL , &publicValue, 1.277 + PR_TRUE, PR_TRUE, sourceKey->keyType, keyUsage, 1.278 + targetPwArg); 1.279 + if (rv != SECSuccess) { 1.280 + goto done; 1.281 + } 1.282 + 1.283 + /* make sure it made it */ 1.284 + rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, privTemplate, 1.285 + privTemplateCount, id, &targetKeyID); 1.286 + if (rv != SECSuccess) { 1.287 + goto done; 1.288 + } 1.289 + 1.290 + if (targetKeyID == CK_INVALID_HANDLE) { 1.291 + /* this time the key should exist */ 1.292 + rv = SECFailure; 1.293 + goto done; 1.294 + } 1.295 + 1.296 + /* fill in remaining attributes */ 1.297 + rv = pk11_copyAttributes(arena, targetSlot, targetKeyID, sourceSlot, id, 1.298 + privCopyTemplate, privCopyTemplateCount); 1.299 +done: 1.300 + /* make sure the 'key' is cleared */ 1.301 + PORT_Memset(randomData, 0, sizeof(randomData)); 1.302 + if (nickname) { 1.303 + PORT_Free(nickname); 1.304 + } 1.305 + if (sourceKey) { 1.306 + SECKEY_DestroyPrivateKey(sourceKey); 1.307 + } 1.308 + if (epki) { 1.309 + SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE); 1.310 + } 1.311 + if (arena) { 1.312 + PORT_FreeArena(arena,PR_FALSE); 1.313 + } 1.314 + return rv; 1.315 +} 1.316 + 1.317 + 1.318 +/************************************************************************* 1.319 + * 1.320 + * Secret Keys 1.321 + * 1.322 + *************************************************************************/ 1.323 + 1.324 +/* 1.325 + * we need to find a unique CKA_ID. 1.326 + * The basic idea is to just increment the lowest byte. 1.327 + * This code also handles the following corner cases: 1.328 + * 1) the single byte overflows. On overflow we increment the next byte up 1.329 + * and so forth until we have overflowed the entire CKA_ID. 1.330 + * 2) If we overflow the entire CKA_ID we expand it by one byte. 1.331 + * 3) the CKA_ID is non-existent, we create a new one with one byte. 1.332 + * This means no matter what CKA_ID is passed, the result of this function 1.333 + * is always a new CKA_ID, and this function will never return the same 1.334 + * CKA_ID the it has returned in the passed. 1.335 + */ 1.336 +static SECStatus 1.337 +pk11_incrementID(PLArenaPool *arena, CK_ATTRIBUTE *ptemplate) 1.338 +{ 1.339 + unsigned char *buf = ptemplate->pValue; 1.340 + CK_ULONG len = ptemplate->ulValueLen; 1.341 + 1.342 + if (buf == NULL || len == (CK_ULONG)-1) { 1.343 + /* we have no valid CKAID, we'll create a basic one byte CKA_ID below */ 1.344 + len = 0; 1.345 + } else { 1.346 + CK_ULONG i; 1.347 + 1.348 + /* walk from the back to front, incrementing 1.349 + * the CKA_ID until we no longer have a carry, 1.350 + * or have hit the front of the id. */ 1.351 + for (i=len; i != 0; i--) { 1.352 + buf[i-1]++; 1.353 + if (buf[i-1] != 0) { 1.354 + /* no more carries, the increment is complete */ 1.355 + return SECSuccess; 1.356 + } 1.357 + } 1.358 + /* we've now overflowed, fall through and expand the CKA_ID by 1.359 + * one byte */ 1.360 + } 1.361 + /* if we are here we've run the counter to zero (indicating an overflow). 1.362 + * create an CKA_ID that is all zeros, but has one more zero than 1.363 + * the previous CKA_ID */ 1.364 + buf = PORT_ArenaZAlloc(arena, len+1); 1.365 + if (buf == NULL) { 1.366 + return SECFailure; 1.367 + } 1.368 + ptemplate->pValue = buf; 1.369 + ptemplate->ulValueLen = len+1; 1.370 + return SECSuccess; 1.371 +} 1.372 + 1.373 + 1.374 +static CK_FLAGS 1.375 +pk11_getSecretKeyFlags(PK11SlotInfo *slot, CK_OBJECT_HANDLE id) 1.376 +{ 1.377 + CK_FLAGS flags = 0; 1.378 + 1.379 + if (PK11_HasAttributeSet(slot, id, CKA_UNWRAP, PR_FALSE)) { 1.380 + flags |= CKF_UNWRAP; 1.381 + } 1.382 + if (PK11_HasAttributeSet(slot, id, CKA_WRAP, PR_FALSE)) { 1.383 + flags |= CKF_WRAP; 1.384 + } 1.385 + if (PK11_HasAttributeSet(slot, id, CKA_ENCRYPT, PR_FALSE)) { 1.386 + flags |= CKF_ENCRYPT; 1.387 + } 1.388 + if (PK11_HasAttributeSet(slot, id, CKA_DECRYPT, PR_FALSE)) { 1.389 + flags |= CKF_DECRYPT; 1.390 + } 1.391 + if (PK11_HasAttributeSet(slot, id, CKA_DERIVE, PR_FALSE)) { 1.392 + flags |= CKF_DERIVE; 1.393 + } 1.394 + if (PK11_HasAttributeSet(slot, id, CKA_SIGN, PR_FALSE)) { 1.395 + flags |= CKF_SIGN; 1.396 + } 1.397 + if (PK11_HasAttributeSet(slot, id, CKA_SIGN_RECOVER, PR_FALSE)) { 1.398 + flags |= CKF_SIGN_RECOVER; 1.399 + } 1.400 + if (PK11_HasAttributeSet(slot, id, CKA_VERIFY, PR_FALSE)) { 1.401 + flags |= CKF_VERIFY; 1.402 + } 1.403 + if (PK11_HasAttributeSet(slot, id, CKA_VERIFY_RECOVER, PR_FALSE)) { 1.404 + flags |= CKF_VERIFY_RECOVER; 1.405 + } 1.406 + return flags; 1.407 +} 1.408 + 1.409 +static const char testString[] = 1.410 + "My Encrytion Test Data (should be at least 32 bytes long)"; 1.411 +/* 1.412 + * merge a secret key, 1.413 + * 1.414 + * Secret keys may collide by CKA_ID as we merge 2 token. If we collide 1.415 + * on the CKA_ID, we need to make sure we are dealing with different keys. 1.416 + * The reason for this is it is possible that we've merged this database 1.417 + * before, and this key could have been merged already. If the keys are 1.418 + * the same, we are done. If they are not, we need to update the CKA_ID of 1.419 + * the source key and try again. 1.420 + * 1.421 + * Once we know we have a unique key to merge in, we use NSS's underlying 1.422 + * key Move function which will do a key exchange if necessary to move 1.423 + * the key from one token to another. Then we set the CKA_ID and additional 1.424 + * pkcs #11 attributes. 1.425 + */ 1.426 +static SECStatus 1.427 +pk11_mergeSecretKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 1.428 + CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) 1.429 +{ 1.430 + PK11SymKey *sourceKey = NULL; 1.431 + PK11SymKey *targetKey = NULL; 1.432 + SECItem *sourceOutput = NULL; 1.433 + SECItem *targetOutput = NULL; 1.434 + SECItem *param = NULL; 1.435 + int blockSize; 1.436 + SECItem input; 1.437 + CK_OBJECT_HANDLE targetKeyID; 1.438 + CK_FLAGS flags; 1.439 + PLArenaPool *arena = NULL; 1.440 + SECStatus rv = SECSuccess; 1.441 + CK_MECHANISM_TYPE keyMechType, cryptoMechType; 1.442 + CK_KEY_TYPE sourceKeyType, targetKeyType; 1.443 + CK_ATTRIBUTE symTemplate[] = { 1.444 + { CKA_ID, NULL, 0 }, 1.445 + { CKA_CLASS, NULL, 0 } 1.446 + }; 1.447 + CK_ULONG symTemplateCount = sizeof(symTemplate)/sizeof(symTemplate[0]); 1.448 + CK_ATTRIBUTE symCopyTemplate[] = { 1.449 + { CKA_LABEL, NULL, 0 } 1.450 + }; 1.451 + CK_ULONG symCopyTemplateCount = 1.452 + sizeof(symCopyTemplate)/sizeof(symCopyTemplate[0]); 1.453 + 1.454 + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); 1.455 + if (arena == NULL) { 1.456 + rv = SECFailure; 1.457 + goto done; 1.458 + } 1.459 + 1.460 + sourceKeyType = PK11_ReadULongAttribute(sourceSlot, id, CKA_KEY_TYPE); 1.461 + if (sourceKeyType == (CK_ULONG) -1) { 1.462 + rv = SECFailure; 1.463 + goto done; 1.464 + } 1.465 + 1.466 + /* get the key mechanism */ 1.467 + keyMechType = PK11_GetKeyMechanism(sourceKeyType); 1.468 + /* get a mechanism suitable to encryption. 1.469 + * PK11_GetKeyMechanism returns a mechanism that is unique to the key 1.470 + * type. It tries to return encryption/decryption mechanisms, however 1.471 + * CKM_DES3_CBC uses and abmiguous keyType, so keyMechType is returned as 1.472 + * 'keygen' mechanism. Detect that case here */ 1.473 + cryptoMechType = keyMechType; 1.474 + if ((keyMechType == CKM_DES3_KEY_GEN) || 1.475 + (keyMechType == CKM_DES2_KEY_GEN)) { 1.476 + cryptoMechType = CKM_DES3_CBC; 1.477 + } 1.478 + 1.479 + sourceKey = PK11_SymKeyFromHandle(sourceSlot, NULL, PK11_OriginDerive, 1.480 + keyMechType , id, PR_FALSE, sourcePwArg); 1.481 + if (sourceKey == NULL) { 1.482 + rv = SECFailure; 1.483 + goto done; 1.484 + } 1.485 + 1.486 + /* check to see a key with the same CKA_ID already exists in 1.487 + * the target slot. If it does, then we need to verify if the keys 1.488 + * really matches. If they don't import the key with a new CKA_ID 1.489 + * value. */ 1.490 + rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, 1.491 + symTemplate, symTemplateCount, id, &targetKeyID); 1.492 + if (rv != SECSuccess) { 1.493 + goto done; 1.494 + } 1.495 + 1.496 + /* set up the input test */ 1.497 + input.data = (unsigned char *)testString; 1.498 + blockSize = PK11_GetBlockSize(cryptoMechType, NULL); 1.499 + if (blockSize < 0) { 1.500 + rv = SECFailure; 1.501 + goto done; 1.502 + } 1.503 + input.len = blockSize; 1.504 + if (input.len == 0) { 1.505 + input.len = sizeof (testString); 1.506 + } 1.507 + while (targetKeyID != CK_INVALID_HANDLE) { 1.508 + /* test to see if the keys are identical */ 1.509 + targetKeyType = PK11_ReadULongAttribute(sourceSlot, id, CKA_KEY_TYPE); 1.510 + if (targetKeyType == sourceKeyType) { 1.511 + /* same keyType - see if it's the same key */ 1.512 + targetKey = PK11_SymKeyFromHandle(targetSlot, NULL, 1.513 + PK11_OriginDerive, keyMechType, targetKeyID, PR_FALSE, 1.514 + targetPwArg); 1.515 + /* get a parameter if we don't already have one */ 1.516 + if (!param) { 1.517 + param = PK11_GenerateNewParam(cryptoMechType, sourceKey); 1.518 + if (param == NULL) { 1.519 + rv = SECFailure; 1.520 + goto done; 1.521 + } 1.522 + } 1.523 + /* use the source key to encrypt a reference */ 1.524 + if (!sourceOutput) { 1.525 + rv = pk11_encrypt(sourceKey, cryptoMechType, param, &input, 1.526 + &sourceOutput); 1.527 + if (rv != SECSuccess) { 1.528 + goto done; 1.529 + } 1.530 + } 1.531 + /* encrypt the reference with the target key */ 1.532 + rv = pk11_encrypt(targetKey, cryptoMechType, param, &input, 1.533 + &targetOutput); 1.534 + if (rv == SECSuccess) { 1.535 + if (SECITEM_ItemsAreEqual(sourceOutput, targetOutput)) { 1.536 + /* they produce the same output, they must be the 1.537 + * same key */ 1.538 + goto done; 1.539 + } 1.540 + SECITEM_FreeItem(targetOutput, PR_TRUE); 1.541 + targetOutput = NULL; 1.542 + } 1.543 + PK11_FreeSymKey(targetKey); 1.544 + targetKey = NULL; 1.545 + } 1.546 + /* keys aren't equal, update the KEY_ID and look again */ 1.547 + rv = pk11_incrementID(arena, &symTemplate[0]); 1.548 + if (rv != SECSuccess) { 1.549 + goto done; 1.550 + } 1.551 + targetKeyID = pk11_FindObjectByTemplate(targetSlot, 1.552 + symTemplate, symTemplateCount); 1.553 + } 1.554 + 1.555 + /* we didn't find a matching key, import this one with the new 1.556 + * CKAID */ 1.557 + flags = pk11_getSecretKeyFlags(sourceSlot, id); 1.558 + targetKey = PK11_MoveSymKey(targetSlot, PK11_OriginDerive, flags, PR_TRUE, 1.559 + sourceKey); 1.560 + if (targetKey == NULL) { 1.561 + rv = SECFailure; 1.562 + goto done; 1.563 + } 1.564 + /* set the key new CKAID */ 1.565 + rv = pk11_setAttributes(targetSlot, targetKey->objectID, symTemplate, 1); 1.566 + if (rv != SECSuccess) { 1.567 + goto done; 1.568 + } 1.569 + 1.570 + /* fill in remaining attributes */ 1.571 + rv = pk11_copyAttributes(arena, targetSlot, targetKey->objectID, 1.572 + sourceSlot, id, symCopyTemplate, symCopyTemplateCount); 1.573 +done: 1.574 + if (sourceKey) { 1.575 + PK11_FreeSymKey(sourceKey); 1.576 + } 1.577 + if (targetKey) { 1.578 + PK11_FreeSymKey(targetKey); 1.579 + } 1.580 + if (sourceOutput) { 1.581 + SECITEM_FreeItem(sourceOutput, PR_TRUE); 1.582 + } 1.583 + if (targetOutput) { 1.584 + SECITEM_FreeItem(targetOutput, PR_TRUE); 1.585 + } 1.586 + if (param) { 1.587 + SECITEM_FreeItem(param, PR_TRUE); 1.588 + } 1.589 + if (arena) { 1.590 + PORT_FreeArena(arena,PR_FALSE); 1.591 + } 1.592 + return rv; 1.593 +} 1.594 + 1.595 +/************************************************************************* 1.596 + * 1.597 + * Public Keys 1.598 + * 1.599 + *************************************************************************/ 1.600 + 1.601 +/* 1.602 + * Merge public key 1.603 + * 1.604 + * Use the high level NSS calls to extract the public key and import it 1.605 + * into the token. Extra attributes are then copied to the new token. 1.606 + */ 1.607 +static SECStatus 1.608 +pk11_mergePublicKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 1.609 + CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) 1.610 +{ 1.611 + SECKEYPublicKey *sourceKey = NULL; 1.612 + CK_OBJECT_HANDLE targetKeyID; 1.613 + PLArenaPool *arena = NULL; 1.614 + SECStatus rv = SECSuccess; 1.615 + CK_ATTRIBUTE pubTemplate[] = { 1.616 + { CKA_ID, NULL, 0 }, 1.617 + { CKA_CLASS, NULL, 0 } 1.618 + }; 1.619 + CK_ULONG pubTemplateCount = sizeof(pubTemplate)/sizeof(pubTemplate[0]); 1.620 + CK_ATTRIBUTE pubCopyTemplate[] = { 1.621 + { CKA_ID, NULL, 0 }, 1.622 + { CKA_LABEL, NULL, 0 }, 1.623 + { CKA_SUBJECT, NULL, 0 } 1.624 + }; 1.625 + CK_ULONG pubCopyTemplateCount = 1.626 + sizeof(pubCopyTemplate)/sizeof(pubCopyTemplate[0]); 1.627 + 1.628 + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); 1.629 + if (arena == NULL) { 1.630 + rv = SECFailure; 1.631 + goto done; 1.632 + } 1.633 + 1.634 + 1.635 + /* check to see if the key is already in the target slot */ 1.636 + rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, pubTemplate, 1.637 + pubTemplateCount, id, &targetKeyID); 1.638 + if (rv != SECSuccess) { 1.639 + goto done; 1.640 + } 1.641 + 1.642 + /* Key is already in the target slot */ 1.643 + if (targetKeyID != CK_INVALID_HANDLE) { 1.644 + /* not an error ... */ 1.645 + goto done; 1.646 + } 1.647 + 1.648 + /* fetch an NSS representation of the public key */ 1.649 + sourceKey = PK11_ExtractPublicKey(sourceSlot, nullKey, id); 1.650 + if (sourceKey== NULL) { 1.651 + rv = SECFailure; 1.652 + goto done; 1.653 + } 1.654 + 1.655 + /* load the public key into the target token. */ 1.656 + targetKeyID = PK11_ImportPublicKey(targetSlot, sourceKey, PR_TRUE); 1.657 + if (targetKeyID == CK_INVALID_HANDLE) { 1.658 + rv = SECFailure; 1.659 + goto done; 1.660 + } 1.661 + 1.662 + /* fill in remaining attributes */ 1.663 + rv = pk11_copyAttributes(arena, targetSlot, targetKeyID, sourceSlot, id, 1.664 + pubCopyTemplate, pubCopyTemplateCount); 1.665 + 1.666 + 1.667 +done: 1.668 + if (sourceKey) { 1.669 + SECKEY_DestroyPublicKey(sourceKey); 1.670 + } 1.671 + if (arena) { 1.672 + PORT_FreeArena(arena,PR_FALSE); 1.673 + } 1.674 + return rv; 1.675 +} 1.676 + 1.677 +/************************************************************************* 1.678 + * 1.679 + * Certificates 1.680 + * 1.681 + *************************************************************************/ 1.682 + 1.683 +/* 1.684 + * Two copies of the source code for this algorithm exist in NSS. 1.685 + * Changes must be made in both copies. 1.686 + * The other copy is in sftkdb_resolveConflicts() in softoken/sftkdb.c. 1.687 + */ 1.688 +static char * 1.689 +pk11_IncrementNickname(char *nickname) 1.690 +{ 1.691 + char *newNickname = NULL; 1.692 + int end; 1.693 + int digit; 1.694 + int len = strlen(nickname); 1.695 + 1.696 + /* does nickname end with " #n*" ? */ 1.697 + for (end = len - 1; 1.698 + end >= 2 && (digit = nickname[end]) <= '9' && digit >= '0'; 1.699 + end--) /* just scan */ ; 1.700 + if (len >= 3 && 1.701 + end < (len - 1) /* at least one digit */ && 1.702 + nickname[end] == '#' && 1.703 + nickname[end - 1] == ' ') { 1.704 + /* Already has a suitable suffix string */ 1.705 + } else { 1.706 + /* ... append " #2" to the name */ 1.707 + static const char num2[] = " #2"; 1.708 + newNickname = PORT_Realloc(nickname, len + sizeof(num2)); 1.709 + if (newNickname) { 1.710 + PORT_Strcat(newNickname, num2); 1.711 + } else { 1.712 + PORT_Free(nickname); 1.713 + } 1.714 + return newNickname; 1.715 + } 1.716 + 1.717 + for (end = len - 1; 1.718 + end >= 0 && (digit = nickname[end]) <= '9' && digit >= '0'; 1.719 + end--) { 1.720 + if (digit < '9') { 1.721 + nickname[end]++; 1.722 + return nickname; 1.723 + } 1.724 + nickname[end] = '0'; 1.725 + } 1.726 + 1.727 + /* we overflowed, insert a new '1' for a carry in front of the number */ 1.728 + newNickname = PORT_Realloc(nickname, len + 2); 1.729 + if (newNickname) { 1.730 + newNickname[++end] = '1'; 1.731 + PORT_Memset(&newNickname[end + 1], '0', len - end); 1.732 + newNickname[len + 1] = 0; 1.733 + } else { 1.734 + PORT_Free(nickname); 1.735 + } 1.736 + return newNickname; 1.737 +} 1.738 + 1.739 +/* 1.740 + * merge a certificate object 1.741 + * 1.742 + * Use the high level NSS calls to extract and import the certificate. 1.743 + */ 1.744 +static SECStatus 1.745 +pk11_mergeCert(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 1.746 + CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) 1.747 +{ 1.748 + CERTCertificate *sourceCert = NULL; 1.749 + CK_OBJECT_HANDLE targetCertID = CK_INVALID_HANDLE; 1.750 + char *nickname = NULL; 1.751 + SECStatus rv = SECSuccess; 1.752 + PLArenaPool *arena = NULL; 1.753 + CK_ATTRIBUTE sourceCKAID = {CKA_ID, NULL, 0}; 1.754 + CK_ATTRIBUTE targetCKAID = {CKA_ID, NULL, 0}; 1.755 + SECStatus lrv = SECSuccess; 1.756 + int error; 1.757 + 1.758 + 1.759 + sourceCert = PK11_MakeCertFromHandle(sourceSlot, id, NULL); 1.760 + if (sourceCert == NULL) { 1.761 + rv = SECFailure; 1.762 + goto done; 1.763 + } 1.764 + 1.765 + nickname = PK11_GetObjectNickname(sourceSlot, id); 1.766 + 1.767 + /* The database code will prevent nickname collisions for certs with 1.768 + * different subjects. This code will prevent us from getting 1.769 + * actual import errors */ 1.770 + if (nickname) { 1.771 + const char *tokenName = PK11_GetTokenName(targetSlot); 1.772 + char *tokenNickname = NULL; 1.773 + 1.774 + do { 1.775 + tokenNickname = PR_smprintf("%s:%s",tokenName, nickname); 1.776 + if (!tokenNickname) { 1.777 + break; 1.778 + } 1.779 + if (!SEC_CertNicknameConflict(tokenNickname, 1.780 + &sourceCert->derSubject, CERT_GetDefaultCertDB())) { 1.781 + break; 1.782 + } 1.783 + nickname = pk11_IncrementNickname(nickname); 1.784 + if (!nickname) { 1.785 + break; 1.786 + } 1.787 + PR_smprintf_free(tokenNickname); 1.788 + } while (1); 1.789 + if (tokenNickname) { 1.790 + PR_smprintf_free(tokenNickname); 1.791 + } 1.792 + } 1.793 + 1.794 + 1.795 + 1.796 + /* see if the cert is already there */ 1.797 + targetCertID = PK11_FindCertInSlot(targetSlot, sourceCert, targetPwArg); 1.798 + if (targetCertID == CK_INVALID_HANDLE) { 1.799 + /* cert doesn't exist load the cert in. */ 1.800 + /* OK for the nickname to be NULL, not all certs have nicknames */ 1.801 + rv = PK11_ImportCert(targetSlot, sourceCert, CK_INVALID_HANDLE, 1.802 + nickname, PR_FALSE); 1.803 + goto done; 1.804 + } 1.805 + 1.806 + /* the cert already exists, see if the nickname and/or CKA_ID need 1.807 + * to be updated */ 1.808 + 1.809 + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); 1.810 + if (arena == NULL) { 1.811 + rv = SECFailure; 1.812 + goto done; 1.813 + } 1.814 + 1.815 + /* does our source have a CKA_ID ? */ 1.816 + rv = PK11_GetAttributes(arena, sourceSlot, id, &sourceCKAID, 1); 1.817 + if (rv != SECSuccess) { 1.818 + sourceCKAID.ulValueLen = 0; 1.819 + } 1.820 + 1.821 + /* if we have a source CKA_ID, see of we need to update the 1.822 + * target's CKA_ID */ 1.823 + if (sourceCKAID.ulValueLen != 0) { 1.824 + rv = PK11_GetAttributes(arena, targetSlot, targetCertID, 1.825 + &targetCKAID, 1); 1.826 + if (rv != SECSuccess) { 1.827 + targetCKAID.ulValueLen = 0; 1.828 + } 1.829 + /* if the target has no CKA_ID, update it from the source */ 1.830 + if (targetCKAID.ulValueLen == 0) { 1.831 + lrv=pk11_setAttributes(targetSlot, targetCertID, &sourceCKAID, 1); 1.832 + if (lrv != SECSuccess) { 1.833 + error = PORT_GetError(); 1.834 + } 1.835 + } 1.836 + } 1.837 + rv = SECSuccess; 1.838 + 1.839 + /* now check if we need to update the nickname */ 1.840 + if (nickname && *nickname) { 1.841 + char *targetname; 1.842 + targetname = PK11_GetObjectNickname(targetSlot, targetCertID); 1.843 + if (!targetname || !*targetname) { 1.844 + /* target has no nickname, or it's empty, update it */ 1.845 + rv = PK11_SetObjectNickname(targetSlot, targetCertID, nickname); 1.846 + } 1.847 + if (targetname) { 1.848 + PORT_Free(targetname); 1.849 + } 1.850 + } 1.851 + 1.852 + /* restore the error code if CKA_ID failed, but nickname didn't */ 1.853 + if ((rv == SECSuccess) && (lrv != SECSuccess)) { 1.854 + rv = lrv; 1.855 + PORT_SetError(error); 1.856 + } 1.857 + 1.858 +done: 1.859 + if (nickname) { 1.860 + PORT_Free(nickname); 1.861 + } 1.862 + if (sourceCert) { 1.863 + CERT_DestroyCertificate(sourceCert); 1.864 + } 1.865 + if (arena) { 1.866 + PORT_FreeArena(arena,PR_FALSE); 1.867 + } 1.868 + return rv; 1.869 +} 1.870 + 1.871 + 1.872 +/************************************************************************* 1.873 + * 1.874 + * Crls 1.875 + * 1.876 + *************************************************************************/ 1.877 + 1.878 +/* 1.879 + * Use the raw PKCS #11 interface to merge the CRLs. 1.880 + * 1.881 + * In the case where of collision, choose the newest CRL that is valid. 1.882 + */ 1.883 +static SECStatus 1.884 +pk11_mergeCrl(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 1.885 + CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) 1.886 +{ 1.887 + CK_OBJECT_HANDLE targetCrlID; 1.888 + PLArenaPool *arena = NULL; 1.889 + SECStatus rv = SECSuccess; 1.890 + CK_ATTRIBUTE crlTemplate[] = { 1.891 + { CKA_SUBJECT, NULL, 0 }, 1.892 + { CKA_CLASS, NULL, 0 }, 1.893 + { CKA_NSS_KRL, NULL, 0 } 1.894 + }; 1.895 + CK_ULONG crlTemplateCount = sizeof(crlTemplate)/sizeof(crlTemplate[0]); 1.896 + CK_ATTRIBUTE crlCopyTemplate[] = { 1.897 + { CKA_CLASS, NULL, 0 }, 1.898 + { CKA_TOKEN, NULL, 0 }, 1.899 + { CKA_LABEL, NULL, 0 }, 1.900 + { CKA_PRIVATE, NULL, 0 }, 1.901 + { CKA_MODIFIABLE, NULL, 0 }, 1.902 + { CKA_SUBJECT, NULL, 0 }, 1.903 + { CKA_NSS_KRL, NULL, 0 }, 1.904 + { CKA_NSS_URL, NULL, 0 }, 1.905 + { CKA_VALUE, NULL, 0 } 1.906 + }; 1.907 + CK_ULONG crlCopyTemplateCount = 1.908 + sizeof(crlCopyTemplate)/sizeof(crlCopyTemplate[0]); 1.909 + 1.910 + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); 1.911 + if (arena == NULL) { 1.912 + rv = SECFailure; 1.913 + goto done; 1.914 + } 1.915 + /* check to see if the crl is already in the target slot */ 1.916 + rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, crlTemplate, 1.917 + crlTemplateCount, id, &targetCrlID); 1.918 + if (rv != SECSuccess) { 1.919 + goto done; 1.920 + } 1.921 + if (targetCrlID != CK_INVALID_HANDLE) { 1.922 + /* we already have a CRL, check to see which is more up-to-date. */ 1.923 + goto done; 1.924 + } 1.925 + 1.926 + /* load the CRL into the target token. */ 1.927 + rv = pk11_copyAttributes(arena, targetSlot, targetCrlID, sourceSlot, id, 1.928 + crlCopyTemplate, crlCopyTemplateCount); 1.929 +done: 1.930 + if (arena) { 1.931 + PORT_FreeArena(arena,PR_FALSE); 1.932 + } 1.933 + return rv; 1.934 +} 1.935 + 1.936 +/************************************************************************* 1.937 + * 1.938 + * SMIME objects 1.939 + * 1.940 + *************************************************************************/ 1.941 + 1.942 +/* 1.943 + * use the raw PKCS #11 interface to merge the S/MIME records 1.944 + */ 1.945 +static SECStatus 1.946 +pk11_mergeSmime(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 1.947 + CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) 1.948 +{ 1.949 + CK_OBJECT_HANDLE targetSmimeID; 1.950 + PLArenaPool *arena = NULL; 1.951 + SECStatus rv = SECSuccess; 1.952 + CK_ATTRIBUTE smimeTemplate[] = { 1.953 + { CKA_SUBJECT, NULL, 0 }, 1.954 + { CKA_NSS_EMAIL, NULL, 0 }, 1.955 + { CKA_CLASS, NULL, 0 }, 1.956 + }; 1.957 + CK_ULONG smimeTemplateCount = 1.958 + sizeof(smimeTemplate)/sizeof(smimeTemplate[0]); 1.959 + CK_ATTRIBUTE smimeCopyTemplate[] = { 1.960 + { CKA_CLASS, NULL, 0 }, 1.961 + { CKA_TOKEN, NULL, 0 }, 1.962 + { CKA_LABEL, NULL, 0 }, 1.963 + { CKA_PRIVATE, NULL, 0 }, 1.964 + { CKA_MODIFIABLE, NULL, 0 }, 1.965 + { CKA_SUBJECT, NULL, 0 }, 1.966 + { CKA_NSS_EMAIL, NULL, 0 }, 1.967 + { CKA_NSS_SMIME_TIMESTAMP, NULL, 0 }, 1.968 + { CKA_VALUE, NULL, 0 } 1.969 + }; 1.970 + CK_ULONG smimeCopyTemplateCount = 1.971 + sizeof(smimeCopyTemplate)/sizeof(smimeCopyTemplate[0]); 1.972 + 1.973 + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); 1.974 + if (arena == NULL) { 1.975 + rv = SECFailure; 1.976 + goto done; 1.977 + } 1.978 + /* check to see if the crl is already in the target slot */ 1.979 + rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, smimeTemplate, 1.980 + smimeTemplateCount, id, &targetSmimeID); 1.981 + if (rv != SECSuccess) { 1.982 + goto done; 1.983 + } 1.984 + if (targetSmimeID != CK_INVALID_HANDLE) { 1.985 + /* we already have a SMIME record */ 1.986 + goto done; 1.987 + } 1.988 + 1.989 + /* load the SMime Record into the target token. */ 1.990 + rv = pk11_copyAttributes(arena, targetSlot, targetSmimeID, sourceSlot, id, 1.991 + smimeCopyTemplate, smimeCopyTemplateCount); 1.992 +done: 1.993 + if (arena) { 1.994 + PORT_FreeArena(arena,PR_FALSE); 1.995 + } 1.996 + return rv; 1.997 +} 1.998 + 1.999 +/************************************************************************* 1.1000 + * 1.1001 + * Trust Objects 1.1002 + * 1.1003 + *************************************************************************/ 1.1004 + 1.1005 + 1.1006 +/* 1.1007 + * decide which trust record entry wins. PR_TRUE (source) or PR_FALSE (target) 1.1008 + */ 1.1009 +#define USE_TARGET PR_FALSE 1.1010 +#define USE_SOURCE PR_TRUE 1.1011 +PRBool 1.1012 +pk11_mergeTrustEntry(CK_ATTRIBUTE *target, CK_ATTRIBUTE *source) 1.1013 +{ 1.1014 + CK_ULONG targetTrust = (target->ulValueLen == sizeof (CK_LONG)) ? 1.1015 + *(CK_ULONG *)target->pValue : CKT_NSS_TRUST_UNKNOWN; 1.1016 + CK_ULONG sourceTrust = (source->ulValueLen == sizeof (CK_LONG)) ? 1.1017 + *(CK_ULONG *)source->pValue : CKT_NSS_TRUST_UNKNOWN; 1.1018 + 1.1019 + /* 1.1020 + * Examine a single entry and deside if the source or target version 1.1021 + * should win out. When all the entries have been checked, if there is 1.1022 + * any case we need to update, we will write the whole source record 1.1023 + * to the target database. That means for each individual record, if the 1.1024 + * target wins, we need to update the source (in case later we have a 1.1025 + * case where the source wins). If the source wins, it already 1.1026 + */ 1.1027 + if (sourceTrust == targetTrust) { 1.1028 + return USE_TARGET; /* which equates to 'do nothing' */ 1.1029 + } 1.1030 + 1.1031 + if (sourceTrust == CKT_NSS_TRUST_UNKNOWN) { 1.1032 + return USE_TARGET; 1.1033 + } 1.1034 + 1.1035 + /* target has no idea, use the source's idea of the trust value */ 1.1036 + if (targetTrust == CKT_NSS_TRUST_UNKNOWN) { 1.1037 + /* source overwrites the target */ 1.1038 + return USE_SOURCE; 1.1039 + } 1.1040 + 1.1041 + /* so both the target and the source have some idea of what this 1.1042 + * trust attribute should be, and neither agree exactly. 1.1043 + * At this point, we prefer 'hard' attributes over 'soft' ones. 1.1044 + * 'hard' ones are CKT_NSS_TRUSTED, CKT_NSS_TRUSTED_DELEGATOR, and 1.1045 + * CKT_NSS_UNTRUTED. Soft ones are ones which don't change the 1.1046 + * actual trust of the cert (CKT_MUST_VERIFY, CKT_NSS_VALID, 1.1047 + * CKT_NSS_VALID_DELEGATOR). 1.1048 + */ 1.1049 + if ((sourceTrust == CKT_NSS_MUST_VERIFY_TRUST) 1.1050 + || (sourceTrust == CKT_NSS_VALID_DELEGATOR)) { 1.1051 + return USE_TARGET; 1.1052 + } 1.1053 + if ((targetTrust == CKT_NSS_MUST_VERIFY_TRUST) 1.1054 + || (targetTrust == CKT_NSS_VALID_DELEGATOR)) { 1.1055 + /* source overrites the target */ 1.1056 + return USE_SOURCE; 1.1057 + } 1.1058 + 1.1059 + /* both have hard attributes, we have a conflict, let the target win. */ 1.1060 + return USE_TARGET; 1.1061 +} 1.1062 +/* 1.1063 + * use the raw PKCS #11 interface to merge the S/MIME records 1.1064 + */ 1.1065 +static SECStatus 1.1066 +pk11_mergeTrust(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 1.1067 + CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) 1.1068 +{ 1.1069 + CK_OBJECT_HANDLE targetTrustID; 1.1070 + PLArenaPool *arena = NULL; 1.1071 + SECStatus rv = SECSuccess; 1.1072 + int error = 0; 1.1073 + CK_ATTRIBUTE trustTemplate[] = { 1.1074 + { CKA_ISSUER, NULL, 0 }, 1.1075 + { CKA_SERIAL_NUMBER, NULL, 0 }, 1.1076 + { CKA_CLASS, NULL, 0 }, 1.1077 + }; 1.1078 + CK_ULONG trustTemplateCount = 1.1079 + sizeof(trustTemplate)/sizeof(trustTemplate[0]); 1.1080 + CK_ATTRIBUTE trustCopyTemplate[] = { 1.1081 + { CKA_CLASS, NULL, 0 }, 1.1082 + { CKA_TOKEN, NULL, 0 }, 1.1083 + { CKA_LABEL, NULL, 0 }, 1.1084 + { CKA_PRIVATE, NULL, 0 }, 1.1085 + { CKA_MODIFIABLE, NULL, 0 }, 1.1086 + { CKA_ISSUER, NULL, 0}, 1.1087 + { CKA_SERIAL_NUMBER, NULL, 0}, 1.1088 + { CKA_CERT_SHA1_HASH, NULL, 0 }, 1.1089 + { CKA_CERT_MD5_HASH, NULL, 0 }, 1.1090 + { CKA_TRUST_SERVER_AUTH, NULL, 0 }, 1.1091 + { CKA_TRUST_CLIENT_AUTH, NULL, 0 }, 1.1092 + { CKA_TRUST_CODE_SIGNING, NULL, 0 }, 1.1093 + { CKA_TRUST_EMAIL_PROTECTION, NULL, 0 }, 1.1094 + { CKA_TRUST_STEP_UP_APPROVED, NULL, 0 } 1.1095 + }; 1.1096 + CK_ULONG trustCopyTemplateCount = 1.1097 + sizeof(trustCopyTemplate)/sizeof(trustCopyTemplate[0]); 1.1098 + 1.1099 + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); 1.1100 + if (arena == NULL) { 1.1101 + rv = SECFailure; 1.1102 + goto done; 1.1103 + } 1.1104 + /* check to see if the crl is already in the target slot */ 1.1105 + rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, trustTemplate, 1.1106 + trustTemplateCount, id, &targetTrustID); 1.1107 + if (rv != SECSuccess) { 1.1108 + goto done; 1.1109 + } 1.1110 + if (targetTrustID != CK_INVALID_HANDLE) { 1.1111 + /* a matching trust record already exists, merge it in */ 1.1112 + CK_ATTRIBUTE_TYPE trustAttrs[] = { 1.1113 + CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, 1.1114 + CKA_TRUST_CODE_SIGNING, CKA_TRUST_EMAIL_PROTECTION, 1.1115 + CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, 1.1116 + CKA_TRUST_TIME_STAMPING 1.1117 + }; 1.1118 + CK_ULONG trustAttrsCount = 1.1119 + sizeof(trustAttrs)/sizeof(trustAttrs[0]); 1.1120 + 1.1121 + CK_ULONG i; 1.1122 + CK_ATTRIBUTE targetTemplate, sourceTemplate; 1.1123 + 1.1124 + /* existing trust record, merge the two together */ 1.1125 + for (i=0; i < trustAttrsCount; i++) { 1.1126 + targetTemplate.type = sourceTemplate.type = trustAttrs[i]; 1.1127 + targetTemplate.pValue = sourceTemplate.pValue = NULL; 1.1128 + targetTemplate.ulValueLen = sourceTemplate.ulValueLen = 0; 1.1129 + PK11_GetAttributes(arena, sourceSlot, id, &sourceTemplate, 1); 1.1130 + PK11_GetAttributes(arena, targetSlot, targetTrustID, 1.1131 + &targetTemplate, 1); 1.1132 + if (pk11_mergeTrustEntry(&targetTemplate, &sourceTemplate)) { 1.1133 + /* source wins, write out the source attribute to the target */ 1.1134 + SECStatus lrv = pk11_setAttributes(targetSlot, targetTrustID, 1.1135 + &sourceTemplate, 1); 1.1136 + if (lrv != SECSuccess) { 1.1137 + rv = SECFailure; 1.1138 + error = PORT_GetError(); 1.1139 + } 1.1140 + } 1.1141 + } 1.1142 + 1.1143 + /* handle step */ 1.1144 + sourceTemplate.type = CKA_TRUST_STEP_UP_APPROVED; 1.1145 + sourceTemplate.pValue = NULL; 1.1146 + sourceTemplate.ulValueLen = 0; 1.1147 + 1.1148 + /* if the source has steup set, then set it in the target */ 1.1149 + PK11_GetAttributes(arena, sourceSlot, id, &sourceTemplate, 1); 1.1150 + if ((sourceTemplate.ulValueLen == sizeof(CK_BBOOL)) && 1.1151 + (sourceTemplate.pValue) && 1.1152 + (*(CK_BBOOL *)sourceTemplate.pValue == CK_TRUE)) { 1.1153 + SECStatus lrv = pk11_setAttributes(targetSlot, targetTrustID, 1.1154 + &sourceTemplate, 1); 1.1155 + if (lrv != SECSuccess) { 1.1156 + rv = SECFailure; 1.1157 + error = PORT_GetError(); 1.1158 + } 1.1159 + } 1.1160 + 1.1161 + goto done; 1.1162 + 1.1163 + } 1.1164 + 1.1165 + /* load the new trust Record into the target token. */ 1.1166 + rv = pk11_copyAttributes(arena, targetSlot, targetTrustID, sourceSlot, id, 1.1167 + trustCopyTemplate, trustCopyTemplateCount); 1.1168 +done: 1.1169 + if (arena) { 1.1170 + PORT_FreeArena(arena,PR_FALSE); 1.1171 + } 1.1172 + 1.1173 + /* restore the error code */ 1.1174 + if (rv == SECFailure && error) { 1.1175 + PORT_SetError(error); 1.1176 + } 1.1177 + 1.1178 + return rv; 1.1179 +} 1.1180 + 1.1181 +/************************************************************************* 1.1182 + * 1.1183 + * Central merge code 1.1184 + * 1.1185 + *************************************************************************/ 1.1186 +/* 1.1187 + * merge a single object from sourceToken to targetToken 1.1188 + */ 1.1189 +static SECStatus 1.1190 +pk11_mergeObject(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 1.1191 + CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) 1.1192 +{ 1.1193 + 1.1194 + CK_OBJECT_CLASS objClass; 1.1195 + 1.1196 + 1.1197 + objClass = PK11_ReadULongAttribute(sourceSlot, id, CKA_CLASS); 1.1198 + if (objClass == (CK_ULONG) -1) { 1.1199 + PORT_SetError( SEC_ERROR_UNKNOWN_OBJECT_TYPE ); 1.1200 + return SECFailure; 1.1201 + } 1.1202 + 1.1203 + switch (objClass) { 1.1204 + case CKO_CERTIFICATE: 1.1205 + return pk11_mergeCert(targetSlot, sourceSlot, id, 1.1206 + targetPwArg, sourcePwArg); 1.1207 + case CKO_NSS_TRUST: 1.1208 + return pk11_mergeTrust(targetSlot, sourceSlot, id, 1.1209 + targetPwArg, sourcePwArg); 1.1210 + case CKO_PUBLIC_KEY: 1.1211 + return pk11_mergePublicKey(targetSlot, sourceSlot, id, 1.1212 + targetPwArg, sourcePwArg); 1.1213 + case CKO_PRIVATE_KEY: 1.1214 + return pk11_mergePrivateKey(targetSlot, sourceSlot, id, 1.1215 + targetPwArg, sourcePwArg); 1.1216 + case CKO_SECRET_KEY: 1.1217 + return pk11_mergeSecretKey(targetSlot, sourceSlot, id, 1.1218 + targetPwArg, sourcePwArg); 1.1219 + case CKO_NSS_CRL: 1.1220 + return pk11_mergeCrl(targetSlot, sourceSlot, id, 1.1221 + targetPwArg, sourcePwArg); 1.1222 + case CKO_NSS_SMIME: 1.1223 + return pk11_mergeSmime(targetSlot, sourceSlot, id, 1.1224 + targetPwArg, sourcePwArg); 1.1225 + default: 1.1226 + break; 1.1227 + } 1.1228 + 1.1229 + PORT_SetError( SEC_ERROR_UNKNOWN_OBJECT_TYPE ); 1.1230 + return SECFailure; 1.1231 +} 1.1232 + 1.1233 +PK11MergeLogNode * 1.1234 +pk11_newMergeLogNode(PLArenaPool *arena, 1.1235 + PK11SlotInfo *slot, CK_OBJECT_HANDLE id, int error) 1.1236 +{ 1.1237 + PK11MergeLogNode *newLog; 1.1238 + PK11GenericObject *obj; 1.1239 + 1.1240 + newLog = PORT_ArenaZNew(arena, PK11MergeLogNode); 1.1241 + if (newLog == NULL) { 1.1242 + return NULL; 1.1243 + } 1.1244 + 1.1245 + obj = PORT_ArenaZNew(arena, PK11GenericObject); 1.1246 + if ( !obj ) { 1.1247 + return NULL; 1.1248 + } 1.1249 + 1.1250 + /* initialize it */ 1.1251 + obj->slot = slot; 1.1252 + obj->objectID = id; 1.1253 + 1.1254 + newLog->object= obj; 1.1255 + newLog->error = error; 1.1256 + return newLog; 1.1257 +} 1.1258 + 1.1259 +/* 1.1260 + * walk down each entry and merge it. keep track of the errors in the log 1.1261 + */ 1.1262 +static SECStatus 1.1263 +pk11_mergeByObjectIDs(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 1.1264 + CK_OBJECT_HANDLE *objectIDs, int count, 1.1265 + PK11MergeLog *log, void *targetPwArg, void *sourcePwArg) 1.1266 +{ 1.1267 + SECStatus rv = SECSuccess; 1.1268 + int error, i; 1.1269 + 1.1270 + for (i=0; i < count; i++) { 1.1271 + /* try to update the entire database. On failure, keep going, 1.1272 + * but remember the error to report back to the caller */ 1.1273 + SECStatus lrv; 1.1274 + PK11MergeLogNode *newLog; 1.1275 + 1.1276 + lrv= pk11_mergeObject(targetSlot, sourceSlot, objectIDs[i], 1.1277 + targetPwArg, sourcePwArg); 1.1278 + if (lrv == SECSuccess) { 1.1279 + /* merged with no problem, go to next object */ 1.1280 + continue; 1.1281 + } 1.1282 + 1.1283 + /* remember that we failed and why */ 1.1284 + rv = SECFailure; 1.1285 + error = PORT_GetError(); 1.1286 + 1.1287 + /* log the errors */ 1.1288 + if (!log) { 1.1289 + /* not logging, go to next entry */ 1.1290 + continue; 1.1291 + } 1.1292 + newLog = pk11_newMergeLogNode(log->arena, sourceSlot, 1.1293 + objectIDs[i], error); 1.1294 + if (!newLog) { 1.1295 + /* failed to allocate entry, just keep going */ 1.1296 + continue; 1.1297 + } 1.1298 + 1.1299 + /* link in the errorlog entry */ 1.1300 + newLog->next = NULL; 1.1301 + if (log->tail) { 1.1302 + log->tail->next = newLog; 1.1303 + } else { 1.1304 + log->head = newLog; 1.1305 + } 1.1306 + newLog->prev = log->tail; 1.1307 + log->tail = newLog; 1.1308 + } 1.1309 + 1.1310 + /* restore the last error code */ 1.1311 + if (rv != SECSuccess) { 1.1312 + PORT_SetError(error); 1.1313 + } 1.1314 + return rv; 1.1315 +} 1.1316 + 1.1317 +/* 1.1318 + * Merge all the records in sourceSlot that aren't in targetSlot 1.1319 + * 1.1320 + * This function will return failure if not all the objects 1.1321 + * successfully merged. 1.1322 + * 1.1323 + * Applications can pass in an optional error log which will record 1.1324 + * each failing object and why it failed to import. PK11MergeLog 1.1325 + * is modelled after the CERTVerifyLog. 1.1326 + */ 1.1327 +SECStatus 1.1328 +PK11_MergeTokens(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, 1.1329 + PK11MergeLog *log, void *targetPwArg, void *sourcePwArg) 1.1330 +{ 1.1331 + SECStatus rv = SECSuccess, lrv = SECSuccess; 1.1332 + int error, count = 0; 1.1333 + CK_ATTRIBUTE search[2]; 1.1334 + CK_OBJECT_HANDLE *objectIDs = NULL; 1.1335 + CK_BBOOL ck_true = CK_TRUE; 1.1336 + CK_OBJECT_CLASS privKey = CKO_PRIVATE_KEY; 1.1337 + 1.1338 + PK11_SETATTRS(&search[0], CKA_TOKEN, &ck_true, sizeof(ck_true)); 1.1339 + PK11_SETATTRS(&search[1], CKA_CLASS, &privKey, sizeof(privKey)); 1.1340 + /* 1.1341 + * make sure both tokens are already authenticated if need be. 1.1342 + */ 1.1343 + rv = PK11_Authenticate(targetSlot, PR_TRUE, targetPwArg); 1.1344 + if (rv != SECSuccess) { 1.1345 + goto loser; 1.1346 + } 1.1347 + rv = PK11_Authenticate(sourceSlot, PR_TRUE, sourcePwArg); 1.1348 + if (rv != SECSuccess) { 1.1349 + goto loser; 1.1350 + } 1.1351 + 1.1352 + /* turns out the old DB's are rather fragile if the private keys aren't 1.1353 + * merged in first, so do the private keys explicity. */ 1.1354 + objectIDs = pk11_FindObjectsByTemplate(sourceSlot, search, 2, &count); 1.1355 + if (objectIDs) { 1.1356 + lrv = pk11_mergeByObjectIDs(targetSlot, sourceSlot, 1.1357 + objectIDs, count, log, 1.1358 + targetPwArg, sourcePwArg); 1.1359 + if (lrv != SECSuccess) { 1.1360 + error = PORT_GetError(); 1.1361 + } 1.1362 + PORT_Free(objectIDs); 1.1363 + count = 0; 1.1364 + } 1.1365 + 1.1366 + /* now do the rest (NOTE: this will repeat the private keys, but 1.1367 + * that shouldnt' be an issue as we will notice they are already 1.1368 + * merged in */ 1.1369 + objectIDs = pk11_FindObjectsByTemplate(sourceSlot, search, 1, &count); 1.1370 + if (!objectIDs) { 1.1371 + rv = SECFailure; 1.1372 + goto loser; 1.1373 + } 1.1374 + 1.1375 + rv = pk11_mergeByObjectIDs(targetSlot, sourceSlot, objectIDs, count, log, 1.1376 + targetPwArg, sourcePwArg); 1.1377 + if (rv == SECSuccess) { 1.1378 + /* if private keys failed, but the rest succeeded, be sure to let 1.1379 + * the caller know that private keys failed and why. 1.1380 + * NOTE: this is highly unlikely since the same keys that failed 1.1381 + * in the previous merge call will most likely fail in this one */ 1.1382 + if (lrv != SECSuccess) { 1.1383 + rv = lrv; 1.1384 + PORT_SetError(error); 1.1385 + } 1.1386 + } 1.1387 + 1.1388 +loser: 1.1389 + if (objectIDs) { 1.1390 + PORT_Free(objectIDs); 1.1391 + } 1.1392 + return rv; 1.1393 +} 1.1394 + 1.1395 +PK11MergeLog * 1.1396 +PK11_CreateMergeLog(void) 1.1397 +{ 1.1398 + PLArenaPool *arena; 1.1399 + PK11MergeLog *log; 1.1400 + 1.1401 + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); 1.1402 + if (arena == NULL) { 1.1403 + return NULL; 1.1404 + } 1.1405 + 1.1406 + log = PORT_ArenaZNew(arena, PK11MergeLog); 1.1407 + if (log == NULL) { 1.1408 + PORT_FreeArena(arena,PR_FALSE); 1.1409 + return NULL; 1.1410 + } 1.1411 + log->arena = arena; 1.1412 + log->version = 1; 1.1413 + return log; 1.1414 +} 1.1415 + 1.1416 +void 1.1417 +PK11_DestroyMergeLog(PK11MergeLog *log) 1.1418 +{ 1.1419 + if (log && log->arena) { 1.1420 + PORT_FreeArena(log->arena, PR_FALSE); 1.1421 + } 1.1422 +}