security/nss/lib/smime/cmsdigest.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * CMS digesting.
michael@0 7 */
michael@0 8
michael@0 9 #include "cmslocal.h"
michael@0 10
michael@0 11 #include "cert.h"
michael@0 12 #include "key.h"
michael@0 13 #include "secitem.h"
michael@0 14 #include "secoid.h"
michael@0 15 #include "pk11func.h"
michael@0 16 #include "prtime.h"
michael@0 17 #include "secerr.h"
michael@0 18
michael@0 19 /* #define CMS_FIND_LEAK_MULTIPLE 1 */
michael@0 20 #ifdef CMS_FIND_LEAK_MULTIPLE
michael@0 21 static int stop_on_err = 1;
michael@0 22 static int global_num_digests = 0;
michael@0 23 #endif
michael@0 24
michael@0 25 struct digestPairStr {
michael@0 26 const SECHashObject * digobj;
michael@0 27 void * digcx;
michael@0 28 };
michael@0 29 typedef struct digestPairStr digestPair;
michael@0 30
michael@0 31 struct NSSCMSDigestContextStr {
michael@0 32 PRBool saw_contents;
michael@0 33 PLArenaPool * pool;
michael@0 34 int digcnt;
michael@0 35 digestPair * digPairs;
michael@0 36 };
michael@0 37
michael@0 38
michael@0 39 /*
michael@0 40 * NSS_CMSDigestContext_StartMultiple - start digest calculation using all the
michael@0 41 * digest algorithms in "digestalgs" in parallel.
michael@0 42 */
michael@0 43 NSSCMSDigestContext *
michael@0 44 NSS_CMSDigestContext_StartMultiple(SECAlgorithmID **digestalgs)
michael@0 45 {
michael@0 46 PLArenaPool * pool;
michael@0 47 NSSCMSDigestContext *cmsdigcx;
michael@0 48 int digcnt;
michael@0 49 int i;
michael@0 50
michael@0 51 #ifdef CMS_FIND_LEAK_MULTIPLE
michael@0 52 PORT_Assert(global_num_digests == 0 || !stop_on_err);
michael@0 53 #endif
michael@0 54
michael@0 55 digcnt = (digestalgs == NULL) ? 0 : NSS_CMSArray_Count((void **)digestalgs);
michael@0 56 /* It's OK if digcnt is zero. We have to allow this for "certs only"
michael@0 57 ** messages.
michael@0 58 */
michael@0 59 pool = PORT_NewArena(2048);
michael@0 60 if (!pool)
michael@0 61 return NULL;
michael@0 62
michael@0 63 cmsdigcx = PORT_ArenaNew(pool, NSSCMSDigestContext);
michael@0 64 if (cmsdigcx == NULL)
michael@0 65 goto loser;
michael@0 66
michael@0 67 cmsdigcx->saw_contents = PR_FALSE;
michael@0 68 cmsdigcx->pool = pool;
michael@0 69 cmsdigcx->digcnt = digcnt;
michael@0 70
michael@0 71 cmsdigcx->digPairs = PORT_ArenaZNewArray(pool, digestPair, digcnt);
michael@0 72 if (cmsdigcx->digPairs == NULL) {
michael@0 73 goto loser;
michael@0 74 }
michael@0 75
michael@0 76 /*
michael@0 77 * Create a digest object context for each algorithm.
michael@0 78 */
michael@0 79 for (i = 0; i < digcnt; i++) {
michael@0 80 const SECHashObject *digobj;
michael@0 81 void *digcx;
michael@0 82
michael@0 83 digobj = NSS_CMSUtil_GetHashObjByAlgID(digestalgs[i]);
michael@0 84 /*
michael@0 85 * Skip any algorithm we do not even recognize; obviously,
michael@0 86 * this could be a problem, but if it is critical then the
michael@0 87 * result will just be that the signature does not verify.
michael@0 88 * We do not necessarily want to error out here, because
michael@0 89 * the particular algorithm may not actually be important,
michael@0 90 * but we cannot know that until later.
michael@0 91 */
michael@0 92 if (digobj == NULL)
michael@0 93 continue;
michael@0 94
michael@0 95 digcx = (*digobj->create)();
michael@0 96 if (digcx != NULL) {
michael@0 97 (*digobj->begin) (digcx);
michael@0 98 cmsdigcx->digPairs[i].digobj = digobj;
michael@0 99 cmsdigcx->digPairs[i].digcx = digcx;
michael@0 100 #ifdef CMS_FIND_LEAK_MULTIPLE
michael@0 101 global_num_digests++;
michael@0 102 #endif
michael@0 103 }
michael@0 104 }
michael@0 105 return cmsdigcx;
michael@0 106
michael@0 107 loser:
michael@0 108 /* no digest objects have been created, or need to be destroyed. */
michael@0 109 if (pool) {
michael@0 110 PORT_FreeArena(pool, PR_FALSE);
michael@0 111 }
michael@0 112 return NULL;
michael@0 113 }
michael@0 114
michael@0 115 /*
michael@0 116 * NSS_CMSDigestContext_StartSingle - same as
michael@0 117 * NSS_CMSDigestContext_StartMultiple, but only one algorithm.
michael@0 118 */
michael@0 119 NSSCMSDigestContext *
michael@0 120 NSS_CMSDigestContext_StartSingle(SECAlgorithmID *digestalg)
michael@0 121 {
michael@0 122 SECAlgorithmID *digestalgs[] = { NULL, NULL }; /* fake array */
michael@0 123
michael@0 124 digestalgs[0] = digestalg;
michael@0 125 return NSS_CMSDigestContext_StartMultiple(digestalgs);
michael@0 126 }
michael@0 127
michael@0 128 /*
michael@0 129 * NSS_CMSDigestContext_Update - feed more data into the digest machine
michael@0 130 */
michael@0 131 void
michael@0 132 NSS_CMSDigestContext_Update(NSSCMSDigestContext *cmsdigcx,
michael@0 133 const unsigned char *data, int len)
michael@0 134 {
michael@0 135 int i;
michael@0 136 digestPair *pair = cmsdigcx->digPairs;
michael@0 137
michael@0 138 cmsdigcx->saw_contents = PR_TRUE;
michael@0 139
michael@0 140 for (i = 0; i < cmsdigcx->digcnt; i++, pair++) {
michael@0 141 if (pair->digcx) {
michael@0 142 (*pair->digobj->update)(pair->digcx, data, len);
michael@0 143 }
michael@0 144 }
michael@0 145 }
michael@0 146
michael@0 147 /*
michael@0 148 * NSS_CMSDigestContext_Cancel - cancel digesting operation
michael@0 149 */
michael@0 150 void
michael@0 151 NSS_CMSDigestContext_Cancel(NSSCMSDigestContext *cmsdigcx)
michael@0 152 {
michael@0 153 int i;
michael@0 154 digestPair *pair = cmsdigcx->digPairs;
michael@0 155
michael@0 156 for (i = 0; i < cmsdigcx->digcnt; i++, pair++) {
michael@0 157 if (pair->digcx) {
michael@0 158 (*pair->digobj->destroy)(pair->digcx, PR_TRUE);
michael@0 159 #ifdef CMS_FIND_LEAK_MULTIPLE
michael@0 160 --global_num_digests;
michael@0 161 #endif
michael@0 162 }
michael@0 163 }
michael@0 164 #ifdef CMS_FIND_LEAK_MULTIPLE
michael@0 165 PORT_Assert(global_num_digests == 0 || !stop_on_err);
michael@0 166 #endif
michael@0 167 PORT_FreeArena(cmsdigcx->pool, PR_FALSE);
michael@0 168 }
michael@0 169
michael@0 170 /*
michael@0 171 * NSS_CMSDigestContext_FinishMultiple - finish the digests and put them
michael@0 172 * into an array of SECItems (allocated on poolp)
michael@0 173 */
michael@0 174 SECStatus
michael@0 175 NSS_CMSDigestContext_FinishMultiple(NSSCMSDigestContext *cmsdigcx,
michael@0 176 PLArenaPool *poolp,
michael@0 177 SECItem ***digestsp)
michael@0 178 {
michael@0 179 SECItem ** digests = NULL;
michael@0 180 digestPair *pair;
michael@0 181 void * mark;
michael@0 182 int i;
michael@0 183 SECStatus rv;
michael@0 184
michael@0 185 /* no contents? do not finish digests */
michael@0 186 if (digestsp == NULL || !cmsdigcx->saw_contents) {
michael@0 187 rv = SECSuccess;
michael@0 188 goto cleanup;
michael@0 189 }
michael@0 190
michael@0 191 mark = PORT_ArenaMark (poolp);
michael@0 192
michael@0 193 /* allocate digest array & SECItems on arena */
michael@0 194 digests = PORT_ArenaNewArray( poolp, SECItem *, cmsdigcx->digcnt + 1);
michael@0 195
michael@0 196 rv = ((digests == NULL) ? SECFailure : SECSuccess);
michael@0 197 pair = cmsdigcx->digPairs;
michael@0 198 for (i = 0; rv == SECSuccess && i < cmsdigcx->digcnt; i++, pair++) {
michael@0 199 SECItem digest;
michael@0 200 unsigned char hash[HASH_LENGTH_MAX];
michael@0 201
michael@0 202 if (!pair->digcx) {
michael@0 203 digests[i] = NULL;
michael@0 204 continue;
michael@0 205 }
michael@0 206
michael@0 207 digest.type = siBuffer;
michael@0 208 digest.data = hash;
michael@0 209 digest.len = pair->digobj->length;
michael@0 210 (* pair->digobj->end)(pair->digcx, hash, &digest.len, digest.len);
michael@0 211 digests[i] = SECITEM_ArenaDupItem(poolp, &digest);
michael@0 212 if (!digests[i]) {
michael@0 213 rv = SECFailure;
michael@0 214 }
michael@0 215 }
michael@0 216 digests[i] = NULL;
michael@0 217 if (rv == SECSuccess) {
michael@0 218 PORT_ArenaUnmark(poolp, mark);
michael@0 219 } else
michael@0 220 PORT_ArenaRelease(poolp, mark);
michael@0 221
michael@0 222 cleanup:
michael@0 223 NSS_CMSDigestContext_Cancel(cmsdigcx);
michael@0 224 /* Don't change the caller's digests pointer if we have no digests.
michael@0 225 ** NSS_CMSSignedData_Encode_AfterData depends on this behavior.
michael@0 226 */
michael@0 227 if (rv == SECSuccess && digestsp && digests) {
michael@0 228 *digestsp = digests;
michael@0 229 }
michael@0 230 return rv;
michael@0 231 }
michael@0 232
michael@0 233 /*
michael@0 234 * NSS_CMSDigestContext_FinishSingle - same as
michael@0 235 * NSS_CMSDigestContext_FinishMultiple, but for one digest.
michael@0 236 */
michael@0 237 SECStatus
michael@0 238 NSS_CMSDigestContext_FinishSingle(NSSCMSDigestContext *cmsdigcx,
michael@0 239 PLArenaPool *poolp,
michael@0 240 SECItem *digest)
michael@0 241 {
michael@0 242 SECStatus rv = SECFailure;
michael@0 243 SECItem **dp;
michael@0 244 PLArenaPool *arena = NULL;
michael@0 245
michael@0 246 if ((arena = PORT_NewArena(1024)) == NULL)
michael@0 247 goto loser;
michael@0 248
michael@0 249 /* get the digests into arena, then copy the first digest into poolp */
michael@0 250 rv = NSS_CMSDigestContext_FinishMultiple(cmsdigcx, arena, &dp);
michael@0 251 if (rv == SECSuccess) {
michael@0 252 /* now copy it into poolp */
michael@0 253 rv = SECITEM_CopyItem(poolp, digest, dp[0]);
michael@0 254 }
michael@0 255 loser:
michael@0 256 if (arena)
michael@0 257 PORT_FreeArena(arena, PR_FALSE);
michael@0 258
michael@0 259 return rv;
michael@0 260 }

mercurial