OLD | NEW |
| (Empty) |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
4 | |
5 #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]->safeBagTyp
e); | |
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 } | |
OLD | NEW |