Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/security/nss/lib/pkcs12/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 42 kB image not shown  

Quelle  p12exp.c   Sprache: C

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#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(PLArenaPool *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(PLArenaPool *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(PLArenaPool *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(PLArenaPool *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)
{
    PLArenaPool *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;
    PLArenaPool *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;
    PLArenaPool *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;
}

Messung V0.5
C=95 H=84 G=89

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.