summaryrefslogtreecommitdiff
path: root/security/nss/lib/pkcs12/p12dec.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/pkcs12/p12dec.c')
-rw-r--r--security/nss/lib/pkcs12/p12dec.c696
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;
-}