Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(232)

Side by Side Diff: nss/lib/pk11wrap/pk11merge.c

Issue 2078763002: Delete bundled copy of NSS and replace with README. (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/nss@master
Patch Set: Delete bundled copy of NSS and replace with README. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « nss/lib/pk11wrap/pk11mech.c ('k') | nss/lib/pk11wrap/pk11nobj.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 = SEC_ERROR_LIBRARY_FAILURE;
754
755 sourceCert = PK11_MakeCertFromHandle(sourceSlot, id, NULL);
756 if (sourceCert == NULL) {
757 rv = SECFailure;
758 goto done;
759 }
760
761 nickname = PK11_GetObjectNickname(sourceSlot, id);
762
763 /* The database code will prevent nickname collisions for certs with
764 * different subjects. This code will prevent us from getting
765 * actual import errors */
766 if (nickname) {
767 const char *tokenName = PK11_GetTokenName(targetSlot);
768 char *tokenNickname = NULL;
769
770 do {
771 tokenNickname = PR_smprintf("%s:%s",tokenName, nickname);
772 if (!tokenNickname) {
773 break;
774 }
775 if (!SEC_CertNicknameConflict(tokenNickname,
776 &sourceCert->derSubject, CERT_GetDefaultCertDB())) {
777 break;
778 }
779 nickname = pk11_IncrementNickname(nickname);
780 if (!nickname) {
781 break;
782 }
783 PR_smprintf_free(tokenNickname);
784 } while (1);
785 if (tokenNickname) {
786 PR_smprintf_free(tokenNickname);
787 }
788 }
789
790
791
792 /* see if the cert is already there */
793 targetCertID = PK11_FindCertInSlot(targetSlot, sourceCert, targetPwArg);
794 if (targetCertID == CK_INVALID_HANDLE) {
795 /* cert doesn't exist load the cert in. */
796 /* OK for the nickname to be NULL, not all certs have nicknames */
797 rv = PK11_ImportCert(targetSlot, sourceCert, CK_INVALID_HANDLE,
798 nickname, PR_FALSE);
799 goto done;
800 }
801
802 /* the cert already exists, see if the nickname and/or CKA_ID need
803 * to be updated */
804
805 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
806 if (arena == NULL) {
807 rv = SECFailure;
808 goto done;
809 }
810
811 /* does our source have a CKA_ID ? */
812 rv = PK11_GetAttributes(arena, sourceSlot, id, &sourceCKAID, 1);
813 if (rv != SECSuccess) {
814 sourceCKAID.ulValueLen = 0;
815 }
816
817 /* if we have a source CKA_ID, see of we need to update the
818 * target's CKA_ID */
819 if (sourceCKAID.ulValueLen != 0) {
820 rv = PK11_GetAttributes(arena, targetSlot, targetCertID,
821 &targetCKAID, 1);
822 if (rv != SECSuccess) {
823 targetCKAID.ulValueLen = 0;
824 }
825 /* if the target has no CKA_ID, update it from the source */
826 if (targetCKAID.ulValueLen == 0) {
827 lrv=pk11_setAttributes(targetSlot, targetCertID, &sourceCKAID, 1);
828 if (lrv != SECSuccess) {
829 error = PORT_GetError();
830 }
831 }
832 }
833 rv = SECSuccess;
834
835 /* now check if we need to update the nickname */
836 if (nickname && *nickname) {
837 char *targetname;
838 targetname = PK11_GetObjectNickname(targetSlot, targetCertID);
839 if (!targetname || !*targetname) {
840 /* target has no nickname, or it's empty, update it */
841 rv = PK11_SetObjectNickname(targetSlot, targetCertID, nickname);
842 }
843 if (targetname) {
844 PORT_Free(targetname);
845 }
846 }
847
848 /* restore the error code if CKA_ID failed, but nickname didn't */
849 if ((rv == SECSuccess) && (lrv != SECSuccess)) {
850 rv = lrv;
851 PORT_SetError(error);
852 }
853
854 done:
855 if (nickname) {
856 PORT_Free(nickname);
857 }
858 if (sourceCert) {
859 CERT_DestroyCertificate(sourceCert);
860 }
861 if (arena) {
862 PORT_FreeArena(arena,PR_FALSE);
863 }
864 return rv;
865 }
866
867
868 /*************************************************************************
869 *
870 * Crls
871 *
872 *************************************************************************/
873
874 /*
875 * Use the raw PKCS #11 interface to merge the CRLs.
876 *
877 * In the case where of collision, choose the newest CRL that is valid.
878 */
879 static SECStatus
880 pk11_mergeCrl(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
881 CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
882 {
883 CK_OBJECT_HANDLE targetCrlID;
884 PLArenaPool *arena = NULL;
885 SECStatus rv = SECSuccess;
886 CK_ATTRIBUTE crlTemplate[] = {
887 { CKA_SUBJECT, NULL, 0 },
888 { CKA_CLASS, NULL, 0 },
889 { CKA_NSS_KRL, NULL, 0 }
890 };
891 CK_ULONG crlTemplateCount = sizeof(crlTemplate)/sizeof(crlTemplate[0]);
892 CK_ATTRIBUTE crlCopyTemplate[] = {
893 { CKA_CLASS, NULL, 0 },
894 { CKA_TOKEN, NULL, 0 },
895 { CKA_LABEL, NULL, 0 },
896 { CKA_PRIVATE, NULL, 0 },
897 { CKA_MODIFIABLE, NULL, 0 },
898 { CKA_SUBJECT, NULL, 0 },
899 { CKA_NSS_KRL, NULL, 0 },
900 { CKA_NSS_URL, NULL, 0 },
901 { CKA_VALUE, NULL, 0 }
902 };
903 CK_ULONG crlCopyTemplateCount =
904 sizeof(crlCopyTemplate)/sizeof(crlCopyTemplate[0]);
905
906 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
907 if (arena == NULL) {
908 rv = SECFailure;
909 goto done;
910 }
911 /* check to see if the crl is already in the target slot */
912 rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, crlTemplate,
913 crlTemplateCount, id, &targetCrlID);
914 if (rv != SECSuccess) {
915 goto done;
916 }
917 if (targetCrlID != CK_INVALID_HANDLE) {
918 /* we already have a CRL, check to see which is more up-to-date. */
919 goto done;
920 }
921
922 /* load the CRL into the target token. */
923 rv = pk11_copyAttributes(arena, targetSlot, targetCrlID, sourceSlot, id,
924 crlCopyTemplate, crlCopyTemplateCount);
925 done:
926 if (arena) {
927 PORT_FreeArena(arena,PR_FALSE);
928 }
929 return rv;
930 }
931
932 /*************************************************************************
933 *
934 * SMIME objects
935 *
936 *************************************************************************/
937
938 /*
939 * use the raw PKCS #11 interface to merge the S/MIME records
940 */
941 static SECStatus
942 pk11_mergeSmime(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
943 CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
944 {
945 CK_OBJECT_HANDLE targetSmimeID;
946 PLArenaPool *arena = NULL;
947 SECStatus rv = SECSuccess;
948 CK_ATTRIBUTE smimeTemplate[] = {
949 { CKA_SUBJECT, NULL, 0 },
950 { CKA_NSS_EMAIL, NULL, 0 },
951 { CKA_CLASS, NULL, 0 },
952 };
953 CK_ULONG smimeTemplateCount =
954 sizeof(smimeTemplate)/sizeof(smimeTemplate[0]);
955 CK_ATTRIBUTE smimeCopyTemplate[] = {
956 { CKA_CLASS, NULL, 0 },
957 { CKA_TOKEN, NULL, 0 },
958 { CKA_LABEL, NULL, 0 },
959 { CKA_PRIVATE, NULL, 0 },
960 { CKA_MODIFIABLE, NULL, 0 },
961 { CKA_SUBJECT, NULL, 0 },
962 { CKA_NSS_EMAIL, NULL, 0 },
963 { CKA_NSS_SMIME_TIMESTAMP, NULL, 0 },
964 { CKA_VALUE, NULL, 0 }
965 };
966 CK_ULONG smimeCopyTemplateCount =
967 sizeof(smimeCopyTemplate)/sizeof(smimeCopyTemplate[0]);
968
969 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
970 if (arena == NULL) {
971 rv = SECFailure;
972 goto done;
973 }
974 /* check to see if the crl is already in the target slot */
975 rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, smimeTemplate,
976 smimeTemplateCount, id, &targetSmimeID);
977 if (rv != SECSuccess) {
978 goto done;
979 }
980 if (targetSmimeID != CK_INVALID_HANDLE) {
981 /* we already have a SMIME record */
982 goto done;
983 }
984
985 /* load the SMime Record into the target token. */
986 rv = pk11_copyAttributes(arena, targetSlot, targetSmimeID, sourceSlot, id,
987 smimeCopyTemplate, smimeCopyTemplateCount);
988 done:
989 if (arena) {
990 PORT_FreeArena(arena,PR_FALSE);
991 }
992 return rv;
993 }
994
995 /*************************************************************************
996 *
997 * Trust Objects
998 *
999 *************************************************************************/
1000
1001
1002 /*
1003 * decide which trust record entry wins. PR_TRUE (source) or PR_FALSE (target)
1004 */
1005 #define USE_TARGET PR_FALSE
1006 #define USE_SOURCE PR_TRUE
1007 PRBool
1008 pk11_mergeTrustEntry(CK_ATTRIBUTE *target, CK_ATTRIBUTE *source)
1009 {
1010 CK_ULONG targetTrust = (target->ulValueLen == sizeof (CK_LONG)) ?
1011 *(CK_ULONG *)target->pValue : CKT_NSS_TRUST_UNKNOWN;
1012 CK_ULONG sourceTrust = (source->ulValueLen == sizeof (CK_LONG)) ?
1013 *(CK_ULONG *)source->pValue : CKT_NSS_TRUST_UNKNOWN;
1014
1015 /*
1016 * Examine a single entry and deside if the source or target version
1017 * should win out. When all the entries have been checked, if there is
1018 * any case we need to update, we will write the whole source record
1019 * to the target database. That means for each individual record, if the
1020 * target wins, we need to update the source (in case later we have a
1021 * case where the source wins). If the source wins, it already
1022 */
1023 if (sourceTrust == targetTrust) {
1024 return USE_TARGET; /* which equates to 'do nothing' */
1025 }
1026
1027 if (sourceTrust == CKT_NSS_TRUST_UNKNOWN) {
1028 return USE_TARGET;
1029 }
1030
1031 /* target has no idea, use the source's idea of the trust value */
1032 if (targetTrust == CKT_NSS_TRUST_UNKNOWN) {
1033 /* source overwrites the target */
1034 return USE_SOURCE;
1035 }
1036
1037 /* so both the target and the source have some idea of what this
1038 * trust attribute should be, and neither agree exactly.
1039 * At this point, we prefer 'hard' attributes over 'soft' ones.
1040 * 'hard' ones are CKT_NSS_TRUSTED, CKT_NSS_TRUSTED_DELEGATOR, and
1041 * CKT_NSS_UNTRUTED. Soft ones are ones which don't change the
1042 * actual trust of the cert (CKT_MUST_VERIFY, CKT_NSS_VALID,
1043 * CKT_NSS_VALID_DELEGATOR).
1044 */
1045 if ((sourceTrust == CKT_NSS_MUST_VERIFY_TRUST)
1046 || (sourceTrust == CKT_NSS_VALID_DELEGATOR)) {
1047 return USE_TARGET;
1048 }
1049 if ((targetTrust == CKT_NSS_MUST_VERIFY_TRUST)
1050 || (targetTrust == CKT_NSS_VALID_DELEGATOR)) {
1051 /* source overrites the target */
1052 return USE_SOURCE;
1053 }
1054
1055 /* both have hard attributes, we have a conflict, let the target win. */
1056 return USE_TARGET;
1057 }
1058 /*
1059 * use the raw PKCS #11 interface to merge the S/MIME records
1060 */
1061 static SECStatus
1062 pk11_mergeTrust(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
1063 CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
1064 {
1065 CK_OBJECT_HANDLE targetTrustID;
1066 PLArenaPool *arena = NULL;
1067 SECStatus rv = SECSuccess;
1068 int error = 0;
1069 CK_ATTRIBUTE trustTemplate[] = {
1070 { CKA_ISSUER, NULL, 0 },
1071 { CKA_SERIAL_NUMBER, NULL, 0 },
1072 { CKA_CLASS, NULL, 0 },
1073 };
1074 CK_ULONG trustTemplateCount =
1075 sizeof(trustTemplate)/sizeof(trustTemplate[0]);
1076 CK_ATTRIBUTE trustCopyTemplate[] = {
1077 { CKA_CLASS, NULL, 0 },
1078 { CKA_TOKEN, NULL, 0 },
1079 { CKA_LABEL, NULL, 0 },
1080 { CKA_PRIVATE, NULL, 0 },
1081 { CKA_MODIFIABLE, NULL, 0 },
1082 { CKA_ISSUER, NULL, 0},
1083 { CKA_SERIAL_NUMBER, NULL, 0},
1084 { CKA_CERT_SHA1_HASH, NULL, 0 },
1085 { CKA_CERT_MD5_HASH, NULL, 0 },
1086 { CKA_TRUST_SERVER_AUTH, NULL, 0 },
1087 { CKA_TRUST_CLIENT_AUTH, NULL, 0 },
1088 { CKA_TRUST_CODE_SIGNING, NULL, 0 },
1089 { CKA_TRUST_EMAIL_PROTECTION, NULL, 0 },
1090 { CKA_TRUST_STEP_UP_APPROVED, NULL, 0 }
1091 };
1092 CK_ULONG trustCopyTemplateCount =
1093 sizeof(trustCopyTemplate)/sizeof(trustCopyTemplate[0]);
1094
1095 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
1096 if (arena == NULL) {
1097 rv = SECFailure;
1098 goto done;
1099 }
1100 /* check to see if the crl is already in the target slot */
1101 rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, trustTemplate,
1102 trustTemplateCount, id, &targetTrustID);
1103 if (rv != SECSuccess) {
1104 goto done;
1105 }
1106 if (targetTrustID != CK_INVALID_HANDLE) {
1107 /* a matching trust record already exists, merge it in */
1108 CK_ATTRIBUTE_TYPE trustAttrs[] = {
1109 CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH,
1110 CKA_TRUST_CODE_SIGNING, CKA_TRUST_EMAIL_PROTECTION,
1111 CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER,
1112 CKA_TRUST_TIME_STAMPING
1113 };
1114 CK_ULONG trustAttrsCount =
1115 sizeof(trustAttrs)/sizeof(trustAttrs[0]);
1116
1117 CK_ULONG i;
1118 CK_ATTRIBUTE targetTemplate, sourceTemplate;
1119
1120 /* existing trust record, merge the two together */
1121 for (i=0; i < trustAttrsCount; i++) {
1122 targetTemplate.type = sourceTemplate.type = trustAttrs[i];
1123 targetTemplate.pValue = sourceTemplate.pValue = NULL;
1124 targetTemplate.ulValueLen = sourceTemplate.ulValueLen = 0;
1125 PK11_GetAttributes(arena, sourceSlot, id, &sourceTemplate, 1);
1126 PK11_GetAttributes(arena, targetSlot, targetTrustID,
1127 &targetTemplate, 1);
1128 if (pk11_mergeTrustEntry(&targetTemplate, &sourceTemplate)) {
1129 /* source wins, write out the source attribute to the target */
1130 SECStatus lrv = pk11_setAttributes(targetSlot, targetTrustID,
1131 &sourceTemplate, 1);
1132 if (lrv != SECSuccess) {
1133 rv = SECFailure;
1134 error = PORT_GetError();
1135 }
1136 }
1137 }
1138
1139 /* handle step */
1140 sourceTemplate.type = CKA_TRUST_STEP_UP_APPROVED;
1141 sourceTemplate.pValue = NULL;
1142 sourceTemplate.ulValueLen = 0;
1143
1144 /* if the source has steup set, then set it in the target */
1145 PK11_GetAttributes(arena, sourceSlot, id, &sourceTemplate, 1);
1146 if ((sourceTemplate.ulValueLen == sizeof(CK_BBOOL)) &&
1147 (sourceTemplate.pValue) &&
1148 (*(CK_BBOOL *)sourceTemplate.pValue == CK_TRUE)) {
1149 SECStatus lrv = pk11_setAttributes(targetSlot, targetTrustID,
1150 &sourceTemplate, 1);
1151 if (lrv != SECSuccess) {
1152 rv = SECFailure;
1153 error = PORT_GetError();
1154 }
1155 }
1156
1157 goto done;
1158
1159 }
1160
1161 /* load the new trust Record into the target token. */
1162 rv = pk11_copyAttributes(arena, targetSlot, targetTrustID, sourceSlot, id,
1163 trustCopyTemplate, trustCopyTemplateCount);
1164 done:
1165 if (arena) {
1166 PORT_FreeArena(arena,PR_FALSE);
1167 }
1168
1169 /* restore the error code */
1170 if (rv == SECFailure && error) {
1171 PORT_SetError(error);
1172 }
1173
1174 return rv;
1175 }
1176
1177 /*************************************************************************
1178 *
1179 * Central merge code
1180 *
1181 *************************************************************************/
1182 /*
1183 * merge a single object from sourceToken to targetToken
1184 */
1185 static SECStatus
1186 pk11_mergeObject(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
1187 CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
1188 {
1189
1190 CK_OBJECT_CLASS objClass;
1191
1192
1193 objClass = PK11_ReadULongAttribute(sourceSlot, id, CKA_CLASS);
1194 if (objClass == (CK_ULONG) -1) {
1195 PORT_SetError( SEC_ERROR_UNKNOWN_OBJECT_TYPE );
1196 return SECFailure;
1197 }
1198
1199 switch (objClass) {
1200 case CKO_CERTIFICATE:
1201 return pk11_mergeCert(targetSlot, sourceSlot, id,
1202 targetPwArg, sourcePwArg);
1203 case CKO_NSS_TRUST:
1204 return pk11_mergeTrust(targetSlot, sourceSlot, id,
1205 targetPwArg, sourcePwArg);
1206 case CKO_PUBLIC_KEY:
1207 return pk11_mergePublicKey(targetSlot, sourceSlot, id,
1208 targetPwArg, sourcePwArg);
1209 case CKO_PRIVATE_KEY:
1210 return pk11_mergePrivateKey(targetSlot, sourceSlot, id,
1211 targetPwArg, sourcePwArg);
1212 case CKO_SECRET_KEY:
1213 return pk11_mergeSecretKey(targetSlot, sourceSlot, id,
1214 targetPwArg, sourcePwArg);
1215 case CKO_NSS_CRL:
1216 return pk11_mergeCrl(targetSlot, sourceSlot, id,
1217 targetPwArg, sourcePwArg);
1218 case CKO_NSS_SMIME:
1219 return pk11_mergeSmime(targetSlot, sourceSlot, id,
1220 targetPwArg, sourcePwArg);
1221 default:
1222 break;
1223 }
1224
1225 PORT_SetError( SEC_ERROR_UNKNOWN_OBJECT_TYPE );
1226 return SECFailure;
1227 }
1228
1229 PK11MergeLogNode *
1230 pk11_newMergeLogNode(PLArenaPool *arena,
1231 PK11SlotInfo *slot, CK_OBJECT_HANDLE id, int error)
1232 {
1233 PK11MergeLogNode *newLog;
1234 PK11GenericObject *obj;
1235
1236 newLog = PORT_ArenaZNew(arena, PK11MergeLogNode);
1237 if (newLog == NULL) {
1238 return NULL;
1239 }
1240
1241 obj = PORT_ArenaZNew(arena, PK11GenericObject);
1242 if ( !obj ) {
1243 return NULL;
1244 }
1245
1246 /* initialize it */
1247 obj->slot = slot;
1248 obj->objectID = id;
1249
1250 newLog->object= obj;
1251 newLog->error = error;
1252 return newLog;
1253 }
1254
1255 /*
1256 * walk down each entry and merge it. keep track of the errors in the log
1257 */
1258 static SECStatus
1259 pk11_mergeByObjectIDs(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
1260 CK_OBJECT_HANDLE *objectIDs, int count,
1261 PK11MergeLog *log, void *targetPwArg, void *sourcePwArg)
1262 {
1263 SECStatus rv = SECSuccess;
1264 int error = SEC_ERROR_LIBRARY_FAILURE;
1265 int 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 = SEC_ERROR_LIBRARY_FAILURE;
1330 int count = 0;
1331 CK_ATTRIBUTE search[2];
1332 CK_OBJECT_HANDLE *objectIDs = NULL;
1333 CK_BBOOL ck_true = CK_TRUE;
1334 CK_OBJECT_CLASS privKey = CKO_PRIVATE_KEY;
1335
1336 PK11_SETATTRS(&search[0], CKA_TOKEN, &ck_true, sizeof(ck_true));
1337 PK11_SETATTRS(&search[1], CKA_CLASS, &privKey, sizeof(privKey));
1338 /*
1339 * make sure both tokens are already authenticated if need be.
1340 */
1341 rv = PK11_Authenticate(targetSlot, PR_TRUE, targetPwArg);
1342 if (rv != SECSuccess) {
1343 goto loser;
1344 }
1345 rv = PK11_Authenticate(sourceSlot, PR_TRUE, sourcePwArg);
1346 if (rv != SECSuccess) {
1347 goto loser;
1348 }
1349
1350 /* turns out the old DB's are rather fragile if the private keys aren't
1351 * merged in first, so do the private keys explicity. */
1352 objectIDs = pk11_FindObjectsByTemplate(sourceSlot, search, 2, &count);
1353 if (objectIDs) {
1354 lrv = pk11_mergeByObjectIDs(targetSlot, sourceSlot,
1355 objectIDs, count, log,
1356 targetPwArg, sourcePwArg);
1357 if (lrv != SECSuccess) {
1358 error = PORT_GetError();
1359 }
1360 PORT_Free(objectIDs);
1361 count = 0;
1362 }
1363
1364 /* now do the rest (NOTE: this will repeat the private keys, but
1365 * that shouldnt' be an issue as we will notice they are already
1366 * merged in */
1367 objectIDs = pk11_FindObjectsByTemplate(sourceSlot, search, 1, &count);
1368 if (!objectIDs) {
1369 rv = SECFailure;
1370 goto loser;
1371 }
1372
1373 rv = pk11_mergeByObjectIDs(targetSlot, sourceSlot, objectIDs, count, log,
1374 targetPwArg, sourcePwArg);
1375 if (rv == SECSuccess) {
1376 /* if private keys failed, but the rest succeeded, be sure to let
1377 * the caller know that private keys failed and why.
1378 * NOTE: this is highly unlikely since the same keys that failed
1379 * in the previous merge call will most likely fail in this one */
1380 if (lrv != SECSuccess) {
1381 rv = lrv;
1382 PORT_SetError(error);
1383 }
1384 }
1385
1386 loser:
1387 if (objectIDs) {
1388 PORT_Free(objectIDs);
1389 }
1390 return rv;
1391 }
1392
1393 PK11MergeLog *
1394 PK11_CreateMergeLog(void)
1395 {
1396 PLArenaPool *arena;
1397 PK11MergeLog *log;
1398
1399 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
1400 if (arena == NULL) {
1401 return NULL;
1402 }
1403
1404 log = PORT_ArenaZNew(arena, PK11MergeLog);
1405 if (log == NULL) {
1406 PORT_FreeArena(arena,PR_FALSE);
1407 return NULL;
1408 }
1409 log->arena = arena;
1410 log->version = 1;
1411 return log;
1412 }
1413
1414 void
1415 PK11_DestroyMergeLog(PK11MergeLog *log)
1416 {
1417 if (log && log->arena) {
1418 PORT_FreeArena(log->arena, PR_FALSE);
1419 }
1420 }
OLDNEW
« no previous file with comments | « nss/lib/pk11wrap/pk11mech.c ('k') | nss/lib/pk11wrap/pk11nobj.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698