1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
48 #define PKCS12_IN_BUFFER_SIZE 200
50 static char *progName
;
51 PRBool pk12_debugging
= PR_FALSE
;
54 PRIntn pk12uErrno
= 0;
59 #define FPS PR_fprintf(PR_STDERR,
60 FPS
"Usage: %s -i importfile [-d certdir] [-P dbprefix] [-h tokenname] [-v]\n",
62 FPS
"\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
64 FPS
"Usage: %s -l listfile [-d certdir] [-P dbprefix] [-h tokenname] [-r]\n",
66 FPS
"\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
68 FPS
"Usage: %s -o exportfile -n certname [-d certdir] [-P dbprefix] [-v]\n",
70 FPS
"\t\t [-c key_cipher] [-C cert_cipher] [-k key_leng]\n");
71 FPS
"\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
77 p12u_OpenFile(p12uContext
*p12cxt
, PRBool fileRead
)
79 if(!p12cxt
|| !p12cxt
->filename
) {
84 p12cxt
->file
= PR_Open(p12cxt
->filename
,
87 p12cxt
->file
= PR_Open(p12cxt
->filename
,
88 PR_CREATE_FILE
| PR_RDWR
| PR_TRUNCATE
,
93 p12cxt
->error
= PR_TRUE
;
101 p12u_DestroyContext(p12uContext
**ppCtx
, PRBool removeFile
)
103 if(!ppCtx
|| !(*ppCtx
)) {
107 if((*ppCtx
)->file
!= NULL
) {
108 PR_Close((*ppCtx
)->file
);
111 if((*ppCtx
)->filename
!= NULL
) {
113 PR_Delete((*ppCtx
)->filename
);
115 PR_Free((*ppCtx
)->filename
);
123 p12u_InitContext(PRBool fileImport
, char *filename
)
128 fileExist
= fileImport
;
130 p12cxt
= PORT_ZNew(p12uContext
);
135 p12cxt
->error
= PR_FALSE
;
136 p12cxt
->errorValue
= 0;
137 p12cxt
->filename
= strdup(filename
);
139 if(!p12u_OpenFile(p12cxt
, fileImport
)) {
140 p12u_DestroyContext(&p12cxt
, PR_FALSE
);
148 P12U_NicknameCollisionCallback(SECItem
*old_nick
, PRBool
*cancel
, void *wincx
)
151 SECItem
*ret_nick
= NULL
;
152 CERTCertificate
* cert
= (CERTCertificate
*)wincx
;
154 if (!cancel
|| !cert
) {
155 pk12uErrno
= PK12UERR_USER_CANCELLED
;
160 fprintf(stdout
, "pk12util: no nickname for cert in PKCS12 file.\n");
163 /* XXX not handled yet */
169 nick
= CERT_MakeCANickname(cert
);
174 if(old_nick
&& old_nick
->data
&& old_nick
->len
&&
175 PORT_Strlen(nick
) == old_nick
->len
&&
176 !PORT_Strncmp((char *)old_nick
->data
, nick
, old_nick
->len
)) {
178 PORT_SetError(SEC_ERROR_IO
);
182 fprintf(stdout
, "pk12util: using nickname: %s\n", nick
);
183 ret_nick
= PORT_ZNew(SECItem
);
184 if(ret_nick
== NULL
) {
189 ret_nick
->data
= (unsigned char *)nick
;
190 ret_nick
->len
= PORT_Strlen(nick
);
197 p12u_SwapUnicodeBytes(SECItem
*uniItem
)
201 if((uniItem
== NULL
) || (uniItem
->len
% 2)) {
204 for(i
= 0; i
< uniItem
->len
; i
+= 2) {
205 a
= uniItem
->data
[i
];
206 uniItem
->data
[i
] = uniItem
->data
[i
+1];
207 uniItem
->data
[i
+1] = a
;
213 p12u_ucs2_ascii_conversion_function(PRBool toUnicode
,
214 unsigned char *inBuf
,
215 unsigned int inBufLen
,
216 unsigned char *outBuf
,
217 unsigned int maxOutBufLen
,
218 unsigned int *outBufLen
,
225 #ifdef DEBUG_CONVERSION
226 if (pk12_debugging
) {
228 printf("Converted from:\n");
229 for (i
=0; i
<inBufLen
; i
++) {
230 printf("%2x ", inBuf
[i
]);
231 /*if (i%60 == 0) printf("\n");*/
238 dup
= SECITEM_DupItem(&it
);
239 /* If converting Unicode to ASCII, swap bytes before conversion
242 if (!toUnicode
&& swapBytes
) {
243 if (p12u_SwapUnicodeBytes(dup
) != SECSuccess
) {
244 SECITEM_ZfreeItem(dup
, PR_TRUE
);
248 /* Perform the conversion. */
249 ret
= PORT_UCS2_UTF8Conversion(toUnicode
, dup
->data
, dup
->len
,
250 outBuf
, maxOutBufLen
, outBufLen
);
252 SECITEM_ZfreeItem(dup
, PR_TRUE
);
254 #ifdef DEBUG_CONVERSION
255 if (pk12_debugging
) {
257 printf("Converted to:\n");
258 for (i
=0; i
<*outBufLen
; i
++) {
259 printf("%2x ", outBuf
[i
]);
260 /*if (i%60 == 0) printf("\n");*/
269 P12U_UnicodeConversion(PRArenaPool
*arena
, SECItem
*dest
, SECItem
*src
,
270 PRBool toUnicode
, PRBool swapBytes
)
272 unsigned int allocLen
;
276 allocLen
= ((toUnicode
) ? (src
->len
<< 2) : src
->len
);
278 dest
->data
= PORT_ArenaZAlloc(arena
, allocLen
);
280 dest
->data
= PORT_ZAlloc(allocLen
);
282 if(PORT_UCS2_ASCIIConversion(toUnicode
, src
->data
, src
->len
,
283 dest
->data
, allocLen
, &dest
->len
,
284 swapBytes
) == PR_FALSE
) {
286 PORT_Free(dest
->data
);
298 P12U_GetP12FilePassword(PRBool confirmPw
, secuPWData
*p12FilePw
)
301 SECItem
*pwItem
= NULL
;
303 if (p12FilePw
== NULL
|| p12FilePw
->source
== PW_NONE
) {
307 p0
= SECU_GetPasswordString(NULL
,
308 "Enter password for PKCS12 file: ");
309 if (!confirmPw
|| p0
== NULL
)
311 p1
= SECU_GetPasswordString(NULL
, "Re-enter password: ");
313 PORT_ZFree(p0
, PL_strlen(p0
));
317 rc
= PL_strcmp(p0
, p1
);
318 PORT_ZFree(p1
, PL_strlen(p1
));
321 PORT_ZFree(p0
, PL_strlen(p0
));
323 } else if (p12FilePw
->source
== PW_FROMFILE
) {
324 p0
= SECU_FilePasswd(NULL
, PR_FALSE
, p12FilePw
->data
);
325 } else { /* Plaintext */
326 p0
= PORT_Strdup(p12FilePw
->data
);
332 pwItem
= SECITEM_AllocItem(NULL
, NULL
, PL_strlen(p0
) + 1);
333 memcpy(pwItem
->data
, p0
, pwItem
->len
);
335 PORT_ZFree(p0
, PL_strlen(p0
));
341 P12U_InitSlot(PK11SlotInfo
*slot
, secuPWData
*slotPw
)
345 /* New databases, initialize keydb password. */
346 if (PK11_NeedUserInit(slot
)) {
347 rv
= SECU_ChangePW(slot
,
348 (slotPw
->source
== PW_PLAINTEXT
) ? slotPw
->data
: 0,
349 (slotPw
->source
== PW_FROMFILE
) ? slotPw
->data
: 0);
350 if (rv
!= SECSuccess
) {
351 SECU_PrintError(progName
, "Failed to initialize slot \"%s\"",
352 PK11_GetSlotName(slot
));
357 if (PK11_Authenticate(slot
, PR_TRUE
, slotPw
) != SECSuccess
) {
358 SECU_PrintError(progName
,
359 "Failed to authenticate to PKCS11 slot");
360 PORT_SetError(SEC_ERROR_USER_CANCELLED
);
361 pk12uErrno
= PK12UERR_USER_CANCELLED
;
368 /* This routine takes care of getting the PKCS12 file password, then reading and
369 * verifying the file. It returns the decoder context and a filled in password.
370 * (The password is needed by P12U_ImportPKCS12Object() to import the private
373 SEC_PKCS12DecoderContext
*
374 p12U_ReadPKCS12File(SECItem
*uniPwp
, char *in_file
, PK11SlotInfo
*slot
,
375 secuPWData
*slotPw
, secuPWData
*p12FilePw
)
377 SEC_PKCS12DecoderContext
*p12dcx
= NULL
;
378 p12uContext
*p12cxt
= NULL
;
379 SECItem
*pwitem
= NULL
;
380 SECItem p12file
= { 0 };
381 SECStatus rv
= SECFailure
;
382 PRBool swapUnicode
= PR_FALSE
;
386 #ifdef IS_LITTLE_ENDIAN
387 swapUnicode
= PR_TRUE
;
390 p12cxt
= p12u_InitContext(PR_TRUE
, in_file
);
392 SECU_PrintError(progName
,"File Open failed: %s", in_file
);
393 pk12uErrno
= PK12UERR_INIT_FILE
;
397 /* get the password */
398 pwitem
= P12U_GetP12FilePassword(PR_FALSE
, p12FilePw
);
400 pk12uErrno
= PK12UERR_USER_CANCELLED
;
404 if(P12U_UnicodeConversion(NULL
, uniPwp
, pwitem
, PR_TRUE
,
405 swapUnicode
) != SECSuccess
) {
406 SECU_PrintError(progName
,"Unicode conversion failed");
407 pk12uErrno
= PK12UERR_UNICODECONV
;
410 rv
= SECU_FileToItem(&p12file
, p12cxt
->file
);
411 if (rv
!= SECSuccess
) {
412 SECU_PrintError(progName
,"Failed to read from import file");
417 trypw
= PR_FALSE
; /* normally we do this once */
419 /* init the decoder context */
420 p12dcx
= SEC_PKCS12DecoderStart(uniPwp
, slot
, slotPw
,
421 NULL
, NULL
, NULL
, NULL
, NULL
);
423 SECU_PrintError(progName
,"PKCS12 decoder start failed");
424 pk12uErrno
= PK12UERR_PK12DECODESTART
;
428 /* decode the item */
429 rv
= SEC_PKCS12DecoderUpdate(p12dcx
, p12file
.data
, p12file
.len
);
431 if(rv
!= SECSuccess
) {
432 error
= PR_GetError();
433 if(error
== SEC_ERROR_DECRYPTION_DISALLOWED
) {
434 PR_SetError(error
, 0);
437 SECU_PrintError(progName
,"PKCS12 decoding failed");
438 pk12uErrno
= PK12UERR_DECODE
;
441 /* does the blob authenticate properly? */
442 rv
= SEC_PKCS12DecoderVerify(p12dcx
);
443 if (rv
!= SECSuccess
) {
444 if(uniPwp
->len
== 2) {
445 /* this is a null PW, try once more with a zero-length PW
446 instead of a null string */
447 SEC_PKCS12DecoderFinish(p12dcx
);
452 SECU_PrintError(progName
,"PKCS12 decode not verified");
453 pk12uErrno
= PK12UERR_DECODEVERIFY
;
457 } while (trypw
== PR_TRUE
);
458 /* rv has been set at this point */
462 if (rv
!= SECSuccess
) {
463 if (p12dcx
!= NULL
) {
464 SEC_PKCS12DecoderFinish(p12dcx
);
468 SECITEM_ZfreeItem(uniPwp
, PR_FALSE
);
472 PR_Close(p12cxt
->file
);
474 /* PK11_FreeSlot(slot); */
475 p12u_DestroyContext(&p12cxt
, PR_FALSE
);
478 SECITEM_ZfreeItem(pwitem
, PR_TRUE
);
484 * given a filename for pkcs12 file, imports certs and keys
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.
492 P12U_ImportPKCS12Object(char *in_file
, PK11SlotInfo
*slot
,
493 secuPWData
*slotPw
, secuPWData
*p12FilePw
)
495 SEC_PKCS12DecoderContext
*p12dcx
= NULL
;
496 SECItem uniPwitem
= { 0 };
497 SECStatus rv
= SECFailure
;
499 rv
= P12U_InitSlot(slot
, slotPw
);
500 if (rv
!= SECSuccess
) {
501 SECU_PrintError(progName
, "Failed to authenticate to \"%s\"",
502 PK11_GetSlotName(slot
));
503 pk12uErrno
= PK12UERR_PK11GETSLOT
;
508 p12dcx
= p12U_ReadPKCS12File(&uniPwitem
, in_file
, slot
, slotPw
, p12FilePw
);
514 /* make sure the bags are okey dokey -- nicknames correct, etc. */
515 rv
= SEC_PKCS12DecoderValidateBags(p12dcx
, P12U_NicknameCollisionCallback
);
516 if (rv
!= SECSuccess
) {
517 if (PORT_GetError() == SEC_ERROR_PKCS12_DUPLICATE_DATA
) {
518 pk12uErrno
= PK12UERR_CERTALREADYEXISTS
;
520 pk12uErrno
= PK12UERR_DECODEVALIBAGS
;
522 SECU_PrintError(progName
,"PKCS12 decode validate bags failed");
527 rv
= SEC_PKCS12DecoderImportBags(p12dcx
);
528 if (rv
!= SECSuccess
) {
529 SECU_PrintError(progName
,"PKCS12 decode import bags failed");
530 pk12uErrno
= PK12UERR_DECODEIMPTBAGS
;
534 fprintf(stdout
, "%s: PKCS12 IMPORT SUCCESSFUL\n", progName
);
539 SEC_PKCS12DecoderFinish(p12dcx
);
542 if (uniPwitem
.data
) {
543 SECITEM_ZfreeItem(&uniPwitem
, PR_FALSE
);
550 p12u_DoPKCS12ExportErrors()
554 error_value
= PORT_GetError();
555 if ((error_value
== SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY
) ||
556 (error_value
== SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME
) ||
557 (error_value
== SEC_ERROR_PKCS12_UNABLE_TO_WRITE
)) {
558 fprintf(stderr
, SECU_ErrorStringRaw((int16
)error_value
));
559 } else if(error_value
== SEC_ERROR_USER_CANCELLED
) {
562 fprintf(stderr
, SECU_ErrorStringRaw(SEC_ERROR_EXPORTING_CERTIFICATES
));
567 p12u_WriteToExportFile(void *arg
, const char *buf
, unsigned long len
)
569 p12uContext
*p12cxt
= arg
;
572 if(!p12cxt
|| (p12cxt
->error
== PR_TRUE
)) {
576 if(p12cxt
->file
== NULL
) {
577 p12cxt
->errorValue
= SEC_ERROR_PKCS12_UNABLE_TO_WRITE
;
578 p12cxt
->error
= PR_TRUE
;
582 writeLen
= PR_Write(p12cxt
->file
, (unsigned char *)buf
, (int32
)len
);
584 if(writeLen
!= (int)len
) {
585 PR_Close(p12cxt
->file
);
586 PR_Free(p12cxt
->filename
);
587 p12cxt
->filename
= NULL
;
589 p12cxt
->errorValue
= SEC_ERROR_PKCS12_UNABLE_TO_WRITE
;
590 p12cxt
->error
= PR_TRUE
;
596 P12U_ExportPKCS12Object(char *nn
, char *outfile
, PK11SlotInfo
*inSlot
,
597 SECOidTag cipher
, SECOidTag certCipher
,
598 secuPWData
*slotPw
, secuPWData
*p12FilePw
)
600 SEC_PKCS12ExportContext
*p12ecx
= NULL
;
601 SEC_PKCS12SafeInfo
*keySafe
= NULL
, *certSafe
= NULL
;
602 SECItem
*pwitem
= NULL
;
603 p12uContext
*p12cxt
= NULL
;
604 CERTCertList
* certlist
= NULL
;
605 CERTCertListNode
* node
= NULL
;
606 PK11SlotInfo
* slot
= NULL
;
608 if (P12U_InitSlot(inSlot
, slotPw
) != SECSuccess
) {
609 SECU_PrintError(progName
,"Failed to authenticate to \"%s\"",
610 PK11_GetSlotName(inSlot
));
611 pk12uErrno
= PK12UERR_PK11GETSLOT
;
614 certlist
= PK11_FindCertsFromNickname(nn
, slotPw
);
616 SECU_PrintError(progName
,"find user certs from nickname failed");
617 pk12uErrno
= PK12UERR_FINDCERTBYNN
;
621 if ((SECSuccess
!= CERT_FilterCertListForUserCerts(certlist
)) ||
622 CERT_LIST_EMPTY(certlist
)) {
623 PR_fprintf(PR_STDERR
, "%s: no user certs from given nickname\n",
625 pk12uErrno
= PK12UERR_FINDCERTBYNN
;
629 /* Password to use for PKCS12 file. */
630 pwitem
= P12U_GetP12FilePassword(PR_TRUE
, p12FilePw
);
635 p12cxt
= p12u_InitContext(PR_FALSE
, outfile
);
637 SECU_PrintError(progName
,"Initialization failed: %s", outfile
);
638 pk12uErrno
= PK12UERR_INIT_FILE
;
643 CERTCertificate
* cert
= NULL
;
644 node
= CERT_LIST_HEAD(certlist
);
649 slot
= cert
->slot
; /* use the slot from the first matching
650 certificate to create the context . This is for keygen */
654 SECU_PrintError(progName
,"cert does not have a slot");
655 pk12uErrno
= PK12UERR_FINDCERTBYNN
;
658 p12ecx
= SEC_PKCS12CreateExportContext(NULL
, NULL
, slot
, slotPw
);
660 SECU_PrintError(progName
,"export context creation failed");
661 pk12uErrno
= PK12UERR_EXPORTCXCREATE
;
665 if(SEC_PKCS12AddPasswordIntegrity(p12ecx
, pwitem
, SEC_OID_SHA1
)
667 SECU_PrintError(progName
,"PKCS12 add password integrity failed");
668 pk12uErrno
= PK12UERR_PK12ADDPWDINTEG
;
672 for (node
= CERT_LIST_HEAD(certlist
);!CERT_LIST_END(node
,certlist
);node
=CERT_LIST_NEXT(node
))
674 CERTCertificate
* cert
= node
->cert
;
676 SECU_PrintError(progName
,"cert does not have a slot");
677 pk12uErrno
= PK12UERR_FINDCERTBYNN
;
681 keySafe
= SEC_PKCS12CreateUnencryptedSafe(p12ecx
);
682 if(certCipher
== SEC_OID_UNKNOWN
) {
686 SEC_PKCS12CreatePasswordPrivSafe(p12ecx
, pwitem
, certCipher
);
689 if(!certSafe
|| !keySafe
) {
690 SECU_PrintError(progName
,"key or cert safe creation failed");
691 pk12uErrno
= PK12UERR_CERTKEYSAFE
;
695 if(SEC_PKCS12AddCertAndKey(p12ecx
, certSafe
, NULL
, cert
,
696 CERT_GetDefaultCertDB(), keySafe
, NULL
, PR_TRUE
, pwitem
, cipher
)
698 SECU_PrintError(progName
,"add cert and key failed");
699 pk12uErrno
= PK12UERR_ADDCERTKEY
;
704 CERT_DestroyCertList(certlist
);
707 if(SEC_PKCS12Encode(p12ecx
, p12u_WriteToExportFile
, p12cxt
)
709 SECU_PrintError(progName
,"PKCS12 encode failed");
710 pk12uErrno
= PK12UERR_ENCODE
;
714 p12u_DestroyContext(&p12cxt
, PR_FALSE
);
715 SECITEM_ZfreeItem(pwitem
, PR_TRUE
);
716 fprintf(stdout
, "%s: PKCS12 EXPORT SUCCESSFUL\n", progName
);
717 SEC_PKCS12DestroyExportContext(p12ecx
);
722 SEC_PKCS12DestroyExportContext(p12ecx
);
725 CERT_DestroyCertList(certlist
);
729 p12u_DestroyContext(&p12cxt
, PR_TRUE
);
731 SECITEM_ZfreeItem(pwitem
, PR_TRUE
);
733 p12u_DoPKCS12ExportErrors();
739 P12U_ListPKCS12File(char *in_file
, PK11SlotInfo
*slot
,
740 secuPWData
*slotPw
, secuPWData
*p12FilePw
)
742 SEC_PKCS12DecoderContext
*p12dcx
= NULL
;
743 SECItem uniPwitem
= { 0 };
744 SECStatus rv
= SECFailure
;
745 const SEC_PKCS12DecoderItem
*dip
;
747 p12dcx
= p12U_ReadPKCS12File(&uniPwitem
, in_file
, slot
, slotPw
,
749 /* did the blob authenticate properly? */
751 SECU_PrintError(progName
,"PKCS12 decode not verified");
752 pk12uErrno
= PK12UERR_DECODEVERIFY
;
755 rv
= SEC_PKCS12DecoderIterateInit(p12dcx
);
756 if(rv
!= SECSuccess
) {
757 SECU_PrintError(progName
,"PKCS12 decode iterate bags failed");
758 pk12uErrno
= PK12UERR_DECODEIMPTBAGS
;
762 while (SEC_PKCS12DecoderIterateNext(p12dcx
, &dip
) == SECSuccess
) {
764 case SEC_OID_PKCS12_V1_CERT_BAG_ID
:
765 printf("Certificate");
769 sprintf(fileName
, "file%04d.der", ++fileCounter
);
770 fd
= PR_Open(fileName
,
771 PR_CREATE_FILE
| PR_RDWR
| PR_TRUNCATE
,
774 SECU_PrintError(progName
,
775 "Cannot create output file");
777 PR_Write(fd
, dip
->der
->data
, dip
->der
->len
);
781 if (SECU_PrintSignedData(stdout
, dip
->der
,
782 (dip
->hasKey
) ? "(has private key)" : "",
783 0, SECU_PrintCertificate
) != 0) {
784 SECU_PrintError(progName
,"PKCS12 print cert bag failed");
786 if (dip
->friendlyName
!= NULL
) {
787 printf(" Friendly Name: %s\n\n",
788 dip
->friendlyName
->data
);
790 if (dip
->shroudAlg
) {
791 SECU_PrintAlgorithmID(stdout
, dip
->shroudAlg
,
792 "Encryption algorithm",1);
795 case SEC_OID_PKCS12_V1_KEY_BAG_ID
:
796 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID
:
798 if (dip
->type
== SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID
)
799 printf("(shrouded)");
801 if (dip
->friendlyName
!= NULL
) {
802 printf(" Friendly Name: %s\n\n",
803 dip
->friendlyName
->data
);
805 if (dip
->shroudAlg
) {
806 SECU_PrintAlgorithmID(stdout
, dip
->shroudAlg
,
807 "Encryption algorithm",1);
811 printf("unknown bag type(%d): %s\n\n", dip
->type
,
812 SECOID_FindOIDTagDescription(dip
->type
));
822 SEC_PKCS12DecoderFinish(p12dcx
);
825 if (uniPwitem
.data
) {
826 SECITEM_ZfreeItem(&uniPwitem
, PR_FALSE
);
833 * use the oid table description to map a user input string to a particular
837 PKCS12U_MapCipherFromString(char *cipherString
, int keyLen
)
843 /* future enhancement: accept dotted oid spec? */
845 /* future enhancement: provide 'friendlier' typed in names for
849 /* look for the oid tag by Description */
850 cipher
= SEC_OID_UNKNOWN
;
851 for (tag
=1; (oid
=SECOID_FindOIDByTag(tag
)) != NULL
; tag
++) {
852 /* only interested in oids that we actually understand */
853 if (oid
->mechanism
== CKM_INVALID_MECHANISM
) {
856 if (PORT_Strcasecmp(oid
->desc
, cipherString
) != 0) {
859 /* we found a match... get the PBE version of this
861 if (!SEC_PKCS5IsAlgorithmPBEAlgTag(tag
)) {
862 cipher
= SEC_PKCS5GetPBEAlgorithm(tag
, keyLen
);
863 /* no eqivalent PKCS5/PKCS12 cipher, use the raw
864 * encryption tag we got and pass it directly in,
865 * pkcs12 will use the pkcsv5 mechanism */
866 if (cipher
== SEC_OID_PKCS5_PBES2
) {
868 } else if (cipher
== SEC_OID_PKCS5_PBMAC1
) {
869 /* make sure we have not macing ciphers here */
870 cipher
= SEC_OID_UNKNOWN
;
881 p12u_EnableAllCiphers()
883 SEC_PKCS12EnableCipher(PKCS12_RC4_40
, 1);
884 SEC_PKCS12EnableCipher(PKCS12_RC4_128
, 1);
885 SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40
, 1);
886 SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128
, 1);
887 SEC_PKCS12EnableCipher(PKCS12_DES_56
, 1);
888 SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168
, 1);
889 SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168
, 1);
893 P12U_Init(char *dir
, char *dbprefix
, PRBool listonly
)
896 PK11_SetPasswordFunc(SECU_GetModulePassword
);
898 PR_Init(PR_SYSTEM_THREAD
, PR_PRIORITY_NORMAL
, 1);
899 if (listonly
&& NSS_NoDB_Init("") == SECSuccess
) {
903 rv
= NSS_Initialize(dir
,dbprefix
,dbprefix
,"secmod.db",0);
905 if (rv
!= SECSuccess
) {
906 SECU_PrintPRandOSError(progName
);
910 /* setup unicode callback functions */
911 PORT_SetUCS2_ASCIIConversionFunction(p12u_ucs2_ascii_conversion_function
);
912 /* use the defaults for UCS4-UTF8 and UCS2-UTF8 */
914 p12u_EnableAllCiphers();
939 static secuCommandFlag pk12util_options
[] =
941 { /* opt_CertDir */ 'd', PR_TRUE
, 0, PR_FALSE
},
942 { /* opt_TokenName */ 'h', PR_TRUE
, 0, PR_FALSE
},
943 { /* opt_Import */ 'i', PR_TRUE
, 0, PR_FALSE
},
944 { /* opt_SlotPWFile */ 'k', PR_TRUE
, 0, PR_FALSE
},
945 { /* opt_SlotPW */ 'K', PR_TRUE
, 0, PR_FALSE
},
946 { /* opt_List */ 'l', PR_TRUE
, 0, PR_FALSE
},
947 { /* opt_Nickname */ 'n', PR_TRUE
, 0, PR_FALSE
},
948 { /* opt_Export */ 'o', PR_TRUE
, 0, PR_FALSE
},
949 { /* opt_Raw */ 'r', PR_FALSE
, 0, PR_FALSE
},
950 { /* opt_P12FilePWFile */ 'w', PR_TRUE
, 0, PR_FALSE
},
951 { /* opt_P12FilePW */ 'W', PR_TRUE
, 0, PR_FALSE
},
952 { /* opt_DBPrefix */ 'P', PR_TRUE
, 0, PR_FALSE
},
953 { /* opt_Debug */ 'v', PR_FALSE
, 0, PR_FALSE
},
954 { /* opt_Cipher */ 'c', PR_TRUE
, 0, PR_FALSE
},
955 { /* opt_CertCipher */ 'C', PR_TRUE
, 0, PR_FALSE
},
956 { /* opt_KeyLength */ 'k', PR_TRUE
, 0, PR_FALSE
},
957 { /* opt_CertKeyLength */ 'K', PR_TRUE
, 0, PR_FALSE
}
961 main(int argc
, char **argv
)
963 secuPWData slotPw
= { PW_NONE
, NULL
};
964 secuPWData p12FilePw
= { PW_NONE
, NULL
};
966 char *slotname
= NULL
;
967 char *import_file
= NULL
;
968 char *export_file
= NULL
;
972 SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC
;
973 SECOidTag certCipher
;
977 secuCommand pk12util
;
978 pk12util
.numCommands
= 0;
979 pk12util
.commands
= 0;
980 pk12util
.numOptions
= sizeof(pk12util_options
) / sizeof(secuCommandFlag
);
981 pk12util
.options
= pk12util_options
;
983 progName
= strrchr(argv
[0], '/');
984 progName
= progName
? progName
+1 : argv
[0];
986 rv
= SECU_ParseCommandLine(argc
, argv
, progName
, &pk12util
);
988 if (rv
!= SECSuccess
)
991 pk12_debugging
= pk12util
.options
[opt_Debug
].activated
;
993 if ((pk12util
.options
[opt_Import
].activated
+
994 pk12util
.options
[opt_Export
].activated
+
995 pk12util
.options
[opt_List
].activated
) != 1) {
999 if (pk12util
.options
[opt_Export
].activated
&&
1000 !pk12util
.options
[opt_Nickname
].activated
) {
1004 slotname
= SECU_GetOptionArg(&pk12util
, opt_TokenName
);
1006 import_file
= (pk12util
.options
[opt_List
].activated
) ?
1007 SECU_GetOptionArg(&pk12util
, opt_List
) :
1008 SECU_GetOptionArg(&pk12util
, opt_Import
);
1009 export_file
= SECU_GetOptionArg(&pk12util
, opt_Export
);
1011 if (pk12util
.options
[opt_P12FilePWFile
].activated
) {
1012 p12FilePw
.source
= PW_FROMFILE
;
1013 p12FilePw
.data
= PL_strdup(pk12util
.options
[opt_P12FilePWFile
].arg
);
1016 if (pk12util
.options
[opt_P12FilePW
].activated
) {
1017 p12FilePw
.source
= PW_PLAINTEXT
;
1018 p12FilePw
.data
= PL_strdup(pk12util
.options
[opt_P12FilePW
].arg
);
1021 if (pk12util
.options
[opt_SlotPWFile
].activated
) {
1022 slotPw
.source
= PW_FROMFILE
;
1023 slotPw
.data
= PL_strdup(pk12util
.options
[opt_SlotPWFile
].arg
);
1026 if (pk12util
.options
[opt_SlotPW
].activated
) {
1027 slotPw
.source
= PW_PLAINTEXT
;
1028 slotPw
.data
= PL_strdup(pk12util
.options
[opt_SlotPW
].arg
);
1031 if (pk12util
.options
[opt_CertDir
].activated
) {
1032 SECU_ConfigDirectory(pk12util
.options
[opt_CertDir
].arg
);
1034 if (pk12util
.options
[opt_DBPrefix
].activated
) {
1035 dbprefix
= pk12util
.options
[opt_DBPrefix
].arg
;
1037 if (pk12util
.options
[opt_Raw
].activated
) {
1038 dumpRawFile
= PR_TRUE
;
1040 if (pk12util
.options
[opt_KeyLength
].activated
) {
1041 keyLen
= atoi(pk12util
.options
[opt_KeyLength
].arg
);
1043 if (pk12util
.options
[opt_CertKeyLength
].activated
) {
1044 certKeyLen
= atoi(pk12util
.options
[opt_CertKeyLength
].arg
);
1047 P12U_Init(SECU_ConfigDirectory(NULL
), dbprefix
,
1048 pk12util
.options
[opt_List
].activated
);
1050 if (!slotname
|| PL_strcmp(slotname
, "internal") == 0)
1051 slot
= PK11_GetInternalKeySlot();
1053 slot
= PK11_FindSlotByName(slotname
);
1056 SECU_PrintError(progName
,"Invalid slot \"%s\"", slotname
);
1057 pk12uErrno
= PK12UERR_PK11GETSLOT
;
1061 if (pk12util
.options
[opt_Cipher
].activated
) {
1062 char *cipherString
= pk12util
.options
[opt_Cipher
].arg
;
1064 cipher
= PKCS12U_MapCipherFromString(cipherString
, keyLen
);
1065 /* We only want encryption PBE's. make sure we don't have
1067 if (cipher
== SEC_OID_UNKNOWN
) {
1068 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM
);
1069 SECU_PrintError(progName
, "Algorithm: \"%s\"", cipherString
);
1070 pk12uErrno
= PK12UERR_INVALIDALGORITHM
;
1075 certCipher
= PK11_IsFIPS() ? SEC_OID_UNKNOWN
:
1076 SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC
;
1077 if (pk12util
.options
[opt_CertCipher
].activated
) {
1078 char *cipherString
= pk12util
.options
[opt_CertCipher
].arg
;
1080 if (PORT_Strcasecmp(cipherString
, "none") == 0) {
1081 certCipher
= SEC_OID_UNKNOWN
;
1083 certCipher
= PKCS12U_MapCipherFromString(cipherString
, certKeyLen
);
1084 /* If the user requested a cipher and we didn't find it, then
1085 * don't just silently not encrypt. */
1086 if (cipher
== SEC_OID_UNKNOWN
) {
1087 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM
);
1088 SECU_PrintError(progName
, "Algorithm: \"%s\"", cipherString
);
1089 pk12uErrno
= PK12UERR_INVALIDALGORITHM
;
1096 if (pk12util
.options
[opt_Import
].activated
) {
1097 P12U_ImportPKCS12Object(import_file
, slot
, &slotPw
,
1100 } else if (pk12util
.options
[opt_Export
].activated
) {
1101 P12U_ExportPKCS12Object(pk12util
.options
[opt_Nickname
].arg
,
1102 export_file
, slot
, cipher
, certCipher
,
1103 &slotPw
, &p12FilePw
);
1105 } else if (pk12util
.options
[opt_List
].activated
) {
1106 P12U_ListPKCS12File(import_file
, slot
, &slotPw
, &p12FilePw
);
1110 pk12uErrno
= PK12UERR_USAGE
;
1114 if (slotPw
.data
!= NULL
)
1115 PORT_ZFree(slotPw
.data
, PL_strlen(slotPw
.data
));
1116 if (p12FilePw
.data
!= NULL
)
1117 PORT_ZFree(p12FilePw
.data
, PL_strlen(p12FilePw
.data
));
1118 if (slot
) PK11_FreeSlot(slot
);
1119 if (NSS_Shutdown() != SECSuccess
) {