Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  cmssigdata.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/. */


/*
 * CMS signedData methods.
 */


#include "cmslocal.h"

#include "cert.h"
/*#include "cdbhdl.h"*/
#include "secasn1.h"
#include "secitem.h"
#include "secoid.h"
#include "pk11func.h"
#include "secerr.h"

NSSCMSSignedData *
NSS_CMSSignedData_Create(NSSCMSMessage *cmsg)
{
    void *mark;
    NSSCMSSignedData *sigd;
    PLArenaPool *poolp;

    if (!cmsg) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return NULL;
    }

    poolp = cmsg->poolp;

    mark = PORT_ArenaMark(poolp);

    sigd = (NSSCMSSignedData *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSSignedData));
    if (sigd == NULL)
        goto loser;

    sigd->cmsg = cmsg;

    /* signerInfos, certs, certlists, crls are all empty */
    /* version is set in NSS_CMSSignedData_Finalize() */

    PORT_ArenaUnmark(poolp, mark);
    return sigd;

loser:
    PORT_ArenaRelease(poolp, mark);
    return NULL;
}

void
NSS_CMSSignedData_Destroy(NSSCMSSignedData *sigd)
{
    CERTCertificate **certs, **tempCerts, *cert;
    CERTCertificateList **certlists, *certlist;
    NSSCMSSignerInfo **signerinfos, *si;

    if (sigd == NULL)
        return;

    certs = sigd->certs;
    tempCerts = sigd->tempCerts;
    certlists = sigd->certLists;
    signerinfos = sigd->signerInfos;

    if (certs != NULL) {
        while ((cert = *certs++) != NULL)
            CERT_DestroyCertificate(cert);
    }

    if (tempCerts != NULL) {
        while ((cert = *tempCerts++) != NULL)
            CERT_DestroyCertificate(cert);
    }

    if (certlists != NULL) {
        while ((certlist = *certlists++) != NULL)
            CERT_DestroyCertificateList(certlist);
    }

    if (signerinfos != NULL) {
        while ((si = *signerinfos++) != NULL)
            NSS_CMSSignerInfo_Destroy(si);
    }

    /* everything's in a pool, so don't worry about the storage */
    NSS_CMSContentInfo_Destroy(&(sigd->contentInfo));
}

/*
 * NSS_CMSSignedData_Encode_BeforeStart - do all the necessary things to a SignedData
 *     before start of encoding.
 *
 * In detail:
 *  - find out about the right value to put into sigd->version
 *  - come up with a list of digestAlgorithms (which should be the union of the algorithms
 *         in the signerinfos).
 *         If we happen to have a pre-set list of algorithms (and digest values!), we
 *         check if we have all the signerinfos' algorithms. If not, this is an error.
 */

SECStatus
NSS_CMSSignedData_Encode_BeforeStart(NSSCMSSignedData *sigd)
{
    NSSCMSSignerInfo *signerinfo;
    SECOidTag digestalgtag;
    SECItem *dummy;
    int version;
    SECStatus rv;
    PRBool haveDigests = PR_FALSE;
    int n, i;
    PLArenaPool *poolp;

    if (!sigd) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    poolp = sigd->cmsg->poolp;

    /* we assume that we have precomputed digests if there is a list of algorithms, and */
    /* a chunk of data for each of those algorithms */
    if (sigd->digestAlgorithms != NULL && sigd->digests != NULL) {
        for (i = 0; sigd->digestAlgorithms[i] != NULL; i++) {
            if (sigd->digests[i] == NULL)
                break;
        }
        if (sigd->digestAlgorithms[i] == NULL) /* reached the end of the array? */
            haveDigests = PR_TRUE;             /* yes: we must have all the digests */
    }

    version = NSS_CMS_SIGNED_DATA_VERSION_BASIC;

    /* RFC2630 5.1 "version is the syntax version number..." */
    if (NSS_CMSContentInfo_GetContentTypeTag(&(sigd->contentInfo)) != SEC_OID_PKCS7_DATA)
        version = NSS_CMS_SIGNED_DATA_VERSION_EXT;

    /* prepare all the SignerInfos (there may be none) */
    for (i = 0; i < NSS_CMSSignedData_SignerInfoCount(sigd); i++) {
        signerinfo = NSS_CMSSignedData_GetSignerInfo(sigd, i);

        /* RFC2630 5.1 "version is the syntax version number..." */
        if (NSS_CMSSignerInfo_GetVersion(signerinfo) != NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN)
            version = NSS_CMS_SIGNED_DATA_VERSION_EXT;

        /* collect digestAlgorithms from SignerInfos */
        /* (we need to know which algorithms we have when the content comes in) */
        /* do not overwrite any existing digestAlgorithms (and digest) */
        digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
        n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
        if (n < 0 && haveDigests) {
            /* oops, there is a digestalg we do not have a digest for */
            /* but we were supposed to have all the digests already... */
            goto loser;
        } else if (n < 0) {
            /* add the digestAlgorithm & a NULL digest */
            rv = NSS_CMSSignedData_AddDigest(poolp, sigd, digestalgtag, NULL);
            if (rv != SECSuccess)
                goto loser;
        } else {
            /* found it, nothing to do */
        }
    }

    dummy = SEC_ASN1EncodeInteger(poolp, &(sigd->version), (long)version);
    if (dummy == NULL)
        return SECFailure;

    /* this is a SET OF, so we need to sort them guys */
    rv = NSS_CMSArray_SortByDER((void **)sigd->digestAlgorithms,
                                SEC_ASN1_GET(SECOID_AlgorithmIDTemplate),
                                (void **)sigd->digests);
    if (rv != SECSuccess)
        return SECFailure;

    return SECSuccess;

loser:
    return SECFailure;
}

SECStatus
NSS_CMSSignedData_Encode_BeforeData(NSSCMSSignedData *sigd)
{
    SECStatus rv;
    if (!sigd) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }
    rv = NSS_CMSContentInfo_Private_Init(&sigd->contentInfo);
    if (rv != SECSuccess) {
        return SECFailure;
    }
    /* set up the digests */
    if (sigd->digests && sigd->digests[0]) {
        sigd->contentInfo.privateInfo->digcx = NULL; /* don't attempt to make new ones. */
    } else if (sigd->digestAlgorithms != NULL) {
        sigd->contentInfo.privateInfo->digcx =
            NSS_CMSDigestContext_StartMultiple(sigd->digestAlgorithms);
        if (sigd->contentInfo.privateInfo->digcx == NULL)
            return SECFailure;
    }
    return SECSuccess;
}

/*
 * NSS_CMSSignedData_Encode_AfterData - do all the necessary things to a SignedData
 *     after all the encapsulated data was passed through the encoder.
 *
 * In detail:
 *  - create the signatures in all the SignerInfos
 *
 * Please note that nothing is done to the Certificates and CRLs in the message - this
 * is entirely the responsibility of our callers.
 */

SECStatus
NSS_CMSSignedData_Encode_AfterData(NSSCMSSignedData *sigd)
{
    NSSCMSSignerInfo **signerinfos, *signerinfo;
    NSSCMSContentInfo *cinfo;
    SECOidTag digestalgtag;
    SECStatus ret = SECFailure;
    SECStatus rv;
    SECItem *contentType;
    int certcount;
    int i, ci, cli, n, rci, si;
    PLArenaPool *poolp;
    CERTCertificateList *certlist;
    extern const SEC_ASN1Template NSSCMSSignerInfoTemplate[];

    if (!sigd) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    poolp = sigd->cmsg->poolp;
    cinfo = &(sigd->contentInfo);

    /* did we have digest calculation going on? */
    if (cinfo->privateInfo && cinfo->privateInfo->digcx) {
        rv = NSS_CMSDigestContext_FinishMultiple(cinfo->privateInfo->digcx, poolp,
                                                 &(sigd->digests));
        /* error has been set by NSS_CMSDigestContext_FinishMultiple */
        cinfo->privateInfo->digcx = NULL;
        if (rv != SECSuccess)
            goto loser;
    }

    signerinfos = sigd->signerInfos;
    certcount = 0;

    /* prepare all the SignerInfos (there may be none) */
    for (i = 0; i < NSS_CMSSignedData_SignerInfoCount(sigd); i++) {
        signerinfo = NSS_CMSSignedData_GetSignerInfo(sigd, i);

        /* find correct digest for this signerinfo */
        digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
        n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
        if (n < 0 || sigd->digests == NULL || sigd->digests[n] == NULL) {
            /* oops - digest not found */
            PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND);
            goto loser;
        }

        /* XXX if our content is anything else but data, we need to force the
         * presence of signed attributes (RFC2630 5.3 "signedAttributes is a
         * collection...") */


        /* pass contentType here as we want a contentType attribute */
        if ((contentType = NSS_CMSContentInfo_GetContentTypeOID(cinfo)) == NULL)
            goto loser;

        /* sign the thing */
        rv = NSS_CMSSignerInfo_Sign(signerinfo, sigd->digests[n], contentType);
        if (rv != SECSuccess)
            goto loser;

        /* while we're at it, count number of certs in certLists */
        certlist = NSS_CMSSignerInfo_GetCertList(signerinfo);
        if (certlist)
            certcount += certlist->len;
    }

    /* this is a SET OF, so we need to sort them guys */
    rv = NSS_CMSArray_SortByDER((void **)signerinfos, NSSCMSSignerInfoTemplate, NULL);
    if (rv != SECSuccess)
        goto loser;

    /*
     * now prepare certs & crls
     */


    /* count the rest of the certs */
    if (sigd->certs != NULL) {
        for (ci = 0; sigd->certs[ci] != NULL; ci++)
            certcount++;
    }

    if (sigd->certLists != NULL) {
        for (cli = 0; sigd->certLists[cli] != NULL; cli++)
            certcount += sigd->certLists[cli]->len;
    }

    if (certcount == 0) {
        sigd->rawCerts = NULL;
    } else {
        /*
         * Combine all of the certs and cert chains into rawcerts.
         * Note: certcount is an upper bound; we may not need that many slots
         * but we will allocate anyway to avoid having to do another pass.
         * (The temporary space saving is not worth it.)
         *
         * XXX ARGH - this NEEDS to be fixed. need to come up with a decent
         *  SetOfDERcertficates implementation
         */

        sigd->rawCerts = (SECItem **)PORT_ArenaAlloc(poolp, (certcount + 1) * sizeof(SECItem *));
        if (sigd->rawCerts == NULL)
            return SECFailure;

        /*
         * XXX Want to check for duplicates and not add *any* cert that is
         * already in the set.  This will be more important when we start
         * dealing with larger sets of certs, dual-key certs (signing and
         * encryption), etc.  For the time being we can slide by...
         *
         * XXX ARGH - this NEEDS to be fixed. need to come up with a decent
         *  SetOfDERcertficates implementation
         */

        rci = 0;
        if (signerinfos != NULL) {
            for (si = 0; signerinfos[si] != NULL; si++) {
                signerinfo = signerinfos[si];
                for (ci = 0; ci < signerinfo->certList->len; ci++)
                    sigd->rawCerts[rci++] = &(signerinfo->certList->certs[ci]);
            }
        }

        if (sigd->certs != NULL) {
            for (ci = 0; sigd->certs[ci] != NULL; ci++)
                sigd->rawCerts[rci++] = &(sigd->certs[ci]->derCert);
        }

        if (sigd->certLists != NULL) {
            for (cli = 0; sigd->certLists[cli] != NULL; cli++) {
                for (ci = 0; ci < sigd->certLists[cli]->len; ci++)
                    sigd->rawCerts[rci++] = &(sigd->certLists[cli]->certs[ci]);
            }
        }

        sigd->rawCerts[rci] = NULL;

        /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
        NSS_CMSArray_Sort((void **)sigd->rawCerts, NSS_CMSUtil_DERCompare, NULL, NULL);
    }

    ret = SECSuccess;

loser:
    return ret;
}

SECStatus
NSS_CMSSignedData_Decode_BeforeData(NSSCMSSignedData *sigd)
{
    SECStatus rv;
    if (!sigd) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }
    rv = NSS_CMSContentInfo_Private_Init(&sigd->contentInfo);
    if (rv != SECSuccess) {
        return SECFailure;
    }
    /* handle issue with Windows 2003 servers and kerberos */
    if (sigd->digestAlgorithms != NULL) {
        int i;
        for (i = 0; sigd->digestAlgorithms[i] != NULL; i++) {
            SECAlgorithmID *algid = sigd->digestAlgorithms[i];
            SECOidTag senttag = SECOID_FindOIDTag(&algid->algorithm);
            SECOidTag maptag = NSS_CMSUtil_MapSignAlgs(senttag);

            if (maptag != senttag) {
                SECOidData *hashoid = SECOID_FindOIDByTag(maptag);
                rv = SECITEM_CopyItem(sigd->cmsg->poolp, &algid->algorithm, &hashoid->oid);
                if (rv != SECSuccess) {
                    return rv;
                }
            }
        }
    }

    /* set up the digests */
    if (sigd->digestAlgorithms != NULL && sigd->digests == NULL) {
        /* if digests are already there, do nothing */
        sigd->contentInfo.privateInfo->digcx = NSS_CMSDigestContext_StartMultiple(sigd->digestAlgorithms);
        if (sigd->contentInfo.privateInfo->digcx == NULL)
            return SECFailure;
    }
    return SECSuccess;
}

/*
 * NSS_CMSSignedData_Decode_AfterData - do all the necessary things to a
 *   SignedData after all the encapsulated data was passed through the decoder.
 */

SECStatus
NSS_CMSSignedData_Decode_AfterData(NSSCMSSignedData *sigd)
{
    SECStatus rv = SECSuccess;

    if (!sigd) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    /* did we have digest calculation going on? */
    if (sigd->contentInfo.privateInfo && sigd->contentInfo.privateInfo->digcx) {
        rv = NSS_CMSDigestContext_FinishMultiple(sigd->contentInfo.privateInfo->digcx,
                                                 sigd->cmsg->poolp, &(sigd->digests));
        /* error set by NSS_CMSDigestContext_FinishMultiple */
        sigd->contentInfo.privateInfo->digcx = NULL;
    }
    return rv;
}

/*
 * NSS_CMSSignedData_Decode_AfterEnd - do all the necessary things to a SignedData
 *     after all decoding is finished.
 */

SECStatus
NSS_CMSSignedData_Decode_AfterEnd(NSSCMSSignedData *sigd)
{
    NSSCMSSignerInfo **signerinfos = NULL;
    int i;

    if (!sigd) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    /* set cmsg for all the signerinfos */
    signerinfos = sigd->signerInfos;

    /* set cmsg for all the signerinfos */
    if (signerinfos) {
        for (i = 0; signerinfos[i] != NULL; i++)
            signerinfos[i]->cmsg = sigd->cmsg;
    }

    return SECSuccess;
}

/*
 * NSS_CMSSignedData_GetSignerInfos - retrieve the SignedData's signer list
 */

NSSCMSSignerInfo **
NSS_CMSSignedData_GetSignerInfos(NSSCMSSignedData *sigd)
{
    if (!sigd) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return NULL;
    }
    return sigd->signerInfos;
}

int
NSS_CMSSignedData_SignerInfoCount(NSSCMSSignedData *sigd)
{
    if (!sigd) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return 0;
    }
    return NSS_CMSArray_Count((void **)sigd->signerInfos);
}

NSSCMSSignerInfo *
NSS_CMSSignedData_GetSignerInfo(NSSCMSSignedData *sigd, int i)
{
    if (!sigd || !sigd->signerInfos) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return NULL;
    }
    return sigd->signerInfos[i];
}

/*
 * NSS_CMSSignedData_GetDigestAlgs - retrieve the SignedData's digest algorithm list
 */

SECAlgorithmID **
NSS_CMSSignedData_GetDigestAlgs(NSSCMSSignedData *sigd)
{
    if (!sigd) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return NULL;
    }
    return sigd->digestAlgorithms;
}

/*
 * NSS_CMSSignedData_GetContentInfo - return pointer to this signedData's contentinfo
 */

NSSCMSContentInfo *
NSS_CMSSignedData_GetContentInfo(NSSCMSSignedData *sigd)
{
    if (!sigd) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return NULL;
    }
    return &(sigd->contentInfo);
}

/*
 * NSS_CMSSignedData_GetCertificateList - retrieve the SignedData's certificate list
 */

SECItem **
NSS_CMSSignedData_GetCertificateList(NSSCMSSignedData *sigd)
{
    if (!sigd) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return NULL;
    }
    return sigd->rawCerts;
}

SECStatus
NSS_CMSSignedData_ImportCerts(NSSCMSSignedData *sigd, CERTCertDBHandle *certdb,
                              SECCertUsage certusage, PRBool keepcerts)
{
    int certcount;
    CERTCertificate **certArray = NULL;
    CERTCertList *certList = NULL;
    CERTCertListNode *node;
    SECStatus rv;
    SECItem **rawArray;
    int i;
    PRTime now;

    if (!sigd) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    certcount = NSS_CMSArray_Count((void **)sigd->rawCerts);

    /* get the certs in the temp DB */
    rv = CERT_ImportCerts(certdb, certusage, certcount, sigd->rawCerts,
                          &certArray, PR_FALSE, PR_FALSE, NULL);
    if (rv != SECSuccess) {
        goto loser;
    }

    /* save the certs so they don't get destroyed */
    for (i = 0; i < certcount; i++) {
        CERTCertificate *cert = certArray[i];
        if (cert)
            NSS_CMSSignedData_AddTempCertificate(sigd, cert);
    }

    if (!keepcerts) {
        goto done;
    }

    /* build a CertList for filtering */
    certList = CERT_NewCertList();
    if (certList == NULL) {
        rv = SECFailure;
        goto loser;
    }
    for (i = 0; i < certcount; i++) {
        CERTCertificate *cert = certArray[i];
        if (cert)
            cert = CERT_DupCertificate(cert);
        if (cert)
            CERT_AddCertToListTail(certList, cert);
    }

    /* filter out the certs we don't want */
    rv = CERT_FilterCertListByUsage(certList, certusage, PR_FALSE);
    if (rv != SECSuccess) {
        goto loser;
    }

    /* go down the remaining list of certs and verify that they have
     * valid chains, then import them.
     */

    now = PR_Now();
    for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
         node = CERT_LIST_NEXT(node)) {
        CERTCertificateList *certChain;

        if (CERT_VerifyCert(certdb, node->cert,
                            PR_TRUE, certusage, now, NULL, NULL) != SECSuccess) {
            continue;
        }

        certChain = CERT_CertChainFromCert(node->cert, certusage, PR_FALSE);
        if (!certChain) {
            continue;
        }

        /*
         * CertChain returns an array of SECItems, import expects an array of
         * SECItem pointers. Create the SECItem Pointers from the array of
         * SECItems.
         */

        rawArray = (SECItem **)PORT_Alloc(certChain->len * sizeof(SECItem *));
        if (!rawArray) {
            CERT_DestroyCertificateList(certChain);
            continue;
        }
        for (i = 0; i < certChain->len; i++) {
            rawArray[i] = &certChain->certs[i];
        }
        (void)CERT_ImportCerts(certdb, certusage, certChain->len,
                               rawArray, NULL, keepcerts, PR_FALSE, NULL);
        PORT_Free(rawArray);
        CERT_DestroyCertificateList(certChain);
    }

    rv = SECSuccess;

    /* XXX CRL handling */

done:
    if (sigd->signerInfos != NULL) {
        /* fill in all signerinfo's certs */
        for (i = 0; sigd->signerInfos[i] != NULL; i++)
            (void)NSS_CMSSignerInfo_GetSigningCertificate(
                sigd->signerInfos[i], certdb);
    }

loser:
    /* now free everything */
    if (certArray) {
        CERT_DestroyCertArray(certArray, certcount);
    }
    if (certList) {
        CERT_DestroyCertList(certList);
    }

    return rv;
}

/*
 * XXX the digests need to be passed in BETWEEN the decoding and the verification in case
 *     of external signatures!
 */


/*
 * NSS_CMSSignedData_VerifySignerInfo - check the signatures.
 *
 * The digests were either calculated during decoding (and are stored in the
 * signedData itself) or set after decoding using NSS_CMSSignedData_SetDigests.
 *
 * The verification checks if the signing cert is valid and has a trusted chain
 * for the purpose specified by "certusage".
 */

SECStatus
NSS_CMSSignedData_VerifySignerInfo(NSSCMSSignedData *sigd, int i,
                                   CERTCertDBHandle *certdb, SECCertUsage certusage)
{
    NSSCMSSignerInfo *signerinfo;
    NSSCMSContentInfo *cinfo;
    SECOidData *algiddata;
    SECItem *contentType, *digest;
    SECOidTag oidTag;
    SECStatus rv;

    if (!sigd || !sigd->signerInfos) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    cinfo = &(sigd->contentInfo);

    signerinfo = sigd->signerInfos[i];

    /* verify certificate */
    rv = NSS_CMSSignerInfo_VerifyCertificate(signerinfo, certdb, certusage);
    if (rv != SECSuccess)
        return rv; /* error is set */

    /* find digest and contentType for signerinfo */
    algiddata = NSS_CMSSignerInfo_GetDigestAlg(signerinfo);
    oidTag = algiddata ? algiddata->offset : SEC_OID_UNKNOWN;
    digest = NSS_CMSSignedData_GetDigestValue(sigd, oidTag);
    /* NULL digest is acceptable. */
    contentType = NSS_CMSContentInfo_GetContentTypeOID(cinfo);
    /* NULL contentType is acceptable. */

    /* now verify signature */
    rv = NSS_CMSSignerInfo_Verify(signerinfo, digest, contentType);
    return rv;
}

/*
 * NSS_CMSSignedData_VerifyCertsOnly - verify the certs in a certs-only message
 */

SECStatus
NSS_CMSSignedData_VerifyCertsOnly(NSSCMSSignedData *sigd,
                                  CERTCertDBHandle *certdb,
                                  SECCertUsage usage)
{
    CERTCertificate *cert;
    SECStatus rv = SECSuccess;
    int i;
    int count;
    PRTime now;
    void *pwarg = NULL;

    if (!sigd || !certdb || !sigd->rawCerts) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    count = NSS_CMSArray_Count((void **)sigd->rawCerts);
    now = PR_Now();
    for (i = 0; i < count; i++) {
        if (sigd->certs && sigd->certs[i]) {
            cert = CERT_DupCertificate(sigd->certs[i]);
        } else {
            cert = CERT_FindCertByDERCert(certdb, sigd->rawCerts[i]);
            if (!cert) {
                rv = SECFailure;
                break;
            }
        }
        if (sigd->cmsg) {
            pwarg = sigd->cmsg->pwfn_arg;
        }
        rv |= CERT_VerifyCert(certdb, cert, PR_TRUE, usage, now,
                              pwarg, NULL);
        CERT_DestroyCertificate(cert);
    }

    return rv;
}

/*
 * NSS_CMSSignedData_HasDigests - see if we have digests in place
 */

PRBool
NSS_CMSSignedData_HasDigests(NSSCMSSignedData *sigd)
{
    if (!sigd) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return PR_FALSE;
    }
    return (sigd->digests != NULL);
}

SECStatus
NSS_CMSSignedData_AddCertList(NSSCMSSignedData *sigd, CERTCertificateList *certlist)
{
    SECStatus rv;

    if (!sigd || !certlist) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    /* XXX memory?? a certlist has an arena of its own and is not refcounted!?!? */
    rv = NSS_CMSArray_Add(sigd->cmsg->poolp, (void ***)&(sigd->certLists), (void *)certlist);

    return rv;
}

/*
 * NSS_CMSSignedData_AddCertChain - add cert and its entire chain to the set of certs
 */

SECStatus
NSS_CMSSignedData_AddCertChain(NSSCMSSignedData *sigd, CERTCertificate *cert)
{
    CERTCertificateList *certlist;
    SECCertUsage usage;
    SECStatus rv;

    usage = certUsageEmailSigner;

    if (!sigd || !cert) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    /* do not include root */
    certlist = CERT_CertChainFromCert(cert, usage, PR_FALSE);
    if (certlist == NULL)
        return SECFailure;

    rv = NSS_CMSSignedData_AddCertList(sigd, certlist);

    return rv;
}

extern SECStatus
NSS_CMSSignedData_AddTempCertificate(NSSCMSSignedData *sigd, CERTCertificate *cert)
{
    CERTCertificate *c;
    SECStatus rv;

    if (!sigd || !cert) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    c = CERT_DupCertificate(cert);
    rv = NSS_CMSArray_Add(sigd->cmsg->poolp, (void ***)&(sigd->tempCerts), (void *)c);
    return rv;
}

SECStatus
NSS_CMSSignedData_AddCertificate(NSSCMSSignedData *sigd, CERTCertificate *cert)
{
    CERTCertificate *c;
    SECStatus rv;

    if (!sigd || !cert) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    c = CERT_DupCertificate(cert);
    rv = NSS_CMSArray_Add(sigd->cmsg->poolp, (void ***)&(sigd->certs), (void *)c);
    return rv;
}

PRBool
NSS_CMSSignedData_ContainsCertsOrCrls(NSSCMSSignedData *sigd)
{
    if (!sigd) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return PR_FALSE;
    }
    if (sigd->rawCerts != NULL && sigd->rawCerts[0] != NULL)
        return PR_TRUE;
    else if (sigd->crls != NULL && sigd->crls[0] != NULL)
        return PR_TRUE;
    else
        return PR_FALSE;
}

SECStatus
NSS_CMSSignedData_AddSignerInfo(NSSCMSSignedData *sigd,
                                NSSCMSSignerInfo *signerinfo)
{
    void *mark;
    SECStatus rv;
    SECOidTag digestalgtag;
    PLArenaPool *poolp;

    if (!sigd || !signerinfo) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    poolp = sigd->cmsg->poolp;

    mark = PORT_ArenaMark(poolp);

    /* add signerinfo */
    rv = NSS_CMSArray_Add(poolp, (void ***)&(sigd->signerInfos), (void *)signerinfo);
    if (rv != SECSuccess)
        goto loser;

    /*
     * add empty digest
     * Empty because we don't have it yet. Either it gets created during encoding
     * (if the data is present) or has to be set externally.
     * XXX maybe pass it in optionally?
     */

    digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
    rv = NSS_CMSSignedData_SetDigestValue(sigd, digestalgtag, NULL);
    if (rv != SECSuccess)
        goto loser;

    /*
     * The last thing to get consistency would be adding the digest.
     */


    PORT_ArenaUnmark(poolp, mark);
    return SECSuccess;

loser:
    PORT_ArenaRelease(poolp, mark);
    return SECFailure;
}

/*
 * NSS_CMSSignedData_SetDigests - set a signedData's digests member
 *
 * "digestalgs" - array of digest algorithm IDs
 * "digests"    - array of digests corresponding to the digest algorithms
 */

SECStatus
NSS_CMSSignedData_SetDigests(NSSCMSSignedData *sigd,
                             SECAlgorithmID **digestalgs,
                             SECItem **digests)
{
    int cnt, i, idx;

    if (!sigd || !digestalgs || !digests) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    if (sigd->digestAlgorithms == NULL) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    /* we assume that the digests array is just not there yet */
    PORT_Assert(sigd->digests == NULL);
    if (sigd->digests != NULL) {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }

    /* now allocate one (same size as digestAlgorithms) */
    cnt = NSS_CMSArray_Count((void **)sigd->digestAlgorithms);
    sigd->digests = PORT_ArenaZAlloc(sigd->cmsg->poolp, (cnt + 1) * sizeof(SECItem *));
    if (sigd->digests == NULL) {
        PORT_SetError(SEC_ERROR_NO_MEMORY);
        return SECFailure;
    }

    for (i = 0; sigd->digestAlgorithms[i] != NULL; i++) {
        /* try to find the sigd's i'th digest algorithm in the array we passed in */
        idx = NSS_CMSAlgArray_GetIndexByAlgID(digestalgs, sigd->digestAlgorithms[i]);
        if (idx < 0) {
            PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND);
            return SECFailure;
        }
        if (!digests[idx]) {
            /* We have no digest for this algorithm, probably because it is
            ** unrecognized or unsupported.  We'll ignore this here.  If this
            ** digest is needed later, an error will be be generated then.
            */

            continue;
        }

        /* found it - now set it */
        if ((sigd->digests[i] = SECITEM_AllocItem(sigd->cmsg->poolp, NULL, 0)) == NULL ||
            SECITEM_CopyItem(sigd->cmsg->poolp, sigd->digests[i], digests[idx]) != SECSuccess) {
            PORT_SetError(SEC_ERROR_NO_MEMORY);
            return SECFailure;
        }
    }
    return SECSuccess;
}

SECStatus
NSS_CMSSignedData_SetDigestValue(NSSCMSSignedData *sigd,
                                 SECOidTag digestalgtag,
                                 SECItem *digestdata)
{
    SECItem *digest = NULL;
    PLArenaPool *poolp;
    void *mark;
    int n, cnt;

    if (!sigd) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    poolp = sigd->cmsg->poolp;

    mark = PORT_ArenaMark(poolp);

    if (digestdata) {
        digest = (SECItem *)PORT_ArenaZAlloc(poolp, sizeof(SECItem));

        /* copy digestdata item to arena (in case we have it and are not only making room) */
        if (SECITEM_CopyItem(poolp, digest, digestdata) != SECSuccess)
            goto loser;
    }

    /* now allocate one (same size as digestAlgorithms) */
    if (sigd->digests == NULL) {
        cnt = NSS_CMSArray_Count((void **)sigd->digestAlgorithms);
        sigd->digests = PORT_ArenaZAlloc(sigd->cmsg->poolp, (cnt + 1) * sizeof(SECItem *));
        if (sigd->digests == NULL) {
            PORT_SetError(SEC_ERROR_NO_MEMORY);
            return SECFailure;
        }
    }

    n = -1;
    if (sigd->digestAlgorithms != NULL)
        n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);

    /* if not found, add a digest */
    if (n < 0) {
        if (NSS_CMSSignedData_AddDigest(poolp, sigd, digestalgtag, digest) != SECSuccess)
            goto loser;
    } else {
        /* replace NULL pointer with digest item (and leak previous value) */
        sigd->digests[n] = digest;
    }

    PORT_ArenaUnmark(poolp, mark);
    return SECSuccess;

loser:
    PORT_ArenaRelease(poolp, mark);
    return SECFailure;
}

SECStatus
NSS_CMSSignedData_AddDigest(PLArenaPool *poolp,
                            NSSCMSSignedData *sigd,
                            SECOidTag digestalgtag,
                            SECItem *digest)
{
    SECAlgorithmID *digestalg;
    void *mark;

    if (!sigd || !poolp) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    mark = PORT_ArenaMark(poolp);

    digestalg = PORT_ArenaZAlloc(poolp, sizeof(SECAlgorithmID));
    if (digestalg == NULL)
        goto loser;

    if (SECOID_SetAlgorithmID(poolp, digestalg, digestalgtag, NULL) != SECSuccess) /* no params */
        goto loser;

    if (NSS_CMSArray_Add(poolp, (void ***)&(sigd->digestAlgorithms),
                         (void *)digestalg) != SECSuccess ||
        /* even if digest is NULL, add dummy to have same-size array */
        NSS_CMSArray_Add(poolp, (void ***)&(sigd->digests),
                         (void *)digest) != SECSuccess) {
        goto loser;
    }

    PORT_ArenaUnmark(poolp, mark);
    return SECSuccess;

loser:
    PORT_ArenaRelease(poolp, mark);
    return SECFailure;
}

/* XXX This function doesn't set the error code on failure. */
SECItem *
NSS_CMSSignedData_GetDigestValue(NSSCMSSignedData *sigd, SECOidTag digestalgtag)
{
    int n;

    if (!sigd) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return NULL;
    }

    if (sigd->digestAlgorithms == NULL || sigd->digests == NULL) {
        PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND);
        return NULL;
    }

    n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);

    return (n < 0) ? NULL : sigd->digests[n];
}

/* =============================================================================
 * Misc. utility functions
 */


/*
 * NSS_CMSSignedData_CreateCertsOnly - create a certs-only SignedData.
 *
 * cert          - base certificates that will be included
 * include_chain - if true, include the complete cert chain for cert
 *
 * More certs and chains can be added via AddCertificate and AddCertChain.
 *
 * An error results in a return value of NULL and an error set.
 *
 * XXXX CRLs
 */

NSSCMSSignedData *
NSS_CMSSignedData_CreateCertsOnly(NSSCMSMessage *cmsg, CERTCertificate *cert, PRBool include_chain)
{
    NSSCMSSignedData *sigd;
    void *mark;
    PLArenaPool *poolp;
    SECStatus rv;

    if (!cmsg || !cert) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return NULL;
    }

    poolp = cmsg->poolp;
    mark = PORT_ArenaMark(poolp);

    sigd = NSS_CMSSignedData_Create(cmsg);
    if (sigd == NULL)
        goto loser;

    /* no signerinfos, thus no digestAlgorithms */

    /* but certs */
    if (include_chain) {
        rv = NSS_CMSSignedData_AddCertChain(sigd, cert);
    } else {
        rv = NSS_CMSSignedData_AddCertificate(sigd, cert);
    }
    if (rv != SECSuccess)
        goto loser;

    /* RFC2630 5.2 sez:
     * In the degenerate case where there are no signers, the
     * EncapsulatedContentInfo value being "signed" is irrelevant.  In this
     * case, the content type within the EncapsulatedContentInfo value being
     * "signed" should be id-data (as defined in section 4), and the content
     * field of the EncapsulatedContentInfo value should be omitted.
     */

    rv = NSS_CMSContentInfo_SetContent_Data(cmsg, &(sigd->contentInfo), NULL, PR_TRUE);
    if (rv != SECSuccess)
        goto loser;

    PORT_ArenaUnmark(poolp, mark);
    return sigd;

loser:
    if (sigd)
        NSS_CMSSignedData_Destroy(sigd);
    PORT_ArenaRelease(poolp, mark);
    return NULL;
}

/* TODO:
 * NSS_CMSSignerInfo_GetReceiptRequest()
 * NSS_CMSSignedData_HasReceiptRequest()
 * easy way to iterate over signers
 */


Messung V0.5
C=92 H=94 G=92

¤ Dauer der Verarbeitung: 0.10 Sekunden  ¤

*© 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge