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