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