comparison nss/lib/pk11wrap/pk11merge.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e5118fa0cb1
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/. */
4
5 /*
6 * Merge the source token into the target token.
7 */
8
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"
21
22 /*************************************************************************
23 *
24 * short utilities to aid in the merge
25 *
26 *************************************************************************/
27
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;
37
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 }
52
53
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 }
80
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 {
90
91 CK_RV crv;
92 *peer = CK_INVALID_HANDLE;
93
94 crv = PK11_GetAttributes(arena, sourceSlot, id, template, tsize);
95 if (crv != CKR_OK) {
96 PORT_SetError( PK11_MapError(crv) );
97 goto loser;
98 }
99
100 if (template[0].ulValueLen == -1) {
101 crv = CKR_ATTRIBUTE_TYPE_INVALID;
102 PORT_SetError( PK11_MapError(crv) );
103 goto loser;
104 }
105
106 *peer = pk11_FindObjectByTemplate(targetSlot, template, tsize);
107 return SECSuccess;
108
109 loser:
110 return SECFailure;
111 }
112
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;
122
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 }
131
132 ctxt = PK11_CreateContextBySymKey(mechType, CKA_ENCRYPT, symKey, param);
133 if (ctxt == NULL) {
134 rv = SECFailure;
135 goto done;
136 }
137
138 rv = PK11_CipherOp(ctxt, (*output)->data,
139 (int *)&((*output)->len),
140 (*output)->len, input->data, input->len);
141
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 }
155
156
157
158 /*************************************************************************
159 *
160 * Private Keys
161 *
162 *************************************************************************/
163
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;
171
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 }
185
186
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]);
220
221 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
222 if (arena == NULL) {
223 rv = SECFailure;
224 goto done;
225 }
226
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 }
233
234 if (targetKeyID != CK_INVALID_HANDLE) {
235 /* match found, not an error ... */
236 goto done;
237 }
238
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 }
246
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 }
279
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 }
286
287 if (targetKeyID == CK_INVALID_HANDLE) {
288 /* this time the key should exist */
289 rv = SECFailure;
290 goto done;
291 }
292
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 }
313
314
315 /*************************************************************************
316 *
317 * Secret Keys
318 *
319 *************************************************************************/
320
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;
338
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;
344
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 }
369
370
371 static CK_FLAGS
372 pk11_getSecretKeyFlags(PK11SlotInfo *slot, CK_OBJECT_HANDLE id)
373 {
374 CK_FLAGS flags = 0;
375
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 }
405
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]);
450
451 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
452 if (arena == NULL) {
453 rv = SECFailure;
454 goto done;
455 }
456
457 sourceKeyType = PK11_ReadULongAttribute(sourceSlot, id, CKA_KEY_TYPE);
458 if (sourceKeyType == (CK_ULONG) -1) {
459 rv = SECFailure;
460 goto done;
461 }
462
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 }
475
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 }
482
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 }
492
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 }
551
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 }
566
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 }
591
592 /*************************************************************************
593 *
594 * Public Keys
595 *
596 *************************************************************************/
597
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]);
624
625 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
626 if (arena == NULL) {
627 rv = SECFailure;
628 goto done;
629 }
630
631
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 }
638
639 /* Key is already in the target slot */
640 if (targetKeyID != CK_INVALID_HANDLE) {
641 /* not an error ... */
642 goto done;
643 }
644
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 }
651
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 }
658
659 /* fill in remaining attributes */
660 rv = pk11_copyAttributes(arena, targetSlot, targetKeyID, sourceSlot, id,
661 pubCopyTemplate, pubCopyTemplateCount);
662
663
664 done:
665 if (sourceKey) {
666 SECKEY_DestroyPublicKey(sourceKey);
667 }
668 if (arena) {
669 PORT_FreeArena(arena,PR_FALSE);
670 }
671 return rv;
672 }
673
674 /*************************************************************************
675 *
676 * Certificates
677 *
678 *************************************************************************/
679
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);
692
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 }
713
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 }
723
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 }
735
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;
754
755
756 sourceCert = PK11_MakeCertFromHandle(sourceSlot, id, NULL);
757 if (sourceCert == NULL) {
758 rv = SECFailure;
759 goto done;
760 }
761
762 nickname = PK11_GetObjectNickname(sourceSlot, id);
763
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;
770
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 }
790
791
792
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 }
802
803 /* the cert already exists, see if the nickname and/or CKA_ID need
804 * to be updated */
805
806 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
807 if (arena == NULL) {
808 rv = SECFailure;
809 goto done;
810 }
811
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 }
817
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;
835
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 }
848
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 }
854
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 }
867
868
869 /*************************************************************************
870 *
871 * Crls
872 *
873 *************************************************************************/
874
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]);
906
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 }
922
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 }
932
933 /*************************************************************************
934 *
935 * SMIME objects
936 *
937 *************************************************************************/
938
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]);
969
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 }
985
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 }
995
996 /*************************************************************************
997 *
998 * Trust Objects
999 *
1000 *************************************************************************/
1001
1002
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)
1010 {
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;
1015
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' */
1026 }
1027
1028 if (sourceTrust == CKT_NSS_TRUST_UNKNOWN) {
1029 return USE_TARGET;
1030 }
1031
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;
1036 }
1037
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;
1049 }
1050 if ((targetTrust == CKT_NSS_MUST_VERIFY_TRUST)
1051 || (targetTrust == CKT_NSS_VALID_DELEGATOR)) {
1052 /* source overrites the target */
1053 return USE_SOURCE;
1054 }
1055
1056 /* both have hard attributes, we have a conflict, let the target win. */
1057 return USE_TARGET;
1058 }
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)
1065 {
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]);
1095
1096 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
1097 if (arena == NULL) {
1098 rv = SECFailure;
1099 goto done;
1100 }
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;
1106 }
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]);
1117
1118 CK_ULONG i;
1119 CK_ATTRIBUTE targetTemplate, sourceTemplate;
1120
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();
1136 }
1137 }
1138 }
1139
1140 /* handle step */
1141 sourceTemplate.type = CKA_TRUST_STEP_UP_APPROVED;
1142 sourceTemplate.pValue = NULL;
1143 sourceTemplate.ulValueLen = 0;
1144
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();
1155 }
1156 }
1157
1158 goto done;
1159
1160 }
1161
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);
1168 }
1169
1170 /* restore the error code */
1171 if (rv == SECFailure && error) {
1172 PORT_SetError(error);
1173 }
1174
1175 return rv;
1176 }
1177
1178 /*************************************************************************
1179 *
1180 * Central merge code
1181 *
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)
1189 {
1190
1191 CK_OBJECT_CLASS objClass;
1192
1193
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;
1198 }
1199
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;
1224 }
1225
1226 PORT_SetError( SEC_ERROR_UNKNOWN_OBJECT_TYPE );
1227 return SECFailure;
1228 }
1229
1230 PK11MergeLogNode *
1231 pk11_newMergeLogNode(PLArenaPool *arena,
1232 PK11SlotInfo *slot, CK_OBJECT_HANDLE id, int error)
1233 {
1234 PK11MergeLogNode *newLog;
1235 PK11GenericObject *obj;
1236
1237 newLog = PORT_ArenaZNew(arena, PK11MergeLogNode);
1238 if (newLog == NULL) {
1239 return NULL;
1240 }
1241
1242 obj = PORT_ArenaZNew(arena, PK11GenericObject);
1243 if ( !obj ) {
1244 return NULL;
1245 }
1246
1247 /* initialize it */
1248 obj->slot = slot;
1249 obj->objectID = id;
1250
1251 newLog->object= obj;
1252 newLog->error = error;
1253 return newLog;
1254 }
1255
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)
1263 {
1264 SECStatus rv = SECSuccess;
1265 int error, i;
1266
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;
1272
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;
1278 }
1279
1280 /* remember that we failed and why */
1281 rv = SECFailure;
1282 error = PORT_GetError();
1283
1284 /* log the errors */
1285 if (!log) {
1286 /* not logging, go to next entry */
1287 continue;
1288 }
1289 newLog = pk11_newMergeLogNode(log->arena, sourceSlot,
1290 objectIDs[i], error);
1291 if (!newLog) {
1292 /* failed to allocate entry, just keep going */
1293 continue;
1294 }
1295
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;
1302 }
1303 newLog->prev = log->tail;
1304 log->tail = newLog;
1305 }
1306
1307 /* restore the last error code */
1308 if (rv != SECSuccess) {
1309 PORT_SetError(error);
1310 }
1311 return rv;
1312 }
1313
1314 /*
1315 * Merge all the records in sourceSlot that aren't in targetSlot
1316 *
1317 * This function will return failure if not all the objects
1318 * successfully merged.
1319 *
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)
1327 {
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;
1334
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;
1343 }
1344 rv = PK11_Authenticate(sourceSlot, PR_TRUE, sourcePwArg);
1345 if (rv != SECSuccess) {
1346 goto loser;
1347 }
1348
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();
1358 }
1359 PORT_Free(objectIDs);
1360 count = 0;
1361 }
1362
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;
1370 }
1371
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);
1382 }
1383 }
1384
1385 loser:
1386 if (objectIDs) {
1387 PORT_Free(objectIDs);
1388 }
1389 return rv;
1390 }
1391
1392 PK11MergeLog *
1393 PK11_CreateMergeLog(void)
1394 {
1395 PLArenaPool *arena;
1396 PK11MergeLog *log;
1397
1398 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
1399 if (arena == NULL) {
1400 return NULL;
1401 }
1402
1403 log = PORT_ArenaZNew(arena, PK11MergeLog);
1404 if (log == NULL) {
1405 PORT_FreeArena(arena,PR_FALSE);
1406 return NULL;
1407 }
1408 log->arena = arena;
1409 log->version = 1;
1410 return log;
1411 }
1412
1413 void
1414 PK11_DestroyMergeLog(PK11MergeLog *log)
1415 {
1416 if (log && log->arena) {
1417 PORT_FreeArena(log->arena, PR_FALSE);
1418 }
1419 }
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)