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
));
97 cmsdigcx
->poolp
= poolp
;
101 /* Security check to prevent under-allocation */
102 if (digcnt
>= (int)((INT_MAX
/(MAX(sizeof(CSSM_CC_HANDLE
),sizeof(SECAlgorithmID
*))))-1)) {
105 cmsdigcx
->digobjs
= (CSSM_CC_HANDLE
*)PORT_ArenaAlloc(poolp
, digcnt
* sizeof(CSSM_CC_HANDLE
));
106 if (cmsdigcx
->digobjs
== NULL
)
109 /* Security check to prevent under-allocation */
110 if (digcnt
>= (int)((INT_MAX
/(MAX(sizeof(void *),sizeof(SECAlgorithmID
*))))-1)) {
113 cmsdigcx
->digobjs
= (void**)PORT_ArenaAlloc(poolp
, digcnt
* sizeof(void *));
114 if (cmsdigcx
->digobjs
== NULL
)
117 cmsdigcx
->digestalgs
= (SECAlgorithmID
**)PORT_ArenaZAlloc(poolp
,
118 (digcnt
+ 1) * sizeof(SECAlgorithmID
*));
119 if (cmsdigcx
->digestalgs
== NULL
)
123 cmsdigcx
->digcnt
= 0;
126 * Create a digest object context for each algorithm.
128 for (i
= 0; i
< digcnt
; i
++) {
129 digobj
= SecCmsUtilGetHashObjByAlgID(digestalgs
[i
]);
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.
140 if (CSSM_DigestDataInit(digobj
))
144 cmsdigcx
->digobjs
[cmsdigcx
->digcnt
] = digobj
;
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
)))
156 cmsdigcx
->saw_contents
= PR_FALSE
;
162 PORT_FreeArena(poolp
, PR_FALSE
);
168 * SecCmsDigestContextStartSingle - same as SecCmsDigestContextStartMultiple, but
169 * only one algorithm.
171 SecCmsDigestContextRef
172 SecCmsDigestContextStartSingle(SECAlgorithmID
*digestalg
)
174 SECAlgorithmID
*digestalgs
[] = { NULL
, NULL
}; /* fake array */
176 digestalgs
[0] = digestalg
;
177 return SecCmsDigestContextStartMultiple(digestalgs
);
181 * SecCmsDigestContextUpdate - feed more data into the digest machine
184 SecCmsDigestContextUpdate(SecCmsDigestContextRef cmsdigcx
, const unsigned char *data
, size_t len
)
189 dataBuf
.Length
= len
;
190 dataBuf
.Data
= (uint8_t *)data
;
191 cmsdigcx
->saw_contents
= PR_TRUE
;
192 for (i
= 0; i
< cmsdigcx
->digcnt
; i
++) {
193 if (cmsdigcx
->digobjs
[i
]) {
195 CSSM_DigestDataUpdate(cmsdigcx
->digobjs
[i
], &dataBuf
, 1);
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. */
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.
206 if (len
> UINT32_MAX
) {
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;
227 * SecCmsDigestContextCancel - cancel digesting operation
230 SecCmsDigestContextCancel(SecCmsDigestContextRef cmsdigcx
)
234 for (i
= 0; i
< cmsdigcx
->digcnt
; i
++)
235 if (cmsdigcx
->digobjs
[i
])
237 CSSM_DeleteContext(cmsdigcx
->digobjs
[i
]);
239 free(cmsdigcx
->digobjs
[i
]);
242 PORT_FreeArena(cmsdigcx
->poolp
, PR_FALSE
);
246 * SecCmsDigestContextDestroy - delete a digesting operation
249 SecCmsDigestContextDestroy(SecCmsDigestContextRef cmsdigcx
)
251 SecCmsDigestContextCancel(cmsdigcx
);
255 * SecCmsDigestContextFinishMultiple - finish the digests
258 SecCmsDigestContextFinishMultiple(SecCmsDigestContextRef cmsdigcx
,
259 SECAlgorithmID
***digestalgsp
,
260 SecAsn1Item
* **digestsp
)
263 CSSM_CC_HANDLE digboj
;
267 SecAsn1Item
**digests
, *digest
;
268 SECAlgorithmID
**digestalgs
;
271 OSStatus rv
= SECFailure
;
273 assert(cmsdigcx
!= NULL
);
275 /* A message with no contents (just signed attributes) is used within SCEP */
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
])
282 CSSM_DeleteContext(cmsdigcx
->digobjs
[i
]);
284 free(cmsdigcx
->digobjs
[i
]);
293 assert(digestsp
!= NULL
);
294 assert(digestalgsp
!= NULL
);
296 mark
= PORT_ArenaMark (cmsdigcx
->poolp
);
298 /* Security check to prevent under-allocation */
299 if (cmsdigcx
->digcnt
>= (int)((INT_MAX
/(MAX_OF_3(sizeof(SECAlgorithmID
*),sizeof(SecAsn1Item
*),sizeof(SecAsn1Item
))))-1)) {
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
) {
310 for (i
= 0; i
< cmsdigcx
->digcnt
; i
++, digest
++) {
312 SECOidTag hash_alg
= SECOID_GetAlgorithmTag(cmsdigcx
->digestalgs
[i
]);
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;
325 digobj
= cmsdigcx
->digobjs
[i
];
328 digest
->Data
= (unsigned char*)PORT_ArenaAlloc(cmsdigcx
->poolp
, diglength
);
329 if (digest
->Data
== NULL
)
331 digest
->Length
= diglength
;
333 CSSM_DigestDataFinal(digobj
, digest
);
334 CSSM_DeleteContext(digobj
);
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;
348 digestalgs
[i
] = cmsdigcx
->digestalgs
[i
];
357 digestalgs
[i
] = NULL
;
359 *digestalgsp
= digestalgs
;
365 if (rv
== SECSuccess
)
366 PORT_ArenaUnmark(cmsdigcx
->poolp
, mark
);
368 PORT_ArenaRelease(cmsdigcx
->poolp
, mark
);
371 /* Set things up so SecCmsDigestContextDestroy won't call CSSM_DeleteContext again. */
372 cmsdigcx
->digcnt
= 0;
378 * SecCmsDigestContextFinishSingle - same as SecCmsDigestContextFinishMultiple,
379 * but for one digest.
382 SecCmsDigestContextFinishSingle(SecCmsDigestContextRef cmsdigcx
,
383 SecAsn1Item
* digest
)
385 OSStatus rv
= SECFailure
;
389 /* get the digests into arena, then copy the first digest into poolp */
390 if (SecCmsDigestContextFinishMultiple(cmsdigcx
, &ap
, &dp
) != SECSuccess
)
393 /* Return the first element in the digest array. */