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); |
- } |
-} |