security/nss/lib/smime/cmsdigest.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/smime/cmsdigest.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,260 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +/*
     1.9 + * CMS digesting.
    1.10 + */
    1.11 +
    1.12 +#include "cmslocal.h"
    1.13 +
    1.14 +#include "cert.h"
    1.15 +#include "key.h"
    1.16 +#include "secitem.h"
    1.17 +#include "secoid.h"
    1.18 +#include "pk11func.h"
    1.19 +#include "prtime.h"
    1.20 +#include "secerr.h"
    1.21 +
    1.22 +/*  #define CMS_FIND_LEAK_MULTIPLE 1 */
    1.23 +#ifdef CMS_FIND_LEAK_MULTIPLE
    1.24 +static int stop_on_err = 1;
    1.25 +static int global_num_digests = 0;
    1.26 +#endif
    1.27 +
    1.28 +struct digestPairStr { 
    1.29 +    const SECHashObject * digobj;
    1.30 +    void *                digcx;
    1.31 +};
    1.32 +typedef struct digestPairStr digestPair;
    1.33 +
    1.34 +struct NSSCMSDigestContextStr {
    1.35 +    PRBool		saw_contents;
    1.36 +    PLArenaPool *       pool;
    1.37 +    int			digcnt;
    1.38 +    digestPair  *       digPairs;
    1.39 +};
    1.40 +
    1.41 +
    1.42 +/*
    1.43 + * NSS_CMSDigestContext_StartMultiple - start digest calculation using all the
    1.44 + *  digest algorithms in "digestalgs" in parallel.
    1.45 + */
    1.46 +NSSCMSDigestContext *
    1.47 +NSS_CMSDigestContext_StartMultiple(SECAlgorithmID **digestalgs)
    1.48 +{
    1.49 +    PLArenaPool *        pool;
    1.50 +    NSSCMSDigestContext *cmsdigcx;
    1.51 +    int digcnt;
    1.52 +    int i;
    1.53 +
    1.54 +#ifdef CMS_FIND_LEAK_MULTIPLE
    1.55 +    PORT_Assert(global_num_digests == 0 || !stop_on_err);
    1.56 +#endif
    1.57 +
    1.58 +    digcnt = (digestalgs == NULL) ? 0 : NSS_CMSArray_Count((void **)digestalgs);
    1.59 +    /* It's OK if digcnt is zero.  We have to allow this for "certs only"
    1.60 +    ** messages.
    1.61 +    */
    1.62 +    pool = PORT_NewArena(2048);
    1.63 +    if (!pool)
    1.64 +    	return NULL;
    1.65 +
    1.66 +    cmsdigcx = PORT_ArenaNew(pool, NSSCMSDigestContext);
    1.67 +    if (cmsdigcx == NULL)
    1.68 +	goto loser;
    1.69 +
    1.70 +    cmsdigcx->saw_contents = PR_FALSE;
    1.71 +    cmsdigcx->pool   = pool;
    1.72 +    cmsdigcx->digcnt = digcnt;
    1.73 +
    1.74 +    cmsdigcx->digPairs = PORT_ArenaZNewArray(pool, digestPair, digcnt);
    1.75 +    if (cmsdigcx->digPairs == NULL) {
    1.76 +	goto loser;
    1.77 +    }
    1.78 +
    1.79 +    /*
    1.80 +     * Create a digest object context for each algorithm.
    1.81 +     */
    1.82 +    for (i = 0; i < digcnt; i++) {
    1.83 +	const SECHashObject *digobj;
    1.84 +	void *digcx;
    1.85 +
    1.86 +	digobj = NSS_CMSUtil_GetHashObjByAlgID(digestalgs[i]);
    1.87 +	/*
    1.88 +	 * Skip any algorithm we do not even recognize; obviously,
    1.89 +	 * this could be a problem, but if it is critical then the
    1.90 +	 * result will just be that the signature does not verify.
    1.91 +	 * We do not necessarily want to error out here, because
    1.92 +	 * the particular algorithm may not actually be important,
    1.93 +	 * but we cannot know that until later.
    1.94 +	 */
    1.95 +	if (digobj == NULL)
    1.96 +	    continue;
    1.97 +
    1.98 +	digcx = (*digobj->create)();
    1.99 +	if (digcx != NULL) {
   1.100 +	    (*digobj->begin) (digcx);
   1.101 +	    cmsdigcx->digPairs[i].digobj = digobj;
   1.102 +	    cmsdigcx->digPairs[i].digcx  = digcx;
   1.103 +#ifdef CMS_FIND_LEAK_MULTIPLE
   1.104 +	    global_num_digests++;
   1.105 +#endif
   1.106 +	}
   1.107 +    }
   1.108 +    return cmsdigcx;
   1.109 +
   1.110 +loser:
   1.111 +    /* no digest objects have been created, or need to be destroyed. */
   1.112 +    if (pool) {
   1.113 +    	PORT_FreeArena(pool, PR_FALSE);
   1.114 +    }
   1.115 +    return NULL;
   1.116 +}
   1.117 +
   1.118 +/*
   1.119 + * NSS_CMSDigestContext_StartSingle - same as 
   1.120 + * NSS_CMSDigestContext_StartMultiple, but only one algorithm.
   1.121 + */
   1.122 +NSSCMSDigestContext *
   1.123 +NSS_CMSDigestContext_StartSingle(SECAlgorithmID *digestalg)
   1.124 +{
   1.125 +    SECAlgorithmID *digestalgs[] = { NULL, NULL };		/* fake array */
   1.126 +
   1.127 +    digestalgs[0] = digestalg;
   1.128 +    return NSS_CMSDigestContext_StartMultiple(digestalgs);
   1.129 +}
   1.130 +
   1.131 +/*
   1.132 + * NSS_CMSDigestContext_Update - feed more data into the digest machine
   1.133 + */
   1.134 +void
   1.135 +NSS_CMSDigestContext_Update(NSSCMSDigestContext *cmsdigcx, 
   1.136 +                            const unsigned char *data, int len)
   1.137 +{
   1.138 +    int i;
   1.139 +    digestPair *pair = cmsdigcx->digPairs;
   1.140 +
   1.141 +    cmsdigcx->saw_contents = PR_TRUE;
   1.142 +
   1.143 +    for (i = 0; i < cmsdigcx->digcnt; i++, pair++) {
   1.144 +	if (pair->digcx) {
   1.145 +	    (*pair->digobj->update)(pair->digcx, data, len);
   1.146 +    	}
   1.147 +    }
   1.148 +}
   1.149 +
   1.150 +/*
   1.151 + * NSS_CMSDigestContext_Cancel - cancel digesting operation
   1.152 + */
   1.153 +void
   1.154 +NSS_CMSDigestContext_Cancel(NSSCMSDigestContext *cmsdigcx)
   1.155 +{
   1.156 +    int i;
   1.157 +    digestPair *pair = cmsdigcx->digPairs;
   1.158 +
   1.159 +    for (i = 0; i < cmsdigcx->digcnt; i++, pair++) {
   1.160 +	if (pair->digcx) {
   1.161 +	    (*pair->digobj->destroy)(pair->digcx, PR_TRUE);
   1.162 +#ifdef CMS_FIND_LEAK_MULTIPLE
   1.163 +	    --global_num_digests;
   1.164 +#endif
   1.165 +    	}
   1.166 +    }
   1.167 +#ifdef CMS_FIND_LEAK_MULTIPLE
   1.168 +    PORT_Assert(global_num_digests == 0 || !stop_on_err);
   1.169 +#endif
   1.170 +    PORT_FreeArena(cmsdigcx->pool, PR_FALSE);
   1.171 +}
   1.172 +
   1.173 +/*
   1.174 + * NSS_CMSDigestContext_FinishMultiple - finish the digests and put them
   1.175 + *  into an array of SECItems (allocated on poolp)
   1.176 + */
   1.177 +SECStatus
   1.178 +NSS_CMSDigestContext_FinishMultiple(NSSCMSDigestContext *cmsdigcx, 
   1.179 +                                    PLArenaPool *poolp,
   1.180 +			            SECItem ***digestsp)
   1.181 +{
   1.182 +    SECItem **  digests = NULL;
   1.183 +    digestPair *pair;
   1.184 +    void *      mark;
   1.185 +    int         i;
   1.186 +    SECStatus   rv;
   1.187 +
   1.188 +    /* no contents? do not finish digests */
   1.189 +    if (digestsp == NULL || !cmsdigcx->saw_contents) {
   1.190 +	rv = SECSuccess;
   1.191 +	goto cleanup;
   1.192 +    }
   1.193 +
   1.194 +    mark = PORT_ArenaMark (poolp);
   1.195 +
   1.196 +    /* allocate digest array & SECItems on arena */
   1.197 +    digests = PORT_ArenaNewArray( poolp, SECItem *, cmsdigcx->digcnt + 1);
   1.198 +
   1.199 +    rv = ((digests == NULL) ? SECFailure : SECSuccess);
   1.200 +    pair = cmsdigcx->digPairs;
   1.201 +    for (i = 0; rv == SECSuccess && i < cmsdigcx->digcnt; i++, pair++) {
   1.202 +	SECItem digest;
   1.203 +	unsigned char hash[HASH_LENGTH_MAX];
   1.204 +
   1.205 +	if (!pair->digcx) {
   1.206 +	    digests[i] = NULL;
   1.207 +	    continue;
   1.208 +	}
   1.209 +
   1.210 +	digest.type = siBuffer;
   1.211 +	digest.data = hash;
   1.212 +	digest.len  = pair->digobj->length;
   1.213 +	(* pair->digobj->end)(pair->digcx, hash, &digest.len, digest.len);
   1.214 +	digests[i] = SECITEM_ArenaDupItem(poolp, &digest);
   1.215 +	if (!digests[i]) {
   1.216 +	    rv = SECFailure;
   1.217 +	}
   1.218 +    }
   1.219 +    digests[i] = NULL;
   1.220 +    if (rv == SECSuccess) {
   1.221 +	PORT_ArenaUnmark(poolp, mark);
   1.222 +    } else
   1.223 +	PORT_ArenaRelease(poolp, mark);
   1.224 +
   1.225 +cleanup:
   1.226 +    NSS_CMSDigestContext_Cancel(cmsdigcx);
   1.227 +    /* Don't change the caller's digests pointer if we have no digests.
   1.228 +    **  NSS_CMSSignedData_Encode_AfterData depends on this behavior.
   1.229 +    */
   1.230 +    if (rv == SECSuccess && digestsp && digests) {
   1.231 +	*digestsp = digests;
   1.232 +    }
   1.233 +    return rv;
   1.234 +}
   1.235 +
   1.236 +/*
   1.237 + * NSS_CMSDigestContext_FinishSingle - same as 
   1.238 + * NSS_CMSDigestContext_FinishMultiple, but for one digest.
   1.239 + */
   1.240 +SECStatus
   1.241 +NSS_CMSDigestContext_FinishSingle(NSSCMSDigestContext *cmsdigcx, 
   1.242 +                                  PLArenaPool *poolp,
   1.243 +			          SECItem *digest)
   1.244 +{
   1.245 +    SECStatus rv = SECFailure;
   1.246 +    SECItem **dp;
   1.247 +    PLArenaPool *arena = NULL;
   1.248 +
   1.249 +    if ((arena = PORT_NewArena(1024)) == NULL)
   1.250 +	goto loser;
   1.251 +
   1.252 +    /* get the digests into arena, then copy the first digest into poolp */
   1.253 +    rv = NSS_CMSDigestContext_FinishMultiple(cmsdigcx, arena, &dp);
   1.254 +    if (rv == SECSuccess) {
   1.255 +	/* now copy it into poolp */
   1.256 +	rv = SECITEM_CopyItem(poolp, digest, dp[0]);
   1.257 +    }
   1.258 +loser:
   1.259 +    if (arena)
   1.260 +	PORT_FreeArena(arena, PR_FALSE);
   1.261 +
   1.262 +    return rv;
   1.263 +}

mercurial