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 + -
显示快捷键?