123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- /* 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 digesting.
- */
- #include "cmslocal.h"
- #include "cert.h"
- #include "keyhi.h"
- #include "secitem.h"
- #include "secoid.h"
- #include "pk11func.h"
- #include "prtime.h"
- #include "secerr.h"
- /* #define CMS_FIND_LEAK_MULTIPLE 1 */
- #ifdef CMS_FIND_LEAK_MULTIPLE
- static int stop_on_err = 1;
- static int global_num_digests = 0;
- #endif
- struct digestPairStr {
- const SECHashObject *digobj;
- void *digcx;
- };
- typedef struct digestPairStr digestPair;
- struct NSSCMSDigestContextStr {
- PRBool saw_contents;
- PLArenaPool *pool;
- int digcnt;
- digestPair *digPairs;
- };
- /*
- * NSS_CMSDigestContext_StartMultiple - start digest calculation using all the
- * digest algorithms in "digestalgs" in parallel.
- */
- NSSCMSDigestContext *
- NSS_CMSDigestContext_StartMultiple(SECAlgorithmID **digestalgs)
- {
- PLArenaPool *pool;
- NSSCMSDigestContext *cmsdigcx;
- int digcnt;
- int i;
- #ifdef CMS_FIND_LEAK_MULTIPLE
- PORT_Assert(global_num_digests == 0 || !stop_on_err);
- #endif
- digcnt = (digestalgs == NULL) ? 0 : NSS_CMSArray_Count((void **)digestalgs);
- /* It's OK if digcnt is zero. We have to allow this for "certs only"
- ** messages.
- */
- pool = PORT_NewArena(2048);
- if (!pool)
- return NULL;
- cmsdigcx = PORT_ArenaNew(pool, NSSCMSDigestContext);
- if (cmsdigcx == NULL)
- goto loser;
- cmsdigcx->saw_contents = PR_FALSE;
- cmsdigcx->pool = pool;
- cmsdigcx->digcnt = digcnt;
- cmsdigcx->digPairs = PORT_ArenaZNewArray(pool, digestPair, digcnt);
- if (cmsdigcx->digPairs == NULL) {
- goto loser;
- }
- /*
- * Create a digest object context for each algorithm.
- */
- for (i = 0; i < digcnt; i++) {
- const SECHashObject *digobj;
- void *digcx;
- digobj = NSS_CMSUtil_GetHashObjByAlgID(digestalgs[i]);
- /*
- * Skip any algorithm we do not even recognize; obviously,
- * this could be a problem, but if it is critical then the
- * result will just be that the signature does not verify.
- * We do not necessarily want to error out here, because
- * the particular algorithm may not actually be important,
- * but we cannot know that until later.
- */
- if (digobj == NULL)
- continue;
- digcx = (*digobj->create)();
- if (digcx != NULL) {
- (*digobj->begin)(digcx);
- cmsdigcx->digPairs[i].digobj = digobj;
- cmsdigcx->digPairs[i].digcx = digcx;
- #ifdef CMS_FIND_LEAK_MULTIPLE
- global_num_digests++;
- #endif
- }
- }
- return cmsdigcx;
- loser:
- /* no digest objects have been created, or need to be destroyed. */
- if (pool) {
- PORT_FreeArena(pool, PR_FALSE);
- }
- return NULL;
- }
- /*
- * NSS_CMSDigestContext_StartSingle - same as
- * NSS_CMSDigestContext_StartMultiple, but only one algorithm.
- */
- NSSCMSDigestContext *
- NSS_CMSDigestContext_StartSingle(SECAlgorithmID *digestalg)
- {
- SECAlgorithmID *digestalgs[] = { NULL, NULL }; /* fake array */
- digestalgs[0] = digestalg;
- return NSS_CMSDigestContext_StartMultiple(digestalgs);
- }
- /*
- * NSS_CMSDigestContext_Update - feed more data into the digest machine
- */
- void
- NSS_CMSDigestContext_Update(NSSCMSDigestContext *cmsdigcx,
- const unsigned char *data, int len)
- {
- int i;
- digestPair *pair = cmsdigcx->digPairs;
- cmsdigcx->saw_contents = PR_TRUE;
- for (i = 0; i < cmsdigcx->digcnt; i++, pair++) {
- if (pair->digcx) {
- (*pair->digobj->update)(pair->digcx, data, len);
- }
- }
- }
- /*
- * NSS_CMSDigestContext_Cancel - cancel digesting operation
- */
- void
- NSS_CMSDigestContext_Cancel(NSSCMSDigestContext *cmsdigcx)
- {
- int i;
- digestPair *pair = cmsdigcx->digPairs;
- for (i = 0; i < cmsdigcx->digcnt; i++, pair++) {
- if (pair->digcx) {
- (*pair->digobj->destroy)(pair->digcx, PR_TRUE);
- #ifdef CMS_FIND_LEAK_MULTIPLE
- --global_num_digests;
- #endif
- }
- }
- #ifdef CMS_FIND_LEAK_MULTIPLE
- PORT_Assert(global_num_digests == 0 || !stop_on_err);
- #endif
- PORT_FreeArena(cmsdigcx->pool, PR_FALSE);
- }
- /*
- * NSS_CMSDigestContext_FinishMultiple - finish the digests and put them
- * into an array of SECItems (allocated on poolp)
- */
- SECStatus
- NSS_CMSDigestContext_FinishMultiple(NSSCMSDigestContext *cmsdigcx,
- PLArenaPool *poolp,
- SECItem ***digestsp)
- {
- SECItem **digests = NULL;
- digestPair *pair;
- void *mark;
- int i;
- SECStatus rv;
- /* no contents? do not finish digests */
- if (digestsp == NULL || !cmsdigcx->saw_contents) {
- rv = SECSuccess;
- goto cleanup;
- }
- mark = PORT_ArenaMark(poolp);
- /* allocate digest array & SECItems on arena */
- digests = PORT_ArenaNewArray(poolp, SECItem *, cmsdigcx->digcnt + 1);
- rv = ((digests == NULL) ? SECFailure : SECSuccess);
- pair = cmsdigcx->digPairs;
- for (i = 0; rv == SECSuccess && i < cmsdigcx->digcnt; i++, pair++) {
- SECItem digest;
- unsigned char hash[HASH_LENGTH_MAX];
- if (!pair->digcx) {
- digests[i] = NULL;
- continue;
- }
- digest.type = siBuffer;
- digest.data = hash;
- digest.len = pair->digobj->length;
- (*pair->digobj->end)(pair->digcx, hash, &digest.len, digest.len);
- digests[i] = SECITEM_ArenaDupItem(poolp, &digest);
- if (!digests[i]) {
- rv = SECFailure;
- }
- }
- digests[i] = NULL;
- if (rv == SECSuccess) {
- PORT_ArenaUnmark(poolp, mark);
- } else
- PORT_ArenaRelease(poolp, mark);
- cleanup:
- NSS_CMSDigestContext_Cancel(cmsdigcx);
- /* Don't change the caller's digests pointer if we have no digests.
- ** NSS_CMSSignedData_Encode_AfterData depends on this behavior.
- */
- if (rv == SECSuccess && digestsp && digests) {
- *digestsp = digests;
- }
- return rv;
- }
- /*
- * NSS_CMSDigestContext_FinishSingle - same as
- * NSS_CMSDigestContext_FinishMultiple, but for one digest.
- */
- SECStatus
- NSS_CMSDigestContext_FinishSingle(NSSCMSDigestContext *cmsdigcx,
- PLArenaPool *poolp,
- SECItem *digest)
- {
- SECStatus rv = SECFailure;
- SECItem **dp;
- PLArenaPool *arena = NULL;
- if ((arena = PORT_NewArena(1024)) == NULL)
- goto loser;
- /* get the digests into arena, then copy the first digest into poolp */
- rv = NSS_CMSDigestContext_FinishMultiple(cmsdigcx, arena, &dp);
- if (rv == SECSuccess) {
- /* now copy it into poolp */
- rv = SECITEM_CopyItem(poolp, digest, dp[0]);
- }
- loser:
- if (arena)
- PORT_FreeArena(arena, PR_FALSE);
- return rv;
- }
|