Back to index

lightning-sunbird  0.9+nobinonly
p12d.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  *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 
00039 #include "nssrenam.h"
00040 #include "p12t.h"
00041 #include "p12.h"
00042 #include "plarena.h"
00043 #include "secitem.h"
00044 #include "secoid.h"
00045 #include "seccomon.h"
00046 #include "secport.h"
00047 #include "cert.h"
00048 #include "secpkcs7.h"
00049 #include "secasn1.h"
00050 #include "secerr.h"
00051 #include "pk11func.h"
00052 #include "p12plcy.h"
00053 #include "p12local.h"
00054 #include "secder.h"
00055 #include "secport.h"
00056 
00057 #include "certdb.h"
00058 
00059 #include "prcpucfg.h"
00060 
00061 typedef struct sec_PKCS12SafeContentsContextStr sec_PKCS12SafeContentsContext;
00062 
00063 /* Opaque structure for decoding SafeContents.  These are used
00064  * for each authenticated safe as well as any nested safe contents.
00065  */
00066 struct sec_PKCS12SafeContentsContextStr {
00067     /* the parent decoder context */
00068     SEC_PKCS12DecoderContext *p12dcx;
00069 
00070     /* memory arena to allocate space from */
00071     PRArenaPool *arena;
00072 
00073     /* decoder context and destination for decoding safe contents */
00074     SEC_ASN1DecoderContext *safeContentsDcx;
00075     sec_PKCS12SafeContents safeContents;
00076 
00077     /* information for decoding safe bags within the safe contents.
00078      * these variables are updated for each safe bag decoded.
00079      */
00080     SEC_ASN1DecoderContext *currentSafeBagDcx;
00081     sec_PKCS12SafeBag *currentSafeBag;
00082     PRBool skipCurrentSafeBag;
00083 
00084     /* if the safe contents is nested, the parent is pointed to here. */
00085     sec_PKCS12SafeContentsContext *nestedCtx;
00086 };
00087 
00088 /* opaque decoder context structure.  information for decoding a pkcs 12
00089  * PDU are stored here as well as decoding pointers for intermediary 
00090  * structures which are part of the PKCS 12 PDU.  Upon a successful
00091  * decode, the safe bags containing certificates and keys encountered.
00092  */  
00093 struct SEC_PKCS12DecoderContextStr {
00094     PRArenaPool *arena;
00095     PK11SlotInfo *slot;
00096     void *wincx;
00097     PRBool error;
00098     int errorValue;
00099 
00100     /* password */
00101     SECItem *pwitem;
00102 
00103     /* used for decoding the PFX structure */
00104     SEC_ASN1DecoderContext *pfxDcx;
00105     sec_PKCS12PFXItem pfx;
00106 
00107     /* safe bags found during decoding */  
00108     sec_PKCS12SafeBag **safeBags;
00109     unsigned int safeBagCount;
00110 
00111     /* state variables for decoding authenticated safes. */
00112     SEC_PKCS7DecoderContext *currentASafeP7Dcx;
00113     SEC_ASN1DecoderContext *aSafeDcx;
00114     SEC_PKCS7DecoderContext *aSafeP7Dcx;
00115     sec_PKCS12AuthenticatedSafe authSafe;
00116     SEC_PKCS7ContentInfo *aSafeCinfo;
00117     sec_PKCS12SafeContents safeContents;
00118 
00119     /* safe contents info */
00120     unsigned int safeContentsCnt;
00121     sec_PKCS12SafeContentsContext **safeContentsList;
00122 
00123     /* HMAC info */
00124     sec_PKCS12MacData       macData;
00125     SEC_ASN1DecoderContext *hmacDcx;
00126 
00127     /* routines for reading back the data to be hmac'd */
00128     digestOpenFn dOpen;
00129     digestCloseFn dClose;
00130     digestIOFn dRead, dWrite;
00131     void *dArg;
00132 
00133     /* helper functions */
00134     SECKEYGetPasswordKey pwfn;
00135     void *pwfnarg;
00136     PRBool swapUnicodeBytes;
00137 
00138     /* import information */
00139     PRBool bagsVerified;
00140 
00141     /* buffer management for the default callbacks implementation */
00142     void        *buffer;      /* storage area */
00143     PRInt32     filesize;     /* actual data size */
00144     PRInt32     allocated;    /* total buffer size allocated */
00145     PRInt32     currentpos;   /* position counter */
00146     SECPKCS12TargetTokenCAs tokenCAs;
00147     sec_PKCS12SafeBag **keyList;/* used by ...IterateNext() */
00148     unsigned int iteration;
00149     SEC_PKCS12DecoderItem decitem;
00150 };
00151 
00152 
00153 /* make sure that the PFX version being decoded is a version
00154  * which we support.
00155  */
00156 static PRBool
00157 sec_pkcs12_proper_version(sec_PKCS12PFXItem *pfx)
00158 {
00159     /* if no version, assume it is not supported */
00160     if(pfx->version.len == 0) {
00161        return PR_FALSE;
00162     }
00163 
00164     if(DER_GetInteger(&pfx->version) > SEC_PKCS12_VERSION) {
00165        return PR_FALSE;
00166     }
00167 
00168     return PR_TRUE;
00169 }
00170 
00171 /* retrieve the key for decrypting the safe contents */ 
00172 static PK11SymKey *
00173 sec_pkcs12_decoder_get_decrypt_key(void *arg, SECAlgorithmID *algid)
00174 {
00175     SEC_PKCS12DecoderContext *p12dcx =
00176        (SEC_PKCS12DecoderContext *) arg;
00177     PK11SlotInfo *slot;
00178     PK11SymKey *bulkKey;
00179 
00180     if(!p12dcx) {
00181        return NULL;
00182     }
00183 
00184     /* if no slot specified, use the internal key slot */
00185     if(p12dcx->slot) {
00186        slot = PK11_ReferenceSlot(p12dcx->slot);
00187     } else {
00188        slot = PK11_GetInternalKeySlot();
00189     }
00190 
00191     bulkKey = PK11_PBEKeyGen(slot, algid, p12dcx->pwitem, 
00192                                           PR_FALSE, p12dcx->wincx);
00193     /* some tokens can't generate PBE keys on their own, generate the
00194      * key in the internal slot, and let the Import code deal with it,
00195      * (if the slot can't generate PBEs, then we need to use the internal
00196      * slot anyway to unwrap). */
00197     if (!bulkKey && !PK11_IsInternal(slot)) {
00198        PK11_FreeSlot(slot);
00199        slot = PK11_GetInternalKeySlot();
00200        bulkKey = PK11_PBEKeyGen(slot, algid, p12dcx->pwitem, 
00201                                           PR_FALSE, p12dcx->wincx);
00202     }
00203     PK11_FreeSlot(slot);
00204 
00205     /* set the password data on the key */
00206     if (bulkKey) {
00207         PK11_SetSymKeyUserData(bulkKey,p12dcx->pwitem, NULL);
00208     }
00209 
00210 
00211     return bulkKey;
00212 }
00213 
00214 /* XXX this needs to be modified to handle enveloped data.  most
00215  * likely, it should mirror the routines for SMIME in that regard.
00216  */
00217 static PRBool
00218 sec_pkcs12_decoder_decryption_allowed(SECAlgorithmID *algid, 
00219                                   PK11SymKey *bulkkey)
00220 {
00221     PRBool decryptionAllowed = SEC_PKCS12DecryptionAllowed(algid);
00222 
00223     if(!decryptionAllowed) {
00224        return PR_FALSE;
00225     }
00226 
00227     return PR_TRUE;
00228 }
00229 
00230 /* when we encounter a new safe bag during the decoding, we need
00231  * to allocate space for the bag to be decoded to and set the 
00232  * state variables appropriately.  all of the safe bags are allocated
00233  * in a buffer in the outer SEC_PKCS12DecoderContext, however,
00234  * a pointer to the safeBag is also used in the sec_PKCS12SafeContentsContext
00235  * for the current bag.
00236  */
00237 static SECStatus
00238 sec_pkcs12_decoder_init_new_safe_bag(sec_PKCS12SafeContentsContext 
00239                                           *safeContentsCtx)
00240 {
00241     void *mark = NULL;
00242     SEC_PKCS12DecoderContext *p12dcx;
00243 
00244     /* make sure that the structures are defined, and there has
00245      * not been an error in the decoding 
00246      */
00247     if(!safeContentsCtx || !safeContentsCtx->p12dcx 
00248               || safeContentsCtx->p12dcx->error) {
00249        return SECFailure;
00250     }
00251 
00252     p12dcx = safeContentsCtx->p12dcx;
00253     mark = PORT_ArenaMark(p12dcx->arena);
00254 
00255     /* allocate a new safe bag, if bags already exist, grow the 
00256      * list of bags, otherwise allocate a new list.  the list is
00257      * NULL terminated.
00258      */
00259     if(p12dcx->safeBagCount) {
00260        p12dcx->safeBags = 
00261            (sec_PKCS12SafeBag**)PORT_ArenaGrow(p12dcx->arena,p12dcx->safeBags,
00262                      (p12dcx->safeBagCount + 1) * sizeof(sec_PKCS12SafeBag *),
00263                      (p12dcx->safeBagCount + 2) * sizeof(sec_PKCS12SafeBag *));
00264     } else {
00265        p12dcx->safeBags = (sec_PKCS12SafeBag**)PORT_ArenaZAlloc(p12dcx->arena,
00266                                        2 * sizeof(sec_PKCS12SafeBag *));
00267     }
00268     if(!p12dcx->safeBags) {
00269        p12dcx->errorValue = SEC_ERROR_NO_MEMORY;
00270        goto loser;
00271     }
00272 
00273     /* append the bag to the end of the list and update the reference
00274      * in the safeContentsCtx.
00275      */
00276     p12dcx->safeBags[p12dcx->safeBagCount] = 
00277         (sec_PKCS12SafeBag*)PORT_ArenaZAlloc(p12dcx->arena,
00278                                         sizeof(sec_PKCS12SafeBag));
00279     safeContentsCtx->currentSafeBag = p12dcx->safeBags[p12dcx->safeBagCount];
00280     p12dcx->safeBags[++p12dcx->safeBagCount] = NULL;
00281     if(!safeContentsCtx->currentSafeBag) {
00282        p12dcx->errorValue = SEC_ERROR_NO_MEMORY;
00283        goto loser;
00284     }
00285 
00286     safeContentsCtx->currentSafeBag->slot = safeContentsCtx->p12dcx->slot;
00287     safeContentsCtx->currentSafeBag->pwitem = safeContentsCtx->p12dcx->pwitem;
00288     safeContentsCtx->currentSafeBag->swapUnicodeBytes = 
00289                             safeContentsCtx->p12dcx->swapUnicodeBytes;
00290     safeContentsCtx->currentSafeBag->arena = safeContentsCtx->p12dcx->arena;
00291     safeContentsCtx->currentSafeBag->tokenCAs = 
00292                             safeContentsCtx->p12dcx->tokenCAs;
00293 
00294     PORT_ArenaUnmark(p12dcx->arena, mark);
00295     return SECSuccess;
00296 
00297 loser:
00298 
00299     /* if an error occurred, release the memory and set the error flag
00300      * the only possible errors triggered by this function are memory 
00301      * related.
00302      */
00303     if(mark) {
00304        PORT_ArenaRelease(p12dcx->arena, mark);
00305     }
00306 
00307     p12dcx->error = PR_TRUE;
00308     return SECFailure;
00309 }
00310 
00311 /* A wrapper for updating the ASN1 context in which a safeBag is
00312  * being decoded.  This function is called as a callback from
00313  * secasn1d when decoding SafeContents structures.
00314  */
00315 static void
00316 sec_pkcs12_decoder_safe_bag_update(void *arg, const char *data, 
00317                                unsigned long len, int depth, 
00318                                SEC_ASN1EncodingPart data_kind)
00319 {
00320     sec_PKCS12SafeContentsContext *safeContentsCtx = 
00321         (sec_PKCS12SafeContentsContext *)arg;
00322     SEC_PKCS12DecoderContext *p12dcx;
00323     SECStatus rv;
00324 
00325     /* make sure that we are not skipping the current safeBag,
00326      * and that there are no errors.  If so, just return rather
00327      * than continuing to process.
00328      */
00329     if(!safeContentsCtx || !safeContentsCtx->p12dcx 
00330               || safeContentsCtx->p12dcx->error 
00331               || safeContentsCtx->skipCurrentSafeBag) {
00332        return;
00333     }
00334     p12dcx = safeContentsCtx->p12dcx;
00335 
00336     rv = SEC_ASN1DecoderUpdate(safeContentsCtx->currentSafeBagDcx, data, len);
00337     if(rv != SECSuccess) {
00338        p12dcx->errorValue = SEC_ERROR_NO_MEMORY;
00339        goto loser;
00340     }
00341 
00342     return;
00343 
00344 loser:
00345     /* set the error, and finish the decoder context.  because there 
00346      * is not a way of returning an error message, it may be worth
00347      * while to do a check higher up and finish any decoding contexts
00348      * that are still open.
00349      */
00350     p12dcx->error = PR_TRUE;
00351     SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagDcx);
00352     safeContentsCtx->currentSafeBagDcx = NULL;
00353     return;
00354 }
00355 
00356 /* forward declarations of functions that are used when decoding
00357  * safeContents bags which are nested and when decoding the 
00358  * authenticatedSafes.
00359  */
00360 static SECStatus
00361 sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext 
00362                                                  *safeContentsCtx);
00363 static SECStatus
00364 sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext
00365                                                  *safeContentsCtx);
00366 static void
00367 sec_pkcs12_decoder_safe_bag_update(void *arg, const char *data, 
00368                                unsigned long len, int depth, 
00369                                SEC_ASN1EncodingPart data_kind);
00370 
00371 /* notify function for decoding safeBags.  This function is
00372  * used to filter safeBag types which are not supported,
00373  * initiate the decoding of nested safe contents, and decode
00374  * safeBags in general.  this function is set when the decoder
00375  * context for the safeBag is first created.
00376  */
00377 static void
00378 sec_pkcs12_decoder_safe_bag_notify(void *arg, PRBool before,
00379                                void *dest, int real_depth)
00380 {
00381     sec_PKCS12SafeContentsContext *safeContentsCtx = 
00382         (sec_PKCS12SafeContentsContext *)arg;
00383     SEC_PKCS12DecoderContext *p12dcx;
00384     sec_PKCS12SafeBag *bag;
00385     PRBool after;
00386 
00387     /* if an error is encountered, return */
00388     if(!safeContentsCtx || !safeContentsCtx->p12dcx || 
00389               safeContentsCtx->p12dcx->error) {
00390        return;
00391     }
00392     p12dcx = safeContentsCtx->p12dcx;
00393 
00394     /* to make things more readable */
00395     if(before)
00396        after = PR_FALSE;
00397     else 
00398        after = PR_TRUE;
00399 
00400     /* have we determined the safeBagType yet? */
00401     bag = safeContentsCtx->currentSafeBag;
00402     if(bag->bagTypeTag == NULL) {
00403        if(after && (dest == &(bag->safeBagType))) {
00404            bag->bagTypeTag = SECOID_FindOID(&(bag->safeBagType));
00405            if(bag->bagTypeTag == NULL) {
00406               p12dcx->error = PR_TRUE;
00407               p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
00408            }
00409        }
00410        return;
00411     }
00412 
00413     /* process the safeBag depending on it's type.  those
00414      * which we do not support, are ignored.  we start a decoding
00415      * context for a nested safeContents.
00416      */
00417     switch(bag->bagTypeTag->offset) {
00418        case SEC_OID_PKCS12_V1_KEY_BAG_ID:
00419        case SEC_OID_PKCS12_V1_CERT_BAG_ID:
00420        case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
00421            break;
00422        case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID:
00423            /* if we are just starting to decode the safeContents, initialize
00424             * a new safeContentsCtx to process it.
00425             */
00426            if(before && (dest == &(bag->safeBagContent))) {
00427               sec_pkcs12_decoder_begin_nested_safe_contents(safeContentsCtx);
00428            } else if(after && (dest == &(bag->safeBagContent))) {
00429               /* clean up the nested decoding */
00430               sec_pkcs12_decoder_finish_nested_safe_contents(safeContentsCtx);
00431            }
00432            break;
00433        case SEC_OID_PKCS12_V1_CRL_BAG_ID:
00434        case SEC_OID_PKCS12_V1_SECRET_BAG_ID:
00435        default:
00436            /* skip any safe bag types we don't understand or handle */
00437            safeContentsCtx->skipCurrentSafeBag = PR_TRUE;
00438            break;
00439     }
00440 
00441     return;
00442 }
00443 
00444 /* notify function for decoding safe contents.  each entry in the
00445  * safe contents is a safeBag which needs to be allocated and
00446  * the decoding context initialized at the beginning and then
00447  * the context needs to be closed and finished at the end.
00448  *
00449  * this function is set when the safeContents decode context is
00450  * initialized.
00451  */
00452 static void
00453 sec_pkcs12_decoder_safe_contents_notify(void *arg, PRBool before,
00454                                    void *dest, int real_depth)
00455 {
00456     sec_PKCS12SafeContentsContext *safeContentsCtx = 
00457         (sec_PKCS12SafeContentsContext*)arg;
00458     SEC_PKCS12DecoderContext *p12dcx;
00459     SECStatus rv;
00460 
00461     /* if there is an error we don't want to continue processing,
00462      * just return and keep going.
00463      */
00464     if(!safeContentsCtx || !safeContentsCtx->p12dcx 
00465               || safeContentsCtx->p12dcx->error) {
00466        return;
00467     }
00468     p12dcx = safeContentsCtx->p12dcx;
00469 
00470     /* if we are done with the current safeBag, then we need to
00471      * finish the context and set the state variables appropriately.
00472      */
00473     if(!before) {
00474        SEC_ASN1DecoderClearFilterProc(safeContentsCtx->safeContentsDcx);
00475        SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagDcx);
00476        safeContentsCtx->currentSafeBagDcx = NULL;
00477        safeContentsCtx->skipCurrentSafeBag = PR_FALSE;
00478     } else {
00479        /* we are starting a new safe bag.  we need to allocate space
00480         * for the bag and initialize the decoding context.
00481         */
00482        rv = sec_pkcs12_decoder_init_new_safe_bag(safeContentsCtx);
00483        if(rv != SECSuccess) {
00484            goto loser;
00485        }
00486 
00487        /* set up the decoder context */
00488        safeContentsCtx->currentSafeBagDcx = SEC_ASN1DecoderStart(p12dcx->arena,
00489                                           safeContentsCtx->currentSafeBag,
00490                                           sec_PKCS12SafeBagTemplate);
00491        if(!safeContentsCtx->currentSafeBagDcx) {
00492            p12dcx->errorValue = SEC_ERROR_NO_MEMORY;
00493            goto loser;
00494        }
00495 
00496        /* set the notify and filter procs so that the safe bag
00497         * data gets sent to the proper location when decoding.
00498         */
00499        SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->currentSafeBagDcx, 
00500                              sec_pkcs12_decoder_safe_bag_notify, 
00501                              safeContentsCtx);
00502        SEC_ASN1DecoderSetFilterProc(safeContentsCtx->safeContentsDcx, 
00503                              sec_pkcs12_decoder_safe_bag_update, 
00504                              safeContentsCtx, PR_TRUE);
00505     }
00506 
00507     return;
00508 
00509 loser:
00510     /* in the event of an error, we want to close the decoding
00511      * context and clear the filter and notify procedures.
00512      */
00513     p12dcx->error = PR_TRUE;
00514 
00515     if(safeContentsCtx->currentSafeBagDcx) {
00516        SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagDcx);
00517        safeContentsCtx->currentSafeBagDcx = NULL;
00518     }
00519 
00520     SEC_ASN1DecoderClearNotifyProc(safeContentsCtx->safeContentsDcx);
00521     SEC_ASN1DecoderClearFilterProc(safeContentsCtx->safeContentsDcx);
00522 
00523     return;
00524 }
00525 
00526 /* initialize the safeContents for decoding.  this routine
00527  * is used for authenticatedSafes as well as nested safeContents.
00528  */
00529 static sec_PKCS12SafeContentsContext *
00530 sec_pkcs12_decoder_safe_contents_init_decode(SEC_PKCS12DecoderContext *p12dcx,
00531                                         PRBool nestedSafe)
00532 {
00533     sec_PKCS12SafeContentsContext *safeContentsCtx = NULL;
00534     const SEC_ASN1Template *theTemplate;
00535 
00536     if(!p12dcx || p12dcx->error) {
00537        return NULL;
00538     }
00539 
00540     /* allocate a new safeContents list or grow the existing list and
00541      * append the new safeContents onto the end.
00542      */
00543     if(!p12dcx->safeContentsCnt) {
00544        p12dcx->safeContentsList = 
00545            (sec_PKCS12SafeContentsContext**)PORT_ArenaZAlloc(p12dcx->arena, 
00546                                     2 * sizeof(sec_PKCS12SafeContentsContext *));
00547     } else {
00548        p12dcx->safeContentsList = 
00549           (sec_PKCS12SafeContentsContext **) PORT_ArenaGrow(p12dcx->arena,
00550                      p12dcx->safeContentsList,
00551                      (1 + p12dcx->safeContentsCnt) * 
00552                             sizeof(sec_PKCS12SafeContentsContext *),
00553                      (2 + p12dcx->safeContentsCnt) * 
00554                             sizeof(sec_PKCS12SafeContentsContext *));
00555     }
00556     if(!p12dcx->safeContentsList) {
00557        p12dcx->errorValue = SEC_ERROR_NO_MEMORY;
00558        goto loser;
00559     }
00560 
00561     p12dcx->safeContentsList[p12dcx->safeContentsCnt] = 
00562         (sec_PKCS12SafeContentsContext*)PORT_ArenaZAlloc(
00563                                    p12dcx->arena,
00564                                    sizeof(sec_PKCS12SafeContentsContext));
00565     p12dcx->safeContentsList[p12dcx->safeContentsCnt+1] = NULL;
00566     if(!p12dcx->safeContentsList[p12dcx->safeContentsCnt]) {
00567        p12dcx->errorValue = SEC_ERROR_NO_MEMORY;
00568        goto loser;
00569     }
00570 
00571     /* set up the state variables */
00572     safeContentsCtx = p12dcx->safeContentsList[p12dcx->safeContentsCnt];
00573     p12dcx->safeContentsCnt++;
00574     safeContentsCtx->p12dcx = p12dcx;
00575     safeContentsCtx->arena = p12dcx->arena;
00576 
00577     /* begin the decoding -- the template is based on whether we are
00578      * decoding a nested safeContents or not.
00579      */
00580     if(nestedSafe == PR_TRUE) {
00581        theTemplate = sec_PKCS12NestedSafeContentsDecodeTemplate;
00582     } else {
00583        theTemplate = sec_PKCS12SafeContentsDecodeTemplate;
00584     }
00585 
00586     /* start the decoder context */
00587     safeContentsCtx->safeContentsDcx = SEC_ASN1DecoderStart(p12dcx->arena, 
00588                                    &safeContentsCtx->safeContents,
00589                                    theTemplate);
00590        
00591     if(!safeContentsCtx->safeContentsDcx) {
00592        p12dcx->errorValue = SEC_ERROR_NO_MEMORY;
00593        goto loser;
00594     }
00595 
00596     /* set the safeContents notify procedure to look for
00597      * and start the decode of safeBags.
00598      */
00599     SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->safeContentsDcx, 
00600                             sec_pkcs12_decoder_safe_contents_notify,
00601                             safeContentsCtx);
00602 
00603     return safeContentsCtx;
00604 
00605 loser:
00606     /* in the case of an error, we want to finish the decoder
00607      * context and set the error flag.
00608      */
00609     if(safeContentsCtx && safeContentsCtx->safeContentsDcx) {
00610        SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsDcx);
00611        safeContentsCtx->safeContentsDcx = NULL;
00612     }
00613 
00614     p12dcx->error = PR_TRUE;
00615 
00616     return NULL;
00617 }
00618 
00619 /* wrapper for updating safeContents.  this is set as the filter of
00620  * safeBag when there is a nested safeContents.
00621  */
00622 static void
00623 sec_pkcs12_decoder_nested_safe_contents_update(void *arg, const char *buf,
00624                                      unsigned long len, int depth,
00625                                      SEC_ASN1EncodingPart data_kind)
00626 {
00627     sec_PKCS12SafeContentsContext *safeContentsCtx = 
00628         (sec_PKCS12SafeContentsContext *)arg;
00629     SEC_PKCS12DecoderContext *p12dcx;
00630     SECStatus rv;
00631 
00632     /* check for an error */
00633     if(!safeContentsCtx || !safeContentsCtx->p12dcx 
00634                      || safeContentsCtx->p12dcx->error) {
00635        return;
00636     }
00637 
00638     /* no need to update if no data sent in */
00639     if(!len || !buf) {
00640        return;
00641     }
00642 
00643     /* update the decoding context */
00644     p12dcx = safeContentsCtx->p12dcx;
00645     rv = SEC_ASN1DecoderUpdate(safeContentsCtx->safeContentsDcx, buf, len);
00646     if(rv != SECSuccess) {
00647        p12dcx->errorValue = SEC_ERROR_NO_MEMORY;
00648        goto loser;
00649     }
00650 
00651     return;
00652 
00653 loser:
00654     /* handle any errors.  If a decoding context is open, close it. */
00655     p12dcx->error = PR_TRUE;
00656     if(safeContentsCtx->safeContentsDcx) {
00657        SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsDcx);
00658        safeContentsCtx->safeContentsDcx = NULL;
00659     }
00660 }
00661 
00662 /* whenever a new safeContentsSafeBag is encountered, we need
00663  * to init a safeContentsContext.  
00664  */
00665 static SECStatus  
00666 sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext 
00667                                                  *safeContentsCtx)
00668 {
00669     /* check for an error */
00670     if(!safeContentsCtx || !safeContentsCtx->p12dcx || 
00671               safeContentsCtx->p12dcx->error) {
00672        return SECFailure;
00673     }
00674 
00675     safeContentsCtx->nestedCtx = sec_pkcs12_decoder_safe_contents_init_decode(
00676                                           safeContentsCtx->p12dcx,
00677                                           PR_TRUE);
00678     if(!safeContentsCtx->nestedCtx) {
00679        return SECFailure;
00680     }
00681 
00682     /* set up new filter proc */
00683     SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->nestedCtx->safeContentsDcx,
00684                              sec_pkcs12_decoder_safe_contents_notify,
00685                              safeContentsCtx->nestedCtx);
00686     SEC_ASN1DecoderSetFilterProc(safeContentsCtx->currentSafeBagDcx,
00687                              sec_pkcs12_decoder_nested_safe_contents_update,
00688                              safeContentsCtx->nestedCtx, PR_TRUE);
00689 
00690     return SECSuccess;
00691 }
00692 
00693 /* when the safeContents is done decoding, we need to reset the
00694  * proper filter and notify procs and close the decoding context 
00695  */
00696 static SECStatus
00697 sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext
00698                                                  *safeContentsCtx)
00699 {
00700     /* check for error */
00701     if(!safeContentsCtx || !safeContentsCtx->p12dcx || 
00702               safeContentsCtx->p12dcx->error) {
00703        return SECFailure;
00704     }
00705 
00706     /* clean up */   
00707     SEC_ASN1DecoderClearFilterProc(safeContentsCtx->currentSafeBagDcx);
00708     SEC_ASN1DecoderClearNotifyProc(safeContentsCtx->nestedCtx->safeContentsDcx);
00709     SEC_ASN1DecoderFinish(safeContentsCtx->nestedCtx->safeContentsDcx);
00710     safeContentsCtx->nestedCtx->safeContentsDcx = NULL;
00711     safeContentsCtx->nestedCtx = NULL;
00712 
00713     return SECSuccess;
00714 }
00715 
00716 /* wrapper for updating safeContents.  This is used when decoding
00717  * the nested safeContents and any authenticatedSafes.
00718  */
00719 static void
00720 sec_pkcs12_decoder_safe_contents_callback(void *arg, const char *buf,
00721                                      unsigned long len)
00722 {
00723     SECStatus rv;
00724     sec_PKCS12SafeContentsContext *safeContentsCtx = 
00725         (sec_PKCS12SafeContentsContext *)arg;
00726     SEC_PKCS12DecoderContext *p12dcx;
00727 
00728     /* check for error */  
00729     if(!safeContentsCtx || !safeContentsCtx->p12dcx 
00730               || safeContentsCtx->p12dcx->error) {
00731        return;
00732     }
00733     p12dcx = safeContentsCtx->p12dcx;
00734 
00735     /* update the decoder */
00736     rv = SEC_ASN1DecoderUpdate(safeContentsCtx->safeContentsDcx, buf, len);
00737     if(rv != SECSuccess) {
00738        /* if we fail while trying to decode a 'safe', it's probably because
00739         * we didn't have the correct password. */
00740        PORT_SetError(SEC_ERROR_BAD_PASSWORD);
00741        p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
00742        SEC_PKCS7DecoderAbort(p12dcx->currentASafeP7Dcx,SEC_ERROR_BAD_PASSWORD);
00743        goto loser;
00744     }
00745 
00746     return;
00747 
00748 loser:
00749     /* set the error and finish the context */
00750     p12dcx->error = PR_TRUE;
00751     if(safeContentsCtx->safeContentsDcx) {
00752        SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsDcx);
00753        safeContentsCtx->safeContentsDcx = NULL;
00754     }
00755 
00756     return;
00757 }
00758 
00759 /* this is a wrapper for the ASN1 decoder to call SEC_PKCS7DecoderUpdate
00760  */
00761 static void
00762 sec_pkcs12_decoder_wrap_p7_update(void *arg, const char *data,
00763                               unsigned long len, int depth,
00764                               SEC_ASN1EncodingPart data_kind)
00765 {
00766     SEC_PKCS7DecoderContext *p7dcx = (SEC_PKCS7DecoderContext *)arg;
00767 
00768     SEC_PKCS7DecoderUpdate(p7dcx, data, len);
00769 }
00770 
00771 /* notify function for decoding aSafes.  at the beginning,
00772  * of an authenticatedSafe, we start a decode of a safeContents.
00773  * at the end, we clean up the safeContents decoder context and
00774  * reset state variables 
00775  */
00776 static void
00777 sec_pkcs12_decoder_asafes_notify(void *arg, PRBool before, void *dest, 
00778                             int real_depth)
00779 {
00780     SEC_PKCS12DecoderContext *p12dcx;
00781     sec_PKCS12SafeContentsContext *safeContentsCtx;
00782 
00783     /* make sure no error occurred. */
00784     p12dcx = (SEC_PKCS12DecoderContext *)arg;
00785     if(!p12dcx || p12dcx->error) {
00786        return;
00787     }
00788 
00789     if(before) {
00790 
00791        /* init a new safeContentsContext */
00792        safeContentsCtx = sec_pkcs12_decoder_safe_contents_init_decode(p12dcx, 
00793                                                         PR_FALSE);
00794        if(!safeContentsCtx) {
00795            goto loser;
00796        }
00797 
00798        /* initiate the PKCS7ContentInfo decode */
00799        p12dcx->currentASafeP7Dcx = SEC_PKCS7DecoderStart(
00800                             sec_pkcs12_decoder_safe_contents_callback,
00801                             safeContentsCtx, 
00802                             p12dcx->pwfn, p12dcx->pwfnarg,
00803                             sec_pkcs12_decoder_get_decrypt_key, p12dcx,
00804                             sec_pkcs12_decoder_decryption_allowed);
00805        if(!p12dcx->currentASafeP7Dcx) {
00806            p12dcx->errorValue = PORT_GetError();
00807            goto loser;
00808        }
00809        SEC_ASN1DecoderSetFilterProc(p12dcx->aSafeDcx, 
00810                                  sec_pkcs12_decoder_wrap_p7_update,
00811                                  p12dcx->currentASafeP7Dcx, PR_TRUE);
00812     }
00813 
00814     if(!before) {
00815        /* if one is being decoded, finish the decode */
00816        if(p12dcx->currentASafeP7Dcx != NULL) {
00817            if(!SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx)) {
00818               p12dcx->currentASafeP7Dcx = NULL;
00819               p12dcx->errorValue = PORT_GetError();
00820               goto loser;
00821            }
00822            p12dcx->currentASafeP7Dcx = NULL;
00823        }
00824        p12dcx->currentASafeP7Dcx = NULL;
00825     }
00826 
00827 
00828     return;
00829 
00830 loser:
00831     /* set the error flag */
00832     p12dcx->error = PR_TRUE;
00833     return;
00834 }
00835 
00836 /* wrapper for updating asafes decoding context.  this function
00837  * writes data being decoded to disk, so that a mac can be computed
00838  * later.  
00839  */
00840 static void
00841 sec_pkcs12_decoder_asafes_callback(void *arg, const char *buf, 
00842                               unsigned long len)
00843 {
00844     SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg;
00845     SECStatus rv;
00846 
00847     if(!p12dcx || p12dcx->error) {
00848        return;
00849     }
00850 
00851     /* update the context */
00852     rv = SEC_ASN1DecoderUpdate(p12dcx->aSafeDcx, buf, len);
00853     if(rv != SECSuccess) {
00854        p12dcx->error = (PRBool)SEC_ERROR_NO_MEMORY;
00855        goto loser;
00856     }
00857 
00858     /* if we are writing to a file, write out the new information */
00859     if(p12dcx->dWrite) {
00860        unsigned long writeLen = (*p12dcx->dWrite)(p12dcx->dArg,       
00861                                              (unsigned char *)buf, len);
00862        if(writeLen != len) {
00863            p12dcx->errorValue = PORT_GetError();
00864            goto loser;
00865        }
00866     }
00867 
00868     return;
00869 
00870 loser:
00871     /* set the error flag */
00872     p12dcx->error = PR_TRUE;
00873     SEC_ASN1DecoderFinish(p12dcx->aSafeDcx);
00874     p12dcx->aSafeDcx = NULL;
00875 
00876     return;
00877 }
00878    
00879 /* start the decode of an authenticatedSafe contentInfo.
00880  */ 
00881 static SECStatus
00882 sec_pkcs12_decode_start_asafes_cinfo(SEC_PKCS12DecoderContext *p12dcx)
00883 {
00884     if(!p12dcx || p12dcx->error) {
00885        return SECFailure;
00886     }
00887 
00888     /* start the decode context */
00889     p12dcx->aSafeDcx = SEC_ASN1DecoderStart(p12dcx->arena, 
00890                                    &p12dcx->authSafe,
00891                                    sec_PKCS12AuthenticatedSafeTemplate);
00892     if(!p12dcx->aSafeDcx) {
00893        p12dcx->errorValue = SEC_ERROR_NO_MEMORY;
00894        goto loser;
00895     }
00896 
00897     /* set the notify function */
00898     SEC_ASN1DecoderSetNotifyProc(p12dcx->aSafeDcx,
00899                              sec_pkcs12_decoder_asafes_notify, p12dcx);
00900 
00901     /* begin the authSafe decoder context */
00902     p12dcx->aSafeP7Dcx = SEC_PKCS7DecoderStart(
00903                             sec_pkcs12_decoder_asafes_callback, p12dcx,
00904                             p12dcx->pwfn, p12dcx->pwfnarg, NULL, NULL, NULL);
00905     if(!p12dcx->aSafeP7Dcx) {
00906        p12dcx->errorValue = SEC_ERROR_NO_MEMORY;
00907        goto loser;
00908     }
00909   
00910     /* open the temp file for writing, if the filter functions were set */ 
00911     if(p12dcx->dOpen && (*p12dcx->dOpen)(p12dcx->dArg, PR_FALSE) 
00912                             != SECSuccess) {
00913        p12dcx->errorValue = PORT_GetError();
00914        goto loser;
00915     }
00916 
00917     return SECSuccess;
00918 
00919 loser:
00920     p12dcx->error = PR_TRUE;
00921 
00922     if(p12dcx->aSafeDcx) {
00923        SEC_ASN1DecoderFinish(p12dcx->aSafeDcx);
00924        p12dcx->aSafeDcx = NULL;
00925     } 
00926 
00927     if(p12dcx->aSafeP7Dcx) {
00928        SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
00929        p12dcx->aSafeP7Dcx = NULL;
00930     }
00931 
00932     return SECFailure;
00933 }
00934 
00935 /* wrapper for updating the safeContents.  this function is used as
00936  * a filter for the pfx when decoding the authenticated safes 
00937  */
00938 static void 
00939 sec_pkcs12_decode_asafes_cinfo_update(void *arg, const char *buf,
00940                                   unsigned long len, int depth,
00941                                   SEC_ASN1EncodingPart data_kind)
00942 {
00943     SEC_PKCS12DecoderContext *p12dcx;
00944     SECStatus rv;
00945 
00946     p12dcx = (SEC_PKCS12DecoderContext*)arg;
00947     if(!p12dcx || p12dcx->error) {
00948        return;
00949     }
00950 
00951     /* update the safeContents decoder */
00952     rv = SEC_PKCS7DecoderUpdate(p12dcx->aSafeP7Dcx, buf, len);
00953     if(rv != SECSuccess) {
00954        p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
00955        goto loser;
00956     }
00957 
00958     return;
00959 
00960 loser:
00961 
00962     /* did we find an error?  if so, close the context and set the 
00963      * error flag.
00964      */
00965     SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
00966     p12dcx->aSafeP7Dcx = NULL;
00967     p12dcx->error = PR_TRUE;
00968 }
00969 
00970 /* notify procedure used while decoding the pfx.  When we encounter
00971  * the authSafes, we want to trigger the decoding of authSafes as well
00972  * as when we encounter the macData, trigger the decoding of it.  we do
00973  * this because we we are streaming the decoder and not decoding in place.
00974  * the pfx which is the destination, only has the version decoded into it.
00975  */
00976 static void 
00977 sec_pkcs12_decoder_pfx_notify_proc(void *arg, PRBool before, void *dest,
00978                                int real_depth)
00979 {
00980     SECStatus rv;
00981     SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext*)arg;
00982 
00983     /* if an error occurrs, clear the notifyProc and the filterProc 
00984      * and continue. 
00985      */
00986     if(p12dcx->error) {
00987        SEC_ASN1DecoderClearNotifyProc(p12dcx->pfxDcx);
00988        SEC_ASN1DecoderClearFilterProc(p12dcx->pfxDcx);
00989        return;
00990     }
00991 
00992     if(before && (dest == &p12dcx->pfx.encodedAuthSafe)) {
00993 
00994        /* we want to make sure this is a version we support */
00995        if(!sec_pkcs12_proper_version(&p12dcx->pfx)) {
00996            p12dcx->errorValue = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION;
00997            goto loser;
00998        }
00999 
01000        /* start the decode of the aSafes cinfo... */
01001        rv = sec_pkcs12_decode_start_asafes_cinfo(p12dcx);
01002        if(rv != SECSuccess) {
01003            goto loser;
01004        }
01005 
01006        /* set the filter proc to update the authenticated safes. */
01007        SEC_ASN1DecoderSetFilterProc(p12dcx->pfxDcx,
01008                                  sec_pkcs12_decode_asafes_cinfo_update,
01009                                  p12dcx, PR_TRUE);
01010     }
01011 
01012     if(!before && (dest == &p12dcx->pfx.encodedAuthSafe)) {
01013 
01014        /* we are done decoding the authenticatedSafes, so we need to 
01015         * finish the decoderContext and clear the filter proc
01016         * and close the hmac callback, if present
01017         */
01018        p12dcx->aSafeCinfo = SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
01019        p12dcx->aSafeP7Dcx = NULL;
01020        if(!p12dcx->aSafeCinfo) {
01021            p12dcx->errorValue = PORT_GetError();
01022            goto loser;
01023        }
01024        SEC_ASN1DecoderClearFilterProc(p12dcx->pfxDcx);
01025        if(p12dcx->dClose && ((*p12dcx->dClose)(p12dcx->dArg, PR_FALSE) 
01026                             != SECSuccess)) {
01027            p12dcx->errorValue = PORT_GetError();
01028            goto loser;
01029        }
01030 
01031     }
01032 
01033     return;
01034 
01035 loser:
01036     p12dcx->error = PR_TRUE;
01037 }
01038 
01039 /*  default implementations of the open/close/read/write functions for
01040     SEC_PKCS12DecoderStart 
01041 */
01042 
01043 #define DEFAULT_TEMP_SIZE 4096
01044 
01045 static SECStatus
01046 p12u_DigestOpen(void *arg, PRBool readData)
01047 {
01048     SEC_PKCS12DecoderContext* p12cxt = arg;
01049 
01050     p12cxt->currentpos = 0;
01051 
01052     if (PR_FALSE == readData) {
01053         /* allocate an initial buffer */
01054         p12cxt->filesize = 0;
01055         p12cxt->allocated = DEFAULT_TEMP_SIZE;
01056         p12cxt->buffer = PORT_Alloc(DEFAULT_TEMP_SIZE);
01057         PR_ASSERT(p12cxt->buffer);
01058     }
01059     else
01060     {
01061         PR_ASSERT(p12cxt->buffer);
01062         if (!p12cxt->buffer) {
01063             return SECFailure; /* no data to read */
01064         }
01065     }
01066 
01067     return SECSuccess;
01068 }
01069 
01070 static SECStatus
01071 p12u_DigestClose(void *arg, PRBool removeFile)
01072 {
01073     SEC_PKCS12DecoderContext* p12cxt = arg;
01074 
01075     PR_ASSERT(p12cxt);
01076     if (!p12cxt) {
01077         return SECFailure;
01078     }
01079     p12cxt->currentpos = 0;
01080 
01081     if (PR_TRUE == removeFile) {
01082         PR_ASSERT(p12cxt->buffer);
01083         if (!p12cxt->buffer) {
01084             return SECFailure;
01085         }
01086         if (p12cxt->buffer) {
01087             PORT_Free(p12cxt->buffer);
01088             p12cxt->buffer = NULL;
01089             p12cxt->allocated = 0;
01090             p12cxt->filesize = 0;
01091         }
01092     }
01093 
01094     return SECSuccess;
01095 }
01096 
01097 static int
01098 p12u_DigestRead(void *arg, unsigned char *buf, unsigned long len)
01099 {
01100     int toread = len;
01101     SEC_PKCS12DecoderContext* p12cxt = arg;
01102 
01103     if(!buf || len == 0 || !p12cxt->buffer) {
01104        PORT_SetError(SEC_ERROR_INVALID_ARGS);
01105        return -1;
01106     }
01107 
01108     if ((p12cxt->filesize - p12cxt->currentpos) < (long)len) {
01109         /* trying to read past the end of the buffer */
01110         toread = p12cxt->filesize - p12cxt->currentpos;
01111     }
01112     memcpy(buf, (char*)p12cxt->buffer + p12cxt->currentpos, toread);
01113     p12cxt->currentpos += toread;
01114     return toread;
01115 }
01116 
01117 static int
01118 p12u_DigestWrite(void *arg, unsigned char *buf, unsigned long len)
01119 {
01120     SEC_PKCS12DecoderContext* p12cxt = arg;
01121 
01122     if(!buf || len == 0) {
01123         return -1;
01124     }
01125 
01126     if (p12cxt->currentpos+(long)len > p12cxt->filesize) {
01127         p12cxt->filesize = p12cxt->currentpos + len;
01128     }
01129     else {
01130         p12cxt->filesize += len;
01131     }
01132     if (p12cxt->filesize > p12cxt->allocated) {
01133         void* newbuffer;
01134         size_t newsize = p12cxt->filesize + DEFAULT_TEMP_SIZE;
01135         newbuffer  = PORT_Realloc(p12cxt->buffer, newsize);
01136         if (NULL == newbuffer) {
01137             return -1; /* can't extend the buffer */
01138         }
01139         p12cxt->buffer = newbuffer;
01140         p12cxt->allocated = newsize;
01141     }
01142     PR_ASSERT(p12cxt->buffer);
01143     memcpy((char*)p12cxt->buffer + p12cxt->currentpos, buf, len);
01144     p12cxt->currentpos += len;
01145     return len;
01146 }
01147 
01148 /* SEC_PKCS12DecoderStart
01149  *     Creates a decoder context for decoding a PKCS 12 PDU objct.
01150  *     This function sets up the initial decoding context for the
01151  *     PFX and sets the needed state variables.
01152  *
01153  *     pwitem - the password for the hMac and any encoded safes.
01154  *             this should be changed to take a callback which retrieves
01155  *             the password.  it may be possible for different safes to
01156  *             have different passwords.  also, the password is already
01157  *             in unicode.  it should probably be converted down below via
01158  *             a unicode conversion callback.
01159  *     slot - the slot to import the dataa into should multiple slots 
01160  *             be supported based on key type and cert type?
01161  *     dOpen, dClose, dRead, dWrite - digest routines for writing data
01162  *             to a file so it could be read back and the hmack recomputed
01163  *             and verified.  doesn't seem to be away for both encoding
01164  *             and decoding to be single pass, thus the need for these
01165  *             routines.
01166  *     dArg - the argument for dOpen, etc.
01167  *
01168  *      if NULL == dOpen == dClose == dRead == dWrite == dArg, then default
01169  *      implementations using a memory buffer are used
01170  *
01171  *     This function returns the decoder context, if it was successful.
01172  *     Otherwise, null is returned.
01173  */
01174 SEC_PKCS12DecoderContext *
01175 SEC_PKCS12DecoderStart(SECItem *pwitem, PK11SlotInfo *slot, void *wincx,
01176                      digestOpenFn dOpen, digestCloseFn dClose, 
01177                      digestIOFn dRead, digestIOFn dWrite, void *dArg)
01178 {
01179     SEC_PKCS12DecoderContext *p12dcx;
01180     PRArenaPool *arena;
01181 
01182     arena = PORT_NewArena(2048); /* different size? */
01183     if(!arena) {
01184        PORT_SetError(SEC_ERROR_NO_MEMORY);
01185        return NULL;
01186     }
01187 
01188     /* allocate the decoder context and set the state variables */
01189     p12dcx = (SEC_PKCS12DecoderContext*)PORT_ArenaZAlloc(arena, sizeof(SEC_PKCS12DecoderContext));
01190     if(!p12dcx) {
01191        PORT_SetError(SEC_ERROR_NO_MEMORY);
01192        goto loser;
01193     }
01194 
01195     if (!dOpen && !dClose && !dRead && !dWrite && !dArg) {
01196         /* use default implementations */
01197         dOpen = p12u_DigestOpen;
01198         dClose = p12u_DigestClose;
01199         dRead = p12u_DigestRead;
01200         dWrite = p12u_DigestWrite;
01201         dArg = (void*)p12dcx;
01202     }
01203 
01204     p12dcx->arena = arena;
01205     p12dcx->pwitem = pwitem;
01206     p12dcx->slot = (slot ? PK11_ReferenceSlot(slot) 
01207                                           : PK11_GetInternalKeySlot());
01208     p12dcx->wincx = wincx;
01209     p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs;
01210 #ifdef IS_LITTLE_ENDIAN
01211     p12dcx->swapUnicodeBytes = PR_TRUE;
01212 #else
01213     p12dcx->swapUnicodeBytes = PR_FALSE;
01214 #endif
01215     p12dcx->errorValue = 0;
01216     p12dcx->error = PR_FALSE;
01217 
01218     /* start the decoding of the PFX and set the notify proc
01219      * for the PFX item.
01220      */
01221     p12dcx->pfxDcx = SEC_ASN1DecoderStart(p12dcx->arena, &p12dcx->pfx,
01222                                      sec_PKCS12PFXItemTemplate);
01223     if(!p12dcx->pfxDcx) {
01224        PORT_SetError(SEC_ERROR_NO_MEMORY); 
01225        PK11_FreeSlot(p12dcx->slot);
01226        goto loser;
01227     }
01228 
01229     SEC_ASN1DecoderSetNotifyProc(p12dcx->pfxDcx, 
01230                              sec_pkcs12_decoder_pfx_notify_proc,
01231                              p12dcx); 
01232     
01233     /* set up digest functions */
01234     p12dcx->dOpen = dOpen;
01235     p12dcx->dWrite = dWrite;
01236     p12dcx->dClose = dClose;
01237     p12dcx->dRead = dRead;
01238     p12dcx->dArg = dArg;
01239     
01240     p12dcx->keyList = NULL;
01241     p12dcx->decitem.type = 0;
01242     p12dcx->decitem.der = NULL;
01243     p12dcx->decitem.hasKey = PR_FALSE;
01244     p12dcx->decitem.friendlyName = NULL;
01245     p12dcx->iteration = 0;
01246 
01247     return p12dcx;
01248 
01249 loser:
01250     PORT_FreeArena(arena, PR_TRUE);
01251     return NULL;
01252 }
01253 
01254 SECStatus
01255 SEC_PKCS12DecoderSetTargetTokenCAs(SEC_PKCS12DecoderContext *p12dcx,
01256               SECPKCS12TargetTokenCAs tokenCAs)
01257 {
01258     if (!p12dcx || p12dcx->error) {
01259        return SECFailure;
01260     }
01261     p12dcx->tokenCAs = tokenCAs;
01262     return SECSuccess;
01263 }
01264 
01265 
01266 /* SEC_PKCS12DecoderUpdate 
01267  *     Streaming update sending more data to the decoder.  If 
01268  *     an error occurs, SECFailure is returned.
01269  *
01270  *     p12dcx - the decoder context 
01271  *     data, len - the data buffer and length of data to send to 
01272  *            the update functions.
01273  */
01274 SECStatus
01275 SEC_PKCS12DecoderUpdate(SEC_PKCS12DecoderContext *p12dcx,
01276                      unsigned char *data, unsigned long len)
01277 {
01278     SECStatus rv;
01279 
01280     if(!p12dcx || p12dcx->error) {
01281        return SECFailure;
01282     }
01283 
01284     /* update the PFX decoder context */
01285     rv = SEC_ASN1DecoderUpdate(p12dcx->pfxDcx, (const char *)data, len);
01286     if(rv != SECSuccess) {
01287        p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
01288        goto loser;
01289     }
01290 
01291     return SECSuccess;
01292 
01293 loser:
01294 
01295     p12dcx->error = PR_TRUE;
01296     return SECFailure;
01297 }
01298 
01299 /* This should be a nice sized buffer for reading in data (potentially large 
01300 ** amounts) to be MACed.  It should be MUCH larger than HASH_LENGTH_MAX.
01301 */
01302 #define IN_BUF_LEN   1024
01303 #ifdef DEBUG
01304 static const char bufferEnd[] = { "BufferEnd" } ;
01305 #endif
01306 #define FUDGE 128 /* must be as large as bufferEnd or more. */
01307 
01308 /* verify the hmac by reading the data from the temporary file
01309  * using the routines specified when the decodingContext was 
01310  * created and return SECSuccess if the hmac matches.
01311  */
01312 static SECStatus
01313 sec_pkcs12_decoder_verify_mac(SEC_PKCS12DecoderContext *p12dcx)
01314 {
01315     PK11Context *     pk11cx = NULL;
01316     PK11SymKey *      symKey = NULL;
01317     SECItem *         params = NULL;
01318     unsigned char *   buf;
01319     SECStatus         rv     = SECFailure;
01320     SECStatus         lrv;
01321     unsigned int      bufLen;
01322     int               iteration;
01323     int               bytesRead;
01324     SECOidTag         algtag;
01325     SECItem           hmacRes;
01326     SECItem           ignore = {0};
01327     CK_MECHANISM_TYPE integrityMech;
01328     
01329     if(!p12dcx || p12dcx->error) {
01330        PORT_SetError(SEC_ERROR_INVALID_ARGS);
01331        return SECFailure;
01332     }
01333     buf = (unsigned char *)PORT_Alloc(IN_BUF_LEN + FUDGE);
01334     if (!buf)
01335        return SECFailure;  /* error code has been set. */
01336 
01337 #ifdef DEBUG
01338     memcpy(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd);
01339 #endif
01340 
01341     /* generate hmac key */
01342     if(p12dcx->macData.iter.data) {
01343        iteration = (int)DER_GetInteger(&p12dcx->macData.iter);
01344     } else {
01345        iteration = 1;
01346     }
01347 
01348     params = PK11_CreatePBEParams(&p12dcx->macData.macSalt, p12dcx->pwitem,
01349                                   iteration);
01350 
01351     algtag = SECOID_GetAlgorithmTag(&p12dcx->macData.safeMac.digestAlgorithm);
01352     switch (algtag) {
01353     case SEC_OID_SHA1:
01354        integrityMech = CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN; break;
01355     case SEC_OID_MD5:
01356        integrityMech = CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN;  break;
01357     case SEC_OID_MD2:
01358        integrityMech = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN;  break;
01359     default:
01360        goto loser;
01361     }
01362 
01363     symKey = PK11_KeyGen(NULL, integrityMech, params, 20, NULL);
01364     PK11_DestroyPBEParams(params);
01365     params = NULL;
01366     if (!symKey) goto loser;
01367     /* init hmac */
01368     pk11cx = PK11_CreateContextBySymKey(sec_pkcs12_algtag_to_mech(algtag),
01369                                         CKA_SIGN, symKey, &ignore);
01370     if(!pk11cx) {
01371        goto loser;
01372     }
01373     lrv = PK11_DigestBegin(pk11cx);
01374     if (lrv == SECFailure ) {
01375        goto loser;
01376     }
01377 
01378     /* try to open the data for readback */
01379     if(p12dcx->dOpen && ((*p12dcx->dOpen)(p12dcx->dArg, PR_TRUE) 
01380                      != SECSuccess)) {
01381        goto loser;
01382     }
01383 
01384     /* read the data back IN_BUF_LEN bytes at a time and recompute
01385      * the hmac.  if fewer bytes are read than are requested, it is
01386      * assumed that the end of file has been reached. if bytesRead
01387      * is returned as -1, then an error occured reading from the 
01388      * file.
01389      */
01390     do {
01391        bytesRead = (*p12dcx->dRead)(p12dcx->dArg, buf, IN_BUF_LEN);
01392        if (bytesRead < 0) {
01393            PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_READ);
01394            goto loser;
01395        }
01396        PORT_Assert(bytesRead <= IN_BUF_LEN);
01397        PORT_Assert(!memcmp(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd));
01398 
01399        if (bytesRead > IN_BUF_LEN) {
01400            /* dRead callback overflowed buffer. */
01401            PORT_SetError(SEC_ERROR_INPUT_LEN);
01402            goto loser;
01403        }
01404 
01405        if (bytesRead) {
01406            lrv = PK11_DigestOp(pk11cx, buf, bytesRead);
01407            if (lrv == SECFailure) {
01408               goto loser;
01409            }
01410        }
01411     } while (bytesRead == IN_BUF_LEN);
01412 
01413     /* finish the hmac context */
01414     lrv = PK11_DigestFinal(pk11cx, buf, &bufLen, IN_BUF_LEN);
01415     if (lrv == SECFailure ) {
01416        goto loser;
01417     }
01418 
01419     hmacRes.data = buf;
01420     hmacRes.len = bufLen;
01421 
01422     /* is the hmac computed the same as the hmac which was decoded? */
01423     rv = SECSuccess;
01424     if(SECITEM_CompareItem(&hmacRes, &p12dcx->macData.safeMac.digest) 
01425                      != SECEqual) {
01426        PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
01427        rv = SECFailure;
01428     }
01429 
01430 loser:
01431     /* close the file and remove it */
01432     if(p12dcx->dClose) {
01433        (*p12dcx->dClose)(p12dcx->dArg, PR_TRUE);
01434     }
01435 
01436     if(pk11cx) {
01437        PK11_DestroyContext(pk11cx, PR_TRUE);
01438     }
01439     if (params) {
01440        PK11_DestroyPBEParams(params);
01441     }
01442     if (symKey) {
01443        PK11_FreeSymKey(symKey);
01444     }
01445     PORT_ZFree(buf, IN_BUF_LEN + FUDGE);
01446 
01447     return rv;
01448 }
01449 
01450 /* SEC_PKCS12DecoderVerify
01451  *     Verify the macData or the signature of the decoded PKCS 12 PDU.
01452  *     If the signature or the macData do not match, SECFailure is
01453  *     returned.
01454  *
01455  *     p12dcx - the decoder context 
01456  */
01457 SECStatus
01458 SEC_PKCS12DecoderVerify(SEC_PKCS12DecoderContext *p12dcx)
01459 {
01460     SECStatus rv = SECSuccess;
01461 
01462     /* make sure that no errors have occured... */
01463     if(!p12dcx || p12dcx->error) {
01464        return SECFailure;
01465     }
01466 
01467     rv = SEC_ASN1DecoderFinish(p12dcx->pfxDcx);
01468     p12dcx->pfxDcx = NULL;
01469     if(rv != SECSuccess) {
01470        return rv;
01471     }
01472 
01473     /* check the signature or the mac depending on the type of
01474      * integrity used.
01475      */
01476     if(p12dcx->pfx.encodedMacData.len) {
01477        rv = SEC_ASN1DecodeItem(p12dcx->arena, &p12dcx->macData,
01478                             sec_PKCS12MacDataTemplate,
01479                             &p12dcx->pfx.encodedMacData);
01480        if(rv == SECSuccess) {
01481            return sec_pkcs12_decoder_verify_mac(p12dcx);
01482        } else {
01483            PORT_SetError(SEC_ERROR_NO_MEMORY);
01484        }
01485     } else {
01486        if(SEC_PKCS7VerifySignature(p12dcx->aSafeCinfo, certUsageEmailSigner,
01487                                 PR_FALSE)) {
01488            return SECSuccess;
01489        } else {
01490            PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
01491        }
01492     }
01493 
01494     return SECFailure;
01495 }
01496 
01497 /* SEC_PKCS12DecoderFinish
01498  *     Free any open ASN1 or PKCS7 decoder contexts and then
01499  *     free the arena pool which everything should be allocated
01500  *     from.  This function should be called upon completion of
01501  *     decoding and installing of a pfx pdu.  This should be
01502  *     called even if an error occurs.
01503  *
01504  *     p12dcx - the decoder context
01505  */
01506 void
01507 SEC_PKCS12DecoderFinish(SEC_PKCS12DecoderContext *p12dcx)
01508 {
01509     if(!p12dcx) {
01510        return;
01511     }
01512 
01513     if(p12dcx->pfxDcx) {
01514        SEC_ASN1DecoderFinish(p12dcx->pfxDcx);
01515        p12dcx->pfxDcx = NULL;
01516     }
01517 
01518     if(p12dcx->aSafeDcx) {
01519        SEC_ASN1DecoderFinish(p12dcx->aSafeDcx);
01520        p12dcx->aSafeDcx = NULL;
01521     }
01522 
01523     if(p12dcx->currentASafeP7Dcx) {
01524        SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx);
01525        p12dcx->currentASafeP7Dcx = NULL;
01526     }
01527 
01528     if(p12dcx->aSafeP7Dcx) {
01529        SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
01530     }
01531 
01532     if(p12dcx->hmacDcx) {
01533        SEC_ASN1DecoderFinish(p12dcx->hmacDcx);
01534        p12dcx->hmacDcx = NULL;
01535     }
01536     
01537     if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
01538         SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
01539     }
01540     if (p12dcx->decitem.friendlyName != NULL) {
01541         SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
01542     }
01543 
01544     if(p12dcx->slot) {
01545        PK11_FreeSlot(p12dcx->slot);
01546        p12dcx->slot = NULL;
01547     }
01548 
01549     if(p12dcx->arena) {
01550        PORT_FreeArena(p12dcx->arena, PR_TRUE);
01551     }
01552 }
01553 
01554 static SECStatus
01555 sec_pkcs12_decoder_set_attribute_value(sec_PKCS12SafeBag *bag,
01556                             SECOidTag attributeType,
01557                             SECItem *attrValue)
01558 {
01559     int i = 0;
01560     SECOidData *oid;
01561 
01562     if(!bag || !attrValue) {
01563        return SECFailure;
01564     }
01565 
01566     oid = SECOID_FindOIDByTag(attributeType);
01567     if(!oid) {
01568        PORT_SetError(SEC_ERROR_NO_MEMORY);
01569        return SECFailure;
01570     }
01571 
01572     if(!bag->attribs) {
01573        bag->attribs = (sec_PKCS12Attribute**)PORT_ArenaZAlloc(bag->arena, 
01574                                    sizeof(sec_PKCS12Attribute *) * 2);
01575     } else {
01576        while(bag->attribs[i]) i++;
01577        bag->attribs = (sec_PKCS12Attribute **)PORT_ArenaGrow(bag->arena, 
01578                                   bag->attribs, 
01579                                   (i + 1) * sizeof(sec_PKCS12Attribute *),
01580                                   (i + 2) * sizeof(sec_PKCS12Attribute *));
01581     }
01582 
01583     if(!bag->attribs) {
01584        PORT_SetError(SEC_ERROR_NO_MEMORY);
01585        return SECFailure;
01586     }
01587 
01588     bag->attribs[i] = (sec_PKCS12Attribute*)PORT_ArenaZAlloc(bag->arena, 
01589                                             sizeof(sec_PKCS12Attribute));
01590     if(!bag->attribs) {
01591        PORT_SetError(SEC_ERROR_NO_MEMORY);
01592        return SECFailure;
01593     }
01594 
01595     bag->attribs[i]->attrValue = (SECItem**)PORT_ArenaZAlloc(bag->arena, 
01596                                             sizeof(SECItem *) * 2);
01597     if(!bag->attribs[i]->attrValue) {
01598        PORT_SetError(SEC_ERROR_NO_MEMORY);
01599        return SECFailure;
01600     }
01601 
01602     bag->attribs[i+1] = NULL;
01603     bag->attribs[i]->attrValue[0] = attrValue;
01604     bag->attribs[i]->attrValue[1] = NULL;
01605 
01606     if(SECITEM_CopyItem(bag->arena, &bag->attribs[i]->attrType, &oid->oid)
01607                      != SECSuccess) {
01608        PORT_SetError(SEC_ERROR_NO_MEMORY);
01609        return SECFailure;
01610     }
01611 
01612     return SECSuccess;
01613 }
01614 
01615 static SECItem *
01616 sec_pkcs12_get_attribute_value(sec_PKCS12SafeBag *bag,
01617                             SECOidTag attributeType)
01618 {
01619     int i = 0;
01620 
01621     if(!bag->attribs) {
01622        return NULL;
01623     }
01624 
01625     while(bag->attribs[i] != NULL) {
01626        if(SECOID_FindOIDTag(&bag->attribs[i]->attrType) 
01627                      == attributeType) {
01628            return bag->attribs[i]->attrValue[0];
01629        }
01630        i++;
01631     }
01632 
01633     return NULL;
01634 }
01635 
01636 /* For now, this function will merely remove any ":"
01637  * in the nickname which the PK11 functions may have
01638  * placed there.  This will keep dual certs from appearing
01639  * twice under "Your" certificates when imported onto smart
01640  * cards.  Once with the name "Slot:Cert" and another with
01641  * the nickname "Slot:Slot:Cert"
01642  */
01643 static void
01644 sec_pkcs12_sanitize_nickname(PK11SlotInfo *slot, SECItem *nick)
01645 {
01646     char *nickname;
01647     char *delimit;
01648     int delimitlen;
01649  
01650     nickname = (char*)nick->data; /*Mac breaks without this type cast*/
01651     if ((delimit = PORT_Strchr(nickname, ':')) != NULL) {
01652         char *slotName;
01653        int slotNameLen;
01654 
01655        slotNameLen = delimit-nickname;
01656        slotName = PORT_NewArray(char, (slotNameLen+1));
01657        PORT_Assert(slotName);
01658        if (slotName == NULL) {
01659          /* What else can we do?*/
01660          return;
01661        }
01662        PORT_Memcpy(slotName, nickname, slotNameLen);
01663        slotName[slotNameLen] = '\0';
01664        if (PORT_Strcmp(PK11_GetTokenName(slot), slotName) == 0) {
01665          delimitlen = PORT_Strlen(delimit+1);
01666          PORT_Memmove(nickname, delimit+1, delimitlen+1);
01667          nick->len = delimitlen;
01668        }
01669        PORT_Free(slotName);
01670     }
01671  
01672 }
01673 
01674 static SECItem *
01675 sec_pkcs12_get_nickname(sec_PKCS12SafeBag *bag)
01676 {
01677     SECItem *src, *dest;
01678 
01679     if(!bag) {
01680        bag->problem = PR_TRUE;
01681        bag->error = SEC_ERROR_NO_MEMORY;
01682        return NULL;
01683     }
01684 
01685     src = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME);
01686     if(!src) {
01687        return NULL;
01688     }
01689 
01690     dest = (SECItem*)PORT_ZAlloc(sizeof(SECItem));
01691     if(!dest) { 
01692        goto loser;
01693     }
01694     if(!sec_pkcs12_convert_item_to_unicode(NULL, dest, src, PR_FALSE, 
01695                             PR_FALSE, PR_FALSE)) {
01696        goto loser;
01697     }
01698 
01699     sec_pkcs12_sanitize_nickname(bag->slot, dest);
01700 
01701     return dest;
01702 
01703 loser:
01704     if(dest) {
01705        SECITEM_ZfreeItem(dest, PR_TRUE);
01706     }
01707 
01708     bag->problem = PR_TRUE;
01709     bag->error = PORT_GetError();
01710     return NULL;
01711 }
01712 
01713 static SECStatus
01714 sec_pkcs12_set_nickname(sec_PKCS12SafeBag *bag, SECItem *name)
01715 {
01716     int i = 0;
01717     sec_PKCS12Attribute *attr = NULL;
01718     SECOidData *oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_FRIENDLY_NAME);
01719 
01720     if(!bag || !bag->arena || !name) {
01721        return SECFailure;
01722     }
01723        
01724     if(!bag->attribs) {
01725        if(!oid) {
01726            goto loser;
01727        }
01728 
01729        bag->attribs = (sec_PKCS12Attribute**)PORT_ArenaZAlloc(bag->arena, 
01730                                         sizeof(sec_PKCS12Attribute *)*2);
01731        if(!bag->attribs) {
01732            goto loser;
01733        }
01734        bag->attribs[0] = (sec_PKCS12Attribute*)PORT_ArenaZAlloc(bag->arena, 
01735                                             sizeof(sec_PKCS12Attribute));
01736        if(!bag->attribs[0]) {
01737            goto loser;
01738        }
01739        bag->attribs[1] = NULL;
01740 
01741        attr = bag->attribs[0];
01742        if(SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid) 
01743                      != SECSuccess) {
01744            goto loser;
01745        }
01746     } else {
01747        while(bag->attribs[i]) {
01748            if(SECOID_FindOIDTag(&bag->attribs[i]->attrType)
01749                      == SEC_OID_PKCS9_FRIENDLY_NAME) {
01750               attr = bag->attribs[i];
01751               goto have_attrib;
01752               
01753            }
01754            i++;
01755        }
01756        if(!attr) {
01757            bag->attribs = (sec_PKCS12Attribute **)PORT_ArenaGrow(bag->arena, 
01758                                                           bag->attribs,
01759                                    (i+1) * sizeof(sec_PKCS12Attribute *),
01760                                    (i+2) * sizeof(sec_PKCS12Attribute *));
01761            if(!bag->attribs) {
01762               goto loser;
01763            }
01764            bag->attribs[i] = 
01765                (sec_PKCS12Attribute *)PORT_ArenaZAlloc(bag->arena, 
01766                                             sizeof(sec_PKCS12Attribute));
01767            if(!bag->attribs[i]) {
01768               goto loser;
01769            }
01770            bag->attribs[i+1] = NULL;
01771            attr = bag->attribs[i];
01772            if(SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid) 
01773                             != SECSuccess) {
01774               goto loser;
01775            }
01776        }
01777     }
01778 have_attrib:
01779     PORT_Assert(attr);
01780     if(!attr->attrValue) {
01781        attr->attrValue = (SECItem **)PORT_ArenaZAlloc(bag->arena, 
01782                                                  sizeof(SECItem *) * 2);
01783        if(!attr->attrValue) {
01784            goto loser;
01785        }
01786        attr->attrValue[0] = (SECItem*)PORT_ArenaZAlloc(bag->arena, 
01787                                                  sizeof(SECItem));
01788        if(!attr->attrValue[0]) {
01789            goto loser;
01790        }
01791        attr->attrValue[1] = NULL;
01792     }
01793 
01794     name->len = PORT_Strlen((char *)name->data);
01795     if(!sec_pkcs12_convert_item_to_unicode(bag->arena, attr->attrValue[0],
01796                             name, PR_FALSE, PR_FALSE, PR_TRUE)) {
01797        goto loser;
01798     }
01799 
01800     return SECSuccess;
01801 
01802 loser:
01803     bag->problem = PR_TRUE;
01804     bag->error = SEC_ERROR_NO_MEMORY;
01805     return SECFailure;
01806 }
01807        
01808 static SECStatus
01809 sec_pkcs12_get_key_info(sec_PKCS12SafeBag *key) 
01810 {
01811     int i = 0;
01812     SECKEYPrivateKeyInfo *pki = NULL;
01813 
01814     if(!key) {
01815        return SECFailure;
01816     }
01817 
01818     /* if the bag does *not* contain an unencrypted PrivateKeyInfo 
01819      * then we cannot convert the attributes.  We are propagating
01820      * attributes within the PrivateKeyInfo to the SafeBag level.
01821      */
01822     if(SECOID_FindOIDTag(&(key->safeBagType)) != 
01823                      SEC_OID_PKCS12_V1_KEY_BAG_ID) {
01824        return SECSuccess;
01825     }
01826 
01827     pki = key->safeBagContent.pkcs8KeyBag;
01828 
01829     if(!pki || !pki->attributes) {
01830        return SECSuccess;
01831     }
01832 
01833     while(pki->attributes[i]) {
01834        SECItem *attrValue = NULL;
01835 
01836        if(SECOID_FindOIDTag(&pki->attributes[i]->attrType) == 
01837                      SEC_OID_PKCS9_LOCAL_KEY_ID) {
01838            attrValue = sec_pkcs12_get_attribute_value(key, 
01839                                            SEC_OID_PKCS9_LOCAL_KEY_ID);
01840            if(!attrValue) {
01841               if(sec_pkcs12_decoder_set_attribute_value(key, 
01842                                    SEC_OID_PKCS9_LOCAL_KEY_ID,
01843                                    pki->attributes[i]->attrValue[0])
01844                                    != SECSuccess) {
01845                   key->problem = PR_TRUE;
01846                   key->error = SEC_ERROR_NO_MEMORY;
01847                   return SECFailure;
01848               }
01849            }
01850        }
01851 
01852        if(SECOID_FindOIDTag(&pki->attributes[i]->attrType) == 
01853                      SEC_OID_PKCS9_FRIENDLY_NAME) {
01854            attrValue = sec_pkcs12_get_attribute_value(key, 
01855                                           SEC_OID_PKCS9_FRIENDLY_NAME);
01856            if(!attrValue) {
01857               if(sec_pkcs12_decoder_set_attribute_value(key, 
01858                                    SEC_OID_PKCS9_FRIENDLY_NAME,
01859                                    pki->attributes[i]->attrValue[0])
01860                                    != SECSuccess) {
01861                   key->problem = PR_TRUE;
01862                   key->error = SEC_ERROR_NO_MEMORY;
01863                   return SECFailure;
01864               }
01865            }
01866        }
01867 
01868        i++;
01869     }
01870 
01871     return SECSuccess;
01872 }
01873 
01874 /* retrieve the nickname for the certificate bag.  first look
01875  * in the cert bag, otherwise get it from the key.
01876  */
01877 static SECItem *
01878 sec_pkcs12_get_nickname_for_cert(sec_PKCS12SafeBag *cert,
01879                              sec_PKCS12SafeBag *key, 
01880                              void *wincx)
01881 {
01882     SECItem *nickname;
01883 
01884     if(!cert) {
01885        return NULL;
01886     }
01887 
01888     nickname = sec_pkcs12_get_nickname(cert);
01889     if(nickname) {
01890        return nickname;
01891     }
01892 
01893     if(key) {
01894        nickname = sec_pkcs12_get_nickname(key);
01895        
01896         if(nickname && sec_pkcs12_set_nickname(cert, nickname)
01897                      != SECSuccess) {
01898            cert->error = SEC_ERROR_NO_MEMORY;
01899            cert->problem = PR_TRUE;
01900            if(nickname) { 
01901               SECITEM_ZfreeItem(nickname, PR_TRUE);
01902            }
01903            return NULL;
01904        }
01905     }
01906 
01907     return nickname;
01908 }
01909 
01910 /* set the nickname for the certificate */
01911 static SECStatus
01912 sec_pkcs12_set_nickname_for_cert(sec_PKCS12SafeBag *cert, 
01913                              sec_PKCS12SafeBag *key, 
01914                              SECItem *nickname, 
01915                              void *wincx)
01916 {
01917     if(!nickname || !cert) {
01918        return SECFailure;
01919     }
01920 
01921     if(sec_pkcs12_set_nickname(cert, nickname) != SECSuccess) {
01922        cert->error = SEC_ERROR_NO_MEMORY;
01923        cert->problem = PR_TRUE;
01924        return SECFailure;
01925     }
01926 
01927     if(key) {
01928        if(sec_pkcs12_set_nickname(key, nickname) != SECSuccess) {
01929            cert->error = SEC_ERROR_NO_MEMORY;
01930            cert->problem = PR_TRUE;
01931            return SECFailure;
01932        }
01933     }
01934 
01935     return SECSuccess;
01936 }
01937 
01938 /* retrieve the DER cert from the cert bag */
01939 static SECItem *
01940 sec_pkcs12_get_der_cert(sec_PKCS12SafeBag *cert) 
01941 {
01942     if(!cert) {
01943        return NULL;
01944     }
01945 
01946     if(SECOID_FindOIDTag(&cert->safeBagType) != SEC_OID_PKCS12_V1_CERT_BAG_ID) {
01947        return NULL;
01948     }
01949 
01950     /* only support X509 certs not SDSI */
01951     if(SECOID_FindOIDTag(&cert->safeBagContent.certBag->bagID) 
01952                      != SEC_OID_PKCS9_X509_CERT) {
01953        return NULL;
01954     }
01955                      
01956     return SECITEM_DupItem(&(cert->safeBagContent.certBag->value.x509Cert));
01957 }
01958 
01959 struct certNickInfo {
01960     PRArenaPool *arena;
01961     unsigned int nNicks;
01962     SECItem **nickList;
01963     unsigned int error;
01964 };
01965 
01966 /* callback for traversing certificates to gather the nicknames 
01967  * used in a particular traversal.  for instance, when using
01968  * CERT_TraversePermCertsForSubject, gather the nicknames and
01969  * store them in the certNickInfo for a particular DN.
01970  * 
01971  * this handles the case where multiple nicknames are allowed
01972  * for the same dn, which is not currently allowed, but may be
01973  * in the future.
01974  */ 
01975 static SECStatus
01976 gatherNicknames(CERTCertificate *cert, void *arg)
01977 {
01978     struct certNickInfo *nickArg = (struct certNickInfo *)arg;
01979     SECItem tempNick;
01980     unsigned int i;
01981 
01982     if(!cert || !nickArg || nickArg->error) {
01983        return SECFailure;
01984     }
01985 
01986     if(!cert->nickname) {
01987        return SECSuccess;
01988     }
01989 
01990     tempNick.data = (unsigned char *)cert->nickname;
01991     tempNick.len = PORT_Strlen(cert->nickname) + 1;
01992 
01993     /* do we already have the nickname in the list? */
01994     if(nickArg->nNicks > 0) {
01995 
01996        /* nicknames have been encountered, but there is no list -- bad */
01997        if(!nickArg->nickList) {
01998            nickArg->error = SEC_ERROR_NO_MEMORY;
01999            return SECFailure;
02000        }
02001 
02002        for(i = 0; i < nickArg->nNicks; i++) {
02003            if(SECITEM_CompareItem(nickArg->nickList[i], &tempNick) 
02004                             == SECEqual) {
02005               return SECSuccess;
02006            }
02007        }
02008     }
02009 
02010     /* add the nickname to the list */
02011     if(nickArg->nNicks == 0) {
02012        nickArg->nickList = (SECItem **)PORT_ArenaZAlloc(nickArg->arena, 
02013                                         2 * sizeof(SECItem *));
02014     } else {
02015        nickArg->nickList = (SECItem **)PORT_ArenaGrow(nickArg->arena,
02016                             nickArg->nickList, 
02017                             (nickArg->nNicks + 1) * sizeof(SECItem *),
02018                             (nickArg->nNicks + 2) * sizeof(SECItem *));
02019     }
02020     if(!nickArg->nickList) {
02021        nickArg->error = SEC_ERROR_NO_MEMORY;
02022        return SECFailure;
02023     }
02024 
02025     nickArg->nickList[nickArg->nNicks] = 
02026         (SECItem *)PORT_ArenaZAlloc(nickArg->arena, sizeof(SECItem));
02027     if(!nickArg->nickList[nickArg->nNicks]) {
02028        nickArg->error = SEC_ERROR_NO_MEMORY;
02029        return SECFailure;
02030     }
02031     
02032 
02033     if(SECITEM_CopyItem(nickArg->arena, nickArg->nickList[nickArg->nNicks],
02034                      &tempNick) != SECSuccess) {
02035        nickArg->error = SEC_ERROR_NO_MEMORY;
02036        return SECFailure;
02037     }
02038 
02039     nickArg->nNicks++;
02040 
02041     return SECSuccess;
02042 }
02043 
02044 /* traverses the certs in the data base or in the token for the
02045  * DN to see if any certs currently have a nickname set.
02046  * If so, return it. 
02047  */
02048 static SECItem *
02049 sec_pkcs12_get_existing_nick_for_dn(sec_PKCS12SafeBag *cert, void *wincx)
02050 {
02051     struct certNickInfo *nickArg = NULL;
02052     SECItem *derCert, *returnDn = NULL;
02053     PRArenaPool *arena = NULL;
02054     CERTCertificate *tempCert;
02055 
02056     if(!cert) {
02057        return NULL;
02058     }
02059 
02060     derCert = sec_pkcs12_get_der_cert(cert);
02061     if(!derCert) {
02062        return NULL;
02063     }
02064 
02065     tempCert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
02066     if(!tempCert) {
02067        returnDn = NULL;
02068        goto loser;
02069     }
02070 
02071     arena = PORT_NewArena(1024);
02072     if(!arena) {
02073        returnDn = NULL;
02074        goto loser;
02075     }
02076     nickArg = (struct certNickInfo *)PORT_ArenaZAlloc(arena, 
02077                                            sizeof(struct certNickInfo));
02078     if(!nickArg) {
02079        returnDn = NULL;
02080        goto loser;
02081     }
02082     nickArg->error = 0;
02083     nickArg->nNicks = 0;
02084     nickArg->nickList = NULL;
02085     nickArg->arena = arena;
02086 
02087     /* if the token is local, first traverse the cert database 
02088      * then traverse the token.
02089      */
02090     if(PK11_TraverseCertsForSubjectInSlot(tempCert, cert->slot, gatherNicknames,
02091                      (void *)nickArg) != SECSuccess) {
02092        returnDn = NULL;
02093        goto loser;
02094     }
02095 
02096     if(nickArg->error) {
02097        /* XXX do we want to set the error? */
02098        returnDn = NULL;
02099        goto loser;
02100     }
02101               
02102     if(nickArg->nNicks == 0) {
02103        returnDn = NULL;
02104        goto loser;
02105     }
02106 
02107     /* set it to the first name, for now.  handle multiple names? */
02108     returnDn = SECITEM_DupItem(nickArg->nickList[0]);
02109 
02110 loser:
02111     if(arena) {
02112        PORT_FreeArena(arena, PR_TRUE);
02113     }
02114 
02115     if(tempCert) {
02116        CERT_DestroyCertificate(tempCert);
02117     }
02118 
02119     if(derCert) {
02120        SECITEM_FreeItem(derCert, PR_TRUE);
02121     }
02122 
02123     return (returnDn);
02124 }
02125 
02126 /* counts certificates found for a given traversal function */
02127 static SECStatus
02128 countCertificate(CERTCertificate *cert, void *arg)
02129 {
02130     unsigned int *nCerts = (unsigned int *)arg;
02131 
02132     if(!cert || !arg) {
02133        return SECFailure;
02134     }
02135 
02136     (*nCerts)++;
02137     return SECSuccess;
02138 }
02139 
02140 static PRBool
02141 sec_pkcs12_certs_for_nickname_exist(SECItem *nickname, PK11SlotInfo *slot)
02142 {
02143     unsigned int nCerts = 0;
02144 
02145     if(!nickname || !slot) {
02146        return PR_TRUE;
02147     }
02148 
02149     /* we want to check the local database first if we are importing to it */
02150     PK11_TraverseCertsForNicknameInSlot(nickname, slot, countCertificate, 
02151                                    (void *)&nCerts);
02152     if(nCerts) return PR_TRUE;
02153 
02154     return PR_FALSE;
02155 }
02156 
02157 /* validate cert nickname such that there is a one-to-one relation
02158  * between nicknames and dn's.  we want to enforce the case that the
02159  * nickname is non-NULL and that there is only one nickname per DN.
02160  * 
02161  * if there is a problem with a nickname or the nickname is not present, 
02162  * the user will be prompted for it.
02163  */
02164 static void
02165 sec_pkcs12_validate_cert_nickname(sec_PKCS12SafeBag *cert,
02166                             sec_PKCS12SafeBag *key,
02167                             SEC_PKCS12NicknameCollisionCallback nicknameCb,
02168                             void *wincx)
02169 {
02170     SECItem *certNickname, *existingDNNick;
02171     PRBool setNickname = PR_FALSE, cancel = PR_FALSE;
02172     SECItem *newNickname = NULL;
02173 
02174     if(!cert || !cert->hasKey) {
02175        return;
02176     }
02177 
02178     if(!nicknameCb) {
02179        cert->problem = PR_TRUE;
02180        cert->error = SEC_ERROR_NO_MEMORY;
02181        return;
02182     }
02183 
02184     if(cert->hasKey && !key) {
02185        cert->problem = PR_TRUE;
02186        cert->error = SEC_ERROR_NO_MEMORY;
02187        return;
02188     }
02189 
02190     certNickname = sec_pkcs12_get_nickname_for_cert(cert, key, wincx);
02191     existingDNNick = sec_pkcs12_get_existing_nick_for_dn(cert, wincx);
02192 
02193     /* nickname is already used w/ this dn, so it is safe to return */
02194     if(certNickname && existingDNNick &&
02195               SECITEM_CompareItem(certNickname, existingDNNick) == SECEqual) {
02196        goto loser;
02197     }
02198 
02199     /* nickname not set in pkcs 12 bags, but a nick is already used for
02200      * this dn.  set the nicks in the p12 bags and finish.
02201      */
02202     if(existingDNNick) {
02203        if(sec_pkcs12_set_nickname_for_cert(cert, key, existingDNNick, wincx)
02204                      != SECSuccess) {
02205            cert->problem = PR_TRUE;
02206            cert->error = SEC_ERROR_NO_MEMORY;
02207        }
02208        goto loser;
02209     }
02210 
02211     /* at this point, we have a certificate for which the DN is not located
02212      * on the token.  the nickname specified may or may not be NULL.  if it
02213      * is not null, we need to make sure that there are no other certificates
02214      * with this nickname in the token for it to be valid.  this imposes a 
02215      * one to one relationship between DN and nickname.  
02216      *
02217      * if the nickname is null, we need the user to enter a nickname for
02218      * the certificate.
02219      *
02220      * once we have a nickname, we make sure that the nickname is unique
02221      * for the DN.  if it is not, the user is reprompted to enter a new 
02222      * nickname.  
02223      *
02224      * in order to exit this loop, the nickname entered is either unique
02225      * or the user hits cancel and the certificate is not imported.
02226      */
02227     setNickname = PR_FALSE;
02228     while(1) {
02229        if(certNickname && certNickname->data) {
02230            /* we will use the nickname so long as no other certs have the
02231             * same nickname.  and the nickname is not NULL.
02232             */              
02233            if(!sec_pkcs12_certs_for_nickname_exist(certNickname, cert->slot)) {
02234               if(setNickname) {
02235                   if(sec_pkcs12_set_nickname_for_cert(cert, key, certNickname,
02236                                    wincx) != SECSuccess) {
02237                      cert->problem = PR_TRUE;
02238                      cert->error = SEC_ERROR_NO_MEMORY;
02239                   }
02240               }
02241               goto loser;
02242            }
02243        }
02244 
02245        setNickname = PR_FALSE;
02246        newNickname = (*nicknameCb)(certNickname, &cancel, wincx);
02247        if(cancel) {
02248            cert->problem = PR_TRUE;
02249            cert->error = SEC_ERROR_USER_CANCELLED;
02250            goto loser;
02251        }
02252 
02253        if(!newNickname) {
02254            cert->problem = PR_TRUE;
02255            cert->error = SEC_ERROR_NO_MEMORY;
02256            goto loser;
02257        }
02258 
02259        /* at this point we have a new nickname, if we have an existing
02260         * certNickname, we need to free it and assign the new nickname
02261         * to it to avoid a memory leak.  happy?
02262         */
02263        if(certNickname) {
02264            SECITEM_ZfreeItem(certNickname, PR_TRUE);
02265            certNickname = NULL;
02266        }
02267 
02268        certNickname = newNickname;
02269        setNickname = PR_TRUE;
02270        /* go back and recheck the new nickname */
02271     }
02272 
02273 loser:
02274     if(certNickname) {
02275        SECITEM_ZfreeItem(certNickname, PR_TRUE);
02276     }
02277 
02278     if(existingDNNick) {
02279        SECITEM_ZfreeItem(existingDNNick, PR_TRUE);
02280     }
02281 }
02282 
02283 static void 
02284 sec_pkcs12_validate_cert(sec_PKCS12SafeBag *cert,
02285                       sec_PKCS12SafeBag *key,
02286                       SEC_PKCS12NicknameCollisionCallback nicknameCb,
02287                       void *wincx)
02288 {
02289     CERTCertificate *leafCert;
02290 
02291     if(!cert) {
02292        return;
02293     }
02294     
02295     cert->validated = PR_TRUE;
02296 
02297     if(!nicknameCb) {
02298        cert->problem = PR_TRUE;
02299        cert->error = SEC_ERROR_NO_MEMORY;
02300        cert->noInstall = PR_TRUE;
02301        return;
02302     }
02303 
02304     if(!cert->safeBagContent.certBag) {
02305        cert->noInstall = PR_TRUE;
02306        cert->problem = PR_TRUE;
02307        cert->error = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
02308        return;
02309     }
02310 
02311     cert->noInstall = PR_FALSE;
02312     cert->unused = PR_FALSE;
02313     cert->problem = PR_FALSE;
02314     cert->error = 0;
02315 
02316     leafCert = CERT_DecodeDERCertificate(
02317         &cert->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL);
02318     if(!leafCert) {
02319        cert->noInstall = PR_TRUE;
02320        cert->problem = PR_TRUE;
02321        cert->error = SEC_ERROR_NO_MEMORY;
02322        return;
02323     }
02324 
02325     CERT_DestroyCertificate(leafCert);
02326 
02327     sec_pkcs12_validate_cert_nickname(cert, key, nicknameCb, wincx);
02328 }
02329 
02330 static void
02331 sec_pkcs12_validate_key_by_cert(sec_PKCS12SafeBag *cert, sec_PKCS12SafeBag *key,
02332                             void *wincx)
02333 {
02334     CERTCertificate *leafCert;
02335     SECKEYPrivateKey *privk;
02336 
02337     if(!key) {
02338        return;
02339     }
02340 
02341     key->validated = PR_TRUE;
02342 
02343     if(!cert) {
02344        key->problem = PR_TRUE;
02345        key->noInstall = PR_TRUE;
02346        key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
02347        return;
02348     }
02349 
02350     leafCert = CERT_DecodeDERCertificate(
02351        &(cert->safeBagContent.certBag->value.x509Cert), PR_FALSE, NULL);
02352     if(!leafCert) {
02353        key->problem = PR_TRUE;
02354        key->noInstall = PR_TRUE;
02355        key->error = SEC_ERROR_NO_MEMORY;
02356        return;
02357     }
02358 
02359     privk = PK11_FindPrivateKeyFromCert(key->slot, leafCert, wincx);
02360     if(!privk) {
02361        privk = PK11_FindKeyByDERCert(key->slot, leafCert, wincx);
02362     }
02363  
02364     if(privk) {
02365        SECKEY_DestroyPrivateKey(privk);
02366        key->noInstall = PR_TRUE;
02367     } 
02368 
02369     CERT_DestroyCertificate(leafCert);
02370 }
02371 
02372 static SECStatus
02373 sec_pkcs12_add_cert(sec_PKCS12SafeBag *cert, PRBool keyExists, void *wincx)
02374 {
02375     SECItem *derCert, *nickName;
02376     char *nickData = NULL;
02377     PRBool isIntermediateCA;
02378     SECStatus rv;
02379 
02380     if(!cert) {
02381        return SECFailure;
02382     }
02383 
02384     if(cert->problem || cert->noInstall || cert->installed) {
02385        return SECSuccess;
02386     }
02387 
02388     derCert = &cert->safeBagContent.certBag->value.x509Cert;
02389 
02390     PORT_Assert(!cert->problem && !cert->noInstall);
02391 
02392     nickName = sec_pkcs12_get_nickname(cert);
02393     if(nickName) {
02394        nickData = (char *)nickName->data;
02395     }
02396 
02397     isIntermediateCA = CERT_IsCADERCert(derCert, NULL) && 
02398                                           !CERT_IsRootDERCert(derCert);
02399 
02400     if(keyExists) {
02401        CERTCertificate *newCert;
02402 
02403        newCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
02404                                          derCert, NULL, PR_FALSE, PR_FALSE);
02405        if(!newCert) {
02406             if(nickName) SECITEM_ZfreeItem(nickName, PR_TRUE);
02407             cert->error = PORT_GetError();
02408             cert->problem = PR_TRUE;
02409             return SECFailure;
02410        }
02411 
02412        rv = PK11_ImportCertForKeyToSlot(cert->slot, newCert, nickData, 
02413                                     PR_TRUE, wincx);
02414        CERT_DestroyCertificate(newCert);
02415     } else if ((cert->tokenCAs == SECPKCS12TargetTokenNoCAs) || 
02416      ((cert->tokenCAs == SECPKCS12TargetTokenIntermediateCAs) && 
02417                                                  !isIntermediateCA)) {
02418        SECItem *certList[2];
02419        certList[0] = derCert;
02420        certList[1] = NULL;
02421        
02422        rv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageUserCertImport,
02423                           1, certList, NULL, PR_TRUE, PR_FALSE, nickData);
02424     } else {
02425        rv = PK11_ImportDERCert(cert->slot, derCert, CK_INVALID_HANDLE,
02426                                                  nickData, PR_FALSE);
02427     }
02428 
02429     cert->installed = PR_TRUE;
02430     if(nickName) SECITEM_ZfreeItem(nickName, PR_TRUE);
02431     return rv;
02432 }
02433 
02434 static SECStatus
02435 sec_pkcs12_add_key(sec_PKCS12SafeBag *key, SECItem *publicValue, 
02436                      KeyType keyType, unsigned int keyUsage, void *wincx)
02437 {
02438     SECStatus rv;
02439     SECItem *nickName;
02440 
02441     if(!key) {
02442        return SECFailure;
02443     }
02444 
02445     if(key->problem || key->noInstall) {
02446        return SECSuccess;
02447     }
02448 
02449     nickName = sec_pkcs12_get_nickname(key);
02450 
02451     switch(SECOID_FindOIDTag(&key->safeBagType))
02452     {
02453        case SEC_OID_PKCS12_V1_KEY_BAG_ID:
02454            rv = PK11_ImportPrivateKeyInfo(key->slot, 
02455                        key->safeBagContent.pkcs8KeyBag, 
02456                        nickName, publicValue, PR_TRUE, PR_TRUE,
02457                        keyUsage,  wincx);
02458            break;
02459        case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
02460            rv = PK11_ImportEncryptedPrivateKeyInfo(key->slot,
02461                                    key->safeBagContent.pkcs8ShroudedKeyBag,
02462                                    key->pwitem, nickName, publicValue, 
02463                                    PR_TRUE, PR_TRUE, keyType, keyUsage,
02464                                    wincx);
02465            break;
02466        default:
02467            key->error = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION;
02468            key->problem = PR_TRUE;
02469            if(nickName) {
02470               SECITEM_ZfreeItem(nickName, PR_TRUE);
02471            }
02472            return SECFailure;
02473     }
02474 
02475     key->installed = PR_TRUE;
02476 
02477     if(nickName) {
02478        SECITEM_ZfreeItem(nickName, PR_TRUE);
02479     }
02480                                    
02481     if(rv != SECSuccess) {
02482        key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
02483        key->problem = PR_TRUE;
02484     } else {
02485        key->installed = PR_TRUE;
02486     }
02487 
02488     return rv;
02489 }
02490 
02491 static SECStatus
02492 sec_pkcs12_add_item_to_bag_list(sec_PKCS12SafeBag ***bagList, 
02493                             sec_PKCS12SafeBag *bag)
02494 {
02495     int i = 0;
02496 
02497     if(!bagList || !bag) {
02498        return SECFailure;
02499     }
02500 
02501     if(!(*bagList)) {
02502        (*bagList) = (sec_PKCS12SafeBag **)PORT_ArenaZAlloc(bag->arena, 
02503                                   sizeof(sec_PKCS12SafeBag *) * 2);
02504     } else {
02505        while((*bagList)[i]) i++;
02506        (*bagList) = (sec_PKCS12SafeBag **)PORT_ArenaGrow(bag->arena, *bagList,
02507                             sizeof(sec_PKCS12SafeBag *) * (i + 1),
02508                             sizeof(sec_PKCS12SafeBag *) * (i + 2));
02509     }
02510 
02511     if(!(*bagList)) {
02512        PORT_SetError(SEC_ERROR_NO_MEMORY);
02513        return SECFailure;
02514     }
02515 
02516     (*bagList)[i] = bag;
02517     (*bagList)[i+1] = NULL;
02518 
02519     return SECSuccess;
02520 }
02521 
02522 static sec_PKCS12SafeBag **
02523 sec_pkcs12_find_certs_for_key(sec_PKCS12SafeBag **safeBags, sec_PKCS12SafeBag *key ) 
02524 {
02525     sec_PKCS12SafeBag **certList = NULL;
02526     SECItem *keyId;
02527     int i;
02528 
02529     if(!safeBags || !safeBags[0]) {
02530        return NULL;
02531     }
02532 
02533     keyId = sec_pkcs12_get_attribute_value(key, SEC_OID_PKCS9_LOCAL_KEY_ID);
02534     if(!keyId) {
02535        return NULL;
02536     }
02537 
02538     i = 0;
02539     certList = NULL;
02540     while(safeBags[i]) {
02541        if(SECOID_FindOIDTag(&(safeBags[i]->safeBagType)) 
02542                             == SEC_OID_PKCS12_V1_CERT_BAG_ID) {
02543            SECItem *certKeyId = sec_pkcs12_get_attribute_value(safeBags[i],
02544                                           SEC_OID_PKCS9_LOCAL_KEY_ID);
02545 
02546            if(certKeyId && (SECITEM_CompareItem(certKeyId, keyId) 
02547                             == SECEqual)) {
02548               if(sec_pkcs12_add_item_to_bag_list(&certList, safeBags[i])
02549                             != SECSuccess) {
02550                   return NULL;
02551               }
02552            }
02553        }
02554        i++;
02555     }
02556 
02557     return certList;
02558 }
02559 
02560 CERTCertList *
02561 SEC_PKCS12DecoderGetCerts(SEC_PKCS12DecoderContext *p12dcx)
02562 {
02563     CERTCertList *certList = NULL;
02564     sec_PKCS12SafeBag **safeBags;
02565     int i;
02566 
02567     if (!p12dcx || !p12dcx->safeBags || !p12dcx->safeBags[0]) {
02568        return NULL;
02569     }
02570 
02571     safeBags = p12dcx->safeBags;
02572     i = 0;
02573     certList = CERT_NewCertList();
02574 
02575     if (certList == NULL) {
02576         return NULL;
02577     }
02578 
02579     while(safeBags[i]) {
02580        if (SECOID_FindOIDTag(&(safeBags[i]->safeBagType)) 
02581                             == SEC_OID_PKCS12_V1_CERT_BAG_ID) {
02582               SECItem *derCert = sec_pkcs12_get_der_cert(safeBags[i]) ;
02583               CERTCertificate *tempCert = NULL;
02584 
02585               if (derCert == NULL) continue;
02586               tempCert=CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
02587                                                derCert, NULL, 
02588                                                PR_FALSE, PR_TRUE);
02589 
02590               if (tempCert) {
02591                   CERT_AddCertToListTail(certList,tempCert);
02592               }
02593               SECITEM_FreeItem(derCert,PR_TRUE);
02594        }
02595        i++;
02596     }
02597 
02598     return certList;
02599 }
02600 static sec_PKCS12SafeBag **
02601 sec_pkcs12_get_key_bags(sec_PKCS12SafeBag **safeBags)
02602 {
02603     int i;
02604     sec_PKCS12SafeBag **keyList = NULL;
02605     SECOidTag bagType;
02606 
02607     if(!safeBags || !safeBags[0]) {
02608        return NULL;
02609     }
02610 
02611     i = 0;
02612     while(safeBags[i]) {
02613        bagType = SECOID_FindOIDTag(&(safeBags[i]->safeBagType));
02614        switch(bagType) {
02615            case SEC_OID_PKCS12_V1_KEY_BAG_ID:
02616            case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
02617               if(sec_pkcs12_add_item_to_bag_list(&keyList, safeBags[i])
02618                             != SECSuccess) {
02619                   return NULL;
02620               }
02621               break;
02622            default:
02623               break;
02624        }
02625        i++;
02626     }
02627 
02628     return keyList;
02629 }
02630 
02631 static SECStatus 
02632 sec_pkcs12_validate_bags(sec_PKCS12SafeBag **safeBags, 
02633                       SEC_PKCS12NicknameCollisionCallback nicknameCb,
02634                       void *wincx)
02635 {
02636     sec_PKCS12SafeBag **keyList;
02637     int i;
02638 
02639     if(!safeBags || !nicknameCb) {
02640        return SECFailure;
02641     }
02642 
02643     if(!safeBags[0]) {
02644        return SECSuccess;
02645     }
02646 
02647     keyList = sec_pkcs12_get_key_bags(safeBags);
02648     if(keyList) {
02649        i = 0;
02650 
02651        while(keyList[i]) {
02652            sec_PKCS12SafeBag **certList = sec_pkcs12_find_certs_for_key(
02653                                                  safeBags, keyList[i]);
02654            if(certList) {
02655               int j = 0;
02656 
02657               if(SECOID_FindOIDTag(&(keyList[i]->safeBagType)) == 
02658                                    SEC_OID_PKCS12_V1_KEY_BAG_ID) {
02659                   /* if it is an unencrypted private key then make sure
02660                    * the attributes are propageted to the appropriate 
02661                    * level 
02662                    */
02663                   if(sec_pkcs12_get_key_info(keyList[i]) != SECSuccess) {
02664                      keyList[i]->problem = PR_TRUE;
02665                      keyList[i]->error = SEC_ERROR_NO_MEMORY;
02666                      return SECFailure;
02667                    }
02668               }
02669        
02670               sec_pkcs12_validate_key_by_cert(certList[0], keyList[i], wincx);
02671               while(certList[j]) {
02672                   certList[j]->hasKey = PR_TRUE;
02673                   if(keyList[i]->problem) {
02674                      certList[j]->problem = PR_TRUE;
02675                      certList[j]->error = keyList[i]->error;
02676                   } else {
02677                      sec_pkcs12_validate_cert(certList[j], keyList[i],
02678                                            nicknameCb, wincx);
02679                      if(certList[j]->problem) {
02680                          keyList[i]->problem = certList[j]->problem;
02681                          keyList[i]->error = certList[j]->error;
02682                      }
02683                   }
02684                   j++;
02685               }
02686            }
02687 
02688            i++;
02689        }
02690     }
02691 
02692     i = 0;
02693     while(safeBags[i]) {
02694        if(!safeBags[i]->validated) {
02695            SECOidTag bagType = SECOID_FindOIDTag(&safeBags[i]->safeBagType);
02696 
02697            switch(bagType) {
02698               case SEC_OID_PKCS12_V1_CERT_BAG_ID:
02699                   sec_pkcs12_validate_cert(safeBags[i], NULL, nicknameCb, 
02700                                         wincx);
02701                   break;
02702               case SEC_OID_PKCS12_V1_KEY_BAG_ID:
02703               case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
02704                   safeBags[i]->noInstall = PR_TRUE;
02705                   safeBags[i]->problem = PR_TRUE;       
02706                   safeBags[i]->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
02707                   break;
02708               default:
02709                   safeBags[i]->noInstall = PR_TRUE;
02710            }
02711        }
02712        i++;
02713     }
02714 
02715     return SECSuccess;
02716 }
02717 
02718 SECStatus
02719 SEC_PKCS12DecoderValidateBags(SEC_PKCS12DecoderContext *p12dcx,
02720                            SEC_PKCS12NicknameCollisionCallback nicknameCb)
02721 {
02722     SECStatus rv;
02723     int i, noInstallCnt, probCnt, bagCnt, errorVal = 0;
02724     if(!p12dcx || p12dcx->error || !p12dcx->safeBags) {
02725        return SECFailure;
02726     }
02727 
02728     rv = sec_pkcs12_validate_bags(p12dcx->safeBags, nicknameCb, p12dcx->wincx);
02729     if(rv == SECSuccess) {
02730        p12dcx->bagsVerified = PR_TRUE;
02731     }
02732 
02733     noInstallCnt = probCnt = bagCnt = 0;
02734     i = 0;
02735     while(p12dcx->safeBags[i]) {
02736        bagCnt++;
02737        if(p12dcx->safeBags[i]->noInstall) noInstallCnt++;
02738        if(p12dcx->safeBags[i]->problem) {
02739            probCnt++;
02740            errorVal = p12dcx->safeBags[i]->error;
02741        }
02742        i++;
02743     }
02744 
02745     if(bagCnt == noInstallCnt) {
02746        PORT_SetError(SEC_ERROR_PKCS12_DUPLICATE_DATA);
02747        return SECFailure;
02748     }
02749 
02750     if(probCnt) {
02751        PORT_SetError(errorVal);
02752        return SECFailure;
02753     }
02754 
02755     return rv;
02756 }
02757 
02758 static SECItem *
02759 sec_pkcs12_get_public_value_and_type(sec_PKCS12SafeBag *certBag,
02760                                    KeyType *type, unsigned int *usage)
02761 {
02762     SECKEYPublicKey *pubKey = NULL;
02763     CERTCertificate *cert = NULL;
02764     SECItem *pubValue;
02765 
02766     *type = nullKey;
02767     *usage = 0;
02768 
02769     if(!certBag) {
02770        return NULL;
02771     }
02772 
02773     cert = CERT_DecodeDERCertificate(
02774         &certBag->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL);
02775     if(!cert) {
02776        return NULL;
02777     }
02778 
02779     *usage = cert->keyUsage;
02780     pubKey = CERT_ExtractPublicKey(cert);
02781     CERT_DestroyCertificate(cert);
02782     if(!pubKey) {
02783        return NULL;
02784     }
02785 
02786     *type = pubKey->keyType;
02787     switch(pubKey->keyType) {
02788        case dsaKey:
02789            pubValue = SECITEM_DupItem(&pubKey->u.dsa.publicValue);
02790            break;
02791        case dhKey:
02792            pubValue = SECITEM_DupItem(&pubKey->u.dh.publicValue);
02793            break;
02794        case rsaKey:
02795            pubValue = SECITEM_DupItem(&pubKey->u.rsa.modulus);
02796            break;
02797         case ecKey:
02798            pubValue = SECITEM_DupItem(&pubKey->u.ec.publicValue);
02799            break;
02800        default:
02801            pubValue = NULL;
02802     }
02803 
02804     SECKEY_DestroyPublicKey(pubKey);
02805 
02806     return pubValue;
02807 }
02808 
02809 static SECStatus 
02810 sec_pkcs12_install_bags(sec_PKCS12SafeBag **safeBags, 
02811                      void *wincx)
02812 {
02813     sec_PKCS12SafeBag **keyList, **certList;
02814     int i;
02815 
02816     if(!safeBags) {
02817        return SECFailure;
02818     }
02819 
02820     if(!safeBags[0]) {
02821        return SECSuccess;
02822     }
02823 
02824     keyList = sec_pkcs12_get_key_bags(safeBags);
02825     if(keyList) {
02826        i = 0;
02827 
02828        while(keyList[i]) {
02829            SECStatus rv;
02830            SECItem *publicValue = NULL;
02831            KeyType keyType;
02832            unsigned int keyUsage;
02833 
02834            if(keyList[i]->problem) {
02835               goto next_key_bag;
02836            }
02837 
02838            certList = sec_pkcs12_find_certs_for_key(safeBags,
02839                                                keyList[i]);
02840            if(certList) {
02841               publicValue = sec_pkcs12_get_public_value_and_type(certList[0],
02842                                                  &keyType, &keyUsage);
02843            }
02844            rv = sec_pkcs12_add_key(keyList[i], publicValue, keyType, keyUsage,
02845                                                                wincx);
02846            if(publicValue) {
02847               SECITEM_FreeItem(publicValue, PR_TRUE);
02848            }
02849            if(rv != SECSuccess) {
02850               PORT_SetError(keyList[i]->error);
02851               return SECFailure;
02852            }
02853 
02854            if(certList) {
02855               int j = 0;
02856 
02857               while(certList[j]) {
02858                   SECStatus certRv;
02859 
02860                   if(rv != SECSuccess) {
02861                      certList[j]->problem = keyList[i]->problem;
02862                      certList[j]->error = keyList[i]->error;   
02863                      certList[j]->noInstall = PR_TRUE;
02864                      goto next_cert_bag;
02865                   }
02866 
02867                   certRv = sec_pkcs12_add_cert(certList[j], 
02868                                            certList[j]->hasKey, wincx);
02869                   if(certRv != SECSuccess) {
02870                      keyList[i]->problem = certList[j]->problem;
02871                      keyList[i]->error = certList[j]->error;
02872                      PORT_SetError(certList[j]->error);
02873                      return SECFailure;
02874                   }
02875 next_cert_bag:
02876                   j++;
02877               }
02878            }
02879 
02880 next_key_bag:
02881            i++;
02882        }
02883     }
02884 
02885     i = 0;
02886     while(safeBags[i]) {
02887        if(!safeBags[i]->installed) {
02888            SECStatus rv;
02889            SECOidTag bagType = SECOID_FindOIDTag(&(safeBags[i]->safeBagType));
02890 
02891            switch(bagType) {
02892               case SEC_OID_PKCS12_V1_CERT_BAG_ID:
02893                   rv = sec_pkcs12_add_cert(safeBags[i], safeBags[i]->hasKey,
02894                                         wincx);
02895                   if(rv != SECSuccess) {
02896                      PORT_SetError(safeBags[i]->error);
02897                      return SECFailure;
02898                   }
02899                   break;
02900               case SEC_OID_PKCS12_V1_KEY_BAG_ID:
02901               case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
02902               default:
02903                   break;
02904            }
02905        }
02906        i++;
02907     }
02908 
02909     return SECSuccess;
02910 }
02911 
02912 SECStatus
02913 SEC_PKCS12DecoderImportBags(SEC_PKCS12DecoderContext *p12dcx)
02914 {
02915     if(!p12dcx || p12dcx->error) {
02916        return SECFailure;
02917     }
02918 
02919     if(!p12dcx->bagsVerified) {
02920        return SECFailure;
02921     }
02922 
02923     return sec_pkcs12_install_bags(p12dcx->safeBags, p12dcx->wincx);
02924 }
02925 
02926 PRBool
02927 sec_pkcs12_bagHasKey(SEC_PKCS12DecoderContext *p12dcx, sec_PKCS12SafeBag *bag)
02928 {
02929     int i;
02930     SECItem *keyId;
02931     SECItem *certKeyId;
02932 
02933     certKeyId = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_LOCAL_KEY_ID);
02934     if (certKeyId == NULL) {
02935         return PR_FALSE;
02936     }
02937             
02938     for (i=0; p12dcx->keyList && p12dcx->keyList[i]; i++) {
02939         keyId = sec_pkcs12_get_attribute_value(p12dcx->keyList[i],
02940                                                 SEC_OID_PKCS9_LOCAL_KEY_ID);
02941         if(!keyId) {
02942             continue;
02943         }
02944         if(SECITEM_CompareItem(certKeyId, keyId) == SECEqual) {
02945             return PR_TRUE;
02946         }
02947     }
02948     return PR_FALSE;
02949 }
02950 
02951 SECItem *
02952 sec_pkcs12_get_friendlyName(sec_PKCS12SafeBag *bag)
02953 {
02954     SECItem *friendlyName;
02955     SECItem *tempnm;
02956     
02957     tempnm = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME);
02958     friendlyName = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
02959     if (friendlyName) {
02960         if (!sec_pkcs12_convert_item_to_unicode(NULL, friendlyName,
02961                                    tempnm, PR_TRUE, PR_FALSE, PR_FALSE)) {
02962             SECITEM_FreeItem(friendlyName, PR_TRUE);
02963             friendlyName = NULL;
02964         }
02965     }
02966     return friendlyName;
02967 }
02968 
02969 /* Following two functions provide access to selected portions of the safe bags.
02970  * Iteration is implemented per decoder context and may be accessed after
02971  * SEC_PKCS12DecoderVerify() returns success.
02972  * When ...DecoderIterateNext() returns SUCCESS a decoder item has been returned
02973  * where item.type is always set; item.friendlyName is set if it is non-null;
02974  * item.der, item.hasKey are set only for SEC_OID_PKCS12_V1_CERT_BAG_ID items.
02975  * ...DecoderIterateNext() returns FAILURE when the list is exhausted or when
02976  * arguments are invalid; PORT_GetError() is 0 at end-of-list.
02977  * Caller has read-only access to decoder items. Any SECItems generated are
02978  * owned by the decoder context and are freed by ...DecoderFinish().
02979  */
02980 SECStatus
02981 SEC_PKCS12DecoderIterateInit(SEC_PKCS12DecoderContext *p12dcx)
02982 {
02983     if(!p12dcx || p12dcx->error) {
02984         PORT_SetError(SEC_ERROR_INVALID_ARGS);
02985        return SECFailure;
02986     }
02987 
02988     p12dcx->iteration = 0;
02989     return SECSuccess;
02990 }
02991 
02992 SECStatus
02993 SEC_PKCS12DecoderIterateNext(SEC_PKCS12DecoderContext *p12dcx,
02994                              const SEC_PKCS12DecoderItem **ipp)
02995 {
02996     sec_PKCS12SafeBag *bag;
02997     
02998     if(!p12dcx || p12dcx->error) {
02999         PORT_SetError(SEC_ERROR_INVALID_ARGS);
03000        return SECFailure;
03001     }
03002 
03003     if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
03004         SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
03005     }
03006     if (p12dcx->decitem.friendlyName != NULL) {
03007         SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
03008     }
03009     p12dcx->decitem.type = 0;
03010     p12dcx->decitem.der = NULL;
03011     p12dcx->decitem.friendlyName = NULL;
03012     p12dcx->decitem.hasKey = PR_FALSE;
03013     *ipp = NULL;
03014     if (p12dcx->keyList == NULL) {
03015         p12dcx->keyList = sec_pkcs12_get_key_bags(p12dcx->safeBags);
03016     }
03017 
03018     
03019     for (; p12dcx->iteration < p12dcx->safeBagCount; p12dcx->iteration++) {
03020         bag = p12dcx->safeBags[p12dcx->iteration];
03021        if(bag == NULL || bag->problem) {
03022             continue;
03023         }
03024         p12dcx->decitem.type = SECOID_FindOIDTag(&(bag->safeBagType));
03025         switch(p12dcx->decitem.type) {
03026             case SEC_OID_PKCS12_V1_CERT_BAG_ID:
03027                 p12dcx->decitem.der = sec_pkcs12_get_der_cert(bag);
03028                 p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
03029                 p12dcx->decitem.hasKey = sec_pkcs12_bagHasKey(p12dcx, bag);
03030                 break;
03031             case SEC_OID_PKCS12_V1_KEY_BAG_ID:
03032             case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
03033                 p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
03034                 break;
03035             default:
03036                 /* return these even though we don't expect them */
03037                 break;
03038             case SEC_OID_UNKNOWN:
03039                 /* ignore these */
03040                 continue;
03041         }
03042         *ipp = &p12dcx->decitem;
03043         p12dcx->iteration++;
03044         break;  /* end for() */
03045     }
03046     
03047     PORT_SetError(0);       /* end-of-list is SECFailure with no PORT error */
03048     return ((p12dcx->decitem.type == 0) ? SECFailure : SECSuccess);
03049 }
03050 
03051 static SECStatus
03052 sec_pkcs12_decoder_append_bag_to_context(SEC_PKCS12DecoderContext *p12dcx,
03053                                     sec_PKCS12SafeBag *bag)
03054 {
03055     if(!p12dcx || p12dcx->error) {
03056        return SECFailure;
03057     }
03058 
03059     if(!p12dcx->safeBagCount) {
03060        p12dcx->safeBags = (sec_PKCS12SafeBag **)PORT_ArenaZAlloc(p12dcx->arena, 
03061                                        sizeof(sec_PKCS12SafeBag *) * 2);
03062     } else {
03063        p12dcx->safeBags = 
03064          (sec_PKCS12SafeBag **)PORT_ArenaGrow(p12dcx->arena, p12dcx->safeBags,
03065                    (p12dcx->safeBagCount + 1) * sizeof(sec_PKCS12SafeBag *),
03066                    (p12dcx->safeBagCount + 2) * sizeof(sec_PKCS12SafeBag *));
03067     }
03068 
03069     if(!p12dcx->safeBags) {
03070        PORT_SetError(SEC_ERROR_NO_MEMORY);
03071        return SECFailure;
03072     }
03073 
03074     p12dcx->safeBags[p12dcx->safeBagCount] = bag;
03075     p12dcx->safeBags[p12dcx->safeBagCount+1] = NULL;
03076     p12dcx->safeBagCount++;
03077 
03078     return SECSuccess;
03079 }
03080 
03081 static sec_PKCS12SafeBag *
03082 sec_pkcs12_decoder_convert_old_key(SEC_PKCS12DecoderContext *p12dcx,
03083                                void *key, PRBool isEspvk)
03084 {
03085     sec_PKCS12SafeBag *keyBag;
03086     SECOidData *oid;
03087     SECOidTag keyTag;
03088     SECItem *keyID, *nickName, *newNickName;
03089 
03090     if(!p12dcx || p12dcx->error || !key) {
03091        return NULL;
03092     }
03093 
03094     newNickName =(SECItem *)PORT_ArenaZAlloc(p12dcx->arena, sizeof(SECItem));
03095     keyBag = (sec_PKCS12SafeBag *)PORT_ArenaZAlloc(p12dcx->arena, 
03096                                              sizeof(sec_PKCS12SafeBag));
03097     if(!keyBag || !newNickName) {
03098        PORT_SetError(SEC_ERROR_NO_MEMORY);
03099        return NULL;
03100     }
03101 
03102     keyBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes;
03103     keyBag->slot = p12dcx->slot;
03104     keyBag->arena = p12dcx->arena;
03105     keyBag->pwitem = p12dcx->pwitem;
03106     keyBag->tokenCAs = p12dcx->tokenCAs;
03107     keyBag->oldBagType = PR_TRUE;
03108 
03109     keyTag = (isEspvk) ? SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID :
03110                       SEC_OID_PKCS12_V1_KEY_BAG_ID;
03111     oid = SECOID_FindOIDByTag(keyTag);
03112     if(!oid) {
03113        PORT_SetError(SEC_ERROR_NO_MEMORY);
03114        return NULL;
03115     }
03116 
03117     if(SECITEM_CopyItem(p12dcx->arena, &keyBag->safeBagType, &oid->oid) 
03118                      != SECSuccess) {
03119        PORT_SetError(SEC_ERROR_NO_MEMORY);
03120        return NULL;
03121     }
03122 
03123     if(isEspvk) {
03124        SEC_PKCS12ESPVKItem *espvk = (SEC_PKCS12ESPVKItem *)key;
03125        keyBag->safeBagContent.pkcs8ShroudedKeyBag  = 
03126                                    espvk->espvkCipherText.pkcs8KeyShroud;
03127        nickName = &(espvk->espvkData.uniNickName); 
03128        if(!espvk->espvkData.assocCerts || !espvk->espvkData.assocCerts[0]) {
03129            PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
03130            return NULL;
03131        }
03132        keyID = &espvk->espvkData.assocCerts[0]->digest;
03133     } else {
03134        SEC_PKCS12PrivateKey *pk = (SEC_PKCS12PrivateKey *)key;
03135        keyBag->safeBagContent.pkcs8KeyBag = &pk->pkcs8data;
03136        nickName= &(pk->pvkData.uniNickName);
03137        if(!pk->pvkData.assocCerts || !pk->pvkData.assocCerts[0]) {
03138            PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
03139            return NULL;
03140        }
03141        keyID = &pk->pvkData.assocCerts[0]->digest;
03142     }
03143 
03144     if(nickName->len) {
03145        if(nickName->len >= 2) {
03146            if(nickName->data[0] && nickName->data[1]) {
03147               if(!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickName, 
03148                                    nickName, PR_FALSE, PR_FALSE, PR_TRUE)) {
03149                   PORT_SetError(SEC_ERROR_NO_MEMORY);
03150                   return NULL;
03151               }
03152               nickName = newNickName;
03153            } else if(nickName->data[0] && !nickName->data[1]) {
03154               unsigned int j = 0;
03155               unsigned char t;
03156               for(j = 0; j < nickName->len; j+=2) {
03157                   t = nickName->data[j+1];
03158                   nickName->data[j+1] = nickName->data[j];
03159                   nickName->data[j] = t;
03160               }
03161            }
03162        } else {
03163            if(!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickName, 
03164                                    nickName, PR_FALSE, PR_FALSE, PR_TRUE)) {
03165               PORT_SetError(SEC_ERROR_NO_MEMORY);
03166               return NULL;
03167            }
03168            nickName = newNickName;
03169        }
03170     }
03171 
03172     if(sec_pkcs12_decoder_set_attribute_value(keyBag,
03173                                          SEC_OID_PKCS9_FRIENDLY_NAME,
03174                                          nickName) != SECSuccess) {
03175        return NULL;
03176     }
03177        
03178     if(sec_pkcs12_decoder_set_attribute_value(keyBag,SEC_OID_PKCS9_LOCAL_KEY_ID,
03179                                    keyID) != SECSuccess) {
03180        return NULL;
03181     }
03182 
03183     return keyBag;
03184 }
03185 
03186 static sec_PKCS12SafeBag *
03187 sec_pkcs12_decoder_create_cert(SEC_PKCS12DecoderContext *p12dcx,
03188                             SECItem *derCert)
03189 {
03190     sec_PKCS12SafeBag *certBag;
03191     SECOidData *oid;
03192     SGNDigestInfo *digest;
03193     SECItem *keyId;
03194     SECStatus rv;
03195 
03196     if(!p12dcx || p12dcx->error || !derCert) {
03197        return NULL;
03198     }
03199 
03200     keyId = (SECItem *)PORT_ArenaZAlloc(p12dcx->arena, sizeof(SECItem));
03201     if(!keyId) {
03202        PORT_SetError(SEC_ERROR_NO_MEMORY);
03203        return NULL;
03204     }
03205 
03206     digest = sec_pkcs12_compute_thumbprint(derCert);
03207     if(!digest) {
03208        return NULL;
03209     }
03210 
03211     rv = SECITEM_CopyItem(p12dcx->arena, keyId, &digest->digest);
03212     SGN_DestroyDigestInfo(digest);
03213     if(rv != SECSuccess) {
03214        PORT_SetError(SEC_ERROR_NO_MEMORY);
03215        return NULL;
03216     }
03217 
03218     oid = SECOID_FindOIDByTag(SEC_OID_PKCS12_V1_CERT_BAG_ID);
03219     certBag = (sec_PKCS12SafeBag *)PORT_ArenaZAlloc(p12dcx->arena, 
03220                                               sizeof(sec_PKCS12SafeBag));
03221     if(!certBag || !oid || (SECITEM_CopyItem(p12dcx->arena, 
03222                      &certBag->safeBagType, &oid->oid) != SECSuccess)) {
03223        PORT_SetError(SEC_ERROR_NO_MEMORY);
03224        return NULL;
03225     }
03226 
03227     certBag->slot = p12dcx->slot;
03228     certBag->pwitem = p12dcx->pwitem;
03229     certBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes;
03230     certBag->arena = p12dcx->arena;
03231     certBag->tokenCAs = p12dcx->tokenCAs;
03232 
03233     oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_X509_CERT);
03234     certBag->safeBagContent.certBag = 
03235         (sec_PKCS12CertBag *)PORT_ArenaZAlloc(p12dcx->arena, 
03236                                          sizeof(sec_PKCS12CertBag));
03237     if(!certBag->safeBagContent.certBag || !oid ||
03238                      (SECITEM_CopyItem(p12dcx->arena, 
03239                              &certBag->safeBagContent.certBag->bagID,
03240                              &oid->oid) != SECSuccess)) {
03241        PORT_SetError(SEC_ERROR_NO_MEMORY);
03242        return NULL;
03243     }
03244       
03245     if(SECITEM_CopyItem(p12dcx->arena, 
03246                       &(certBag->safeBagContent.certBag->value.x509Cert),
03247                       derCert) != SECSuccess) {
03248        PORT_SetError(SEC_ERROR_NO_MEMORY);
03249        return NULL;
03250     }
03251 
03252     if(sec_pkcs12_decoder_set_attribute_value(certBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
03253                                    keyId) != SECSuccess) {
03254        return NULL;
03255     }
03256 
03257     return certBag;
03258 }
03259 
03260 static sec_PKCS12SafeBag **
03261 sec_pkcs12_decoder_convert_old_cert(SEC_PKCS12DecoderContext *p12dcx,
03262                                 SEC_PKCS12CertAndCRL *oldCert)
03263 {
03264     sec_PKCS12SafeBag **certList;
03265     SECItem **derCertList;
03266     int i, j;
03267 
03268     if(!p12dcx || p12dcx->error || !oldCert) {
03269        return NULL;
03270     }
03271 
03272     derCertList = SEC_PKCS7GetCertificateList(&oldCert->value.x509->certOrCRL);
03273     if(!derCertList) {
03274        return NULL;
03275     }
03276 
03277     i = 0;
03278     while(derCertList[i]) i++;
03279 
03280     certList = (sec_PKCS12SafeBag **)PORT_ArenaZAlloc(p12dcx->arena, 
03281                             (i + 1) * sizeof(sec_PKCS12SafeBag *));
03282     if(!certList) {
03283        PORT_SetError(SEC_ERROR_NO_MEMORY);
03284        return NULL;
03285     }
03286 
03287     for(j = 0; j < i; j++) {
03288        certList[j] = sec_pkcs12_decoder_create_cert(p12dcx, derCertList[j]);
03289        if(!certList[j]) {
03290            return NULL;
03291        }
03292     }
03293 
03294     return certList;
03295 }   
03296 
03297 static SECStatus
03298 sec_pkcs12_decoder_convert_old_key_and_certs(SEC_PKCS12DecoderContext *p12dcx,
03299                                         void *oldKey, PRBool isEspvk,
03300                                         SEC_PKCS12SafeContents *safe,
03301                                         SEC_PKCS12Baggage *baggage)
03302 {
03303     sec_PKCS12SafeBag *key, **certList;
03304     SEC_PKCS12CertAndCRL *oldCert;
03305     SEC_PKCS12PVKSupportingData *pvkData;
03306     int i;
03307     SECItem *keyName;
03308 
03309     if(!p12dcx || !oldKey) {
03310        return SECFailure;
03311     }
03312 
03313     if(isEspvk) {
03314        pvkData = &((SEC_PKCS12ESPVKItem *)(oldKey))->espvkData;
03315     } else {
03316        pvkData = &((SEC_PKCS12PrivateKey *)(oldKey))->pvkData;
03317     }
03318 
03319     if(!pvkData->assocCerts || !pvkData->assocCerts[0]) {
03320        PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
03321        return SECFailure;
03322     }
03323 
03324     oldCert = (SEC_PKCS12CertAndCRL *)sec_pkcs12_find_object(safe, baggage, 
03325                                  SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID, NULL,
03326                                  pvkData->assocCerts[0]);
03327     if(!oldCert) {
03328        PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
03329        return SECFailure;
03330     }
03331        
03332     key = sec_pkcs12_decoder_convert_old_key(p12dcx,oldKey, isEspvk);
03333     certList = sec_pkcs12_decoder_convert_old_cert(p12dcx, oldCert);
03334     if(!key || !certList) {
03335        return SECFailure;
03336     }
03337 
03338     if(sec_pkcs12_decoder_append_bag_to_context(p12dcx, key) != SECSuccess) {
03339        return SECFailure;
03340     }
03341 
03342     keyName = sec_pkcs12_get_nickname(key);
03343     if(!keyName) {
03344        return SECFailure;
03345     }
03346 
03347     i = 0;
03348     while(certList[i]) {
03349        if(sec_pkcs12_decoder_append_bag_to_context(p12dcx, certList[i]) 
03350                             != SECSuccess) {
03351            return SECFailure;
03352        }
03353        i++;
03354     }
03355 
03356     certList = sec_pkcs12_find_certs_for_key(p12dcx->safeBags, key);
03357     if(!certList) {
03358        return SECFailure;
03359     }
03360 
03361     i = 0;
03362     while(certList[i] != 0) {
03363        if(sec_pkcs12_set_nickname(certList[i], keyName) != SECSuccess) {
03364            return SECFailure;
03365        }
03366        i++;
03367     }
03368                             
03369     return SECSuccess;
03370 }
03371        
03372 static SECStatus
03373 sec_pkcs12_decoder_convert_old_safe_to_bags(SEC_PKCS12DecoderContext *p12dcx,
03374                                        SEC_PKCS12SafeContents *safe,
03375                                        SEC_PKCS12Baggage *baggage)
03376 {
03377     SECStatus rv;
03378 
03379     if(!p12dcx || p12dcx->error) {
03380        return SECFailure;
03381     }
03382 
03383     if(safe && safe->contents) {
03384        int i = 0;
03385        while(safe->contents[i] != NULL) {
03386            if(SECOID_FindOIDTag(&safe->contents[i]->safeBagType) 
03387                             == SEC_OID_PKCS12_KEY_BAG_ID) {
03388               int j = 0;
03389               SEC_PKCS12PrivateKeyBag *privBag = 
03390                                    safe->contents[i]->safeContent.keyBag;
03391               
03392               while(privBag->privateKeys[j] != NULL) {
03393                   SEC_PKCS12PrivateKey *pk = privBag->privateKeys[j];
03394                   rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx,pk,
03395                                           PR_FALSE, safe, baggage);
03396                   if(rv != SECSuccess) {
03397                      goto loser;
03398                   }
03399                   j++;
03400               }
03401            }
03402            i++;
03403        }
03404     }
03405 
03406     if(baggage && baggage->bags) {
03407        int i = 0;
03408        while(baggage->bags[i] != NULL) {
03409            SEC_PKCS12BaggageItem *bag = baggage->bags[i];
03410            int j = 0;
03411 
03412            if(!bag->espvks) {
03413               i++;
03414               continue;
03415            }
03416 
03417            while(bag->espvks[j] != NULL) {
03418               SEC_PKCS12ESPVKItem *espvk = bag->espvks[j];
03419               rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx, espvk,
03420                                                  PR_TRUE, safe, baggage);
03421               if(rv != SECSuccess) {
03422                   goto loser;
03423               }
03424               j++;
03425            }
03426            i++;
03427        }
03428     }
03429 
03430     return SECSuccess;
03431 
03432 loser:
03433     return SECFailure;
03434 }
03435 
03436 SEC_PKCS12DecoderContext *
03437 sec_PKCS12ConvertOldSafeToNew(PRArenaPool *arena, PK11SlotInfo *slot, 
03438                            PRBool swapUnicode, SECItem *pwitem,
03439                            void *wincx, SEC_PKCS12SafeContents *safe,
03440                            SEC_PKCS12Baggage *baggage)
03441 {
03442     SEC_PKCS12DecoderContext *p12dcx;
03443 
03444     if(!arena || !slot || !pwitem) {
03445        return NULL;
03446     }
03447 
03448     if(!safe && !baggage) {
03449        return NULL;
03450     }
03451 
03452     p12dcx = (SEC_PKCS12DecoderContext *)PORT_ArenaZAlloc(arena, 
03453                                        sizeof(SEC_PKCS12DecoderContext));
03454     if(!p12dcx) {
03455        return NULL;
03456     }
03457 
03458     p12dcx->arena = arena;
03459     p12dcx->slot = PK11_ReferenceSlot(slot);
03460     p12dcx->wincx = wincx;
03461     p12dcx->error = PR_FALSE;
03462     p12dcx->swapUnicodeBytes = swapUnicode; 
03463     p12dcx->pwitem = pwitem;
03464     p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs;
03465     
03466     if(sec_pkcs12_decoder_convert_old_safe_to_bags(p12dcx, safe, baggage) 
03467                             != SECSuccess) {
03468        p12dcx->error = PR_TRUE;
03469        return NULL;
03470     }
03471 
03472     return p12dcx;
03473 }