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/
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.
12 * The Original Code is the Netscape security libraries.
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
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
41 #include "SecAsn1Item.h"
44 #include <security_asn1/secerr.h>
45 #include <security_asn1/secport.h>
48 #include <Security/cssmapi.h>
50 #include <CommonCrypto/CommonDigest.h>
53 #include "SecCmsDigestContext.h"
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);})
59 struct SecCmsDigestContextStr
{
64 CSSM_CC_HANDLE
* digobjs
;
68 SECAlgorithmID
** digestalgs
;
72 * SecCmsDigestContextStartMultiple - start digest calculation using all the
73 * digest algorithms in "digestalgs" in parallel.
75 SecCmsDigestContextRef
76 SecCmsDigestContextStartMultiple(SECAlgorithmID
**digestalgs
)
79 SecCmsDigestContextRef cmsdigcx
;
81 CSSM_CC_HANDLE digobj
;
88 poolp
= PORT_NewArena(1024);
92 digcnt
= (digestalgs
== NULL
) ? 0 : SecCmsArrayCount((void **)digestalgs
);
94 cmsdigcx
= (SecCmsDigestContextRef
)PORT_ArenaAlloc(poolp
, sizeof(struct SecCmsDigestContextStr
));
95 if (cmsdigcx
== NULL
) {
98 cmsdigcx
->poolp
= poolp
;
102 /* Security check to prevent under-allocation */
103 if (digcnt
>= (int)((INT_MAX
/(MAX(sizeof(CSSM_CC_HANDLE
),sizeof(SECAlgorithmID
*))))-1)) {
106 cmsdigcx
->digobjs
= (CSSM_CC_HANDLE
*)PORT_ArenaAlloc(poolp
, digcnt
* sizeof(CSSM_CC_HANDLE
));
107 if (cmsdigcx
->digobjs
== NULL
)
110 /* Security check to prevent under-allocation */
111 if (digcnt
>= (int)((INT_MAX
/(MAX(sizeof(void *),sizeof(SECAlgorithmID
*))))-1)) {
114 cmsdigcx
->digobjs
= (void**)PORT_ArenaAlloc(poolp
, digcnt
* sizeof(void *));
115 if (cmsdigcx
->digobjs
== NULL
)
118 cmsdigcx
->digestalgs
= (SECAlgorithmID
**)PORT_ArenaZAlloc(poolp
,
119 (digcnt
+ 1) * sizeof(SECAlgorithmID
*));
120 if (cmsdigcx
->digestalgs
== NULL
)
124 cmsdigcx
->digcnt
= 0;
127 * Create a digest object context for each algorithm.
129 for (i
= 0; i
< digcnt
; i
++) {
130 digobj
= SecCmsUtilGetHashObjByAlgID(digestalgs
[i
]);
132 * Skip any algorithm we do not even recognize; obviously,
133 * this could be a problem, but if it is critical then the
134 * result will just be that the signature does not verify.
135 * We do not necessarily want to error out here, because
136 * the particular algorithm may not actually be important,
137 * but we cannot know that until later.
141 if (CSSM_DigestDataInit(digobj
))
145 cmsdigcx
->digobjs
[cmsdigcx
->digcnt
] = digobj
;
146 cmsdigcx
->digestalgs
[cmsdigcx
->digcnt
] = PORT_ArenaAlloc(poolp
, sizeof(SECAlgorithmID
));
147 if (SECITEM_CopyItem(poolp
,
148 &(cmsdigcx
->digestalgs
[cmsdigcx
->digcnt
]->algorithm
),
149 &(digestalgs
[i
]->algorithm
))
150 || SECITEM_CopyItem(poolp
,
151 &(cmsdigcx
->digestalgs
[cmsdigcx
->digcnt
]->parameters
),
152 &(digestalgs
[i
]->parameters
)))
157 cmsdigcx
->saw_contents
= PR_FALSE
;
163 PORT_FreeArena(poolp
, PR_FALSE
);
169 * SecCmsDigestContextStartSingle - same as SecCmsDigestContextStartMultiple, but
170 * only one algorithm.
172 SecCmsDigestContextRef
173 SecCmsDigestContextStartSingle(SECAlgorithmID
*digestalg
)
175 SECAlgorithmID
*digestalgs
[] = { NULL
, NULL
}; /* fake array */
177 digestalgs
[0] = digestalg
;
178 return SecCmsDigestContextStartMultiple(digestalgs
);
182 * SecCmsDigestContextUpdate - feed more data into the digest machine
185 SecCmsDigestContextUpdate(SecCmsDigestContextRef cmsdigcx
, const unsigned char *data
, size_t len
)
190 dataBuf
.Length
= len
;
191 dataBuf
.Data
= (uint8_t *)data
;
192 cmsdigcx
->saw_contents
= PR_TRUE
;
193 for (i
= 0; i
< cmsdigcx
->digcnt
; i
++) {
194 if (cmsdigcx
->digobjs
[i
]) {
196 CSSM_DigestDataUpdate(cmsdigcx
->digobjs
[i
], &dataBuf
, 1);
198 /* 64 bits cast: worst case is we truncate the length and we dont hash all the data.
199 This may cause an invalid CMS blob larger than 4GB to be validated. Unlikely, but
200 possible security issue. There is no way to return an error here, but a check at
201 the upper level may happen. */
203 rdar://problem/20642513
204 Let's just die a horrible death rather than have the security issue.
205 CMS blob over 4GB? Oh well.
207 if (len
> UINT32_MAX
) {
211 assert(len
<=UINT32_MAX
); /* Debug check. Correct as long as CC_LONG is uint32_t */
212 switch (SECOID_GetAlgorithmTag(cmsdigcx
->digestalgs
[i
])) {
213 case SEC_OID_SHA1
: CC_SHA1_Update((CC_SHA1_CTX
*)cmsdigcx
->digobjs
[i
], data
, (CC_LONG
)len
); break;
214 case SEC_OID_MD5
: CC_MD5_Update((CC_MD5_CTX
*)cmsdigcx
->digobjs
[i
], data
, (CC_LONG
)len
); break;
215 case SEC_OID_SHA224
: CC_SHA224_Update((CC_SHA256_CTX
*)cmsdigcx
->digobjs
[i
], data
, (CC_LONG
)len
); break;
216 case SEC_OID_SHA256
: CC_SHA256_Update((CC_SHA256_CTX
*)cmsdigcx
->digobjs
[i
], data
, (CC_LONG
)len
); break;
217 case SEC_OID_SHA384
: CC_SHA384_Update((CC_SHA512_CTX
*)cmsdigcx
->digobjs
[i
], data
, (CC_LONG
)len
); break;
218 case SEC_OID_SHA512
: CC_SHA512_Update((CC_SHA512_CTX
*)cmsdigcx
->digobjs
[i
], data
, (CC_LONG
)len
); break;
228 * SecCmsDigestContextCancel - cancel digesting operation
231 SecCmsDigestContextCancel(SecCmsDigestContextRef cmsdigcx
)
235 for (i
= 0; i
< cmsdigcx
->digcnt
; i
++)
236 if (cmsdigcx
->digobjs
[i
])
238 CSSM_DeleteContext(cmsdigcx
->digobjs
[i
]);
240 free(cmsdigcx
->digobjs
[i
]);
243 PORT_FreeArena(cmsdigcx
->poolp
, PR_TRUE
);
247 * SecCmsDigestContextDestroy - delete a digesting operation
250 SecCmsDigestContextDestroy(SecCmsDigestContextRef cmsdigcx
)
252 SecCmsDigestContextCancel(cmsdigcx
);
256 * SecCmsDigestContextFinishMultiple - finish the digests
259 SecCmsDigestContextFinishMultiple(SecCmsDigestContextRef cmsdigcx
,
260 SECAlgorithmID
***digestalgsp
,
261 SecAsn1Item
* **digestsp
)
264 CSSM_CC_HANDLE digboj
;
268 SecAsn1Item
**digests
, *digest
;
269 SECAlgorithmID
**digestalgs
;
272 OSStatus rv
= SECFailure
;
274 assert(cmsdigcx
!= NULL
);
276 /* A message with no contents (just signed attributes) is used within SCEP */
278 /* no contents? do not update digests */
279 if (digestsp
== NULL
|| !cmsdigcx
->saw_contents
) {
280 for (i
= 0; i
< cmsdigcx
->digcnt
; i
++)
281 if (cmsdigcx
->digobjs
[i
])
283 CSSM_DeleteContext(cmsdigcx
->digobjs
[i
]);
285 free(cmsdigcx
->digobjs
[i
]);
294 assert(digestsp
!= NULL
);
295 assert(digestalgsp
!= NULL
);
297 mark
= PORT_ArenaMark (cmsdigcx
->poolp
);
299 /* Security check to prevent under-allocation */
300 if (cmsdigcx
->digcnt
>= (int)((INT_MAX
/(MAX_OF_3(sizeof(SECAlgorithmID
*),sizeof(SecAsn1Item
*),sizeof(SecAsn1Item
))))-1)) {
303 /* allocate digest array & SecAsn1Items on arena */
304 digestalgs
= (SECAlgorithmID
**)PORT_ArenaZAlloc(cmsdigcx
->poolp
, (cmsdigcx
->digcnt
+1) * sizeof(SECAlgorithmID
*));
305 digests
= (SecAsn1Item
* *)PORT_ArenaZAlloc(cmsdigcx
->poolp
, (cmsdigcx
->digcnt
+1) * sizeof(SecAsn1Item
*));
306 digest
= (SecAsn1Item
*)PORT_ArenaZAlloc(cmsdigcx
->poolp
, cmsdigcx
->digcnt
* sizeof(SecAsn1Item
));
307 if (digestalgs
== NULL
|| digests
== NULL
|| digest
== NULL
) {
311 for (i
= 0; i
< cmsdigcx
->digcnt
; i
++, digest
++) {
313 SECOidTag hash_alg
= SECOID_GetAlgorithmTag(cmsdigcx
->digestalgs
[i
]);
317 case SEC_OID_SHA1
: diglength
= CC_SHA1_DIGEST_LENGTH
; break;
318 case SEC_OID_MD5
: diglength
= CC_MD5_DIGEST_LENGTH
; break;
319 case SEC_OID_SHA224
: diglength
= CC_SHA224_DIGEST_LENGTH
; break;
320 case SEC_OID_SHA256
: diglength
= CC_SHA256_DIGEST_LENGTH
; break;
321 case SEC_OID_SHA384
: diglength
= CC_SHA384_DIGEST_LENGTH
; break;
322 case SEC_OID_SHA512
: diglength
= CC_SHA512_DIGEST_LENGTH
; break;
323 default: goto loser
; break;
326 digobj
= cmsdigcx
->digobjs
[i
];
329 digest
->Data
= (unsigned char*)PORT_ArenaAlloc(cmsdigcx
->poolp
, diglength
);
330 if (digest
->Data
== NULL
)
332 digest
->Length
= diglength
;
334 CSSM_DigestDataFinal(digobj
, digest
);
335 CSSM_DeleteContext(digobj
);
338 case SEC_OID_SHA1
: CC_SHA1_Final(digest
->Data
, digobj
); break;
339 case SEC_OID_MD5
: CC_MD5_Final(digest
->Data
, digobj
); break;
340 case SEC_OID_SHA224
: CC_SHA224_Final(digest
->Data
, digobj
); break;
341 case SEC_OID_SHA256
: CC_SHA256_Final(digest
->Data
, digobj
); break;
342 case SEC_OID_SHA384
: CC_SHA384_Final(digest
->Data
, digobj
); break;
343 case SEC_OID_SHA512
: CC_SHA512_Final(digest
->Data
, digobj
); break;
344 default: goto loser
; break;
349 digestalgs
[i
] = cmsdigcx
->digestalgs
[i
];
358 digestalgs
[i
] = NULL
;
360 *digestalgsp
= digestalgs
;
366 if (rv
== SECSuccess
)
367 PORT_ArenaUnmark(cmsdigcx
->poolp
, mark
);
369 PORT_ArenaRelease(cmsdigcx
->poolp
, mark
);
372 /* Set things up so SecCmsDigestContextDestroy won't call CSSM_DeleteContext again. */
373 cmsdigcx
->digcnt
= 0;
379 * SecCmsDigestContextFinishSingle - same as SecCmsDigestContextFinishMultiple,
380 * but for one digest.
383 SecCmsDigestContextFinishSingle(SecCmsDigestContextRef cmsdigcx
,
384 SecAsn1Item
* digest
)
386 OSStatus rv
= SECFailure
;
390 /* get the digests into arena, then copy the first digest into poolp */
391 if (SecCmsDigestContextFinishMultiple(cmsdigcx
, &ap
, &dp
) != SECSuccess
)
394 /* Return the first element in the digest array. */