security/nss/cmd/pk12util/pk12util.c

branch
TOR_BUG_9701
changeset 3
141e0f1194b1
equal deleted inserted replaced
-1:000000000000 0:e5998df5d106
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 }

mercurial