p12d.c

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

C
2,435
字号
/* * 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 "p12t.h"#include "p12.h"#include "plarena.h"#include "secitem.h"#include "secoid.h"#include "seccomon.h"#include "secport.h"#include "cert.h"#include "secpkcs7.h"#include "secasn1.h"#include "secerr.h"#include "pk11func.h"#include "p12plcy.h"#include "p12local.h"#include "alghmac.h"#include "secder.h"#include "secport.h"#include "certdb.h"#include "prcpucfg.h"typedef struct sec_PKCS12SafeContentsContextStr sec_PKCS12SafeContentsContext;/* Opaque structure for decoding SafeContents.  These are used * for each authenticated safe as well as any nested safe contents. */struct sec_PKCS12SafeContentsContextStr {    /* the parent decoder context */    SEC_PKCS12DecoderContext *p12dcx;    /* memory arena to allocate space from */    PRArenaPool *arena;    /* decoder context and destination for decoding safe contents */    SEC_ASN1DecoderContext *safeContentsDcx;    sec_PKCS12SafeContents safeContents;    /* information for decoding safe bags within the safe contents.     * these variables are updated for each safe bag decoded.     */    SEC_ASN1DecoderContext *currentSafeBagDcx;    sec_PKCS12SafeBag *currentSafeBag;    PRBool skipCurrentSafeBag;    /* if the safe contents is nested, the parent is pointed to here. */    sec_PKCS12SafeContentsContext *nestedCtx;};/* opaque decoder context structure.  information for decoding a pkcs 12 * PDU are stored here as well as decoding pointers for intermediary  * structures which are part of the PKCS 12 PDU.  Upon a successful * decode, the safe bags containing certificates and keys encountered. */  struct SEC_PKCS12DecoderContextStr {    PRArenaPool *arena;    PK11SlotInfo *slot;    void *wincx;    PRBool error;    int errorValue;    /* password */    SECItem *pwitem;    /* used for decoding the PFX structure */    SEC_ASN1DecoderContext *pfxDcx;    sec_PKCS12PFXItem pfx;    /* safe bags found during decoding */      sec_PKCS12SafeBag **safeBags;    unsigned int safeBagCount;    /* state variables for decoding authenticated safes. */    SEC_PKCS7DecoderContext *currentASafeP7Dcx;    SEC_PKCS5KeyAndPassword *currentASafeKeyPwd;    SEC_ASN1DecoderContext *aSafeDcx;    SEC_PKCS7DecoderContext *aSafeP7Dcx;    sec_PKCS12AuthenticatedSafe authSafe;    SEC_PKCS7ContentInfo *aSafeCinfo;    sec_PKCS12SafeContents safeContents;    /* safe contents info */    unsigned int safeContentsCnt;    sec_PKCS12SafeContentsContext **safeContentsList;    /* HMAC info */    sec_PKCS12MacData	macData;    SEC_ASN1DecoderContext *hmacDcx;    /* routines for reading back the data to be hmac'd */    digestOpenFn dOpen;    digestCloseFn dClose;    digestIOFn dRead, dWrite;    void *dArg;    /* helper functions */    SECKEYGetPasswordKey pwfn;    void *pwfnarg;    PRBool swapUnicodeBytes;    /* import information */    PRBool bagsVerified;};/* make sure that the PFX version being decoded is a version * which we support. */static PRBoolsec_pkcs12_proper_version(sec_PKCS12PFXItem *pfx){    /* if no version, assume it is not supported */    if(pfx->version.len == 0) {	return PR_FALSE;    }    if(DER_GetInteger(&pfx->version) > SEC_PKCS12_VERSION) {	return PR_FALSE;    }    return PR_TRUE;}/* retrieve the key for decrypting the safe contents */ static PK11SymKey *sec_pkcs12_decoder_get_decrypt_key(void *arg, SECAlgorithmID *algid){    SEC_PKCS5KeyAndPassword *keyPwd =         (SEC_PKCS5KeyAndPassword *)arg;    if(!keyPwd) {	return NULL;    }    /* if no slot specified, use the internal key slot */    if(!keyPwd->slot) {	keyPwd->slot = PK11_GetInternalKeySlot();    }    /* retrieve the key */    if(!keyPwd->key) {	keyPwd->key = PK11_PBEKeyGen(keyPwd->slot, algid, 				     keyPwd->pwitem, PR_FALSE, keyPwd->wincx);    }    return (PK11SymKey *)keyPwd;}/* XXX this needs to be modified to handle enveloped data.  most * likely, it should mirror the routines for SMIME in that regard. */static PRBoolsec_pkcs12_decoder_decryption_allowed(SECAlgorithmID *algid, 				      PK11SymKey *bulkkey){    PRBool decryptionAllowed = SEC_PKCS12DecryptionAllowed(algid);    if(!decryptionAllowed) {	return PR_FALSE;    }    return PR_TRUE;}/* when we encounter a new safe bag during the decoding, we need * to allocate space for the bag to be decoded to and set the  * state variables appropriately.  all of the safe bags are allocated * in a buffer in the outer SEC_PKCS12DecoderContext, however, * a pointer to the safeBag is also used in the sec_PKCS12SafeContentsContext * for the current bag. */static SECStatussec_pkcs12_decoder_init_new_safe_bag(sec_PKCS12SafeContentsContext 						*safeContentsCtx){    void *mark = NULL;    SEC_PKCS12DecoderContext *p12dcx;    /* make sure that the structures are defined, and there has     * not been an error in the decoding      */    if(!safeContentsCtx || !safeContentsCtx->p12dcx 		|| safeContentsCtx->p12dcx->error) {	return SECFailure;    }    p12dcx = safeContentsCtx->p12dcx;    mark = PORT_ArenaMark(p12dcx->arena);    /* allocate a new safe bag, if bags already exist, grow the      * list of bags, otherwise allocate a new list.  the list is     * NULL terminated.     */    if(p12dcx->safeBagCount) {	p12dcx->safeBags = 	    (sec_PKCS12SafeBag**)PORT_ArenaGrow(p12dcx->arena,p12dcx->safeBags,			(p12dcx->safeBagCount + 1) * sizeof(sec_PKCS12SafeBag *),			(p12dcx->safeBagCount + 2) * sizeof(sec_PKCS12SafeBag *));    } else {	p12dcx->safeBags = (sec_PKCS12SafeBag**)PORT_ArenaZAlloc(p12dcx->arena,					    2 * sizeof(sec_PKCS12SafeBag *));    }    if(!p12dcx->safeBags) {	p12dcx->errorValue = SEC_ERROR_NO_MEMORY;	goto loser;    }    /* append the bag to the end of the list and update the reference     * in the safeContentsCtx.     */    p12dcx->safeBags[p12dcx->safeBagCount] =         (sec_PKCS12SafeBag*)PORT_ArenaZAlloc(p12dcx->arena,					     sizeof(sec_PKCS12SafeBag));    safeContentsCtx->currentSafeBag = p12dcx->safeBags[p12dcx->safeBagCount];    p12dcx->safeBags[++p12dcx->safeBagCount] = NULL;    if(!safeContentsCtx->currentSafeBag) {	p12dcx->errorValue = SEC_ERROR_NO_MEMORY;	goto loser;    }    safeContentsCtx->currentSafeBag->slot = safeContentsCtx->p12dcx->slot;    safeContentsCtx->currentSafeBag->pwitem = safeContentsCtx->p12dcx->pwitem;    safeContentsCtx->currentSafeBag->swapUnicodeBytes = 				safeContentsCtx->p12dcx->swapUnicodeBytes;    safeContentsCtx->currentSafeBag->arena = safeContentsCtx->p12dcx->arena;    PORT_ArenaUnmark(p12dcx->arena, mark);    return SECSuccess;loser:    /* if an error occurred, release the memory and set the error flag     * the only possible errors triggered by this function are memory      * related.     */    if(mark) {	PORT_ArenaRelease(p12dcx->arena, mark);    }    p12dcx->error = PR_TRUE;    return SECFailure;}/* A wrapper for updating the ASN1 context in which a safeBag is * being decoded.  This function is called as a callback from * secasn1d when decoding SafeContents structures. */static voidsec_pkcs12_decoder_safe_bag_update(void *arg, const char *data, 				   unsigned long len, int depth, 				   SEC_ASN1EncodingPart data_kind){    sec_PKCS12SafeContentsContext *safeContentsCtx =         (sec_PKCS12SafeContentsContext *)arg;    SEC_PKCS12DecoderContext *p12dcx;    SECStatus rv;    /* make sure that we are not skipping the current safeBag,     * and that there are no errors.  If so, just return rather     * than continuing to process.     */    if(!safeContentsCtx || !safeContentsCtx->p12dcx 		|| safeContentsCtx->p12dcx->error 		|| safeContentsCtx->skipCurrentSafeBag) {	return;    }    p12dcx = safeContentsCtx->p12dcx;    rv = SEC_ASN1DecoderUpdate(safeContentsCtx->currentSafeBagDcx, data, len);    if(rv != SECSuccess) {	p12dcx->errorValue = SEC_ERROR_NO_MEMORY;	goto loser;    }    return;loser:    /* set the error, and finish the decoder context.  because there      * is not a way of returning an error message, it may be worth     * while to do a check higher up and finish any decoding contexts     * that are still open.     */    p12dcx->error = PR_TRUE;    SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagDcx);    safeContentsCtx->currentSafeBagDcx = NULL;    return;}/* forward declarations of functions that are used when decoding * safeContents bags which are nested and when decoding the  * authenticatedSafes. */static SECStatussec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext 							*safeContentsCtx);static SECStatussec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext							*safeContentsCtx);static voidsec_pkcs12_decoder_safe_bag_update(void *arg, const char *data, 				   unsigned long len, int depth, 				   SEC_ASN1EncodingPart data_kind);/* notify function for decoding safeBags.  This function is * used to filter safeBag types which are not supported, * initiate the decoding of nested safe contents, and decode * safeBags in general.  this function is set when the decoder * context for the safeBag is first created. */static voidsec_pkcs12_decoder_safe_bag_notify(void *arg, PRBool before,				   void *dest, int real_depth){    sec_PKCS12SafeContentsContext *safeContentsCtx =         (sec_PKCS12SafeContentsContext *)arg;    SEC_PKCS12DecoderContext *p12dcx;    sec_PKCS12SafeBag *bag;    PRBool after;    /* if an error is encountered, return */    if(!safeContentsCtx || !safeContentsCtx->p12dcx || 		safeContentsCtx->p12dcx->error) {	return;    }    p12dcx = safeContentsCtx->p12dcx;    /* to make things more readable */    if(before)	after = PR_FALSE;    else 	after = PR_TRUE;    /* have we determined the safeBagType yet? */    bag = safeContentsCtx->currentSafeBag;    if(bag->bagTypeTag == NULL) {	if(after && (dest == &(bag->safeBagType))) {	    bag->bagTypeTag = SECOID_FindOID(&(bag->safeBagType));	    if(bag->bagTypeTag == NULL) {		p12dcx->error = PR_TRUE;		p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;	    }	}	return;    }    /* process the safeBag depending on it's type.  those     * which we do not support, are ignored.  we start a decoding     * context for a nested safeContents.     */    switch(bag->bagTypeTag->offset) {	case SEC_OID_PKCS12_V1_KEY_BAG_ID:	case SEC_OID_PKCS12_V1_CERT_BAG_ID:	case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:	    break;	case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID:	    /* if we are just starting to decode the safeContents, initialize	     * a new safeContentsCtx to process it.	     */	    if(before && (dest == &(bag->safeBagContent))) {		sec_pkcs12_decoder_begin_nested_safe_contents(safeContentsCtx);	    } else if(after && (dest == &(bag->safeBagContent))) {		/* clean up the nested decoding */		sec_pkcs12_decoder_finish_nested_safe_contents(safeContentsCtx);	    }	    break;	case SEC_OID_PKCS12_V1_CRL_BAG_ID:	case SEC_OID_PKCS12_V1_SECRET_BAG_ID:	default:	    /* skip any safe bag types we don't understand or handle */	    safeContentsCtx->skipCurrentSafeBag = PR_TRUE;	    break;    }    return;}/* notify function for decoding safe contents.  each entry in the * safe contents is a safeBag which needs to be allocated and * the decoding context initialized at the beginning and then * the context needs to be closed and finished at the end. * * this function is set when the safeContents decode context is * initialized. */static voidsec_pkcs12_decoder_safe_contents_notify(void *arg, PRBool before,					void *dest, int real_depth){    sec_PKCS12SafeContentsContext *safeContentsCtx =         (sec_PKCS12SafeContentsContext*)arg;    SEC_PKCS12DecoderContext *p12dcx;    SECStatus rv;    /* if there is an error we don't want to continue processing,     * just return and keep going.     */    if(!safeContentsCtx || !safeContentsCtx->p12dcx 		|| safeContentsCtx->p12dcx->error) {	return;    }    p12dcx = safeContentsCtx->p12dcx;    /* if we are done with the current safeBag, then we need to     * finish the context and set the state variables appropriately.     */    if(!before) {	SEC_ASN1DecoderClearFilterProc(safeContentsCtx->safeContentsDcx);	SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagDcx);	safeContentsCtx->currentSafeBagDcx = NULL;	safeContentsCtx->skipCurrentSafeBag = PR_FALSE;    } else {	/* we are starting a new safe bag.  we need to allocate space	 * for the bag and initialize the decoding context.	 */	rv = sec_pkcs12_decoder_init_new_safe_bag(safeContentsCtx);	if(rv != SECSuccess) {	    goto loser;	}	/* set up the decoder context */	safeContentsCtx->currentSafeBagDcx = SEC_ASN1DecoderStart(p12dcx->arena,						safeContentsCtx->currentSafeBag,						sec_PKCS12SafeBagTemplate);	if(!safeContentsCtx->currentSafeBagDcx) {	    p12dcx->errorValue = SEC_ERROR_NO_MEMORY;	    goto loser;	}	/* set the notify and filter procs so that the safe bag	 * data gets sent to the proper location when decoding.	 */	SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->currentSafeBagDcx, 				 sec_pkcs12_decoder_safe_bag_notify, 				 safeContentsCtx);	SEC_ASN1DecoderSetFilterProc(safeContentsCtx->safeContentsDcx, 				 sec_pkcs12_decoder_safe_bag_update, 				 safeContentsCtx, PR_TRUE);    }    return;loser:    /* in the event of an error, we want to close the decoding     * context and clear the filter and notify procedures.     */    p12dcx->error = PR_TRUE;    if(safeContentsCtx->currentSafeBagDcx) {	SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagDcx);	safeContentsCtx->currentSafeBagDcx = NULL;    }    SEC_ASN1DecoderClearNotifyProc(safeContentsCtx->safeContentsDcx);

⌨️ 快捷键说明

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