security/nss/cmd/pk12util/pk12util.c

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

     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/. */
     5 #ifdef _CRTDBG_MAP_ALLOC
     6 #include <stdlib.h>
     7 #include <crtdbg.h>
     8 #endif
    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"
    21 #define PKCS12_IN_BUFFER_SIZE	200
    23 static char *progName;
    24 PRBool pk12_debugging = PR_FALSE;
    25 PRBool dumpRawFile;
    27 PRIntn pk12uErrno = 0;
    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");
    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");
    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");
    50     exit(PK12UERR_USAGE);
    51 }
    53 static PRBool
    54 p12u_OpenFile(p12uContext *p12cxt, PRBool fileRead)
    55 {
    56     if(!p12cxt || !p12cxt->filename) {
    57 	return PR_FALSE;
    58     }
    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     }
    69     if(!p12cxt->file) {
    70 	p12cxt->error = PR_TRUE;
    71 	return PR_FALSE;
    72     }
    74     return PR_TRUE;
    75 }
    77 static void
    78 p12u_DestroyContext(p12uContext **ppCtx, PRBool removeFile)
    79 {
    80     if(!ppCtx || !(*ppCtx)) {
    81 	return;
    82     }
    84     if((*ppCtx)->file != NULL) {
    85 	PR_Close((*ppCtx)->file);
    86     }
    88     if((*ppCtx)->filename != NULL) {
    89 	if(removeFile) {
    90 	    PR_Delete((*ppCtx)->filename);
    91 	}
    92 	PL_strfree((*ppCtx)->filename);
    93 	(*ppCtx)->filename = NULL;
    94     }
    96     PR_Free(*ppCtx);
    97     *ppCtx = NULL;
    98 }
   100 static p12uContext *
   101 p12u_InitContext(PRBool fileImport, char *filename)
   102 {
   103     p12uContext *p12cxt;
   104     PRBool fileExist;
   106     fileExist = fileImport;
   108     p12cxt = PORT_ZNew(p12uContext);
   109     if(!p12cxt) {
   110 	return NULL;
   111     }
   113     p12cxt->error = PR_FALSE;
   114     p12cxt->errorValue = 0;
   115     p12cxt->filename = PL_strdup(filename);
   117     if(!p12u_OpenFile(p12cxt, fileImport)) {
   118 	p12u_DestroyContext(&p12cxt, PR_FALSE);
   119 	return NULL;
   120     }
   122     return p12cxt;
   123 }
   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;
   132     if (!cancel || !cert) {
   133 	pk12uErrno = PK12UERR_USER_CANCELLED;
   134 	return NULL;
   135     }
   137     if (!old_nick)
   138 	fprintf(stdout, "pk12util: no nickname for cert in PKCS12 file.\n");
   140 #if 0
   141     /* XXX not handled yet  */
   142     *cancel = PR_TRUE;
   143     return NULL;
   145 #else
   147     nick = CERT_MakeCANickname(cert); 
   148     if (!nick) {
   149     	return NULL;
   150     }
   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     }
   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     }
   167     ret_nick->data = (unsigned char *)nick;
   168     ret_nick->len = PORT_Strlen(nick);
   170     return ret_nick;
   171 #endif
   172 }
   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 }
   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;
   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);
   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 }
   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 }
   272 /*
   273  *
   274  */
   275 SECItem *
   276 P12U_GetP12FilePassword(PRBool confirmPw, secuPWData *p12FilePw)
   277 {
   278     char *p0 = NULL;
   279     SECItem *pwItem = NULL;
   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     }
   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);
   313     PORT_ZFree(p0, PL_strlen(p0));
   315     return pwItem;
   316 }
   318 SECStatus
   319 P12U_InitSlot(PK11SlotInfo *slot, secuPWData *slotPw)
   320 {
   321     SECStatus rv;
   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     }
   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     }
   343     return SECSuccess;
   344 }
   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;
   364 #ifdef IS_LITTLE_ENDIAN
   365     swapUnicode = PR_TRUE;
   366 #endif
   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     }
   375     /* get the password */
   376     pwitem = P12U_GetP12FilePassword(PR_FALSE, p12FilePw);
   377     if (!pwitem) {
   378 	pk12uErrno = PK12UERR_USER_CANCELLED;
   379 	goto done;
   380     }
   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     }
   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         }
   406         /* decode the item */
   407         rv = SEC_PKCS12DecoderUpdate(p12dcx, p12file.data, p12file.len);
   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         }
   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 */
   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);
   455     if (pwitem) {
   456 	SECITEM_ZfreeItem(pwitem, PR_TRUE);
   457     }
   458     SECITEM_ZfreeItem(&p12file, PR_FALSE);
   459     return p12dcx;
   460 }
   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;
   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     }
   486     rv = SECFailure;
   487     p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw, p12FilePw);
   489     if(p12dcx == NULL) {
   490         goto loser;
   491     }
   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     }
   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     }
   513     fprintf(stdout, "%s: PKCS12 IMPORT SUCCESSFUL\n", progName);
   514     rv = SECSuccess;
   516 loser:
   517     if (p12dcx) {
   518 	SEC_PKCS12DecoderFinish(p12dcx);
   519     }
   521     if (uniPwitem.data) {
   522 	SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
   523     }
   525     return rv;
   526 }
   528 static void
   529 p12u_DoPKCS12ExportErrors()
   530 {
   531     PRErrorCode error_value;
   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 }
   545 static void
   546 p12u_WriteToExportFile(void *arg, const char *buf, unsigned long len)
   547 {
   548     p12uContext *p12cxt = arg;
   549     int writeLen;
   551     if(!p12cxt || (p12cxt->error == PR_TRUE)) {
   552 	return;
   553     }
   555     if(p12cxt->file == NULL) {
   556 	p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
   557 	p12cxt->error = PR_TRUE;
   558 	return;
   559     }
   561     writeLen = PR_Write(p12cxt->file, (unsigned char *)buf, (PRInt32)len);
   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 }
   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;
   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     }
   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     }
   608     /*	Password to use for PKCS12 file.  */
   609     pwitem = P12U_GetP12FilePassword(PR_TRUE, p12FilePw);
   610     if(!pwitem) {
   611 	goto loser;
   612     }
   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     }
   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     }
   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     }
   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         }
   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         }
   669         if(!certSafe || !keySafe) {
   670             SECU_PrintError(progName,"key or cert safe creation failed");
   671             pk12uErrno = PK12UERR_CERTKEYSAFE;
   672             goto loser;
   673         }
   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     }
   684     CERT_DestroyCertList(certlist);
   685     certlist = NULL;
   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     }
   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);
   699     return;
   701 loser:
   702     SEC_PKCS12DestroyExportContext(p12ecx);
   704     if (certlist) {
   705         CERT_DestroyCertList(certlist);
   706         certlist = NULL;
   707     }    
   709     p12u_DestroyContext(&p12cxt, PR_TRUE);
   710     if(pwitem) {
   711         SECITEM_ZfreeItem(pwitem, PR_TRUE);
   712     }
   713     p12u_DoPKCS12ExportErrors();
   714     return;
   715 }
   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;
   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     }
   798 loser:
   800     if (p12dcx) {
   801 	SEC_PKCS12DecoderFinish(p12dcx);
   802     }
   804     if (uniPwitem.data) {
   805 	SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
   806     }
   808     return rv;
   809 }
   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;
   822     /* future enhancement: accept dotted oid spec? */
   824     /* future enhancement: provide 'friendlier' typed in names for
   825      * pbe mechanisms.
   826      */
   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 }
   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 }
   871 static PRUintn
   872 P12U_Init(char *dir, char *dbprefix, PRBool listonly)
   873 {
   874     SECStatus rv;
   875     PK11_SetPasswordFunc(SECU_GetModulePassword);
   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     }
   889     /* setup unicode callback functions */
   890     PORT_SetUCS2_ASCIIConversionFunction(p12u_ucs2_ascii_conversion_function);
   891     /* use the defaults for UCS4-UTF8 and UCS2-UTF8 */
   893     p12u_EnableAllCiphers();
   895     return 0;
   896 }
   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 };
   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 };
   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;
   957 #ifdef _CRTDBG_MAP_ALLOC
   958     _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
   959 #endif
   961     pk12util.numCommands = 0;
   962     pk12util.commands = 0;
   963     pk12util.numOptions = sizeof(pk12util_options) / sizeof(secuCommandFlag);
   964     pk12util.options = pk12util_options;
   966     progName = strrchr(argv[0], '/');
   967     progName = progName ? progName+1 : argv[0];
   969     rv = SECU_ParseCommandLine(argc, argv, progName, &pk12util);
   971     if (rv != SECSuccess)
   972 	Usage(progName);
   974     pk12_debugging = pk12util.options[opt_Debug].activated;
   976     if ((pk12util.options[opt_Import].activated +
   977 	pk12util.options[opt_Export].activated +
   978         pk12util.options[opt_List].activated) != 1) {
   979 	Usage(progName);
   980     }
   982     if (pk12util.options[opt_Export].activated &&
   983        !pk12util.options[opt_Nickname].activated) {
   984 	Usage(progName);
   985     }
   987     slotname = SECU_GetOptionArg(&pk12util, opt_TokenName);
   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);
   994     if (pk12util.options[opt_P12FilePWFile].activated) {
   995 	p12FilePw.source = PW_FROMFILE;
   996 	p12FilePw.data = PORT_Strdup(pk12util.options[opt_P12FilePWFile].arg);
   997     }
   999     if (pk12util.options[opt_P12FilePW].activated) {
  1000 	p12FilePw.source = PW_PLAINTEXT;
  1001 	p12FilePw.data = PORT_Strdup(pk12util.options[opt_P12FilePW].arg);
  1004     if (pk12util.options[opt_SlotPWFile].activated) {
  1005 	slotPw.source = PW_FROMFILE;
  1006 	slotPw.data = PORT_Strdup(pk12util.options[opt_SlotPWFile].arg);
  1009     if (pk12util.options[opt_SlotPW].activated) {
  1010 	slotPw.source = PW_PLAINTEXT;
  1011 	slotPw.data = PORT_Strdup(pk12util.options[opt_SlotPW].arg);
  1014     if (pk12util.options[opt_CertDir].activated) {
  1015 	SECU_ConfigDirectory(pk12util.options[opt_CertDir].arg);
  1017     if (pk12util.options[opt_DBPrefix].activated) {
  1018     	dbprefix = pk12util.options[opt_DBPrefix].arg;
  1020     if (pk12util.options[opt_Raw].activated) {
  1021     	dumpRawFile = PR_TRUE;
  1023     if (pk12util.options[opt_KeyLength].activated) {
  1024     	keyLen = atoi(pk12util.options[opt_KeyLength].arg);
  1026     if (pk12util.options[opt_CertKeyLength].activated) {
  1027     	certKeyLen = atoi(pk12util.options[opt_CertKeyLength].arg);
  1030     P12U_Init(SECU_ConfigDirectory(NULL), dbprefix,
  1031                 pk12util.options[opt_List].activated);
  1033     if (!slotname || PL_strcmp(slotname, "internal") == 0)
  1034 	slot = PK11_GetInternalKeySlot();
  1035     else
  1036 	slot = PK11_FindSlotByName(slotname);
  1038     if (!slot) {
  1039 	SECU_PrintError(progName,"Invalid slot \"%s\"", slotname);
  1040 	pk12uErrno = PK12UERR_PK11GETSLOT;
  1041 	goto done;
  1044     if (pk12util.options[opt_Cipher].activated) {
  1045 	char *cipherString = pk12util.options[opt_Cipher].arg;
  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;
  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;
  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;
  1079     if (pk12util.options[opt_Import].activated) {
  1080 	P12U_ImportPKCS12Object(import_file, slot,  &slotPw, &p12FilePw);
  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);
  1087     } else if (pk12util.options[opt_List].activated) {
  1088 	P12U_ListPKCS12File(import_file, slot, &slotPw, &p12FilePw);
  1090     } else {
  1091 	Usage(progName);
  1092 	pk12uErrno = PK12UERR_USAGE;
  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;
  1105     PL_ArenaFinish();
  1106     PR_Cleanup();
  1107     return pk12uErrno;

mercurial