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