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