p12dec.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 693 行 · 第 1/2 页

C
693
字号
/* * 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 Netscape are  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#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"/* 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 SECStatussec_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:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?