p12exp.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:36k
- /*
- * 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 void
- sec_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 void
- sec_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 void
- sec_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 void
- sec_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;
- int i, j;
- SECComparison rv = SECEqual;
- SECItem *t_name;
- SEC_PKCS12BaggageItem *bag;
- if((luggage == NULL) || (name == NULL)) {
- return NULL;
- }
- i = 0;
- while((found == PR_FALSE) && (i < luggage->luggage_size)) {
- j = 0;
- bag = luggage->bags[i];
- while((found == PR_FALSE) && (j < bag->nEspvks)) {
- espvk = bag->espvks[j];
- if(espvk->poolp == NULL) {
- espvk->poolp = luggage->poolp;
- }
- t_name = SECITEM_DupItem(&espvk->espvkData.nickname);
- if(t_name != NULL) {
- rv = SECITEM_CompareItem(name, t_name);
- if(rv == SECEqual) {
- found = PR_TRUE;
- }
- SECITEM_FreeItem(t_name, PR_TRUE);
- } else {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return NULL;
- }
- j++;
- }
- i++;
- }
- if(found != PR_TRUE) {
- PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME);
- return NULL;
- }
- return espvk;
- }
- /* locates a certificate and copies the thumbprint to the
- * appropriate private key
- */
- static SECStatus
- sec_pkcs12_propagate_thumbprints(SECItem **nicknames,
- CERTCertificate **ref_certs,
- SEC_PKCS12SafeContents *safe,
- SEC_PKCS12Baggage *baggage)
- {
- SEC_PKCS12CertAndCRL *cert;
- SEC_PKCS12PrivateKey *key;
- SEC_PKCS12ESPVKItem *espvk;
- int i;
- PRBool error = PR_FALSE;
- SECStatus rv = SECFailure;
- if((nicknames == NULL) || (safe == NULL)) {
- return SECFailure;
- }
- i = 0;
- while((nicknames[i] != NULL) && (error == PR_FALSE)) {
- /* process all certs */
- cert = (SEC_PKCS12CertAndCRL *)sec_pkcs12_find_object(safe, baggage,
- SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID,
- nicknames[i], NULL);
- if(cert != NULL) {
- /* locate key and copy thumbprint */
- key = (SEC_PKCS12PrivateKey *)sec_pkcs12_find_object(safe, baggage,
- SEC_OID_PKCS12_KEY_BAG_ID,
- nicknames[i], NULL);
- if(key != NULL) {
- key->pvkData.poolp = key->poolp;
- rv = sec_pkcs12_add_thumbprint(&key->pvkData,
- &cert->value.x509->thumbprint);
- if(rv == SECFailure)
- error = PR_TRUE; /* XXX Set error? */
- }
- /* look in the baggage as well...*/
- if((baggage != NULL) && (error == PR_FALSE)) {
- espvk = sec_pkcs12_get_espvk_by_name(baggage, nicknames[i]);
- if(espvk != NULL) {
- espvk->espvkData.poolp = espvk->poolp;
- rv = sec_pkcs12_add_thumbprint(&espvk->espvkData,
- &cert->value.x509->thumbprint);
- if(rv == SECFailure)
- error = PR_TRUE; /* XXX Set error? */
- }
- }
- }
- i++;
- }
- if(error == PR_TRUE) {
- return SECFailure;
- }
- return SECSuccess;
- }
- /* append a safe bag to the end of the safe contents list */
- SECStatus
- sec_pkcs12_append_safe_bag(SEC_PKCS12SafeContents *safe,
- SEC_PKCS12SafeBag *bag)
- {
- int size;
- void *mark = NULL, *dummy = NULL;
- if((bag == NULL) || (safe == NULL))
- return SECFailure;
- mark = PORT_ArenaMark(safe->poolp);
- size = (safe->safe_size * sizeof(SEC_PKCS12SafeBag *));
-
- if(safe->safe_size > 0) {
- dummy = (SEC_PKCS12SafeBag **)PORT_ArenaGrow(safe->poolp,
- safe->contents,
- size,
- (size + sizeof(SEC_PKCS12SafeBag *)));
- safe->contents = dummy;
- } else {
- safe->contents = (SEC_PKCS12SafeBag **)PORT_ArenaZAlloc(safe->poolp,
- (2 * sizeof(SEC_PKCS12SafeBag *)));
- dummy = safe->contents;
- }
- if(dummy == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- safe->contents[safe->safe_size] = bag;
- safe->safe_size++;
- safe->contents[safe->safe_size] = NULL;
- PORT_ArenaUnmark(safe->poolp, mark);
- return SECSuccess;
- loser:
- PORT_ArenaRelease(safe->poolp, mark);
- return SECFailure;
- }
- /* append a certificate onto the end of a cert bag */
- static SECStatus
- sec_pkcs12_append_cert_to_bag(PRArenaPool *arena,
- SEC_PKCS12SafeBag *safebag,
- CERTCertificate *cert,
- SECItem *nickname)
- {
- int size;
- void *dummy = NULL, *mark = NULL;
- SEC_PKCS12CertAndCRL *p12cert;
- SEC_PKCS12CertAndCRLBag *bag;
- if((arena == NULL) || (safebag == NULL) ||
- (cert == NULL) || (nickname == NULL)) {
- return SECFailure;
- }
- bag = safebag->safeContent.certAndCRLBag;
- if(bag == NULL) {
- return SECFailure;
- }
- mark = PORT_ArenaMark(arena);
- p12cert = sec_pkcs12_get_cert(arena, cert, nickname);
- if(p12cert == NULL) {
- PORT_ArenaRelease(bag->poolp, mark);
- return SECFailure;
- }
- size = bag->bag_size * sizeof(SEC_PKCS12CertAndCRL *);
- if(bag->bag_size > 0) {
- dummy = (SEC_PKCS12CertAndCRL **)PORT_ArenaGrow(bag->poolp,
- bag->certAndCRLs, size, size + sizeof(SEC_PKCS12CertAndCRL *));
- bag->certAndCRLs = dummy;
- } else {
- bag->certAndCRLs = (SEC_PKCS12CertAndCRL **)PORT_ArenaZAlloc(bag->poolp,
- (2 * sizeof(SEC_PKCS12CertAndCRL *)));
- dummy = bag->certAndCRLs;
- }
- if(dummy == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- bag->certAndCRLs[bag->bag_size] = p12cert;
- bag->bag_size++;
- bag->certAndCRLs[bag->bag_size] = NULL;
- PORT_ArenaUnmark(bag->poolp, mark);
- return SECSuccess;
- loser:
- PORT_ArenaRelease(bag->poolp, mark);
- return SECFailure;
- }
- /* append a key onto the end of a list of keys in a key bag */
- SECStatus
- sec_pkcs12_append_key_to_bag(SEC_PKCS12SafeBag *safebag,
- SEC_PKCS12PrivateKey *pk)
- {
- void *mark, *dummy;
- SEC_PKCS12PrivateKeyBag *bag;
- int size;
- if((safebag == NULL) || (pk == NULL))
- return SECFailure;
- bag = safebag->safeContent.keyBag;
- if(bag == NULL) {
- return SECFailure;
- }
- mark = PORT_ArenaMark(bag->poolp);
- size = (bag->bag_size * sizeof(SEC_PKCS12PrivateKey *));
- if(bag->bag_size > 0) {
- dummy = (SEC_PKCS12PrivateKey **)PORT_ArenaGrow(bag->poolp,
- bag->privateKeys,
- size,
- size + sizeof(SEC_PKCS12PrivateKey *));
- bag->privateKeys = dummy;
- } else {
- bag->privateKeys = (SEC_PKCS12PrivateKey **)PORT_ArenaZAlloc(bag->poolp,
- (2 * sizeof(SEC_PKCS12PrivateKey *)));
- dummy = bag->privateKeys;
- }
- if(dummy == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- bag->privateKeys[bag->bag_size] = pk;
- bag->bag_size++;
- bag->privateKeys[bag->bag_size] = NULL;
- PORT_ArenaUnmark(bag->poolp, mark);
- return SECSuccess;
- loser:
- /* XXX Free memory? */
- PORT_ArenaRelease(bag->poolp, mark);
- return SECFailure;
- }
- /* append a safe bag to the baggage area */
- static SECStatus
- sec_pkcs12_append_unshrouded_bag(SEC_PKCS12BaggageItem *bag,
- SEC_PKCS12SafeBag *u_bag)
- {
- int size;
- void *mark = NULL, *dummy = NULL;
- if((bag == NULL) || (u_bag == NULL))
- return SECFailure;
- mark = PORT_ArenaMark(bag->poolp);
- /* dump things into the first bag */
- size = (bag->nSecrets + 1) * sizeof(SEC_PKCS12SafeBag *);
- dummy = PORT_ArenaGrow(bag->poolp,
- bag->unencSecrets, size,
- size + sizeof(SEC_PKCS12SafeBag *));
- bag->unencSecrets = dummy;
- if(dummy == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- bag->unencSecrets[bag->nSecrets] = u_bag;
- bag->nSecrets++;
- bag->unencSecrets[bag->nSecrets] = NULL;
- PORT_ArenaUnmark(bag->poolp, mark);
- return SECSuccess;
- loser:
- PORT_ArenaRelease(bag->poolp, mark);
- return SECFailure;
- }
- /* gather up all certificates and keys and package them up
- * in the safe, baggage, or both.
- * nicknames is the list of nicknames and corresponding certs in ref_certs
- * ref_certs a null terminated list of certificates
- * rSafe, rBaggage -- return areas for safe and baggage
- * shroud_keys -- store keys externally
- * pwitem -- password for computing integrity mac and encrypting contents
- * wincx -- window handle
- *
- * if a failure occurs, an error is set and SECFailure returned.
- */
- static SECStatus
- sec_pkcs12_package_certs_and_keys(SECItem **nicknames,
- CERTCertificate **ref_certs,
- PRBool unencryptedCerts,
- SEC_PKCS12SafeContents **rSafe,
- SEC_PKCS12Baggage **rBaggage,
- PRBool shroud_keys,
- SECOidTag shroud_alg,
- SECItem *pwitem,
- PKCS12UnicodeConvertFunction unicodeFn,
- void *wincx)
- {
- PRArenaPool *permArena;
- SEC_PKCS12SafeContents *safe = NULL;
- SEC_PKCS12Baggage *baggage = NULL;
- SECStatus rv = SECFailure;
- PRBool problem = PR_FALSE;
- SEC_PKCS12ESPVKItem *espvk = NULL;
- SEC_PKCS12PrivateKey *pk = NULL;
- CERTCertificate *add_cert = NULL;
- SEC_PKCS12SafeBag *certbag = NULL, *keybag = NULL;
- SEC_PKCS12BaggageItem *external_bag = NULL;
- int ncerts = 0, nkeys = 0;
- int i;
- if((nicknames == NULL) || (rSafe == NULL) || (rBaggage == NULL)) {
- return SECFailure;
- }
-
- *rBaggage = baggage;
- *rSafe = safe;
- permArena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
- if(permArena == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return SECFailure;
- }
- /* allocate structures */
- safe = sec_pkcs12_create_safe_contents(permArena);
- if(safe == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- rv = SECFailure;
- goto loser;
- }
- certbag = sec_pkcs12_create_safe_bag(permArena,
- SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID);
- if(certbag == NULL) {
- rv = SECFailure;
- goto loser;
- }
- if(shroud_keys != PR_TRUE) {
- keybag = sec_pkcs12_create_safe_bag(permArena,
- SEC_OID_PKCS12_KEY_BAG_ID);
- if(keybag == NULL) {
- rv = SECFailure;
- goto loser;
- }
- }
- if((shroud_keys == PR_TRUE) || (unencryptedCerts == PR_TRUE)) {
- baggage = sec_pkcs12_create_baggage(permArena);
- if(baggage == NULL) {
- rv = SECFailure;
- goto loser;
- }
- external_bag = sec_pkcs12_create_external_bag(baggage);
- }
- /* package keys and certs */
- i = 0;
- while((nicknames[i] != NULL) && (problem == PR_FALSE)) {
- if(ref_certs[i] != NULL) {
- /* append cert to bag o certs */
- rv = sec_pkcs12_append_cert_to_bag(permArena, certbag,
- ref_certs[i],
- nicknames[i]);
- if(rv == SECFailure) {
- problem = PR_FALSE;
- } else {
- ncerts++;
- }
- if(rv == SECSuccess) {
- /* package up them keys */
- if(shroud_keys == PR_TRUE) {
- espvk = sec_pkcs12_get_shrouded_key(permArena,
- nicknames[i],
- ref_certs[i],
- shroud_alg,
- pwitem, unicodeFn,
- wincx);
- if(espvk != NULL) {
- rv = sec_pkcs12_append_shrouded_key(external_bag, espvk);
- SECITEM_CopyItem(permArena, &espvk->derCert,
- &ref_certs[i]->derCert);
- } else {
- rv = SECFailure;
- }
- } else {
- pk = sec_pkcs12_get_private_key(permArena, nicknames[i],
- ref_certs[i], wincx);
- if(pk != NULL) {
- rv = sec_pkcs12_append_key_to_bag(keybag, pk);
- SECITEM_CopyItem(permArena, &espvk->derCert,
- &ref_certs[i]->derCert);
- } else {
- rv = SECFailure;
- }
- }
-
- if(rv == SECFailure) {
- problem = PR_TRUE;
- } else {
- nkeys++;
- }
- }
- } else {
- /* handle only keys here ? */
- problem = PR_TRUE;
- }
- i++;
- }
- /* let success fall through */
- loser:
- if(problem == PR_FALSE) {
- /* if we have certs, we want to append the cert bag to the
- * appropriate area
- */
- if(ncerts > 0) {
- if(unencryptedCerts != PR_TRUE) {
- rv = sec_pkcs12_append_safe_bag(safe, certbag);
- } else {
- rv = sec_pkcs12_append_unshrouded_bag(external_bag, certbag);
- }
- } else {
- rv = SECSuccess;
- }
- /* append key bag, if they are stored in safe contents */
- if((rv == SECSuccess) && (shroud_keys == PR_FALSE) && (nkeys > 0)) {
- rv = sec_pkcs12_append_safe_bag(safe, keybag);
- }
- } else {
- rv = SECFailure;
- }
- /* if baggage not used, NULLify it */
- if((shroud_keys == PR_TRUE) || (unencryptedCerts == PR_TRUE)) {
- if(((unencryptedCerts == PR_TRUE) && (ncerts == 0)) &&
- ((shroud_keys == PR_TRUE) && (nkeys == 0)))
- baggage = NULL;
- } else {
- baggage = NULL;
- }
- if((problem == PR_TRUE) || (rv == SECFailure)) {
- PORT_FreeArena(permArena, PR_TRUE);
- rv = SECFailure;
- baggage = NULL;
- safe = NULL;
- }
- *rBaggage = baggage;
- *rSafe = safe;
- return rv;
- }
- /* DER encode the safe contents and return a SECItem. if an error
- * occurs, NULL is returned.
- */
- static SECItem *
- sec_pkcs12_encode_safe_contents(SEC_PKCS12SafeContents *safe)
- {
- SECItem *dsafe = NULL, *tsafe;
- void *dummy = NULL;
- PRArenaPool *arena;
- if(safe == NULL) {
- return NULL;
- }
- /* rv = sec_pkcs12_prepare_for_der_code_safe(safe, PR_TRUE);
- if(rv != SECSuccess) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return NULL;
- }*/
- arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
- if(arena == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return NULL;
- }
- tsafe = (SECItem *)PORT_ArenaZAlloc(arena, sizeof(SECItem));
- if(tsafe != NULL) {
- dummy = SEC_ASN1EncodeItem(arena, tsafe, safe,
- SEC_PKCS12SafeContentsTemplate);
- if(dummy != NULL) {
- dsafe = SECITEM_DupItem(tsafe);
- } else {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- }
- } else {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- }
- PORT_FreeArena(arena, PR_TRUE);
- return dsafe;
- }
- /* prepare the authenicated safe for encoding and encode it.
- * baggage is copied to the appropriate area, safe is encoded and
- * encrypted. the version and transport mode are set on the asafe.
- * the whole ball of wax is then der encoded and packaged up into
- * data content info
- * safe -- container of certs and keys, is encrypted.
- * baggage -- container of certs and keys, keys assumed to be encrypted by
- * another method, certs are in the clear
- * algorithm -- algorithm by which to encrypt safe
- * pwitem -- password for encryption
- * wincx - window handle
- *
- * return of NULL is an error condition.
- */
- static SEC_PKCS7ContentInfo *
- sec_pkcs12_get_auth_safe(SEC_PKCS12SafeContents *safe,
- SEC_PKCS12Baggage *baggage,
- SECOidTag algorithm,
- SECItem *pwitem,
- PKCS12UnicodeConvertFunction unicodeFn,
- void *wincx)
- {
- SECItem *src = NULL, *dest = NULL, *psalt = NULL;
- PRArenaPool *poolp;
- SEC_PKCS12AuthenticatedSafe *asafe;
- SEC_PKCS7ContentInfo *safe_cinfo = NULL;
- SEC_PKCS7ContentInfo *asafe_cinfo = NULL;
- void *dummy;
- SECStatus rv = SECSuccess;
- PRBool swapUnicodeBytes = PR_FALSE;
- #ifdef IS_LITTLE_ENDIAN
- swapUnicodeBytes = PR_TRUE;
- #endif
-
- if(((safe != NULL) && (pwitem == NULL)) && (baggage == NULL))
- return NULL;
- poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
- if(poolp == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return NULL;
- }
- /* prepare authenticated safe for encode */
- asafe = sec_pkcs12_new_asafe(poolp);
- if(asafe != NULL) {
- /* set version */
- dummy = SEC_ASN1EncodeInteger(asafe->poolp, &asafe->version,
- SEC_PKCS12_PFX_VERSION);
- if(dummy == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- rv = SECFailure;
- goto loser;
- }
- /* generate the privacy salt used to create virtual pwd */
- psalt = sec_pkcs12_generate_salt();
- if(psalt != NULL) {
- rv = SECITEM_CopyItem(asafe->poolp, &asafe->privacySalt,
- psalt);
- if(rv == SECSuccess) {
- asafe->privacySalt.len *= 8;
- }
- else {
- SECITEM_ZfreeItem(psalt, PR_TRUE);
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- }
- if((psalt == NULL) || (rv == SECFailure)) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- rv = SECFailure;
- goto loser;
- }
- /* package up safe contents */
- if(safe != NULL)
- {
- safe_cinfo = SEC_PKCS7CreateEncryptedData(algorithm, NULL, wincx);
- if((safe_cinfo != NULL) && (safe->safe_size > 0)) {
- /* encode the safe and encrypt the contents of the
- * content info
- */
- src = sec_pkcs12_encode_safe_contents(safe);
- if(src != NULL) {
- rv = SEC_PKCS7SetContent(safe_cinfo, (char *)src->data, src->len);
- SECITEM_ZfreeItem(src, PR_TRUE);
- if(rv == SECSuccess) {
- SECItem *vpwd;
- vpwd = sec_pkcs12_create_virtual_password(pwitem, psalt,
- unicodeFn, swapUnicodeBytes);
- if(vpwd != NULL) {
- rv = SEC_PKCS7EncryptContents(NULL, safe_cinfo,
- vpwd, wincx);
- SECITEM_ZfreeItem(vpwd, PR_TRUE);
- } else {
- rv = SECFailure;
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- }
- } else {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- }
- } else {
- rv = SECFailure;
- }
- } else if(safe->safe_size > 0) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- } else {
- /* case where there is NULL content in the safe contents */
- rv = SEC_PKCS7SetContent(safe_cinfo, NULL, 0);
- if(rv != SECFailure) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- }
- }
- if(rv != SECSuccess) {
- SEC_PKCS7DestroyContentInfo(safe_cinfo);
- safe_cinfo = NULL;
- goto loser;
- }
- asafe->safe = safe_cinfo;
- /*
- PORT_Memcpy(&asafe->safe, safe_cinfo, sizeof(*safe_cinfo));
- */
- }
- /* copy the baggage to the authenticated safe baggage if present */
- if(baggage != NULL) {
- PORT_Memcpy(&asafe->baggage, baggage, sizeof(*baggage));
- }
- /* encode authenticated safe and store it in a Data content info */
- dest = (SECItem *)PORT_ArenaZAlloc(poolp, sizeof(SECItem));
- if(dest != NULL) {
- dummy = SEC_ASN1EncodeItem(poolp, dest, asafe,
- SEC_PKCS12AuthenticatedSafeTemplate);
- if(dummy != NULL) {
- asafe_cinfo = SEC_PKCS7CreateData();
- if(asafe_cinfo != NULL) {
- rv = SEC_PKCS7SetContent(asafe_cinfo,
- (char *)dest->data,
- dest->len);
- if(rv != SECSuccess) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- SEC_PKCS7DestroyContentInfo(asafe_cinfo);
- asafe_cinfo = NULL;
- }
- }
- } else {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- rv = SECFailure;
- }
- }
- }
- loser:
- PORT_FreeArena(poolp, PR_TRUE);
- if(safe_cinfo != NULL) {
- SEC_PKCS7DestroyContentInfo(safe_cinfo);
- }
- if(psalt != NULL) {
- SECITEM_ZfreeItem(psalt, PR_TRUE);
- }
- if(rv == SECFailure) {
- return NULL;
- }
-
- return asafe_cinfo;
- }
- /* generates the PFX and computes the mac on the authenticated safe
- * NULL implies an error
- */
- static SEC_PKCS12PFXItem *
- sec_pkcs12_get_pfx(SEC_PKCS7ContentInfo *cinfo,
- PRBool do_mac,
- SECItem *pwitem, PKCS12UnicodeConvertFunction unicodeFn)
- {
- SECItem *dest = NULL, *mac = NULL, *salt = NULL, *key = NULL;
- SEC_PKCS12PFXItem *pfx;
- SECStatus rv = SECFailure;
- SGNDigestInfo *di;
- SECItem *vpwd;
- PRBool swapUnicodeBytes = PR_FALSE;
- #ifdef IS_LITTLE_ENDIAN
- swapUnicodeBytes = PR_TRUE;
- #endif
- if((cinfo == NULL) || ((do_mac == PR_TRUE) && (pwitem == NULL))) {
- return NULL;
- }
- /* allocate new pfx structure */
- pfx = sec_pkcs12_new_pfx();
- if(pfx == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return NULL;
- }
- PORT_Memcpy(&pfx->authSafe, cinfo, sizeof(*cinfo));
- if(do_mac == PR_TRUE) {
- /* salt for computing mac */
- salt = sec_pkcs12_generate_salt();
- if(salt != NULL) {
- rv = SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, salt);
- pfx->macData.macSalt.len *= 8;
- vpwd = sec_pkcs12_create_virtual_password(pwitem, salt,
- unicodeFn, swapUnicodeBytes);
- if(vpwd == NULL) {
- rv = SECFailure;
- key = NULL;
- } else {
- key = sec_pkcs12_generate_key_from_password(SEC_OID_SHA1,
- salt, vpwd);
- SECITEM_ZfreeItem(vpwd, PR_TRUE);
- }
- if((key != NULL) && (rv == SECSuccess)) {
- dest = SEC_PKCS7GetContent(cinfo);
- if(dest != NULL) {
- /* compute mac on data -- for password integrity mode */
- mac = sec_pkcs12_generate_mac(key, dest, PR_FALSE);
- if(mac != NULL) {
- di = SGN_CreateDigestInfo(SEC_OID_SHA1,
- mac->data, mac->len);
- if(di != NULL) {
- rv = SGN_CopyDigestInfo(pfx->poolp,
- &pfx->macData.safeMac, di);
- SGN_DestroyDigestInfo(di);
- } else {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- }
- SECITEM_ZfreeItem(mac, PR_TRUE);
- }
- } else {
- rv = SECFailure;
- }
- } else {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- rv = SECFailure;
- }
- if(key != NULL) {
- SECITEM_ZfreeItem(key, PR_TRUE);
- }
- SECITEM_ZfreeItem(salt, PR_TRUE);
- }
- }
- if(rv == SECFailure) {
- SEC_PKCS12DestroyPFX(pfx);
- pfx = NULL;
- }
- return pfx;
- }
- /* der encode the pfx */
- static SECItem *
- sec_pkcs12_encode_pfx(SEC_PKCS12PFXItem *pfx)
- {
- SECItem *dest;
- void *dummy;
- if(pfx == NULL) {
- return NULL;
- }
- dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
- if(dest == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return NULL;
- }
- dummy = SEC_ASN1EncodeItem(NULL, dest, pfx, SEC_PKCS12PFXItemTemplate);
- if(dummy == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- SECITEM_ZfreeItem(dest, PR_TRUE);
- dest = NULL;
- }
- return dest;
- }
- SECItem *
- SEC_PKCS12GetPFX(char **nicknames,
- CERTCertificate **ref_certs,
- PRBool shroud_keys,
- SEC_PKCS5GetPBEPassword pbef,
- void *pbearg,
- PKCS12UnicodeConvertFunction unicodeFn,
- void *wincx)
- {
- SECItem **nicks = NULL;
- SEC_PKCS12PFXItem *pfx = NULL;
- SEC_PKCS12Baggage *baggage = NULL;
- SEC_PKCS12SafeContents *safe = NULL;
- SEC_PKCS7ContentInfo *cinfo = NULL;
- SECStatus rv = SECFailure;
- SECItem *dest = NULL, *pwitem = NULL;
- PRBool problem = PR_FALSE;
- PRBool unencryptedCerts;
- SECOidTag shroud_alg, safe_alg;
- /* how should we encrypt certs ? */
- unencryptedCerts = !SEC_PKCS12IsEncryptionAllowed();
- if(!unencryptedCerts) {
- safe_alg = SEC_PKCS12GetPreferredEncryptionAlgorithm();
- if(safe_alg == SEC_OID_UNKNOWN) {
- safe_alg = SEC_PKCS12GetStrongestAllowedAlgorithm();
- }
- if(safe_alg == SEC_OID_UNKNOWN) {
- unencryptedCerts = PR_TRUE;
- /* for export where no encryption is allowed, we still need
- * to encrypt the NULL contents per the spec. encrypted info
- * is known plaintext, so it shouldn't be a problem.
- */
- safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC;
- }
- } else {
- /* for export where no encryption is allowed, we still need
- * to encrypt the NULL contents per the spec. encrypted info
- * is known plaintext, so it shouldn't be a problem.
- */
- safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC;
- }
- /* keys are always stored with triple DES */
- shroud_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC;
- /* check for FIPS, if so, do not encrypt certs */
- if(PK11_IsFIPS() && !unencryptedCerts) {
- unencryptedCerts = PR_TRUE;
- }
- if((nicknames == NULL) || (pbef == NULL) || (ref_certs == NULL)) {
- problem = PR_TRUE;
- goto loser;
- }
- /* get password */
- pwitem = (*pbef)(pbearg);
- if(pwitem == NULL) {
- problem = PR_TRUE;
- goto loser;
- }
- nicks = sec_pkcs12_convert_nickname_list(nicknames);
- /* get safe and baggage */
- rv = sec_pkcs12_package_certs_and_keys(nicks, ref_certs, unencryptedCerts,
- &safe, &baggage, shroud_keys,
- shroud_alg, pwitem, unicodeFn, wincx);
- if(rv == SECFailure) {
- problem = PR_TRUE;
- }
- if((safe != NULL) && (problem == PR_FALSE)) {
- /* copy thumbprints */
- rv = sec_pkcs12_propagate_thumbprints(nicks, ref_certs, safe, baggage);
- /* package everything up into AuthenticatedSafe */
- cinfo = sec_pkcs12_get_auth_safe(safe, baggage,
- safe_alg, pwitem, unicodeFn, wincx);
- sec_pkcs12_destroy_cert_content_infos(safe, baggage);
- /* get the pfx and mac it */
- if(cinfo != NULL) {
- pfx = sec_pkcs12_get_pfx(cinfo, PR_TRUE, pwitem, unicodeFn);
- if(pfx != NULL) {
- dest = sec_pkcs12_encode_pfx(pfx);
- SEC_PKCS12DestroyPFX(pfx);
- }
- SEC_PKCS7DestroyContentInfo(cinfo);
- }
- if(safe != NULL) {
- PORT_FreeArena(safe->poolp, PR_TRUE);
- }
- } else {
- if(safe != NULL) {
- PORT_FreeArena(safe->poolp, PR_TRUE);
- }
- }
- loser:
- if(nicks != NULL) {
- sec_pkcs12_destroy_nickname_list(nicks);
- }
- if(ref_certs != NULL) {
- sec_pkcs12_destroy_certificate_list(ref_certs);
- }
- if(pwitem != NULL) {
- SECITEM_ZfreeItem(pwitem, PR_TRUE);
- }
- if(problem == PR_TRUE) {
- dest = NULL;
- }
- return dest;
- }