]> git.saurik.com Git - apple/security.git/blame - libsecurity_smime/lib/cmsdigest.c
Security-57337.60.2.tar.gz
[apple/security.git] / libsecurity_smime / lib / cmsdigest.c
CommitLineData
b1ab9ed8
A
1/*
2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
6 *
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
11 *
12 * The Original Code is the Netscape security libraries.
13 *
14 * The Initial Developer of the Original Code is Netscape
15 * Communications Corporation. Portions created by Netscape are
16 * Copyright (C) 1994-2000 Netscape Communications Corporation. All
17 * Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * Alternatively, the contents of this file may be used under the
22 * terms of the GNU General Public License Version 2 or later (the
23 * "GPL"), in which case the provisions of the GPL are applicable
24 * instead of those above. If you wish to allow use of your
25 * version of this file only under the terms of the GPL and not to
26 * allow others to use your version of this file under the MPL,
27 * indicate your decision by deleting the provisions above and
28 * replace them with the notice and other provisions required by
29 * the GPL. If you do not delete the provisions above, a recipient
30 * may use your version of this file under either the MPL or the
31 * GPL.
32 */
33
34/*
35 * CMS digesting.
36 */
d8f41ccd 37#include <assert.h>
b1ab9ed8
A
38
39#include "cmslocal.h"
40
d8f41ccd 41#include "SecAsn1Item.h"
b1ab9ed8
A
42#include "secoid.h"
43
44#include <security_asn1/secerr.h>
d8f41ccd 45#include <security_asn1/secport.h>
b1ab9ed8 46
d8f41ccd
A
47#if USE_CDSA_CRYPTO
48#include <Security/cssmapi.h>
49#else
50#include <CommonCrypto/CommonDigest.h>
51#endif
427c49bc 52
d8f41ccd 53#include "SecCmsDigestContext.h"
b1ab9ed8 54
60c433a9
A
55/* Return the maximum value between S and T (and U) */
56#define MAX(S, T) ({__typeof__(S) _max_s = S; __typeof__(T) _max_t = T; _max_s > _max_t ? _max_s : _max_t;})
57#define MAX_OF_3(S, T, U) ({__typeof__(U) _max_st = MAX(S,T); MAX(_max_st,U);})
58
b1ab9ed8 59struct SecCmsDigestContextStr {
d8f41ccd 60 PLArenaPool * poolp;
b1ab9ed8 61 Boolean saw_contents;
d8f41ccd
A
62 int digcnt;
63#if USE_CDSA_CRYPTO
b1ab9ed8 64 CSSM_CC_HANDLE * digobjs;
d8f41ccd
A
65#else
66 void ** digobjs;
67#endif
68 SECAlgorithmID ** digestalgs;
b1ab9ed8
A
69};
70
71/*
72 * SecCmsDigestContextStartMultiple - start digest calculation using all the
73 * digest algorithms in "digestalgs" in parallel.
74 */
75SecCmsDigestContextRef
76SecCmsDigestContextStartMultiple(SECAlgorithmID **digestalgs)
77{
d8f41ccd 78 PLArenaPool *poolp;
b1ab9ed8 79 SecCmsDigestContextRef cmsdigcx;
d8f41ccd 80#if USE_CDSA_CRYPTO
b1ab9ed8 81 CSSM_CC_HANDLE digobj;
d8f41ccd
A
82#else
83 void * digobj;
84#endif
b1ab9ed8
A
85 int digcnt;
86 int i;
87
d8f41ccd
A
88 poolp = PORT_NewArena(1024);
89 if (poolp == NULL)
90 goto loser;
91
b1ab9ed8
A
92 digcnt = (digestalgs == NULL) ? 0 : SecCmsArrayCount((void **)digestalgs);
93
d8f41ccd 94 cmsdigcx = (SecCmsDigestContextRef)PORT_ArenaAlloc(poolp, sizeof(struct SecCmsDigestContextStr));
b1ab9ed8
A
95 if (cmsdigcx == NULL)
96 return NULL;
d8f41ccd 97 cmsdigcx->poolp = poolp;
b1ab9ed8
A
98
99 if (digcnt > 0) {
d8f41ccd 100#if USE_CDSA_CRYPTO
60c433a9
A
101 /* Security check to prevent under-allocation */
102 if (digcnt >= (int)((INT_MAX/(MAX(sizeof(CSSM_CC_HANDLE),sizeof(SECAlgorithmID *))))-1)) {
103 goto loser;
104 }
d8f41ccd
A
105 cmsdigcx->digobjs = (CSSM_CC_HANDLE *)PORT_ArenaAlloc(poolp, digcnt * sizeof(CSSM_CC_HANDLE));
106 if (cmsdigcx->digobjs == NULL)
107 goto loser;
108#else
60c433a9
A
109 /* Security check to prevent under-allocation */
110 if (digcnt >= (int)((INT_MAX/(MAX(sizeof(void *),sizeof(SECAlgorithmID *))))-1)) {
111 goto loser;
112 }
d8f41ccd 113 cmsdigcx->digobjs = (void**)PORT_ArenaAlloc(poolp, digcnt * sizeof(void *));
b1ab9ed8
A
114 if (cmsdigcx->digobjs == NULL)
115 goto loser;
d8f41ccd
A
116#endif
117 cmsdigcx->digestalgs = (SECAlgorithmID **)PORT_ArenaZAlloc(poolp,
118 (digcnt + 1) * sizeof(SECAlgorithmID *));
119 if (cmsdigcx->digestalgs == NULL)
120 goto loser;
b1ab9ed8
A
121 }
122
123 cmsdigcx->digcnt = 0;
124
125 /*
126 * Create a digest object context for each algorithm.
127 */
128 for (i = 0; i < digcnt; i++) {
129 digobj = SecCmsUtilGetHashObjByAlgID(digestalgs[i]);
130 /*
131 * Skip any algorithm we do not even recognize; obviously,
132 * this could be a problem, but if it is critical then the
133 * result will just be that the signature does not verify.
134 * We do not necessarily want to error out here, because
135 * the particular algorithm may not actually be important,
136 * but we cannot know that until later.
137 */
d8f41ccd 138#if USE_CDSA_CRYPTO
b1ab9ed8 139 if (digobj)
d8f41ccd
A
140 if (CSSM_DigestDataInit(digobj))
141 goto loser;
142#endif
143
b1ab9ed8 144 cmsdigcx->digobjs[cmsdigcx->digcnt] = digobj;
d8f41ccd
A
145 cmsdigcx->digestalgs[cmsdigcx->digcnt] = PORT_ArenaAlloc(poolp, sizeof(SECAlgorithmID));
146 if (SECITEM_CopyItem(poolp,
147 &(cmsdigcx->digestalgs[cmsdigcx->digcnt]->algorithm),
148 &(digestalgs[i]->algorithm))
149 || SECITEM_CopyItem(poolp,
150 &(cmsdigcx->digestalgs[cmsdigcx->digcnt]->parameters),
151 &(digestalgs[i]->parameters)))
152 goto loser;
b1ab9ed8
A
153 cmsdigcx->digcnt++;
154 }
155
156 cmsdigcx->saw_contents = PR_FALSE;
157
158 return cmsdigcx;
159
160loser:
d8f41ccd
A
161 if (poolp)
162 PORT_FreeArena(poolp, PR_FALSE);
163
b1ab9ed8
A
164 return NULL;
165}
166
167/*
168 * SecCmsDigestContextStartSingle - same as SecCmsDigestContextStartMultiple, but
169 * only one algorithm.
170 */
171SecCmsDigestContextRef
172SecCmsDigestContextStartSingle(SECAlgorithmID *digestalg)
173{
174 SECAlgorithmID *digestalgs[] = { NULL, NULL }; /* fake array */
175
176 digestalgs[0] = digestalg;
177 return SecCmsDigestContextStartMultiple(digestalgs);
178}
179
180/*
181 * SecCmsDigestContextUpdate - feed more data into the digest machine
182 */
183void
184SecCmsDigestContextUpdate(SecCmsDigestContextRef cmsdigcx, const unsigned char *data, size_t len)
185{
d8f41ccd 186 SecAsn1Item dataBuf;
b1ab9ed8
A
187 int i;
188
189 dataBuf.Length = len;
d8f41ccd 190 dataBuf.Data = (uint8_t *)data;
b1ab9ed8 191 cmsdigcx->saw_contents = PR_TRUE;
d8f41ccd
A
192 for (i = 0; i < cmsdigcx->digcnt; i++) {
193 if (cmsdigcx->digobjs[i]) {
194#if USE_CDSA_CRYPTO
b1ab9ed8 195 CSSM_DigestDataUpdate(cmsdigcx->digobjs[i], &dataBuf, 1);
d8f41ccd
A
196#else
197 /* 64 bits cast: worst case is we truncate the length and we dont hash all the data.
198 This may cause an invalid CMS blob larger than 4GB to be validated. Unlikely, but
199 possible security issue. There is no way to return an error here, but a check at
200 the upper level may happen. */
60c433a9
A
201 /*
202 rdar://problem/20642513
203 Let's just die a horrible death rather than have the security issue.
204 CMS blob over 4GB? Oh well.
205 */
206 if (len > UINT32_MAX) {
207 /* Ugh. */
208 abort();
209 }
d8f41ccd
A
210 assert(len<=UINT32_MAX); /* Debug check. Correct as long as CC_LONG is uint32_t */
211 switch (SECOID_GetAlgorithmTag(cmsdigcx->digestalgs[i])) {
212 case SEC_OID_SHA1: CC_SHA1_Update((CC_SHA1_CTX *)cmsdigcx->digobjs[i], data, (CC_LONG)len); break;
213 case SEC_OID_MD5: CC_MD5_Update((CC_MD5_CTX *)cmsdigcx->digobjs[i], data, (CC_LONG)len); break;
214 case SEC_OID_SHA224: CC_SHA224_Update((CC_SHA256_CTX *)cmsdigcx->digobjs[i], data, (CC_LONG)len); break;
215 case SEC_OID_SHA256: CC_SHA256_Update((CC_SHA256_CTX *)cmsdigcx->digobjs[i], data, (CC_LONG)len); break;
216 case SEC_OID_SHA384: CC_SHA384_Update((CC_SHA512_CTX *)cmsdigcx->digobjs[i], data, (CC_LONG)len); break;
217 case SEC_OID_SHA512: CC_SHA512_Update((CC_SHA512_CTX *)cmsdigcx->digobjs[i], data, (CC_LONG)len); break;
218 default:
219 break;
220 }
221#endif
222 }
223 }
b1ab9ed8
A
224}
225
226/*
227 * SecCmsDigestContextCancel - cancel digesting operation
228 */
229void
230SecCmsDigestContextCancel(SecCmsDigestContextRef cmsdigcx)
231{
232 int i;
233
234 for (i = 0; i < cmsdigcx->digcnt; i++)
235 if (cmsdigcx->digobjs[i])
d8f41ccd 236#if USE_CDSA_CRYPTO
b1ab9ed8 237 CSSM_DeleteContext(cmsdigcx->digobjs[i]);
d8f41ccd
A
238#else
239 free(cmsdigcx->digobjs[i]);
240#endif
241
242 PORT_FreeArena(cmsdigcx->poolp, PR_FALSE);
b1ab9ed8
A
243}
244
245/*
d8f41ccd
A
246 * SecCmsDigestContextDestroy - delete a digesting operation
247 */
248void
249SecCmsDigestContextDestroy(SecCmsDigestContextRef cmsdigcx)
250{
251 SecCmsDigestContextCancel(cmsdigcx);
252}
253
254/*
255 * SecCmsDigestContextFinishMultiple - finish the digests
b1ab9ed8
A
256 */
257OSStatus
d8f41ccd
A
258SecCmsDigestContextFinishMultiple(SecCmsDigestContextRef cmsdigcx,
259 SECAlgorithmID ***digestalgsp,
260 SecAsn1Item * **digestsp)
b1ab9ed8 261{
d8f41ccd
A
262#if USE_CDSA_CRYPTO
263 CSSM_CC_HANDLE digboj;
264#else
265 void * digobj;
266#endif
267 SecAsn1Item **digests, *digest;
268 SECAlgorithmID **digestalgs;
b1ab9ed8
A
269 int i;
270 void *mark;
271 OSStatus rv = SECFailure;
272
d8f41ccd
A
273 assert(cmsdigcx != NULL);
274
275 /* A message with no contents (just signed attributes) is used within SCEP */
276#if 0
b1ab9ed8
A
277 /* no contents? do not update digests */
278 if (digestsp == NULL || !cmsdigcx->saw_contents) {
279 for (i = 0; i < cmsdigcx->digcnt; i++)
280 if (cmsdigcx->digobjs[i])
d8f41ccd 281#if USE_CDSA_CRYPTO
b1ab9ed8 282 CSSM_DeleteContext(cmsdigcx->digobjs[i]);
d8f41ccd
A
283#else
284 free(cmsdigcx->digobjs[i]);
285#endif
b1ab9ed8
A
286 rv = SECSuccess;
287 if (digestsp)
288 *digestsp = NULL;
289 goto cleanup;
290 }
d8f41ccd
A
291#endif
292
293 assert(digestsp != NULL);
294 assert(digestalgsp != NULL);
b1ab9ed8 295
d8f41ccd 296 mark = PORT_ArenaMark (cmsdigcx->poolp);
b1ab9ed8 297
60c433a9
A
298 /* Security check to prevent under-allocation */
299 if (cmsdigcx->digcnt >= (int)((INT_MAX/(MAX_OF_3(sizeof(SECAlgorithmID *),sizeof(SecAsn1Item *),sizeof(SecAsn1Item))))-1)) {
300 goto loser;
301 }
d8f41ccd
A
302 /* allocate digest array & SecAsn1Items on arena */
303 digestalgs = (SECAlgorithmID **)PORT_ArenaZAlloc(cmsdigcx->poolp, (cmsdigcx->digcnt+1) * sizeof(SECAlgorithmID *));
304 digests = (SecAsn1Item * *)PORT_ArenaZAlloc(cmsdigcx->poolp, (cmsdigcx->digcnt+1) * sizeof(SecAsn1Item *));
305 digest = (SecAsn1Item *)PORT_ArenaZAlloc(cmsdigcx->poolp, cmsdigcx->digcnt * sizeof(SecAsn1Item));
306 if (digestalgs == NULL || digests == NULL || digest == NULL) {
b1ab9ed8
A
307 goto loser;
308 }
309
310 for (i = 0; i < cmsdigcx->digcnt; i++, digest++) {
d8f41ccd
A
311
312 SECOidTag hash_alg = SECOID_GetAlgorithmTag(cmsdigcx->digestalgs[i]);
313 int diglength = 0;
314
315 switch (hash_alg) {
316 case SEC_OID_SHA1: diglength = CC_SHA1_DIGEST_LENGTH; break;
317 case SEC_OID_MD5: diglength = CC_MD5_DIGEST_LENGTH; break;
318 case SEC_OID_SHA224: diglength = CC_SHA224_DIGEST_LENGTH; break;
319 case SEC_OID_SHA256: diglength = CC_SHA256_DIGEST_LENGTH; break;
320 case SEC_OID_SHA384: diglength = CC_SHA384_DIGEST_LENGTH; break;
321 case SEC_OID_SHA512: diglength = CC_SHA512_DIGEST_LENGTH; break;
322 default: goto loser; break;
427c49bc
A
323 }
324
d8f41ccd 325 digobj = cmsdigcx->digobjs[i];
b1ab9ed8
A
326 if (digobj)
327 {
d8f41ccd 328 digest->Data = (unsigned char*)PORT_ArenaAlloc(cmsdigcx->poolp, diglength);
b1ab9ed8
A
329 if (digest->Data == NULL)
330 goto loser;
331 digest->Length = diglength;
d8f41ccd
A
332#if USE_CDSA_CRYPTO
333 CSSM_DigestDataFinal(digobj, digest);
b1ab9ed8 334 CSSM_DeleteContext(digobj);
d8f41ccd
A
335#else
336 switch (hash_alg) {
337 case SEC_OID_SHA1: CC_SHA1_Final(digest->Data, digobj); break;
338 case SEC_OID_MD5: CC_MD5_Final(digest->Data, digobj); break;
339 case SEC_OID_SHA224: CC_SHA224_Final(digest->Data, digobj); break;
340 case SEC_OID_SHA256: CC_SHA256_Final(digest->Data, digobj); break;
341 case SEC_OID_SHA384: CC_SHA384_Final(digest->Data, digobj); break;
342 case SEC_OID_SHA512: CC_SHA512_Final(digest->Data, digobj); break;
343 default: goto loser; break;
344 }
345
346 free(digobj);
347#endif
348 digestalgs[i] = cmsdigcx->digestalgs[i];
349 digests[i] = digest;
b1ab9ed8
A
350 }
351 else
352 {
353 digest->Data = NULL;
354 digest->Length = 0;
355 }
d8f41ccd
A
356 }
357 digestalgs[i] = NULL;
b1ab9ed8 358 digests[i] = NULL;
d8f41ccd 359 *digestalgsp = digestalgs;
b1ab9ed8
A
360 *digestsp = digests;
361
362 rv = SECSuccess;
363
364loser:
365 if (rv == SECSuccess)
d8f41ccd 366 PORT_ArenaUnmark(cmsdigcx->poolp, mark);
b1ab9ed8 367 else
d8f41ccd 368 PORT_ArenaRelease(cmsdigcx->poolp, mark);
b1ab9ed8 369
d8f41ccd
A
370/*cleanup:*/
371 /* Set things up so SecCmsDigestContextDestroy won't call CSSM_DeleteContext again. */
372 cmsdigcx->digcnt = 0;
b1ab9ed8
A
373
374 return rv;
375}
376
377/*
378 * SecCmsDigestContextFinishSingle - same as SecCmsDigestContextFinishMultiple,
379 * but for one digest.
380 */
381OSStatus
d8f41ccd
A
382SecCmsDigestContextFinishSingle(SecCmsDigestContextRef cmsdigcx,
383 SecAsn1Item * digest)
b1ab9ed8
A
384{
385 OSStatus rv = SECFailure;
d8f41ccd
A
386 SecAsn1Item * *dp;
387 SECAlgorithmID **ap;
b1ab9ed8
A
388
389 /* get the digests into arena, then copy the first digest into poolp */
d8f41ccd 390 if (SecCmsDigestContextFinishMultiple(cmsdigcx, &ap, &dp) != SECSuccess)
b1ab9ed8
A
391 goto loser;
392
d8f41ccd
A
393 /* Return the first element in the digest array. */
394 digest = *dp;
b1ab9ed8
A
395
396 rv = SECSuccess;
397
398loser:
b1ab9ed8
A
399 return rv;
400}