security/nss/lib/pk11wrap/pk11merge.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial