|
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 #include "plarena.h" |
|
6 #include "secitem.h" |
|
7 #include "secoid.h" |
|
8 #include "seccomon.h" |
|
9 #include "secport.h" |
|
10 #include "cert.h" |
|
11 #include "pkcs12.h" |
|
12 #include "p12local.h" |
|
13 #include "secpkcs7.h" |
|
14 #include "secasn1.h" |
|
15 #include "secerr.h" |
|
16 #include "p12plcy.h" |
|
17 |
|
18 /* release the memory taken up by the list of nicknames */ |
|
19 static void |
|
20 sec_pkcs12_destroy_nickname_list(SECItem **nicknames) |
|
21 { |
|
22 int i = 0; |
|
23 |
|
24 if(nicknames == NULL) { |
|
25 return; |
|
26 } |
|
27 |
|
28 while(nicknames[i] != NULL) { |
|
29 SECITEM_FreeItem(nicknames[i], PR_FALSE); |
|
30 i++; |
|
31 } |
|
32 |
|
33 PORT_Free(nicknames); |
|
34 } |
|
35 |
|
36 /* release the memory taken up by the list of certificates */ |
|
37 static void |
|
38 sec_pkcs12_destroy_certificate_list(CERTCertificate **ref_certs) |
|
39 { |
|
40 int i = 0; |
|
41 |
|
42 if(ref_certs == NULL) { |
|
43 return; |
|
44 } |
|
45 |
|
46 while(ref_certs[i] != NULL) { |
|
47 CERT_DestroyCertificate(ref_certs[i]); |
|
48 i++; |
|
49 } |
|
50 } |
|
51 |
|
52 static void |
|
53 sec_pkcs12_destroy_cinfos_for_cert_bags(SEC_PKCS12CertAndCRLBag *certBag) |
|
54 { |
|
55 int j = 0; |
|
56 j = 0; |
|
57 while(certBag->certAndCRLs[j] != NULL) { |
|
58 SECOidTag certType = SECOID_FindOIDTag(&certBag->certAndCRLs[j]->BagID); |
|
59 if(certType == SEC_OID_PKCS12_X509_CERT_CRL_BAG) { |
|
60 SEC_PKCS12X509CertCRL *x509; |
|
61 x509 = certBag->certAndCRLs[j]->value.x509; |
|
62 SEC_PKCS7DestroyContentInfo(&x509->certOrCRL); |
|
63 } |
|
64 j++; |
|
65 } |
|
66 } |
|
67 |
|
68 /* destroy all content infos since they were not allocated in common |
|
69 * pool |
|
70 */ |
|
71 static void |
|
72 sec_pkcs12_destroy_cert_content_infos(SEC_PKCS12SafeContents *safe, |
|
73 SEC_PKCS12Baggage *baggage) |
|
74 { |
|
75 int i, j; |
|
76 |
|
77 if((safe != NULL) && (safe->contents != NULL)) { |
|
78 i = 0; |
|
79 while(safe->contents[i] != NULL) { |
|
80 SECOidTag bagType = SECOID_FindOIDTag(&safe->contents[i]->safeBagType); |
|
81 if(bagType == SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID) { |
|
82 SEC_PKCS12CertAndCRLBag *certBag; |
|
83 certBag = safe->contents[i]->safeContent.certAndCRLBag; |
|
84 sec_pkcs12_destroy_cinfos_for_cert_bags(certBag); |
|
85 } |
|
86 i++; |
|
87 } |
|
88 } |
|
89 |
|
90 if((baggage != NULL) && (baggage->bags != NULL)) { |
|
91 i = 0; |
|
92 while(baggage->bags[i] != NULL) { |
|
93 if(baggage->bags[i]->unencSecrets != NULL) { |
|
94 j = 0; |
|
95 while(baggage->bags[i]->unencSecrets[j] != NULL) { |
|
96 SECOidTag bagType; |
|
97 bagType = SECOID_FindOIDTag(&baggage->bags[i]->unencSecrets[j]->safeBagType); |
|
98 if(bagType == SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID) { |
|
99 SEC_PKCS12CertAndCRLBag *certBag; |
|
100 certBag = baggage->bags[i]->unencSecrets[j]->safeContent.certAndCRLBag; |
|
101 sec_pkcs12_destroy_cinfos_for_cert_bags(certBag); |
|
102 } |
|
103 j++; |
|
104 } |
|
105 } |
|
106 i++; |
|
107 } |
|
108 } |
|
109 } |
|
110 |
|
111 /* convert the nickname list from a NULL termincated Char list |
|
112 * to a NULL terminated SECItem list |
|
113 */ |
|
114 static SECItem ** |
|
115 sec_pkcs12_convert_nickname_list(char **nicknames) |
|
116 { |
|
117 SECItem **nicks; |
|
118 int i, j; |
|
119 PRBool error = PR_FALSE; |
|
120 |
|
121 if(nicknames == NULL) { |
|
122 return NULL; |
|
123 } |
|
124 |
|
125 i = j = 0; |
|
126 while(nicknames[i] != NULL) { |
|
127 i++; |
|
128 } |
|
129 |
|
130 /* allocate the space and copy the data */ |
|
131 nicks = (SECItem **)PORT_ZAlloc(sizeof(SECItem *) * (i + 1)); |
|
132 if(nicks != NULL) { |
|
133 for(j = 0; ((j < i) && (error == PR_FALSE)); j++) { |
|
134 nicks[j] = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); |
|
135 if(nicks[j] != NULL) { |
|
136 nicks[j]->data = |
|
137 (unsigned char *)PORT_ZAlloc(PORT_Strlen(nicknames[j])+1); |
|
138 if(nicks[j]->data != NULL) { |
|
139 nicks[j]->len = PORT_Strlen(nicknames[j]); |
|
140 PORT_Memcpy(nicks[j]->data, nicknames[j], nicks[j]->len); |
|
141 nicks[j]->data[nicks[j]->len] = 0; |
|
142 } else { |
|
143 error = PR_TRUE; |
|
144 } |
|
145 } else { |
|
146 error = PR_TRUE; |
|
147 } |
|
148 } |
|
149 } |
|
150 |
|
151 if(error == PR_TRUE) { |
|
152 for(i = 0; i < j; i++) { |
|
153 SECITEM_FreeItem(nicks[i], PR_TRUE); |
|
154 } |
|
155 PORT_Free(nicks); |
|
156 nicks = NULL; |
|
157 } |
|
158 |
|
159 return nicks; |
|
160 } |
|
161 |
|
162 /* package the certificate add_cert into PKCS12 structures, |
|
163 * retrieve the certificate chain for the cert and return |
|
164 * the packaged contents. |
|
165 * poolp -- common memory pool; |
|
166 * add_cert -- certificate to package up |
|
167 * nickname for the certificate |
|
168 * a return of NULL indicates an error |
|
169 */ |
|
170 static SEC_PKCS12CertAndCRL * |
|
171 sec_pkcs12_get_cert(PLArenaPool *poolp, |
|
172 CERTCertificate *add_cert, |
|
173 SECItem *nickname) |
|
174 { |
|
175 SEC_PKCS12CertAndCRL *cert; |
|
176 SEC_PKCS7ContentInfo *cinfo; |
|
177 SGNDigestInfo *t_di; |
|
178 void *mark; |
|
179 SECStatus rv; |
|
180 |
|
181 if((poolp == NULL) || (add_cert == NULL) || (nickname == NULL)) { |
|
182 return NULL; |
|
183 } |
|
184 mark = PORT_ArenaMark(poolp); |
|
185 |
|
186 cert = sec_pkcs12_new_cert_crl(poolp, SEC_OID_PKCS12_X509_CERT_CRL_BAG); |
|
187 if(cert != NULL) { |
|
188 |
|
189 /* copy the nickname */ |
|
190 rv = SECITEM_CopyItem(poolp, &cert->nickname, nickname); |
|
191 if(rv != SECSuccess) { |
|
192 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
193 cert = NULL; |
|
194 } else { |
|
195 |
|
196 /* package the certificate and cert chain into a NULL signer |
|
197 * PKCS 7 SignedData content Info and prepare it for encoding |
|
198 * since we cannot use DER_ANY_TEMPLATE |
|
199 */ |
|
200 cinfo = SEC_PKCS7CreateCertsOnly(add_cert, PR_TRUE, NULL); |
|
201 rv = SEC_PKCS7PrepareForEncode(cinfo, NULL, NULL, NULL); |
|
202 |
|
203 /* thumbprint the certificate */ |
|
204 if((cinfo != NULL) && (rv == SECSuccess)) |
|
205 { |
|
206 PORT_Memcpy(&cert->value.x509->certOrCRL, cinfo, sizeof(*cinfo)); |
|
207 t_di = sec_pkcs12_compute_thumbprint(&add_cert->derCert); |
|
208 if(t_di != NULL) |
|
209 { |
|
210 /* test */ |
|
211 rv = SGN_CopyDigestInfo(poolp, &cert->value.x509->thumbprint, |
|
212 t_di); |
|
213 if(rv != SECSuccess) { |
|
214 cert = NULL; |
|
215 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
216 } |
|
217 SGN_DestroyDigestInfo(t_di); |
|
218 } |
|
219 else |
|
220 cert = NULL; |
|
221 } |
|
222 } |
|
223 } |
|
224 |
|
225 if (cert == NULL) { |
|
226 PORT_ArenaRelease(poolp, mark); |
|
227 } else { |
|
228 PORT_ArenaUnmark(poolp, mark); |
|
229 } |
|
230 |
|
231 return cert; |
|
232 } |
|
233 |
|
234 /* package the private key associated with the certificate and |
|
235 * return the appropriate PKCS 12 structure |
|
236 * poolp common memory pool |
|
237 * nickname key nickname |
|
238 * cert -- cert to look up |
|
239 * wincx -- window handle |
|
240 * an error is indicated by a return of NULL |
|
241 */ |
|
242 static SEC_PKCS12PrivateKey * |
|
243 sec_pkcs12_get_private_key(PLArenaPool *poolp, |
|
244 SECItem *nickname, |
|
245 CERTCertificate *cert, |
|
246 void *wincx) |
|
247 { |
|
248 SECKEYPrivateKeyInfo *pki; |
|
249 SEC_PKCS12PrivateKey *pk; |
|
250 SECStatus rv; |
|
251 void *mark; |
|
252 |
|
253 if((poolp == NULL) || (nickname == NULL)) { |
|
254 return NULL; |
|
255 } |
|
256 |
|
257 mark = PORT_ArenaMark(poolp); |
|
258 |
|
259 /* retrieve key from the data base */ |
|
260 pki = PK11_ExportPrivateKeyInfo(nickname, cert, wincx); |
|
261 if(pki == NULL) { |
|
262 PORT_ArenaRelease(poolp, mark); |
|
263 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY); |
|
264 return NULL; |
|
265 } |
|
266 |
|
267 pk = (SEC_PKCS12PrivateKey *)PORT_ArenaZAlloc(poolp, |
|
268 sizeof(SEC_PKCS12PrivateKey)); |
|
269 if(pk != NULL) { |
|
270 rv = sec_pkcs12_init_pvk_data(poolp, &pk->pvkData); |
|
271 |
|
272 if(rv == SECSuccess) { |
|
273 /* copy the key into poolp memory space */ |
|
274 rv = SECKEY_CopyPrivateKeyInfo(poolp, &pk->pkcs8data, pki); |
|
275 if(rv == SECSuccess) { |
|
276 rv = SECITEM_CopyItem(poolp, &pk->pvkData.nickname, nickname); |
|
277 } |
|
278 } |
|
279 |
|
280 if(rv != SECSuccess) { |
|
281 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
282 pk = NULL; |
|
283 } |
|
284 } else { |
|
285 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
286 } |
|
287 |
|
288 /* destroy private key, zeroing out data */ |
|
289 SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE); |
|
290 if (pk == NULL) { |
|
291 PORT_ArenaRelease(poolp, mark); |
|
292 } else { |
|
293 PORT_ArenaUnmark(poolp, mark); |
|
294 } |
|
295 |
|
296 return pk; |
|
297 } |
|
298 |
|
299 /* get a shrouded key item associated with a certificate |
|
300 * return the appropriate PKCS 12 structure |
|
301 * poolp common memory pool |
|
302 * nickname key nickname |
|
303 * cert -- cert to look up |
|
304 * wincx -- window handle |
|
305 * an error is indicated by a return of NULL |
|
306 */ |
|
307 static SEC_PKCS12ESPVKItem * |
|
308 sec_pkcs12_get_shrouded_key(PLArenaPool *poolp, |
|
309 SECItem *nickname, |
|
310 CERTCertificate *cert, |
|
311 SECOidTag algorithm, |
|
312 SECItem *pwitem, |
|
313 PKCS12UnicodeConvertFunction unicodeFn, |
|
314 void *wincx) |
|
315 { |
|
316 SECKEYEncryptedPrivateKeyInfo *epki; |
|
317 SEC_PKCS12ESPVKItem *pk; |
|
318 void *mark; |
|
319 SECStatus rv; |
|
320 PK11SlotInfo *slot = NULL; |
|
321 PRBool swapUnicodeBytes = PR_FALSE; |
|
322 |
|
323 #ifdef IS_LITTLE_ENDIAN |
|
324 swapUnicodeBytes = PR_TRUE; |
|
325 #endif |
|
326 |
|
327 if((poolp == NULL) || (nickname == NULL)) |
|
328 return NULL; |
|
329 |
|
330 mark = PORT_ArenaMark(poolp); |
|
331 |
|
332 /* use internal key slot */ |
|
333 slot = PK11_GetInternalKeySlot(); |
|
334 |
|
335 /* retrieve encrypted prviate key */ |
|
336 epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algorithm, pwitem, |
|
337 nickname, cert, 1, 0, NULL); |
|
338 PK11_FreeSlot(slot); |
|
339 if(epki == NULL) { |
|
340 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY); |
|
341 PORT_ArenaRelease(poolp, mark); |
|
342 return NULL; |
|
343 } |
|
344 |
|
345 /* create a private key and store the data into the poolp memory space */ |
|
346 pk = sec_pkcs12_create_espvk(poolp, SEC_OID_PKCS12_PKCS8_KEY_SHROUDING); |
|
347 if(pk != NULL) { |
|
348 rv = sec_pkcs12_init_pvk_data(poolp, &pk->espvkData); |
|
349 rv = SECITEM_CopyItem(poolp, &pk->espvkData.nickname, nickname); |
|
350 pk->espvkCipherText.pkcs8KeyShroud = |
|
351 (SECKEYEncryptedPrivateKeyInfo *)PORT_ArenaZAlloc(poolp, |
|
352 sizeof(SECKEYEncryptedPrivateKeyInfo)); |
|
353 if((pk->espvkCipherText.pkcs8KeyShroud != NULL) && (rv == SECSuccess)) { |
|
354 rv = SECKEY_CopyEncryptedPrivateKeyInfo(poolp, |
|
355 pk->espvkCipherText.pkcs8KeyShroud, epki); |
|
356 if(rv == SECSuccess) { |
|
357 rv = (*unicodeFn)(poolp, &pk->espvkData.uniNickName, nickname, |
|
358 PR_TRUE, swapUnicodeBytes); |
|
359 } |
|
360 } |
|
361 |
|
362 if(rv != SECSuccess) { |
|
363 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
364 pk = NULL; |
|
365 } |
|
366 } |
|
367 |
|
368 SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE); |
|
369 if(pk == NULL) { |
|
370 PORT_ArenaRelease(poolp, mark); |
|
371 } else { |
|
372 PORT_ArenaUnmark(poolp, mark); |
|
373 } |
|
374 |
|
375 return pk; |
|
376 } |
|
377 |
|
378 /* add a thumbprint to a private key associated certs list |
|
379 * pvk is the area where the list is stored |
|
380 * thumb is the thumbprint to copy |
|
381 * a return of SECFailure indicates an error |
|
382 */ |
|
383 static SECStatus |
|
384 sec_pkcs12_add_thumbprint(SEC_PKCS12PVKSupportingData *pvk, |
|
385 SGNDigestInfo *thumb) |
|
386 { |
|
387 SGNDigestInfo **thumb_list = NULL; |
|
388 int nthumbs, size; |
|
389 void *mark, *dummy; |
|
390 SECStatus rv = SECFailure; |
|
391 |
|
392 if((pvk == NULL) || (thumb == NULL)) { |
|
393 return SECFailure; |
|
394 } |
|
395 |
|
396 mark = PORT_ArenaMark(pvk->poolp); |
|
397 |
|
398 thumb_list = pvk->assocCerts; |
|
399 nthumbs = pvk->nThumbs; |
|
400 |
|
401 /* allocate list space needed -- either growing or allocating |
|
402 * list must be NULL terminated |
|
403 */ |
|
404 size = sizeof(SGNDigestInfo *); |
|
405 dummy = PORT_ArenaGrow(pvk->poolp, thumb_list, (size * (nthumbs + 1)), |
|
406 (size * (nthumbs + 2))); |
|
407 thumb_list = dummy; |
|
408 if(dummy != NULL) { |
|
409 thumb_list[nthumbs] = (SGNDigestInfo *)PORT_ArenaZAlloc(pvk->poolp, |
|
410 sizeof(SGNDigestInfo)); |
|
411 if(thumb_list[nthumbs] != NULL) { |
|
412 SGN_CopyDigestInfo(pvk->poolp, thumb_list[nthumbs], thumb); |
|
413 nthumbs += 1; |
|
414 thumb_list[nthumbs] = 0; |
|
415 } else { |
|
416 dummy = NULL; |
|
417 } |
|
418 } |
|
419 |
|
420 if(dummy == NULL) { |
|
421 PORT_ArenaRelease(pvk->poolp, mark); |
|
422 return SECFailure; |
|
423 } |
|
424 |
|
425 pvk->assocCerts = thumb_list; |
|
426 pvk->nThumbs = nthumbs; |
|
427 |
|
428 PORT_ArenaUnmark(pvk->poolp, mark); |
|
429 return SECSuccess; |
|
430 } |
|
431 |
|
432 /* search the list of shrouded keys in the baggage for the desired |
|
433 * name. return a pointer to the item. a return of NULL indicates |
|
434 * that no match was present or that an error occurred. |
|
435 */ |
|
436 static SEC_PKCS12ESPVKItem * |
|
437 sec_pkcs12_get_espvk_by_name(SEC_PKCS12Baggage *luggage, |
|
438 SECItem *name) |
|
439 { |
|
440 PRBool found = PR_FALSE; |
|
441 SEC_PKCS12ESPVKItem *espvk = NULL; |
|
442 int i, j; |
|
443 SECComparison rv = SECEqual; |
|
444 SECItem *t_name; |
|
445 SEC_PKCS12BaggageItem *bag; |
|
446 |
|
447 if((luggage == NULL) || (name == NULL)) { |
|
448 return NULL; |
|
449 } |
|
450 |
|
451 i = 0; |
|
452 while((found == PR_FALSE) && (i < luggage->luggage_size)) { |
|
453 j = 0; |
|
454 bag = luggage->bags[i]; |
|
455 while((found == PR_FALSE) && (j < bag->nEspvks)) { |
|
456 espvk = bag->espvks[j]; |
|
457 if(espvk->poolp == NULL) { |
|
458 espvk->poolp = luggage->poolp; |
|
459 } |
|
460 t_name = SECITEM_DupItem(&espvk->espvkData.nickname); |
|
461 if(t_name != NULL) { |
|
462 rv = SECITEM_CompareItem(name, t_name); |
|
463 if(rv == SECEqual) { |
|
464 found = PR_TRUE; |
|
465 } |
|
466 SECITEM_FreeItem(t_name, PR_TRUE); |
|
467 } else { |
|
468 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
469 return NULL; |
|
470 } |
|
471 j++; |
|
472 } |
|
473 i++; |
|
474 } |
|
475 |
|
476 if(found != PR_TRUE) { |
|
477 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME); |
|
478 return NULL; |
|
479 } |
|
480 |
|
481 return espvk; |
|
482 } |
|
483 |
|
484 /* locates a certificate and copies the thumbprint to the |
|
485 * appropriate private key |
|
486 */ |
|
487 static SECStatus |
|
488 sec_pkcs12_propagate_thumbprints(SECItem **nicknames, |
|
489 CERTCertificate **ref_certs, |
|
490 SEC_PKCS12SafeContents *safe, |
|
491 SEC_PKCS12Baggage *baggage) |
|
492 { |
|
493 SEC_PKCS12CertAndCRL *cert; |
|
494 SEC_PKCS12PrivateKey *key; |
|
495 SEC_PKCS12ESPVKItem *espvk; |
|
496 int i; |
|
497 PRBool error = PR_FALSE; |
|
498 SECStatus rv = SECFailure; |
|
499 |
|
500 if((nicknames == NULL) || (safe == NULL)) { |
|
501 return SECFailure; |
|
502 } |
|
503 |
|
504 i = 0; |
|
505 while((nicknames[i] != NULL) && (error == PR_FALSE)) { |
|
506 /* process all certs */ |
|
507 cert = (SEC_PKCS12CertAndCRL *)sec_pkcs12_find_object(safe, baggage, |
|
508 SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID, |
|
509 nicknames[i], NULL); |
|
510 if(cert != NULL) { |
|
511 /* locate key and copy thumbprint */ |
|
512 key = (SEC_PKCS12PrivateKey *)sec_pkcs12_find_object(safe, baggage, |
|
513 SEC_OID_PKCS12_KEY_BAG_ID, |
|
514 nicknames[i], NULL); |
|
515 if(key != NULL) { |
|
516 key->pvkData.poolp = key->poolp; |
|
517 rv = sec_pkcs12_add_thumbprint(&key->pvkData, |
|
518 &cert->value.x509->thumbprint); |
|
519 if(rv == SECFailure) |
|
520 error = PR_TRUE; /* XXX Set error? */ |
|
521 } |
|
522 |
|
523 /* look in the baggage as well...*/ |
|
524 if((baggage != NULL) && (error == PR_FALSE)) { |
|
525 espvk = sec_pkcs12_get_espvk_by_name(baggage, nicknames[i]); |
|
526 if(espvk != NULL) { |
|
527 espvk->espvkData.poolp = espvk->poolp; |
|
528 rv = sec_pkcs12_add_thumbprint(&espvk->espvkData, |
|
529 &cert->value.x509->thumbprint); |
|
530 if(rv == SECFailure) |
|
531 error = PR_TRUE; /* XXX Set error? */ |
|
532 } |
|
533 } |
|
534 } |
|
535 i++; |
|
536 } |
|
537 |
|
538 if(error == PR_TRUE) { |
|
539 return SECFailure; |
|
540 } |
|
541 |
|
542 return SECSuccess; |
|
543 } |
|
544 |
|
545 /* append a safe bag to the end of the safe contents list */ |
|
546 SECStatus |
|
547 sec_pkcs12_append_safe_bag(SEC_PKCS12SafeContents *safe, |
|
548 SEC_PKCS12SafeBag *bag) |
|
549 { |
|
550 int size; |
|
551 void *mark = NULL, *dummy = NULL; |
|
552 |
|
553 if((bag == NULL) || (safe == NULL)) |
|
554 return SECFailure; |
|
555 |
|
556 mark = PORT_ArenaMark(safe->poolp); |
|
557 |
|
558 size = (safe->safe_size * sizeof(SEC_PKCS12SafeBag *)); |
|
559 |
|
560 if(safe->safe_size > 0) { |
|
561 dummy = (SEC_PKCS12SafeBag **)PORT_ArenaGrow(safe->poolp, |
|
562 safe->contents, |
|
563 size, |
|
564 (size + sizeof(SEC_PKCS12SafeBag *))); |
|
565 safe->contents = dummy; |
|
566 } else { |
|
567 safe->contents = (SEC_PKCS12SafeBag **)PORT_ArenaZAlloc(safe->poolp, |
|
568 (2 * sizeof(SEC_PKCS12SafeBag *))); |
|
569 dummy = safe->contents; |
|
570 } |
|
571 |
|
572 if(dummy == NULL) { |
|
573 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
574 goto loser; |
|
575 } |
|
576 |
|
577 safe->contents[safe->safe_size] = bag; |
|
578 safe->safe_size++; |
|
579 safe->contents[safe->safe_size] = NULL; |
|
580 |
|
581 PORT_ArenaUnmark(safe->poolp, mark); |
|
582 return SECSuccess; |
|
583 |
|
584 loser: |
|
585 PORT_ArenaRelease(safe->poolp, mark); |
|
586 return SECFailure; |
|
587 } |
|
588 |
|
589 /* append a certificate onto the end of a cert bag */ |
|
590 static SECStatus |
|
591 sec_pkcs12_append_cert_to_bag(PLArenaPool *arena, |
|
592 SEC_PKCS12SafeBag *safebag, |
|
593 CERTCertificate *cert, |
|
594 SECItem *nickname) |
|
595 { |
|
596 int size; |
|
597 void *dummy = NULL, *mark = NULL; |
|
598 SEC_PKCS12CertAndCRL *p12cert; |
|
599 SEC_PKCS12CertAndCRLBag *bag; |
|
600 |
|
601 if((arena == NULL) || (safebag == NULL) || |
|
602 (cert == NULL) || (nickname == NULL)) { |
|
603 return SECFailure; |
|
604 } |
|
605 |
|
606 bag = safebag->safeContent.certAndCRLBag; |
|
607 if(bag == NULL) { |
|
608 return SECFailure; |
|
609 } |
|
610 |
|
611 mark = PORT_ArenaMark(arena); |
|
612 |
|
613 p12cert = sec_pkcs12_get_cert(arena, cert, nickname); |
|
614 if(p12cert == NULL) { |
|
615 PORT_ArenaRelease(bag->poolp, mark); |
|
616 return SECFailure; |
|
617 } |
|
618 |
|
619 size = bag->bag_size * sizeof(SEC_PKCS12CertAndCRL *); |
|
620 if(bag->bag_size > 0) { |
|
621 dummy = (SEC_PKCS12CertAndCRL **)PORT_ArenaGrow(bag->poolp, |
|
622 bag->certAndCRLs, size, size + sizeof(SEC_PKCS12CertAndCRL *)); |
|
623 bag->certAndCRLs = dummy; |
|
624 } else { |
|
625 bag->certAndCRLs = (SEC_PKCS12CertAndCRL **)PORT_ArenaZAlloc(bag->poolp, |
|
626 (2 * sizeof(SEC_PKCS12CertAndCRL *))); |
|
627 dummy = bag->certAndCRLs; |
|
628 } |
|
629 |
|
630 if(dummy == NULL) { |
|
631 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
632 goto loser; |
|
633 } |
|
634 |
|
635 bag->certAndCRLs[bag->bag_size] = p12cert; |
|
636 bag->bag_size++; |
|
637 bag->certAndCRLs[bag->bag_size] = NULL; |
|
638 |
|
639 PORT_ArenaUnmark(bag->poolp, mark); |
|
640 return SECSuccess; |
|
641 |
|
642 loser: |
|
643 PORT_ArenaRelease(bag->poolp, mark); |
|
644 return SECFailure; |
|
645 } |
|
646 |
|
647 /* append a key onto the end of a list of keys in a key bag */ |
|
648 SECStatus |
|
649 sec_pkcs12_append_key_to_bag(SEC_PKCS12SafeBag *safebag, |
|
650 SEC_PKCS12PrivateKey *pk) |
|
651 { |
|
652 void *mark, *dummy; |
|
653 SEC_PKCS12PrivateKeyBag *bag; |
|
654 int size; |
|
655 |
|
656 if((safebag == NULL) || (pk == NULL)) |
|
657 return SECFailure; |
|
658 |
|
659 bag = safebag->safeContent.keyBag; |
|
660 if(bag == NULL) { |
|
661 return SECFailure; |
|
662 } |
|
663 |
|
664 mark = PORT_ArenaMark(bag->poolp); |
|
665 |
|
666 size = (bag->bag_size * sizeof(SEC_PKCS12PrivateKey *)); |
|
667 |
|
668 if(bag->bag_size > 0) { |
|
669 dummy = (SEC_PKCS12PrivateKey **)PORT_ArenaGrow(bag->poolp, |
|
670 bag->privateKeys, |
|
671 size, |
|
672 size + sizeof(SEC_PKCS12PrivateKey *)); |
|
673 bag->privateKeys = dummy; |
|
674 } else { |
|
675 bag->privateKeys = (SEC_PKCS12PrivateKey **)PORT_ArenaZAlloc(bag->poolp, |
|
676 (2 * sizeof(SEC_PKCS12PrivateKey *))); |
|
677 dummy = bag->privateKeys; |
|
678 } |
|
679 |
|
680 if(dummy == NULL) { |
|
681 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
682 goto loser; |
|
683 } |
|
684 |
|
685 bag->privateKeys[bag->bag_size] = pk; |
|
686 bag->bag_size++; |
|
687 bag->privateKeys[bag->bag_size] = NULL; |
|
688 |
|
689 PORT_ArenaUnmark(bag->poolp, mark); |
|
690 return SECSuccess; |
|
691 |
|
692 loser: |
|
693 /* XXX Free memory? */ |
|
694 PORT_ArenaRelease(bag->poolp, mark); |
|
695 return SECFailure; |
|
696 } |
|
697 |
|
698 /* append a safe bag to the baggage area */ |
|
699 static SECStatus |
|
700 sec_pkcs12_append_unshrouded_bag(SEC_PKCS12BaggageItem *bag, |
|
701 SEC_PKCS12SafeBag *u_bag) |
|
702 { |
|
703 int size; |
|
704 void *mark = NULL, *dummy = NULL; |
|
705 |
|
706 if((bag == NULL) || (u_bag == NULL)) |
|
707 return SECFailure; |
|
708 |
|
709 mark = PORT_ArenaMark(bag->poolp); |
|
710 |
|
711 /* dump things into the first bag */ |
|
712 size = (bag->nSecrets + 1) * sizeof(SEC_PKCS12SafeBag *); |
|
713 dummy = PORT_ArenaGrow(bag->poolp, |
|
714 bag->unencSecrets, size, |
|
715 size + sizeof(SEC_PKCS12SafeBag *)); |
|
716 bag->unencSecrets = dummy; |
|
717 if(dummy == NULL) { |
|
718 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
719 goto loser; |
|
720 } |
|
721 |
|
722 bag->unencSecrets[bag->nSecrets] = u_bag; |
|
723 bag->nSecrets++; |
|
724 bag->unencSecrets[bag->nSecrets] = NULL; |
|
725 |
|
726 PORT_ArenaUnmark(bag->poolp, mark); |
|
727 return SECSuccess; |
|
728 |
|
729 loser: |
|
730 PORT_ArenaRelease(bag->poolp, mark); |
|
731 return SECFailure; |
|
732 } |
|
733 |
|
734 /* gather up all certificates and keys and package them up |
|
735 * in the safe, baggage, or both. |
|
736 * nicknames is the list of nicknames and corresponding certs in ref_certs |
|
737 * ref_certs a null terminated list of certificates |
|
738 * rSafe, rBaggage -- return areas for safe and baggage |
|
739 * shroud_keys -- store keys externally |
|
740 * pwitem -- password for computing integrity mac and encrypting contents |
|
741 * wincx -- window handle |
|
742 * |
|
743 * if a failure occurs, an error is set and SECFailure returned. |
|
744 */ |
|
745 static SECStatus |
|
746 sec_pkcs12_package_certs_and_keys(SECItem **nicknames, |
|
747 CERTCertificate **ref_certs, |
|
748 PRBool unencryptedCerts, |
|
749 SEC_PKCS12SafeContents **rSafe, |
|
750 SEC_PKCS12Baggage **rBaggage, |
|
751 PRBool shroud_keys, |
|
752 SECOidTag shroud_alg, |
|
753 SECItem *pwitem, |
|
754 PKCS12UnicodeConvertFunction unicodeFn, |
|
755 void *wincx) |
|
756 { |
|
757 PLArenaPool *permArena; |
|
758 SEC_PKCS12SafeContents *safe = NULL; |
|
759 SEC_PKCS12Baggage *baggage = NULL; |
|
760 |
|
761 SECStatus rv = SECFailure; |
|
762 PRBool problem = PR_FALSE; |
|
763 |
|
764 SEC_PKCS12ESPVKItem *espvk = NULL; |
|
765 SEC_PKCS12PrivateKey *pk = NULL; |
|
766 CERTCertificate *add_cert = NULL; |
|
767 SEC_PKCS12SafeBag *certbag = NULL, *keybag = NULL; |
|
768 SEC_PKCS12BaggageItem *external_bag = NULL; |
|
769 int ncerts = 0, nkeys = 0; |
|
770 int i; |
|
771 |
|
772 if((nicknames == NULL) || (rSafe == NULL) || (rBaggage == NULL)) { |
|
773 return SECFailure; |
|
774 } |
|
775 |
|
776 *rBaggage = baggage; |
|
777 *rSafe = safe; |
|
778 |
|
779 permArena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
|
780 if(permArena == NULL) { |
|
781 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
782 return SECFailure; |
|
783 } |
|
784 |
|
785 /* allocate structures */ |
|
786 safe = sec_pkcs12_create_safe_contents(permArena); |
|
787 if(safe == NULL) { |
|
788 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
789 rv = SECFailure; |
|
790 goto loser; |
|
791 } |
|
792 |
|
793 certbag = sec_pkcs12_create_safe_bag(permArena, |
|
794 SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID); |
|
795 if(certbag == NULL) { |
|
796 rv = SECFailure; |
|
797 goto loser; |
|
798 } |
|
799 |
|
800 if(shroud_keys != PR_TRUE) { |
|
801 keybag = sec_pkcs12_create_safe_bag(permArena, |
|
802 SEC_OID_PKCS12_KEY_BAG_ID); |
|
803 if(keybag == NULL) { |
|
804 rv = SECFailure; |
|
805 goto loser; |
|
806 } |
|
807 } |
|
808 |
|
809 if((shroud_keys == PR_TRUE) || (unencryptedCerts == PR_TRUE)) { |
|
810 baggage = sec_pkcs12_create_baggage(permArena); |
|
811 if(baggage == NULL) { |
|
812 rv = SECFailure; |
|
813 goto loser; |
|
814 } |
|
815 external_bag = sec_pkcs12_create_external_bag(baggage); |
|
816 } |
|
817 |
|
818 /* package keys and certs */ |
|
819 i = 0; |
|
820 while((nicknames[i] != NULL) && (problem == PR_FALSE)) { |
|
821 if(ref_certs[i] != NULL) { |
|
822 /* append cert to bag o certs */ |
|
823 rv = sec_pkcs12_append_cert_to_bag(permArena, certbag, |
|
824 ref_certs[i], |
|
825 nicknames[i]); |
|
826 if(rv == SECFailure) { |
|
827 problem = PR_FALSE; |
|
828 } else { |
|
829 ncerts++; |
|
830 } |
|
831 |
|
832 if(rv == SECSuccess) { |
|
833 /* package up them keys */ |
|
834 if(shroud_keys == PR_TRUE) { |
|
835 espvk = sec_pkcs12_get_shrouded_key(permArena, |
|
836 nicknames[i], |
|
837 ref_certs[i], |
|
838 shroud_alg, |
|
839 pwitem, unicodeFn, |
|
840 wincx); |
|
841 if(espvk != NULL) { |
|
842 rv = sec_pkcs12_append_shrouded_key(external_bag, espvk); |
|
843 SECITEM_CopyItem(permArena, &espvk->derCert, |
|
844 &ref_certs[i]->derCert); |
|
845 } else { |
|
846 rv = SECFailure; |
|
847 } |
|
848 } else { |
|
849 pk = sec_pkcs12_get_private_key(permArena, nicknames[i], |
|
850 ref_certs[i], wincx); |
|
851 if(pk != NULL) { |
|
852 rv = sec_pkcs12_append_key_to_bag(keybag, pk); |
|
853 SECITEM_CopyItem(permArena, &espvk->derCert, |
|
854 &ref_certs[i]->derCert); |
|
855 } else { |
|
856 rv = SECFailure; |
|
857 } |
|
858 } |
|
859 |
|
860 if(rv == SECFailure) { |
|
861 problem = PR_TRUE; |
|
862 } else { |
|
863 nkeys++; |
|
864 } |
|
865 } |
|
866 } else { |
|
867 /* handle only keys here ? */ |
|
868 problem = PR_TRUE; |
|
869 } |
|
870 i++; |
|
871 } |
|
872 |
|
873 /* let success fall through */ |
|
874 loser: |
|
875 if(problem == PR_FALSE) { |
|
876 /* if we have certs, we want to append the cert bag to the |
|
877 * appropriate area |
|
878 */ |
|
879 if(ncerts > 0) { |
|
880 if(unencryptedCerts != PR_TRUE) { |
|
881 rv = sec_pkcs12_append_safe_bag(safe, certbag); |
|
882 } else { |
|
883 rv = sec_pkcs12_append_unshrouded_bag(external_bag, certbag); |
|
884 } |
|
885 } else { |
|
886 rv = SECSuccess; |
|
887 } |
|
888 |
|
889 /* append key bag, if they are stored in safe contents */ |
|
890 if((rv == SECSuccess) && (shroud_keys == PR_FALSE) && (nkeys > 0)) { |
|
891 rv = sec_pkcs12_append_safe_bag(safe, keybag); |
|
892 } |
|
893 } else { |
|
894 rv = SECFailure; |
|
895 } |
|
896 |
|
897 /* if baggage not used, NULLify it */ |
|
898 if((shroud_keys == PR_TRUE) || (unencryptedCerts == PR_TRUE)) { |
|
899 if(((unencryptedCerts == PR_TRUE) && (ncerts == 0)) && |
|
900 ((shroud_keys == PR_TRUE) && (nkeys == 0))) |
|
901 baggage = NULL; |
|
902 } else { |
|
903 baggage = NULL; |
|
904 } |
|
905 |
|
906 if((problem == PR_TRUE) || (rv == SECFailure)) { |
|
907 PORT_FreeArena(permArena, PR_TRUE); |
|
908 rv = SECFailure; |
|
909 baggage = NULL; |
|
910 safe = NULL; |
|
911 } |
|
912 |
|
913 *rBaggage = baggage; |
|
914 *rSafe = safe; |
|
915 |
|
916 return rv; |
|
917 } |
|
918 |
|
919 /* DER encode the safe contents and return a SECItem. if an error |
|
920 * occurs, NULL is returned. |
|
921 */ |
|
922 static SECItem * |
|
923 sec_pkcs12_encode_safe_contents(SEC_PKCS12SafeContents *safe) |
|
924 { |
|
925 SECItem *dsafe = NULL, *tsafe; |
|
926 void *dummy = NULL; |
|
927 PLArenaPool *arena; |
|
928 |
|
929 if(safe == NULL) { |
|
930 return NULL; |
|
931 } |
|
932 |
|
933 /* rv = sec_pkcs12_prepare_for_der_code_safe(safe, PR_TRUE); |
|
934 if(rv != SECSuccess) { |
|
935 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
936 return NULL; |
|
937 }*/ |
|
938 |
|
939 arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
|
940 if(arena == NULL) { |
|
941 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
942 return NULL; |
|
943 } |
|
944 |
|
945 tsafe = (SECItem *)PORT_ArenaZAlloc(arena, sizeof(SECItem)); |
|
946 if(tsafe != NULL) { |
|
947 dummy = SEC_ASN1EncodeItem(arena, tsafe, safe, |
|
948 SEC_PKCS12SafeContentsTemplate); |
|
949 if(dummy != NULL) { |
|
950 dsafe = SECITEM_DupItem(tsafe); |
|
951 } else { |
|
952 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
953 } |
|
954 } else { |
|
955 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
956 } |
|
957 |
|
958 PORT_FreeArena(arena, PR_TRUE); |
|
959 |
|
960 return dsafe; |
|
961 } |
|
962 |
|
963 /* prepare the authenicated safe for encoding and encode it. |
|
964 * baggage is copied to the appropriate area, safe is encoded and |
|
965 * encrypted. the version and transport mode are set on the asafe. |
|
966 * the whole ball of wax is then der encoded and packaged up into |
|
967 * data content info |
|
968 * safe -- container of certs and keys, is encrypted. |
|
969 * baggage -- container of certs and keys, keys assumed to be encrypted by |
|
970 * another method, certs are in the clear |
|
971 * algorithm -- algorithm by which to encrypt safe |
|
972 * pwitem -- password for encryption |
|
973 * wincx - window handle |
|
974 * |
|
975 * return of NULL is an error condition. |
|
976 */ |
|
977 static SEC_PKCS7ContentInfo * |
|
978 sec_pkcs12_get_auth_safe(SEC_PKCS12SafeContents *safe, |
|
979 SEC_PKCS12Baggage *baggage, |
|
980 SECOidTag algorithm, |
|
981 SECItem *pwitem, |
|
982 PKCS12UnicodeConvertFunction unicodeFn, |
|
983 void *wincx) |
|
984 { |
|
985 SECItem *src = NULL, *dest = NULL, *psalt = NULL; |
|
986 PLArenaPool *poolp; |
|
987 SEC_PKCS12AuthenticatedSafe *asafe; |
|
988 SEC_PKCS7ContentInfo *safe_cinfo = NULL; |
|
989 SEC_PKCS7ContentInfo *asafe_cinfo = NULL; |
|
990 void *dummy; |
|
991 SECStatus rv = SECSuccess; |
|
992 PRBool swapUnicodeBytes = PR_FALSE; |
|
993 |
|
994 #ifdef IS_LITTLE_ENDIAN |
|
995 swapUnicodeBytes = PR_TRUE; |
|
996 #endif |
|
997 |
|
998 if(((safe != NULL) && (pwitem == NULL)) && (baggage == NULL)) |
|
999 return NULL; |
|
1000 |
|
1001 poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
|
1002 if(poolp == NULL) { |
|
1003 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
1004 return NULL; |
|
1005 } |
|
1006 |
|
1007 /* prepare authenticated safe for encode */ |
|
1008 asafe = sec_pkcs12_new_asafe(poolp); |
|
1009 if(asafe != NULL) { |
|
1010 |
|
1011 /* set version */ |
|
1012 dummy = SEC_ASN1EncodeInteger(asafe->poolp, &asafe->version, |
|
1013 SEC_PKCS12_PFX_VERSION); |
|
1014 if(dummy == NULL) { |
|
1015 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
1016 rv = SECFailure; |
|
1017 goto loser; |
|
1018 } |
|
1019 |
|
1020 /* generate the privacy salt used to create virtual pwd */ |
|
1021 psalt = sec_pkcs12_generate_salt(); |
|
1022 if(psalt != NULL) { |
|
1023 rv = SECITEM_CopyItem(asafe->poolp, &asafe->privacySalt, |
|
1024 psalt); |
|
1025 if(rv == SECSuccess) { |
|
1026 asafe->privacySalt.len *= 8; |
|
1027 } |
|
1028 else { |
|
1029 SECITEM_ZfreeItem(psalt, PR_TRUE); |
|
1030 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
1031 goto loser; |
|
1032 } |
|
1033 } |
|
1034 |
|
1035 if((psalt == NULL) || (rv == SECFailure)) { |
|
1036 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
1037 rv = SECFailure; |
|
1038 goto loser; |
|
1039 } |
|
1040 |
|
1041 /* package up safe contents */ |
|
1042 if(safe != NULL) |
|
1043 { |
|
1044 safe_cinfo = SEC_PKCS7CreateEncryptedData(algorithm, NULL, wincx); |
|
1045 if((safe_cinfo != NULL) && (safe->safe_size > 0)) { |
|
1046 /* encode the safe and encrypt the contents of the |
|
1047 * content info |
|
1048 */ |
|
1049 src = sec_pkcs12_encode_safe_contents(safe); |
|
1050 |
|
1051 if(src != NULL) { |
|
1052 rv = SEC_PKCS7SetContent(safe_cinfo, (char *)src->data, src->len); |
|
1053 SECITEM_ZfreeItem(src, PR_TRUE); |
|
1054 if(rv == SECSuccess) { |
|
1055 SECItem *vpwd; |
|
1056 vpwd = sec_pkcs12_create_virtual_password(pwitem, psalt, |
|
1057 unicodeFn, swapUnicodeBytes); |
|
1058 if(vpwd != NULL) { |
|
1059 rv = SEC_PKCS7EncryptContents(NULL, safe_cinfo, |
|
1060 vpwd, wincx); |
|
1061 SECITEM_ZfreeItem(vpwd, PR_TRUE); |
|
1062 } else { |
|
1063 rv = SECFailure; |
|
1064 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
1065 } |
|
1066 } else { |
|
1067 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
1068 } |
|
1069 } else { |
|
1070 rv = SECFailure; |
|
1071 } |
|
1072 } else if(safe->safe_size > 0) { |
|
1073 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
1074 goto loser; |
|
1075 } else { |
|
1076 /* case where there is NULL content in the safe contents */ |
|
1077 rv = SEC_PKCS7SetContent(safe_cinfo, NULL, 0); |
|
1078 if(rv != SECFailure) { |
|
1079 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
1080 } |
|
1081 } |
|
1082 |
|
1083 if(rv != SECSuccess) { |
|
1084 SEC_PKCS7DestroyContentInfo(safe_cinfo); |
|
1085 safe_cinfo = NULL; |
|
1086 goto loser; |
|
1087 } |
|
1088 |
|
1089 asafe->safe = safe_cinfo; |
|
1090 /* |
|
1091 PORT_Memcpy(&asafe->safe, safe_cinfo, sizeof(*safe_cinfo)); |
|
1092 */ |
|
1093 } |
|
1094 |
|
1095 /* copy the baggage to the authenticated safe baggage if present */ |
|
1096 if(baggage != NULL) { |
|
1097 PORT_Memcpy(&asafe->baggage, baggage, sizeof(*baggage)); |
|
1098 } |
|
1099 |
|
1100 /* encode authenticated safe and store it in a Data content info */ |
|
1101 dest = (SECItem *)PORT_ArenaZAlloc(poolp, sizeof(SECItem)); |
|
1102 if(dest != NULL) { |
|
1103 dummy = SEC_ASN1EncodeItem(poolp, dest, asafe, |
|
1104 SEC_PKCS12AuthenticatedSafeTemplate); |
|
1105 if(dummy != NULL) { |
|
1106 asafe_cinfo = SEC_PKCS7CreateData(); |
|
1107 if(asafe_cinfo != NULL) { |
|
1108 rv = SEC_PKCS7SetContent(asafe_cinfo, |
|
1109 (char *)dest->data, |
|
1110 dest->len); |
|
1111 if(rv != SECSuccess) { |
|
1112 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
1113 SEC_PKCS7DestroyContentInfo(asafe_cinfo); |
|
1114 asafe_cinfo = NULL; |
|
1115 } |
|
1116 } |
|
1117 } else { |
|
1118 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
1119 rv = SECFailure; |
|
1120 } |
|
1121 } |
|
1122 } |
|
1123 |
|
1124 loser: |
|
1125 PORT_FreeArena(poolp, PR_TRUE); |
|
1126 if(safe_cinfo != NULL) { |
|
1127 SEC_PKCS7DestroyContentInfo(safe_cinfo); |
|
1128 } |
|
1129 if(psalt != NULL) { |
|
1130 SECITEM_ZfreeItem(psalt, PR_TRUE); |
|
1131 } |
|
1132 |
|
1133 if(rv == SECFailure) { |
|
1134 return NULL; |
|
1135 } |
|
1136 |
|
1137 return asafe_cinfo; |
|
1138 } |
|
1139 |
|
1140 /* generates the PFX and computes the mac on the authenticated safe |
|
1141 * NULL implies an error |
|
1142 */ |
|
1143 static SEC_PKCS12PFXItem * |
|
1144 sec_pkcs12_get_pfx(SEC_PKCS7ContentInfo *cinfo, |
|
1145 PRBool do_mac, |
|
1146 SECItem *pwitem, PKCS12UnicodeConvertFunction unicodeFn) |
|
1147 { |
|
1148 SECItem *dest = NULL, *mac = NULL, *salt = NULL, *key = NULL; |
|
1149 SEC_PKCS12PFXItem *pfx; |
|
1150 SECStatus rv = SECFailure; |
|
1151 SGNDigestInfo *di; |
|
1152 SECItem *vpwd; |
|
1153 PRBool swapUnicodeBytes = PR_FALSE; |
|
1154 |
|
1155 #ifdef IS_LITTLE_ENDIAN |
|
1156 swapUnicodeBytes = PR_TRUE; |
|
1157 #endif |
|
1158 |
|
1159 if((cinfo == NULL) || ((do_mac == PR_TRUE) && (pwitem == NULL))) { |
|
1160 return NULL; |
|
1161 } |
|
1162 |
|
1163 /* allocate new pfx structure */ |
|
1164 pfx = sec_pkcs12_new_pfx(); |
|
1165 if(pfx == NULL) { |
|
1166 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
1167 return NULL; |
|
1168 } |
|
1169 |
|
1170 PORT_Memcpy(&pfx->authSafe, cinfo, sizeof(*cinfo)); |
|
1171 if(do_mac == PR_TRUE) { |
|
1172 |
|
1173 /* salt for computing mac */ |
|
1174 salt = sec_pkcs12_generate_salt(); |
|
1175 if(salt != NULL) { |
|
1176 rv = SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, salt); |
|
1177 pfx->macData.macSalt.len *= 8; |
|
1178 |
|
1179 vpwd = sec_pkcs12_create_virtual_password(pwitem, salt, |
|
1180 unicodeFn, swapUnicodeBytes); |
|
1181 if(vpwd == NULL) { |
|
1182 rv = SECFailure; |
|
1183 key = NULL; |
|
1184 } else { |
|
1185 key = sec_pkcs12_generate_key_from_password(SEC_OID_SHA1, |
|
1186 salt, vpwd); |
|
1187 SECITEM_ZfreeItem(vpwd, PR_TRUE); |
|
1188 } |
|
1189 |
|
1190 if((key != NULL) && (rv == SECSuccess)) { |
|
1191 dest = SEC_PKCS7GetContent(cinfo); |
|
1192 if(dest != NULL) { |
|
1193 |
|
1194 /* compute mac on data -- for password integrity mode */ |
|
1195 mac = sec_pkcs12_generate_mac(key, dest, PR_FALSE); |
|
1196 if(mac != NULL) { |
|
1197 di = SGN_CreateDigestInfo(SEC_OID_SHA1, |
|
1198 mac->data, mac->len); |
|
1199 if(di != NULL) { |
|
1200 rv = SGN_CopyDigestInfo(pfx->poolp, |
|
1201 &pfx->macData.safeMac, di); |
|
1202 SGN_DestroyDigestInfo(di); |
|
1203 } else { |
|
1204 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
1205 } |
|
1206 SECITEM_ZfreeItem(mac, PR_TRUE); |
|
1207 } |
|
1208 } else { |
|
1209 rv = SECFailure; |
|
1210 } |
|
1211 } else { |
|
1212 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
1213 rv = SECFailure; |
|
1214 } |
|
1215 |
|
1216 if(key != NULL) { |
|
1217 SECITEM_ZfreeItem(key, PR_TRUE); |
|
1218 } |
|
1219 SECITEM_ZfreeItem(salt, PR_TRUE); |
|
1220 } |
|
1221 } |
|
1222 |
|
1223 if(rv == SECFailure) { |
|
1224 SEC_PKCS12DestroyPFX(pfx); |
|
1225 pfx = NULL; |
|
1226 } |
|
1227 |
|
1228 return pfx; |
|
1229 } |
|
1230 |
|
1231 /* der encode the pfx */ |
|
1232 static SECItem * |
|
1233 sec_pkcs12_encode_pfx(SEC_PKCS12PFXItem *pfx) |
|
1234 { |
|
1235 SECItem *dest; |
|
1236 void *dummy; |
|
1237 |
|
1238 if(pfx == NULL) { |
|
1239 return NULL; |
|
1240 } |
|
1241 |
|
1242 dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); |
|
1243 if(dest == NULL) { |
|
1244 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
1245 return NULL; |
|
1246 } |
|
1247 |
|
1248 dummy = SEC_ASN1EncodeItem(NULL, dest, pfx, SEC_PKCS12PFXItemTemplate); |
|
1249 if(dummy == NULL) { |
|
1250 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
1251 SECITEM_ZfreeItem(dest, PR_TRUE); |
|
1252 dest = NULL; |
|
1253 } |
|
1254 |
|
1255 return dest; |
|
1256 } |
|
1257 |
|
1258 SECItem * |
|
1259 SEC_PKCS12GetPFX(char **nicknames, |
|
1260 CERTCertificate **ref_certs, |
|
1261 PRBool shroud_keys, |
|
1262 SEC_PKCS5GetPBEPassword pbef, |
|
1263 void *pbearg, |
|
1264 PKCS12UnicodeConvertFunction unicodeFn, |
|
1265 void *wincx) |
|
1266 { |
|
1267 SECItem **nicks = NULL; |
|
1268 SEC_PKCS12PFXItem *pfx = NULL; |
|
1269 SEC_PKCS12Baggage *baggage = NULL; |
|
1270 SEC_PKCS12SafeContents *safe = NULL; |
|
1271 SEC_PKCS7ContentInfo *cinfo = NULL; |
|
1272 SECStatus rv = SECFailure; |
|
1273 SECItem *dest = NULL, *pwitem = NULL; |
|
1274 PRBool problem = PR_FALSE; |
|
1275 PRBool unencryptedCerts; |
|
1276 SECOidTag shroud_alg, safe_alg; |
|
1277 |
|
1278 /* how should we encrypt certs ? */ |
|
1279 unencryptedCerts = !SEC_PKCS12IsEncryptionAllowed(); |
|
1280 if(!unencryptedCerts) { |
|
1281 safe_alg = SEC_PKCS12GetPreferredEncryptionAlgorithm(); |
|
1282 if(safe_alg == SEC_OID_UNKNOWN) { |
|
1283 safe_alg = SEC_PKCS12GetStrongestAllowedAlgorithm(); |
|
1284 } |
|
1285 if(safe_alg == SEC_OID_UNKNOWN) { |
|
1286 unencryptedCerts = PR_TRUE; |
|
1287 /* for export where no encryption is allowed, we still need |
|
1288 * to encrypt the NULL contents per the spec. encrypted info |
|
1289 * is known plaintext, so it shouldn't be a problem. |
|
1290 */ |
|
1291 safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC; |
|
1292 } |
|
1293 } else { |
|
1294 /* for export where no encryption is allowed, we still need |
|
1295 * to encrypt the NULL contents per the spec. encrypted info |
|
1296 * is known plaintext, so it shouldn't be a problem. |
|
1297 */ |
|
1298 safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC; |
|
1299 } |
|
1300 |
|
1301 /* keys are always stored with triple DES */ |
|
1302 shroud_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC; |
|
1303 |
|
1304 /* check for FIPS, if so, do not encrypt certs */ |
|
1305 if(PK11_IsFIPS() && !unencryptedCerts) { |
|
1306 unencryptedCerts = PR_TRUE; |
|
1307 } |
|
1308 |
|
1309 if((nicknames == NULL) || (pbef == NULL) || (ref_certs == NULL)) { |
|
1310 problem = PR_TRUE; |
|
1311 goto loser; |
|
1312 } |
|
1313 |
|
1314 |
|
1315 /* get password */ |
|
1316 pwitem = (*pbef)(pbearg); |
|
1317 if(pwitem == NULL) { |
|
1318 problem = PR_TRUE; |
|
1319 goto loser; |
|
1320 } |
|
1321 nicks = sec_pkcs12_convert_nickname_list(nicknames); |
|
1322 |
|
1323 /* get safe and baggage */ |
|
1324 rv = sec_pkcs12_package_certs_and_keys(nicks, ref_certs, unencryptedCerts, |
|
1325 &safe, &baggage, shroud_keys, |
|
1326 shroud_alg, pwitem, unicodeFn, wincx); |
|
1327 if(rv == SECFailure) { |
|
1328 problem = PR_TRUE; |
|
1329 } |
|
1330 |
|
1331 if((safe != NULL) && (problem == PR_FALSE)) { |
|
1332 /* copy thumbprints */ |
|
1333 rv = sec_pkcs12_propagate_thumbprints(nicks, ref_certs, safe, baggage); |
|
1334 |
|
1335 /* package everything up into AuthenticatedSafe */ |
|
1336 cinfo = sec_pkcs12_get_auth_safe(safe, baggage, |
|
1337 safe_alg, pwitem, unicodeFn, wincx); |
|
1338 |
|
1339 sec_pkcs12_destroy_cert_content_infos(safe, baggage); |
|
1340 |
|
1341 /* get the pfx and mac it */ |
|
1342 if(cinfo != NULL) { |
|
1343 pfx = sec_pkcs12_get_pfx(cinfo, PR_TRUE, pwitem, unicodeFn); |
|
1344 if(pfx != NULL) { |
|
1345 dest = sec_pkcs12_encode_pfx(pfx); |
|
1346 SEC_PKCS12DestroyPFX(pfx); |
|
1347 } |
|
1348 SEC_PKCS7DestroyContentInfo(cinfo); |
|
1349 } |
|
1350 |
|
1351 if(safe != NULL) { |
|
1352 PORT_FreeArena(safe->poolp, PR_TRUE); |
|
1353 } |
|
1354 } else { |
|
1355 if(safe != NULL) { |
|
1356 PORT_FreeArena(safe->poolp, PR_TRUE); |
|
1357 } |
|
1358 } |
|
1359 |
|
1360 loser: |
|
1361 if(nicks != NULL) { |
|
1362 sec_pkcs12_destroy_nickname_list(nicks); |
|
1363 } |
|
1364 |
|
1365 if(ref_certs != NULL) { |
|
1366 sec_pkcs12_destroy_certificate_list(ref_certs); |
|
1367 } |
|
1368 |
|
1369 if(pwitem != NULL) { |
|
1370 SECITEM_ZfreeItem(pwitem, PR_TRUE); |
|
1371 } |
|
1372 |
|
1373 if(problem == PR_TRUE) { |
|
1374 dest = NULL; |
|
1375 } |
|
1376 |
|
1377 return dest; |
|
1378 } |