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 #ifdef _CRTDBG_MAP_ALLOC
6 #include <stdlib.h>
7 #include <crtdbg.h>
8 #endif
9 
10 #include <nspr.h>
11 #include "secutil.h"
12 #include "pk11func.h"
13 #include "pkcs12.h"
14 #include "p12plcy.h"
15 #include "pk12util.h"
16 #include "nss.h"
17 #include "secport.h"
18 #include "secpkcs5.h"
19 #include "sechash.h"
20 #include "certdb.h"
21 
22 #define PKCS12_IN_BUFFER_SIZE 200
23 
24 static char *progName;
25 PRBool pk12_debugging = PR_FALSE;
26 PRBool dumpRawFile;
27 static PRBool pk12uForceUnicode;
28 
29 PRIntn pk12uErrno = 0;
30 
31 static void
Usage()32 Usage()
33 {
34 #define FPS PR_fprintf(PR_STDERR,
35     FPS "Usage:	 %s -i importfile [-d certdir] [-P dbprefix] [-h tokenname]\n",
36 				 progName);
37     FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
38     FPS "\t\t [-v]\n");
39 
40     FPS "Usage:	 %s -l listfile [-d certdir] [-P dbprefix] [-h tokenname]\n",
41 				 progName);
42     FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
43     FPS "\t\t [-v]\n");
44 
45     FPS "Usage:	 %s -o exportfile -n certname [-d certdir] [-P dbprefix]\n",
46 		progName);
47     FPS "\t\t [-c key_cipher] [-C cert_cipher] [-M mac_alg]\n"
48         "\t\t [-m | --key_len keyLen] [--cert_key_len certKeyLen] [-v]\n");
49     FPS "\t\t [-k slotpwfile | -K slotpw]\n"
50         "\t\t [-w p12filepwfile | -W p12filepw]\n");
51 
52     exit(PK12UERR_USAGE);
53 }
54 
55 static PRBool
p12u_OpenFile(p12uContext * p12cxt,PRBool fileRead)56 p12u_OpenFile(p12uContext *p12cxt, PRBool fileRead)
57 {
58     if (!p12cxt || !p12cxt->filename) {
59         return PR_FALSE;
60     }
61 
62     if (fileRead) {
63         p12cxt->file = PR_Open(p12cxt->filename,
64                                PR_RDONLY, 0400);
65     } else {
66         p12cxt->file = PR_Open(p12cxt->filename,
67                                PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE,
68                                0600);
69     }
70 
71     if (!p12cxt->file) {
72         p12cxt->error = PR_TRUE;
73         return PR_FALSE;
74     }
75 
76     return PR_TRUE;
77 }
78 
79 static void
p12u_DestroyContext(p12uContext ** ppCtx,PRBool removeFile)80 p12u_DestroyContext(p12uContext **ppCtx, PRBool removeFile)
81 {
82     if (!ppCtx || !(*ppCtx)) {
83         return;
84     }
85 
86     if ((*ppCtx)->file != NULL) {
87         PR_Close((*ppCtx)->file);
88     }
89 
90     if ((*ppCtx)->filename != NULL) {
91         if (removeFile) {
92             PR_Delete((*ppCtx)->filename);
93         }
94         PL_strfree((*ppCtx)->filename);
95         (*ppCtx)->filename = NULL;
96     }
97 
98     PR_Free(*ppCtx);
99     *ppCtx = NULL;
100 }
101 
102 static p12uContext *
p12u_InitContext(PRBool fileImport,char * filename)103 p12u_InitContext(PRBool fileImport, char *filename)
104 {
105     p12uContext *p12cxt;
106 
107     p12cxt = PORT_ZNew(p12uContext);
108     if (!p12cxt) {
109         return NULL;
110     }
111 
112     p12cxt->error = PR_FALSE;
113     p12cxt->errorValue = 0;
114     p12cxt->filename = PL_strdup(filename);
115 
116     if (!p12u_OpenFile(p12cxt, fileImport)) {
117         p12u_DestroyContext(&p12cxt, PR_FALSE);
118         return NULL;
119     }
120 
121     return p12cxt;
122 }
123 
124 SECItem *
P12U_NicknameCollisionCallback(SECItem * old_nick,PRBool * cancel,void * wincx)125 P12U_NicknameCollisionCallback(SECItem *old_nick, PRBool *cancel, void *wincx)
126 {
127     char *nick = NULL;
128     SECItem *ret_nick = NULL;
129     CERTCertificate *cert = (CERTCertificate *)wincx;
130 
131     if (!cancel || !cert) {
132         pk12uErrno = PK12UERR_USER_CANCELLED;
133         return NULL;
134     }
135 
136     if (!old_nick)
137         fprintf(stdout, "pk12util: no nickname for cert in PKCS12 file.\n");
138 
139 #if 0
140     /* XXX not handled yet  */
141     *cancel = PR_TRUE;
142     return NULL;
143 
144 #else
145 
146     nick = CERT_MakeCANickname(cert);
147     if (!nick) {
148         return NULL;
149     }
150 
151     if (old_nick && old_nick->data && old_nick->len &&
152         PORT_Strlen(nick) == old_nick->len &&
153         !PORT_Strncmp((char *)old_nick->data, nick, old_nick->len)) {
154         PORT_Free(nick);
155         PORT_SetError(SEC_ERROR_IO);
156         return NULL;
157     }
158 
159     fprintf(stdout, "pk12util: using nickname: %s\n", nick);
160     ret_nick = PORT_ZNew(SECItem);
161     if (ret_nick == NULL) {
162         PORT_Free(nick);
163         return NULL;
164     }
165 
166     ret_nick->data = (unsigned char *)nick;
167     ret_nick->len = PORT_Strlen(nick);
168 
169     return ret_nick;
170 #endif
171 }
172 
173 static SECStatus
p12u_SwapUnicodeBytes(SECItem * uniItem)174 p12u_SwapUnicodeBytes(SECItem *uniItem)
175 {
176     unsigned int i;
177     unsigned char a;
178     if ((uniItem == NULL) || (uniItem->len % 2)) {
179         return SECFailure;
180     }
181     for (i = 0; i < uniItem->len; i += 2) {
182         a = uniItem->data[i];
183         uniItem->data[i] = uniItem->data[i + 1];
184         uniItem->data[i + 1] = a;
185     }
186     return SECSuccess;
187 }
188 
189 static PRBool
p12u_ucs2_ascii_conversion_function(PRBool toUnicode,unsigned char * inBuf,unsigned int inBufLen,unsigned char * outBuf,unsigned int maxOutBufLen,unsigned int * outBufLen,PRBool swapBytes)190 p12u_ucs2_ascii_conversion_function(PRBool toUnicode,
191                                     unsigned char *inBuf,
192                                     unsigned int inBufLen,
193                                     unsigned char *outBuf,
194                                     unsigned int maxOutBufLen,
195                                     unsigned int *outBufLen,
196                                     PRBool swapBytes)
197 {
198     SECItem it = { 0 };
199     SECItem *dup = NULL;
200     PRBool ret;
201 
202 #ifdef DEBUG_CONVERSION
203     if (pk12_debugging) {
204         int i;
205         printf("Converted from:\n");
206         for (i = 0; i < inBufLen; i++) {
207             printf("%2x ", inBuf[i]);
208             /*if (i%60 == 0) printf("\n");*/
209         }
210         printf("\n");
211     }
212 #endif
213     it.data = inBuf;
214     it.len = inBufLen;
215     dup = SECITEM_DupItem(&it);
216     if (!dup) {
217         return PR_FALSE;
218     }
219     /* If converting Unicode to ASCII, swap bytes before conversion
220      * as neccessary.
221      */
222     if (!toUnicode && swapBytes) {
223         if (p12u_SwapUnicodeBytes(dup) != SECSuccess) {
224             SECITEM_ZfreeItem(dup, PR_TRUE);
225             return PR_FALSE;
226         }
227     }
228     /* Perform the conversion. */
229     ret = PORT_UCS2_UTF8Conversion(toUnicode, dup->data, dup->len,
230                                    outBuf, maxOutBufLen, outBufLen);
231     SECITEM_ZfreeItem(dup, PR_TRUE);
232 
233 #ifdef DEBUG_CONVERSION
234     if (pk12_debugging) {
235         int i;
236         printf("Converted to:\n");
237         for (i = 0; i < *outBufLen; i++) {
238             printf("%2x ", outBuf[i]);
239             /*if (i%60 == 0) printf("\n");*/
240         }
241         printf("\n");
242     }
243 #endif
244     return ret;
245 }
246 
247 SECStatus
P12U_UnicodeConversion(PLArenaPool * arena,SECItem * dest,SECItem * src,PRBool toUnicode,PRBool swapBytes)248 P12U_UnicodeConversion(PLArenaPool *arena, SECItem *dest, SECItem *src,
249                        PRBool toUnicode, PRBool swapBytes)
250 {
251     unsigned int allocLen;
252     if (!dest || !src) {
253         return SECFailure;
254     }
255     allocLen = ((toUnicode) ? (src->len << 2) : src->len);
256     if (arena) {
257         dest->data = PORT_ArenaZAlloc(arena, allocLen);
258     } else {
259         dest->data = PORT_ZAlloc(allocLen);
260     }
261     if (PORT_UCS2_ASCIIConversion(toUnicode, src->data, src->len,
262                                   dest->data, allocLen, &dest->len,
263                                   swapBytes) == PR_FALSE) {
264         if (!arena) {
265             PORT_Free(dest->data);
266         }
267         dest->data = NULL;
268         return SECFailure;
269     }
270     return SECSuccess;
271 }
272 
273 /*
274  *
275  */
276 SECItem *
P12U_GetP12FilePassword(PRBool confirmPw,secuPWData * p12FilePw)277 P12U_GetP12FilePassword(PRBool confirmPw, secuPWData *p12FilePw)
278 {
279     char *p0 = NULL;
280     SECItem *pwItem = NULL;
281 
282     if (p12FilePw == NULL || p12FilePw->source == PW_NONE) {
283         char *p1 = NULL;
284         int rc;
285         for (;;) {
286             p0 = SECU_GetPasswordString(NULL,
287                                         "Enter password for PKCS12 file: ");
288             if (!confirmPw || p0 == NULL)
289                 break;
290             p1 = SECU_GetPasswordString(NULL, "Re-enter password: ");
291             if (p1 == NULL) {
292                 PORT_ZFree(p0, PL_strlen(p0));
293                 p0 = NULL;
294                 break;
295             }
296             rc = PL_strcmp(p0, p1);
297             PORT_ZFree(p1, PL_strlen(p1));
298             if (rc == 0)
299                 break;
300             PORT_ZFree(p0, PL_strlen(p0));
301         }
302     } else if (p12FilePw->source == PW_FROMFILE) {
303         p0 = SECU_FilePasswd(NULL, PR_FALSE, p12FilePw->data);
304     } else { /* Plaintext */
305         p0 = PORT_Strdup(p12FilePw->data);
306     }
307 
308     if (p0 == NULL) {
309         return NULL;
310     }
311     pwItem = SECITEM_AllocItem(NULL, NULL, PL_strlen(p0) + 1);
312     memcpy(pwItem->data, p0, pwItem->len);
313 
314     PORT_ZFree(p0, PL_strlen(p0));
315 
316     return pwItem;
317 }
318 
319 SECStatus
P12U_InitSlot(PK11SlotInfo * slot,secuPWData * slotPw)320 P12U_InitSlot(PK11SlotInfo *slot, secuPWData *slotPw)
321 {
322     SECStatus rv;
323 
324     /*	New databases, initialize keydb password. */
325     if (PK11_NeedUserInit(slot)) {
326         rv = SECU_ChangePW(slot,
327                            (slotPw->source == PW_PLAINTEXT) ? slotPw->data : 0,
328                            (slotPw->source == PW_FROMFILE) ? slotPw->data : 0);
329         if (rv != SECSuccess) {
330             SECU_PrintError(progName, "Failed to initialize slot \"%s\"",
331                             PK11_GetSlotName(slot));
332             return SECFailure;
333         }
334     }
335 
336     if (PK11_Authenticate(slot, PR_TRUE, slotPw) != SECSuccess) {
337         SECU_PrintError(progName,
338                         "Failed to authenticate to PKCS11 slot");
339         PORT_SetError(SEC_ERROR_USER_CANCELLED);
340         pk12uErrno = PK12UERR_USER_CANCELLED;
341         return SECFailure;
342     }
343 
344     return SECSuccess;
345 }
346 
347 /* This routine takes care of getting the PKCS12 file password, then reading and
348  * verifying the file. It returns the decoder context and a filled in password.
349  * (The password is needed by P12U_ImportPKCS12Object() to import the private
350  * key.)
351  */
352 SEC_PKCS12DecoderContext *
p12U_ReadPKCS12File(SECItem * uniPwp,char * in_file,PK11SlotInfo * slot,secuPWData * slotPw,secuPWData * p12FilePw)353 p12U_ReadPKCS12File(SECItem *uniPwp, char *in_file, PK11SlotInfo *slot,
354                     secuPWData *slotPw, secuPWData *p12FilePw)
355 {
356     SEC_PKCS12DecoderContext *p12dcx = NULL;
357     p12uContext *p12cxt = NULL;
358     SECItem *pwitem = NULL;
359     SECItem p12file = { 0 };
360     SECStatus rv = SECFailure;
361     PRBool swapUnicode = PR_FALSE;
362     PRBool forceUnicode = pk12uForceUnicode;
363     PRBool trypw;
364     int error;
365 
366 #ifdef IS_LITTLE_ENDIAN
367     swapUnicode = PR_TRUE;
368 #endif
369 
370     p12cxt = p12u_InitContext(PR_TRUE, in_file);
371     if (!p12cxt) {
372         SECU_PrintError(progName, "File Open failed: %s", in_file);
373         pk12uErrno = PK12UERR_INIT_FILE;
374         return NULL;
375     }
376 
377     /* get the password */
378     pwitem = P12U_GetP12FilePassword(PR_FALSE, p12FilePw);
379     if (!pwitem) {
380         pk12uErrno = PK12UERR_USER_CANCELLED;
381         goto done;
382     }
383 
384     if (P12U_UnicodeConversion(NULL, uniPwp, pwitem, PR_TRUE,
385                                swapUnicode) != SECSuccess) {
386         SECU_PrintError(progName, "Unicode conversion failed");
387         pk12uErrno = PK12UERR_UNICODECONV;
388         goto done;
389     }
390     rv = SECU_FileToItem(&p12file, p12cxt->file);
391     if (rv != SECSuccess) {
392         SECU_PrintError(progName, "Failed to read from import file");
393         goto done;
394     }
395 
396     do {
397         trypw = PR_FALSE; /* normally we do this once */
398         rv = SECFailure;
399         /* init the decoder context */
400         p12dcx = SEC_PKCS12DecoderStart(uniPwp, slot, slotPw,
401                                         NULL, NULL, NULL, NULL, NULL);
402         if (!p12dcx) {
403             SECU_PrintError(progName, "PKCS12 decoder start failed");
404             pk12uErrno = PK12UERR_PK12DECODESTART;
405             break;
406         }
407 
408         /* decode the item */
409         rv = SEC_PKCS12DecoderUpdate(p12dcx, p12file.data, p12file.len);
410 
411         if (rv != SECSuccess) {
412             error = PR_GetError();
413             if (error == SEC_ERROR_DECRYPTION_DISALLOWED) {
414                 PR_SetError(error, 0);
415                 break;
416             }
417             SECU_PrintError(progName, "PKCS12 decoding failed");
418             pk12uErrno = PK12UERR_DECODE;
419         }
420 
421         /* does the blob authenticate properly? */
422         rv = SEC_PKCS12DecoderVerify(p12dcx);
423         if (rv != SECSuccess) {
424             if (uniPwp->len == 2) {
425                 /* this is a null PW, try once more with a zero-length PW
426                    instead of a null string */
427                 SEC_PKCS12DecoderFinish(p12dcx);
428                 uniPwp->len = 0;
429                 trypw = PR_TRUE;
430             } else if (forceUnicode == pk12uForceUnicode) {
431                 /* try again with a different password encoding */
432                 forceUnicode = !pk12uForceUnicode;
433                 rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE,
434                                    forceUnicode);
435                 if (rv != SECSuccess) {
436                     SECU_PrintError(progName, "PKCS12 decoding failed to set option");
437                     pk12uErrno = PK12UERR_DECODEVERIFY;
438                     break;
439                 }
440                 SEC_PKCS12DecoderFinish(p12dcx);
441                 trypw = PR_TRUE;
442             } else {
443                 SECU_PrintError(progName, "PKCS12 decode not verified");
444                 pk12uErrno = PK12UERR_DECODEVERIFY;
445                 break;
446             }
447         }
448     } while (trypw == PR_TRUE);
449 
450     /* revert the option setting */
451     if (forceUnicode != pk12uForceUnicode) {
452         rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE, pk12uForceUnicode);
453         if (rv != SECSuccess) {
454             SECU_PrintError(progName, "PKCS12 decoding failed to set option");
455             pk12uErrno = PK12UERR_DECODEVERIFY;
456         }
457     }
458 /* rv has been set at this point */
459 
460 done:
461     if (rv != SECSuccess) {
462         if (p12dcx != NULL) {
463             SEC_PKCS12DecoderFinish(p12dcx);
464             p12dcx = NULL;
465         }
466         if (uniPwp->data) {
467             SECITEM_ZfreeItem(uniPwp, PR_FALSE);
468             uniPwp->data = NULL;
469         }
470     }
471     PR_Close(p12cxt->file);
472     p12cxt->file = NULL;
473     /* PK11_FreeSlot(slot); */
474     p12u_DestroyContext(&p12cxt, PR_FALSE);
475 
476     if (pwitem) {
477         SECITEM_ZfreeItem(pwitem, PR_TRUE);
478     }
479     SECITEM_ZfreeItem(&p12file, PR_FALSE);
480     return p12dcx;
481 }
482 
483 /*
484  * given a filename for pkcs12 file, imports certs and keys
485  *
486  * Change: altitude
487  *  I've changed this function so that it takes the keydb and pkcs12 file
488  *  passwords from files.  The "pwdKeyDB" and "pwdP12File"
489  *  variables have been added for this purpose.
490  */
491 PRIntn
P12U_ImportPKCS12Object(char * in_file,PK11SlotInfo * slot,secuPWData * slotPw,secuPWData * p12FilePw)492 P12U_ImportPKCS12Object(char *in_file, PK11SlotInfo *slot,
493                         secuPWData *slotPw, secuPWData *p12FilePw)
494 {
495     SEC_PKCS12DecoderContext *p12dcx = NULL;
496     SECItem uniPwitem = { 0 };
497     PRBool forceUnicode = pk12uForceUnicode;
498     PRBool trypw;
499     SECStatus rv = SECFailure;
500 
501     rv = P12U_InitSlot(slot, slotPw);
502     if (rv != SECSuccess) {
503         SECU_PrintError(progName, "Failed to authenticate to \"%s\"",
504                         PK11_GetSlotName(slot));
505         pk12uErrno = PK12UERR_PK11GETSLOT;
506         return rv;
507     }
508 
509     do {
510         trypw = PR_FALSE; /* normally we do this once */
511         rv = SECFailure;
512         p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw, p12FilePw);
513 
514         if (p12dcx == NULL) {
515             goto loser;
516         }
517 
518         /* make sure the bags are okey dokey -- nicknames correct, etc. */
519         rv = SEC_PKCS12DecoderValidateBags(p12dcx, P12U_NicknameCollisionCallback);
520         if (rv != SECSuccess) {
521             if (PORT_GetError() == SEC_ERROR_PKCS12_DUPLICATE_DATA) {
522                 pk12uErrno = PK12UERR_CERTALREADYEXISTS;
523             } else {
524                 pk12uErrno = PK12UERR_DECODEVALIBAGS;
525             }
526             SECU_PrintError(progName, "PKCS12 decode validate bags failed");
527             goto loser;
528         }
529 
530         /* stuff 'em in */
531         if (forceUnicode != pk12uForceUnicode) {
532             rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE,
533                                forceUnicode);
534             if (rv != SECSuccess) {
535                 SECU_PrintError(progName, "PKCS12 decode set option failed");
536                 pk12uErrno = PK12UERR_DECODEIMPTBAGS;
537                 goto loser;
538             }
539         }
540         rv = SEC_PKCS12DecoderImportBags(p12dcx);
541         if (rv != SECSuccess) {
542             if (PR_GetError() == SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY &&
543                 forceUnicode == pk12uForceUnicode) {
544                 /* try again with a different password encoding */
545                 forceUnicode = !pk12uForceUnicode;
546                 SEC_PKCS12DecoderFinish(p12dcx);
547                 SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
548                 trypw = PR_TRUE;
549             } else {
550                 SECU_PrintError(progName, "PKCS12 decode import bags failed");
551                 pk12uErrno = PK12UERR_DECODEIMPTBAGS;
552                 goto loser;
553             }
554         }
555     } while (trypw);
556 
557     /* revert the option setting */
558     if (forceUnicode != pk12uForceUnicode) {
559         rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE, pk12uForceUnicode);
560         if (rv != SECSuccess) {
561             SECU_PrintError(progName, "PKCS12 decode set option failed");
562             pk12uErrno = PK12UERR_DECODEIMPTBAGS;
563             goto loser;
564         }
565     }
566 
567     fprintf(stdout, "%s: PKCS12 IMPORT SUCCESSFUL\n", progName);
568     rv = SECSuccess;
569 
570 loser:
571     if (p12dcx) {
572         SEC_PKCS12DecoderFinish(p12dcx);
573     }
574 
575     if (uniPwitem.data) {
576         SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
577     }
578 
579     return rv;
580 }
581 
582 static void
p12u_DoPKCS12ExportErrors()583 p12u_DoPKCS12ExportErrors()
584 {
585     PRErrorCode error_value;
586 
587     error_value = PORT_GetError();
588     if ((error_value == SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY) ||
589         (error_value == SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME) ||
590         (error_value == SEC_ERROR_PKCS12_UNABLE_TO_WRITE)) {
591         fputs(SECU_Strerror(error_value), stderr);
592     } else if (error_value == SEC_ERROR_USER_CANCELLED) {
593         ;
594     } else {
595         fputs(SECU_Strerror(SEC_ERROR_EXPORTING_CERTIFICATES), stderr);
596     }
597 }
598 
599 static void
p12u_WriteToExportFile(void * arg,const char * buf,unsigned long len)600 p12u_WriteToExportFile(void *arg, const char *buf, unsigned long len)
601 {
602     p12uContext *p12cxt = arg;
603     int writeLen;
604 
605     if (!p12cxt || (p12cxt->error == PR_TRUE)) {
606         return;
607     }
608 
609     if (p12cxt->file == NULL) {
610         p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
611         p12cxt->error = PR_TRUE;
612         return;
613     }
614 
615     writeLen = PR_Write(p12cxt->file, (unsigned char *)buf, (PRInt32)len);
616 
617     if (writeLen != (int)len) {
618         PR_Close(p12cxt->file);
619         PL_strfree(p12cxt->filename);
620         p12cxt->filename = NULL;
621         p12cxt->file = NULL;
622         p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
623         p12cxt->error = PR_TRUE;
624     }
625 }
626 
627 void
P12U_ExportPKCS12Object(char * nn,char * outfile,PK11SlotInfo * inSlot,SECOidTag cipher,SECOidTag certCipher,SECOidTag hash,secuPWData * slotPw,secuPWData * p12FilePw)628 P12U_ExportPKCS12Object(char *nn, char *outfile, PK11SlotInfo *inSlot,
629                         SECOidTag cipher, SECOidTag certCipher, SECOidTag hash,
630                         secuPWData *slotPw, secuPWData *p12FilePw)
631 {
632     SEC_PKCS12ExportContext *p12ecx = NULL;
633     SEC_PKCS12SafeInfo *keySafe = NULL, *certSafe = NULL;
634     SECItem *pwitem = NULL;
635     p12uContext *p12cxt = NULL;
636     CERTCertList *certlist = NULL;
637     CERTCertListNode *node = NULL;
638     PK11SlotInfo *slot = NULL;
639 
640     if (P12U_InitSlot(inSlot, slotPw) != SECSuccess) {
641         SECU_PrintError(progName, "Failed to authenticate to \"%s\"",
642                         PK11_GetSlotName(inSlot));
643         pk12uErrno = PK12UERR_PK11GETSLOT;
644         goto loser;
645     }
646     certlist = PK11_FindCertsFromNickname(nn, slotPw);
647     if (!certlist) {
648         PORT_SetError(SEC_ERROR_UNKNOWN_CERT);
649         SECU_PrintError(progName, "find user certs from nickname failed");
650         pk12uErrno = PK12UERR_FINDCERTBYNN;
651         return;
652     }
653 
654     if ((SECSuccess != CERT_FilterCertListForUserCerts(certlist)) ||
655         CERT_LIST_EMPTY(certlist)) {
656         PR_fprintf(PR_STDERR, "%s: no user certs from given nickname\n",
657                    progName);
658         pk12uErrno = PK12UERR_FINDCERTBYNN;
659         goto loser;
660     }
661 
662     /*	Password to use for PKCS12 file.  */
663     pwitem = P12U_GetP12FilePassword(PR_TRUE, p12FilePw);
664     if (!pwitem) {
665         goto loser;
666     }
667 
668     p12cxt = p12u_InitContext(PR_FALSE, outfile);
669     if (!p12cxt) {
670         SECU_PrintError(progName, "Initialization failed: %s", outfile);
671         pk12uErrno = PK12UERR_INIT_FILE;
672         goto loser;
673     }
674 
675     if (certlist) {
676         CERTCertificate *cert = CERT_LIST_HEAD(certlist)->cert;
677         if (cert) {
678             slot = cert->slot; /* use the slot from the first matching
679                 certificate to create the context . This is for keygen */
680         }
681     }
682     if (!slot) {
683         SECU_PrintError(progName, "cert does not have a slot");
684         pk12uErrno = PK12UERR_FINDCERTBYNN;
685         goto loser;
686     }
687     p12ecx = SEC_PKCS12CreateExportContext(NULL, NULL, slot, slotPw);
688     if (!p12ecx) {
689         SECU_PrintError(progName, "export context creation failed");
690         pk12uErrno = PK12UERR_EXPORTCXCREATE;
691         goto loser;
692     }
693 
694     if (SEC_PKCS12AddPasswordIntegrity(p12ecx, pwitem, hash) !=
695         SECSuccess) {
696         SECU_PrintError(progName, "PKCS12 add password integrity failed");
697         pk12uErrno = PK12UERR_PK12ADDPWDINTEG;
698         goto loser;
699     }
700 
701     for (node = CERT_LIST_HEAD(certlist);
702          !CERT_LIST_END(node, certlist);
703          node = CERT_LIST_NEXT(node)) {
704         CERTCertificate *cert = node->cert;
705         if (!cert->slot) {
706             SECU_PrintError(progName, "cert does not have a slot");
707             pk12uErrno = PK12UERR_FINDCERTBYNN;
708             goto loser;
709         }
710 
711         keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx);
712         if (certCipher == SEC_OID_UNKNOWN) {
713             certSafe = keySafe;
714         } else {
715             certSafe =
716                 SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem, certCipher);
717         }
718 
719         if (!certSafe || !keySafe) {
720             SECU_PrintError(progName, "key or cert safe creation failed");
721             pk12uErrno = PK12UERR_CERTKEYSAFE;
722             goto loser;
723         }
724 
725         if (SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert,
726                                     CERT_GetDefaultCertDB(), keySafe, NULL,
727                                     PR_TRUE, pwitem, cipher) != SECSuccess) {
728             SECU_PrintError(progName, "add cert and key failed");
729             pk12uErrno = PK12UERR_ADDCERTKEY;
730             goto loser;
731         }
732     }
733 
734     CERT_DestroyCertList(certlist);
735     certlist = NULL;
736 
737     if (SEC_PKCS12Encode(p12ecx, p12u_WriteToExportFile, p12cxt) !=
738         SECSuccess) {
739         SECU_PrintError(progName, "PKCS12 encode failed");
740         pk12uErrno = PK12UERR_ENCODE;
741         goto loser;
742     }
743 
744     p12u_DestroyContext(&p12cxt, PR_FALSE);
745     SECITEM_ZfreeItem(pwitem, PR_TRUE);
746     fprintf(stdout, "%s: PKCS12 EXPORT SUCCESSFUL\n", progName);
747     SEC_PKCS12DestroyExportContext(p12ecx);
748 
749     return;
750 
751 loser:
752     SEC_PKCS12DestroyExportContext(p12ecx);
753 
754     if (certlist) {
755         CERT_DestroyCertList(certlist);
756         certlist = NULL;
757     }
758 
759     p12u_DestroyContext(&p12cxt, PR_TRUE);
760     if (pwitem) {
761         SECITEM_ZfreeItem(pwitem, PR_TRUE);
762     }
763     p12u_DoPKCS12ExportErrors();
764     return;
765 }
766 
767 PRIntn
P12U_ListPKCS12File(char * in_file,PK11SlotInfo * slot,secuPWData * slotPw,secuPWData * p12FilePw)768 P12U_ListPKCS12File(char *in_file, PK11SlotInfo *slot,
769                     secuPWData *slotPw, secuPWData *p12FilePw)
770 {
771     SEC_PKCS12DecoderContext *p12dcx = NULL;
772     SECItem uniPwitem = { 0 };
773     SECStatus rv = SECFailure;
774     const SEC_PKCS12DecoderItem *dip;
775 
776     p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw, p12FilePw);
777     /* did the blob authenticate properly? */
778     if (p12dcx == NULL) {
779         SECU_PrintError(progName, "PKCS12 decode not verified");
780         pk12uErrno = PK12UERR_DECODEVERIFY;
781         goto loser;
782     }
783     rv = SEC_PKCS12DecoderIterateInit(p12dcx);
784     if (rv != SECSuccess) {
785         SECU_PrintError(progName, "PKCS12 decode iterate bags failed");
786         pk12uErrno = PK12UERR_DECODEIMPTBAGS;
787         rv = SECFailure;
788     } else {
789         int fileCounter = 0;
790         while (SEC_PKCS12DecoderIterateNext(p12dcx, &dip) == SECSuccess) {
791             switch (dip->type) {
792                 case SEC_OID_PKCS12_V1_CERT_BAG_ID:
793                     printf("Certificate");
794                     if (dumpRawFile) {
795                         PRFileDesc *fd;
796                         char fileName[20];
797                         sprintf(fileName, "file%04d.der", ++fileCounter);
798                         fd = PR_Open(fileName,
799                                      PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE,
800                                      0600);
801                         if (!fd) {
802                             SECU_PrintError(progName,
803                                             "Cannot create output file");
804                         } else {
805                             PR_Write(fd, dip->der->data, dip->der->len);
806                             PR_Close(fd);
807                         }
808                     } else if (SECU_PrintSignedData(stdout, dip->der,
809                                                     (dip->hasKey) ? "(has private key)"
810                                                                   : "",
811                                                     0, (SECU_PPFunc)SECU_PrintCertificate) !=
812                                0) {
813                         SECU_PrintError(progName, "PKCS12 print cert bag failed");
814                     }
815                     if (dip->friendlyName != NULL) {
816                         printf("    Friendly Name: %s\n\n",
817                                dip->friendlyName->data);
818                     }
819                     if (dip->shroudAlg) {
820                         SECU_PrintAlgorithmID(stdout, dip->shroudAlg,
821                                               "Encryption algorithm", 1);
822                     }
823                     break;
824                 case SEC_OID_PKCS12_V1_KEY_BAG_ID:
825                 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
826                     printf("Key");
827                     if (dip->type == SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID)
828                         printf("(shrouded)");
829                     printf(":\n");
830                     if (dip->friendlyName != NULL) {
831                         printf("    Friendly Name: %s\n\n",
832                                dip->friendlyName->data);
833                     }
834                     if (dip->shroudAlg) {
835                         SECU_PrintAlgorithmID(stdout, dip->shroudAlg,
836                                               "Encryption algorithm", 1);
837                     }
838                     break;
839                 default:
840                     printf("unknown bag type(%d): %s\n\n", dip->type,
841                            SECOID_FindOIDTagDescription(dip->type));
842                     break;
843             }
844         }
845         rv = SECSuccess;
846     }
847 
848 loser:
849 
850     if (p12dcx) {
851         SEC_PKCS12DecoderFinish(p12dcx);
852     }
853 
854     if (uniPwitem.data) {
855         SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
856     }
857 
858     return rv;
859 }
860 
861 SECOidTag
PKCS12U_FindTagFromString(char * cipherString)862 PKCS12U_FindTagFromString(char *cipherString)
863 {
864     SECOidTag tag;
865     SECOidData *oid;
866 
867     /* future enhancement: accept dotted oid spec? */
868 
869     for (tag = 1; (oid = SECOID_FindOIDByTag(tag)) != NULL; tag++) {
870         /* only interested in oids that we actually understand */
871         if (oid->mechanism == CKM_INVALID_MECHANISM) {
872             continue;
873         }
874         if (PORT_Strcasecmp(oid->desc, cipherString) != 0) {
875             continue;
876         }
877         return tag;
878     }
879     return SEC_OID_UNKNOWN;
880 }
881 
882 /*
883  * use the oid table description to map a user input string to a particular
884  * oid.
885  */
886 SECOidTag
PKCS12U_MapCipherFromString(char * cipherString,int keyLen)887 PKCS12U_MapCipherFromString(char *cipherString, int keyLen)
888 {
889     SECOidTag tag;
890     SECOidTag cipher;
891 
892     /* future enhancement: provide 'friendlier' typed in names for
893      * pbe mechanisms.
894      */
895 
896     /* look for the oid tag by Description */
897     tag = PKCS12U_FindTagFromString(cipherString);
898     if (tag == SEC_OID_UNKNOWN) {
899         return tag;
900     }
901 
902     cipher = SEC_OID_UNKNOWN;
903     /* we found a match... get the PBE version of this
904      * cipher... */
905     if (!SEC_PKCS5IsAlgorithmPBEAlgTag(tag)) {
906         cipher = SEC_PKCS5GetPBEAlgorithm(tag, keyLen);
907         /* no eqivalent PKCS5/PKCS12 cipher, use the raw
908          * encryption tag we got and pass it directly in,
909          * pkcs12 will use the pkcsv5 mechanism */
910         if (cipher == SEC_OID_PKCS5_PBES2) {
911             cipher = tag;
912         } else if (cipher == SEC_OID_PKCS5_PBMAC1) {
913             /* make sure we have not macing ciphers here */
914             cipher = SEC_OID_UNKNOWN;
915         }
916     } else {
917         cipher = tag;
918     }
919     return cipher;
920 }
921 
922 SECOidTag
PKCS12U_MapHashFromString(char * hashString)923 PKCS12U_MapHashFromString(char *hashString)
924 {
925     SECOidTag hashAlg;
926 
927     /* look for the oid tag by Description */
928     hashAlg = PKCS12U_FindTagFromString(hashString);
929     if (hashAlg == SEC_OID_UNKNOWN) {
930         return hashAlg;
931     }
932     /* make sure it's a hashing oid */
933     if (HASH_GetHashTypeByOidTag(hashAlg) == HASH_AlgNULL) {
934         return SEC_OID_UNKNOWN;
935     }
936     return hashAlg;
937 }
938 
939 static void
p12u_EnableAllCiphers()940 p12u_EnableAllCiphers()
941 {
942     SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1);
943     SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1);
944     SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
945     SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1);
946     SEC_PKCS12EnableCipher(PKCS12_DES_56, 1);
947     SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
948     SEC_PKCS12EnableCipher(PKCS12_AES_CBC_128, 1);
949     SEC_PKCS12EnableCipher(PKCS12_AES_CBC_192, 1);
950     SEC_PKCS12EnableCipher(PKCS12_AES_CBC_256, 1);
951     SEC_PKCS12SetPreferredCipher(PKCS12_AES_CBC_256, 1);
952 }
953 
954 static PRUintn
P12U_Init(char * dir,char * dbprefix,PRBool listonly)955 P12U_Init(char *dir, char *dbprefix, PRBool listonly)
956 {
957     SECStatus rv;
958     PK11_SetPasswordFunc(SECU_GetModulePassword);
959 
960     PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
961     if (listonly && NSS_NoDB_Init("") == SECSuccess) {
962         rv = SECSuccess;
963     } else {
964         rv = NSS_Initialize(dir, dbprefix, dbprefix, "secmod.db", 0);
965     }
966     if (rv != SECSuccess) {
967         SECU_PrintPRandOSError(progName);
968         exit(-1);
969     }
970 
971     /* setup unicode callback functions */
972     PORT_SetUCS2_ASCIIConversionFunction(p12u_ucs2_ascii_conversion_function);
973     /* use the defaults for UCS4-UTF8 and UCS2-UTF8 */
974 
975     p12u_EnableAllCiphers();
976 
977     return 0;
978 }
979 
980 enum {
981     opt_CertDir = 0,
982     opt_TokenName,
983     opt_Import,
984     opt_SlotPWFile,
985     opt_SlotPW,
986     opt_List,
987     opt_Nickname,
988     opt_Export,
989     opt_Raw,
990     opt_P12FilePWFile,
991     opt_P12FilePW,
992     opt_DBPrefix,
993     opt_Debug,
994     opt_Cipher,
995     opt_CertCipher,
996     opt_KeyLength,
997     opt_CertKeyLength,
998     opt_Mac
999 };
1000 
1001 static secuCommandFlag pk12util_options[] =
1002     {
1003       { /* opt_CertDir	       */ 'd', PR_TRUE, 0, PR_FALSE },
1004       { /* opt_TokenName	       */ 'h', PR_TRUE, 0, PR_FALSE },
1005       { /* opt_Import	       */ 'i', PR_TRUE, 0, PR_FALSE },
1006       { /* opt_SlotPWFile	       */ 'k', PR_TRUE, 0, PR_FALSE },
1007       { /* opt_SlotPW	       */ 'K', PR_TRUE, 0, PR_FALSE },
1008       { /* opt_List              */ 'l', PR_TRUE, 0, PR_FALSE },
1009       { /* opt_Nickname	       */ 'n', PR_TRUE, 0, PR_FALSE },
1010       { /* opt_Export	       */ 'o', PR_TRUE, 0, PR_FALSE },
1011       { /* opt_Raw   	       */ 'r', PR_FALSE, 0, PR_FALSE },
1012       { /* opt_P12FilePWFile     */ 'w', PR_TRUE, 0, PR_FALSE },
1013       { /* opt_P12FilePW	       */ 'W', PR_TRUE, 0, PR_FALSE },
1014       { /* opt_DBPrefix	       */ 'P', PR_TRUE, 0, PR_FALSE },
1015       { /* opt_Debug	       */ 'v', PR_FALSE, 0, PR_FALSE },
1016       { /* opt_Cipher	       */ 'c', PR_TRUE, 0, PR_FALSE },
1017       { /* opt_CertCipher	       */ 'C', PR_TRUE, 0, PR_FALSE },
1018       { /* opt_KeyLength         */ 'm', PR_TRUE, 0, PR_FALSE, "key_len" },
1019       { /* opt_CertKeyLength     */ 0, PR_TRUE, 0, PR_FALSE, "cert_key_len" },
1020       { /* opt_Mac               */ 'M', PR_TRUE, 0, PR_FALSE, PR_FALSE }
1021     };
1022 
1023 int
main(int argc,char ** argv)1024 main(int argc, char **argv)
1025 {
1026     secuPWData slotPw = { PW_NONE, NULL };
1027     secuPWData p12FilePw = { PW_NONE, NULL };
1028     PK11SlotInfo *slot;
1029     char *slotname = NULL;
1030     char *import_file = NULL;
1031     char *export_file = NULL;
1032     char *dbprefix = "";
1033     SECStatus rv;
1034     SECOidTag cipher = SEC_OID_AES_256_CBC;
1035     SECOidTag hash = SEC_OID_SHA256;
1036     SECOidTag certCipher = SEC_OID_AES_128_CBC;
1037     int keyLen = 0;
1038     int certKeyLen = 0;
1039     secuCommand pk12util;
1040     PRInt32 forceUnicode;
1041 
1042 #ifdef _CRTDBG_MAP_ALLOC
1043     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
1044 #endif
1045 
1046     pk12util.numCommands = 0;
1047     pk12util.commands = 0;
1048     pk12util.numOptions = sizeof(pk12util_options) / sizeof(secuCommandFlag);
1049     pk12util.options = pk12util_options;
1050 
1051     progName = strrchr(argv[0], '/');
1052     progName = progName ? progName + 1 : argv[0];
1053 
1054     rv = SECU_ParseCommandLine(argc, argv, progName, &pk12util);
1055 
1056     if (rv != SECSuccess)
1057         Usage();
1058 
1059     pk12_debugging = pk12util.options[opt_Debug].activated;
1060 
1061     if ((pk12util.options[opt_Import].activated +
1062          pk12util.options[opt_Export].activated +
1063          pk12util.options[opt_List].activated) != 1) {
1064         Usage();
1065     }
1066 
1067     if (pk12util.options[opt_Export].activated &&
1068         !pk12util.options[opt_Nickname].activated) {
1069         Usage();
1070     }
1071 
1072     rv = NSS_OptionGet(__NSS_PKCS12_DECODE_FORCE_UNICODE, &forceUnicode);
1073     if (rv != SECSuccess) {
1074         SECU_PrintError(progName,
1075                         "Failed to get NSS_PKCS12_DECODE_FORCE_UNICODE option");
1076         Usage();
1077     }
1078     pk12uForceUnicode = forceUnicode;
1079 
1080     slotname = SECU_GetOptionArg(&pk12util, opt_TokenName);
1081 
1082     import_file = (pk12util.options[opt_List].activated) ? SECU_GetOptionArg(&pk12util, opt_List)
1083                                                          : SECU_GetOptionArg(&pk12util, opt_Import);
1084     export_file = SECU_GetOptionArg(&pk12util, opt_Export);
1085 
1086     if (pk12util.options[opt_P12FilePWFile].activated) {
1087         p12FilePw.source = PW_FROMFILE;
1088         p12FilePw.data = PORT_Strdup(pk12util.options[opt_P12FilePWFile].arg);
1089     }
1090 
1091     if (pk12util.options[opt_P12FilePW].activated) {
1092         p12FilePw.source = PW_PLAINTEXT;
1093         p12FilePw.data = PORT_Strdup(pk12util.options[opt_P12FilePW].arg);
1094     }
1095 
1096     if (pk12util.options[opt_SlotPWFile].activated) {
1097         slotPw.source = PW_FROMFILE;
1098         slotPw.data = PORT_Strdup(pk12util.options[opt_SlotPWFile].arg);
1099     }
1100 
1101     if (pk12util.options[opt_SlotPW].activated) {
1102         slotPw.source = PW_PLAINTEXT;
1103         slotPw.data = PORT_Strdup(pk12util.options[opt_SlotPW].arg);
1104     }
1105 
1106     if (pk12util.options[opt_CertDir].activated) {
1107         SECU_ConfigDirectory(pk12util.options[opt_CertDir].arg);
1108     }
1109     if (pk12util.options[opt_DBPrefix].activated) {
1110         dbprefix = pk12util.options[opt_DBPrefix].arg;
1111     }
1112     if (pk12util.options[opt_Raw].activated) {
1113         dumpRawFile = PR_TRUE;
1114     }
1115     if (pk12util.options[opt_KeyLength].activated) {
1116         keyLen = atoi(pk12util.options[opt_KeyLength].arg);
1117     }
1118     if (pk12util.options[opt_CertKeyLength].activated) {
1119         certKeyLen = atoi(pk12util.options[opt_CertKeyLength].arg);
1120     }
1121 
1122     P12U_Init(SECU_ConfigDirectory(NULL), dbprefix,
1123               pk12util.options[opt_List].activated);
1124 
1125     if (!slotname || PL_strcmp(slotname, "internal") == 0)
1126         slot = PK11_GetInternalKeySlot();
1127     else
1128         slot = PK11_FindSlotByName(slotname);
1129 
1130     if (!slot) {
1131         SECU_PrintError(progName, "Invalid slot \"%s\"", slotname);
1132         pk12uErrno = PK12UERR_PK11GETSLOT;
1133         goto done;
1134     }
1135 
1136     if (pk12util.options[opt_Cipher].activated) {
1137         char *cipherString = pk12util.options[opt_Cipher].arg;
1138 
1139         cipher = PKCS12U_MapCipherFromString(cipherString, keyLen);
1140         /* We only want encryption PBE's. make sure we don't have
1141 	 * any MAC pbes */
1142         if (cipher == SEC_OID_UNKNOWN) {
1143             PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
1144             SECU_PrintError(progName, "Algorithm: \"%s\"", cipherString);
1145             pk12uErrno = PK12UERR_INVALIDALGORITHM;
1146             goto done;
1147         }
1148     }
1149 
1150     if (pk12util.options[opt_CertCipher].activated) {
1151         char *cipherString = pk12util.options[opt_CertCipher].arg;
1152 
1153         if (PORT_Strcasecmp(cipherString, "none") == 0) {
1154             certCipher = SEC_OID_UNKNOWN;
1155         } else {
1156             certCipher = PKCS12U_MapCipherFromString(cipherString, certKeyLen);
1157             /* If the user requested a cipher and we didn't find it, then
1158 	     * don't just silently not encrypt. */
1159             if (certCipher == SEC_OID_UNKNOWN) {
1160                 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
1161                 SECU_PrintError(progName, "Algorithm: \"%s\"", cipherString);
1162                 pk12uErrno = PK12UERR_INVALIDALGORITHM;
1163                 goto done;
1164             }
1165         }
1166     }
1167     if (pk12util.options[opt_Mac].activated) {
1168         char *hashString = pk12util.options[opt_Mac].arg;
1169 
1170         hash = PKCS12U_MapHashFromString(hashString);
1171         /* We don't support creating Mac-less pkcs 12 files */
1172         if (hash == SEC_OID_UNKNOWN) {
1173             PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
1174             SECU_PrintError(progName, "Algorithm: \"%s\"", hashString);
1175             pk12uErrno = PK12UERR_INVALIDALGORITHM;
1176             goto done;
1177         }
1178     }
1179 
1180     if (pk12util.options[opt_Import].activated) {
1181         P12U_ImportPKCS12Object(import_file, slot, &slotPw, &p12FilePw);
1182 
1183     } else if (pk12util.options[opt_Export].activated) {
1184         P12U_ExportPKCS12Object(pk12util.options[opt_Nickname].arg,
1185                                 export_file, slot, cipher, certCipher,
1186                                 hash, &slotPw, &p12FilePw);
1187 
1188     } else if (pk12util.options[opt_List].activated) {
1189         P12U_ListPKCS12File(import_file, slot, &slotPw, &p12FilePw);
1190 
1191     } else {
1192         Usage();
1193         pk12uErrno = PK12UERR_USAGE;
1194     }
1195 
1196 done:
1197     if (import_file != NULL)
1198         PORT_ZFree(import_file, PL_strlen(import_file));
1199     if (export_file != NULL)
1200         PORT_ZFree(export_file, PL_strlen(export_file));
1201     if (slotPw.data != NULL)
1202         PORT_ZFree(slotPw.data, PL_strlen(slotPw.data));
1203     if (p12FilePw.data != NULL)
1204         PORT_ZFree(p12FilePw.data, PL_strlen(p12FilePw.data));
1205     if (slot)
1206         PK11_FreeSlot(slot);
1207     if (NSS_Shutdown() != SECSuccess) {
1208         pk12uErrno = 1;
1209     }
1210     PL_ArenaFinish();
1211     PR_Cleanup();
1212     return pk12uErrno;
1213 }
1214