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
37 #include <security_utilities/simulatecrash_assert.h>
41 #include "SecAsn1Item.h"
44 #include <security_asn1/secerr.h>
45 #include <security_asn1/secport.h>
47 #include <CommonCrypto/CommonDigest.h>
49 #include <Security/SecCmsDigestContext.h>
51 /* Return the maximum value between S and T (and U) */
52 #define MAX(S, T) ({__typeof__(S) _max_s = S; __typeof__(T) _max_t = T; _max_s > _max_t ? _max_s : _max_t;})
53 #define MAX_OF_3(S, T, U) ({__typeof__(U) _max_st = MAX(S,T); MAX(_max_st,U);})
55 struct SecCmsDigestContextStr
{
60 SECAlgorithmID
** digestalgs
;
64 * SecCmsDigestContextStartMultiple - start digest calculation using all the
65 * digest algorithms in "digestalgs" in parallel.
67 SecCmsDigestContextRef
68 SecCmsDigestContextStartMultiple(SECAlgorithmID
**digestalgs
)
71 SecCmsDigestContextRef cmsdigcx
;
76 poolp
= PORT_NewArena(1024);
81 digcnt
= (digestalgs
== NULL
) ? 0 : SecCmsArrayCount((void **)digestalgs
);
83 cmsdigcx
= (SecCmsDigestContextRef
)PORT_ArenaAlloc(poolp
, sizeof(struct SecCmsDigestContextStr
));
84 if (cmsdigcx
== NULL
) {
87 cmsdigcx
->poolp
= poolp
;
90 /* Security check to prevent under-allocation */
91 if (digcnt
>= (int)((INT_MAX
/(MAX(sizeof(void *),sizeof(SECAlgorithmID
*))))-1)) {
94 cmsdigcx
->digobjs
= (void**)PORT_ArenaAlloc(poolp
, digcnt
* sizeof(void *));
95 if (cmsdigcx
->digobjs
== NULL
) {
98 cmsdigcx
->digestalgs
= (SECAlgorithmID
**)PORT_ArenaZAlloc(poolp
, (digcnt
+ 1) * sizeof(SECAlgorithmID
*));
99 if (cmsdigcx
->digestalgs
== NULL
) {
104 cmsdigcx
->digcnt
= 0;
107 * Create a digest object context for each algorithm.
109 for (i
= 0; i
< digcnt
; i
++) {
110 digobj
= SecCmsUtilGetHashObjByAlgID(digestalgs
[i
]);
112 * Skip any algorithm we do not even recognize; obviously,
113 * this could be a problem, but if it is critical then the
114 * result will just be that the signature does not verify.
115 * We do not necessarily want to error out here, because
116 * the particular algorithm may not actually be important,
117 * but we cannot know that until later.
120 cmsdigcx
->digobjs
[cmsdigcx
->digcnt
] = digobj
;
121 cmsdigcx
->digestalgs
[cmsdigcx
->digcnt
] = PORT_ArenaAlloc(poolp
, sizeof(SECAlgorithmID
));
122 if (SECITEM_CopyItem(poolp
,
123 &(cmsdigcx
->digestalgs
[cmsdigcx
->digcnt
]->algorithm
),
124 &(digestalgs
[i
]->algorithm
))
125 || SECITEM_CopyItem(poolp
,
126 &(cmsdigcx
->digestalgs
[cmsdigcx
->digcnt
]->parameters
),
127 &(digestalgs
[i
]->parameters
))) {
133 cmsdigcx
->saw_contents
= PR_FALSE
;
139 PORT_FreeArena(poolp
, PR_FALSE
);
146 * SecCmsDigestContextStartSingle - same as SecCmsDigestContextStartMultiple, but
147 * only one algorithm.
149 SecCmsDigestContextRef
150 SecCmsDigestContextStartSingle(SECAlgorithmID
*digestalg
)
152 SECAlgorithmID
*digestalgs
[] = { NULL
, NULL
}; /* fake array */
154 digestalgs
[0] = digestalg
;
155 return SecCmsDigestContextStartMultiple(digestalgs
);
159 * SecCmsDigestContextUpdate - feed more data into the digest machine
162 SecCmsDigestContextUpdate(SecCmsDigestContextRef cmsdigcx
, const unsigned char *data
, size_t len
)
167 dataBuf
.Length
= len
;
168 dataBuf
.Data
= (uint8_t *)data
;
169 cmsdigcx
->saw_contents
= PR_TRUE
;
170 for (i
= 0; i
< cmsdigcx
->digcnt
; i
++) {
171 if (cmsdigcx
->digobjs
[i
]) {
172 /* 64 bits cast: worst case is we truncate the length and we dont hash all the data.
173 This may cause an invalid CMS blob larger than 4GB to be validated. Unlikely, but
174 possible security issue. There is no way to return an error here, but a check at
175 the upper level may happen. */
177 rdar://problem/20642513
178 Let's just die a horrible death rather than have the security issue.
179 CMS blob over 4GB? Oh well.
181 if (len
> UINT32_MAX
) {
185 assert(len
<=UINT32_MAX
); /* Debug check. Correct as long as CC_LONG is uint32_t */
186 switch (SECOID_GetAlgorithmTag(cmsdigcx
->digestalgs
[i
])) {
187 case SEC_OID_SHA1
: CC_SHA1_Update((CC_SHA1_CTX
*)cmsdigcx
->digobjs
[i
], data
, (CC_LONG
)len
); break;
188 case SEC_OID_MD5
: CC_MD5_Update((CC_MD5_CTX
*)cmsdigcx
->digobjs
[i
], data
, (CC_LONG
)len
); break;
189 case SEC_OID_SHA224
: CC_SHA224_Update((CC_SHA256_CTX
*)cmsdigcx
->digobjs
[i
], data
, (CC_LONG
)len
); break;
190 case SEC_OID_SHA256
: CC_SHA256_Update((CC_SHA256_CTX
*)cmsdigcx
->digobjs
[i
], data
, (CC_LONG
)len
); break;
191 case SEC_OID_SHA384
: CC_SHA384_Update((CC_SHA512_CTX
*)cmsdigcx
->digobjs
[i
], data
, (CC_LONG
)len
); break;
192 case SEC_OID_SHA512
: CC_SHA512_Update((CC_SHA512_CTX
*)cmsdigcx
->digobjs
[i
], data
, (CC_LONG
)len
); break;
201 * SecCmsDigestContextCancel - cancel digesting operation
204 SecCmsDigestContextCancel(SecCmsDigestContextRef cmsdigcx
)
208 for (i
= 0; i
< cmsdigcx
->digcnt
; i
++) {
209 if (cmsdigcx
->digobjs
&& cmsdigcx
->digobjs
[i
]) {
210 free(cmsdigcx
->digobjs
[i
]);
211 cmsdigcx
->digobjs
[i
] = NULL
;
215 PORT_FreeArena(cmsdigcx
->poolp
, PR_TRUE
);
219 * SecCmsDigestContextDestroy - delete a digesting operation
222 SecCmsDigestContextDestroy(SecCmsDigestContextRef cmsdigcx
)
224 SecCmsDigestContextCancel(cmsdigcx
);
228 * SecCmsDigestContextFinishMultiple - finish the digests
229 * Note that on iOS, this call only frees the digest objects and requires a call to SecCmsDisgestContextDestroy
230 * or SecCmsDisgestContextCancel (because the digests are allocated out of the context's pool).
231 * The macOS version cancels and frees the digest context (because the digests are allocated from an input arena pool).
234 SecCmsDigestContextFinishMultiple(SecCmsDigestContextRef cmsdigcx
,
235 SECAlgorithmID
***digestalgsp
,
236 SecAsn1Item
* **digestsp
)
239 SecAsn1Item
**digests
, *digest
;
240 SECAlgorithmID
**digestalgs
;
243 OSStatus rv
= SECFailure
;
245 assert(cmsdigcx
!= NULL
);
247 /* A message with no contents (just signed attributes) is used within SCEP */
249 /* no contents? do not update digests */
250 if (digestsp
== NULL
|| !cmsdigcx
->saw_contents
) {
251 for (i
= 0; i
< cmsdigcx
->digcnt
; i
++) {
252 if (cmsdigcx
->digobjs
[i
]) {
253 free(cmsdigcx
->digobjs
[i
]);
264 assert(digestsp
!= NULL
);
265 assert(digestalgsp
!= NULL
);
267 mark
= PORT_ArenaMark (cmsdigcx
->poolp
);
269 /* Security check to prevent under-allocation */
270 if (cmsdigcx
->digcnt
>= (int)((INT_MAX
/(MAX_OF_3(sizeof(SECAlgorithmID
*),sizeof(SecAsn1Item
*),sizeof(SecAsn1Item
))))-1)) {
273 /* allocate digest array & SecAsn1Items on arena */
274 digestalgs
= (SECAlgorithmID
**)PORT_ArenaZAlloc(cmsdigcx
->poolp
, (cmsdigcx
->digcnt
+1) * sizeof(SECAlgorithmID
*));
275 digests
= (SecAsn1Item
* *)PORT_ArenaZAlloc(cmsdigcx
->poolp
, (cmsdigcx
->digcnt
+1) * sizeof(SecAsn1Item
*));
276 digest
= (SecAsn1Item
*)PORT_ArenaZAlloc(cmsdigcx
->poolp
, cmsdigcx
->digcnt
* sizeof(SecAsn1Item
));
277 if (digestalgs
== NULL
|| digests
== NULL
|| digest
== NULL
) {
281 for (i
= 0; i
< cmsdigcx
->digcnt
; i
++, digest
++) {
282 SECOidTag hash_alg
= SECOID_GetAlgorithmTag(cmsdigcx
->digestalgs
[i
]);
286 case SEC_OID_SHA1
: diglength
= CC_SHA1_DIGEST_LENGTH
; break;
287 case SEC_OID_MD5
: diglength
= CC_MD5_DIGEST_LENGTH
; break;
288 case SEC_OID_SHA224
: diglength
= CC_SHA224_DIGEST_LENGTH
; break;
289 case SEC_OID_SHA256
: diglength
= CC_SHA256_DIGEST_LENGTH
; break;
290 case SEC_OID_SHA384
: diglength
= CC_SHA384_DIGEST_LENGTH
; break;
291 case SEC_OID_SHA512
: diglength
= CC_SHA512_DIGEST_LENGTH
; break;
295 digobj
= cmsdigcx
->digobjs
[i
];
297 digest
->Data
= (unsigned char*)PORT_ArenaAlloc(cmsdigcx
->poolp
, diglength
);
298 if (digest
->Data
== NULL
)
300 digest
->Length
= diglength
;
302 case SEC_OID_SHA1
: CC_SHA1_Final(digest
->Data
, digobj
); break;
303 case SEC_OID_MD5
: CC_MD5_Final(digest
->Data
, digobj
); break;
304 case SEC_OID_SHA224
: CC_SHA224_Final(digest
->Data
, digobj
); break;
305 case SEC_OID_SHA256
: CC_SHA256_Final(digest
->Data
, digobj
); break;
306 case SEC_OID_SHA384
: CC_SHA384_Final(digest
->Data
, digobj
); break;
307 case SEC_OID_SHA512
: CC_SHA512_Final(digest
->Data
, digobj
); break;
312 digestalgs
[i
] = cmsdigcx
->digestalgs
[i
];
319 digestalgs
[i
] = NULL
;
321 *digestalgsp
= digestalgs
;
327 if (rv
== SECSuccess
) {
328 PORT_ArenaUnmark(cmsdigcx
->poolp
, mark
);
330 PORT_ArenaRelease(cmsdigcx
->poolp
, mark
);
334 /* Set things up so SecCmsDigestContextDestroy won't call CSSM_DeleteContext again. */
335 cmsdigcx
->digcnt
= 0;
341 * SecCmsDigestContextFinishSingle - same as SecCmsDigestContextFinishMultiple,
342 * but for one digest.
345 SecCmsDigestContextFinishSingle(SecCmsDigestContextRef cmsdigcx
,
346 SecAsn1Item
* digest
)
348 OSStatus rv
= SECFailure
;
352 /* get the digests into arena, then copy the first digest into poolp */
353 if (SecCmsDigestContextFinishMultiple(cmsdigcx
, &ap
, &dp
) != SECSuccess
) {
357 /* Return the first element in the digest array. */