Back to index

lightning-sunbird  0.9+nobinonly
p12dec.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #include "pkcs12.h"
00038 #include "plarena.h"
00039 #include "secpkcs7.h"
00040 #include "p12local.h"
00041 #include "secoid.h"
00042 #include "secitem.h"
00043 #include "secport.h"
00044 #include "secasn1.h"
00045 #include "secder.h"
00046 #include "secerr.h"
00047 #include "cert.h"
00048 #include "certdb.h"
00049 #include "p12plcy.h"
00050 #include "p12.h" 
00051 #include "secpkcs5.h" 
00052 
00053 /* PFX extraction and validation routines */
00054 
00055 /* decode the DER encoded PFX item.  if unable to decode, check to see if it
00056  * is an older PFX item.  If that fails, assume the file was not a valid
00057  * pfx file.
00058  * the returned pfx structure should be destroyed using SEC_PKCS12DestroyPFX
00059  */
00060 static SEC_PKCS12PFXItem *
00061 sec_pkcs12_decode_pfx(SECItem *der_pfx)
00062 {
00063     SEC_PKCS12PFXItem *pfx;
00064     SECStatus rv;
00065 
00066     if(der_pfx == NULL) {
00067        return NULL;
00068     }
00069 
00070     /* allocate the space for a new PFX item */
00071     pfx = sec_pkcs12_new_pfx();
00072     if(pfx == NULL) {
00073        return NULL;
00074     }
00075 
00076     rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate, 
00077                          der_pfx);
00078 
00079     /* if a failure occurred, check for older version...
00080      * we also get rid of the old pfx structure, because we don't
00081      * know where it failed and what data in may contain
00082      */
00083     if(rv != SECSuccess) {
00084        SEC_PKCS12DestroyPFX(pfx);
00085        pfx = sec_pkcs12_new_pfx();
00086        if(pfx == NULL) {
00087            return NULL;
00088        }
00089        rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate_OLD, 
00090                             der_pfx);
00091        if(rv != SECSuccess) {
00092            PORT_SetError(SEC_ERROR_PKCS12_DECODING_PFX);
00093            PORT_FreeArena(pfx->poolp, PR_TRUE);
00094            return NULL;
00095        }
00096        pfx->old = PR_TRUE;
00097        SGN_CopyDigestInfo(pfx->poolp, &pfx->macData.safeMac, &pfx->old_safeMac);
00098        SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, &pfx->old_macSalt);
00099     } else {
00100        pfx->old = PR_FALSE;
00101     }
00102 
00103     /* convert bit string from bits to bytes */
00104     pfx->macData.macSalt.len /= 8;
00105 
00106     return pfx;
00107 }
00108 
00109 /* validate the integrity MAC used in the PFX.  The MAC is generated
00110  * per the PKCS 12 document.  If the MAC is incorrect, it is most likely
00111  * due to an invalid password.
00112  * pwitem is the integrity password
00113  * pfx is the decoded pfx item
00114  */
00115 static PRBool 
00116 sec_pkcs12_check_pfx_mac(SEC_PKCS12PFXItem *pfx,
00117                       SECItem *pwitem)
00118 {
00119     SECItem *key = NULL, *mac = NULL, *data = NULL;
00120     SECItem *vpwd = NULL;
00121     SECOidTag algorithm;
00122     PRBool ret = PR_FALSE;
00123 
00124     if(pfx == NULL) {
00125        return PR_FALSE;
00126     }
00127 
00128     algorithm = SECOID_GetAlgorithmTag(&pfx->macData.safeMac.digestAlgorithm);
00129     switch(algorithm) {
00130        /* only SHA1 hashing supported as a MACing algorithm */
00131        case SEC_OID_SHA1:
00132            if(pfx->old == PR_FALSE) {
00133               pfx->swapUnicode = PR_FALSE;
00134            }
00135 
00136 recheckUnicodePassword:
00137            vpwd = sec_pkcs12_create_virtual_password(pwitem, 
00138                                           &pfx->macData.macSalt, 
00139                                           pfx->swapUnicode);
00140            if(vpwd == NULL) {
00141               return PR_FALSE;
00142            }
00143 
00144            key = sec_pkcs12_generate_key_from_password(algorithm,
00145                                           &pfx->macData.macSalt, 
00146                                           (pfx->old ? pwitem : vpwd));
00147            /* free vpwd only for newer PFX */
00148            if(vpwd) {
00149               SECITEM_ZfreeItem(vpwd, PR_TRUE);
00150            }
00151            if(key == NULL) {
00152               return PR_FALSE;
00153            }
00154 
00155            data = SEC_PKCS7GetContent(&pfx->authSafe);
00156            if(data == NULL) {
00157               break;
00158            }
00159 
00160            /* check MAC */
00161            mac = sec_pkcs12_generate_mac(key, data, pfx->old);
00162            ret = PR_TRUE;
00163            if(mac) {
00164               SECItem *safeMac = &pfx->macData.safeMac.digest;
00165               if(SECITEM_CompareItem(mac, safeMac) != SECEqual) {
00166 
00167                   /* if we encounter an invalid mac, lets invert the
00168                    * password in case of unicode changes 
00169                    */
00170                   if(((!pfx->old) && pfx->swapUnicode) || (pfx->old)){
00171                      PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
00172                      ret = PR_FALSE;
00173                   } else {
00174                      SECITEM_ZfreeItem(mac, PR_TRUE);
00175                      pfx->swapUnicode = PR_TRUE;
00176                      goto recheckUnicodePassword;
00177                   }
00178               } 
00179               SECITEM_ZfreeItem(mac, PR_TRUE);
00180            } else {
00181               ret = PR_FALSE;
00182            }
00183            break;
00184        default:
00185            PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM);
00186            ret = PR_FALSE;
00187            break;
00188     }
00189 
00190     /* let success fall through */
00191     if(key != NULL)
00192        SECITEM_ZfreeItem(key, PR_TRUE);
00193 
00194     return ret;
00195 }
00196 
00197 /* check the validity of the pfx structure.  we currently only support
00198  * password integrity mode, so we check the MAC.
00199  */
00200 static PRBool 
00201 sec_pkcs12_validate_pfx(SEC_PKCS12PFXItem *pfx, 
00202                      SECItem *pwitem)
00203 {
00204     SECOidTag contentType;
00205 
00206     contentType = SEC_PKCS7ContentType(&pfx->authSafe);
00207     switch(contentType)
00208     {
00209        case SEC_OID_PKCS7_DATA:
00210            return sec_pkcs12_check_pfx_mac(pfx, pwitem);
00211            break;
00212        case SEC_OID_PKCS7_SIGNED_DATA:
00213        default:
00214            PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE);
00215            break;
00216     }
00217 
00218     return PR_FALSE;
00219 }
00220 
00221 /* decode and return the valid PFX.  if the PFX item is not valid,
00222  * NULL is returned.
00223  */
00224 static SEC_PKCS12PFXItem *
00225 sec_pkcs12_get_pfx(SECItem *pfx_data, 
00226                  SECItem *pwitem)
00227 {
00228     SEC_PKCS12PFXItem *pfx;
00229     PRBool valid_pfx;
00230 
00231     if((pfx_data == NULL) || (pwitem == NULL)) {
00232        return NULL;
00233     }
00234 
00235     pfx = sec_pkcs12_decode_pfx(pfx_data);
00236     if(pfx == NULL) {
00237        return NULL;
00238     }
00239 
00240     valid_pfx = sec_pkcs12_validate_pfx(pfx, pwitem);
00241     if(valid_pfx != PR_TRUE) {
00242        SEC_PKCS12DestroyPFX(pfx);
00243        pfx = NULL;
00244     }
00245 
00246     return pfx;
00247 }
00248 
00249 /* authenticated safe decoding, validation, and access routines
00250  */
00251 
00252 /* convert dogbert beta 3 authenticated safe structure to a post
00253  * beta three structure, so that we don't have to change more routines.
00254  */
00255 static SECStatus
00256 sec_pkcs12_convert_old_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe)
00257 {
00258     SEC_PKCS12Baggage *baggage;
00259     SEC_PKCS12BaggageItem *bag;
00260     SECStatus rv = SECSuccess;
00261 
00262     if(asafe->old_baggage.espvks == NULL) {
00263        /* XXX should the ASN1 engine produce a single NULL element list
00264         * rather than setting the pointer to NULL?  
00265         * There is no need to return an error -- assume that the list
00266         * was empty.
00267         */
00268        return SECSuccess;
00269     }
00270 
00271     baggage = sec_pkcs12_create_baggage(asafe->poolp);
00272     if(!baggage) {
00273        return SECFailure;
00274     }
00275     bag = sec_pkcs12_create_external_bag(baggage);
00276     if(!bag) {
00277        return SECFailure;
00278     }
00279 
00280     PORT_Memcpy(&asafe->baggage, baggage, sizeof(SEC_PKCS12Baggage));
00281 
00282     /* if there are shrouded keys, append them to the bag */
00283     rv = SECSuccess;
00284     if(asafe->old_baggage.espvks[0] != NULL) {
00285        int nEspvk = 0;
00286        rv = SECSuccess;
00287        while((asafe->old_baggage.espvks[nEspvk] != NULL) && 
00288               (rv == SECSuccess)) {
00289            rv = sec_pkcs12_append_shrouded_key(bag, 
00290                                    asafe->old_baggage.espvks[nEspvk]);
00291            nEspvk++;
00292        }
00293     }
00294 
00295     return rv;
00296 }    
00297 
00298 /* decodes the authenticated safe item.  a return of NULL indicates
00299  * an error.  however, the error will have occured either in memory
00300  * allocation or in decoding the authenticated safe.
00301  *
00302  * if an old PFX item has been found, we want to convert the
00303  * old authenticated safe to the new one.
00304  */
00305 static SEC_PKCS12AuthenticatedSafe *
00306 sec_pkcs12_decode_authenticated_safe(SEC_PKCS12PFXItem *pfx) 
00307 {
00308     SECItem *der_asafe = NULL;
00309     SEC_PKCS12AuthenticatedSafe *asafe = NULL;
00310     SECStatus rv;
00311 
00312     if(pfx == NULL) {
00313        return NULL;
00314     }
00315 
00316     der_asafe = SEC_PKCS7GetContent(&pfx->authSafe);
00317     if(der_asafe == NULL) {
00318        /* XXX set error ? */
00319        goto loser;
00320     }
00321 
00322     asafe = sec_pkcs12_new_asafe(pfx->poolp);
00323     if(asafe == NULL) {
00324        goto loser;
00325     }
00326 
00327     if(pfx->old == PR_FALSE) {
00328        rv = SEC_ASN1DecodeItem(pfx->poolp, asafe, 
00329                             SEC_PKCS12AuthenticatedSafeTemplate, 
00330                             der_asafe);
00331        asafe->old = PR_FALSE;
00332        asafe->swapUnicode = pfx->swapUnicode;
00333     } else {
00334        /* handle beta exported files */
00335        rv = SEC_ASN1DecodeItem(pfx->poolp, asafe, 
00336                             SEC_PKCS12AuthenticatedSafeTemplate_OLD,
00337                             der_asafe);
00338        asafe->safe = &(asafe->old_safe);
00339        rv = sec_pkcs12_convert_old_auth_safe(asafe);
00340        asafe->old = PR_TRUE;
00341     }
00342 
00343     if(rv != SECSuccess) {
00344        goto loser;
00345     }
00346 
00347     asafe->poolp = pfx->poolp;
00348     
00349     return asafe;
00350 
00351 loser:
00352     return NULL;
00353 }
00354 
00355 /* validates the safe within the authenticated safe item.  
00356  * in order to be valid:
00357  *  1.  the privacy salt must be present
00358  *  2.  the encryption algorithm must be supported (including
00359  *     export policy)
00360  * PR_FALSE indicates an error, PR_TRUE indicates a valid safe
00361  */
00362 static PRBool 
00363 sec_pkcs12_validate_encrypted_safe(SEC_PKCS12AuthenticatedSafe *asafe)
00364 {
00365     PRBool valid = PR_FALSE;
00366     SECAlgorithmID *algid;
00367 
00368     if(asafe == NULL) {
00369        return PR_FALSE;
00370     }
00371 
00372     /* if mode is password privacy, then privacySalt is assumed
00373      * to be non-zero.
00374      */
00375     if(asafe->privacySalt.len != 0) {
00376        valid = PR_TRUE;
00377        asafe->privacySalt.len /= 8;
00378     } else {
00379        PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
00380        return PR_FALSE;
00381     }
00382 
00383     /* until spec changes, content will have between 2 and 8 bytes depending
00384      * upon the algorithm used if certs are unencrypted...
00385      * also want to support case where content is empty -- which we produce 
00386      */ 
00387     if(SEC_PKCS7IsContentEmpty(asafe->safe, 8) == PR_TRUE) {
00388        asafe->emptySafe = PR_TRUE;
00389        return PR_TRUE;
00390     }
00391 
00392     asafe->emptySafe = PR_FALSE;
00393 
00394     /* make sure that a pbe algorithm is being used */
00395     algid = SEC_PKCS7GetEncryptionAlgorithm(asafe->safe);
00396     if(algid != NULL) {
00397        if(SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
00398            valid = SEC_PKCS12DecryptionAllowed(algid);
00399 
00400            if(valid == PR_FALSE) {
00401               PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM);
00402            }
00403        } else {
00404            PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM);
00405            valid = PR_FALSE;
00406        }
00407     } else {
00408        valid = PR_FALSE;
00409        PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM);
00410     }
00411 
00412     return valid;
00413 }
00414 
00415 /* validates authenticates safe:
00416  *  1.  checks that the version is supported
00417  *  2.  checks that only password privacy mode is used (currently)
00418  *  3.  further, makes sure safe has appropriate policies per above function
00419  * PR_FALSE indicates failure.
00420  */
00421 static PRBool 
00422 sec_pkcs12_validate_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe)
00423 {
00424     PRBool valid = PR_TRUE;
00425     SECOidTag safe_type;
00426     int version;
00427 
00428     if(asafe == NULL) {
00429        return PR_FALSE;
00430     }
00431 
00432     /* check version, since it is default it may not be present.
00433      * therefore, assume ok
00434      */
00435     if((asafe->version.len > 0) && (asafe->old == PR_FALSE)) {
00436        version = DER_GetInteger(&asafe->version);
00437        if(version > SEC_PKCS12_PFX_VERSION) {
00438            PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_VERSION);
00439            return PR_FALSE;
00440        }
00441     }
00442 
00443     /* validate password mode is being used */
00444     safe_type = SEC_PKCS7ContentType(asafe->safe);
00445     switch(safe_type)
00446     {
00447        case SEC_OID_PKCS7_ENCRYPTED_DATA:
00448            valid = sec_pkcs12_validate_encrypted_safe(asafe);
00449            break;
00450        case SEC_OID_PKCS7_ENVELOPED_DATA:
00451        default:
00452            PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE);
00453            valid = PR_FALSE;
00454            break;
00455     }
00456 
00457     return valid;
00458 }
00459 
00460 /* retrieves the authenticated safe item from the PFX item
00461  *  before returning the authenticated safe, the validity of the
00462  *  authenticated safe is checked and if valid, returned.
00463  * a return of NULL indicates that an error occured.
00464  */
00465 static SEC_PKCS12AuthenticatedSafe *
00466 sec_pkcs12_get_auth_safe(SEC_PKCS12PFXItem *pfx)
00467 {
00468     SEC_PKCS12AuthenticatedSafe *asafe;
00469     PRBool valid_safe;
00470 
00471     if(pfx == NULL) {
00472        return NULL;
00473     }
00474 
00475     asafe = sec_pkcs12_decode_authenticated_safe(pfx);
00476     if(asafe == NULL) {
00477        return NULL;
00478     }
00479 
00480     valid_safe = sec_pkcs12_validate_auth_safe(asafe);
00481     if(valid_safe != PR_TRUE) {
00482        asafe = NULL;
00483     } else if(asafe) {
00484        asafe->baggage.poolp = asafe->poolp;
00485     }
00486 
00487     return asafe;
00488 }
00489 
00490 /* decrypts the authenticated safe.
00491  * a return of anything but SECSuccess indicates an error.  the
00492  * password is not known to be valid until the call to the 
00493  * function sec_pkcs12_get_safe_contents.  If decoding the safe
00494  * fails, it is assumed the password was incorrect and the error
00495  * is set then.  any failure here is assumed to be due to 
00496  * internal problems in SEC_PKCS7DecryptContents or below.
00497  */
00498 static SECStatus
00499 sec_pkcs12_decrypt_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe, 
00500                           SECItem *pwitem,
00501                           void *wincx)
00502 {
00503     SECStatus rv = SECFailure;
00504     SECItem *vpwd = NULL;
00505 
00506     if((asafe == NULL) || (pwitem == NULL)) {
00507        return SECFailure;
00508     }
00509 
00510     if(asafe->old == PR_FALSE) {
00511        vpwd = sec_pkcs12_create_virtual_password(pwitem, &asafe->privacySalt,
00512                                            asafe->swapUnicode);
00513        if(vpwd == NULL) {
00514            return SECFailure;
00515        }
00516     }
00517 
00518     rv = SEC_PKCS7DecryptContents(asafe->poolp, asafe->safe, 
00519                               (asafe->old ? pwitem : vpwd), wincx);
00520 
00521     if(asafe->old == PR_FALSE) {
00522        SECITEM_ZfreeItem(vpwd, PR_TRUE);
00523     }
00524 
00525     return rv;
00526 }
00527 
00528 /* extract the safe from the authenticated safe.
00529  *  if we are unable to decode the safe, then it is likely that the 
00530  *  safe has not been decrypted or the password used to decrypt
00531  *  the safe was invalid.  we assume that the password was invalid and
00532  *  set an error accordingly.
00533  * a return of NULL indicates that an error occurred.
00534  */
00535 static SEC_PKCS12SafeContents *
00536 sec_pkcs12_get_safe_contents(SEC_PKCS12AuthenticatedSafe *asafe)
00537 {
00538     SECItem *src = NULL;
00539     SEC_PKCS12SafeContents *safe = NULL;
00540     SECStatus rv = SECFailure;
00541 
00542     if(asafe == NULL) {
00543        return NULL;
00544     }
00545 
00546     safe = (SEC_PKCS12SafeContents *)PORT_ArenaZAlloc(asafe->poolp, 
00547                                           sizeof(SEC_PKCS12SafeContents));
00548     if(safe == NULL) {
00549        return NULL;
00550     }
00551     safe->poolp = asafe->poolp;
00552     safe->old = asafe->old;
00553     safe->swapUnicode = asafe->swapUnicode;
00554 
00555     src = SEC_PKCS7GetContent(asafe->safe);
00556     if(src != NULL) {
00557        const SEC_ASN1Template *theTemplate;
00558        if(asafe->old != PR_TRUE) {
00559            theTemplate = SEC_PKCS12SafeContentsTemplate;
00560        } else {
00561            theTemplate = SEC_PKCS12SafeContentsTemplate_OLD;
00562        }
00563 
00564        rv = SEC_ASN1DecodeItem(asafe->poolp, safe, theTemplate, src);
00565 
00566        /* if we could not decode the item, password was probably invalid */
00567        if(rv != SECSuccess) {
00568            safe = NULL;
00569            PORT_SetError(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT);
00570        }
00571     } else {
00572        PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
00573        rv = SECFailure;
00574     }
00575 
00576     return safe;
00577 }
00578 
00579 /* import PFX item 
00580  * der_pfx is the der encoded pfx structure
00581  * pbef and pbearg are the integrity/encryption password call back
00582  * ncCall is the nickname collision calllback
00583  * slot is the destination token
00584  * wincx window handler
00585  *
00586  * on error, error code set and SECFailure returned 
00587  */
00588 SECStatus
00589 SEC_PKCS12PutPFX(SECItem *der_pfx, SECItem *pwitem,
00590                SEC_PKCS12NicknameCollisionCallback ncCall,
00591                PK11SlotInfo *slot,
00592                void *wincx)
00593 {
00594     SEC_PKCS12PFXItem *pfx;
00595     SEC_PKCS12AuthenticatedSafe *asafe;
00596     SEC_PKCS12SafeContents *safe_contents = NULL;
00597     SECStatus rv;
00598 
00599     if(!der_pfx || !pwitem || !slot) {
00600        return SECFailure;
00601     }
00602 
00603     /* decode and validate each section */
00604     rv = SECFailure;
00605 
00606     pfx = sec_pkcs12_get_pfx(der_pfx, pwitem);
00607     if(pfx != NULL) {
00608        asafe = sec_pkcs12_get_auth_safe(pfx);
00609        if(asafe != NULL) {
00610 
00611            /* decrypt safe -- only if not empty */
00612            if(asafe->emptySafe != PR_TRUE) {
00613               rv = sec_pkcs12_decrypt_auth_safe(asafe, pwitem, wincx);
00614               if(rv == SECSuccess) {
00615                   safe_contents = sec_pkcs12_get_safe_contents(asafe);
00616                   if(safe_contents == NULL) {
00617                      rv = SECFailure;
00618                   }
00619               }
00620            } else {
00621               safe_contents = sec_pkcs12_create_safe_contents(asafe->poolp);
00622               safe_contents->swapUnicode = pfx->swapUnicode;
00623               if(safe_contents == NULL) {
00624                   rv = SECFailure;
00625               } else {
00626                   rv = SECSuccess;
00627               }
00628            }
00629 
00630            /* get safe contents and begin import */
00631            if(rv == SECSuccess) {
00632               SEC_PKCS12DecoderContext *p12dcx;
00633 
00634               p12dcx = sec_PKCS12ConvertOldSafeToNew(pfx->poolp, slot,
00635                                    pfx->swapUnicode,
00636                                    pwitem, wincx, safe_contents,
00637                                    &asafe->baggage);
00638               if(!p12dcx) {
00639                   rv = SECFailure;
00640                   goto loser;
00641               }
00642 
00643               if(SEC_PKCS12DecoderValidateBags(p12dcx, ncCall) 
00644                             != SECSuccess) {
00645                   rv = SECFailure;
00646                   goto loser;
00647               }
00648 
00649               rv = SEC_PKCS12DecoderImportBags(p12dcx);
00650            }
00651 
00652        }
00653     }
00654 
00655 loser:
00656 
00657     if(pfx) {
00658        SEC_PKCS12DestroyPFX(pfx);
00659     }
00660 
00661     return rv;
00662 }
00663 
00664 PRBool 
00665 SEC_PKCS12ValidData(char *buf, int bufLen, long int totalLength)
00666 {
00667     int lengthLength;
00668 
00669     PRBool valid = PR_FALSE;
00670 
00671     if(buf == NULL) {
00672        return PR_FALSE;
00673     }
00674 
00675     /* check for constructed sequence identifier tag */
00676     if(*buf == (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) {
00677        totalLength--;   /* header byte taken care of */
00678        buf++;
00679 
00680        lengthLength = (long int)SEC_ASN1LengthLength(totalLength - 1);
00681        if(totalLength > 0x7f) {
00682            lengthLength--;
00683            *buf &= 0x7f;  /* remove bit 8 indicator */
00684            if((*buf - (char)lengthLength) == 0) {
00685               valid = PR_TRUE;
00686            }
00687        } else {
00688            lengthLength--;
00689            if((*buf - (char)lengthLength) == 0) {
00690               valid = PR_TRUE;
00691            }
00692        }
00693     }
00694 
00695     return valid;
00696 }