p12exp.c

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

C
1,408
字号
/* * 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 "plarena.h"#include "secitem.h"#include "secoid.h"#include "seccomon.h"#include "secport.h"#include "cert.h"#include "pkcs12.h"#include "p12local.h"#include "secpkcs7.h"#include "secasn1.h"#include "secerr.h"#include "p12plcy.h"/* release the memory taken up by the list of nicknames */static voidsec_pkcs12_destroy_nickname_list(SECItem **nicknames){    int i = 0;    if(nicknames == NULL) {	return;    }    while(nicknames[i] != NULL) {	SECITEM_FreeItem(nicknames[i], PR_FALSE);	i++;    }    PORT_Free(nicknames);}   /* release the memory taken up by the list of certificates */ static voidsec_pkcs12_destroy_certificate_list(CERTCertificate **ref_certs){    int i = 0;    if(ref_certs == NULL) {	return;    }    while(ref_certs[i] != NULL) {	CERT_DestroyCertificate(ref_certs[i]);	i++;    }}static voidsec_pkcs12_destroy_cinfos_for_cert_bags(SEC_PKCS12CertAndCRLBag *certBag){    int j = 0;    j = 0;    while(certBag->certAndCRLs[j] != NULL) {	SECOidTag certType = SECOID_FindOIDTag(&certBag->certAndCRLs[j]->BagID);	if(certType == SEC_OID_PKCS12_X509_CERT_CRL_BAG) {	    SEC_PKCS12X509CertCRL *x509;	    x509 = certBag->certAndCRLs[j]->value.x509;	    SEC_PKCS7DestroyContentInfo(&x509->certOrCRL);	}	j++;    }}/* destroy all content infos since they were not allocated in common * pool */static voidsec_pkcs12_destroy_cert_content_infos(SEC_PKCS12SafeContents *safe,				      SEC_PKCS12Baggage *baggage){    int i, j;    if((safe != NULL) && (safe->contents != NULL)) {	i = 0;	while(safe->contents[i] != NULL) {	    SECOidTag bagType = SECOID_FindOIDTag(&safe->contents[i]->safeBagType);	    if(bagType == SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID) {		SEC_PKCS12CertAndCRLBag *certBag;		certBag = safe->contents[i]->safeContent.certAndCRLBag;		sec_pkcs12_destroy_cinfos_for_cert_bags(certBag);	    }	    i++;	}    }    if((baggage != NULL) && (baggage->bags != NULL)) {	i = 0;	while(baggage->bags[i] != NULL) { 	    if(baggage->bags[i]->unencSecrets != NULL) {		j = 0;		while(baggage->bags[i]->unencSecrets[j] != NULL) {		    SECOidTag bagType;		    bagType = SECOID_FindOIDTag(&baggage->bags[i]->unencSecrets[j]->safeBagType);		    if(bagType == SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID) {			SEC_PKCS12CertAndCRLBag *certBag;			certBag = baggage->bags[i]->unencSecrets[j]->safeContent.certAndCRLBag;			sec_pkcs12_destroy_cinfos_for_cert_bags(certBag);		    }		    j++;		}	    }	    i++;	}    }}/* convert the nickname list from a NULL termincated Char list * to a NULL terminated SECItem list */static SECItem **sec_pkcs12_convert_nickname_list(char **nicknames){    SECItem **nicks;    int i, j;    PRBool error = PR_FALSE;    if(nicknames == NULL) {	return NULL;    }    i = j = 0;    while(nicknames[i] != NULL) {	i++;    }    /* allocate the space and copy the data */	    nicks = (SECItem **)PORT_ZAlloc(sizeof(SECItem *) * (i + 1));    if(nicks != NULL) {	for(j = 0; ((j < i) && (error == PR_FALSE)); j++) {	    nicks[j] = (SECItem *)PORT_ZAlloc(sizeof(SECItem));	    if(nicks[j] != NULL) {		nicks[j]->data = 		    (unsigned char *)PORT_ZAlloc(PORT_Strlen(nicknames[j])+1);		if(nicks[j]->data != NULL) {		    nicks[j]->len = PORT_Strlen(nicknames[j]);		    PORT_Memcpy(nicks[j]->data, nicknames[j], nicks[j]->len);		    nicks[j]->data[nicks[j]->len] = 0;		} else {		    error = PR_TRUE;		}	    } else {	       error = PR_TRUE;	    }	}    }    if(error == PR_TRUE) {        for(i = 0; i < j; i++) { 	    SECITEM_FreeItem(nicks[i], PR_TRUE);	}	PORT_Free(nicks);	nicks = NULL;    }    return nicks;}/* package the certificate add_cert into PKCS12 structures, * retrieve the certificate chain for the cert and return * the packaged contents. * poolp -- common memory pool; * add_cert -- certificate to package up * nickname for the certificate  * a return of NULL indicates an error */static SEC_PKCS12CertAndCRL *sec_pkcs12_get_cert(PRArenaPool *poolp,		       CERTCertificate *add_cert, 		       SECItem *nickname){    SEC_PKCS12CertAndCRL *cert;    SEC_PKCS7ContentInfo *cinfo;    SGNDigestInfo *t_di;    void *mark;    SECStatus rv;    if((poolp == NULL) || (add_cert == NULL) || (nickname == NULL)) {    	return NULL;    }    mark = PORT_ArenaMark(poolp);    cert = sec_pkcs12_new_cert_crl(poolp, SEC_OID_PKCS12_X509_CERT_CRL_BAG);    if(cert != NULL) {	/* copy the nickname */	rv = SECITEM_CopyItem(poolp, &cert->nickname, nickname);	if(rv != SECSuccess) {	    PORT_SetError(SEC_ERROR_NO_MEMORY);	    cert = NULL;	} else {	    /* package the certificate and cert chain into a NULL signer	     * PKCS 7 SignedData content Info and prepare it for encoding 	     * since we cannot use DER_ANY_TEMPLATE	     */	    cinfo = SEC_PKCS7CreateCertsOnly(add_cert, PR_TRUE, NULL);	    rv = SEC_PKCS7PrepareForEncode(cinfo, NULL, NULL, NULL);	    /* thumbprint the certificate */	    if((cinfo != NULL) && (rv == SECSuccess))	    {		PORT_Memcpy(&cert->value.x509->certOrCRL, cinfo, sizeof(*cinfo));		t_di = sec_pkcs12_compute_thumbprint(&add_cert->derCert);		if(t_di != NULL)		{		    /* test */		    rv = SGN_CopyDigestInfo(poolp, &cert->value.x509->thumbprint,		    			    t_di);		    if(rv != SECSuccess) {			cert = NULL;			PORT_SetError(SEC_ERROR_NO_MEMORY);		    }		    SGN_DestroyDigestInfo(t_di);		}		else		    cert = NULL;	    }	}    }    if (cert == NULL) {	PORT_ArenaRelease(poolp, mark);    } else {	PORT_ArenaUnmark(poolp, mark);    }    return cert;}/* package the private key associated with the certificate and  * return the appropriate PKCS 12 structure  * poolp common memory pool * nickname key nickname * cert -- cert to look up * wincx -- window handle  * an error is indicated by a return of NULL */static SEC_PKCS12PrivateKey *sec_pkcs12_get_private_key(PRArenaPool *poolp,			   SECItem *nickname,			   CERTCertificate *cert,			   void *wincx){    SECKEYPrivateKeyInfo *pki;    SEC_PKCS12PrivateKey *pk;    SECStatus rv;    void *mark;    if((poolp == NULL) || (nickname == NULL)) {	return NULL;    }    mark = PORT_ArenaMark(poolp);    /* retrieve key from the data base */    pki = PK11_ExportPrivateKeyInfo(nickname, cert, wincx);    if(pki == NULL) {	PORT_ArenaRelease(poolp, mark);	PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);	return NULL;    }    pk = (SEC_PKCS12PrivateKey *)PORT_ArenaZAlloc(poolp,						  sizeof(SEC_PKCS12PrivateKey));    if(pk != NULL) {	rv = sec_pkcs12_init_pvk_data(poolp, &pk->pvkData);	if(rv == SECSuccess) {	    /* copy the key into poolp memory space */	    rv = SECKEY_CopyPrivateKeyInfo(poolp, &pk->pkcs8data, pki);	    if(rv == SECSuccess) {		rv = SECITEM_CopyItem(poolp, &pk->pvkData.nickname, nickname);	    }	}	if(rv != SECSuccess) {	    PORT_SetError(SEC_ERROR_NO_MEMORY);	    pk = NULL;	}    } else {	PORT_SetError(SEC_ERROR_NO_MEMORY);     }    /* destroy private key, zeroing out data */    SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE);    if (pk == NULL) {	PORT_ArenaRelease(poolp, mark);    } else {	PORT_ArenaUnmark(poolp, mark);    }    return pk;}/* get a shrouded key item associated with a certificate * return the appropriate PKCS 12 structure  * poolp common memory pool * nickname key nickname * cert -- cert to look up * wincx -- window handle  * an error is indicated by a return of NULL */static SEC_PKCS12ESPVKItem *sec_pkcs12_get_shrouded_key(PRArenaPool *poolp,			    SECItem *nickname,			    CERTCertificate *cert,			    SECOidTag algorithm, 			    SECItem *pwitem,			    PKCS12UnicodeConvertFunction unicodeFn,			    void *wincx){    SECKEYEncryptedPrivateKeyInfo *epki;    SEC_PKCS12ESPVKItem *pk;    void *mark;    SECStatus rv;    PK11SlotInfo *slot = NULL;    PRBool swapUnicodeBytes = PR_FALSE;#ifdef IS_LITTLE_ENDIAN    swapUnicodeBytes = PR_TRUE;#endif    if((poolp == NULL) || (nickname == NULL))	return NULL;    mark = PORT_ArenaMark(poolp);    /* use internal key slot */    slot = PK11_GetInternalKeySlot();    /* retrieve encrypted prviate key */    epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algorithm, pwitem,     					      nickname, cert, 1, 0, NULL);    PK11_FreeSlot(slot);    if(epki == NULL) {	PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);	PORT_ArenaRelease(poolp, mark);	return NULL;    }    /* create a private key and store the data into the poolp memory space */    pk = sec_pkcs12_create_espvk(poolp, SEC_OID_PKCS12_PKCS8_KEY_SHROUDING);    if(pk != NULL) {	rv = sec_pkcs12_init_pvk_data(poolp, &pk->espvkData);	rv = SECITEM_CopyItem(poolp, &pk->espvkData.nickname, nickname);	pk->espvkCipherText.pkcs8KeyShroud = 	    (SECKEYEncryptedPrivateKeyInfo *)PORT_ArenaZAlloc(poolp,					sizeof(SECKEYEncryptedPrivateKeyInfo));	if((pk->espvkCipherText.pkcs8KeyShroud != NULL)  && (rv == SECSuccess)) {	    rv = SECKEY_CopyEncryptedPrivateKeyInfo(poolp, 					pk->espvkCipherText.pkcs8KeyShroud, epki);	    if(rv == SECSuccess) {		rv = (*unicodeFn)(poolp, &pk->espvkData.uniNickName, nickname, 				  PR_TRUE, swapUnicodeBytes);	    }	}	if(rv != SECSuccess) {	    PORT_SetError(SEC_ERROR_NO_MEMORY);	    pk = NULL;	}    }    SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);    if(pk == NULL) {	PORT_ArenaRelease(poolp, mark);    } else {	PORT_ArenaUnmark(poolp, mark);    }	    return pk;}/* add a thumbprint to a private key associated certs list  * pvk is the area where the list is stored * thumb is the thumbprint to copy * a return of SECFailure indicates an error  */static SECStatus sec_pkcs12_add_thumbprint(SEC_PKCS12PVKSupportingData *pvk,			  SGNDigestInfo *thumb){    SGNDigestInfo **thumb_list = NULL;    int nthumbs, size;    void *mark, *dummy;    SECStatus rv = SECFailure;    if((pvk == NULL) || (thumb == NULL)) {	return SECFailure;    }    mark = PORT_ArenaMark(pvk->poolp);    thumb_list = pvk->assocCerts;    nthumbs = pvk->nThumbs;    /* allocate list space needed -- either growing or allocating      * list must be NULL terminated      */    size = sizeof(SGNDigestInfo *);    dummy = PORT_ArenaGrow(pvk->poolp, thumb_list, (size * (nthumbs + 1)),    			   (size * (nthumbs + 2)));    thumb_list = dummy;    if(dummy != NULL) {	thumb_list[nthumbs] = (SGNDigestInfo *)PORT_ArenaZAlloc(pvk->poolp, 						sizeof(SGNDigestInfo));	if(thumb_list[nthumbs] != NULL) {	    SGN_CopyDigestInfo(pvk->poolp, thumb_list[nthumbs], thumb);	    nthumbs += 1;	    thumb_list[nthumbs] = 0;	} else {	    dummy = NULL;	}    }    if(dummy == NULL) {    	PORT_ArenaRelease(pvk->poolp, mark);	return SECFailure;    }     pvk->assocCerts = thumb_list;    pvk->nThumbs = nthumbs;    PORT_ArenaUnmark(pvk->poolp, mark);    return SECSuccess;}/* search the list of shrouded keys in the baggage for the desired * name.  return a pointer to the item.  a return of NULL indicates * that no match was present or that an error occurred. */static SEC_PKCS12ESPVKItem *sec_pkcs12_get_espvk_by_name(SEC_PKCS12Baggage *luggage, 			     SECItem *name){    PRBool found = PR_FALSE;    SEC_PKCS12ESPVKItem *espvk = NULL;

⌨️ 快捷键说明

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