Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / security / nss / lib / pkcs12 / p12exp.c
blobb9ae89241fe3d6725d42db9651319b75e258c27e
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #include "plarena.h"
38 #include "secitem.h"
39 #include "secoid.h"
40 #include "seccomon.h"
41 #include "secport.h"
42 #include "cert.h"
43 #include "pkcs12.h"
44 #include "p12local.h"
45 #include "secpkcs7.h"
46 #include "secasn1.h"
47 #include "secerr.h"
48 #include "p12plcy.h"
50 /* release the memory taken up by the list of nicknames */
51 static void
52 sec_pkcs12_destroy_nickname_list(SECItem **nicknames)
54 int i = 0;
56 if(nicknames == NULL) {
57 return;
60 while(nicknames[i] != NULL) {
61 SECITEM_FreeItem(nicknames[i], PR_FALSE);
62 i++;
65 PORT_Free(nicknames);
68 /* release the memory taken up by the list of certificates */
69 static void
70 sec_pkcs12_destroy_certificate_list(CERTCertificate **ref_certs)
72 int i = 0;
74 if(ref_certs == NULL) {
75 return;
78 while(ref_certs[i] != NULL) {
79 CERT_DestroyCertificate(ref_certs[i]);
80 i++;
84 static void
85 sec_pkcs12_destroy_cinfos_for_cert_bags(SEC_PKCS12CertAndCRLBag *certBag)
87 int j = 0;
88 j = 0;
89 while(certBag->certAndCRLs[j] != NULL) {
90 SECOidTag certType = SECOID_FindOIDTag(&certBag->certAndCRLs[j]->BagID);
91 if(certType == SEC_OID_PKCS12_X509_CERT_CRL_BAG) {
92 SEC_PKCS12X509CertCRL *x509;
93 x509 = certBag->certAndCRLs[j]->value.x509;
94 SEC_PKCS7DestroyContentInfo(&x509->certOrCRL);
96 j++;
100 /* destroy all content infos since they were not allocated in common
101 * pool
103 static void
104 sec_pkcs12_destroy_cert_content_infos(SEC_PKCS12SafeContents *safe,
105 SEC_PKCS12Baggage *baggage)
107 int i, j;
109 if((safe != NULL) && (safe->contents != NULL)) {
110 i = 0;
111 while(safe->contents[i] != NULL) {
112 SECOidTag bagType = SECOID_FindOIDTag(&safe->contents[i]->safeBagType);
113 if(bagType == SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID) {
114 SEC_PKCS12CertAndCRLBag *certBag;
115 certBag = safe->contents[i]->safeContent.certAndCRLBag;
116 sec_pkcs12_destroy_cinfos_for_cert_bags(certBag);
118 i++;
122 if((baggage != NULL) && (baggage->bags != NULL)) {
123 i = 0;
124 while(baggage->bags[i] != NULL) {
125 if(baggage->bags[i]->unencSecrets != NULL) {
126 j = 0;
127 while(baggage->bags[i]->unencSecrets[j] != NULL) {
128 SECOidTag bagType;
129 bagType = SECOID_FindOIDTag(&baggage->bags[i]->unencSecrets[j]->safeBagType);
130 if(bagType == SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID) {
131 SEC_PKCS12CertAndCRLBag *certBag;
132 certBag = baggage->bags[i]->unencSecrets[j]->safeContent.certAndCRLBag;
133 sec_pkcs12_destroy_cinfos_for_cert_bags(certBag);
135 j++;
138 i++;
143 /* convert the nickname list from a NULL termincated Char list
144 * to a NULL terminated SECItem list
146 static SECItem **
147 sec_pkcs12_convert_nickname_list(char **nicknames)
149 SECItem **nicks;
150 int i, j;
151 PRBool error = PR_FALSE;
153 if(nicknames == NULL) {
154 return NULL;
157 i = j = 0;
158 while(nicknames[i] != NULL) {
159 i++;
162 /* allocate the space and copy the data */
163 nicks = (SECItem **)PORT_ZAlloc(sizeof(SECItem *) * (i + 1));
164 if(nicks != NULL) {
165 for(j = 0; ((j < i) && (error == PR_FALSE)); j++) {
166 nicks[j] = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
167 if(nicks[j] != NULL) {
168 nicks[j]->data =
169 (unsigned char *)PORT_ZAlloc(PORT_Strlen(nicknames[j])+1);
170 if(nicks[j]->data != NULL) {
171 nicks[j]->len = PORT_Strlen(nicknames[j]);
172 PORT_Memcpy(nicks[j]->data, nicknames[j], nicks[j]->len);
173 nicks[j]->data[nicks[j]->len] = 0;
174 } else {
175 error = PR_TRUE;
177 } else {
178 error = PR_TRUE;
183 if(error == PR_TRUE) {
184 for(i = 0; i < j; i++) {
185 SECITEM_FreeItem(nicks[i], PR_TRUE);
187 PORT_Free(nicks);
188 nicks = NULL;
191 return nicks;
194 /* package the certificate add_cert into PKCS12 structures,
195 * retrieve the certificate chain for the cert and return
196 * the packaged contents.
197 * poolp -- common memory pool;
198 * add_cert -- certificate to package up
199 * nickname for the certificate
200 * a return of NULL indicates an error
202 static SEC_PKCS12CertAndCRL *
203 sec_pkcs12_get_cert(PRArenaPool *poolp,
204 CERTCertificate *add_cert,
205 SECItem *nickname)
207 SEC_PKCS12CertAndCRL *cert;
208 SEC_PKCS7ContentInfo *cinfo;
209 SGNDigestInfo *t_di;
210 void *mark;
211 SECStatus rv;
213 if((poolp == NULL) || (add_cert == NULL) || (nickname == NULL)) {
214 return NULL;
216 mark = PORT_ArenaMark(poolp);
218 cert = sec_pkcs12_new_cert_crl(poolp, SEC_OID_PKCS12_X509_CERT_CRL_BAG);
219 if(cert != NULL) {
221 /* copy the nickname */
222 rv = SECITEM_CopyItem(poolp, &cert->nickname, nickname);
223 if(rv != SECSuccess) {
224 PORT_SetError(SEC_ERROR_NO_MEMORY);
225 cert = NULL;
226 } else {
228 /* package the certificate and cert chain into a NULL signer
229 * PKCS 7 SignedData content Info and prepare it for encoding
230 * since we cannot use DER_ANY_TEMPLATE
232 cinfo = SEC_PKCS7CreateCertsOnly(add_cert, PR_TRUE, NULL);
233 rv = SEC_PKCS7PrepareForEncode(cinfo, NULL, NULL, NULL);
235 /* thumbprint the certificate */
236 if((cinfo != NULL) && (rv == SECSuccess))
238 PORT_Memcpy(&cert->value.x509->certOrCRL, cinfo, sizeof(*cinfo));
239 t_di = sec_pkcs12_compute_thumbprint(&add_cert->derCert);
240 if(t_di != NULL)
242 /* test */
243 rv = SGN_CopyDigestInfo(poolp, &cert->value.x509->thumbprint,
244 t_di);
245 if(rv != SECSuccess) {
246 cert = NULL;
247 PORT_SetError(SEC_ERROR_NO_MEMORY);
249 SGN_DestroyDigestInfo(t_di);
251 else
252 cert = NULL;
257 if (cert == NULL) {
258 PORT_ArenaRelease(poolp, mark);
259 } else {
260 PORT_ArenaUnmark(poolp, mark);
263 return cert;
266 /* package the private key associated with the certificate and
267 * return the appropriate PKCS 12 structure
268 * poolp common memory pool
269 * nickname key nickname
270 * cert -- cert to look up
271 * wincx -- window handle
272 * an error is indicated by a return of NULL
274 static SEC_PKCS12PrivateKey *
275 sec_pkcs12_get_private_key(PRArenaPool *poolp,
276 SECItem *nickname,
277 CERTCertificate *cert,
278 void *wincx)
280 SECKEYPrivateKeyInfo *pki;
281 SEC_PKCS12PrivateKey *pk;
282 SECStatus rv;
283 void *mark;
285 if((poolp == NULL) || (nickname == NULL)) {
286 return NULL;
289 mark = PORT_ArenaMark(poolp);
291 /* retrieve key from the data base */
292 pki = PK11_ExportPrivateKeyInfo(nickname, cert, wincx);
293 if(pki == NULL) {
294 PORT_ArenaRelease(poolp, mark);
295 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
296 return NULL;
299 pk = (SEC_PKCS12PrivateKey *)PORT_ArenaZAlloc(poolp,
300 sizeof(SEC_PKCS12PrivateKey));
301 if(pk != NULL) {
302 rv = sec_pkcs12_init_pvk_data(poolp, &pk->pvkData);
304 if(rv == SECSuccess) {
305 /* copy the key into poolp memory space */
306 rv = SECKEY_CopyPrivateKeyInfo(poolp, &pk->pkcs8data, pki);
307 if(rv == SECSuccess) {
308 rv = SECITEM_CopyItem(poolp, &pk->pvkData.nickname, nickname);
312 if(rv != SECSuccess) {
313 PORT_SetError(SEC_ERROR_NO_MEMORY);
314 pk = NULL;
316 } else {
317 PORT_SetError(SEC_ERROR_NO_MEMORY);
320 /* destroy private key, zeroing out data */
321 SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE);
322 if (pk == NULL) {
323 PORT_ArenaRelease(poolp, mark);
324 } else {
325 PORT_ArenaUnmark(poolp, mark);
328 return pk;
331 /* get a shrouded key item associated with a certificate
332 * return the appropriate PKCS 12 structure
333 * poolp common memory pool
334 * nickname key nickname
335 * cert -- cert to look up
336 * wincx -- window handle
337 * an error is indicated by a return of NULL
339 static SEC_PKCS12ESPVKItem *
340 sec_pkcs12_get_shrouded_key(PRArenaPool *poolp,
341 SECItem *nickname,
342 CERTCertificate *cert,
343 SECOidTag algorithm,
344 SECItem *pwitem,
345 PKCS12UnicodeConvertFunction unicodeFn,
346 void *wincx)
348 SECKEYEncryptedPrivateKeyInfo *epki;
349 SEC_PKCS12ESPVKItem *pk;
350 void *mark;
351 SECStatus rv;
352 PK11SlotInfo *slot = NULL;
353 PRBool swapUnicodeBytes = PR_FALSE;
355 #ifdef IS_LITTLE_ENDIAN
356 swapUnicodeBytes = PR_TRUE;
357 #endif
359 if((poolp == NULL) || (nickname == NULL))
360 return NULL;
362 mark = PORT_ArenaMark(poolp);
364 /* use internal key slot */
365 slot = PK11_GetInternalKeySlot();
367 /* retrieve encrypted prviate key */
368 epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algorithm, pwitem,
369 nickname, cert, 1, 0, NULL);
370 PK11_FreeSlot(slot);
371 if(epki == NULL) {
372 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
373 PORT_ArenaRelease(poolp, mark);
374 return NULL;
377 /* create a private key and store the data into the poolp memory space */
378 pk = sec_pkcs12_create_espvk(poolp, SEC_OID_PKCS12_PKCS8_KEY_SHROUDING);
379 if(pk != NULL) {
380 rv = sec_pkcs12_init_pvk_data(poolp, &pk->espvkData);
381 rv = SECITEM_CopyItem(poolp, &pk->espvkData.nickname, nickname);
382 pk->espvkCipherText.pkcs8KeyShroud =
383 (SECKEYEncryptedPrivateKeyInfo *)PORT_ArenaZAlloc(poolp,
384 sizeof(SECKEYEncryptedPrivateKeyInfo));
385 if((pk->espvkCipherText.pkcs8KeyShroud != NULL) && (rv == SECSuccess)) {
386 rv = SECKEY_CopyEncryptedPrivateKeyInfo(poolp,
387 pk->espvkCipherText.pkcs8KeyShroud, epki);
388 if(rv == SECSuccess) {
389 rv = (*unicodeFn)(poolp, &pk->espvkData.uniNickName, nickname,
390 PR_TRUE, swapUnicodeBytes);
394 if(rv != SECSuccess) {
395 PORT_SetError(SEC_ERROR_NO_MEMORY);
396 pk = NULL;
400 SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
401 if(pk == NULL) {
402 PORT_ArenaRelease(poolp, mark);
403 } else {
404 PORT_ArenaUnmark(poolp, mark);
407 return pk;
410 /* add a thumbprint to a private key associated certs list
411 * pvk is the area where the list is stored
412 * thumb is the thumbprint to copy
413 * a return of SECFailure indicates an error
415 static SECStatus
416 sec_pkcs12_add_thumbprint(SEC_PKCS12PVKSupportingData *pvk,
417 SGNDigestInfo *thumb)
419 SGNDigestInfo **thumb_list = NULL;
420 int nthumbs, size;
421 void *mark, *dummy;
422 SECStatus rv = SECFailure;
424 if((pvk == NULL) || (thumb == NULL)) {
425 return SECFailure;
428 mark = PORT_ArenaMark(pvk->poolp);
430 thumb_list = pvk->assocCerts;
431 nthumbs = pvk->nThumbs;
433 /* allocate list space needed -- either growing or allocating
434 * list must be NULL terminated
436 size = sizeof(SGNDigestInfo *);
437 dummy = PORT_ArenaGrow(pvk->poolp, thumb_list, (size * (nthumbs + 1)),
438 (size * (nthumbs + 2)));
439 thumb_list = dummy;
440 if(dummy != NULL) {
441 thumb_list[nthumbs] = (SGNDigestInfo *)PORT_ArenaZAlloc(pvk->poolp,
442 sizeof(SGNDigestInfo));
443 if(thumb_list[nthumbs] != NULL) {
444 SGN_CopyDigestInfo(pvk->poolp, thumb_list[nthumbs], thumb);
445 nthumbs += 1;
446 thumb_list[nthumbs] = 0;
447 } else {
448 dummy = NULL;
452 if(dummy == NULL) {
453 PORT_ArenaRelease(pvk->poolp, mark);
454 return SECFailure;
457 pvk->assocCerts = thumb_list;
458 pvk->nThumbs = nthumbs;
460 PORT_ArenaUnmark(pvk->poolp, mark);
461 return SECSuccess;
464 /* search the list of shrouded keys in the baggage for the desired
465 * name. return a pointer to the item. a return of NULL indicates
466 * that no match was present or that an error occurred.
468 static SEC_PKCS12ESPVKItem *
469 sec_pkcs12_get_espvk_by_name(SEC_PKCS12Baggage *luggage,
470 SECItem *name)
472 PRBool found = PR_FALSE;
473 SEC_PKCS12ESPVKItem *espvk = NULL;
474 int i, j;
475 SECComparison rv = SECEqual;
476 SECItem *t_name;
477 SEC_PKCS12BaggageItem *bag;
479 if((luggage == NULL) || (name == NULL)) {
480 return NULL;
483 i = 0;
484 while((found == PR_FALSE) && (i < luggage->luggage_size)) {
485 j = 0;
486 bag = luggage->bags[i];
487 while((found == PR_FALSE) && (j < bag->nEspvks)) {
488 espvk = bag->espvks[j];
489 if(espvk->poolp == NULL) {
490 espvk->poolp = luggage->poolp;
492 t_name = SECITEM_DupItem(&espvk->espvkData.nickname);
493 if(t_name != NULL) {
494 rv = SECITEM_CompareItem(name, t_name);
495 if(rv == SECEqual) {
496 found = PR_TRUE;
498 SECITEM_FreeItem(t_name, PR_TRUE);
499 } else {
500 PORT_SetError(SEC_ERROR_NO_MEMORY);
501 return NULL;
503 j++;
505 i++;
508 if(found != PR_TRUE) {
509 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME);
510 return NULL;
513 return espvk;
516 /* locates a certificate and copies the thumbprint to the
517 * appropriate private key
519 static SECStatus
520 sec_pkcs12_propagate_thumbprints(SECItem **nicknames,
521 CERTCertificate **ref_certs,
522 SEC_PKCS12SafeContents *safe,
523 SEC_PKCS12Baggage *baggage)
525 SEC_PKCS12CertAndCRL *cert;
526 SEC_PKCS12PrivateKey *key;
527 SEC_PKCS12ESPVKItem *espvk;
528 int i;
529 PRBool error = PR_FALSE;
530 SECStatus rv = SECFailure;
532 if((nicknames == NULL) || (safe == NULL)) {
533 return SECFailure;
536 i = 0;
537 while((nicknames[i] != NULL) && (error == PR_FALSE)) {
538 /* process all certs */
539 cert = (SEC_PKCS12CertAndCRL *)sec_pkcs12_find_object(safe, baggage,
540 SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID,
541 nicknames[i], NULL);
542 if(cert != NULL) {
543 /* locate key and copy thumbprint */
544 key = (SEC_PKCS12PrivateKey *)sec_pkcs12_find_object(safe, baggage,
545 SEC_OID_PKCS12_KEY_BAG_ID,
546 nicknames[i], NULL);
547 if(key != NULL) {
548 key->pvkData.poolp = key->poolp;
549 rv = sec_pkcs12_add_thumbprint(&key->pvkData,
550 &cert->value.x509->thumbprint);
551 if(rv == SECFailure)
552 error = PR_TRUE; /* XXX Set error? */
555 /* look in the baggage as well...*/
556 if((baggage != NULL) && (error == PR_FALSE)) {
557 espvk = sec_pkcs12_get_espvk_by_name(baggage, nicknames[i]);
558 if(espvk != NULL) {
559 espvk->espvkData.poolp = espvk->poolp;
560 rv = sec_pkcs12_add_thumbprint(&espvk->espvkData,
561 &cert->value.x509->thumbprint);
562 if(rv == SECFailure)
563 error = PR_TRUE; /* XXX Set error? */
567 i++;
570 if(error == PR_TRUE) {
571 return SECFailure;
574 return SECSuccess;
577 /* append a safe bag to the end of the safe contents list */
578 SECStatus
579 sec_pkcs12_append_safe_bag(SEC_PKCS12SafeContents *safe,
580 SEC_PKCS12SafeBag *bag)
582 int size;
583 void *mark = NULL, *dummy = NULL;
585 if((bag == NULL) || (safe == NULL))
586 return SECFailure;
588 mark = PORT_ArenaMark(safe->poolp);
590 size = (safe->safe_size * sizeof(SEC_PKCS12SafeBag *));
592 if(safe->safe_size > 0) {
593 dummy = (SEC_PKCS12SafeBag **)PORT_ArenaGrow(safe->poolp,
594 safe->contents,
595 size,
596 (size + sizeof(SEC_PKCS12SafeBag *)));
597 safe->contents = dummy;
598 } else {
599 safe->contents = (SEC_PKCS12SafeBag **)PORT_ArenaZAlloc(safe->poolp,
600 (2 * sizeof(SEC_PKCS12SafeBag *)));
601 dummy = safe->contents;
604 if(dummy == NULL) {
605 PORT_SetError(SEC_ERROR_NO_MEMORY);
606 goto loser;
609 safe->contents[safe->safe_size] = bag;
610 safe->safe_size++;
611 safe->contents[safe->safe_size] = NULL;
613 PORT_ArenaUnmark(safe->poolp, mark);
614 return SECSuccess;
616 loser:
617 PORT_ArenaRelease(safe->poolp, mark);
618 return SECFailure;
621 /* append a certificate onto the end of a cert bag */
622 static SECStatus
623 sec_pkcs12_append_cert_to_bag(PRArenaPool *arena,
624 SEC_PKCS12SafeBag *safebag,
625 CERTCertificate *cert,
626 SECItem *nickname)
628 int size;
629 void *dummy = NULL, *mark = NULL;
630 SEC_PKCS12CertAndCRL *p12cert;
631 SEC_PKCS12CertAndCRLBag *bag;
633 if((arena == NULL) || (safebag == NULL) ||
634 (cert == NULL) || (nickname == NULL)) {
635 return SECFailure;
638 bag = safebag->safeContent.certAndCRLBag;
639 if(bag == NULL) {
640 return SECFailure;
643 mark = PORT_ArenaMark(arena);
645 p12cert = sec_pkcs12_get_cert(arena, cert, nickname);
646 if(p12cert == NULL) {
647 PORT_ArenaRelease(bag->poolp, mark);
648 return SECFailure;
651 size = bag->bag_size * sizeof(SEC_PKCS12CertAndCRL *);
652 if(bag->bag_size > 0) {
653 dummy = (SEC_PKCS12CertAndCRL **)PORT_ArenaGrow(bag->poolp,
654 bag->certAndCRLs, size, size + sizeof(SEC_PKCS12CertAndCRL *));
655 bag->certAndCRLs = dummy;
656 } else {
657 bag->certAndCRLs = (SEC_PKCS12CertAndCRL **)PORT_ArenaZAlloc(bag->poolp,
658 (2 * sizeof(SEC_PKCS12CertAndCRL *)));
659 dummy = bag->certAndCRLs;
662 if(dummy == NULL) {
663 PORT_SetError(SEC_ERROR_NO_MEMORY);
664 goto loser;
667 bag->certAndCRLs[bag->bag_size] = p12cert;
668 bag->bag_size++;
669 bag->certAndCRLs[bag->bag_size] = NULL;
671 PORT_ArenaUnmark(bag->poolp, mark);
672 return SECSuccess;
674 loser:
675 PORT_ArenaRelease(bag->poolp, mark);
676 return SECFailure;
679 /* append a key onto the end of a list of keys in a key bag */
680 SECStatus
681 sec_pkcs12_append_key_to_bag(SEC_PKCS12SafeBag *safebag,
682 SEC_PKCS12PrivateKey *pk)
684 void *mark, *dummy;
685 SEC_PKCS12PrivateKeyBag *bag;
686 int size;
688 if((safebag == NULL) || (pk == NULL))
689 return SECFailure;
691 bag = safebag->safeContent.keyBag;
692 if(bag == NULL) {
693 return SECFailure;
696 mark = PORT_ArenaMark(bag->poolp);
698 size = (bag->bag_size * sizeof(SEC_PKCS12PrivateKey *));
700 if(bag->bag_size > 0) {
701 dummy = (SEC_PKCS12PrivateKey **)PORT_ArenaGrow(bag->poolp,
702 bag->privateKeys,
703 size,
704 size + sizeof(SEC_PKCS12PrivateKey *));
705 bag->privateKeys = dummy;
706 } else {
707 bag->privateKeys = (SEC_PKCS12PrivateKey **)PORT_ArenaZAlloc(bag->poolp,
708 (2 * sizeof(SEC_PKCS12PrivateKey *)));
709 dummy = bag->privateKeys;
712 if(dummy == NULL) {
713 PORT_SetError(SEC_ERROR_NO_MEMORY);
714 goto loser;
717 bag->privateKeys[bag->bag_size] = pk;
718 bag->bag_size++;
719 bag->privateKeys[bag->bag_size] = NULL;
721 PORT_ArenaUnmark(bag->poolp, mark);
722 return SECSuccess;
724 loser:
725 /* XXX Free memory? */
726 PORT_ArenaRelease(bag->poolp, mark);
727 return SECFailure;
730 /* append a safe bag to the baggage area */
731 static SECStatus
732 sec_pkcs12_append_unshrouded_bag(SEC_PKCS12BaggageItem *bag,
733 SEC_PKCS12SafeBag *u_bag)
735 int size;
736 void *mark = NULL, *dummy = NULL;
738 if((bag == NULL) || (u_bag == NULL))
739 return SECFailure;
741 mark = PORT_ArenaMark(bag->poolp);
743 /* dump things into the first bag */
744 size = (bag->nSecrets + 1) * sizeof(SEC_PKCS12SafeBag *);
745 dummy = PORT_ArenaGrow(bag->poolp,
746 bag->unencSecrets, size,
747 size + sizeof(SEC_PKCS12SafeBag *));
748 bag->unencSecrets = dummy;
749 if(dummy == NULL) {
750 PORT_SetError(SEC_ERROR_NO_MEMORY);
751 goto loser;
754 bag->unencSecrets[bag->nSecrets] = u_bag;
755 bag->nSecrets++;
756 bag->unencSecrets[bag->nSecrets] = NULL;
758 PORT_ArenaUnmark(bag->poolp, mark);
759 return SECSuccess;
761 loser:
762 PORT_ArenaRelease(bag->poolp, mark);
763 return SECFailure;
766 /* gather up all certificates and keys and package them up
767 * in the safe, baggage, or both.
768 * nicknames is the list of nicknames and corresponding certs in ref_certs
769 * ref_certs a null terminated list of certificates
770 * rSafe, rBaggage -- return areas for safe and baggage
771 * shroud_keys -- store keys externally
772 * pwitem -- password for computing integrity mac and encrypting contents
773 * wincx -- window handle
775 * if a failure occurs, an error is set and SECFailure returned.
777 static SECStatus
778 sec_pkcs12_package_certs_and_keys(SECItem **nicknames,
779 CERTCertificate **ref_certs,
780 PRBool unencryptedCerts,
781 SEC_PKCS12SafeContents **rSafe,
782 SEC_PKCS12Baggage **rBaggage,
783 PRBool shroud_keys,
784 SECOidTag shroud_alg,
785 SECItem *pwitem,
786 PKCS12UnicodeConvertFunction unicodeFn,
787 void *wincx)
789 PRArenaPool *permArena;
790 SEC_PKCS12SafeContents *safe = NULL;
791 SEC_PKCS12Baggage *baggage = NULL;
793 SECStatus rv = SECFailure;
794 PRBool problem = PR_FALSE;
796 SEC_PKCS12ESPVKItem *espvk = NULL;
797 SEC_PKCS12PrivateKey *pk = NULL;
798 CERTCertificate *add_cert = NULL;
799 SEC_PKCS12SafeBag *certbag = NULL, *keybag = NULL;
800 SEC_PKCS12BaggageItem *external_bag = NULL;
801 int ncerts = 0, nkeys = 0;
802 int i;
804 if((nicknames == NULL) || (rSafe == NULL) || (rBaggage == NULL)) {
805 return SECFailure;
808 *rBaggage = baggage;
809 *rSafe = safe;
811 permArena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
812 if(permArena == NULL) {
813 PORT_SetError(SEC_ERROR_NO_MEMORY);
814 return SECFailure;
817 /* allocate structures */
818 safe = sec_pkcs12_create_safe_contents(permArena);
819 if(safe == NULL) {
820 PORT_SetError(SEC_ERROR_NO_MEMORY);
821 rv = SECFailure;
822 goto loser;
825 certbag = sec_pkcs12_create_safe_bag(permArena,
826 SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID);
827 if(certbag == NULL) {
828 rv = SECFailure;
829 goto loser;
832 if(shroud_keys != PR_TRUE) {
833 keybag = sec_pkcs12_create_safe_bag(permArena,
834 SEC_OID_PKCS12_KEY_BAG_ID);
835 if(keybag == NULL) {
836 rv = SECFailure;
837 goto loser;
841 if((shroud_keys == PR_TRUE) || (unencryptedCerts == PR_TRUE)) {
842 baggage = sec_pkcs12_create_baggage(permArena);
843 if(baggage == NULL) {
844 rv = SECFailure;
845 goto loser;
847 external_bag = sec_pkcs12_create_external_bag(baggage);
850 /* package keys and certs */
851 i = 0;
852 while((nicknames[i] != NULL) && (problem == PR_FALSE)) {
853 if(ref_certs[i] != NULL) {
854 /* append cert to bag o certs */
855 rv = sec_pkcs12_append_cert_to_bag(permArena, certbag,
856 ref_certs[i],
857 nicknames[i]);
858 if(rv == SECFailure) {
859 problem = PR_FALSE;
860 } else {
861 ncerts++;
864 if(rv == SECSuccess) {
865 /* package up them keys */
866 if(shroud_keys == PR_TRUE) {
867 espvk = sec_pkcs12_get_shrouded_key(permArena,
868 nicknames[i],
869 ref_certs[i],
870 shroud_alg,
871 pwitem, unicodeFn,
872 wincx);
873 if(espvk != NULL) {
874 rv = sec_pkcs12_append_shrouded_key(external_bag, espvk);
875 SECITEM_CopyItem(permArena, &espvk->derCert,
876 &ref_certs[i]->derCert);
877 } else {
878 rv = SECFailure;
880 } else {
881 pk = sec_pkcs12_get_private_key(permArena, nicknames[i],
882 ref_certs[i], wincx);
883 if(pk != NULL) {
884 rv = sec_pkcs12_append_key_to_bag(keybag, pk);
885 SECITEM_CopyItem(permArena, &espvk->derCert,
886 &ref_certs[i]->derCert);
887 } else {
888 rv = SECFailure;
892 if(rv == SECFailure) {
893 problem = PR_TRUE;
894 } else {
895 nkeys++;
898 } else {
899 /* handle only keys here ? */
900 problem = PR_TRUE;
902 i++;
905 /* let success fall through */
906 loser:
907 if(problem == PR_FALSE) {
908 /* if we have certs, we want to append the cert bag to the
909 * appropriate area
911 if(ncerts > 0) {
912 if(unencryptedCerts != PR_TRUE) {
913 rv = sec_pkcs12_append_safe_bag(safe, certbag);
914 } else {
915 rv = sec_pkcs12_append_unshrouded_bag(external_bag, certbag);
917 } else {
918 rv = SECSuccess;
921 /* append key bag, if they are stored in safe contents */
922 if((rv == SECSuccess) && (shroud_keys == PR_FALSE) && (nkeys > 0)) {
923 rv = sec_pkcs12_append_safe_bag(safe, keybag);
925 } else {
926 rv = SECFailure;
929 /* if baggage not used, NULLify it */
930 if((shroud_keys == PR_TRUE) || (unencryptedCerts == PR_TRUE)) {
931 if(((unencryptedCerts == PR_TRUE) && (ncerts == 0)) &&
932 ((shroud_keys == PR_TRUE) && (nkeys == 0)))
933 baggage = NULL;
934 } else {
935 baggage = NULL;
938 if((problem == PR_TRUE) || (rv == SECFailure)) {
939 PORT_FreeArena(permArena, PR_TRUE);
940 rv = SECFailure;
941 baggage = NULL;
942 safe = NULL;
945 *rBaggage = baggage;
946 *rSafe = safe;
948 return rv;
951 /* DER encode the safe contents and return a SECItem. if an error
952 * occurs, NULL is returned.
954 static SECItem *
955 sec_pkcs12_encode_safe_contents(SEC_PKCS12SafeContents *safe)
957 SECItem *dsafe = NULL, *tsafe;
958 void *dummy = NULL;
959 PRArenaPool *arena;
961 if(safe == NULL) {
962 return NULL;
965 /* rv = sec_pkcs12_prepare_for_der_code_safe(safe, PR_TRUE);
966 if(rv != SECSuccess) {
967 PORT_SetError(SEC_ERROR_NO_MEMORY);
968 return NULL;
971 arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
972 if(arena == NULL) {
973 PORT_SetError(SEC_ERROR_NO_MEMORY);
974 return NULL;
977 tsafe = (SECItem *)PORT_ArenaZAlloc(arena, sizeof(SECItem));
978 if(tsafe != NULL) {
979 dummy = SEC_ASN1EncodeItem(arena, tsafe, safe,
980 SEC_PKCS12SafeContentsTemplate);
981 if(dummy != NULL) {
982 dsafe = SECITEM_DupItem(tsafe);
983 } else {
984 PORT_SetError(SEC_ERROR_NO_MEMORY);
986 } else {
987 PORT_SetError(SEC_ERROR_NO_MEMORY);
990 PORT_FreeArena(arena, PR_TRUE);
992 return dsafe;
995 /* prepare the authenicated safe for encoding and encode it.
996 * baggage is copied to the appropriate area, safe is encoded and
997 * encrypted. the version and transport mode are set on the asafe.
998 * the whole ball of wax is then der encoded and packaged up into
999 * data content info
1000 * safe -- container of certs and keys, is encrypted.
1001 * baggage -- container of certs and keys, keys assumed to be encrypted by
1002 * another method, certs are in the clear
1003 * algorithm -- algorithm by which to encrypt safe
1004 * pwitem -- password for encryption
1005 * wincx - window handle
1007 * return of NULL is an error condition.
1009 static SEC_PKCS7ContentInfo *
1010 sec_pkcs12_get_auth_safe(SEC_PKCS12SafeContents *safe,
1011 SEC_PKCS12Baggage *baggage,
1012 SECOidTag algorithm,
1013 SECItem *pwitem,
1014 PKCS12UnicodeConvertFunction unicodeFn,
1015 void *wincx)
1017 SECItem *src = NULL, *dest = NULL, *psalt = NULL;
1018 PRArenaPool *poolp;
1019 SEC_PKCS12AuthenticatedSafe *asafe;
1020 SEC_PKCS7ContentInfo *safe_cinfo = NULL;
1021 SEC_PKCS7ContentInfo *asafe_cinfo = NULL;
1022 void *dummy;
1023 SECStatus rv = SECSuccess;
1024 PRBool swapUnicodeBytes = PR_FALSE;
1026 #ifdef IS_LITTLE_ENDIAN
1027 swapUnicodeBytes = PR_TRUE;
1028 #endif
1030 if(((safe != NULL) && (pwitem == NULL)) && (baggage == NULL))
1031 return NULL;
1033 poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
1034 if(poolp == NULL) {
1035 PORT_SetError(SEC_ERROR_NO_MEMORY);
1036 return NULL;
1039 /* prepare authenticated safe for encode */
1040 asafe = sec_pkcs12_new_asafe(poolp);
1041 if(asafe != NULL) {
1043 /* set version */
1044 dummy = SEC_ASN1EncodeInteger(asafe->poolp, &asafe->version,
1045 SEC_PKCS12_PFX_VERSION);
1046 if(dummy == NULL) {
1047 PORT_SetError(SEC_ERROR_NO_MEMORY);
1048 rv = SECFailure;
1049 goto loser;
1052 /* generate the privacy salt used to create virtual pwd */
1053 psalt = sec_pkcs12_generate_salt();
1054 if(psalt != NULL) {
1055 rv = SECITEM_CopyItem(asafe->poolp, &asafe->privacySalt,
1056 psalt);
1057 if(rv == SECSuccess) {
1058 asafe->privacySalt.len *= 8;
1060 else {
1061 SECITEM_ZfreeItem(psalt, PR_TRUE);
1062 PORT_SetError(SEC_ERROR_NO_MEMORY);
1063 goto loser;
1067 if((psalt == NULL) || (rv == SECFailure)) {
1068 PORT_SetError(SEC_ERROR_NO_MEMORY);
1069 rv = SECFailure;
1070 goto loser;
1073 /* package up safe contents */
1074 if(safe != NULL)
1076 safe_cinfo = SEC_PKCS7CreateEncryptedData(algorithm, NULL, wincx);
1077 if((safe_cinfo != NULL) && (safe->safe_size > 0)) {
1078 /* encode the safe and encrypt the contents of the
1079 * content info
1081 src = sec_pkcs12_encode_safe_contents(safe);
1083 if(src != NULL) {
1084 rv = SEC_PKCS7SetContent(safe_cinfo, (char *)src->data, src->len);
1085 SECITEM_ZfreeItem(src, PR_TRUE);
1086 if(rv == SECSuccess) {
1087 SECItem *vpwd;
1088 vpwd = sec_pkcs12_create_virtual_password(pwitem, psalt,
1089 unicodeFn, swapUnicodeBytes);
1090 if(vpwd != NULL) {
1091 rv = SEC_PKCS7EncryptContents(NULL, safe_cinfo,
1092 vpwd, wincx);
1093 SECITEM_ZfreeItem(vpwd, PR_TRUE);
1094 } else {
1095 rv = SECFailure;
1096 PORT_SetError(SEC_ERROR_NO_MEMORY);
1098 } else {
1099 PORT_SetError(SEC_ERROR_NO_MEMORY);
1101 } else {
1102 rv = SECFailure;
1104 } else if(safe->safe_size > 0) {
1105 PORT_SetError(SEC_ERROR_NO_MEMORY);
1106 goto loser;
1107 } else {
1108 /* case where there is NULL content in the safe contents */
1109 rv = SEC_PKCS7SetContent(safe_cinfo, NULL, 0);
1110 if(rv != SECFailure) {
1111 PORT_SetError(SEC_ERROR_NO_MEMORY);
1115 if(rv != SECSuccess) {
1116 SEC_PKCS7DestroyContentInfo(safe_cinfo);
1117 safe_cinfo = NULL;
1118 goto loser;
1121 asafe->safe = safe_cinfo;
1123 PORT_Memcpy(&asafe->safe, safe_cinfo, sizeof(*safe_cinfo));
1127 /* copy the baggage to the authenticated safe baggage if present */
1128 if(baggage != NULL) {
1129 PORT_Memcpy(&asafe->baggage, baggage, sizeof(*baggage));
1132 /* encode authenticated safe and store it in a Data content info */
1133 dest = (SECItem *)PORT_ArenaZAlloc(poolp, sizeof(SECItem));
1134 if(dest != NULL) {
1135 dummy = SEC_ASN1EncodeItem(poolp, dest, asafe,
1136 SEC_PKCS12AuthenticatedSafeTemplate);
1137 if(dummy != NULL) {
1138 asafe_cinfo = SEC_PKCS7CreateData();
1139 if(asafe_cinfo != NULL) {
1140 rv = SEC_PKCS7SetContent(asafe_cinfo,
1141 (char *)dest->data,
1142 dest->len);
1143 if(rv != SECSuccess) {
1144 PORT_SetError(SEC_ERROR_NO_MEMORY);
1145 SEC_PKCS7DestroyContentInfo(asafe_cinfo);
1146 asafe_cinfo = NULL;
1149 } else {
1150 PORT_SetError(SEC_ERROR_NO_MEMORY);
1151 rv = SECFailure;
1156 loser:
1157 PORT_FreeArena(poolp, PR_TRUE);
1158 if(safe_cinfo != NULL) {
1159 SEC_PKCS7DestroyContentInfo(safe_cinfo);
1161 if(psalt != NULL) {
1162 SECITEM_ZfreeItem(psalt, PR_TRUE);
1165 if(rv == SECFailure) {
1166 return NULL;
1169 return asafe_cinfo;
1172 /* generates the PFX and computes the mac on the authenticated safe
1173 * NULL implies an error
1175 static SEC_PKCS12PFXItem *
1176 sec_pkcs12_get_pfx(SEC_PKCS7ContentInfo *cinfo,
1177 PRBool do_mac,
1178 SECItem *pwitem, PKCS12UnicodeConvertFunction unicodeFn)
1180 SECItem *dest = NULL, *mac = NULL, *salt = NULL, *key = NULL;
1181 SEC_PKCS12PFXItem *pfx;
1182 SECStatus rv = SECFailure;
1183 SGNDigestInfo *di;
1184 SECItem *vpwd;
1185 PRBool swapUnicodeBytes = PR_FALSE;
1187 #ifdef IS_LITTLE_ENDIAN
1188 swapUnicodeBytes = PR_TRUE;
1189 #endif
1191 if((cinfo == NULL) || ((do_mac == PR_TRUE) && (pwitem == NULL))) {
1192 return NULL;
1195 /* allocate new pfx structure */
1196 pfx = sec_pkcs12_new_pfx();
1197 if(pfx == NULL) {
1198 PORT_SetError(SEC_ERROR_NO_MEMORY);
1199 return NULL;
1202 PORT_Memcpy(&pfx->authSafe, cinfo, sizeof(*cinfo));
1203 if(do_mac == PR_TRUE) {
1205 /* salt for computing mac */
1206 salt = sec_pkcs12_generate_salt();
1207 if(salt != NULL) {
1208 rv = SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, salt);
1209 pfx->macData.macSalt.len *= 8;
1211 vpwd = sec_pkcs12_create_virtual_password(pwitem, salt,
1212 unicodeFn, swapUnicodeBytes);
1213 if(vpwd == NULL) {
1214 rv = SECFailure;
1215 key = NULL;
1216 } else {
1217 key = sec_pkcs12_generate_key_from_password(SEC_OID_SHA1,
1218 salt, vpwd);
1219 SECITEM_ZfreeItem(vpwd, PR_TRUE);
1222 if((key != NULL) && (rv == SECSuccess)) {
1223 dest = SEC_PKCS7GetContent(cinfo);
1224 if(dest != NULL) {
1226 /* compute mac on data -- for password integrity mode */
1227 mac = sec_pkcs12_generate_mac(key, dest, PR_FALSE);
1228 if(mac != NULL) {
1229 di = SGN_CreateDigestInfo(SEC_OID_SHA1,
1230 mac->data, mac->len);
1231 if(di != NULL) {
1232 rv = SGN_CopyDigestInfo(pfx->poolp,
1233 &pfx->macData.safeMac, di);
1234 SGN_DestroyDigestInfo(di);
1235 } else {
1236 PORT_SetError(SEC_ERROR_NO_MEMORY);
1238 SECITEM_ZfreeItem(mac, PR_TRUE);
1240 } else {
1241 rv = SECFailure;
1243 } else {
1244 PORT_SetError(SEC_ERROR_NO_MEMORY);
1245 rv = SECFailure;
1248 if(key != NULL) {
1249 SECITEM_ZfreeItem(key, PR_TRUE);
1251 SECITEM_ZfreeItem(salt, PR_TRUE);
1255 if(rv == SECFailure) {
1256 SEC_PKCS12DestroyPFX(pfx);
1257 pfx = NULL;
1260 return pfx;
1263 /* der encode the pfx */
1264 static SECItem *
1265 sec_pkcs12_encode_pfx(SEC_PKCS12PFXItem *pfx)
1267 SECItem *dest;
1268 void *dummy;
1270 if(pfx == NULL) {
1271 return NULL;
1274 dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
1275 if(dest == NULL) {
1276 PORT_SetError(SEC_ERROR_NO_MEMORY);
1277 return NULL;
1280 dummy = SEC_ASN1EncodeItem(NULL, dest, pfx, SEC_PKCS12PFXItemTemplate);
1281 if(dummy == NULL) {
1282 PORT_SetError(SEC_ERROR_NO_MEMORY);
1283 SECITEM_ZfreeItem(dest, PR_TRUE);
1284 dest = NULL;
1287 return dest;
1290 SECItem *
1291 SEC_PKCS12GetPFX(char **nicknames,
1292 CERTCertificate **ref_certs,
1293 PRBool shroud_keys,
1294 SEC_PKCS5GetPBEPassword pbef,
1295 void *pbearg,
1296 PKCS12UnicodeConvertFunction unicodeFn,
1297 void *wincx)
1299 SECItem **nicks = NULL;
1300 SEC_PKCS12PFXItem *pfx = NULL;
1301 SEC_PKCS12Baggage *baggage = NULL;
1302 SEC_PKCS12SafeContents *safe = NULL;
1303 SEC_PKCS7ContentInfo *cinfo = NULL;
1304 SECStatus rv = SECFailure;
1305 SECItem *dest = NULL, *pwitem = NULL;
1306 PRBool problem = PR_FALSE;
1307 PRBool unencryptedCerts;
1308 SECOidTag shroud_alg, safe_alg;
1310 /* how should we encrypt certs ? */
1311 unencryptedCerts = !SEC_PKCS12IsEncryptionAllowed();
1312 if(!unencryptedCerts) {
1313 safe_alg = SEC_PKCS12GetPreferredEncryptionAlgorithm();
1314 if(safe_alg == SEC_OID_UNKNOWN) {
1315 safe_alg = SEC_PKCS12GetStrongestAllowedAlgorithm();
1317 if(safe_alg == SEC_OID_UNKNOWN) {
1318 unencryptedCerts = PR_TRUE;
1319 /* for export where no encryption is allowed, we still need
1320 * to encrypt the NULL contents per the spec. encrypted info
1321 * is known plaintext, so it shouldn't be a problem.
1323 safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC;
1325 } else {
1326 /* for export where no encryption is allowed, we still need
1327 * to encrypt the NULL contents per the spec. encrypted info
1328 * is known plaintext, so it shouldn't be a problem.
1330 safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC;
1333 /* keys are always stored with triple DES */
1334 shroud_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC;
1336 /* check for FIPS, if so, do not encrypt certs */
1337 if(PK11_IsFIPS() && !unencryptedCerts) {
1338 unencryptedCerts = PR_TRUE;
1341 if((nicknames == NULL) || (pbef == NULL) || (ref_certs == NULL)) {
1342 problem = PR_TRUE;
1343 goto loser;
1347 /* get password */
1348 pwitem = (*pbef)(pbearg);
1349 if(pwitem == NULL) {
1350 problem = PR_TRUE;
1351 goto loser;
1353 nicks = sec_pkcs12_convert_nickname_list(nicknames);
1355 /* get safe and baggage */
1356 rv = sec_pkcs12_package_certs_and_keys(nicks, ref_certs, unencryptedCerts,
1357 &safe, &baggage, shroud_keys,
1358 shroud_alg, pwitem, unicodeFn, wincx);
1359 if(rv == SECFailure) {
1360 problem = PR_TRUE;
1363 if((safe != NULL) && (problem == PR_FALSE)) {
1364 /* copy thumbprints */
1365 rv = sec_pkcs12_propagate_thumbprints(nicks, ref_certs, safe, baggage);
1367 /* package everything up into AuthenticatedSafe */
1368 cinfo = sec_pkcs12_get_auth_safe(safe, baggage,
1369 safe_alg, pwitem, unicodeFn, wincx);
1371 sec_pkcs12_destroy_cert_content_infos(safe, baggage);
1373 /* get the pfx and mac it */
1374 if(cinfo != NULL) {
1375 pfx = sec_pkcs12_get_pfx(cinfo, PR_TRUE, pwitem, unicodeFn);
1376 if(pfx != NULL) {
1377 dest = sec_pkcs12_encode_pfx(pfx);
1378 SEC_PKCS12DestroyPFX(pfx);
1380 SEC_PKCS7DestroyContentInfo(cinfo);
1383 if(safe != NULL) {
1384 PORT_FreeArena(safe->poolp, PR_TRUE);
1386 } else {
1387 if(safe != NULL) {
1388 PORT_FreeArena(safe->poolp, PR_TRUE);
1392 loser:
1393 if(nicks != NULL) {
1394 sec_pkcs12_destroy_nickname_list(nicks);
1397 if(ref_certs != NULL) {
1398 sec_pkcs12_destroy_certificate_list(ref_certs);
1401 if(pwitem != NULL) {
1402 SECITEM_ZfreeItem(pwitem, PR_TRUE);
1405 if(problem == PR_TRUE) {
1406 dest = NULL;
1409 return dest;