p12e.c

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

C
2,255
字号
/* * 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 "prcpucfg.h"/********************************* * Structures used in exporting the PKCS 12 blob *********************************//* A SafeInfo is used for each ContentInfo which makes up the * sequence of safes in the AuthenticatedSafe portion of the * PFX structure. */struct SEC_PKCS12SafeInfoStr {    PRArenaPool *arena;    /* information for setting up password encryption */    SECItem pwitem;    SECOidTag algorithm;    PK11SymKey *encryptionKey;    /* how many items have been stored in this safe,     * we will skip any safe which does not contain any     * items      */    unsigned int itemCount;    /* the content info for the safe */    SEC_PKCS7ContentInfo *cinfo;    sec_PKCS12SafeContents *safe;};/* An opaque structure which contains information needed for exporting * certificates and keys through PKCS 12. */struct SEC_PKCS12ExportContextStr {    PRArenaPool *arena;    PK11SlotInfo *slot;    void *wincx;    /* integrity information */    PRBool integrityEnabled;    PRBool	pwdIntegrity;    union {	struct sec_PKCS12PasswordModeInfo pwdInfo;	struct sec_PKCS12PublicKeyModeInfo pubkeyInfo;    } integrityInfo;     /* helper functions */    /* retrieve the password call back */    SECKEYGetPasswordKey pwfn;    void *pwfnarg;    /* safe contents bags */    SEC_PKCS12SafeInfo **safeInfos;    unsigned int safeInfoCount;    /* the sequence of safes */    sec_PKCS12AuthenticatedSafe authSafe;    /* information needing deletion */    CERTCertificate **certList;};/* structures for passing information to encoder callbacks when processing * data through the ASN1 engine. */struct sec_pkcs12_encoder_output {    SEC_PKCS12EncoderOutputCallback outputfn;    void *outputarg;};struct sec_pkcs12_hmac_and_output_info {    void *arg;    struct sec_pkcs12_encoder_output output;};/* An encoder context which is used for the actual encoding * portion of PKCS 12.  */typedef struct sec_PKCS12EncoderContextStr {    PRArenaPool *arena;    SEC_PKCS12ExportContext *p12exp;    PK11SymKey *encryptionKey;    /* encoder information - this is set up based on whether      * password based or public key pased privacy is being used     */    SEC_ASN1EncoderContext *ecx;    union {	struct sec_pkcs12_hmac_and_output_info hmacAndOutputInfo;	struct sec_pkcs12_encoder_output encOutput;    } output;    /* structures for encoding of PFX and MAC */    sec_PKCS12PFXItem pfx;    sec_PKCS12MacData mac;    /* authenticated safe encoding tracking information */    SEC_PKCS7ContentInfo *aSafeCinfo;    SEC_PKCS7EncoderContext *aSafeP7Ecx;    SEC_ASN1EncoderContext *aSafeEcx;    unsigned int currentSafe;    /* hmac context */    void *hmacCx;} sec_PKCS12EncoderContext;/********************************* * Export setup routines *********************************//* SEC_PKCS12CreateExportContext  *   Creates an export context and sets the unicode and password retrieval *   callbacks.  This is the first call which must be made when exporting *   a PKCS 12 blob. * * pwfn, pwfnarg - password retrieval callback and argument.  these are * 		   required for password-authentication mode. */SEC_PKCS12ExportContext *SEC_PKCS12CreateExportContext(SECKEYGetPasswordKey pwfn, void *pwfnarg,  			      PK11SlotInfo *slot, void *wincx){    PRArenaPool *arena = NULL;    SEC_PKCS12ExportContext *p12ctxt = NULL;    /* allocate the arena and create the context */    arena = PORT_NewArena(4096);    if(!arena) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	return NULL;    }    p12ctxt = (SEC_PKCS12ExportContext *)PORT_ArenaZAlloc(arena, 					sizeof(SEC_PKCS12ExportContext));    if(!p12ctxt) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	goto loser;    }    /* password callback for key retrieval */    p12ctxt->pwfn = pwfn;    p12ctxt->pwfnarg = pwfnarg;    p12ctxt->integrityEnabled = PR_FALSE;    p12ctxt->arena = arena;    p12ctxt->wincx = wincx;    p12ctxt->slot = (slot) ? slot : PK11_GetInternalSlot();    return p12ctxt;loser:    if(arena) {	PORT_FreeArena(arena, PR_TRUE);    }    return NULL;}/*  * Adding integrity mode *//* SEC_PKCS12AddPasswordIntegrity  *	Add password integrity to the exported data.  If an integrity method *	has already been set, then return an error. *	 *	p12ctxt - the export context * 	pwitem - the password for integrity mode *	integAlg - the integrity algorithm to use for authentication. */SECStatusSEC_PKCS12AddPasswordIntegrity(SEC_PKCS12ExportContext *p12ctxt,			       SECItem *pwitem, SECOidTag integAlg) {			           if(!p12ctxt || p12ctxt->integrityEnabled) {	return SECFailure;    }       /* set up integrity information */    p12ctxt->pwdIntegrity = PR_TRUE;    p12ctxt->integrityInfo.pwdInfo.password =         (SECItem*)PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECItem));    if(!p12ctxt->integrityInfo.pwdInfo.password) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	return SECFailure;    }    if(SECITEM_CopyItem(p12ctxt->arena, 			p12ctxt->integrityInfo.pwdInfo.password, pwitem)		!= SECSuccess) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	return SECFailure;    }    p12ctxt->integrityInfo.pwdInfo.algorithm = integAlg;    p12ctxt->integrityEnabled = PR_TRUE;    return SECSuccess;}/* SEC_PKCS12AddPublicKeyIntegrity *	Add public key integrity to the exported data.  If an integrity method *	has already been set, then return an error.  The certificate must be *	allowed to be used as a signing cert. *	 *	p12ctxt - the export context *	cert - signer certificate *	certDb - the certificate database *	algorithm - signing algorithm *	keySize - size of the signing key (?) */SECStatusSEC_PKCS12AddPublicKeyIntegrity(SEC_PKCS12ExportContext *p12ctxt,				CERTCertificate *cert, CERTCertDBHandle *certDb,				SECOidTag algorithm, int keySize){    if(!p12ctxt) {	return SECFailure;    }        p12ctxt->integrityInfo.pubkeyInfo.cert = cert;    p12ctxt->integrityInfo.pubkeyInfo.certDb = certDb;    p12ctxt->integrityInfo.pubkeyInfo.algorithm = algorithm;    p12ctxt->integrityInfo.pubkeyInfo.keySize = keySize;    p12ctxt->integrityEnabled = PR_TRUE;    return SECSuccess;}/* * Adding safes - encrypted (password/public key) or unencrypted *	Each of the safe creation routines return an opaque pointer which *	are later passed into the routines for exporting certificates and *	keys. *//* append the newly created safeInfo to list of safeInfos in the export * context.   */static SECStatussec_pkcs12_append_safe_info(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *info){    void *mark = NULL, *dummy1 = NULL, *dummy2 = NULL;    if(!p12ctxt || !info) {	return SECFailure;    }    mark = PORT_ArenaMark(p12ctxt->arena);    /* if no safeInfos have been set, create the list, otherwise expand it. */    if(!p12ctxt->safeInfoCount) {	p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)PORT_ArenaZAlloc(p12ctxt->arena, 					      2 * sizeof(SEC_PKCS12SafeInfo *));	dummy1 = p12ctxt->safeInfos;	p12ctxt->authSafe.encodedSafes = (SECItem **)PORT_ArenaZAlloc(p12ctxt->arena, 					2 * sizeof(SECItem *));	dummy2 = p12ctxt->authSafe.encodedSafes;    } else {	dummy1 = PORT_ArenaGrow(p12ctxt->arena, p12ctxt->safeInfos, 			       (p12ctxt->safeInfoCount + 1) * sizeof(SEC_PKCS12SafeInfo *),			       (p12ctxt->safeInfoCount + 2) * sizeof(SEC_PKCS12SafeInfo *));	p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)dummy1;	dummy2 = PORT_ArenaGrow(p12ctxt->arena, p12ctxt->authSafe.encodedSafes, 			       (p12ctxt->authSafe.safeCount + 1) * sizeof(SECItem *),			       (p12ctxt->authSafe.safeCount + 2) * sizeof(SECItem *));	p12ctxt->authSafe.encodedSafes = (SECItem**)dummy2;    }    if(!dummy1 || !dummy2) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	goto loser;    }    /* append the new safeInfo and null terminate the list */    p12ctxt->safeInfos[p12ctxt->safeInfoCount] = info;    p12ctxt->safeInfos[++p12ctxt->safeInfoCount] = NULL;    p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount] =         (SECItem*)PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECItem));    if(!p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount]) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	goto loser;    }    p12ctxt->authSafe.encodedSafes[++p12ctxt->authSafe.safeCount] = NULL;    PORT_ArenaUnmark(p12ctxt->arena, mark);    return SECSuccess;loser:    PORT_ArenaRelease(p12ctxt->arena, mark);    return SECFailure;}/* SEC_PKCS12CreatePasswordPrivSafe *	Create a password privacy safe to store exported information in. * * 	p12ctxt - export context *	pwitem - password for encryption *	privAlg - pbe algorithm through which encryption is done. */SEC_PKCS12SafeInfo *SEC_PKCS12CreatePasswordPrivSafe(SEC_PKCS12ExportContext *p12ctxt, 				 SECItem *pwitem, SECOidTag privAlg){    SEC_PKCS12SafeInfo *safeInfo = NULL;    void *mark = NULL;    PK11SlotInfo *slot;    SECAlgorithmID *algId;    SECItem uniPwitem = {siBuffer, NULL, 0};    if(!p12ctxt) {	return NULL;    }    /* allocate the safe info */    mark = PORT_ArenaMark(p12ctxt->arena);    safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,     						sizeof(SEC_PKCS12SafeInfo));    if(!safeInfo) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	PORT_ArenaRelease(p12ctxt->arena, mark);	return NULL;    }    safeInfo->itemCount = 0;    /* create the encrypted safe */    safeInfo->cinfo = SEC_PKCS7CreateEncryptedData(privAlg, 0, p12ctxt->pwfn,     						   p12ctxt->pwfnarg);    if(!safeInfo->cinfo) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	goto loser;    }    safeInfo->arena = p12ctxt->arena;    /* convert the password to unicode */     if(!sec_pkcs12_convert_item_to_unicode(NULL, &uniPwitem, pwitem,					       PR_TRUE, PR_TRUE, PR_TRUE)) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	goto loser;    }    if(SECITEM_CopyItem(p12ctxt->arena, &safeInfo->pwitem, &uniPwitem) != SECSuccess) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	goto loser;    }    /* generate the encryption key */    slot = p12ctxt->slot;    if(!slot) {	slot = PK11_GetInternalKeySlot();	if(!slot) {	    PORT_SetError(SEC_ERROR_NO_MEMORY);	    goto loser;	}    }    algId = SEC_PKCS7GetEncryptionAlgorithm(safeInfo->cinfo);    safeInfo->encryptionKey = PK11_PBEKeyGen(slot, algId, &uniPwitem, 					     PR_FALSE, p12ctxt->wincx);    if(!safeInfo->encryptionKey) {	goto loser;    }    safeInfo->arena = p12ctxt->arena;    safeInfo->safe = NULL;    if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {	goto loser;    }    if(uniPwitem.data) {	SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);    }    PORT_ArenaUnmark(p12ctxt->arena, mark);    return safeInfo;loser:    if(safeInfo->cinfo) {	SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);    }    if(uniPwitem.data) {	SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);    }    PORT_ArenaRelease(p12ctxt->arena, mark);    return NULL;}/* SEC_PKCS12CreateUnencryptedSafe  *	Creates an unencrypted safe within the export context. * *	p12ctxt - the export context  */SEC_PKCS12SafeInfo *SEC_PKCS12CreateUnencryptedSafe(SEC_PKCS12ExportContext *p12ctxt){    SEC_PKCS12SafeInfo *safeInfo = NULL;    void *mark = NULL;    if(!p12ctxt) {	return NULL;    }    /* create the safe info */    mark = PORT_ArenaMark(p12ctxt->arena);    safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,     					      sizeof(SEC_PKCS12SafeInfo));    if(!safeInfo) {	PORT_ArenaRelease(p12ctxt->arena, mark);	PORT_SetError(SEC_ERROR_NO_MEMORY);	return NULL;    }    safeInfo->itemCount = 0;    /* create the safe content */    safeInfo->cinfo = SEC_PKCS7CreateData();    if(!safeInfo->cinfo) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	goto loser;    }    if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {	goto loser;    }    PORT_ArenaUnmark(p12ctxt->arena, mark);    return safeInfo;loser:    if(safeInfo->cinfo) {	SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);    }    PORT_ArenaRelease(p12ctxt->arena, mark);    return NULL;}/* SEC_PKCS12CreatePubKeyEncryptedSafe *	Creates a safe which is protected by public key encryption.   * *	p12ctxt - the export context *	certDb - the certificate database *	signer - the signer's certificate *	recipients - the list of recipient certificates. *	algorithm - the encryption algorithm to use *	keysize - the algorithms key size (?) */SEC_PKCS12SafeInfo *SEC_PKCS12CreatePubKeyEncryptedSafe(SEC_PKCS12ExportContext *p12ctxt,				    CERTCertDBHandle *certDb,				    CERTCertificate *signer,				    CERTCertificate **recipients,				    SECOidTag algorithm, int keysize) {    SEC_PKCS12SafeInfo *safeInfo = NULL;    void *mark = NULL;    if(!p12ctxt || !signer || !recipients || !(*recipients)) {	return NULL;    }    /* allocate the safeInfo */    mark = PORT_ArenaMark(p12ctxt->arena);    safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,     						      sizeof(SEC_PKCS12SafeInfo));    if(!safeInfo) {	PORT_ArenaRelease(p12ctxt->arena, mark);	PORT_SetError(SEC_ERROR_NO_MEMORY);	return NULL;    }    safeInfo->itemCount = 0;    safeInfo->arena = p12ctxt->arena;    /* create the enveloped content info using certUsageEmailSigner currently.     * XXX We need to eventually use something other than certUsageEmailSigner     */    safeInfo->cinfo = SEC_PKCS7CreateEnvelopedData(signer, certUsageEmailSigner,					certDb, algorithm, keysize, 					p12ctxt->pwfn, p12ctxt->pwfnarg);    if(!safeInfo->cinfo) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	goto loser;    }    /* add recipients */    if(recipients) {	unsigned int i = 0;	while(recipients[i] != NULL) {	    SECStatus rv = SEC_PKCS7AddRecipient(safeInfo->cinfo, recipients[i],					       certUsageEmailRecipient, certDb);	    if(rv != SECSuccess) {		goto loser;	    }	    i++;	}    }    if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {	goto loser;    }    PORT_ArenaUnmark(p12ctxt->arena, mark);    return safeInfo;loser:    if(safeInfo->cinfo) {	SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);	safeInfo->cinfo = NULL;    }    PORT_ArenaRelease(p12ctxt->arena, mark);    return NULL;} /*********************************

⌨️ 快捷键说明

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