diff options
Diffstat (limited to 'security/nss/lib/pkcs12/p12e.c')
-rw-r--r-- | security/nss/lib/pkcs12/p12e.c | 2254 |
1 files changed, 0 insertions, 2254 deletions
diff --git a/security/nss/lib/pkcs12/p12e.c b/security/nss/lib/pkcs12/p12e.c deleted file mode 100644 index 8cc683667..000000000 --- a/security/nss/lib/pkcs12/p12e.c +++ /dev/null @@ -1,2254 +0,0 @@ -/* - * 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. - */ -SECStatus -SEC_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 (?) - */ -SECStatus -SEC_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 SECStatus -sec_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; -} - -/********************************* - * Routines to handle the exporting of the keys and certificates - *********************************/ - -/* creates a safe contents which safeBags will be appended to */ -sec_PKCS12SafeContents * -sec_PKCS12CreateSafeContents(PRArenaPool *arena) -{ - sec_PKCS12SafeContents *safeContents; - - if(arena == NULL) { - return NULL; - } - - /* create the safe contents */ - safeContents = (sec_PKCS12SafeContents *)PORT_ArenaZAlloc(arena, - sizeof(sec_PKCS12SafeContents)); - if(!safeContents) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - /* set up the internal contents info */ - safeContents->safeBags = NULL; - safeContents->arena = arena; - safeContents->bagCount = 0; - - return safeContents; - -loser: - return NULL; -} - -/* appends a safe bag to a safeContents using the specified arena. - */ -SECStatus -sec_pkcs12_append_bag_to_safe_contents(PRArenaPool *arena, - sec_PKCS12SafeContents *safeContents, - sec_PKCS12SafeBag *safeBag) -{ - void *mark = NULL, *dummy = NULL; - - if(!arena || !safeBag || !safeContents) { - return SECFailure; - } - - mark = PORT_ArenaMark(arena); - if(!mark) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return SECFailure; - } - - /* allocate space for the list, or reallocate to increase space */ - if(!safeContents->safeBags) { - safeContents->safeBags = (sec_PKCS12SafeBag **)PORT_ArenaZAlloc(arena, - (2 * sizeof(sec_PKCS12SafeBag *))); - dummy = safeContents->safeBags; - safeContents->bagCount = 0; - } else { - dummy = PORT_ArenaGrow(arena, safeContents->safeBags, - (safeContents->bagCount + 1) * sizeof(sec_PKCS12SafeBag *), - (safeContents->bagCount + 2) * sizeof(sec_PKCS12SafeBag *)); - safeContents->safeBags = (sec_PKCS12SafeBag **)dummy; - } - - if(!dummy) { - PORT_ArenaRelease(arena, mark); - PORT_SetError(SEC_ERROR_NO_MEMORY); - return SECFailure; - } - - /* append the bag at the end and null terminate the list */ - safeContents->safeBags[safeContents->bagCount++] = safeBag; - safeContents->safeBags[safeContents->bagCount] = NULL; - - PORT_ArenaUnmark(arena, mark); - - return SECSuccess; -} - -/* appends a safeBag to a specific safeInfo. - */ -SECStatus -sec_pkcs12_append_bag(SEC_PKCS12ExportContext *p12ctxt, - SEC_PKCS12SafeInfo *safeInfo, sec_PKCS12SafeBag *safeBag) -{ - sec_PKCS12SafeContents *dest; - SECStatus rv = SECFailure; - - if(!p12ctxt || !safeBag || !safeInfo) { - return SECFailure; - } - - if(!safeInfo->safe) { - safeInfo->safe = sec_PKCS12CreateSafeContents(p12ctxt->arena); - if(!safeInfo->safe) { - return SECFailure; - } - } - - dest = safeInfo->safe; - rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, dest, safeBag); - if(rv == SECSuccess) { - safeInfo->itemCount++; - } - - return rv; -} - -/* Creates a safeBag of the specified type, and if bagData is specified, - * the contents are set. The contents could be set later by the calling - * routine. - */ -sec_PKCS12SafeBag * -sec_PKCS12CreateSafeBag(SEC_PKCS12ExportContext *p12ctxt, SECOidTag bagType, - void *bagData) -{ - sec_PKCS12SafeBag *safeBag; - PRBool setName = PR_TRUE; - void *mark = NULL; - SECStatus rv = SECSuccess; - SECOidData *oidData = NULL; - - if(!p12ctxt) { - return NULL; - } - - mark = PORT_ArenaMark(p12ctxt->arena); - if(!mark) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return NULL; - } - - safeBag = (sec_PKCS12SafeBag *)PORT_ArenaZAlloc(p12ctxt->arena, - sizeof(sec_PKCS12SafeBag)); - if(!safeBag) { - PORT_ArenaRelease(p12ctxt->arena, mark); - PORT_SetError(SEC_ERROR_NO_MEMORY); - return NULL; - } - - /* set the bags content based upon bag type */ - switch(bagType) { - case SEC_OID_PKCS12_V1_KEY_BAG_ID: - safeBag->safeBagContent.pkcs8KeyBag = - (SECKEYPrivateKeyInfo *)bagData; - break; - case SEC_OID_PKCS12_V1_CERT_BAG_ID: - safeBag->safeBagContent.certBag = (sec_PKCS12CertBag *)bagData; - break; - case SEC_OID_PKCS12_V1_CRL_BAG_ID: - safeBag->safeBagContent.crlBag = (sec_PKCS12CRLBag *)bagData; - break; - case SEC_OID_PKCS12_V1_SECRET_BAG_ID: - safeBag->safeBagContent.secretBag = (sec_PKCS12SecretBag *)bagData; - break; - case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID: - safeBag->safeBagContent.pkcs8ShroudedKeyBag = - (SECKEYEncryptedPrivateKeyInfo *)bagData; - break; - case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID: - safeBag->safeBagContent.safeContents = - (sec_PKCS12SafeContents *)bagData; - setName = PR_FALSE; - break; - default: - goto loser; - } - - oidData = SECOID_FindOIDByTag(bagType); - if(oidData) { - rv = SECITEM_CopyItem(p12ctxt->arena, &safeBag->safeBagType, &oidData->oid); - if(rv != SECSuccess) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - } else { - goto loser; - } - - safeBag->arena = p12ctxt->arena; - PORT_ArenaUnmark(p12ctxt->arena, mark); - - return safeBag; - -loser: - if(mark) { - PORT_ArenaRelease(p12ctxt->arena, mark); - } - - return NULL; -} - -/* Creates a new certificate bag and returns a pointer to it. If an error - * occurs NULL is returned. - */ -sec_PKCS12CertBag * -sec_PKCS12NewCertBag(PRArenaPool *arena, SECOidTag certType) -{ - sec_PKCS12CertBag *certBag = NULL; - SECOidData *bagType = NULL; - SECStatus rv; - void *mark = NULL; - - if(!arena) { - return NULL; - } - - mark = PORT_ArenaMark(arena); - certBag = (sec_PKCS12CertBag *)PORT_ArenaZAlloc(arena, - sizeof(sec_PKCS12CertBag)); - if(!certBag) { - PORT_ArenaRelease(arena, mark); - PORT_SetError(SEC_ERROR_NO_MEMORY); - return NULL; - } - - bagType = SECOID_FindOIDByTag(certType); - if(!bagType) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - rv = SECITEM_CopyItem(arena, &certBag->bagID, &bagType->oid); - if(rv != SECSuccess) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - PORT_ArenaUnmark(arena, mark); - return certBag; - -loser: - PORT_ArenaRelease(arena, mark); - return NULL; -} - -/* Creates a new CRL bag and returns a pointer to it. If an error - * occurs NULL is returned. - */ -sec_PKCS12CRLBag * -sec_PKCS12NewCRLBag(PRArenaPool *arena, SECOidTag crlType) -{ - sec_PKCS12CRLBag *crlBag = NULL; - SECOidData *bagType = NULL; - SECStatus rv; - void *mark = NULL; - - if(!arena) { - return NULL; - } - - mark = PORT_ArenaMark(arena); - crlBag = (sec_PKCS12CRLBag *)PORT_ArenaZAlloc(arena, - sizeof(sec_PKCS12CRLBag)); - if(!crlBag) { - PORT_ArenaRelease(arena, mark); - PORT_SetError(SEC_ERROR_NO_MEMORY); - return NULL; - } - - bagType = SECOID_FindOIDByTag(crlType); - if(!bagType) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - rv = SECITEM_CopyItem(arena, &crlBag->bagID, &bagType->oid); - if(rv != SECSuccess) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - PORT_ArenaUnmark(arena, mark); - return crlBag; - -loser: - PORT_ArenaRelease(arena, mark); - return NULL; -} - -/* sec_PKCS12AddAttributeToBag - * adds an attribute to a safeBag. currently, the only attributes supported - * are those which are specified within PKCS 12. - * - * p12ctxt - the export context - * safeBag - the safeBag to which attributes are appended - * attrType - the attribute type - * attrData - the attribute data - */ -SECStatus -sec_PKCS12AddAttributeToBag(SEC_PKCS12ExportContext *p12ctxt, - sec_PKCS12SafeBag *safeBag, SECOidTag attrType, - SECItem *attrData) -{ - sec_PKCS12Attribute *attribute; - void *mark = NULL, *dummy = NULL; - SECOidData *oiddata = NULL; - SECItem unicodeName = { siBuffer, NULL, 0}; - void *src = NULL; - unsigned int nItems = 0; - SECStatus rv; - - if(!safeBag || !p12ctxt) { - return SECFailure; - } - - mark = PORT_ArenaMark(safeBag->arena); - - /* allocate the attribute */ - attribute = (sec_PKCS12Attribute *)PORT_ArenaZAlloc(safeBag->arena, - sizeof(sec_PKCS12Attribute)); - if(!attribute) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - /* set up the attribute */ - oiddata = SECOID_FindOIDByTag(attrType); - if(!oiddata) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - if(SECITEM_CopyItem(p12ctxt->arena, &attribute->attrType, &oiddata->oid) != - SECSuccess) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - nItems = 1; - switch(attrType) { - case SEC_OID_PKCS9_LOCAL_KEY_ID: - { - src = attrData; - break; - } - case SEC_OID_PKCS9_FRIENDLY_NAME: - { - if(!sec_pkcs12_convert_item_to_unicode(p12ctxt->arena, - &unicodeName, attrData, PR_FALSE, - PR_FALSE, PR_TRUE)) { - goto loser; - } - src = &unicodeName; - break; - } - default: - goto loser; - } - - /* append the attribute to the attribute value list */ - attribute->attrValue = (SECItem **)PORT_ArenaZAlloc(p12ctxt->arena, - ((nItems + 1) * sizeof(SECItem *))); - if(!attribute->attrValue) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - /* XXX this will need to be changed if attributes requiring more than - * one element are ever used. - */ - attribute->attrValue[0] = (SECItem *)PORT_ArenaZAlloc(p12ctxt->arena, - sizeof(SECItem)); - if(!attribute->attrValue[0]) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - attribute->attrValue[1] = NULL; - - rv = SECITEM_CopyItem(p12ctxt->arena, attribute->attrValue[0], - (SECItem*)src); - if(rv != SECSuccess) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - /* append the attribute to the safeBag attributes */ - if(safeBag->nAttribs) { - dummy = PORT_ArenaGrow(p12ctxt->arena, safeBag->attribs, - ((safeBag->nAttribs + 1) * sizeof(sec_PKCS12Attribute *)), - ((safeBag->nAttribs + 2) * sizeof(sec_PKCS12Attribute *))); - safeBag->attribs = (sec_PKCS12Attribute **)dummy; - } else { - safeBag->attribs = (sec_PKCS12Attribute **)PORT_ArenaZAlloc(p12ctxt->arena, - 2 * sizeof(sec_PKCS12Attribute *)); - dummy = safeBag->attribs; - } - if(!dummy) { - goto loser; - } - - safeBag->attribs[safeBag->nAttribs] = attribute; - safeBag->attribs[++safeBag->nAttribs] = NULL; - - PORT_ArenaUnmark(p12ctxt->arena, mark); - return SECSuccess; - -loser: - if(mark) { - PORT_ArenaRelease(p12ctxt->arena, mark); - } - - return SECFailure; -} - -/* SEC_PKCS12AddCert - * Adds a certificate to the data being exported. - * - * p12ctxt - the export context - * safe - the safeInfo to which the certificate is placed - * nestedDest - if the cert is to be placed within a nested safeContents then, - * this value is to be specified with the destination - * cert - the cert to export - * certDb - the certificate database handle - * keyId - a unique identifier to associate a certificate/key pair - * includeCertChain - PR_TRUE if the certificate chain is to be included. - */ -SECStatus -SEC_PKCS12AddCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *safe, - void *nestedDest, CERTCertificate *cert, - CERTCertDBHandle *certDb, SECItem *keyId, - PRBool includeCertChain) -{ - sec_PKCS12CertBag *certBag; - sec_PKCS12SafeBag *safeBag; - void *mark; - SECStatus rv; - SECItem nick = {siBuffer, NULL,0}; - - if(!p12ctxt || !cert) { - return SECFailure; - } - mark = PORT_ArenaMark(p12ctxt->arena); - - /* allocate the cert bag */ - certBag = sec_PKCS12NewCertBag(p12ctxt->arena, - SEC_OID_PKCS9_X509_CERT); - if(!certBag) { - goto loser; - } - - if(SECITEM_CopyItem(p12ctxt->arena, &certBag->value.x509Cert, - &cert->derCert) != SECSuccess) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - /* if the cert chain is to be included, we should only be exporting - * the cert from our internal database. - */ - if(includeCertChain) { - CERTCertificateList *certList = CERT_CertChainFromCert(cert, - certUsageSSLClient, - PR_TRUE); - unsigned int count = 0; - if(!certList) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - /* add cert chain */ - for(count = 0; count < (unsigned int)certList->len; count++) { - if(SECITEM_CompareItem(&certList->certs[count], &cert->derCert) - != SECEqual) { - CERTCertificate *tempCert; - - /* decode the certificate */ - tempCert = CERT_NewTempCertificate(certDb, - &certList->certs[count], NULL, - PR_FALSE, PR_TRUE); - if(!tempCert) { - CERT_DestroyCertificateList(certList); - goto loser; - } - - /* add the certificate */ - if(SEC_PKCS12AddCert(p12ctxt, safe, nestedDest, tempCert, certDb, - NULL, PR_FALSE) != SECSuccess) { - CERT_DestroyCertificate(tempCert); - CERT_DestroyCertificateList(certList); - goto loser; - } - CERT_DestroyCertificate(tempCert); - } - } - CERT_DestroyCertificateList(certList); - } - - /* if the certificate has a nickname, we will set the friendly name - * to that. - */ - if(cert->nickname) { - if (cert->slot && !PK11_IsInternal(cert->slot)) { - /* - * The cert is coming off of an external token, - * let's strip the token name from the nickname - * and only add what comes after the colon as the - * nickname. -javi - */ - char *delimit; - - delimit = PORT_Strchr(cert->nickname,':'); - if (delimit == NULL) { - nick.data = (unsigned char *)cert->nickname; - nick.len = PORT_Strlen(cert->nickname); - } else { - delimit++; - nick.data = (unsigned char *)PORT_ArenaStrdup(p12ctxt->arena, - delimit); - nick.len = PORT_Strlen(delimit); - } - } else { - nick.data = (unsigned char *)cert->nickname; - nick.len = PORT_Strlen(cert->nickname); - } - } - - safeBag = sec_PKCS12CreateSafeBag(p12ctxt, SEC_OID_PKCS12_V1_CERT_BAG_ID, - certBag); - if(!safeBag) { - goto loser; - } - - /* add the friendly name and keyId attributes, if necessary */ - if(nick.data) { - if(sec_PKCS12AddAttributeToBag(p12ctxt, safeBag, - SEC_OID_PKCS9_FRIENDLY_NAME, &nick) - != SECSuccess) { - goto loser; - } - } - - if(keyId) { - if(sec_PKCS12AddAttributeToBag(p12ctxt, safeBag, SEC_OID_PKCS9_LOCAL_KEY_ID, - keyId) != SECSuccess) { - goto loser; - } - } - - /* append the cert safeBag */ - if(nestedDest) { - rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, - (sec_PKCS12SafeContents*)nestedDest, - safeBag); - } else { - rv = sec_pkcs12_append_bag(p12ctxt, safe, safeBag); - } - - if(rv != SECSuccess) { - goto loser; - } - - PORT_ArenaUnmark(p12ctxt->arena, mark); - return SECSuccess; - -loser: - if(mark) { - PORT_ArenaRelease(p12ctxt->arena, mark); - } - - return SECFailure; -} - -/* SEC_PKCS12AddEncryptedKey - * Extracts the key associated with a particular certificate and exports - * it. - * - * p12ctxt - the export context - * safe - the safeInfo to place the key in - * nestedDest - the nested safeContents to place a key - * cert - the certificate which the key belongs to - * shroudKey - encrypt the private key for export. This value should - * always be true. lower level code will not allow the export - * of unencrypted private keys. - * algorithm - the algorithm with which to encrypt the private key - * pwitem - the password to encrypted the private key with - * keyId - the keyID attribute - * nickName - the nickname attribute - */ -static SECStatus -SEC_PKCS12AddEncryptedKey(SEC_PKCS12ExportContext *p12ctxt, - SECKEYEncryptedPrivateKeyInfo *epki, SEC_PKCS12SafeInfo *safe, - void *nestedDest, SECItem *keyId, SECItem *nickName) -{ - void *mark; - void *keyItem; - SECOidTag keyType; - SECStatus rv = SECFailure; - sec_PKCS12SafeBag *returnBag; - - if(!p12ctxt || !safe || !epki) { - return SECFailure; - } - - mark = PORT_ArenaMark(p12ctxt->arena); - - keyItem = PORT_ArenaZAlloc(p12ctxt->arena, - sizeof(SECKEYEncryptedPrivateKeyInfo)); - if(!keyItem) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - rv = SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt->arena, - (SECKEYEncryptedPrivateKeyInfo *)keyItem, - epki); - keyType = SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID; - - if(rv != SECSuccess) { - goto loser; - } - - /* create the safe bag and set any attributes */ - returnBag = sec_PKCS12CreateSafeBag(p12ctxt, keyType, keyItem); - if(!returnBag) { - rv = SECFailure; - goto loser; - } - - if(nickName) { - if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag, - SEC_OID_PKCS9_FRIENDLY_NAME, nickName) - != SECSuccess) { - goto loser; - } - } - - if(keyId) { - if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag, SEC_OID_PKCS9_LOCAL_KEY_ID, - keyId) != SECSuccess) { - goto loser; - } - } - - if(nestedDest) { - rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, - (sec_PKCS12SafeContents*)nestedDest, - returnBag); - } else { - rv = sec_pkcs12_append_bag(p12ctxt, safe, returnBag); - } - -loser: - - if (rv != SECSuccess) { - PORT_ArenaRelease(p12ctxt->arena, mark); - } else { - PORT_ArenaUnmark(p12ctxt->arena, mark); - } - - return rv; -} - -/* SEC_PKCS12AddKeyForCert - * Extracts the key associated with a particular certificate and exports - * it. - * - * p12ctxt - the export context - * safe - the safeInfo to place the key in - * nestedDest - the nested safeContents to place a key - * cert - the certificate which the key belongs to - * shroudKey - encrypt the private key for export. This value should - * always be true. lower level code will not allow the export - * of unencrypted private keys. - * algorithm - the algorithm with which to encrypt the private key - * pwitem - the password to encrypt the private key with - * keyId - the keyID attribute - * nickName - the nickname attribute - */ -SECStatus -SEC_PKCS12AddKeyForCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *safe, - void *nestedDest, CERTCertificate *cert, - PRBool shroudKey, SECOidTag algorithm, SECItem *pwitem, - SECItem *keyId, SECItem *nickName) -{ - void *mark; - void *keyItem; - SECOidTag keyType; - SECStatus rv = SECFailure; - SECItem nickname = {siBuffer,NULL,0}, uniPwitem = {siBuffer, NULL, 0}; - sec_PKCS12SafeBag *returnBag; - - if(!p12ctxt || !cert || !safe) { - return SECFailure; - } - - mark = PORT_ArenaMark(p12ctxt->arena); - - /* retrieve the key based upon the type that it is and - * specify the type of safeBag to store the key in - */ - if(!shroudKey) { - - /* extract the key unencrypted. this will most likely go away */ - SECKEYPrivateKeyInfo *pki = PK11_ExportPrivateKeyInfo(cert, - p12ctxt->wincx); - if(!pki) { - PORT_ArenaRelease(p12ctxt->arena, mark); - PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY); - return SECFailure; - } - keyItem = PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECKEYPrivateKeyInfo)); - if(!keyItem) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - rv = SECKEY_CopyPrivateKeyInfo(p12ctxt->arena, - (SECKEYPrivateKeyInfo *)keyItem, pki); - keyType = SEC_OID_PKCS12_V1_KEY_BAG_ID; - SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE); - } else { - - /* extract the key encrypted */ - SECKEYEncryptedPrivateKeyInfo *epki = NULL; - PK11SlotInfo *slot = p12ctxt->slot; - - if(!sec_pkcs12_convert_item_to_unicode(p12ctxt->arena, &uniPwitem, - pwitem, PR_TRUE, PR_TRUE, PR_TRUE)) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - /* we want to make sure to take the key out of the key slot */ - if(PK11_IsInternal(p12ctxt->slot)) { - slot = PK11_GetInternalKeySlot(); - } - - epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algorithm, - &uniPwitem, cert, 1, - p12ctxt->wincx); - if(PK11_IsInternal(p12ctxt->slot)) { - PK11_FreeSlot(slot); - } - - keyItem = PORT_ArenaZAlloc(p12ctxt->arena, - sizeof(SECKEYEncryptedPrivateKeyInfo)); - if(!keyItem) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - if(!epki) { - PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY); - return SECFailure; - } - rv = SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt->arena, - (SECKEYEncryptedPrivateKeyInfo *)keyItem, - epki); - keyType = SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID; - SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE); - } - - if(rv != SECSuccess) { - goto loser; - } - - /* if no nickname specified, let's see if the certificate has a - * nickname. - */ - if(!nickName) { - if(cert->nickname) { - nickname.data = (unsigned char *)cert->nickname; - nickname.len = PORT_Strlen(cert->nickname); - nickName = &nickname; - } - } - - /* create the safe bag and set any attributes */ - returnBag = sec_PKCS12CreateSafeBag(p12ctxt, keyType, keyItem); - if(!returnBag) { - rv = SECFailure; - goto loser; - } - - if(nickName) { - if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag, - SEC_OID_PKCS9_FRIENDLY_NAME, nickName) - != SECSuccess) { - goto loser; - } - } - - if(keyId) { - if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag, SEC_OID_PKCS9_LOCAL_KEY_ID, - keyId) != SECSuccess) { - goto loser; - } - } - - if(nestedDest) { - rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, - (sec_PKCS12SafeContents*)nestedDest, - returnBag); - } else { - rv = sec_pkcs12_append_bag(p12ctxt, safe, returnBag); - } - -loser: - - if (rv != SECSuccess) { - PORT_ArenaRelease(p12ctxt->arena, mark); - } else { - PORT_ArenaUnmark(p12ctxt->arena, mark); - } - - return rv; -} - -/* SEC_PKCS12AddCertAndEncryptedKey - * Add a certificate and key pair to be exported. - * - * p12ctxt - the export context - * certSafe - the safeInfo where the cert is stored - * certNestedDest - the nested safeContents to store the cert - * keySafe - the safeInfo where the key is stored - * keyNestedDest - the nested safeContents to store the key - * shroudKey - extract the private key encrypted? - * pwitem - the password with which the key is encrypted - * algorithm - the algorithm with which the key is encrypted - */ -SECStatus -SEC_PKCS12AddDERCertAndEncryptedKey(SEC_PKCS12ExportContext *p12ctxt, - void *certSafe, void *certNestedDest, - SECItem *derCert, void *keySafe, - void *keyNestedDest, SECKEYEncryptedPrivateKeyInfo *epki, - char *nickname) -{ - SECStatus rv = SECFailure; - SGNDigestInfo *digest = NULL; - void *mark = NULL; - CERTCertificate *cert; - SECItem nick = {siBuffer, NULL,0}, *nickPtr = NULL; - - if(!p12ctxt || !certSafe || !keySafe || !derCert) { - return SECFailure; - } - - mark = PORT_ArenaMark(p12ctxt->arena); - - cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), derCert, - NULL, PR_FALSE, PR_TRUE); - if(!cert) { - PORT_ArenaRelease(p12ctxt->arena, mark); - PORT_SetError(SEC_ERROR_NO_MEMORY); - return SECFailure; - } - cert->nickname = nickname; - - /* generate the thumbprint of the cert to use as a keyId */ - digest = sec_pkcs12_compute_thumbprint(&cert->derCert); - if(!digest) { - CERT_DestroyCertificate(cert); - return SECFailure; - } - - /* add the certificate */ - rv = SEC_PKCS12AddCert(p12ctxt, (SEC_PKCS12SafeInfo*)certSafe, - certNestedDest, cert, NULL, - &digest->digest, PR_FALSE); - if(rv != SECSuccess) { - goto loser; - } - - if(nickname) { - nick.data = (unsigned char *)nickname; - nick.len = PORT_Strlen(nickname); - nickPtr = &nick; - } else { - nickPtr = NULL; - } - - /* add the key */ - rv = SEC_PKCS12AddEncryptedKey(p12ctxt, epki, (SEC_PKCS12SafeInfo*)keySafe, - keyNestedDest, &digest->digest, nickPtr ); - if(rv != SECSuccess) { - goto loser; - } - - SGN_DestroyDigestInfo(digest); - - PORT_ArenaUnmark(p12ctxt->arena, mark); - return SECSuccess; - -loser: - SGN_DestroyDigestInfo(digest); - CERT_DestroyCertificate(cert); - PORT_ArenaRelease(p12ctxt->arena, mark); - - return SECFailure; -} - -/* SEC_PKCS12AddCertAndKey - * Add a certificate and key pair to be exported. - * - * p12ctxt - the export context - * certSafe - the safeInfo where the cert is stored - * certNestedDest - the nested safeContents to store the cert - * keySafe - the safeInfo where the key is stored - * keyNestedDest - the nested safeContents to store the key - * shroudKey - extract the private key encrypted? - * pwitem - the password with which the key is encrypted - * algorithm - the algorithm with which the key is encrypted - */ -SECStatus -SEC_PKCS12AddCertAndKey(SEC_PKCS12ExportContext *p12ctxt, - void *certSafe, void *certNestedDest, - CERTCertificate *cert, CERTCertDBHandle *certDb, - void *keySafe, void *keyNestedDest, - PRBool shroudKey, SECItem *pwitem, SECOidTag algorithm) -{ - SECStatus rv = SECFailure; - SGNDigestInfo *digest = NULL; - void *mark = NULL; - - if(!p12ctxt || !certSafe || !keySafe || !cert) { - return SECFailure; - } - - mark = PORT_ArenaMark(p12ctxt->arena); - - /* generate the thumbprint of the cert to use as a keyId */ - digest = sec_pkcs12_compute_thumbprint(&cert->derCert); - if(!digest) { - PORT_ArenaRelease(p12ctxt->arena, mark); - return SECFailure; - } - - /* add the certificate */ - rv = SEC_PKCS12AddCert(p12ctxt, (SEC_PKCS12SafeInfo*)certSafe, - (SEC_PKCS12SafeInfo*)certNestedDest, cert, certDb, - &digest->digest, PR_TRUE); - if(rv != SECSuccess) { - goto loser; - } - - /* add the key */ - rv = SEC_PKCS12AddKeyForCert(p12ctxt, (SEC_PKCS12SafeInfo*)keySafe, - keyNestedDest, cert, - shroudKey, algorithm, pwitem, - &digest->digest, NULL ); - if(rv != SECSuccess) { - goto loser; - } - - SGN_DestroyDigestInfo(digest); - - PORT_ArenaUnmark(p12ctxt->arena, mark); - return SECSuccess; - -loser: - SGN_DestroyDigestInfo(digest); - PORT_ArenaRelease(p12ctxt->arena, mark); - - return SECFailure; -} - -/* SEC_PKCS12CreateNestedSafeContents - * Allows nesting of safe contents to be implemented. No limit imposed on - * depth. - * - * p12ctxt - the export context - * baseSafe - the base safeInfo - * nestedDest - a parent safeContents (?) - */ -void * -SEC_PKCS12CreateNestedSafeContents(SEC_PKCS12ExportContext *p12ctxt, - void *baseSafe, void *nestedDest) -{ - sec_PKCS12SafeContents *newSafe; - sec_PKCS12SafeBag *safeContentsBag; - void *mark; - SECStatus rv; - - if(!p12ctxt || !baseSafe) { - return NULL; - } - - mark = PORT_ArenaMark(p12ctxt->arena); - - newSafe = sec_PKCS12CreateSafeContents(p12ctxt->arena); - if(!newSafe) { - PORT_ArenaRelease(p12ctxt->arena, mark); - PORT_SetError(SEC_ERROR_NO_MEMORY); - return NULL; - } - - /* create the safeContents safeBag */ - safeContentsBag = sec_PKCS12CreateSafeBag(p12ctxt, - SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID, - newSafe); - if(!safeContentsBag) { - goto loser; - } - - /* append the safeContents to the appropriate area */ - if(nestedDest) { - rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, - (sec_PKCS12SafeContents*)nestedDest, - safeContentsBag); - } else { - rv = sec_pkcs12_append_bag(p12ctxt, (SEC_PKCS12SafeInfo*)baseSafe, - safeContentsBag); - } - if(rv != SECSuccess) { - goto loser; - } - - PORT_ArenaUnmark(p12ctxt->arena, mark); - return newSafe; - -loser: - PORT_ArenaRelease(p12ctxt->arena, mark); - return NULL; -} - -/********************************* - * Encoding routines - *********************************/ - -/* set up the encoder context based on information in the export context - * and return the newly allocated enocoder context. A return of NULL - * indicates an error occurred. - */ -sec_PKCS12EncoderContext * -sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp) -{ - sec_PKCS12EncoderContext *p12enc = NULL; - unsigned int i, nonEmptyCnt; - - if(!p12exp || !p12exp->safeInfos) { - return NULL; - } - - /* check for any empty safes and skip them */ - i = nonEmptyCnt = 0; - while(p12exp->safeInfos[i]) { - if(p12exp->safeInfos[i]->itemCount) { - nonEmptyCnt++; - } - i++; - } - if(nonEmptyCnt == 0) { - return NULL; - } - p12exp->authSafe.encodedSafes[nonEmptyCnt] = NULL; - - /* allocate the encoder context */ - p12enc = (sec_PKCS12EncoderContext*)PORT_ArenaZAlloc(p12exp->arena, - sizeof(sec_PKCS12EncoderContext)); - if(!p12enc) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return NULL; - } - - p12enc->arena = p12exp->arena; - p12enc->p12exp = p12exp; - - /* set up the PFX version and information */ - PORT_Memset(&p12enc->pfx, 0, sizeof(sec_PKCS12PFXItem)); - if(!SEC_ASN1EncodeInteger(p12exp->arena, &(p12enc->pfx.version), - SEC_PKCS12_VERSION) ) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - /* set up the authenticated safe content info based on the - * type of integrity being used. this should be changed to - * enforce integrity mode, but will not be implemented until - * it is confirmed that integrity must be in place - */ - if(p12exp->integrityEnabled && !p12exp->pwdIntegrity) { - SECStatus rv; - - /* create public key integrity mode */ - p12enc->aSafeCinfo = SEC_PKCS7CreateSignedData( - p12exp->integrityInfo.pubkeyInfo.cert, - certUsageEmailSigner, - p12exp->integrityInfo.pubkeyInfo.certDb, - p12exp->integrityInfo.pubkeyInfo.algorithm, - NULL, - p12exp->pwfn, - p12exp->pwfnarg); - if(!p12enc->aSafeCinfo) { - goto loser; - } - if(SEC_PKCS7IncludeCertChain(p12enc->aSafeCinfo,NULL) != SECSuccess) { - SEC_PKCS7DestroyContentInfo(p12enc->aSafeCinfo); - goto loser; - } - rv = SEC_PKCS7AddSigningTime(p12enc->aSafeCinfo); - PORT_Assert(rv == SECSuccess); - } else { - p12enc->aSafeCinfo = SEC_PKCS7CreateData(); - - /* init password pased integrity mode */ - if(p12exp->integrityEnabled) { - SECItem pwd = {siBuffer,NULL, 0}, *key; - SECItem *salt = sec_pkcs12_generate_salt(); - PBEBitGenContext *pbeCtxt = NULL; - - /* zero out macData and set values */ - PORT_Memset(&p12enc->mac, 0, sizeof(sec_PKCS12MacData)); - - if(!salt) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - if(SECITEM_CopyItem(p12exp->arena, &(p12enc->mac.macSalt), salt) - != SECSuccess) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - SECITEM_ZfreeItem(salt, PR_TRUE); - - /* generate HMAC key */ - if(!sec_pkcs12_convert_item_to_unicode(p12exp->arena, &pwd, - p12exp->integrityInfo.pwdInfo.password, PR_TRUE, - PR_TRUE, PR_TRUE)) { - goto loser; - } - pbeCtxt = PBE_CreateContext(p12exp->integrityInfo.pwdInfo.algorithm, - pbeBitGenIntegrityKey, &pwd, - &(p12enc->mac.macSalt), 160, 1); - if(!pbeCtxt) { - goto loser; - } - key = PBE_GenerateBits(pbeCtxt); - PBE_DestroyContext(pbeCtxt); - if(!key) { - goto loser; - } - - /* initialize hmac */ - p12enc->hmacCx = HMAC_Create( - p12exp->integrityInfo.pwdInfo.algorithm, - key->data, key->len); - SECITEM_ZfreeItem(key, PR_TRUE); - if(!p12enc->hmacCx) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - HMAC_Begin((HMACContext*)p12enc->hmacCx); - } - } - - if(!p12enc->aSafeCinfo) { - goto loser; - } - - return p12enc; - -loser: - if(p12enc) { - if(p12enc->aSafeCinfo) { - SEC_PKCS7DestroyContentInfo(p12enc->aSafeCinfo); - } - - PORT_Free(p12enc); - } - - return NULL; -} - -/* callback wrapper to allow the ASN1 engine to call the PKCS 12 - * output routines. - */ -static void -sec_pkcs12_encoder_out(void *arg, const char *buf, unsigned long len, - int depth, SEC_ASN1EncodingPart data_kind) -{ - struct sec_pkcs12_encoder_output *output; - - output = (struct sec_pkcs12_encoder_output*)arg; - (* output->outputfn)(output->outputarg, buf, len); -} - -/* callback wrapper to wrap SEC_PKCS7EncoderUpdate for ASN1 encoder - */ -static void -sec_pkcs12_wrap_pkcs7_encoder_update(void *arg, const char *buf, - unsigned long len, int depth, - SEC_ASN1EncodingPart data_kind) -{ - SEC_PKCS7EncoderContext *ecx; - if(!buf || !len) { - return; - } - - ecx = (SEC_PKCS7EncoderContext*)arg; - SEC_PKCS7EncoderUpdate(ecx, buf, len); -} - -/* callback wrapper to wrap SEC_ASN1EncoderUpdate for PKCS 7 encoding - */ -static void -sec_pkcs12_wrap_asn1_update_for_p7_update(void *arg, const char *buf, - unsigned long len) -{ - if(!buf && !len) return; - - SEC_ASN1EncoderUpdate((SEC_ASN1EncoderContext*)arg, buf, len); -} - -/* callback wrapper which updates the HMAC and passes on bytes to the - * appropriate output function. - */ -static void -sec_pkcs12_asafe_update_hmac_and_encode_bits(void *arg, const char *buf, - unsigned long len, int depth, - SEC_ASN1EncodingPart data_kind) -{ - sec_PKCS12EncoderContext *p12ecx; - - p12ecx = (sec_PKCS12EncoderContext*)arg; - HMAC_Update((HMACContext*)p12ecx->hmacCx, (unsigned char *)buf, len); - sec_pkcs12_wrap_pkcs7_encoder_update(p12ecx->aSafeP7Ecx, buf, len, - depth, data_kind); -} - -/* this function encodes content infos which are part of the - * sequence of content infos labeled AuthenticatedSafes - */ -static SECStatus -sec_pkcs12_encoder_asafe_process(sec_PKCS12EncoderContext *p12ecx) -{ - SECStatus rv = SECSuccess; - SEC_PKCS5KeyAndPassword keyPwd; - SEC_PKCS7EncoderContext *p7ecx; - SEC_PKCS7ContentInfo *cinfo; - SEC_ASN1EncoderContext *ecx = NULL; - - void *arg = NULL; - - if(p12ecx->currentSafe < p12ecx->p12exp->authSafe.safeCount) { - SEC_PKCS12SafeInfo *safeInfo; - SECOidTag cinfoType; - - safeInfo = p12ecx->p12exp->safeInfos[p12ecx->currentSafe]; - - /* skip empty safes */ - if(safeInfo->itemCount == 0) { - return SECSuccess; - } - - cinfo = safeInfo->cinfo; - cinfoType = SEC_PKCS7ContentType(cinfo); - - /* determine the safe type and set the appropriate argument */ - switch(cinfoType) { - case SEC_OID_PKCS7_DATA: - arg = NULL; - break; - case SEC_OID_PKCS7_ENCRYPTED_DATA: - keyPwd.pwitem = &safeInfo->pwitem; - keyPwd.key = safeInfo->encryptionKey; - arg = &keyPwd; - break; - case SEC_OID_PKCS7_ENVELOPED_DATA: - arg = NULL; - break; - default: - return SECFailure; - - } - - /* start the PKCS7 encoder */ - p7ecx = SEC_PKCS7EncoderStart(cinfo, - sec_pkcs12_wrap_asn1_update_for_p7_update, - p12ecx->aSafeEcx, (PK11SymKey *)arg); - if(!p7ecx) { - goto loser; - } - - /* encode safe contents */ - ecx = SEC_ASN1EncoderStart(safeInfo->safe, sec_PKCS12SafeContentsTemplate, - sec_pkcs12_wrap_pkcs7_encoder_update, p7ecx); - if(!ecx) { - goto loser; - } - rv = SEC_ASN1EncoderUpdate(ecx, NULL, 0); - SEC_ASN1EncoderFinish(ecx); - ecx = NULL; - if(rv != SECSuccess) { - goto loser; - } - - - /* finish up safe content info */ - rv = SEC_PKCS7EncoderFinish(p7ecx, p12ecx->p12exp->pwfn, - p12ecx->p12exp->pwfnarg); - } - - return SECSuccess; - -loser: - if(p7ecx) { - SEC_PKCS7EncoderFinish(p7ecx, p12ecx->p12exp->pwfn, - p12ecx->p12exp->pwfnarg); - } - - if(ecx) { - SEC_ASN1EncoderFinish(ecx); - } - - return SECFailure; -} - -/* finish the HMAC and encode the macData so that it can be - * encoded. - */ -static SECStatus -sec_pkcs12_update_mac(sec_PKCS12EncoderContext *p12ecx) -{ - SECItem hmac = { siBuffer, NULL, 0 }; - SECStatus rv; - SGNDigestInfo *di = NULL; - void *dummy; - - if(!p12ecx) { - return SECFailure; - } - - /* make sure we are using password integrity mode */ - if(!p12ecx->p12exp->integrityEnabled) { - return SECSuccess; - } - - if(!p12ecx->p12exp->pwdIntegrity) { - return SECSuccess; - } - - /* finish the hmac */ - hmac.data = (unsigned char *)PORT_ZAlloc(SHA1_LENGTH); - if(!hmac.data) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return SECFailure; - } - - rv = HMAC_Finish((HMACContext*)p12ecx->hmacCx, - hmac.data, &hmac.len, SHA1_LENGTH); - - if(rv != SECSuccess) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - /* create the digest info */ - di = SGN_CreateDigestInfo(p12ecx->p12exp->integrityInfo.pwdInfo.algorithm, - hmac.data, hmac.len); - if(!di) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - rv = SECFailure; - goto loser; - } - - rv = SGN_CopyDigestInfo(p12ecx->arena, &p12ecx->mac.safeMac, di); - if(rv != SECSuccess) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - /* encode the mac data */ - dummy = SEC_ASN1EncodeItem(p12ecx->arena, &p12ecx->pfx.encodedMacData, - &p12ecx->mac, sec_PKCS12MacDataTemplate); - if(!dummy) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - rv = SECFailure; - } - -loser: - if(di) { - SGN_DestroyDigestInfo(di); - } - if(hmac.data) { - SECITEM_ZfreeItem(&hmac, PR_FALSE); - } - HMAC_Destroy((HMACContext*)p12ecx->hmacCx); - p12ecx->hmacCx = NULL; - - return rv; -} - -/* wraps the ASN1 encoder update for PKCS 7 encoder */ -static void -sec_pkcs12_wrap_asn1_encoder_update(void *arg, const char *buf, - unsigned long len) -{ - SEC_ASN1EncoderContext *cx; - - cx = (SEC_ASN1EncoderContext*)arg; - SEC_ASN1EncoderUpdate(cx, buf, len); -} - -/* pfx notify function for ASN1 encoder. we want to stop encoding, once we reach - * the authenticated safe. at that point, the encoder will be updated via streaming - * as the authenticated safe is encoded. - */ -static void -sec_pkcs12_encoder_pfx_notify(void *arg, PRBool before, void *dest, int real_depth) -{ - sec_PKCS12EncoderContext *p12ecx; - - if(!before) { - return; - } - - /* look for authenticated safe */ - p12ecx = (sec_PKCS12EncoderContext*)arg; - if(dest != &p12ecx->pfx.encodedAuthSafe) { - return; - } - - SEC_ASN1EncoderSetTakeFromBuf(p12ecx->ecx); - SEC_ASN1EncoderSetStreaming(p12ecx->ecx); - SEC_ASN1EncoderClearNotifyProc(p12ecx->ecx); -} - -/* SEC_PKCS12Encode - * Encodes the PFX item and returns it to the output function, via - * callback. the output function must be capable of multiple updates. - * - * p12exp - the export context - * output - the output function callback, will be called more than once, - * must be able to accept streaming data. - * outputarg - argument for the output callback. - */ -SECStatus -SEC_PKCS12Encode(SEC_PKCS12ExportContext *p12exp, - SEC_PKCS12EncoderOutputCallback output, void *outputarg) -{ - sec_PKCS12EncoderContext *p12enc; - struct sec_pkcs12_encoder_output outInfo; - SECStatus rv; - - if(!p12exp || !output) { - return SECFailure; - } - - /* get the encoder context */ - p12enc = sec_pkcs12_encoder_start_context(p12exp); - if(!p12enc) { - return SECFailure; - } - - outInfo.outputfn = output; - outInfo.outputarg = outputarg; - - /* set up PFX encoder. Set it for streaming */ - p12enc->ecx = SEC_ASN1EncoderStart(&p12enc->pfx, sec_PKCS12PFXItemTemplate, - sec_pkcs12_encoder_out, - &outInfo); - if(!p12enc->ecx) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - rv = SECFailure; - goto loser; - } - SEC_ASN1EncoderSetStreaming(p12enc->ecx); - SEC_ASN1EncoderSetNotifyProc(p12enc->ecx, sec_pkcs12_encoder_pfx_notify, p12enc); - rv = SEC_ASN1EncoderUpdate(p12enc->ecx, NULL, 0); - if(rv != SECSuccess) { - rv = SECFailure; - goto loser; - } - - /* set up asafe cinfo - the output of the encoder feeds the PFX encoder */ - p12enc->aSafeP7Ecx = SEC_PKCS7EncoderStart(p12enc->aSafeCinfo, - sec_pkcs12_wrap_asn1_encoder_update, - p12enc->ecx, NULL); - if(!p12enc->aSafeP7Ecx) { - rv = SECFailure; - goto loser; - } - - /* encode asafe */ - if(p12enc->p12exp->integrityEnabled && p12enc->p12exp->pwdIntegrity) { - p12enc->aSafeEcx = SEC_ASN1EncoderStart(&p12enc->p12exp->authSafe, - sec_PKCS12AuthenticatedSafeTemplate, - sec_pkcs12_asafe_update_hmac_and_encode_bits, - p12enc); - } else { - p12enc->aSafeEcx = SEC_ASN1EncoderStart(&p12enc->p12exp->authSafe, - sec_PKCS12AuthenticatedSafeTemplate, - sec_pkcs12_wrap_pkcs7_encoder_update, - p12enc->aSafeP7Ecx); - } - if(!p12enc->aSafeEcx) { - rv = SECFailure; - goto loser; - } - SEC_ASN1EncoderSetStreaming(p12enc->aSafeEcx); - SEC_ASN1EncoderSetTakeFromBuf(p12enc->aSafeEcx); - - /* encode each of the safes */ - while(p12enc->currentSafe != p12enc->p12exp->safeInfoCount) { - sec_pkcs12_encoder_asafe_process(p12enc); - p12enc->currentSafe++; - } - SEC_ASN1EncoderClearTakeFromBuf(p12enc->aSafeEcx); - SEC_ASN1EncoderClearStreaming(p12enc->aSafeEcx); - SEC_ASN1EncoderUpdate(p12enc->aSafeEcx, NULL, 0); - SEC_ASN1EncoderFinish(p12enc->aSafeEcx); - - /* finish the encoding of the authenticated safes */ - rv = SEC_PKCS7EncoderFinish(p12enc->aSafeP7Ecx, p12exp->pwfn, - p12exp->pwfnarg); - if(rv != SECSuccess) { - goto loser; - } - - SEC_ASN1EncoderClearTakeFromBuf(p12enc->ecx); - SEC_ASN1EncoderClearStreaming(p12enc->ecx); - - /* update the mac, if necessary */ - rv = sec_pkcs12_update_mac(p12enc); - if(rv != SECSuccess) { - goto loser; - } - - /* finish encoding the pfx */ - rv = SEC_ASN1EncoderUpdate(p12enc->ecx, NULL, 0); - - SEC_ASN1EncoderFinish(p12enc->ecx); - -loser: - return rv; -} - -void -SEC_PKCS12DestroyExportContext(SEC_PKCS12ExportContext *p12ecx) -{ - int i = 0; - - if(!p12ecx) { - return; - } - - if(p12ecx->safeInfos) { - i = 0; - while(p12ecx->safeInfos[i] != NULL) { - if(p12ecx->safeInfos[i]->encryptionKey) { - PK11_FreeSymKey(p12ecx->safeInfos[i]->encryptionKey); - } - if(p12ecx->safeInfos[i]->cinfo) { - SEC_PKCS7DestroyContentInfo(p12ecx->safeInfos[i]->cinfo); - } - i++; - } - } - - PORT_FreeArena(p12ecx->arena, PR_TRUE); -} - - -/********************************* - * All-in-one routines for exporting certificates - *********************************/ -struct inPlaceEncodeInfo { - PRBool error; - SECItem outItem; -}; - -static void -sec_pkcs12_in_place_encoder_output(void *arg, const char *buf, unsigned long len) -{ - struct inPlaceEncodeInfo *outInfo = (struct inPlaceEncodeInfo*)arg; - - if(!outInfo || !len || outInfo->error) { - return; - } - - if(!outInfo->outItem.data) { - outInfo->outItem.data = (unsigned char*)PORT_ZAlloc(len); - outInfo->outItem.len = 0; - } else { - if(!PORT_Realloc(&(outInfo->outItem.data), (outInfo->outItem.len + len))) { - SECITEM_ZfreeItem(&(outInfo->outItem), PR_FALSE); - outInfo->outItem.data = NULL; - PORT_SetError(SEC_ERROR_NO_MEMORY); - outInfo->error = PR_TRUE; - return; - } - } - - PORT_Memcpy(&(outInfo->outItem.data[outInfo->outItem.len]), buf, len); - outInfo->outItem.len += len; - - return; -} - -/* - * SEC_PKCS12ExportCertifcateAndKeyUsingPassword - * Exports a certificate/key pair using password-based encryption and - * authentication. - * - * pwfn, pwfnarg - password function and argument for the key database - * cert - the certificate to export - * certDb - certificate database - * pwitem - the password to use - * shroudKey - encrypt the key externally, - * keyShroudAlg - encryption algorithm for key - * encryptionAlg - the algorithm with which data is encrypted - * integrityAlg - the algorithm for integrity - */ -SECItem * -SEC_PKCS12ExportCertificateAndKeyUsingPassword( - SECKEYGetPasswordKey pwfn, void *pwfnarg, - CERTCertificate *cert, PK11SlotInfo *slot, - CERTCertDBHandle *certDb, SECItem *pwitem, - PRBool shroudKey, SECOidTag shroudAlg, - PRBool encryptCert, SECOidTag certEncAlg, - SECOidTag integrityAlg, void *wincx) -{ - struct inPlaceEncodeInfo outInfo; - SEC_PKCS12ExportContext *p12ecx = NULL; - SEC_PKCS12SafeInfo *keySafe, *certSafe; - SECItem *returnItem = NULL; - - if(!cert || !pwitem || !slot) { - return NULL; - } - - outInfo.error = PR_FALSE; - outInfo.outItem.data = NULL; - outInfo.outItem.len = 0; - - p12ecx = SEC_PKCS12CreateExportContext(pwfn, pwfnarg, slot, wincx); - if(!p12ecx) { - return NULL; - } - - /* set up cert safe */ - if(encryptCert) { - certSafe = SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem, certEncAlg); - } else { - certSafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx); - } - if(!certSafe) { - goto loser; - } - - /* set up key safe */ - if(shroudKey) { - keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx); - } else { - keySafe = certSafe; - } - if(!keySafe) { - goto loser; - } - - /* add integrity mode */ - if(SEC_PKCS12AddPasswordIntegrity(p12ecx, pwitem, integrityAlg) - != SECSuccess) { - goto loser; - } - - /* add cert and key pair */ - if(SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert, certDb, - keySafe, NULL, shroudKey, pwitem, shroudAlg) - != SECSuccess) { - goto loser; - } - - /* encode the puppy */ - if(SEC_PKCS12Encode(p12ecx, sec_pkcs12_in_place_encoder_output, &outInfo) - != SECSuccess) { - goto loser; - } - if(outInfo.error) { - goto loser; - } - - SEC_PKCS12DestroyExportContext(p12ecx); - - returnItem = SECITEM_DupItem(&outInfo.outItem); - SECITEM_ZfreeItem(&outInfo.outItem, PR_FALSE); - - return returnItem; - -loser: - if(outInfo.outItem.data) { - SECITEM_ZfreeItem(&(outInfo.outItem), PR_TRUE); - } - - if(p12ecx) { - SEC_PKCS12DestroyExportContext(p12ecx); - } - - return NULL; -} - - |