| Index: mozilla/security/nss/lib/pk11wrap/pk11merge.c | 
| =================================================================== | 
| --- mozilla/security/nss/lib/pk11wrap/pk11merge.c	(revision 191424) | 
| +++ mozilla/security/nss/lib/pk11wrap/pk11merge.c	(working copy) | 
| @@ -1,1419 +0,0 @@ | 
| -/* This Source Code Form is subject to the terms of the Mozilla Public | 
| - * License, v. 2.0. If a copy of the MPL was not distributed with this | 
| - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | 
| - | 
| -/* | 
| - * Merge the source token into the target token. | 
| - */ | 
| - | 
| -#include "secmod.h" | 
| -#include "secmodi.h" | 
| -#include "secmodti.h" | 
| -#include "pk11pub.h" | 
| -#include "pk11priv.h" | 
| -#include "pkcs11.h" | 
| -#include "seccomon.h" | 
| -#include "secerr.h" | 
| -#include "keyhi.h" | 
| -#include "hasht.h" | 
| -#include "cert.h" | 
| -#include "certdb.h" | 
| - | 
| -/************************************************************************* | 
| - * | 
| - *             short utilities to aid in the merge | 
| - * | 
| - *************************************************************************/ | 
| - | 
| -/* | 
| - * write a bunch of attributes out to an existing object. | 
| - */ | 
| -static SECStatus | 
| -pk11_setAttributes(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, | 
| -		CK_ATTRIBUTE *setTemplate, CK_ULONG setTemplCount) | 
| -{ | 
| -    CK_RV crv; | 
| -    CK_SESSION_HANDLE rwsession; | 
| - | 
| -    rwsession = PK11_GetRWSession(slot); | 
| -    if (rwsession == CK_INVALID_SESSION) { | 
| -    	PORT_SetError(SEC_ERROR_BAD_DATA); | 
| -    	return SECFailure; | 
| -    } | 
| -    crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id, | 
| -			setTemplate, setTemplCount); | 
| -    PK11_RestoreROSession(slot, rwsession); | 
| -    if (crv != CKR_OK) { | 
| -	PORT_SetError(PK11_MapError(crv)); | 
| -	return SECFailure; | 
| -    } | 
| -    return SECSuccess; | 
| -} | 
| - | 
| - | 
| -/* | 
| - * copy a template of attributes from a source object to a target object. | 
| - * if target object is not given, create it. | 
| - */ | 
| -static SECStatus | 
| -pk11_copyAttributes(PRArenaPool *arena, | 
| -	PK11SlotInfo *targetSlot, CK_OBJECT_HANDLE targetID, | 
| -	PK11SlotInfo *sourceSlot, CK_OBJECT_HANDLE sourceID, | 
| -	CK_ATTRIBUTE *copyTemplate, CK_ULONG copyTemplateCount) | 
| -{ | 
| -    SECStatus rv = PK11_GetAttributes(arena, sourceSlot, sourceID, | 
| -				copyTemplate, copyTemplateCount); | 
| -    if (rv != SECSuccess) { | 
| -	return rv; | 
| -    } | 
| -    if (targetID == CK_INVALID_HANDLE) { | 
| -	/* we need to create the object */ | 
| -	rv = PK11_CreateNewObject(targetSlot, CK_INVALID_SESSION, | 
| -		copyTemplate, copyTemplateCount, PR_TRUE, &targetID); | 
| -    } else { | 
| -	/* update the existing object with the new attributes */ | 
| -	rv = pk11_setAttributes(targetSlot, targetID, | 
| -			copyTemplate, copyTemplateCount); | 
| -    } | 
| -    return rv; | 
| -} | 
| - | 
| -/* | 
| - * look for a matching object across tokens. | 
| - */ | 
| -static SECStatus | 
| -pk11_matchAcrossTokens(PRArenaPool *arena, PK11SlotInfo *targetSlot, | 
| -		       PK11SlotInfo *sourceSlot, | 
| -		       CK_ATTRIBUTE *template, CK_ULONG tsize, | 
| -		       CK_OBJECT_HANDLE id, CK_OBJECT_HANDLE *peer) | 
| -{ | 
| - | 
| -    CK_RV crv; | 
| -    *peer = CK_INVALID_HANDLE; | 
| - | 
| -    crv = PK11_GetAttributes(arena, sourceSlot, id, template, tsize); | 
| -    if (crv != CKR_OK) { | 
| - 	PORT_SetError( PK11_MapError(crv) ); | 
| -	goto loser; | 
| -    } | 
| - | 
| -    if (template[0].ulValueLen == -1) { | 
| -	crv = CKR_ATTRIBUTE_TYPE_INVALID; | 
| - 	PORT_SetError( PK11_MapError(crv) ); | 
| -	goto loser; | 
| -    } | 
| - | 
| -    *peer = pk11_FindObjectByTemplate(targetSlot, template, tsize); | 
| -    return SECSuccess; | 
| - | 
| -loser: | 
| -    return SECFailure; | 
| -} | 
| - | 
| -/* | 
| - * Encrypt using key and parameters | 
| - */ | 
| -SECStatus | 
| -pk11_encrypt(PK11SymKey *symKey, CK_MECHANISM_TYPE mechType, SECItem *param, | 
| -	SECItem *input, SECItem **output) | 
| -{ | 
| -    PK11Context *ctxt = NULL; | 
| -    SECStatus rv = SECSuccess; | 
| - | 
| -    if (*output) { | 
| -	SECITEM_FreeItem(*output,PR_TRUE); | 
| -    } | 
| -    *output = SECITEM_AllocItem(NULL, NULL, input->len+20 /*slop*/); | 
| -    if (!*output) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| - | 
| -    ctxt = PK11_CreateContextBySymKey(mechType, CKA_ENCRYPT, symKey, param); | 
| -    if (ctxt == NULL) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| - | 
| -    rv = PK11_CipherOp(ctxt, (*output)->data, | 
| -		(int *)&((*output)->len), | 
| -		(*output)->len, input->data, input->len); | 
| - | 
| -done: | 
| -    if (ctxt) { | 
| -	PK11_Finalize(ctxt); | 
| -	PK11_DestroyContext(ctxt,PR_TRUE); | 
| -    } | 
| -    if (rv != SECSuccess) { | 
| -	if (*output) { | 
| -	    SECITEM_FreeItem(*output, PR_TRUE); | 
| -	    *output = NULL; | 
| -	} | 
| -    } | 
| -    return rv; | 
| -} | 
| - | 
| - | 
| - | 
| -/************************************************************************* | 
| - * | 
| - *            Private Keys | 
| - * | 
| - *************************************************************************/ | 
| - | 
| -/* | 
| - * Fetch the key usage based on the pkcs #11 flags | 
| - */ | 
| -unsigned int | 
| -pk11_getPrivateKeyUsage(PK11SlotInfo *slot, CK_OBJECT_HANDLE id) | 
| -{ | 
| -    unsigned int usage = 0; | 
| - | 
| -    if ((PK11_HasAttributeSet(slot, id, CKA_UNWRAP,PR_FALSE) || | 
| -			PK11_HasAttributeSet(slot,id, CKA_DECRYPT,PR_FALSE))) { | 
| -	usage |= KU_KEY_ENCIPHERMENT; | 
| -    } | 
| -    if (PK11_HasAttributeSet(slot, id, CKA_DERIVE, PR_FALSE)) { | 
| -	usage |= KU_KEY_AGREEMENT; | 
| -    } | 
| -    if ((PK11_HasAttributeSet(slot, id, CKA_SIGN_RECOVER, PR_FALSE) || | 
| -			PK11_HasAttributeSet(slot, id, CKA_SIGN, PR_FALSE))) { | 
| -	usage |= KU_DIGITAL_SIGNATURE; | 
| -    } | 
| -    return usage; | 
| -} | 
| - | 
| - | 
| -/* | 
| - * merge a private key, | 
| - * | 
| - * Private keys are merged using PBE wrapped keys with a random | 
| - * value as the 'password'. Once the base key is moved, The remaining | 
| - * attributes (SUBJECT) is copied. | 
| - */ | 
| -static SECStatus | 
| -pk11_mergePrivateKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, | 
| -		CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) | 
| -{ | 
| -    SECKEYPrivateKey *sourceKey = NULL; | 
| -    CK_OBJECT_HANDLE targetKeyID; | 
| -    SECKEYEncryptedPrivateKeyInfo *epki = NULL; | 
| -    char *nickname = NULL; | 
| -    SECItem nickItem; | 
| -    SECItem pwitem; | 
| -    SECItem publicValue; | 
| -    PRArenaPool *arena = NULL; | 
| -    SECStatus rv = SECSuccess; | 
| -    unsigned int keyUsage; | 
| -    unsigned char randomData[SHA1_LENGTH]; | 
| -    SECOidTag algTag = SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC; | 
| -    CK_ATTRIBUTE privTemplate[] = { | 
| -	{ CKA_ID, NULL, 0 }, | 
| -	{ CKA_CLASS, NULL, 0 } | 
| -    }; | 
| -    CK_ULONG privTemplateCount = sizeof(privTemplate)/sizeof(privTemplate[0]); | 
| -    CK_ATTRIBUTE privCopyTemplate[] = { | 
| -	{ CKA_SUBJECT, NULL, 0 } | 
| -    }; | 
| -    CK_ULONG privCopyTemplateCount = | 
| -		sizeof(privCopyTemplate)/sizeof(privCopyTemplate[0]); | 
| - | 
| -    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); | 
| -    if (arena == NULL) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| - | 
| -    /* check to see if the key is already in the target slot */ | 
| -    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, privTemplate, | 
| -				privTemplateCount, id, &targetKeyID); | 
| -    if (rv != SECSuccess) { | 
| -	goto done; | 
| -    } | 
| - | 
| -    if (targetKeyID != CK_INVALID_HANDLE) { | 
| -	/* match found,  not an error ... */ | 
| -	goto done; | 
| -    } | 
| - | 
| -    /* get an NSS representation of our source key */ | 
| -    sourceKey = PK11_MakePrivKey(sourceSlot, nullKey, PR_FALSE, | 
| -				 id, sourcePwArg); | 
| -    if (sourceKey == NULL) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| - | 
| -    /* Load the private key */ | 
| -    /* generate a random pwitem */ | 
| -    rv = PK11_GenerateRandom(randomData, sizeof(randomData)); | 
| -    if (rv != SECSuccess) { | 
| -	goto done; | 
| -    } | 
| -    pwitem.data = randomData; | 
| -    pwitem.len = sizeof(randomData); | 
| -    /* fetch the private key encrypted */ | 
| -    epki = PK11_ExportEncryptedPrivKeyInfo(sourceSlot, algTag, &pwitem, | 
| -					   sourceKey, 1, sourcePwArg); | 
| -    if (epki == NULL) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| -    nickname = PK11_GetObjectNickname(sourceSlot, id); | 
| -    /* NULL nickanme is fine (in fact is often normal) */ | 
| -    if (nickname)  { | 
| -	nickItem.data = (unsigned char *)nickname; | 
| -	nickItem.len = PORT_Strlen(nickname); | 
| -    } | 
| -    keyUsage = pk11_getPrivateKeyUsage(sourceSlot, id); | 
| -    /* pass in the CKA_ID */ | 
| -    publicValue.data = privTemplate[0].pValue; | 
| -    publicValue.len = privTemplate[0].ulValueLen; | 
| -    rv = PK11_ImportEncryptedPrivateKeyInfo(targetSlot, epki, &pwitem, | 
| -			nickname? &nickItem : NULL , &publicValue, | 
| -			PR_TRUE, PR_TRUE, sourceKey->keyType, keyUsage, | 
| -			targetPwArg); | 
| -    if (rv != SECSuccess) { | 
| -	goto done; | 
| -    } | 
| - | 
| -    /* make sure it made it */ | 
| -    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, privTemplate, | 
| -				privTemplateCount, id, &targetKeyID); | 
| -    if (rv != SECSuccess) { | 
| -	goto done; | 
| -    } | 
| - | 
| -    if (targetKeyID == CK_INVALID_HANDLE) { | 
| -	/* this time the key should exist */ | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| - | 
| -    /* fill in remaining attributes */ | 
| -    rv = pk11_copyAttributes(arena, targetSlot, targetKeyID, sourceSlot, id, | 
| -				privCopyTemplate, privCopyTemplateCount); | 
| -done: | 
| -    /* make sure the 'key' is cleared */ | 
| -    PORT_Memset(randomData, 0, sizeof(randomData)); | 
| -    if (nickname) { | 
| -	PORT_Free(nickname); | 
| -    } | 
| -    if (sourceKey) { | 
| -	SECKEY_DestroyPrivateKey(sourceKey); | 
| -    } | 
| -    if (epki) { | 
| -	SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE); | 
| -    } | 
| -    if (arena) { | 
| -         PORT_FreeArena(arena,PR_FALSE); | 
| -    } | 
| -    return rv; | 
| -} | 
| - | 
| - | 
| -/************************************************************************* | 
| - * | 
| - *            Secret Keys | 
| - * | 
| - *************************************************************************/ | 
| - | 
| -/* | 
| - * we need to find a unique CKA_ID. | 
| - *  The basic idea is to just increment the lowest byte. | 
| - *  This code also handles the following corner cases: | 
| - *   1) the single byte overflows. On overflow we increment the next byte up | 
| - *    and so forth until we have overflowed the entire CKA_ID. | 
| - *   2) If we overflow the entire CKA_ID we expand it by one byte. | 
| - *   3) the CKA_ID is non-existent, we create a new one with one byte. | 
| - *    This means no matter what CKA_ID is passed, the result of this function | 
| - *    is always a new CKA_ID, and this function will never return the same | 
| - *    CKA_ID the it has returned in the passed. | 
| - */ | 
| -static SECStatus | 
| -pk11_incrementID(PRArenaPool *arena, CK_ATTRIBUTE *ptemplate) | 
| -{ | 
| -    unsigned char *buf = ptemplate->pValue; | 
| -    CK_ULONG len = ptemplate->ulValueLen; | 
| - | 
| -    if (buf == NULL || len == (CK_ULONG)-1) { | 
| -	/* we have no valid CKAID, we'll create a basic one byte CKA_ID below */ | 
| -	len = 0; | 
| -    } else { | 
| -	CK_ULONG i; | 
| - | 
| -	/* walk from the back to front, incrementing | 
| -	 * the CKA_ID until we no longer have a carry, | 
| -	 * or have hit the front of the id. */ | 
| -	for (i=len; i != 0; i--) { | 
| -	    buf[i-1]++; | 
| -	    if (buf[i-1] != 0) { | 
| -		/* no more carries, the increment is complete */ | 
| -		return SECSuccess; | 
| -	     } | 
| -	} | 
| -	/* we've now overflowed, fall through and expand the CKA_ID by | 
| -	 * one byte */ | 
| -    } | 
| -    /* if we are here we've run the counter to zero (indicating an overflow). | 
| -     * create an CKA_ID that is all zeros, but has one more zero than | 
| -     * the previous CKA_ID */ | 
| -    buf = PORT_ArenaZAlloc(arena, len+1); | 
| -    if (buf == NULL) { | 
| -	return SECFailure; | 
| -    } | 
| -    ptemplate->pValue = buf; | 
| -    ptemplate->ulValueLen = len+1; | 
| -    return SECSuccess; | 
| -} | 
| - | 
| - | 
| -static CK_FLAGS | 
| -pk11_getSecretKeyFlags(PK11SlotInfo *slot, CK_OBJECT_HANDLE id) | 
| -{ | 
| -    CK_FLAGS flags = 0; | 
| - | 
| -    if (PK11_HasAttributeSet(slot, id, CKA_UNWRAP, PR_FALSE)) { | 
| -	flags |= CKF_UNWRAP; | 
| -    } | 
| -    if (PK11_HasAttributeSet(slot, id, CKA_WRAP, PR_FALSE)) { | 
| -	flags |= CKF_WRAP; | 
| -    } | 
| -    if (PK11_HasAttributeSet(slot, id, CKA_ENCRYPT, PR_FALSE)) { | 
| -	flags |= CKF_ENCRYPT; | 
| -    } | 
| -    if (PK11_HasAttributeSet(slot, id, CKA_DECRYPT, PR_FALSE)) { | 
| -	flags |= CKF_DECRYPT; | 
| -    } | 
| -    if (PK11_HasAttributeSet(slot, id, CKA_DERIVE, PR_FALSE)) { | 
| -	flags |= CKF_DERIVE; | 
| -    } | 
| -    if (PK11_HasAttributeSet(slot, id, CKA_SIGN, PR_FALSE)) { | 
| -	flags |= CKF_SIGN; | 
| -    } | 
| -    if (PK11_HasAttributeSet(slot, id, CKA_SIGN_RECOVER, PR_FALSE)) { | 
| -	flags |= CKF_SIGN_RECOVER; | 
| -    } | 
| -    if (PK11_HasAttributeSet(slot, id, CKA_VERIFY, PR_FALSE)) { | 
| -	flags |= CKF_VERIFY; | 
| -    } | 
| -    if (PK11_HasAttributeSet(slot, id, CKA_VERIFY_RECOVER, PR_FALSE)) { | 
| -	flags |= CKF_VERIFY_RECOVER; | 
| -    } | 
| -    return flags; | 
| -} | 
| - | 
| -static const char testString[] = | 
| -	"My Encrytion Test Data (should be at least 32 bytes long)"; | 
| -/* | 
| - * merge a secret key, | 
| - * | 
| - * Secret keys may collide by CKA_ID as we merge 2 token. If we collide | 
| - * on the CKA_ID, we need to make sure we are dealing with different keys. | 
| - * The reason for this is it is possible that we've merged this database | 
| - * before, and this key could have been merged already.  If the keys are | 
| - * the same, we are done. If they are not, we need to update the CKA_ID of | 
| - * the source key and try again. | 
| - * | 
| - * Once we know we have a unique key to merge in, we use NSS's underlying | 
| - * key Move function which will do a key exchange if necessary to move | 
| - * the key from one token to another. Then we set the CKA_ID and additional | 
| - * pkcs #11 attributes. | 
| - */ | 
| -static SECStatus | 
| -pk11_mergeSecretKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, | 
| -		CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) | 
| -{ | 
| -    PK11SymKey *sourceKey = NULL; | 
| -    PK11SymKey *targetKey = NULL; | 
| -    SECItem *sourceOutput = NULL; | 
| -    SECItem *targetOutput = NULL; | 
| -    SECItem *param = NULL; | 
| -    int blockSize; | 
| -    SECItem input; | 
| -    CK_OBJECT_HANDLE targetKeyID; | 
| -    CK_FLAGS flags; | 
| -    PRArenaPool *arena = NULL; | 
| -    SECStatus rv = SECSuccess; | 
| -    CK_MECHANISM_TYPE keyMechType, cryptoMechType; | 
| -    CK_KEY_TYPE sourceKeyType, targetKeyType; | 
| -    CK_ATTRIBUTE symTemplate[] = { | 
| -	{ CKA_ID, NULL, 0 }, | 
| -	{ CKA_CLASS, NULL, 0 } | 
| -    }; | 
| -    CK_ULONG symTemplateCount = sizeof(symTemplate)/sizeof(symTemplate[0]); | 
| -    CK_ATTRIBUTE symCopyTemplate[] = { | 
| -	{ CKA_LABEL, NULL, 0 } | 
| -    }; | 
| -    CK_ULONG symCopyTemplateCount = | 
| -		sizeof(symCopyTemplate)/sizeof(symCopyTemplate[0]); | 
| - | 
| -    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); | 
| -    if (arena == NULL) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| - | 
| -    sourceKeyType = PK11_ReadULongAttribute(sourceSlot, id, CKA_KEY_TYPE); | 
| -    if (sourceKeyType == (CK_ULONG) -1) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| - | 
| -    /* get the key mechanism */ | 
| -    keyMechType = PK11_GetKeyMechanism(sourceKeyType); | 
| -    /* get a mechanism suitable to encryption. | 
| -     * PK11_GetKeyMechanism returns a mechanism that is unique to the key | 
| -     * type. It tries to return encryption/decryption mechanisms, however | 
| -     * CKM_DES3_CBC uses and abmiguous keyType, so keyMechType is returned as | 
| -     * 'keygen' mechanism. Detect that case here */ | 
| -    cryptoMechType =  keyMechType; | 
| -    if ((keyMechType == CKM_DES3_KEY_GEN) || | 
| -				(keyMechType == CKM_DES2_KEY_GEN)) { | 
| -	cryptoMechType = CKM_DES3_CBC; | 
| -    } | 
| - | 
| -    sourceKey = PK11_SymKeyFromHandle(sourceSlot, NULL, PK11_OriginDerive, | 
| -				keyMechType , id, PR_FALSE, sourcePwArg); | 
| -    if (sourceKey == NULL) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| - | 
| -    /* check to see a key with the same CKA_ID  already exists in | 
| -     * the target slot. If it does, then we need to verify if the keys | 
| -     * really matches. If they don't import the key with a new CKA_ID | 
| -     * value. */ | 
| -    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, | 
| -			symTemplate, symTemplateCount, id, &targetKeyID); | 
| -    if (rv != SECSuccess) { | 
| -	goto done; | 
| -    } | 
| - | 
| -    /* set up the input test */ | 
| -    input.data = (unsigned char *)testString; | 
| -    blockSize = PK11_GetBlockSize(cryptoMechType, NULL); | 
| -    if (blockSize < 0) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| -    input.len = blockSize; | 
| -    if (input.len == 0) { | 
| -	input.len = sizeof (testString); | 
| -    } | 
| -    while (targetKeyID != CK_INVALID_HANDLE) { | 
| -	/* test to see if the keys are identical */ | 
| -	targetKeyType = PK11_ReadULongAttribute(sourceSlot, id, CKA_KEY_TYPE); | 
| -	if (targetKeyType == sourceKeyType) { | 
| -		/* same keyType  - see if it's the same key */ | 
| -		targetKey = PK11_SymKeyFromHandle(targetSlot, NULL, | 
| -			PK11_OriginDerive, keyMechType, targetKeyID, PR_FALSE, | 
| -			targetPwArg); | 
| -		/* get a parameter if we don't already have one */ | 
| -		if (!param) { | 
| -		    param = PK11_GenerateNewParam(cryptoMechType, sourceKey); | 
| -		    if (param == NULL) { | 
| -			rv = SECFailure; | 
| -			goto done; | 
| -		    } | 
| -		} | 
| -		/* use the source key to encrypt a reference */ | 
| -		if (!sourceOutput) { | 
| -		    rv = pk11_encrypt(sourceKey, cryptoMechType, param, &input, | 
| -			&sourceOutput); | 
| -		    if (rv != SECSuccess) { | 
| -			goto done; | 
| -		    } | 
| -		} | 
| -		/* encrypt the reference with the target key */ | 
| -		rv = pk11_encrypt(targetKey, cryptoMechType, param, &input, | 
| -			&targetOutput); | 
| -		if (rv == SECSuccess) { | 
| -		    if (SECITEM_ItemsAreEqual(sourceOutput, targetOutput)) { | 
| -			/* they produce the same output, they must be the | 
| -			 * same key */ | 
| -			goto done; | 
| -		    } | 
| -		    SECITEM_FreeItem(targetOutput, PR_TRUE); | 
| -		    targetOutput = NULL; | 
| -		} | 
| -		PK11_FreeSymKey(targetKey); | 
| -		targetKey = NULL; | 
| -	} | 
| -	/* keys aren't equal, update the KEY_ID and look again */ | 
| -	rv = pk11_incrementID(arena, &symTemplate[0]); | 
| -	if (rv != SECSuccess) { | 
| -	    goto done; | 
| -	} | 
| -	targetKeyID = pk11_FindObjectByTemplate(targetSlot, | 
| -					symTemplate, symTemplateCount); | 
| -    } | 
| - | 
| -    /* we didn't find a matching key, import this one with the new | 
| -     * CKAID */ | 
| -    flags = pk11_getSecretKeyFlags(sourceSlot, id); | 
| -    targetKey = PK11_MoveSymKey(targetSlot, PK11_OriginDerive, flags, PR_TRUE, | 
| -			sourceKey); | 
| -    if (targetKey == NULL) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| -    /* set the key new CKAID */ | 
| -    rv = pk11_setAttributes(targetSlot, targetKey->objectID, symTemplate, 1); | 
| -    if (rv != SECSuccess) { | 
| -	goto done; | 
| -    } | 
| - | 
| -    /* fill in remaining attributes */ | 
| -    rv = pk11_copyAttributes(arena, targetSlot, targetKey->objectID, | 
| -			sourceSlot, id, symCopyTemplate, symCopyTemplateCount); | 
| -done: | 
| -    if (sourceKey) { | 
| -	PK11_FreeSymKey(sourceKey); | 
| -    } | 
| -    if (targetKey) { | 
| -	PK11_FreeSymKey(targetKey); | 
| -    } | 
| -    if (sourceOutput) { | 
| -	SECITEM_FreeItem(sourceOutput, PR_TRUE); | 
| -    } | 
| -    if (targetOutput) { | 
| -	SECITEM_FreeItem(targetOutput, PR_TRUE); | 
| -    } | 
| -    if (param) { | 
| -	SECITEM_FreeItem(param, PR_TRUE); | 
| -    } | 
| -    if (arena) { | 
| -         PORT_FreeArena(arena,PR_FALSE); | 
| -    } | 
| -    return rv; | 
| -} | 
| - | 
| -/************************************************************************* | 
| - * | 
| - *            Public Keys | 
| - * | 
| - *************************************************************************/ | 
| - | 
| -/* | 
| - * Merge public key | 
| - * | 
| - * Use the high level NSS calls to extract the public key and import it | 
| - * into the token. Extra attributes are then copied to the new token. | 
| - */ | 
| -static SECStatus | 
| -pk11_mergePublicKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, | 
| -		CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) | 
| -{ | 
| -    SECKEYPublicKey *sourceKey = NULL; | 
| -    CK_OBJECT_HANDLE targetKeyID; | 
| -    PRArenaPool *arena = NULL; | 
| -    SECStatus rv = SECSuccess; | 
| -    CK_ATTRIBUTE pubTemplate[] = { | 
| -	{ CKA_ID, NULL, 0 }, | 
| -	{ CKA_CLASS, NULL, 0 } | 
| -    }; | 
| -    CK_ULONG pubTemplateCount = sizeof(pubTemplate)/sizeof(pubTemplate[0]); | 
| -    CK_ATTRIBUTE pubCopyTemplate[] = { | 
| -	{ CKA_ID, NULL, 0 }, | 
| -	{ CKA_LABEL, NULL, 0 }, | 
| -	{ CKA_SUBJECT, NULL, 0 } | 
| -    }; | 
| -    CK_ULONG pubCopyTemplateCount = | 
| -		sizeof(pubCopyTemplate)/sizeof(pubCopyTemplate[0]); | 
| - | 
| -    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); | 
| -    if (arena == NULL) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| - | 
| - | 
| -    /* check to see if the key is already in the target slot */ | 
| -    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, pubTemplate, | 
| -				pubTemplateCount, id, &targetKeyID); | 
| -    if (rv != SECSuccess) { | 
| -	goto done; | 
| -    } | 
| - | 
| -    /* Key is already in the target slot */ | 
| -    if (targetKeyID != CK_INVALID_HANDLE) { | 
| -	/* not an error ... */ | 
| -	goto done; | 
| -    } | 
| - | 
| -    /* fetch an NSS representation of the public key */ | 
| -    sourceKey = PK11_ExtractPublicKey(sourceSlot, nullKey, id); | 
| -    if (sourceKey== NULL) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| - | 
| -    /* load the public key into the target token. */ | 
| -    targetKeyID = PK11_ImportPublicKey(targetSlot, sourceKey, PR_TRUE); | 
| -    if (targetKeyID == CK_INVALID_HANDLE) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| - | 
| -    /* fill in remaining attributes */ | 
| -    rv = pk11_copyAttributes(arena, targetSlot, targetKeyID, sourceSlot, id, | 
| -				pubCopyTemplate, pubCopyTemplateCount); | 
| - | 
| - | 
| -done: | 
| -    if (sourceKey) { | 
| -	SECKEY_DestroyPublicKey(sourceKey); | 
| -    } | 
| -    if (arena) { | 
| -         PORT_FreeArena(arena,PR_FALSE); | 
| -    } | 
| -    return rv; | 
| -} | 
| - | 
| -/************************************************************************* | 
| - * | 
| - *            Certificates | 
| - * | 
| - *************************************************************************/ | 
| - | 
| -/* | 
| - * Two copies of the source code for this algorithm exist in NSS. | 
| - * Changes must be made in both copies. | 
| - * The other copy is in sftkdb_resolveConflicts() in softoken/sftkdb.c. | 
| - */ | 
| -static char * | 
| -pk11_IncrementNickname(char *nickname) | 
| -{ | 
| -    char *newNickname = NULL; | 
| -    int end; | 
| -    int digit; | 
| -    int len = strlen(nickname); | 
| - | 
| -    /* does nickname end with " #n*" ? */ | 
| -    for (end = len - 1; | 
| -         end >= 2 && (digit = nickname[end]) <= '9' &&  digit >= '0'; | 
| -	 end--)  /* just scan */ ; | 
| -    if (len >= 3 && | 
| -        end < (len - 1) /* at least one digit */ && | 
| -	nickname[end]     == '#'  && | 
| -	nickname[end - 1] == ' ') { | 
| -    	/* Already has a suitable suffix string */ | 
| -    } else { | 
| -	/* ... append " #2" to the name */ | 
| -	static const char num2[] = " #2"; | 
| -	newNickname = PORT_Realloc(nickname, len + sizeof(num2)); | 
| -	if (newNickname) { | 
| -	    PORT_Strcat(newNickname, num2); | 
| -	} else { | 
| -	    PORT_Free(nickname); | 
| -	} | 
| -	return newNickname; | 
| -    } | 
| - | 
| -    for (end = len - 1; | 
| -	 end >= 0 && (digit = nickname[end]) <= '9' &&  digit >= '0'; | 
| -	 end--) { | 
| -	if (digit < '9') { | 
| -	    nickname[end]++; | 
| -	    return nickname; | 
| -	} | 
| -	nickname[end] = '0'; | 
| -    } | 
| - | 
| -    /* we overflowed, insert a new '1' for a carry in front of the number */ | 
| -    newNickname = PORT_Realloc(nickname, len + 2); | 
| -    if (newNickname) { | 
| -	newNickname[++end] = '1'; | 
| -	PORT_Memset(&newNickname[end + 1], '0', len - end); | 
| -	newNickname[len + 1] = 0; | 
| -    } else { | 
| -	PORT_Free(nickname); | 
| -    } | 
| -    return newNickname; | 
| -} | 
| - | 
| -/* | 
| - * merge a certificate object | 
| - * | 
| - * Use the high level NSS calls to extract and import the certificate. | 
| - */ | 
| -static SECStatus | 
| -pk11_mergeCert(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, | 
| -		CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) | 
| -{ | 
| -    CERTCertificate *sourceCert = NULL; | 
| -    CK_OBJECT_HANDLE targetCertID = CK_INVALID_HANDLE; | 
| -    char *nickname = NULL; | 
| -    SECStatus rv = SECSuccess; | 
| -    PRArenaPool *arena = NULL; | 
| -    CK_ATTRIBUTE sourceCKAID = {CKA_ID, NULL, 0}; | 
| -    CK_ATTRIBUTE targetCKAID = {CKA_ID, NULL, 0}; | 
| -    SECStatus lrv = SECSuccess; | 
| -    int error; | 
| - | 
| - | 
| -    sourceCert = PK11_MakeCertFromHandle(sourceSlot, id, NULL); | 
| -    if (sourceCert == NULL) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| - | 
| -    nickname = PK11_GetObjectNickname(sourceSlot, id); | 
| - | 
| -    /* The database code will prevent nickname collisions for certs with | 
| -     * different subjects. This code will prevent us from getting | 
| -     * actual import errors */ | 
| -    if (nickname) { | 
| -	const char *tokenName = PK11_GetTokenName(targetSlot); | 
| -	char *tokenNickname = NULL; | 
| - | 
| -	do { | 
| -	    tokenNickname = PR_smprintf("%s:%s",tokenName, nickname); | 
| -	    if (!tokenNickname) { | 
| -		break; | 
| -	    } | 
| -	    if (!SEC_CertNicknameConflict(tokenNickname, | 
| -			&sourceCert->derSubject, CERT_GetDefaultCertDB())) { | 
| -		break; | 
| -	     } | 
| -	    nickname = pk11_IncrementNickname(nickname); | 
| -	    if (!nickname) { | 
| -		break; | 
| -	    } | 
| -	    PR_smprintf_free(tokenNickname); | 
| -	} while (1); | 
| -	if (tokenNickname) { | 
| -	    PR_smprintf_free(tokenNickname); | 
| -	} | 
| -    } | 
| - | 
| - | 
| - | 
| -    /* see if the cert is already there */ | 
| -    targetCertID = PK11_FindCertInSlot(targetSlot, sourceCert, targetPwArg); | 
| -    if (targetCertID == CK_INVALID_HANDLE) { | 
| -	/* cert doesn't exist load the cert in. */ | 
| -	/* OK for the nickname to be NULL, not all certs have nicknames */ | 
| -	rv = PK11_ImportCert(targetSlot, sourceCert, CK_INVALID_HANDLE, | 
| -			     nickname, PR_FALSE); | 
| -	goto done; | 
| -    } | 
| - | 
| -    /* the cert already exists, see if the nickname and/or  CKA_ID need | 
| -     * to be updated */ | 
| - | 
| -    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); | 
| -    if (arena == NULL) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| - | 
| -    /* does our source have a CKA_ID ? */ | 
| -    rv = PK11_GetAttributes(arena, sourceSlot, id,  &sourceCKAID, 1); | 
| -    if (rv != SECSuccess) { | 
| -	sourceCKAID.ulValueLen = 0; | 
| -    } | 
| - | 
| -    /* if we have a source CKA_ID, see of we need to update the | 
| -     * target's CKA_ID */ | 
| -    if (sourceCKAID.ulValueLen != 0) { | 
| -	rv = PK11_GetAttributes(arena, targetSlot, targetCertID, | 
| -				    &targetCKAID, 1); | 
| -	if (rv != SECSuccess) { | 
| -	    targetCKAID.ulValueLen = 0; | 
| -	} | 
| -	/* if the target has no CKA_ID, update it from the source */ | 
| -	if (targetCKAID.ulValueLen == 0) { | 
| -	    lrv=pk11_setAttributes(targetSlot, targetCertID, &sourceCKAID, 1); | 
| -	    if (lrv != SECSuccess) { | 
| -		error = PORT_GetError(); | 
| -	    } | 
| -	} | 
| -    } | 
| -    rv = SECSuccess; | 
| - | 
| -    /* now check if we need to update the nickname */ | 
| -    if (nickname && *nickname) { | 
| -	char *targetname; | 
| -	targetname = PK11_GetObjectNickname(targetSlot, targetCertID); | 
| -	if (!targetname || !*targetname) { | 
| -	    /* target has no nickname, or it's empty, update it */ | 
| -	    rv = PK11_SetObjectNickname(targetSlot, targetCertID, nickname); | 
| -	} | 
| -	if (targetname) { | 
| -	    PORT_Free(targetname); | 
| -	} | 
| -    } | 
| - | 
| -    /* restore the error code if CKA_ID failed, but nickname didn't */ | 
| -    if ((rv == SECSuccess) && (lrv != SECSuccess)) { | 
| -	rv = lrv; | 
| -	PORT_SetError(error); | 
| -    } | 
| - | 
| -done: | 
| -    if (nickname) { | 
| -	PORT_Free(nickname); | 
| -    } | 
| -    if (sourceCert) { | 
| -	CERT_DestroyCertificate(sourceCert); | 
| -    } | 
| -    if (arena) { | 
| -         PORT_FreeArena(arena,PR_FALSE); | 
| -    } | 
| -    return rv; | 
| -} | 
| - | 
| - | 
| -/************************************************************************* | 
| - * | 
| - *            Crls | 
| - * | 
| - *************************************************************************/ | 
| - | 
| -/* | 
| - * Use the raw PKCS #11 interface to merge the CRLs. | 
| - * | 
| - * In the case where of collision, choose the newest CRL that is valid. | 
| - */ | 
| -static SECStatus | 
| -pk11_mergeCrl(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, | 
| -		CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) | 
| -{ | 
| -    CK_OBJECT_HANDLE targetCrlID; | 
| -    PRArenaPool *arena = NULL; | 
| -    SECStatus rv = SECSuccess; | 
| -    CK_ATTRIBUTE crlTemplate[] = { | 
| -	{ CKA_SUBJECT, NULL, 0 }, | 
| -	{ CKA_CLASS, NULL, 0 }, | 
| -	{ CKA_NSS_KRL, NULL, 0 } | 
| -    }; | 
| -    CK_ULONG crlTemplateCount = sizeof(crlTemplate)/sizeof(crlTemplate[0]); | 
| -    CK_ATTRIBUTE crlCopyTemplate[] = { | 
| -	{ CKA_CLASS, NULL, 0 }, | 
| -	{ CKA_TOKEN, NULL, 0 }, | 
| -	{ CKA_LABEL, NULL, 0 }, | 
| -	{ CKA_PRIVATE, NULL, 0 }, | 
| -	{ CKA_MODIFIABLE, NULL, 0 }, | 
| -	{ CKA_SUBJECT, NULL, 0 }, | 
| -	{ CKA_NSS_KRL, NULL, 0 }, | 
| -	{ CKA_NSS_URL, NULL, 0 }, | 
| -	{ CKA_VALUE, NULL, 0 } | 
| -    }; | 
| -    CK_ULONG crlCopyTemplateCount = | 
| -		sizeof(crlCopyTemplate)/sizeof(crlCopyTemplate[0]); | 
| - | 
| -    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); | 
| -    if (arena == NULL) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| -    /* check to see if the crl is already in the target slot */ | 
| -    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, crlTemplate, | 
| -				crlTemplateCount, id, &targetCrlID); | 
| -    if (rv != SECSuccess) { | 
| -	goto done; | 
| -    } | 
| -    if (targetCrlID != CK_INVALID_HANDLE) { | 
| -	/* we already have a CRL, check to see which is more up-to-date. */ | 
| -	goto done; | 
| -    } | 
| - | 
| -    /* load the CRL into the target token. */ | 
| -    rv = pk11_copyAttributes(arena, targetSlot, targetCrlID, sourceSlot, id, | 
| -				crlCopyTemplate, crlCopyTemplateCount); | 
| -done: | 
| -    if (arena) { | 
| -         PORT_FreeArena(arena,PR_FALSE); | 
| -    } | 
| -    return rv; | 
| -} | 
| - | 
| -/************************************************************************* | 
| - * | 
| - *            SMIME objects | 
| - * | 
| - *************************************************************************/ | 
| - | 
| -/* | 
| - * use the raw PKCS #11 interface to merge the S/MIME records | 
| - */ | 
| -static SECStatus | 
| -pk11_mergeSmime(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, | 
| -		CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) | 
| -{ | 
| -    CK_OBJECT_HANDLE targetSmimeID; | 
| -    PRArenaPool *arena = NULL; | 
| -    SECStatus rv = SECSuccess; | 
| -    CK_ATTRIBUTE smimeTemplate[] = { | 
| -	{ CKA_SUBJECT, NULL, 0 }, | 
| -	{ CKA_NSS_EMAIL, NULL, 0 }, | 
| -	{ CKA_CLASS, NULL, 0 }, | 
| -    }; | 
| -    CK_ULONG smimeTemplateCount = | 
| -		sizeof(smimeTemplate)/sizeof(smimeTemplate[0]); | 
| -    CK_ATTRIBUTE smimeCopyTemplate[] = { | 
| -	{ CKA_CLASS, NULL, 0 }, | 
| -	{ CKA_TOKEN, NULL, 0 }, | 
| -	{ CKA_LABEL, NULL, 0 }, | 
| -	{ CKA_PRIVATE, NULL, 0 }, | 
| -	{ CKA_MODIFIABLE, NULL, 0 }, | 
| -	{ CKA_SUBJECT, NULL, 0 }, | 
| -	{ CKA_NSS_EMAIL, NULL, 0 }, | 
| -	{ CKA_NSS_SMIME_TIMESTAMP, NULL, 0 }, | 
| -	{ CKA_VALUE, NULL, 0 } | 
| -    }; | 
| -    CK_ULONG smimeCopyTemplateCount = | 
| -		sizeof(smimeCopyTemplate)/sizeof(smimeCopyTemplate[0]); | 
| - | 
| -    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); | 
| -    if (arena == NULL) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| -    /* check to see if the crl is already in the target slot */ | 
| -    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, smimeTemplate, | 
| -				smimeTemplateCount, id, &targetSmimeID); | 
| -    if (rv != SECSuccess) { | 
| -	goto done; | 
| -    } | 
| -    if (targetSmimeID != CK_INVALID_HANDLE) { | 
| -	/* we already have a SMIME record */ | 
| -	goto done; | 
| -    } | 
| - | 
| -    /* load the SMime Record into the target token. */ | 
| -    rv = pk11_copyAttributes(arena, targetSlot, targetSmimeID, sourceSlot, id, | 
| -				smimeCopyTemplate, smimeCopyTemplateCount); | 
| -done: | 
| -    if (arena) { | 
| -         PORT_FreeArena(arena,PR_FALSE); | 
| -    } | 
| -    return rv; | 
| -} | 
| - | 
| -/************************************************************************* | 
| - * | 
| - *            Trust Objects | 
| - * | 
| - *************************************************************************/ | 
| - | 
| - | 
| -/* | 
| - * decide which trust record entry wins. PR_TRUE (source) or PR_FALSE (target) | 
| - */ | 
| -#define USE_TARGET PR_FALSE | 
| -#define USE_SOURCE PR_TRUE | 
| -PRBool | 
| -pk11_mergeTrustEntry(CK_ATTRIBUTE *target, CK_ATTRIBUTE *source) | 
| -{ | 
| -    CK_ULONG targetTrust = (target->ulValueLen == sizeof (CK_LONG)) ? | 
| -		*(CK_ULONG *)target->pValue : CKT_NSS_TRUST_UNKNOWN; | 
| -    CK_ULONG sourceTrust = (source->ulValueLen == sizeof (CK_LONG)) ? | 
| -		*(CK_ULONG *)source->pValue : CKT_NSS_TRUST_UNKNOWN; | 
| - | 
| -    /* | 
| -     * Examine a single entry and deside if the source or target version | 
| -     * should win out. When all the entries have been checked, if there is | 
| -     * any case we need to update, we will write the whole source record | 
| -     * to the target database. That means for each individual record, if the | 
| -     * target wins, we need to update the source (in case later we have a | 
| -     * case where the source wins). If the source wins, it already | 
| -     */ | 
| -    if (sourceTrust == targetTrust) { | 
| -	return USE_TARGET;  /* which equates to 'do nothing' */ | 
| -    } | 
| - | 
| -    if (sourceTrust == CKT_NSS_TRUST_UNKNOWN) { | 
| -	return USE_TARGET; | 
| -    } | 
| - | 
| -    /* target has no idea, use the source's idea of the trust value */ | 
| -    if (targetTrust == CKT_NSS_TRUST_UNKNOWN) { | 
| -	/* source overwrites the target */ | 
| -	return USE_SOURCE; | 
| -    } | 
| - | 
| -    /* so both the target and the source have some idea of what this | 
| -     * trust attribute should be, and neither agree exactly. | 
| -     * At this point, we prefer 'hard' attributes over 'soft' ones. | 
| -     * 'hard' ones are CKT_NSS_TRUSTED, CKT_NSS_TRUSTED_DELEGATOR, and | 
| -     * CKT_NSS_UNTRUTED. Soft ones are ones which don't change the | 
| -     * actual trust of the cert (CKT_MUST_VERIFY, CKT_NSS_VALID, | 
| -     * CKT_NSS_VALID_DELEGATOR). | 
| -     */ | 
| -    if ((sourceTrust == CKT_NSS_MUST_VERIFY_TRUST) | 
| -	|| (sourceTrust == CKT_NSS_VALID_DELEGATOR)) { | 
| -	return USE_TARGET; | 
| -    } | 
| -    if ((targetTrust == CKT_NSS_MUST_VERIFY_TRUST) | 
| -	|| (targetTrust == CKT_NSS_VALID_DELEGATOR)) { | 
| -	/* source overrites the target */ | 
| -	return USE_SOURCE; | 
| -    } | 
| - | 
| -    /* both have hard attributes, we have a conflict, let the target win. */ | 
| -    return USE_TARGET; | 
| -} | 
| -/* | 
| - * use the raw PKCS #11 interface to merge the S/MIME records | 
| - */ | 
| -static SECStatus | 
| -pk11_mergeTrust(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, | 
| -		CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) | 
| -{ | 
| -    CK_OBJECT_HANDLE targetTrustID; | 
| -    PRArenaPool *arena = NULL; | 
| -    SECStatus rv = SECSuccess; | 
| -    int error = 0; | 
| -    CK_ATTRIBUTE trustTemplate[] = { | 
| -	{ CKA_ISSUER, NULL, 0 }, | 
| -	{ CKA_SERIAL_NUMBER, NULL, 0 }, | 
| -	{ CKA_CLASS, NULL, 0 }, | 
| -    }; | 
| -    CK_ULONG trustTemplateCount = | 
| -		sizeof(trustTemplate)/sizeof(trustTemplate[0]); | 
| -    CK_ATTRIBUTE trustCopyTemplate[] = { | 
| -	{ CKA_CLASS, NULL, 0 }, | 
| -	{ CKA_TOKEN, NULL, 0 }, | 
| -	{ CKA_LABEL, NULL, 0 }, | 
| -	{ CKA_PRIVATE, NULL, 0 }, | 
| -	{ CKA_MODIFIABLE, NULL, 0 }, | 
| -	{ CKA_ISSUER, NULL, 0}, | 
| -	{ CKA_SERIAL_NUMBER, NULL, 0}, | 
| -	{ CKA_CERT_SHA1_HASH, NULL, 0 }, | 
| -	{ CKA_CERT_MD5_HASH, NULL, 0 }, | 
| -	{ CKA_TRUST_SERVER_AUTH, NULL, 0 }, | 
| -	{ CKA_TRUST_CLIENT_AUTH, NULL, 0 }, | 
| -	{ CKA_TRUST_CODE_SIGNING, NULL, 0 }, | 
| -	{ CKA_TRUST_EMAIL_PROTECTION, NULL, 0 }, | 
| -	{ CKA_TRUST_STEP_UP_APPROVED, NULL, 0 } | 
| -    }; | 
| -    CK_ULONG trustCopyTemplateCount = | 
| -		sizeof(trustCopyTemplate)/sizeof(trustCopyTemplate[0]); | 
| - | 
| -    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); | 
| -    if (arena == NULL) { | 
| -	rv = SECFailure; | 
| -	goto done; | 
| -    } | 
| -    /* check to see if the crl is already in the target slot */ | 
| -    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, trustTemplate, | 
| -				trustTemplateCount, id, &targetTrustID); | 
| -    if (rv != SECSuccess) { | 
| -	goto done; | 
| -    } | 
| -    if (targetTrustID != CK_INVALID_HANDLE) { | 
| -	/* a matching trust record already exists, merge it in */ | 
| -	CK_ATTRIBUTE_TYPE trustAttrs[] = { | 
| -	    CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, | 
| -	    CKA_TRUST_CODE_SIGNING, CKA_TRUST_EMAIL_PROTECTION, | 
| -	    CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, | 
| -	    CKA_TRUST_TIME_STAMPING | 
| -	}; | 
| -	CK_ULONG trustAttrsCount = | 
| -		sizeof(trustAttrs)/sizeof(trustAttrs[0]); | 
| - | 
| -	CK_ULONG i; | 
| -	CK_ATTRIBUTE targetTemplate, sourceTemplate; | 
| - | 
| -	/* existing trust record, merge the two together */ | 
| -        for (i=0; i < trustAttrsCount; i++) { | 
| -	    targetTemplate.type = sourceTemplate.type = trustAttrs[i]; | 
| -	    targetTemplate.pValue = sourceTemplate.pValue = NULL; | 
| -	    targetTemplate.ulValueLen = sourceTemplate.ulValueLen = 0; | 
| -	    PK11_GetAttributes(arena, sourceSlot, id, &sourceTemplate, 1); | 
| -	    PK11_GetAttributes(arena, targetSlot, targetTrustID, | 
| -							&targetTemplate, 1); | 
| -	    if (pk11_mergeTrustEntry(&targetTemplate, &sourceTemplate)) { | 
| -		/* source wins, write out the source attribute to the target */ | 
| -		SECStatus lrv = pk11_setAttributes(targetSlot, targetTrustID, | 
| -				   &sourceTemplate, 1); | 
| -		if (lrv != SECSuccess) { | 
| -		    rv = SECFailure; | 
| -		    error = PORT_GetError(); | 
| -		} | 
| -	    } | 
| -	} | 
| - | 
| -	/* handle step */ | 
| -	sourceTemplate.type = CKA_TRUST_STEP_UP_APPROVED; | 
| -	sourceTemplate.pValue = NULL; | 
| -	sourceTemplate.ulValueLen = 0; | 
| - | 
| -	/* if the source has steup set, then set it in the target */ | 
| -	PK11_GetAttributes(arena, sourceSlot, id, &sourceTemplate, 1); | 
| -	if ((sourceTemplate.ulValueLen == sizeof(CK_BBOOL)) && | 
| -		(sourceTemplate.pValue) && | 
| -		(*(CK_BBOOL *)sourceTemplate.pValue == CK_TRUE)) { | 
| -	    SECStatus lrv = pk11_setAttributes(targetSlot, targetTrustID, | 
| -				   &sourceTemplate, 1); | 
| -	    if (lrv != SECSuccess) { | 
| -		rv = SECFailure; | 
| -		error = PORT_GetError(); | 
| -	    } | 
| -	} | 
| - | 
| -	goto done; | 
| - | 
| -    } | 
| - | 
| -    /* load the new trust Record into the target token. */ | 
| -    rv = pk11_copyAttributes(arena, targetSlot, targetTrustID, sourceSlot, id, | 
| -				trustCopyTemplate, trustCopyTemplateCount); | 
| -done: | 
| -    if (arena) { | 
| -         PORT_FreeArena(arena,PR_FALSE); | 
| -    } | 
| - | 
| -    /* restore the error code */ | 
| -    if (rv == SECFailure && error) { | 
| -	PORT_SetError(error); | 
| -    } | 
| - | 
| -    return rv; | 
| -} | 
| - | 
| -/************************************************************************* | 
| - * | 
| - *            Central merge code | 
| - * | 
| - *************************************************************************/ | 
| -/* | 
| - * merge a single object from sourceToken to targetToken | 
| - */ | 
| -static SECStatus | 
| -pk11_mergeObject(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, | 
| -		CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg) | 
| -{ | 
| - | 
| -    CK_OBJECT_CLASS objClass; | 
| - | 
| - | 
| -    objClass = PK11_ReadULongAttribute(sourceSlot, id, CKA_CLASS); | 
| -    if (objClass == (CK_ULONG) -1) { | 
| -	PORT_SetError( SEC_ERROR_UNKNOWN_OBJECT_TYPE ); | 
| -	return SECFailure; | 
| -    } | 
| - | 
| -    switch (objClass) { | 
| -    case CKO_CERTIFICATE: | 
| -	return pk11_mergeCert(targetSlot, sourceSlot, id, | 
| -					targetPwArg, sourcePwArg); | 
| -    case CKO_NSS_TRUST: | 
| -	return pk11_mergeTrust(targetSlot, sourceSlot, id, | 
| -					targetPwArg, sourcePwArg); | 
| -    case CKO_PUBLIC_KEY: | 
| -	return pk11_mergePublicKey(targetSlot, sourceSlot, id, | 
| -					targetPwArg, sourcePwArg); | 
| -    case CKO_PRIVATE_KEY: | 
| -	return pk11_mergePrivateKey(targetSlot, sourceSlot, id, | 
| -					targetPwArg, sourcePwArg); | 
| -    case CKO_SECRET_KEY: | 
| -	return pk11_mergeSecretKey(targetSlot, sourceSlot, id, | 
| -					targetPwArg, sourcePwArg); | 
| -    case CKO_NSS_CRL: | 
| -	return pk11_mergeCrl(targetSlot, sourceSlot, id, | 
| -					targetPwArg, sourcePwArg); | 
| -    case CKO_NSS_SMIME: | 
| -	return pk11_mergeSmime(targetSlot, sourceSlot, id, | 
| -					targetPwArg, sourcePwArg); | 
| -    default: | 
| -	break; | 
| -    } | 
| - | 
| -    PORT_SetError( SEC_ERROR_UNKNOWN_OBJECT_TYPE ); | 
| -    return SECFailure; | 
| -} | 
| - | 
| -PK11MergeLogNode * | 
| -pk11_newMergeLogNode(PRArenaPool *arena, | 
| -		     PK11SlotInfo *slot, CK_OBJECT_HANDLE id, int error) | 
| -{ | 
| -    PK11MergeLogNode *newLog; | 
| -    PK11GenericObject *obj; | 
| - | 
| -    newLog = PORT_ArenaZNew(arena, PK11MergeLogNode); | 
| -    if (newLog == NULL) { | 
| -	return NULL; | 
| -    } | 
| - | 
| -    obj = PORT_ArenaZNew(arena, PK11GenericObject); | 
| -    if ( !obj ) { | 
| -	return NULL; | 
| -    } | 
| - | 
| -    /* initialize it */ | 
| -    obj->slot = slot; | 
| -    obj->objectID = id; | 
| - | 
| -    newLog->object= obj; | 
| -    newLog->error = error; | 
| -    return newLog; | 
| -} | 
| - | 
| -/* | 
| - * walk down each entry and merge it. keep track of the errors in the log | 
| - */ | 
| -static SECStatus | 
| -pk11_mergeByObjectIDs(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, | 
| -		CK_OBJECT_HANDLE *objectIDs, int count, | 
| -		PK11MergeLog *log, void *targetPwArg, void *sourcePwArg) | 
| -{ | 
| -    SECStatus rv = SECSuccess; | 
| -    int error, i; | 
| - | 
| -    for (i=0; i < count; i++) { | 
| -	/* try to update the entire database. On failure, keep going, | 
| -	 * but remember the error to report back to the caller */ | 
| -	SECStatus lrv; | 
| -	PK11MergeLogNode *newLog; | 
| - | 
| -	lrv= pk11_mergeObject(targetSlot, sourceSlot, objectIDs[i], | 
| -				targetPwArg, sourcePwArg); | 
| -	if (lrv == SECSuccess) { | 
| -	   /* merged with no problem, go to next object */ | 
| -	   continue; | 
| -	} | 
| - | 
| -	/* remember that we failed and why */ | 
| -	rv = SECFailure; | 
| -	error = PORT_GetError(); | 
| - | 
| -	/* log the errors */ | 
| -	if (!log) { | 
| -	    /* not logging, go to next entry */ | 
| -	    continue; | 
| -	} | 
| -	newLog = pk11_newMergeLogNode(log->arena, sourceSlot, | 
| -				      objectIDs[i], error); | 
| -	if (!newLog) { | 
| -	    /* failed to allocate entry, just keep going */ | 
| -	    continue; | 
| -	} | 
| - | 
| -	/* link in the errorlog entry */ | 
| -	newLog->next = NULL; | 
| -	if (log->tail) { | 
| -	    log->tail->next = newLog; | 
| -	} else { | 
| -	    log->head = newLog; | 
| -	} | 
| -	newLog->prev = log->tail; | 
| -	log->tail = newLog; | 
| -    } | 
| - | 
| -    /* restore the last error code */ | 
| -    if (rv != SECSuccess) { | 
| -	PORT_SetError(error); | 
| -    } | 
| -    return rv; | 
| -} | 
| - | 
| -/* | 
| - * Merge all the records in sourceSlot that aren't in targetSlot | 
| - * | 
| - *   This function will return failure if not all the objects | 
| - *   successfully merged. | 
| - * | 
| - *   Applications can pass in an optional error log which will record | 
| - *   each failing object and why it failed to import. PK11MergeLog | 
| - *   is modelled after the CERTVerifyLog. | 
| - */ | 
| -SECStatus | 
| -PK11_MergeTokens(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot, | 
| -		PK11MergeLog *log, void *targetPwArg, void *sourcePwArg) | 
| -{ | 
| -    SECStatus rv = SECSuccess, lrv = SECSuccess; | 
| -    int error, count = 0; | 
| -    CK_ATTRIBUTE search[2]; | 
| -    CK_OBJECT_HANDLE *objectIDs = NULL; | 
| -    CK_BBOOL ck_true = CK_TRUE; | 
| -    CK_OBJECT_CLASS privKey = CKO_PRIVATE_KEY; | 
| - | 
| -    PK11_SETATTRS(&search[0], CKA_TOKEN, &ck_true, sizeof(ck_true)); | 
| -    PK11_SETATTRS(&search[1], CKA_CLASS, &privKey, sizeof(privKey)); | 
| -    /* | 
| -     * make sure both tokens are already authenticated if need be. | 
| -     */ | 
| -    rv = PK11_Authenticate(targetSlot, PR_TRUE, targetPwArg); | 
| -    if (rv != SECSuccess) { | 
| -	goto loser; | 
| -    } | 
| -    rv = PK11_Authenticate(sourceSlot, PR_TRUE, sourcePwArg); | 
| -    if (rv != SECSuccess) { | 
| -	goto loser; | 
| -    } | 
| - | 
| -    /* turns out the old DB's are rather fragile if the private keys aren't | 
| -     * merged in first, so do the private keys explicity. */ | 
| -    objectIDs = pk11_FindObjectsByTemplate(sourceSlot, search, 2, &count); | 
| -    if (objectIDs) { | 
| -	lrv = pk11_mergeByObjectIDs(targetSlot, sourceSlot, | 
| -				    objectIDs, count, log, | 
| -				    targetPwArg, sourcePwArg); | 
| -	if (lrv != SECSuccess) { | 
| -	    error = PORT_GetError(); | 
| -	} | 
| -	PORT_Free(objectIDs); | 
| -	count = 0; | 
| -    } | 
| - | 
| -    /* now do the rest  (NOTE: this will repeat the private keys, but | 
| -     * that shouldnt' be an issue as we will notice they are already | 
| -     * merged in */ | 
| -    objectIDs = pk11_FindObjectsByTemplate(sourceSlot, search, 1, &count); | 
| -    if (!objectIDs) { | 
| -	rv = SECFailure; | 
| -	goto loser; | 
| -    } | 
| - | 
| -    rv = pk11_mergeByObjectIDs(targetSlot, sourceSlot, objectIDs, count, log, | 
| -			targetPwArg, sourcePwArg); | 
| -    if (rv == SECSuccess) { | 
| -	/* if private keys failed, but the rest succeeded, be sure to let | 
| -	 * the caller know that private keys failed and why. | 
| -	 * NOTE: this is highly unlikely since the same keys that failed | 
| -	 * in the previous merge call will most likely fail in this one */ | 
| -	if (lrv != SECSuccess) { | 
| -	    rv = lrv; | 
| -	    PORT_SetError(error); | 
| -	} | 
| -    } | 
| - | 
| -loser: | 
| -    if (objectIDs) { | 
| -	PORT_Free(objectIDs); | 
| -    } | 
| -    return rv; | 
| -} | 
| - | 
| -PK11MergeLog * | 
| -PK11_CreateMergeLog(void) | 
| -{ | 
| -    PRArenaPool *arena; | 
| -    PK11MergeLog *log; | 
| - | 
| -    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); | 
| -    if (arena == NULL) { | 
| -	return NULL; | 
| -    } | 
| - | 
| -    log = PORT_ArenaZNew(arena, PK11MergeLog); | 
| -    if (log == NULL) { | 
| -         PORT_FreeArena(arena,PR_FALSE); | 
| -	return NULL; | 
| -    } | 
| -    log->arena = arena; | 
| -    log->version = 1; | 
| -    return log; | 
| -} | 
| - | 
| -void | 
| -PK11_DestroyMergeLog(PK11MergeLog *log) | 
| -{ | 
| -   if (log && log->arena) { | 
| -	PORT_FreeArena(log->arena, PR_FALSE); | 
| -    } | 
| -} | 
|  |