Back to index

lightning-sunbird  0.9+nobinonly
pk12util.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #include "nspr.h"
00038 #include "secutil.h"
00039 #include "pk11func.h"
00040 #include "pkcs12.h"
00041 #include "p12plcy.h"
00042 #include "pk12util.h"
00043 #include "nss.h"
00044 #include "secport.h"
00045 #include "certdb.h"
00046 
00047 #define PKCS12_IN_BUFFER_SIZE      200
00048 
00049 static char *progName;
00050 PRBool pk12_debugging = PR_FALSE;
00051 
00052 PRIntn pk12uErrno = 0;
00053 
00054 static void
00055 Usage(char *progName)
00056 {
00057 #define FPS PR_fprintf(PR_STDERR,
00058     FPS "Usage:       %s -i importfile [-d certdir] [-P dbprefix] [-h tokenname]\n",
00059                              progName);
00060     FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
00061     FPS "\t\t [-v]\n");
00062     FPS "Usage:       %s -l listfile [-d certdir] [-P dbprefix] [-h tokenname]\n",
00063                              progName);
00064     FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
00065     FPS "Usage:       %s -o exportfile -n certname [-d certdir] [-P dbprefix]\n", progName);
00066     FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
00067     FPS "\t\t [-v]\n");
00068     exit(PK12UERR_USAGE);
00069 }
00070 
00071 static PRBool
00072 p12u_OpenFile(p12uContext *p12cxt, PRBool fileRead)
00073 {
00074     if(!p12cxt || !p12cxt->filename) {
00075        return PR_FALSE;
00076     }
00077 
00078     if(fileRead) {
00079        p12cxt->file = PR_Open(p12cxt->filename,
00080                              PR_RDONLY, 0400);
00081     } else {
00082        p12cxt->file = PR_Open(p12cxt->filename,
00083                              PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE,
00084                              0600);
00085     }
00086 
00087     if(!p12cxt->file) {
00088        p12cxt->error = PR_TRUE;
00089        return PR_FALSE;
00090     }
00091 
00092     return PR_TRUE;
00093 }
00094 
00095 static void
00096 p12u_DestroyContext(p12uContext **ppCtx, PRBool removeFile)
00097 {
00098     if(!ppCtx || !(*ppCtx)) {
00099        return;
00100     }
00101 
00102     if((*ppCtx)->file != NULL) {
00103        PR_Close((*ppCtx)->file);
00104     }
00105 
00106     if((*ppCtx)->filename != NULL) {
00107        if(removeFile) {
00108            PR_Delete((*ppCtx)->filename);
00109        }
00110        PR_Free((*ppCtx)->filename);
00111     }
00112 
00113     PR_Free(*ppCtx);
00114     *ppCtx = NULL;
00115 }
00116 
00117 static p12uContext *
00118 p12u_InitContext(PRBool fileImport, char *filename)
00119 {
00120     p12uContext *p12cxt;
00121     PRBool fileExist;
00122 
00123     fileExist = fileImport;
00124 
00125     p12cxt = PORT_ZNew(p12uContext);
00126     if(!p12cxt) {
00127        return NULL;
00128     }
00129 
00130     p12cxt->error = PR_FALSE;
00131     p12cxt->errorValue = 0;
00132     p12cxt->filename = strdup(filename);
00133 
00134     if(!p12u_OpenFile(p12cxt, fileImport)) {
00135        p12u_DestroyContext(&p12cxt, PR_FALSE);
00136        return NULL;
00137     }
00138 
00139     return p12cxt;
00140 }
00141 
00142 SECItem *
00143 P12U_NicknameCollisionCallback(SECItem *old_nick, PRBool *cancel, void *wincx)
00144 {
00145     if(cancel == NULL) {
00146       pk12uErrno = PK12UERR_USER_CANCELLED;
00147       return NULL;
00148     }
00149 
00150     if (!old_nick)
00151       fprintf(stdout, "pk12util: no nickname for cert...not handled\n");
00152 
00153     /* XXX not handled yet  */
00154     *cancel = PR_TRUE;
00155     return NULL;
00156 
00157 #if 0
00158     char *nick = NULL;
00159     SECItem *ret_nick = NULL;
00160 
00161     nick = strdup( DEFAULT_CERT_NICKNAME );
00162 
00163     if(old_nick && !PORT_Strcmp((char *)old_nick->data, nick)) {
00164        PORT_Free(nick);
00165        return NULL;
00166     }
00167 
00168     ret_nick = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
00169     if(ret_nick == NULL) {
00170        PORT_Free(nick);
00171        return NULL;
00172     }
00173 
00174     ret_nick->data = (unsigned char *)nick;
00175     ret_nick->len = PORT_Strlen(nick);
00176 
00177     return ret_nick;
00178 #endif
00179 }
00180 
00181 static SECStatus
00182 p12u_SwapUnicodeBytes(SECItem *uniItem)
00183 {
00184     unsigned int i;
00185     unsigned char a;
00186     if((uniItem == NULL) || (uniItem->len % 2)) {
00187        return SECFailure;
00188     }
00189     for(i = 0; i < uniItem->len; i += 2) {
00190        a = uniItem->data[i];
00191        uniItem->data[i] = uniItem->data[i+1];
00192        uniItem->data[i+1] = a;
00193     }
00194     return SECSuccess;
00195 }
00196 
00197 static PRBool
00198 p12u_ucs2_ascii_conversion_function(PRBool          toUnicode,
00199                                 unsigned char *inBuf,
00200                                 unsigned int   inBufLen,
00201                                 unsigned char *outBuf,
00202                                 unsigned int   maxOutBufLen,
00203                                 unsigned int  *outBufLen,
00204                                 PRBool       swapBytes)
00205 {
00206     SECItem it = { 0 };
00207     SECItem *dup = NULL;
00208     PRBool ret;
00209 
00210 #ifdef DEBUG_CONVERSION
00211     if (pk12_debugging) {
00212        int i;
00213        printf("Converted from:\n");
00214        for (i=0; i<inBufLen; i++) {
00215            printf("%2x ", inBuf[i]);
00216            /*if (i%60 == 0) printf("\n");*/
00217        }
00218        printf("\n");
00219     }
00220 #endif
00221     it.data = inBuf;
00222     it.len = inBufLen;
00223     dup = SECITEM_DupItem(&it);
00224     /* If converting Unicode to ASCII, swap bytes before conversion
00225      * as neccessary.
00226      */
00227     if (!toUnicode && swapBytes) {
00228        if (p12u_SwapUnicodeBytes(dup) != SECSuccess) {
00229            SECITEM_ZfreeItem(dup, PR_TRUE);
00230            return PR_FALSE;
00231        }
00232     }
00233     /* Perform the conversion. */
00234     ret = PORT_UCS2_UTF8Conversion(toUnicode, dup->data, dup->len,
00235                                    outBuf, maxOutBufLen, outBufLen);
00236     if (dup)
00237        SECITEM_ZfreeItem(dup, PR_TRUE);
00238 
00239 #ifdef DEBUG_CONVERSION
00240     if (pk12_debugging) {
00241        int i;
00242        printf("Converted to:\n");
00243        for (i=0; i<*outBufLen; i++) {
00244            printf("%2x ", outBuf[i]);
00245            /*if (i%60 == 0) printf("\n");*/
00246        }
00247        printf("\n");
00248     }
00249 #endif
00250     return ret;
00251 }
00252 
00253 SECStatus
00254 P12U_UnicodeConversion(PRArenaPool *arena, SECItem *dest, SECItem *src,
00255                      PRBool toUnicode, PRBool swapBytes)
00256 {
00257     unsigned int allocLen;
00258     if(!dest || !src) {
00259        return SECFailure;
00260     }
00261     allocLen = ((toUnicode) ? (src->len << 2) : src->len);
00262     if(arena) {
00263        dest->data = PORT_ArenaZAlloc(arena, allocLen);
00264     } else {
00265        dest->data = PORT_ZAlloc(allocLen);
00266     }
00267     if(PORT_UCS2_ASCIIConversion(toUnicode, src->data, src->len,
00268                              dest->data, allocLen, &dest->len,
00269                              swapBytes) == PR_FALSE) {
00270        if(!arena) {
00271            PORT_Free(dest->data);
00272        }
00273        dest->data = NULL;
00274        return SECFailure;
00275     }
00276     return SECSuccess;
00277 }
00278 
00279 /*
00280  *
00281  */
00282 SECItem *
00283 P12U_GetP12FilePassword(PRBool confirmPw, secuPWData *p12FilePw)
00284 {
00285     char *p0 = NULL;
00286     SECItem *pwItem = NULL;
00287 
00288     if (p12FilePw == NULL || p12FilePw->source == PW_NONE) {
00289        char *p1 = NULL;
00290        int   rc;
00291        for (;;) {
00292            p0 = SECU_GetPasswordString(NULL,
00293                                    "Enter password for PKCS12 file: ");
00294            if (!confirmPw || p0 == NULL)
00295               break;
00296            p1 = SECU_GetPasswordString(NULL, "Re-enter password: ");
00297            if (p1 == NULL) {
00298               PORT_ZFree(p0, PL_strlen(p0));
00299               p0 = NULL;
00300               break;
00301            }
00302            rc = PL_strcmp(p0, p1);
00303            PORT_ZFree(p1, PL_strlen(p1));
00304            if (rc == 0)
00305               break;
00306            PORT_ZFree(p0, PL_strlen(p0));
00307        }
00308     } else if (p12FilePw->source == PW_FROMFILE) {
00309        p0 = SECU_FilePasswd(NULL, PR_FALSE, p12FilePw->data);
00310     } else { /* Plaintext */
00311        p0 = PORT_Strdup(p12FilePw->data);
00312     }
00313 
00314     if (p0 == NULL) {
00315         return NULL;
00316     }
00317     pwItem = SECITEM_AllocItem(NULL, NULL, PL_strlen(p0) + 1);
00318     memcpy(pwItem->data, p0, pwItem->len);
00319 
00320     PORT_ZFree(p0, PL_strlen(p0));
00321 
00322     return pwItem;
00323 }
00324 
00325 SECStatus
00326 P12U_InitSlot(PK11SlotInfo *slot, secuPWData *slotPw)
00327 {
00328     SECStatus rv;
00329 
00330     /* New databases, initialize keydb password. */
00331     if (PK11_NeedUserInit(slot)) {
00332        rv = SECU_ChangePW(slot,
00333                         (slotPw->source == PW_PLAINTEXT) ? slotPw->data : 0,
00334                         (slotPw->source == PW_FROMFILE) ? slotPw->data : 0);
00335        if (rv != SECSuccess) {
00336            SECU_PrintError(progName, "Failed to initialize slot \"%s\"",
00337                                 PK11_GetSlotName(slot));
00338            return SECFailure;
00339        }
00340     }
00341 
00342     if (PK11_Authenticate(slot, PR_TRUE, slotPw) != SECSuccess) {
00343        SECU_PrintError(progName,
00344                       "Failed to authenticate to PKCS11 slot");
00345        PORT_SetError(SEC_ERROR_USER_CANCELLED);
00346        pk12uErrno = PK12UERR_USER_CANCELLED;
00347        return SECFailure;
00348     }
00349 
00350     return SECSuccess;
00351 }
00352 
00353 /* This routine takes care of getting the PKCS12 file password, then reading and
00354  * verifying the file. It returns the decoder context and a filled in password.
00355  * (The password is needed by P12U_ImportPKCS12Object() to import the private
00356  * key.)
00357  */
00358 SEC_PKCS12DecoderContext *
00359 p12U_ReadPKCS12File(SECItem *uniPwp, char *in_file, PK11SlotInfo *slot,
00360                     secuPWData *slotPw, secuPWData *p12FilePw)
00361 {
00362     SEC_PKCS12DecoderContext *p12dcx = NULL;
00363     p12uContext *p12cxt = NULL;
00364     SECItem *pwitem = NULL;
00365     SECItem p12file = { 0 };
00366     SECStatus rv = SECFailure;
00367     PRBool swapUnicode = PR_FALSE;
00368     PRBool trypw;
00369     int error;
00370     
00371 #ifdef IS_LITTLE_ENDIAN
00372     swapUnicode = PR_TRUE;
00373 #endif
00374 
00375     p12cxt = p12u_InitContext(PR_TRUE, in_file);
00376     if(!p12cxt) {
00377        SECU_PrintError(progName,"File Open failed: %s", in_file);
00378        pk12uErrno = PK12UERR_INIT_FILE;
00379         return NULL;
00380     }
00381 
00382     /* get the password */
00383     pwitem = P12U_GetP12FilePassword(PR_FALSE, p12FilePw);
00384     if (!pwitem) {
00385        pk12uErrno = PK12UERR_USER_CANCELLED;
00386        goto done;
00387     }
00388 
00389     if(P12U_UnicodeConversion(NULL, uniPwp, pwitem, PR_TRUE,
00390                               swapUnicode) != SECSuccess) {
00391        SECU_PrintError(progName,"Unicode conversion failed");
00392        pk12uErrno = PK12UERR_UNICODECONV;
00393        goto done;
00394     }
00395     rv = SECU_FileToItem(&p12file, p12cxt->file);
00396     if (rv != SECSuccess) {
00397         SECU_PrintError(progName,"Failed to read from import file");
00398         goto done;
00399     }
00400 
00401     do {
00402         trypw = PR_FALSE;                  /* normally we do this once */
00403         rv = SECFailure;
00404         /* init the decoder context */
00405         p12dcx = SEC_PKCS12DecoderStart(uniPwp, slot, slotPw,
00406                                         NULL, NULL, NULL, NULL, NULL);
00407         if(!p12dcx) {
00408             SECU_PrintError(progName,"PKCS12 decoder start failed");
00409             pk12uErrno = PK12UERR_PK12DECODESTART;
00410             break;
00411         }
00412 
00413         /* decode the item */
00414         rv = SEC_PKCS12DecoderUpdate(p12dcx, p12file.data, p12file.len);
00415 
00416         if(rv != SECSuccess) {
00417             error = PR_GetError();
00418             if(error == SEC_ERROR_DECRYPTION_DISALLOWED) {
00419                 PR_SetError(error, 0);
00420                 break;
00421             }
00422             SECU_PrintError(progName,"PKCS12 decoding failed");
00423             pk12uErrno = PK12UERR_DECODE;
00424         }
00425 
00426         /* does the blob authenticate properly? */
00427         rv = SEC_PKCS12DecoderVerify(p12dcx);
00428         if (rv != SECSuccess) {
00429             if(uniPwp->len == 2) {
00430                 /* this is a null PW, try once more with a zero-length PW
00431                    instead of a null string */
00432                 SEC_PKCS12DecoderFinish(p12dcx);
00433                 uniPwp->len = 0;
00434                 trypw = PR_TRUE;
00435             }
00436             else {
00437                 SECU_PrintError(progName,"PKCS12 decode not verified");
00438                 pk12uErrno = PK12UERR_DECODEVERIFY;
00439                 break;
00440             }
00441         }
00442     } while (trypw == PR_TRUE);
00443     /* rv has been set at this point */
00444 
00445 
00446 done:
00447     if (rv != SECSuccess) {
00448         if (p12dcx != NULL) {
00449             SEC_PKCS12DecoderFinish(p12dcx);
00450             p12dcx = NULL;
00451         }
00452         if (uniPwp->data) {
00453             SECITEM_ZfreeItem(uniPwp, PR_FALSE);
00454             uniPwp->data = NULL;
00455         }
00456     }
00457     PR_Close(p12cxt->file);
00458     p12cxt->file = NULL;
00459     /* PK11_FreeSlot(slot); */
00460     p12u_DestroyContext(&p12cxt, PR_FALSE);
00461 
00462     if (pwitem) {
00463        SECITEM_ZfreeItem(pwitem, PR_TRUE);
00464     }
00465     return p12dcx;
00466 }
00467 
00468 /*
00469  * given a filename for pkcs12 file, imports certs and keys
00470  *
00471  * Change: altitude
00472  *  I've changed this function so that it takes the keydb and pkcs12 file
00473  *  passwords from files.  The "pwdKeyDB" and "pwdP12File"
00474  *  variables have been added for this purpose.
00475  */
00476 PRIntn
00477 P12U_ImportPKCS12Object(char *in_file, PK11SlotInfo *slot,
00478                      secuPWData *slotPw, secuPWData *p12FilePw)
00479 {
00480     SEC_PKCS12DecoderContext *p12dcx = NULL;
00481     SECItem uniPwitem = { 0 };
00482     SECStatus rv = SECFailure;
00483     int error;
00484 
00485     rv = P12U_InitSlot(slot, slotPw);
00486     if (rv != SECSuccess) {
00487        SECU_PrintError(progName, "Failed to authenticate to \"%s\"",
00488                                                   PK11_GetSlotName(slot));
00489        pk12uErrno = PK12UERR_PK11GETSLOT;
00490        return rv;
00491     }
00492 
00493     rv = SECFailure;
00494     p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw, p12FilePw);
00495     
00496     if(p12dcx == NULL) {
00497         goto loser;
00498     }
00499     
00500     /* make sure the bags are okey dokey -- nicknames correct, etc. */
00501     rv = SEC_PKCS12DecoderValidateBags(p12dcx, P12U_NicknameCollisionCallback);
00502     if (rv != SECSuccess) {
00503        if (PORT_GetError() == SEC_ERROR_PKCS12_DUPLICATE_DATA) {
00504            pk12uErrno = PK12UERR_CERTALREADYEXISTS;
00505        } else {
00506            pk12uErrno = PK12UERR_DECODEVALIBAGS;
00507        }
00508        SECU_PrintError(progName,"PKCS12 decode validate bags failed");
00509        goto loser;
00510     }
00511 
00512     /* stuff 'em in */
00513     rv = SEC_PKCS12DecoderImportBags(p12dcx);
00514     if (rv != SECSuccess) {
00515        SECU_PrintError(progName,"PKCS12 decode import bags failed");
00516        pk12uErrno = PK12UERR_DECODEIMPTBAGS;
00517        goto loser;
00518     }
00519 
00520     fprintf(stdout, "%s: PKCS12 IMPORT SUCCESSFUL\n", progName);
00521     rv = SECSuccess;
00522 
00523 loser:
00524     if (p12dcx) {
00525        SEC_PKCS12DecoderFinish(p12dcx);
00526     }
00527     
00528     if (uniPwitem.data) {
00529        SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
00530     }
00531     
00532     return rv;
00533 }
00534 
00535 static void
00536 p12u_DoPKCS12ExportErrors()
00537 {
00538     int error_value;
00539 
00540     error_value = PORT_GetError();
00541     if ((error_value == SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY) ||
00542        (error_value == SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME) ||
00543        (error_value == SEC_ERROR_PKCS12_UNABLE_TO_WRITE)) {
00544        fprintf(stderr, SECU_ErrorStringRaw((int16)error_value));
00545     } else if(error_value == SEC_ERROR_USER_CANCELLED) {
00546        ;
00547     } else {
00548        fprintf(stderr, SECU_ErrorStringRaw(SEC_ERROR_EXPORTING_CERTIFICATES));
00549     }
00550 }
00551 
00552 static void
00553 p12u_WriteToExportFile(void *arg, const char *buf, unsigned long len)
00554 {
00555     p12uContext *p12cxt = arg;
00556     int writeLen;
00557 
00558     if(!p12cxt || (p12cxt->error == PR_TRUE)) {
00559        return;
00560     }
00561 
00562     if(p12cxt->file == NULL) {
00563        p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
00564        p12cxt->error = PR_TRUE;
00565        return;
00566     }
00567 
00568     writeLen = PR_Write(p12cxt->file, (unsigned char *)buf, (int32)len);
00569 
00570     if(writeLen != (int)len) {
00571        PR_Close(p12cxt->file);
00572        PR_Free(p12cxt->filename);
00573        p12cxt->filename = NULL;
00574        p12cxt->file = NULL;
00575        p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
00576        p12cxt->error = PR_TRUE;
00577     }
00578 }
00579 
00580 
00581 void
00582 P12U_ExportPKCS12Object(char *nn, char *outfile, PK11SlotInfo *inSlot,
00583                      secuPWData *slotPw, secuPWData *p12FilePw)
00584 {
00585     SEC_PKCS12ExportContext *p12ecx = NULL;
00586     SEC_PKCS12SafeInfo *keySafe = NULL, *certSafe = NULL;
00587     SECItem *pwitem = NULL;
00588     p12uContext *p12cxt = NULL;
00589     CERTCertList* certlist = NULL;
00590     CERTCertListNode* node = NULL;
00591     PK11SlotInfo* slot = NULL;
00592 
00593     if (P12U_InitSlot(inSlot, slotPw) != SECSuccess) {
00594        SECU_PrintError(progName,"Failed to authenticate to \"%s\"",
00595                        PK11_GetSlotName(inSlot));
00596        pk12uErrno = PK12UERR_PK11GETSLOT;
00597        goto loser;
00598     }
00599     certlist = PK11_FindCertsFromNickname(nn, slotPw);
00600     if(!certlist) {
00601        SECU_PrintError(progName,"find user certs from nickname failed");
00602        pk12uErrno = PK12UERR_FINDCERTBYNN;
00603        return;
00604     }
00605 
00606     if ((SECSuccess != CERT_FilterCertListForUserCerts(certlist)) ||
00607         CERT_LIST_EMPTY(certlist)) {
00608         SECU_PrintError(progName,"no user certs from given nickname");
00609         pk12uErrno = PK12UERR_FINDCERTBYNN;
00610         goto loser;
00611     }
00612 
00613     /* Password to use for PKCS12 file.  */
00614     pwitem = P12U_GetP12FilePassword(PR_TRUE, p12FilePw);
00615     if(!pwitem) {
00616        goto loser;
00617     }
00618 
00619     p12cxt = p12u_InitContext(PR_FALSE, outfile); 
00620     if(!p12cxt) {
00621        SECU_PrintError(progName,"Initialization failed: %s", outfile);
00622        pk12uErrno = PK12UERR_INIT_FILE;
00623        goto loser;
00624     }
00625 
00626     if (certlist) {
00627         CERTCertificate* cert = NULL;
00628         node = CERT_LIST_HEAD(certlist);
00629         if (node) {
00630             cert = node->cert;
00631         }
00632         if (cert) {
00633             slot = cert->slot; /* use the slot from the first matching
00634                 certificate to create the context . This is for keygen */
00635         }
00636     }
00637     if (!slot) {
00638         SECU_PrintError(progName,"cert does not have a slot");
00639         pk12uErrno = PK12UERR_FINDCERTBYNN;
00640         goto loser;
00641     }
00642     p12ecx = SEC_PKCS12CreateExportContext(NULL, NULL, slot, slotPw);
00643     if(!p12ecx) {
00644         SECU_PrintError(progName,"export context creation failed");
00645         pk12uErrno = PK12UERR_EXPORTCXCREATE;
00646         goto loser;
00647     }
00648 
00649     if(SEC_PKCS12AddPasswordIntegrity(p12ecx, pwitem, SEC_OID_SHA1)
00650        != SECSuccess) {
00651         SECU_PrintError(progName,"PKCS12 add password integrity failed");
00652         pk12uErrno = PK12UERR_PK12ADDPWDINTEG;
00653         goto loser;
00654     }
00655 
00656     for (node = CERT_LIST_HEAD(certlist);!CERT_LIST_END(node,certlist);node=CERT_LIST_NEXT(node))
00657     {
00658         CERTCertificate* cert = node->cert;
00659         if (!cert->slot) {
00660             SECU_PrintError(progName,"cert does not have a slot");
00661             pk12uErrno = PK12UERR_FINDCERTBYNN;
00662             goto loser;
00663         }
00664     
00665         keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx);
00666         if( PK11_IsFIPS()) {
00667             certSafe = keySafe;
00668         } else {
00669             certSafe = SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem,
00670                 SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC);
00671         }
00672     
00673         if(!certSafe || !keySafe) {
00674             SECU_PrintError(progName,"key or cert safe creation failed");
00675             pk12uErrno = PK12UERR_CERTKEYSAFE;
00676             goto loser;
00677         }
00678     
00679         if(SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert,
00680             CERT_GetDefaultCertDB(), keySafe, NULL, PR_TRUE, pwitem,
00681             SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC)
00682             != SECSuccess) {
00683                 SECU_PrintError(progName,"add cert and key failed");
00684                 pk12uErrno = PK12UERR_ADDCERTKEY;
00685                 goto loser;
00686         }
00687     }
00688 
00689     CERT_DestroyCertList(certlist);
00690     certlist = NULL;
00691 
00692     if(SEC_PKCS12Encode(p12ecx, p12u_WriteToExportFile, p12cxt)
00693                         != SECSuccess) {
00694         SECU_PrintError(progName,"PKCS12 encode failed");
00695         pk12uErrno = PK12UERR_ENCODE;
00696         goto loser;
00697     }
00698 
00699     p12u_DestroyContext(&p12cxt, PR_FALSE);
00700     SECITEM_ZfreeItem(pwitem, PR_TRUE);
00701     fprintf(stdout, "%s: PKCS12 EXPORT SUCCESSFUL\n", progName);
00702     SEC_PKCS12DestroyExportContext(p12ecx);
00703 
00704     return;
00705 
00706 loser:
00707     SEC_PKCS12DestroyExportContext(p12ecx);
00708 
00709     if (certlist) {
00710         CERT_DestroyCertList(certlist);
00711         certlist = NULL;
00712     }    
00713 
00714     p12u_DestroyContext(&p12cxt, PR_TRUE);
00715     if(pwitem) {
00716         SECITEM_ZfreeItem(pwitem, PR_TRUE);
00717     }
00718     p12u_DoPKCS12ExportErrors();
00719     return;
00720 }
00721 
00722 
00723 PRIntn
00724 P12U_ListPKCS12File(char *in_file, PK11SlotInfo *slot,
00725                      secuPWData *slotPw, secuPWData *p12FilePw)
00726 {
00727     SEC_PKCS12DecoderContext *p12dcx = NULL;
00728     SECItem uniPwitem = { 0 };
00729     SECStatus rv = SECFailure;
00730     const SEC_PKCS12DecoderItem *dip;
00731     int error;
00732 
00733     p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw,
00734                              p12FilePw);
00735     /* did the blob authenticate properly? */
00736     if(p12dcx == NULL) {
00737        SECU_PrintError(progName,"PKCS12 decode not verified");
00738        pk12uErrno = PK12UERR_DECODEVERIFY;
00739         goto loser;
00740     }
00741     rv = SEC_PKCS12DecoderIterateInit(p12dcx);
00742     if(rv != SECSuccess) {
00743        SECU_PrintError(progName,"PKCS12 decode iterate bags failed");
00744        pk12uErrno = PK12UERR_DECODEIMPTBAGS;
00745         rv = SECFailure;
00746     }
00747     else {
00748         while (SEC_PKCS12DecoderIterateNext(p12dcx, &dip) == SECSuccess) {
00749             switch (dip->type) {
00750                 case SEC_OID_PKCS12_V1_CERT_BAG_ID:
00751                     printf("Certificate");
00752                     if (SECU_PrintSignedData(stdout, dip->der,
00753                             (dip->hasKey) ? "(has private key)" : "",
00754                              0, SECU_PrintCertificate) != 0) {
00755                         SECU_PrintError(progName,"PKCS12 print cert bag failed");
00756                     }
00757                     if (dip->friendlyName != NULL) {
00758                         printf("    Friendly Name: %s\n\n",
00759                                 dip->friendlyName->data);
00760                     }
00761                     break;
00762                 case SEC_OID_PKCS12_V1_KEY_BAG_ID:
00763                 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
00764                     printf("Key");
00765                     if (dip->type == SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID)
00766                         printf("(shrouded)");
00767                     printf(":\n");
00768                     if (dip->friendlyName != NULL) {
00769                         printf("    Friendly Name: %s\n\n",
00770                                 dip->friendlyName->data);
00771                     }
00772                     break;
00773                 default:
00774                     printf("unknown bag type(%d): %s\n\n", dip->type,
00775                             SECOID_FindOIDTagDescription(dip->type));
00776                     break;
00777             }
00778         }
00779         rv = SECSuccess;
00780     }
00781 
00782 loser:
00783     
00784     if (p12dcx) {
00785        SEC_PKCS12DecoderFinish(p12dcx);
00786     }
00787     
00788     if (uniPwitem.data) {
00789        SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
00790     }
00791     
00792     return rv;
00793 }
00794 
00795 static void
00796 p12u_EnableAllCiphers()
00797 {
00798     SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1);
00799     SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1);
00800     SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
00801     SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1);
00802     SEC_PKCS12EnableCipher(PKCS12_DES_56, 1);
00803     SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
00804     SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);
00805 }
00806 
00807 static PRUintn
00808 P12U_Init(char *dir, char *dbprefix, PRBool listonly)
00809 {
00810     SECStatus rv;
00811     PK11_SetPasswordFunc(SECU_GetModulePassword);
00812 
00813     PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
00814     if (listonly && NSS_NoDB_Init("") == SECSuccess) {
00815         rv = SECSuccess;
00816     }
00817     else {
00818         rv = NSS_Initialize(dir,dbprefix,dbprefix,"secmod.db",0);
00819     }
00820     if (rv != SECSuccess) {
00821        SECU_PrintPRandOSError(progName);
00822         exit(-1);
00823     }
00824 
00825     /* setup unicode callback functions */
00826     PORT_SetUCS2_ASCIIConversionFunction(p12u_ucs2_ascii_conversion_function);
00827     /* use the defaults for UCS4-UTF8 and UCS2-UTF8 */
00828 
00829     p12u_EnableAllCiphers();
00830 
00831     return 0;
00832 }
00833 
00834 enum {
00835     opt_CertDir = 0,
00836     opt_TokenName,
00837     opt_Import,
00838     opt_SlotPWFile,
00839     opt_SlotPW,
00840     opt_List,
00841     opt_Nickname,
00842     opt_Export,
00843     opt_P12FilePWFile,
00844     opt_P12FilePW,
00845     opt_DBPrefix,
00846     opt_Debug
00847 };
00848 
00849 static secuCommandFlag pk12util_options[] =
00850 {
00851     { /* opt_CertDir        */ 'd', PR_TRUE,      0, PR_FALSE },
00852     { /* opt_TokenName             */ 'h', PR_TRUE,      0, PR_FALSE },
00853     { /* opt_Import         */ 'i', PR_TRUE,      0, PR_FALSE },
00854     { /* opt_SlotPWFile            */ 'k', PR_TRUE,      0, PR_FALSE },
00855     { /* opt_SlotPW         */ 'K', PR_TRUE,      0, PR_FALSE },
00856     { /* opt_List              */ 'l', PR_TRUE,  0, PR_FALSE },
00857     { /* opt_Nickname              */ 'n', PR_TRUE,      0, PR_FALSE },
00858     { /* opt_Export         */ 'o', PR_TRUE,      0, PR_FALSE },
00859     { /* opt_P12FilePWFile     */ 'w', PR_TRUE,   0, PR_FALSE },
00860     { /* opt_P12FilePW             */ 'W', PR_TRUE,      0, PR_FALSE },
00861     { /* opt_DBPrefix              */ 'P', PR_TRUE,      0, PR_FALSE },
00862     { /* opt_Debug          */ 'v', PR_FALSE, 0, PR_FALSE }
00863 };
00864 
00865 int
00866 main(int argc, char **argv)
00867 {
00868     secuPWData slotPw = { PW_NONE, NULL };
00869     secuPWData p12FilePw = { PW_NONE, NULL };
00870     PK11SlotInfo *slot;
00871     char *slotname = NULL;
00872     char *import_file = NULL;
00873     char *export_file = NULL;
00874     char *dbprefix = "";
00875     SECStatus rv;
00876 
00877     secuCommand pk12util;
00878     pk12util.numCommands = 0;
00879     pk12util.commands = 0;
00880     pk12util.numOptions = sizeof(pk12util_options) / sizeof(secuCommandFlag);
00881     pk12util.options = pk12util_options;
00882 
00883     progName = strrchr(argv[0], '/');
00884     progName = progName ? progName+1 : argv[0];
00885 
00886     rv = SECU_ParseCommandLine(argc, argv, progName, &pk12util);
00887 
00888     if (rv != SECSuccess)
00889        Usage(progName);
00890 
00891     pk12_debugging = pk12util.options[opt_Debug].activated;
00892 
00893     if ((pk12util.options[opt_Import].activated +
00894        pk12util.options[opt_Export].activated +
00895         pk12util.options[opt_List].activated) != 1) {
00896        Usage(progName);
00897     }
00898 
00899     if (pk12util.options[opt_Export].activated &&
00900        !pk12util.options[opt_Nickname].activated) {
00901        Usage(progName);
00902     }
00903 
00904     slotname = SECU_GetOptionArg(&pk12util, opt_TokenName);
00905 
00906     import_file = (pk12util.options[opt_List].activated) ?
00907                     SECU_GetOptionArg(&pk12util, opt_List) :
00908                     SECU_GetOptionArg(&pk12util, opt_Import);
00909     export_file = SECU_GetOptionArg(&pk12util, opt_Export);
00910 
00911     if (pk12util.options[opt_P12FilePWFile].activated) {
00912        p12FilePw.source = PW_FROMFILE;
00913        p12FilePw.data = PL_strdup(pk12util.options[opt_P12FilePWFile].arg);
00914     }
00915 
00916     if (pk12util.options[opt_P12FilePW].activated) {
00917        p12FilePw.source = PW_PLAINTEXT;
00918        p12FilePw.data = PL_strdup(pk12util.options[opt_P12FilePW].arg);
00919     }
00920 
00921     if (pk12util.options[opt_SlotPWFile].activated) {
00922        slotPw.source = PW_FROMFILE;
00923        slotPw.data = PL_strdup(pk12util.options[opt_SlotPWFile].arg);
00924     }
00925 
00926     if (pk12util.options[opt_SlotPW].activated) {
00927        slotPw.source = PW_PLAINTEXT;
00928        slotPw.data = PL_strdup(pk12util.options[opt_SlotPW].arg);
00929     }
00930 
00931     if (pk12util.options[opt_CertDir].activated) {
00932        SECU_ConfigDirectory(pk12util.options[opt_CertDir].arg);
00933     }
00934     if (pk12util.options[opt_DBPrefix].activated) {
00935        dbprefix = pk12util.options[opt_DBPrefix].arg;
00936     }
00937     P12U_Init(SECU_ConfigDirectory(NULL), dbprefix,
00938                 pk12util.options[opt_List].activated);
00939 
00940     if (!slotname || PL_strcmp(slotname, "internal") == 0)
00941        slot = PK11_GetInternalKeySlot();
00942     else
00943        slot = PK11_FindSlotByName(slotname);
00944 
00945     if (!slot) {
00946        SECU_PrintError(progName,"Invalid slot \"%s\"", slotname);
00947        pk12uErrno = PK12UERR_PK11GETSLOT;
00948        goto done;
00949     }
00950 
00951     if (pk12util.options[opt_Import].activated) {
00952        P12U_ImportPKCS12Object(import_file, slot, &slotPw,
00953                                       &p12FilePw);
00954 
00955     } else if (pk12util.options[opt_Export].activated) {
00956        P12U_ExportPKCS12Object(pk12util.options[opt_Nickname].arg,
00957                             export_file, slot, &slotPw, &p12FilePw);
00958         
00959     } else if (pk12util.options[opt_List].activated) {
00960        P12U_ListPKCS12File(import_file, slot, &slotPw, &p12FilePw);
00961                                            
00962     } else {
00963        Usage(progName);
00964        pk12uErrno = PK12UERR_USAGE;
00965     }
00966 
00967 done:
00968     if (slotPw.data != NULL)
00969        PORT_ZFree(slotPw.data, PL_strlen(slotPw.data));
00970     if (p12FilePw.data != NULL)
00971        PORT_ZFree(p12FilePw.data, PL_strlen(p12FilePw.data));
00972     if (slot) PK11_FreeSlot(slot);
00973     if (NSS_Shutdown() != SECSuccess) {
00974        pk12uErrno = 1;
00975     }
00976     return pk12uErrno;
00977 }