michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "pkcs12.h" michael@0: #include "plarena.h" michael@0: #include "secpkcs7.h" michael@0: #include "p12local.h" michael@0: #include "secoid.h" michael@0: #include "secitem.h" michael@0: #include "secport.h" michael@0: #include "secasn1.h" michael@0: #include "secder.h" michael@0: #include "secerr.h" michael@0: #include "cert.h" michael@0: #include "certdb.h" michael@0: #include "p12plcy.h" michael@0: #include "p12.h" michael@0: #include "secpkcs5.h" michael@0: michael@0: /* PFX extraction and validation routines */ michael@0: michael@0: /* decode the DER encoded PFX item. if unable to decode, check to see if it michael@0: * is an older PFX item. If that fails, assume the file was not a valid michael@0: * pfx file. michael@0: * the returned pfx structure should be destroyed using SEC_PKCS12DestroyPFX michael@0: */ michael@0: static SEC_PKCS12PFXItem * michael@0: sec_pkcs12_decode_pfx(SECItem *der_pfx) michael@0: { michael@0: SEC_PKCS12PFXItem *pfx; michael@0: SECStatus rv; michael@0: michael@0: if(der_pfx == NULL) { michael@0: return NULL; michael@0: } michael@0: michael@0: /* allocate the space for a new PFX item */ michael@0: pfx = sec_pkcs12_new_pfx(); michael@0: if(pfx == NULL) { michael@0: return NULL; michael@0: } michael@0: michael@0: rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate, michael@0: der_pfx); michael@0: michael@0: /* if a failure occurred, check for older version... michael@0: * we also get rid of the old pfx structure, because we don't michael@0: * know where it failed and what data in may contain michael@0: */ michael@0: if(rv != SECSuccess) { michael@0: SEC_PKCS12DestroyPFX(pfx); michael@0: pfx = sec_pkcs12_new_pfx(); michael@0: if(pfx == NULL) { michael@0: return NULL; michael@0: } michael@0: rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate_OLD, michael@0: der_pfx); michael@0: if(rv != SECSuccess) { michael@0: PORT_SetError(SEC_ERROR_PKCS12_DECODING_PFX); michael@0: PORT_FreeArena(pfx->poolp, PR_TRUE); michael@0: return NULL; michael@0: } michael@0: pfx->old = PR_TRUE; michael@0: SGN_CopyDigestInfo(pfx->poolp, &pfx->macData.safeMac, &pfx->old_safeMac); michael@0: SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, &pfx->old_macSalt); michael@0: } else { michael@0: pfx->old = PR_FALSE; michael@0: } michael@0: michael@0: /* convert bit string from bits to bytes */ michael@0: pfx->macData.macSalt.len /= 8; michael@0: michael@0: return pfx; michael@0: } michael@0: michael@0: /* validate the integrity MAC used in the PFX. The MAC is generated michael@0: * per the PKCS 12 document. If the MAC is incorrect, it is most likely michael@0: * due to an invalid password. michael@0: * pwitem is the integrity password michael@0: * pfx is the decoded pfx item michael@0: */ michael@0: static PRBool michael@0: sec_pkcs12_check_pfx_mac(SEC_PKCS12PFXItem *pfx, michael@0: SECItem *pwitem) michael@0: { michael@0: SECItem *key = NULL, *mac = NULL, *data = NULL; michael@0: SECItem *vpwd = NULL; michael@0: SECOidTag algorithm; michael@0: PRBool ret = PR_FALSE; michael@0: michael@0: if(pfx == NULL) { michael@0: return PR_FALSE; michael@0: } michael@0: michael@0: algorithm = SECOID_GetAlgorithmTag(&pfx->macData.safeMac.digestAlgorithm); michael@0: switch(algorithm) { michael@0: /* only SHA1 hashing supported as a MACing algorithm */ michael@0: case SEC_OID_SHA1: michael@0: if(pfx->old == PR_FALSE) { michael@0: pfx->swapUnicode = PR_FALSE; michael@0: } michael@0: michael@0: recheckUnicodePassword: michael@0: vpwd = sec_pkcs12_create_virtual_password(pwitem, michael@0: &pfx->macData.macSalt, michael@0: pfx->swapUnicode); michael@0: if(vpwd == NULL) { michael@0: return PR_FALSE; michael@0: } michael@0: michael@0: key = sec_pkcs12_generate_key_from_password(algorithm, michael@0: &pfx->macData.macSalt, michael@0: (pfx->old ? pwitem : vpwd)); michael@0: /* free vpwd only for newer PFX */ michael@0: if(vpwd) { michael@0: SECITEM_ZfreeItem(vpwd, PR_TRUE); michael@0: } michael@0: if(key == NULL) { michael@0: return PR_FALSE; michael@0: } michael@0: michael@0: data = SEC_PKCS7GetContent(&pfx->authSafe); michael@0: if(data == NULL) { michael@0: break; michael@0: } michael@0: michael@0: /* check MAC */ michael@0: mac = sec_pkcs12_generate_mac(key, data, pfx->old); michael@0: ret = PR_TRUE; michael@0: if(mac) { michael@0: SECItem *safeMac = &pfx->macData.safeMac.digest; michael@0: if(SECITEM_CompareItem(mac, safeMac) != SECEqual) { michael@0: michael@0: /* if we encounter an invalid mac, lets invert the michael@0: * password in case of unicode changes michael@0: */ michael@0: if(((!pfx->old) && pfx->swapUnicode) || (pfx->old)){ michael@0: PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC); michael@0: ret = PR_FALSE; michael@0: } else { michael@0: SECITEM_ZfreeItem(mac, PR_TRUE); michael@0: pfx->swapUnicode = PR_TRUE; michael@0: goto recheckUnicodePassword; michael@0: } michael@0: } michael@0: SECITEM_ZfreeItem(mac, PR_TRUE); michael@0: } else { michael@0: ret = PR_FALSE; michael@0: } michael@0: break; michael@0: default: michael@0: PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM); michael@0: ret = PR_FALSE; michael@0: break; michael@0: } michael@0: michael@0: /* let success fall through */ michael@0: if(key != NULL) michael@0: SECITEM_ZfreeItem(key, PR_TRUE); michael@0: michael@0: return ret; michael@0: } michael@0: michael@0: /* check the validity of the pfx structure. we currently only support michael@0: * password integrity mode, so we check the MAC. michael@0: */ michael@0: static PRBool michael@0: sec_pkcs12_validate_pfx(SEC_PKCS12PFXItem *pfx, michael@0: SECItem *pwitem) michael@0: { michael@0: SECOidTag contentType; michael@0: michael@0: contentType = SEC_PKCS7ContentType(&pfx->authSafe); michael@0: switch(contentType) michael@0: { michael@0: case SEC_OID_PKCS7_DATA: michael@0: return sec_pkcs12_check_pfx_mac(pfx, pwitem); michael@0: break; michael@0: case SEC_OID_PKCS7_SIGNED_DATA: michael@0: default: michael@0: PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE); michael@0: break; michael@0: } michael@0: michael@0: return PR_FALSE; michael@0: } michael@0: michael@0: /* decode and return the valid PFX. if the PFX item is not valid, michael@0: * NULL is returned. michael@0: */ michael@0: static SEC_PKCS12PFXItem * michael@0: sec_pkcs12_get_pfx(SECItem *pfx_data, michael@0: SECItem *pwitem) michael@0: { michael@0: SEC_PKCS12PFXItem *pfx; michael@0: PRBool valid_pfx; michael@0: michael@0: if((pfx_data == NULL) || (pwitem == NULL)) { michael@0: return NULL; michael@0: } michael@0: michael@0: pfx = sec_pkcs12_decode_pfx(pfx_data); michael@0: if(pfx == NULL) { michael@0: return NULL; michael@0: } michael@0: michael@0: valid_pfx = sec_pkcs12_validate_pfx(pfx, pwitem); michael@0: if(valid_pfx != PR_TRUE) { michael@0: SEC_PKCS12DestroyPFX(pfx); michael@0: pfx = NULL; michael@0: } michael@0: michael@0: return pfx; michael@0: } michael@0: michael@0: /* authenticated safe decoding, validation, and access routines michael@0: */ michael@0: michael@0: /* convert dogbert beta 3 authenticated safe structure to a post michael@0: * beta three structure, so that we don't have to change more routines. michael@0: */ michael@0: static SECStatus michael@0: sec_pkcs12_convert_old_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe) michael@0: { michael@0: SEC_PKCS12Baggage *baggage; michael@0: SEC_PKCS12BaggageItem *bag; michael@0: SECStatus rv = SECSuccess; michael@0: michael@0: if(asafe->old_baggage.espvks == NULL) { michael@0: /* XXX should the ASN1 engine produce a single NULL element list michael@0: * rather than setting the pointer to NULL? michael@0: * There is no need to return an error -- assume that the list michael@0: * was empty. michael@0: */ michael@0: return SECSuccess; michael@0: } michael@0: michael@0: baggage = sec_pkcs12_create_baggage(asafe->poolp); michael@0: if(!baggage) { michael@0: return SECFailure; michael@0: } michael@0: bag = sec_pkcs12_create_external_bag(baggage); michael@0: if(!bag) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: PORT_Memcpy(&asafe->baggage, baggage, sizeof(SEC_PKCS12Baggage)); michael@0: michael@0: /* if there are shrouded keys, append them to the bag */ michael@0: rv = SECSuccess; michael@0: if(asafe->old_baggage.espvks[0] != NULL) { michael@0: int nEspvk = 0; michael@0: rv = SECSuccess; michael@0: while((asafe->old_baggage.espvks[nEspvk] != NULL) && michael@0: (rv == SECSuccess)) { michael@0: rv = sec_pkcs12_append_shrouded_key(bag, michael@0: asafe->old_baggage.espvks[nEspvk]); michael@0: nEspvk++; michael@0: } michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: /* decodes the authenticated safe item. a return of NULL indicates michael@0: * an error. however, the error will have occurred either in memory michael@0: * allocation or in decoding the authenticated safe. michael@0: * michael@0: * if an old PFX item has been found, we want to convert the michael@0: * old authenticated safe to the new one. michael@0: */ michael@0: static SEC_PKCS12AuthenticatedSafe * michael@0: sec_pkcs12_decode_authenticated_safe(SEC_PKCS12PFXItem *pfx) michael@0: { michael@0: SECItem *der_asafe = NULL; michael@0: SEC_PKCS12AuthenticatedSafe *asafe = NULL; michael@0: SECStatus rv; michael@0: michael@0: if(pfx == NULL) { michael@0: return NULL; michael@0: } michael@0: michael@0: der_asafe = SEC_PKCS7GetContent(&pfx->authSafe); michael@0: if(der_asafe == NULL) { michael@0: /* XXX set error ? */ michael@0: goto loser; michael@0: } michael@0: michael@0: asafe = sec_pkcs12_new_asafe(pfx->poolp); michael@0: if(asafe == NULL) { michael@0: goto loser; michael@0: } michael@0: michael@0: if(pfx->old == PR_FALSE) { michael@0: rv = SEC_ASN1DecodeItem(pfx->poolp, asafe, michael@0: SEC_PKCS12AuthenticatedSafeTemplate, michael@0: der_asafe); michael@0: asafe->old = PR_FALSE; michael@0: asafe->swapUnicode = pfx->swapUnicode; michael@0: } else { michael@0: /* handle beta exported files */ michael@0: rv = SEC_ASN1DecodeItem(pfx->poolp, asafe, michael@0: SEC_PKCS12AuthenticatedSafeTemplate_OLD, michael@0: der_asafe); michael@0: asafe->safe = &(asafe->old_safe); michael@0: rv = sec_pkcs12_convert_old_auth_safe(asafe); michael@0: asafe->old = PR_TRUE; michael@0: } michael@0: michael@0: if(rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: michael@0: asafe->poolp = pfx->poolp; michael@0: michael@0: return asafe; michael@0: michael@0: loser: michael@0: return NULL; michael@0: } michael@0: michael@0: /* validates the safe within the authenticated safe item. michael@0: * in order to be valid: michael@0: * 1. the privacy salt must be present michael@0: * 2. the encryption algorithm must be supported (including michael@0: * export policy) michael@0: * PR_FALSE indicates an error, PR_TRUE indicates a valid safe michael@0: */ michael@0: static PRBool michael@0: sec_pkcs12_validate_encrypted_safe(SEC_PKCS12AuthenticatedSafe *asafe) michael@0: { michael@0: PRBool valid = PR_FALSE; michael@0: SECAlgorithmID *algid; michael@0: michael@0: if(asafe == NULL) { michael@0: return PR_FALSE; michael@0: } michael@0: michael@0: /* if mode is password privacy, then privacySalt is assumed michael@0: * to be non-zero. michael@0: */ michael@0: if(asafe->privacySalt.len != 0) { michael@0: valid = PR_TRUE; michael@0: asafe->privacySalt.len /= 8; michael@0: } else { michael@0: PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE); michael@0: return PR_FALSE; michael@0: } michael@0: michael@0: /* until spec changes, content will have between 2 and 8 bytes depending michael@0: * upon the algorithm used if certs are unencrypted... michael@0: * also want to support case where content is empty -- which we produce michael@0: */ michael@0: if(SEC_PKCS7IsContentEmpty(asafe->safe, 8) == PR_TRUE) { michael@0: asafe->emptySafe = PR_TRUE; michael@0: return PR_TRUE; michael@0: } michael@0: michael@0: asafe->emptySafe = PR_FALSE; michael@0: michael@0: /* make sure that a pbe algorithm is being used */ michael@0: algid = SEC_PKCS7GetEncryptionAlgorithm(asafe->safe); michael@0: if(algid != NULL) { michael@0: if(SEC_PKCS5IsAlgorithmPBEAlg(algid)) { michael@0: valid = SEC_PKCS12DecryptionAllowed(algid); michael@0: michael@0: if(valid == PR_FALSE) { michael@0: PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM); michael@0: } michael@0: } else { michael@0: PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM); michael@0: valid = PR_FALSE; michael@0: } michael@0: } else { michael@0: valid = PR_FALSE; michael@0: PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM); michael@0: } michael@0: michael@0: return valid; michael@0: } michael@0: michael@0: /* validates authenticates safe: michael@0: * 1. checks that the version is supported michael@0: * 2. checks that only password privacy mode is used (currently) michael@0: * 3. further, makes sure safe has appropriate policies per above function michael@0: * PR_FALSE indicates failure. michael@0: */ michael@0: static PRBool michael@0: sec_pkcs12_validate_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe) michael@0: { michael@0: PRBool valid = PR_TRUE; michael@0: SECOidTag safe_type; michael@0: int version; michael@0: michael@0: if(asafe == NULL) { michael@0: return PR_FALSE; michael@0: } michael@0: michael@0: /* check version, since it is default it may not be present. michael@0: * therefore, assume ok michael@0: */ michael@0: if((asafe->version.len > 0) && (asafe->old == PR_FALSE)) { michael@0: version = DER_GetInteger(&asafe->version); michael@0: if(version > SEC_PKCS12_PFX_VERSION) { michael@0: PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_VERSION); michael@0: return PR_FALSE; michael@0: } michael@0: } michael@0: michael@0: /* validate password mode is being used */ michael@0: safe_type = SEC_PKCS7ContentType(asafe->safe); michael@0: switch(safe_type) michael@0: { michael@0: case SEC_OID_PKCS7_ENCRYPTED_DATA: michael@0: valid = sec_pkcs12_validate_encrypted_safe(asafe); michael@0: break; michael@0: case SEC_OID_PKCS7_ENVELOPED_DATA: michael@0: default: michael@0: PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE); michael@0: valid = PR_FALSE; michael@0: break; michael@0: } michael@0: michael@0: return valid; michael@0: } michael@0: michael@0: /* retrieves the authenticated safe item from the PFX item michael@0: * before returning the authenticated safe, the validity of the michael@0: * authenticated safe is checked and if valid, returned. michael@0: * a return of NULL indicates that an error occurred. michael@0: */ michael@0: static SEC_PKCS12AuthenticatedSafe * michael@0: sec_pkcs12_get_auth_safe(SEC_PKCS12PFXItem *pfx) michael@0: { michael@0: SEC_PKCS12AuthenticatedSafe *asafe; michael@0: PRBool valid_safe; michael@0: michael@0: if(pfx == NULL) { michael@0: return NULL; michael@0: } michael@0: michael@0: asafe = sec_pkcs12_decode_authenticated_safe(pfx); michael@0: if(asafe == NULL) { michael@0: return NULL; michael@0: } michael@0: michael@0: valid_safe = sec_pkcs12_validate_auth_safe(asafe); michael@0: if(valid_safe != PR_TRUE) { michael@0: asafe = NULL; michael@0: } else if(asafe) { michael@0: asafe->baggage.poolp = asafe->poolp; michael@0: } michael@0: michael@0: return asafe; michael@0: } michael@0: michael@0: /* decrypts the authenticated safe. michael@0: * a return of anything but SECSuccess indicates an error. the michael@0: * password is not known to be valid until the call to the michael@0: * function sec_pkcs12_get_safe_contents. If decoding the safe michael@0: * fails, it is assumed the password was incorrect and the error michael@0: * is set then. any failure here is assumed to be due to michael@0: * internal problems in SEC_PKCS7DecryptContents or below. michael@0: */ michael@0: static SECStatus michael@0: sec_pkcs12_decrypt_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe, michael@0: SECItem *pwitem, michael@0: void *wincx) michael@0: { michael@0: SECStatus rv = SECFailure; michael@0: SECItem *vpwd = NULL; michael@0: michael@0: if((asafe == NULL) || (pwitem == NULL)) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: if(asafe->old == PR_FALSE) { michael@0: vpwd = sec_pkcs12_create_virtual_password(pwitem, &asafe->privacySalt, michael@0: asafe->swapUnicode); michael@0: if(vpwd == NULL) { michael@0: return SECFailure; michael@0: } michael@0: } michael@0: michael@0: rv = SEC_PKCS7DecryptContents(asafe->poolp, asafe->safe, michael@0: (asafe->old ? pwitem : vpwd), wincx); michael@0: michael@0: if(asafe->old == PR_FALSE) { michael@0: SECITEM_ZfreeItem(vpwd, PR_TRUE); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: /* extract the safe from the authenticated safe. michael@0: * if we are unable to decode the safe, then it is likely that the michael@0: * safe has not been decrypted or the password used to decrypt michael@0: * the safe was invalid. we assume that the password was invalid and michael@0: * set an error accordingly. michael@0: * a return of NULL indicates that an error occurred. michael@0: */ michael@0: static SEC_PKCS12SafeContents * michael@0: sec_pkcs12_get_safe_contents(SEC_PKCS12AuthenticatedSafe *asafe) michael@0: { michael@0: SECItem *src = NULL; michael@0: SEC_PKCS12SafeContents *safe = NULL; michael@0: SECStatus rv = SECFailure; michael@0: michael@0: if(asafe == NULL) { michael@0: return NULL; michael@0: } michael@0: michael@0: safe = (SEC_PKCS12SafeContents *)PORT_ArenaZAlloc(asafe->poolp, michael@0: sizeof(SEC_PKCS12SafeContents)); michael@0: if(safe == NULL) { michael@0: return NULL; michael@0: } michael@0: safe->poolp = asafe->poolp; michael@0: safe->old = asafe->old; michael@0: safe->swapUnicode = asafe->swapUnicode; michael@0: michael@0: src = SEC_PKCS7GetContent(asafe->safe); michael@0: if(src != NULL) { michael@0: const SEC_ASN1Template *theTemplate; michael@0: if(asafe->old != PR_TRUE) { michael@0: theTemplate = SEC_PKCS12SafeContentsTemplate; michael@0: } else { michael@0: theTemplate = SEC_PKCS12SafeContentsTemplate_OLD; michael@0: } michael@0: michael@0: rv = SEC_ASN1DecodeItem(asafe->poolp, safe, theTemplate, src); michael@0: michael@0: /* if we could not decode the item, password was probably invalid */ michael@0: if(rv != SECSuccess) { michael@0: safe = NULL; michael@0: PORT_SetError(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT); michael@0: } michael@0: } else { michael@0: PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE); michael@0: rv = SECFailure; michael@0: } michael@0: michael@0: return safe; michael@0: } michael@0: michael@0: /* import PFX item michael@0: * der_pfx is the der encoded pfx structure michael@0: * pbef and pbearg are the integrity/encryption password call back michael@0: * ncCall is the nickname collision calllback michael@0: * slot is the destination token michael@0: * wincx window handler michael@0: * michael@0: * on error, error code set and SECFailure returned michael@0: */ michael@0: SECStatus michael@0: SEC_PKCS12PutPFX(SECItem *der_pfx, SECItem *pwitem, michael@0: SEC_PKCS12NicknameCollisionCallback ncCall, michael@0: PK11SlotInfo *slot, michael@0: void *wincx) michael@0: { michael@0: SEC_PKCS12PFXItem *pfx; michael@0: SEC_PKCS12AuthenticatedSafe *asafe; michael@0: SEC_PKCS12SafeContents *safe_contents = NULL; michael@0: SECStatus rv; michael@0: michael@0: if(!der_pfx || !pwitem || !slot) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: /* decode and validate each section */ michael@0: rv = SECFailure; michael@0: michael@0: pfx = sec_pkcs12_get_pfx(der_pfx, pwitem); michael@0: if(pfx != NULL) { michael@0: asafe = sec_pkcs12_get_auth_safe(pfx); michael@0: if(asafe != NULL) { michael@0: michael@0: /* decrypt safe -- only if not empty */ michael@0: if(asafe->emptySafe != PR_TRUE) { michael@0: rv = sec_pkcs12_decrypt_auth_safe(asafe, pwitem, wincx); michael@0: if(rv == SECSuccess) { michael@0: safe_contents = sec_pkcs12_get_safe_contents(asafe); michael@0: if(safe_contents == NULL) { michael@0: rv = SECFailure; michael@0: } michael@0: } michael@0: } else { michael@0: safe_contents = sec_pkcs12_create_safe_contents(asafe->poolp); michael@0: if(safe_contents == NULL) { michael@0: rv = SECFailure; michael@0: } else { michael@0: safe_contents->swapUnicode = pfx->swapUnicode; michael@0: rv = SECSuccess; michael@0: } michael@0: } michael@0: michael@0: /* get safe contents and begin import */ michael@0: if(rv == SECSuccess) { michael@0: SEC_PKCS12DecoderContext *p12dcx; michael@0: michael@0: p12dcx = sec_PKCS12ConvertOldSafeToNew(pfx->poolp, slot, michael@0: pfx->swapUnicode, michael@0: pwitem, wincx, safe_contents, michael@0: &asafe->baggage); michael@0: if(!p12dcx) { michael@0: rv = SECFailure; michael@0: goto loser; michael@0: } michael@0: michael@0: if(SEC_PKCS12DecoderValidateBags(p12dcx, ncCall) michael@0: != SECSuccess) { michael@0: rv = SECFailure; michael@0: goto loser; michael@0: } michael@0: michael@0: rv = SEC_PKCS12DecoderImportBags(p12dcx); michael@0: } michael@0: michael@0: } michael@0: } michael@0: michael@0: loser: michael@0: michael@0: if(pfx) { michael@0: SEC_PKCS12DestroyPFX(pfx); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: PRBool michael@0: SEC_PKCS12ValidData(char *buf, int bufLen, long int totalLength) michael@0: { michael@0: int lengthLength; michael@0: michael@0: PRBool valid = PR_FALSE; michael@0: michael@0: if(buf == NULL) { michael@0: return PR_FALSE; michael@0: } michael@0: michael@0: /* check for constructed sequence identifier tag */ michael@0: if(*buf == (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) { michael@0: totalLength--; /* header byte taken care of */ michael@0: buf++; michael@0: michael@0: lengthLength = (long int)SEC_ASN1LengthLength(totalLength - 1); michael@0: if(totalLength > 0x7f) { michael@0: lengthLength--; michael@0: *buf &= 0x7f; /* remove bit 8 indicator */ michael@0: if((*buf - (char)lengthLength) == 0) { michael@0: valid = PR_TRUE; michael@0: } michael@0: } else { michael@0: lengthLength--; michael@0: if((*buf - (char)lengthLength) == 0) { michael@0: valid = PR_TRUE; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return valid; michael@0: }