Mercurial > trustbridge > nss-cmake-static
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 } |