2 * Merge the source token into the target token.
17 /*************************************************************************
19 * short utilities to aid in the merge
21 *************************************************************************/
24 * write a bunch of attributes out to an existing object.
27 pk11_setAttributes(PK11SlotInfo
*slot
, CK_OBJECT_HANDLE id
,
28 CK_ATTRIBUTE
*setTemplate
, CK_ULONG setTemplCount
)
31 CK_SESSION_HANDLE rwsession
;
33 rwsession
= PK11_GetRWSession(slot
);
34 if (rwsession
== CK_INVALID_SESSION
) {
35 PORT_SetError(SEC_ERROR_BAD_DATA
);
38 crv
= PK11_GETTAB(slot
)->C_SetAttributeValue(rwsession
, id
,
39 setTemplate
, setTemplCount
);
40 PK11_RestoreROSession(slot
, rwsession
);
42 PORT_SetError(PK11_MapError(crv
));
50 * copy a template of attributes from a source object to a target object.
51 * if target object is not given, create it.
54 pk11_copyAttributes(PRArenaPool
*arena
,
55 PK11SlotInfo
*targetSlot
, CK_OBJECT_HANDLE targetID
,
56 PK11SlotInfo
*sourceSlot
, CK_OBJECT_HANDLE sourceID
,
57 CK_ATTRIBUTE
*copyTemplate
, CK_ULONG copyTemplateCount
)
59 SECStatus rv
= PK11_GetAttributes(arena
, sourceSlot
, sourceID
,
60 copyTemplate
, copyTemplateCount
);
61 if (rv
!= SECSuccess
) {
64 if (targetID
== CK_INVALID_HANDLE
) {
65 /* we need to create the object */
66 rv
= PK11_CreateNewObject(targetSlot
, CK_INVALID_SESSION
,
67 copyTemplate
, copyTemplateCount
, PR_TRUE
, &targetID
);
69 /* update the existing object with the new attributes */
70 rv
= pk11_setAttributes(targetSlot
, targetID
,
71 copyTemplate
, copyTemplateCount
);
77 * look for a matching object across tokens.
80 pk11_matchAcrossTokens(PRArenaPool
*arena
, PK11SlotInfo
*targetSlot
,
81 PK11SlotInfo
*sourceSlot
,
82 CK_ATTRIBUTE
*template, CK_ULONG tsize
,
83 CK_OBJECT_HANDLE id
, CK_OBJECT_HANDLE
*peer
)
87 *peer
= CK_INVALID_HANDLE
;
89 crv
= PK11_GetAttributes(arena
, sourceSlot
, id
, template, tsize
);
91 PORT_SetError( PK11_MapError(crv
) );
95 if (template[0].ulValueLen
== -1) {
96 crv
= CKR_ATTRIBUTE_TYPE_INVALID
;
97 PORT_SetError( PK11_MapError(crv
) );
101 *peer
= pk11_FindObjectByTemplate(targetSlot
, template, tsize
);
109 * Encrypt using key and parameters
112 pk11_encrypt(PK11SymKey
*symKey
, CK_MECHANISM_TYPE mechType
, SECItem
*param
,
113 SECItem
*input
, SECItem
**output
)
115 PK11Context
*ctxt
= NULL
;
116 SECStatus rv
= SECSuccess
;
119 SECITEM_FreeItem(*output
,PR_TRUE
);
121 *output
= SECITEM_AllocItem(NULL
, NULL
, input
->len
+20 /*slop*/);
127 ctxt
= PK11_CreateContextBySymKey(mechType
, CKA_ENCRYPT
, symKey
, param
);
133 rv
= PK11_CipherOp(ctxt
, (*output
)->data
,
134 (int *)&((*output
)->len
),
135 (*output
)->len
, input
->data
, input
->len
);
140 PK11_DestroyContext(ctxt
,PR_TRUE
);
142 if (rv
!= SECSuccess
) {
144 SECITEM_FreeItem(*output
, PR_TRUE
);
153 /*************************************************************************
157 *************************************************************************/
160 * Fetch the key usage based on the pkcs #11 flags
163 pk11_getPrivateKeyUsage(PK11SlotInfo
*slot
, CK_OBJECT_HANDLE id
)
165 unsigned int usage
= 0;
167 if ((PK11_HasAttributeSet(slot
, id
, CKA_UNWRAP
) ||
168 PK11_HasAttributeSet(slot
,id
, CKA_DECRYPT
))) {
169 usage
|= KU_KEY_ENCIPHERMENT
;
171 if (PK11_HasAttributeSet(slot
, id
, CKA_DERIVE
)) {
172 usage
|= KU_KEY_AGREEMENT
;
174 if ((PK11_HasAttributeSet(slot
, id
, CKA_SIGN_RECOVER
) ||
175 PK11_HasAttributeSet(slot
, id
, CKA_SIGN
))) {
176 usage
|= KU_DIGITAL_SIGNATURE
;
183 * merge a private key,
185 * Private keys are merged using PBE wrapped keys with a random
186 * value as the 'password'. Once the base key is moved, The remaining
187 * attributes (SUBJECT) is copied.
190 pk11_mergePrivateKey(PK11SlotInfo
*targetSlot
, PK11SlotInfo
*sourceSlot
,
191 CK_OBJECT_HANDLE id
, void *targetPwArg
, void *sourcePwArg
)
193 SECKEYPrivateKey
*sourceKey
= NULL
;
194 CK_OBJECT_HANDLE targetKeyID
;
195 SECKEYEncryptedPrivateKeyInfo
*epki
= NULL
;
196 char *nickname
= NULL
;
200 PRArenaPool
*arena
= NULL
;
201 SECStatus rv
= SECSuccess
;
202 unsigned int keyUsage
;
203 unsigned char randomData
[SHA1_LENGTH
];
204 SECOidTag algTag
= SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC
;
205 CK_ATTRIBUTE privTemplate
[] = {
207 { CKA_CLASS
, NULL
, 0 }
209 CK_ULONG privTemplateCount
= sizeof(privTemplate
)/sizeof(privTemplate
[0]);
210 CK_ATTRIBUTE privCopyTemplate
[] = {
211 { CKA_SUBJECT
, NULL
, 0 }
213 CK_ULONG privCopyTemplateCount
=
214 sizeof(privCopyTemplate
)/sizeof(privCopyTemplate
[0]);
216 arena
= PORT_NewArena( DER_DEFAULT_CHUNKSIZE
);
222 /* check to see if the key is already in the target slot */
223 rv
= pk11_matchAcrossTokens(arena
, targetSlot
, sourceSlot
, privTemplate
,
224 privTemplateCount
, id
, &targetKeyID
);
225 if (rv
!= SECSuccess
) {
229 if (targetKeyID
!= CK_INVALID_HANDLE
) {
230 /* match found, not an error ... */
234 /* get an NSS representation of our source key */
235 sourceKey
= PK11_MakePrivKey(sourceSlot
, nullKey
, PR_FALSE
,
237 if (sourceKey
== NULL
) {
242 /* Load the private key */
243 /* generate a random pwitem */
244 rv
= PK11_GenerateRandom(randomData
, sizeof(randomData
));
245 if (rv
!= SECSuccess
) {
248 pwitem
.data
= randomData
;
249 pwitem
.len
= sizeof(randomData
);
250 /* fetch the private key encrypted */
251 epki
= PK11_ExportEncryptedPrivKeyInfo(sourceSlot
, algTag
, &pwitem
,
252 sourceKey
, 1, sourcePwArg
);
257 nickname
= PK11_GetObjectNickname(sourceSlot
, id
);
258 /* NULL nickanme is fine (in fact is often normal) */
260 nickItem
.data
= (unsigned char *)nickname
;
261 nickItem
.len
= PORT_Strlen(nickname
);
263 keyUsage
= pk11_getPrivateKeyUsage(sourceSlot
, id
);
264 /* pass in the CKA_ID */
265 publicValue
.data
= privTemplate
[0].pValue
;
266 publicValue
.len
= privTemplate
[0].ulValueLen
;
267 rv
= PK11_ImportEncryptedPrivateKeyInfo(targetSlot
, epki
, &pwitem
,
268 nickname
? &nickItem
: NULL
, &publicValue
,
269 PR_TRUE
, PR_TRUE
, sourceKey
->keyType
, keyUsage
,
271 if (rv
!= SECSuccess
) {
275 /* make sure it made it */
276 rv
= pk11_matchAcrossTokens(arena
, targetSlot
, sourceSlot
, privTemplate
,
277 privTemplateCount
, id
, &targetKeyID
);
278 if (rv
!= SECSuccess
) {
282 if (targetKeyID
== CK_INVALID_HANDLE
) {
283 /* this time the key should exist */
288 /* fill in remaining attributes */
289 rv
= pk11_copyAttributes(arena
, targetSlot
, targetKeyID
, sourceSlot
, id
,
290 privCopyTemplate
, privCopyTemplateCount
);
292 /* make sure the 'key' is cleared */
293 PORT_Memset(randomData
, 0, sizeof(randomData
));
298 SECKEY_DestroyPrivateKey(sourceKey
);
301 SECKEY_DestroyEncryptedPrivateKeyInfo(epki
, PR_TRUE
);
304 PORT_FreeArena(arena
,PR_FALSE
);
310 /*************************************************************************
314 *************************************************************************/
317 * we need to find a unique CKA_ID.
318 * The basic idea is to just increment the lowest byte.
319 * This code also handles the following corner cases:
320 * 1) the single byte overflows. On overflow we increment the next byte up
321 * and so forth until we have overflowed the entire CKA_ID.
322 * 2) If we overflow the entire CKA_ID we expand it by one byte.
323 * 3) the CKA_ID is non-existant, we create a new one with one byte.
324 * This means no matter what CKA_ID is passed, the result of this function
325 * is always a new CKA_ID, and this function will never return the same
326 * CKA_ID the it has returned in the passed.
329 pk11_incrementID(PRArenaPool
*arena
, CK_ATTRIBUTE
*ptemplate
)
331 unsigned char *buf
= ptemplate
->pValue
;
332 CK_ULONG len
= ptemplate
->ulValueLen
;
334 if (buf
== NULL
|| len
== (CK_ULONG
)-1) {
335 /* we have no valid CKAID, we'll create a basic one byte CKA_ID below */
340 /* walk from the back to front, incrementing
341 * the CKA_ID until we no longer have a carry,
342 * or have hit the front of the id. */
343 for (i
=len
; i
!= 0; i
--) {
346 /* no more carries, the increment is complete */
350 /* we've now overflowed, fall through and expand the CKA_ID by
353 /* if we are here we've run the counter to zero (indicating an overflow).
354 * create an CKA_ID that is all zeros, but has one more zero than
355 * the previous CKA_ID */
356 buf
= PORT_ArenaZAlloc(arena
, len
+1);
360 ptemplate
->pValue
= buf
;
361 ptemplate
->ulValueLen
= len
+1;
367 pk11_getSecretKeyFlags(PK11SlotInfo
*slot
, CK_OBJECT_HANDLE id
)
371 if (PK11_HasAttributeSet(slot
, id
, CKA_UNWRAP
)) {
374 if (PK11_HasAttributeSet(slot
, id
, CKA_WRAP
)) {
377 if (PK11_HasAttributeSet(slot
, id
, CKA_ENCRYPT
)) {
378 flags
|= CKF_ENCRYPT
;
380 if (PK11_HasAttributeSet(slot
, id
, CKA_DECRYPT
)) {
381 flags
|= CKF_DECRYPT
;
383 if (PK11_HasAttributeSet(slot
, id
, CKA_DERIVE
)) {
386 if (PK11_HasAttributeSet(slot
, id
, CKA_SIGN
)) {
389 if (PK11_HasAttributeSet(slot
, id
, CKA_SIGN_RECOVER
)) {
390 flags
|= CKF_SIGN_RECOVER
;
392 if (PK11_HasAttributeSet(slot
, id
, CKA_VERIFY
)) {
395 if (PK11_HasAttributeSet(slot
, id
, CKA_VERIFY_RECOVER
)) {
396 flags
|= CKF_VERIFY_RECOVER
;
401 static const char testString
[] =
402 "My Encrytion Test Data (should be at least 32 bytes long)";
404 * merge a secret key,
406 * Secret keys may collide by CKA_ID as we merge 2 token. If we collide
407 * on the CKA_ID, we need to make sure we are dealing with different keys.
408 * The reason for this is it is possible that we've merged this database
409 * before, and this key could have been merged already. If the keys are
410 * the same, we are done. If they are not, we need to update the CKA_ID of
411 * the source key and try again.
413 * Once we know we have a unique key to merge in, we use NSS's underlying
414 * key Move function which will do a key exchange if necessary to move
415 * the key from one token to another. Then we set the CKA_ID and additional
416 * pkcs #11 attributes.
419 pk11_mergeSecretKey(PK11SlotInfo
*targetSlot
, PK11SlotInfo
*sourceSlot
,
420 CK_OBJECT_HANDLE id
, void *targetPwArg
, void *sourcePwArg
)
422 PK11SymKey
*sourceKey
= NULL
;
423 PK11SymKey
*targetKey
= NULL
;
424 SECItem
*sourceOutput
= NULL
;
425 SECItem
*targetOutput
= NULL
;
426 SECItem
*param
= NULL
;
428 CK_OBJECT_HANDLE targetKeyID
;
430 PRArenaPool
*arena
= NULL
;
431 SECStatus rv
= SECSuccess
;
432 CK_MECHANISM_TYPE keyMechType
, cryptoMechType
;
433 CK_KEY_TYPE sourceKeyType
, targetKeyType
;
434 CK_ATTRIBUTE symTemplate
[] = {
436 { CKA_CLASS
, NULL
, 0 }
438 CK_ULONG symTemplateCount
= sizeof(symTemplate
)/sizeof(symTemplate
[0]);
439 CK_ATTRIBUTE symCopyTemplate
[] = {
440 { CKA_LABEL
, NULL
, 0 }
442 CK_ULONG symCopyTemplateCount
=
443 sizeof(symCopyTemplate
)/sizeof(symCopyTemplate
[0]);
445 arena
= PORT_NewArena( DER_DEFAULT_CHUNKSIZE
);
451 sourceKeyType
= PK11_ReadULongAttribute(sourceSlot
, id
, CKA_KEY_TYPE
);
452 if (sourceKeyType
== (CK_ULONG
) -1) {
457 /* get the key mechanism */
458 keyMechType
= PK11_GetKeyMechanism(sourceKeyType
);
459 /* get a mechanism suitable to encryption.
460 * PK11_GetKeyMechanism returns a mechanism that is unique to the key
461 * type. It tries to return encryption/decryption mechanisms, however
462 * CKM_DES3_CBC uses and abmiguous keyType, so keyMechType is returned as
463 * 'keygen' mechanism. Detect that case here */
464 cryptoMechType
= keyMechType
;
465 if ((keyMechType
== CKM_DES3_KEY_GEN
) ||
466 (keyMechType
== CKM_DES2_KEY_GEN
)) {
467 cryptoMechType
= CKM_DES3_CBC
;
470 sourceKey
= PK11_SymKeyFromHandle(sourceSlot
, NULL
, PK11_OriginDerive
,
471 keyMechType
, id
, PR_FALSE
, sourcePwArg
);
472 if (sourceKey
== NULL
) {
477 /* check to see a key with the same CKA_ID already exists in
478 * the target slot. If it does, then we need to verify if the keys
479 * really matches. If they don't import the key with a new CKA_ID
481 rv
= pk11_matchAcrossTokens(arena
, targetSlot
, sourceSlot
,
482 symTemplate
, symTemplateCount
, id
, &targetKeyID
);
483 if (rv
!= SECSuccess
) {
487 /* set up the input test */
488 input
.data
= (unsigned char *)testString
;
489 input
.len
= PK11_GetBlockSize(cryptoMechType
, NULL
);
494 if (input
.len
== 0) {
495 input
.len
= sizeof (testString
);
497 while (targetKeyID
!= CK_INVALID_HANDLE
) {
498 /* test to see if the keys are identical */
499 targetKeyType
= PK11_ReadULongAttribute(sourceSlot
, id
, CKA_KEY_TYPE
);
500 if (targetKeyType
== sourceKeyType
) {
501 /* same keyType - see if it's the same key */
502 targetKey
= PK11_SymKeyFromHandle(targetSlot
, NULL
,
503 PK11_OriginDerive
, keyMechType
, targetKeyID
, PR_FALSE
,
505 /* get a parameter if we don't already have one */
507 param
= PK11_GenerateNewParam(cryptoMechType
, sourceKey
);
513 /* use the source key to encrypt a reference */
515 rv
= pk11_encrypt(sourceKey
, cryptoMechType
, param
, &input
,
517 if (rv
!= SECSuccess
) {
521 /* encrypt the reference with the target key */
522 rv
= pk11_encrypt(targetKey
, cryptoMechType
, param
, &input
,
524 if (rv
== SECSuccess
) {
525 if (SECITEM_ItemsAreEqual(sourceOutput
, targetOutput
)) {
526 /* they produce the same output, they must be the
530 SECITEM_FreeItem(targetOutput
, PR_TRUE
);
533 PK11_FreeSymKey(targetKey
);
536 /* keys aren't equal, update the KEY_ID and look again */
537 rv
= pk11_incrementID(arena
, &symTemplate
[0]);
538 if (rv
!= SECSuccess
) {
541 targetKeyID
= pk11_FindObjectByTemplate(targetSlot
,
542 symTemplate
, symTemplateCount
);
545 /* we didn't find a matching key, import this one with the new
547 flags
= pk11_getSecretKeyFlags(sourceSlot
, id
);
548 targetKey
= PK11_MoveSymKey(targetSlot
, PK11_OriginDerive
, flags
, PR_TRUE
,
550 if (targetKey
== NULL
) {
554 /* set the key new CKAID */
555 rv
= pk11_setAttributes(targetSlot
, targetKey
->objectID
, symTemplate
, 1);
556 if (rv
!= SECSuccess
) {
560 /* fill in remaining attributes */
561 rv
= pk11_copyAttributes(arena
, targetSlot
, targetKey
->objectID
,
562 sourceSlot
, id
, symCopyTemplate
, symCopyTemplateCount
);
565 PK11_FreeSymKey(sourceKey
);
568 PK11_FreeSymKey(targetKey
);
571 SECITEM_FreeItem(sourceOutput
, PR_TRUE
);
574 SECITEM_FreeItem(targetOutput
, PR_TRUE
);
577 SECITEM_FreeItem(param
, PR_TRUE
);
580 PORT_FreeArena(arena
,PR_FALSE
);
585 /*************************************************************************
589 *************************************************************************/
594 * Use the high level NSS calls to extract the public key and import it
595 * into the token. Extra attributes are then copied to the new token.
598 pk11_mergePublicKey(PK11SlotInfo
*targetSlot
, PK11SlotInfo
*sourceSlot
,
599 CK_OBJECT_HANDLE id
, void *targetPwArg
, void *sourcePwArg
)
601 SECKEYPublicKey
*sourceKey
= NULL
;
602 CK_OBJECT_HANDLE targetKeyID
;
603 PRArenaPool
*arena
= NULL
;
604 SECStatus rv
= SECSuccess
;
605 CK_ATTRIBUTE pubTemplate
[] = {
607 { CKA_CLASS
, NULL
, 0 }
609 CK_ULONG pubTemplateCount
= sizeof(pubTemplate
)/sizeof(pubTemplate
[0]);
610 CK_ATTRIBUTE pubCopyTemplate
[] = {
612 { CKA_LABEL
, NULL
, 0 },
613 { CKA_SUBJECT
, NULL
, 0 }
615 CK_ULONG pubCopyTemplateCount
=
616 sizeof(pubCopyTemplate
)/sizeof(pubCopyTemplate
[0]);
618 arena
= PORT_NewArena( DER_DEFAULT_CHUNKSIZE
);
625 /* check to see if the key is already in the target slot */
626 rv
= pk11_matchAcrossTokens(arena
, targetSlot
, sourceSlot
, pubTemplate
,
627 pubTemplateCount
, id
, &targetKeyID
);
628 if (rv
!= SECSuccess
) {
632 /* Key is already in the target slot */
633 if (targetKeyID
!= CK_INVALID_HANDLE
) {
634 /* not an error ... */
638 /* fetch an NSS representation of the public key */
639 sourceKey
= PK11_ExtractPublicKey(sourceSlot
, nullKey
, id
);
640 if (sourceKey
== NULL
) {
645 /* load the public key into the target token. */
646 targetKeyID
= PK11_ImportPublicKey(targetSlot
, sourceKey
, PR_TRUE
);
647 if (targetKeyID
== CK_INVALID_HANDLE
) {
652 /* fill in remaining attributes */
653 rv
= pk11_copyAttributes(arena
, targetSlot
, targetKeyID
, sourceSlot
, id
,
654 pubCopyTemplate
, pubCopyTemplateCount
);
659 SECKEY_DestroyPublicKey(sourceKey
);
662 PORT_FreeArena(arena
,PR_FALSE
);
667 /*************************************************************************
671 *************************************************************************/
674 * merge a certificate object
676 * Use the high level NSS calls to extract and import the certificate.
679 pk11_mergeCert(PK11SlotInfo
*targetSlot
, PK11SlotInfo
*sourceSlot
,
680 CK_OBJECT_HANDLE id
, void *targetPwArg
, void *sourcePwArg
)
682 CERTCertificate
*sourceCert
= NULL
;
683 CK_OBJECT_HANDLE targetCertID
= CK_INVALID_HANDLE
;
684 char *nickname
= NULL
;
685 SECStatus rv
= SECSuccess
;
686 PRArenaPool
*arena
= NULL
;
687 CK_ATTRIBUTE sourceCKAID
= {CKA_ID
, NULL
, 0};
688 CK_ATTRIBUTE targetCKAID
= {CKA_ID
, NULL
, 0};
689 SECStatus lrv
= SECSuccess
;
693 sourceCert
= PK11_MakeCertFromHandle(sourceSlot
, id
, NULL
);
694 if (sourceCert
== NULL
) {
699 nickname
= PK11_GetObjectNickname(sourceSlot
, id
);
701 /* see if the cert is already there */
702 targetCertID
= PK11_FindCertInSlot(targetSlot
, sourceCert
, targetPwArg
);
703 if (targetCertID
== CK_INVALID_HANDLE
) {
704 /* cert doesn't exist load the cert in. */
705 /* OK for the nickname to be NULL, not all certs have nicknames */
706 rv
= PK11_ImportCert(targetSlot
, sourceCert
, CK_INVALID_HANDLE
,
711 /* the cert already exists, see if the nickname and/or CKA_ID need
714 arena
= PORT_NewArena( DER_DEFAULT_CHUNKSIZE
);
720 /* does our source have a CKA_ID ? */
721 rv
= PK11_GetAttributes(arena
, sourceSlot
, id
, &sourceCKAID
, 1);
722 if (rv
!= SECSuccess
) {
723 sourceCKAID
.ulValueLen
= 0;
726 /* if we have a source CKA_ID, see of we need to update the
728 if (sourceCKAID
.ulValueLen
!= 0) {
729 rv
= PK11_GetAttributes(arena
, targetSlot
, targetCertID
,
731 if (rv
!= SECSuccess
) {
732 targetCKAID
.ulValueLen
= 0;
734 /* if the target has no CKA_ID, update it from the source */
735 if (targetCKAID
.ulValueLen
== 0) {
736 lrv
=pk11_setAttributes(targetSlot
, targetCertID
, &sourceCKAID
, 1);
737 if (lrv
!= SECSuccess
) {
738 error
= PORT_GetError();
744 /* now check if we need to update the nickname */
745 if (nickname
&& *nickname
) {
747 targetname
= PK11_GetObjectNickname(targetSlot
, targetCertID
);
748 if (!targetname
|| !*targetname
) {
749 /* target has no nickname, or it's empty, update it */
750 rv
= PK11_SetObjectNickname(targetSlot
, targetCertID
, nickname
);
753 PORT_Free(targetname
);
757 /* restore the error code if CKA_ID failed, but nickname didn't */
758 if ((rv
== SECSuccess
) && (lrv
!= SECSuccess
)) {
760 PORT_SetError(error
);
768 CERT_DestroyCertificate(sourceCert
);
771 PORT_FreeArena(arena
,PR_FALSE
);
777 /*************************************************************************
781 *************************************************************************/
784 * Use the raw PKCS #11 interface to merge the CRLs.
786 * In the case where of collision, choose the newest CRL that is valid.
789 pk11_mergeCrl(PK11SlotInfo
*targetSlot
, PK11SlotInfo
*sourceSlot
,
790 CK_OBJECT_HANDLE id
, void *targetPwArg
, void *sourcePwArg
)
792 CK_OBJECT_HANDLE targetCrlID
;
793 PRArenaPool
*arena
= NULL
;
794 SECStatus rv
= SECSuccess
;
795 CK_ATTRIBUTE crlTemplate
[] = {
796 { CKA_SUBJECT
, NULL
, 0 },
797 { CKA_CLASS
, NULL
, 0 },
798 { CKA_NSS_KRL
, NULL
, 0 }
800 CK_ULONG crlTemplateCount
= sizeof(crlTemplate
)/sizeof(crlTemplate
[0]);
801 CK_ATTRIBUTE crlCopyTemplate
[] = {
802 { CKA_CLASS
, NULL
, 0 },
803 { CKA_TOKEN
, NULL
, 0 },
804 { CKA_LABEL
, NULL
, 0 },
805 { CKA_PRIVATE
, NULL
, 0 },
806 { CKA_MODIFIABLE
, NULL
, 0 },
807 { CKA_SUBJECT
, NULL
, 0 },
808 { CKA_NSS_KRL
, NULL
, 0 },
809 { CKA_NSS_URL
, NULL
, 0 },
810 { CKA_VALUE
, NULL
, 0 }
812 CK_ULONG crlCopyTemplateCount
=
813 sizeof(crlCopyTemplate
)/sizeof(crlCopyTemplate
[0]);
815 arena
= PORT_NewArena( DER_DEFAULT_CHUNKSIZE
);
820 /* check to see if the crl is already in the target slot */
821 rv
= pk11_matchAcrossTokens(arena
, targetSlot
, sourceSlot
, crlTemplate
,
822 crlTemplateCount
, id
, &targetCrlID
);
823 if (rv
!= SECSuccess
) {
826 if (targetCrlID
!= CK_INVALID_HANDLE
) {
827 /* we already have a CRL, check to see which is more up-to-date. */
831 /* load the CRL into the target token. */
832 rv
= pk11_copyAttributes(arena
, targetSlot
, targetCrlID
, sourceSlot
, id
,
833 crlCopyTemplate
, crlCopyTemplateCount
);
836 PORT_FreeArena(arena
,PR_FALSE
);
841 /*************************************************************************
845 *************************************************************************/
848 * use the raw PKCS #11 interface to merge the S/MIME records
851 pk11_mergeSmime(PK11SlotInfo
*targetSlot
, PK11SlotInfo
*sourceSlot
,
852 CK_OBJECT_HANDLE id
, void *targetPwArg
, void *sourcePwArg
)
854 CK_OBJECT_HANDLE targetSmimeID
;
855 PRArenaPool
*arena
= NULL
;
856 SECStatus rv
= SECSuccess
;
857 CK_ATTRIBUTE smimeTemplate
[] = {
858 { CKA_SUBJECT
, NULL
, 0 },
859 { CKA_NSS_EMAIL
, NULL
, 0 },
860 { CKA_CLASS
, NULL
, 0 },
862 CK_ULONG smimeTemplateCount
=
863 sizeof(smimeTemplate
)/sizeof(smimeTemplate
[0]);
864 CK_ATTRIBUTE smimeCopyTemplate
[] = {
865 { CKA_CLASS
, NULL
, 0 },
866 { CKA_TOKEN
, NULL
, 0 },
867 { CKA_LABEL
, NULL
, 0 },
868 { CKA_PRIVATE
, NULL
, 0 },
869 { CKA_MODIFIABLE
, NULL
, 0 },
870 { CKA_SUBJECT
, NULL
, 0 },
871 { CKA_NSS_EMAIL
, NULL
, 0 },
872 { CKA_NSS_SMIME_TIMESTAMP
, NULL
, 0 },
873 { CKA_VALUE
, NULL
, 0 }
875 CK_ULONG smimeCopyTemplateCount
=
876 sizeof(smimeCopyTemplate
)/sizeof(smimeCopyTemplate
[0]);
878 arena
= PORT_NewArena( DER_DEFAULT_CHUNKSIZE
);
883 /* check to see if the crl is already in the target slot */
884 rv
= pk11_matchAcrossTokens(arena
, targetSlot
, sourceSlot
, smimeTemplate
,
885 smimeTemplateCount
, id
, &targetSmimeID
);
886 if (rv
!= SECSuccess
) {
889 if (targetSmimeID
!= CK_INVALID_HANDLE
) {
890 /* we already have a SMIME record */
894 /* load the SMime Record into the target token. */
895 rv
= pk11_copyAttributes(arena
, targetSlot
, targetSmimeID
, sourceSlot
, id
,
896 smimeCopyTemplate
, smimeCopyTemplateCount
);
899 PORT_FreeArena(arena
,PR_FALSE
);
904 /*************************************************************************
908 *************************************************************************/
912 * decide which trust record entry wins. PR_TRUE (source) or PR_FALSE (target)
914 #define USE_TARGET PR_FALSE
915 #define USE_SOURCE PR_TRUE
917 pk11_mergeTrustEntry(CK_ATTRIBUTE
*target
, CK_ATTRIBUTE
*source
)
919 CK_ULONG targetTrust
= (target
->ulValueLen
== sizeof (CK_LONG
)) ?
920 *(CK_ULONG
*)target
->pValue
: CKT_NSS_TRUST_UNKNOWN
;
921 CK_ULONG sourceTrust
= (source
->ulValueLen
== sizeof (CK_LONG
)) ?
922 *(CK_ULONG
*)source
->pValue
: CKT_NSS_TRUST_UNKNOWN
;
925 * Examine a single entry and deside if the source or target version
926 * should win out. When all the entries have been checked, if there is
927 * any case we need to update, we will write the whole source record
928 * to the target database. That means for each individual record, if the
929 * target wins, we need to update the source (in case later we have a
930 * case where the source wins). If the source wins, it already
932 if (sourceTrust
== targetTrust
) {
933 return USE_TARGET
; /* which equates to 'do nothing' */
936 if (sourceTrust
== CKT_NSS_TRUST_UNKNOWN
) {
940 /* target has no idea, use the source's idea of the trust value */
941 if (targetTrust
== CKT_NSS_TRUST_UNKNOWN
) {
942 /* source overwrites the target */
946 /* so both the target and the source have some idea of what this
947 * trust attribute should be, and neither agree exactly.
948 * At this point, we prefer 'hard' attributes over 'soft' ones.
949 * 'hard' ones are CKT_NSS_TRUSTED, CKT_NSS_TRUSTED_DELEGATOR, and
950 * CKT_NSS_UNTRUTED. Soft ones are ones which don't change the
951 * actual trust of the cert (CKT_MUST_VERIFY, CKT_NSS_VALID,
952 * CKT_NSS_VALID_DELEGATOR).
954 if ((sourceTrust
== CKT_NSS_MUST_VERIFY
)
955 || (sourceTrust
== CKT_NSS_VALID
)
956 || (sourceTrust
== CKT_NSS_VALID_DELEGATOR
)) {
959 if ((targetTrust
== CKT_NSS_MUST_VERIFY
)
960 || (targetTrust
== CKT_NSS_VALID
)
961 || (targetTrust
== CKT_NSS_VALID_DELEGATOR
)) {
962 /* source overrites the target */
966 /* both have hard attributes, we have a conflict, let the target win. */
970 * use the raw PKCS #11 interface to merge the S/MIME records
973 pk11_mergeTrust(PK11SlotInfo
*targetSlot
, PK11SlotInfo
*sourceSlot
,
974 CK_OBJECT_HANDLE id
, void *targetPwArg
, void *sourcePwArg
)
976 CK_OBJECT_HANDLE targetTrustID
;
977 PRArenaPool
*arena
= NULL
;
978 SECStatus rv
= SECSuccess
;
980 CK_ATTRIBUTE trustTemplate
[] = {
981 { CKA_ISSUER
, NULL
, 0 },
982 { CKA_SERIAL_NUMBER
, NULL
, 0 },
983 { CKA_CLASS
, NULL
, 0 },
985 CK_ULONG trustTemplateCount
=
986 sizeof(trustTemplate
)/sizeof(trustTemplate
[0]);
987 CK_ATTRIBUTE trustCopyTemplate
[] = {
988 { CKA_CLASS
, NULL
, 0 },
989 { CKA_TOKEN
, NULL
, 0 },
990 { CKA_LABEL
, NULL
, 0 },
991 { CKA_PRIVATE
, NULL
, 0 },
992 { CKA_MODIFIABLE
, NULL
, 0 },
993 { CKA_ISSUER
, NULL
, 0},
994 { CKA_SERIAL_NUMBER
, NULL
, 0},
995 { CKA_CERT_SHA1_HASH
, NULL
, 0 },
996 { CKA_CERT_MD5_HASH
, NULL
, 0 },
997 { CKA_TRUST_SERVER_AUTH
, NULL
, 0 },
998 { CKA_TRUST_CLIENT_AUTH
, NULL
, 0 },
999 { CKA_TRUST_CODE_SIGNING
, NULL
, 0 },
1000 { CKA_TRUST_EMAIL_PROTECTION
, NULL
, 0 },
1001 { CKA_TRUST_STEP_UP_APPROVED
, NULL
, 0 }
1003 CK_ULONG trustCopyTemplateCount
=
1004 sizeof(trustCopyTemplate
)/sizeof(trustCopyTemplate
[0]);
1006 arena
= PORT_NewArena( DER_DEFAULT_CHUNKSIZE
);
1007 if (arena
== NULL
) {
1011 /* check to see if the crl is already in the target slot */
1012 rv
= pk11_matchAcrossTokens(arena
, targetSlot
, sourceSlot
, trustTemplate
,
1013 trustTemplateCount
, id
, &targetTrustID
);
1014 if (rv
!= SECSuccess
) {
1017 if (targetTrustID
!= CK_INVALID_HANDLE
) {
1018 /* a matching trust record already exists, merge it in */
1019 CK_ATTRIBUTE_TYPE trustAttrs
[] = {
1020 CKA_TRUST_SERVER_AUTH
, CKA_TRUST_CLIENT_AUTH
,
1021 CKA_TRUST_CODE_SIGNING
, CKA_TRUST_EMAIL_PROTECTION
,
1022 CKA_TRUST_IPSEC_TUNNEL
, CKA_TRUST_IPSEC_USER
,
1023 CKA_TRUST_TIME_STAMPING
1025 CK_ULONG trustAttrsCount
=
1026 sizeof(trustAttrs
)/sizeof(trustAttrs
[0]);
1029 CK_ATTRIBUTE targetTemplate
, sourceTemplate
;
1031 /* existing trust record, merge the two together */
1032 for (i
=0; i
< trustAttrsCount
; i
++) {
1033 targetTemplate
.type
= sourceTemplate
.type
= trustAttrs
[i
];
1034 targetTemplate
.pValue
= sourceTemplate
.pValue
= NULL
;
1035 targetTemplate
.ulValueLen
= sourceTemplate
.ulValueLen
= 0;
1036 PK11_GetAttributes(arena
, sourceSlot
, id
, &sourceTemplate
, 1);
1037 PK11_GetAttributes(arena
, targetSlot
, targetTrustID
,
1038 &targetTemplate
, 1);
1039 if (pk11_mergeTrustEntry(&targetTemplate
, &sourceTemplate
)) {
1040 /* source wins, write out the source attribute to the target */
1041 SECStatus lrv
= pk11_setAttributes(targetSlot
, targetTrustID
,
1042 &sourceTemplate
, 1);
1043 if (lrv
!= SECSuccess
) {
1045 error
= PORT_GetError();
1051 sourceTemplate
.type
= CKA_TRUST_STEP_UP_APPROVED
;
1052 sourceTemplate
.pValue
= NULL
;
1053 sourceTemplate
.ulValueLen
= 0;
1055 /* if the source has steup set, then set it in the target */
1056 PK11_GetAttributes(arena
, sourceSlot
, id
, &sourceTemplate
, 1);
1057 if ((sourceTemplate
.ulValueLen
== sizeof(CK_BBOOL
)) &&
1058 (sourceTemplate
.pValue
) &&
1059 (*(CK_BBOOL
*)sourceTemplate
.pValue
== CK_TRUE
)) {
1060 SECStatus lrv
= pk11_setAttributes(targetSlot
, targetTrustID
,
1061 &sourceTemplate
, 1);
1062 if (lrv
!= SECSuccess
) {
1064 error
= PORT_GetError();
1072 /* load the new trust Record into the target token. */
1073 rv
= pk11_copyAttributes(arena
, targetSlot
, targetTrustID
, sourceSlot
, id
,
1074 trustCopyTemplate
, trustCopyTemplateCount
);
1077 PORT_FreeArena(arena
,PR_FALSE
);
1080 /* restore the error code */
1081 if (rv
== SECFailure
&& error
) {
1082 PORT_SetError(error
);
1088 /*************************************************************************
1090 * Central merge code
1092 *************************************************************************/
1094 * merge a single object from sourceToken to targetToken
1097 pk11_mergeObject(PK11SlotInfo
*targetSlot
, PK11SlotInfo
*sourceSlot
,
1098 CK_OBJECT_HANDLE id
, void *targetPwArg
, void *sourcePwArg
)
1101 CK_OBJECT_CLASS objClass
;
1104 objClass
= PK11_ReadULongAttribute(sourceSlot
, id
, CKA_CLASS
);
1105 if (objClass
== (CK_ULONG
) -1) {
1106 PORT_SetError( SEC_ERROR_UNKNOWN_OBJECT_TYPE
);
1111 case CKO_CERTIFICATE
:
1112 return pk11_mergeCert(targetSlot
, sourceSlot
, id
,
1113 targetPwArg
, sourcePwArg
);
1115 return pk11_mergeTrust(targetSlot
, sourceSlot
, id
,
1116 targetPwArg
, sourcePwArg
);
1117 case CKO_PUBLIC_KEY
:
1118 return pk11_mergePublicKey(targetSlot
, sourceSlot
, id
,
1119 targetPwArg
, sourcePwArg
);
1120 case CKO_PRIVATE_KEY
:
1121 return pk11_mergePrivateKey(targetSlot
, sourceSlot
, id
,
1122 targetPwArg
, sourcePwArg
);
1123 case CKO_SECRET_KEY
:
1124 return pk11_mergeSecretKey(targetSlot
, sourceSlot
, id
,
1125 targetPwArg
, sourcePwArg
);
1127 return pk11_mergeCrl(targetSlot
, sourceSlot
, id
,
1128 targetPwArg
, sourcePwArg
);
1130 return pk11_mergeSmime(targetSlot
, sourceSlot
, id
,
1131 targetPwArg
, sourcePwArg
);
1136 PORT_SetError( SEC_ERROR_UNKNOWN_OBJECT_TYPE
);
1141 pk11_newMergeLogNode(PRArenaPool
*arena
,
1142 PK11SlotInfo
*slot
, CK_OBJECT_HANDLE id
, int error
)
1144 PK11MergeLogNode
*newLog
;
1145 PK11GenericObject
*obj
;
1147 newLog
= PORT_ArenaZNew(arena
, PK11MergeLogNode
);
1148 if (newLog
== NULL
) {
1152 obj
= PORT_ArenaZNew(arena
, PK11GenericObject
);
1161 newLog
->object
= obj
;
1162 newLog
->error
= error
;
1167 * walk down each entry and merge it. keep track of the errors in the log
1170 pk11_mergeByObjectIDs(PK11SlotInfo
*targetSlot
, PK11SlotInfo
*sourceSlot
,
1171 CK_OBJECT_HANDLE
*objectIDs
, int count
,
1172 PK11MergeLog
*log
, void *targetPwArg
, void *sourcePwArg
)
1174 SECStatus rv
= SECSuccess
;
1177 for (i
=0; i
< count
; i
++) {
1178 /* try to update the entire database. On failure, keep going,
1179 * but remember the error to report back to the caller */
1181 PK11MergeLogNode
*newLog
;
1183 lrv
= pk11_mergeObject(targetSlot
, sourceSlot
, objectIDs
[i
],
1184 targetPwArg
, sourcePwArg
);
1185 if (lrv
== SECSuccess
) {
1186 /* merged with no problem, go to next object */
1190 /* remember that we failed and why */
1192 error
= PORT_GetError();
1194 /* log the errors */
1196 /* not logging, go to next entry */
1199 newLog
= pk11_newMergeLogNode(log
->arena
, sourceSlot
,
1200 objectIDs
[i
], error
);
1202 /* failed to allocate entry, just keep going */
1206 /* link in the errorlog entry */
1207 newLog
->next
= NULL
;
1209 log
->tail
->next
= newLog
;
1213 newLog
->prev
= log
->tail
;
1217 /* restore the last error code */
1218 if (rv
!= SECSuccess
) {
1219 PORT_SetError(error
);
1225 * Merge all the records in sourceSlot that aren't in targetSlot
1227 * This function will return failure if not all the objects
1228 * successfully merged.
1230 * Applications can pass in an optional error log which will record
1231 * each failing object and why it failed to import. PK11MergeLog
1232 * is modelled after the CERTVerifyLog.
1235 PK11_MergeTokens(PK11SlotInfo
*targetSlot
, PK11SlotInfo
*sourceSlot
,
1236 PK11MergeLog
*log
, void *targetPwArg
, void *sourcePwArg
)
1238 SECStatus rv
= SECSuccess
, lrv
= SECSuccess
;
1239 int error
, count
= 0;
1240 CK_ATTRIBUTE search
[2];
1241 CK_OBJECT_HANDLE
*objectIDs
= NULL
;
1242 CK_BBOOL ck_true
= CK_TRUE
;
1243 CK_OBJECT_CLASS privKey
= CKO_PRIVATE_KEY
;
1245 PK11_SETATTRS(&search
[0], CKA_TOKEN
, &ck_true
, sizeof(ck_true
));
1246 PK11_SETATTRS(&search
[1], CKA_CLASS
, &privKey
, sizeof(privKey
));
1248 * make sure both tokens are already authenticated if need be.
1250 rv
= PK11_Authenticate(targetSlot
, PR_TRUE
, targetPwArg
);
1251 if (rv
!= SECSuccess
) {
1254 rv
= PK11_Authenticate(sourceSlot
, PR_TRUE
, sourcePwArg
);
1255 if (rv
!= SECSuccess
) {
1259 /* turns out the old DB's are rather fragile if the private keys aren't
1260 * merged in first, so do the private keys explicity. */
1261 objectIDs
= pk11_FindObjectsByTemplate(sourceSlot
, search
, 2, &count
);
1263 lrv
= pk11_mergeByObjectIDs(targetSlot
, sourceSlot
,
1264 objectIDs
, count
, log
,
1265 targetPwArg
, sourcePwArg
);
1266 if (lrv
!= SECSuccess
) {
1267 error
= PORT_GetError();
1269 PORT_Free(objectIDs
);
1273 /* now do the rest (NOTE: this will repeat the private keys, but
1274 * that shouldnt' be an issue as we will notice they are already
1276 objectIDs
= pk11_FindObjectsByTemplate(sourceSlot
, search
, 1, &count
);
1282 rv
= pk11_mergeByObjectIDs(targetSlot
, sourceSlot
, objectIDs
, count
, log
,
1283 targetPwArg
, sourcePwArg
);
1284 if (rv
== SECSuccess
) {
1285 /* if private keys failed, but the rest succeeded, be sure to let
1286 * the caller know that private keys failed and why.
1287 * NOTE: this is highly unlikely since the same keys that failed
1288 * in the previous merge call will most likely fail in this one */
1289 if (lrv
!= SECSuccess
) {
1291 PORT_SetError(error
);
1297 PORT_Free(objectIDs
);
1303 PK11_CreateMergeLog(void)
1308 arena
= PORT_NewArena( DER_DEFAULT_CHUNKSIZE
);
1309 if (arena
== NULL
) {
1313 log
= PORT_ArenaZNew(arena
, PK11MergeLog
);
1315 PORT_FreeArena(arena
,PR_FALSE
);
1324 PK11_DestroyMergeLog(PK11MergeLog
*log
)
1326 if (log
&& log
->arena
) {
1327 PORT_FreeArena(log
->arena
, PR_FALSE
);