]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/cmsdigest.c
df9d463fa85a25787978cf6bf8271c33c30b6e79
[apple/security.git] / libsecurity_smime / lib / cmsdigest.c
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 */
37
38 #include "cmslocal.h"
39
40 #include "secitem.h"
41 #include "secoid.h"
42
43 #include <security_asn1/secerr.h>
44 #include <Security/cssmapi.h>
45
46
47 struct SecCmsDigestContextStr {
48 Boolean saw_contents;
49 int digcnt;
50 CSSM_CC_HANDLE * digobjs;
51 };
52
53 /*
54 * SecCmsDigestContextStartMultiple - start digest calculation using all the
55 * digest algorithms in "digestalgs" in parallel.
56 */
57 SecCmsDigestContextRef
58 SecCmsDigestContextStartMultiple(SECAlgorithmID **digestalgs)
59 {
60 SecCmsDigestContextRef cmsdigcx;
61 CSSM_CC_HANDLE digobj;
62 int digcnt;
63 int i;
64
65 digcnt = (digestalgs == NULL) ? 0 : SecCmsArrayCount((void **)digestalgs);
66
67 cmsdigcx = (SecCmsDigestContextRef)PORT_Alloc(sizeof(struct SecCmsDigestContextStr));
68 if (cmsdigcx == NULL)
69 return NULL;
70
71 if (digcnt > 0) {
72 cmsdigcx->digobjs = (CSSM_CC_HANDLE *)PORT_Alloc(digcnt * sizeof(CSSM_CC_HANDLE));
73 if (cmsdigcx->digobjs == NULL)
74 goto loser;
75 }
76
77 cmsdigcx->digcnt = 0;
78
79 /*
80 * Create a digest object context for each algorithm.
81 */
82 for (i = 0; i < digcnt; i++) {
83 digobj = SecCmsUtilGetHashObjByAlgID(digestalgs[i]);
84 /*
85 * Skip any algorithm we do not even recognize; obviously,
86 * this could be a problem, but if it is critical then the
87 * result will just be that the signature does not verify.
88 * We do not necessarily want to error out here, because
89 * the particular algorithm may not actually be important,
90 * but we cannot know that until later.
91 */
92 if (digobj)
93 CSSM_DigestDataInit(digobj);
94
95 cmsdigcx->digobjs[cmsdigcx->digcnt] = digobj;
96 cmsdigcx->digcnt++;
97 }
98
99 cmsdigcx->saw_contents = PR_FALSE;
100
101 return cmsdigcx;
102
103 loser:
104 if (cmsdigcx) {
105 if (cmsdigcx->digobjs)
106 PORT_Free(cmsdigcx->digobjs);
107 }
108 return NULL;
109 }
110
111 /*
112 * SecCmsDigestContextStartSingle - same as SecCmsDigestContextStartMultiple, but
113 * only one algorithm.
114 */
115 SecCmsDigestContextRef
116 SecCmsDigestContextStartSingle(SECAlgorithmID *digestalg)
117 {
118 SECAlgorithmID *digestalgs[] = { NULL, NULL }; /* fake array */
119
120 digestalgs[0] = digestalg;
121 return SecCmsDigestContextStartMultiple(digestalgs);
122 }
123
124 /*
125 * SecCmsDigestContextUpdate - feed more data into the digest machine
126 */
127 void
128 SecCmsDigestContextUpdate(SecCmsDigestContextRef cmsdigcx, const unsigned char *data, size_t len)
129 {
130 CSSM_DATA dataBuf;
131 int i;
132
133 dataBuf.Length = len;
134 dataBuf.Data = (uint8 *)data;
135 cmsdigcx->saw_contents = PR_TRUE;
136 for (i = 0; i < cmsdigcx->digcnt; i++)
137 if (cmsdigcx->digobjs[i])
138 CSSM_DigestDataUpdate(cmsdigcx->digobjs[i], &dataBuf, 1);
139 }
140
141 /*
142 * SecCmsDigestContextCancel - cancel digesting operation
143 */
144 void
145 SecCmsDigestContextCancel(SecCmsDigestContextRef cmsdigcx)
146 {
147 int i;
148
149 for (i = 0; i < cmsdigcx->digcnt; i++)
150 if (cmsdigcx->digobjs[i])
151 CSSM_DeleteContext(cmsdigcx->digobjs[i]);
152 }
153
154 /*
155 * SecCmsDigestContextFinishMultiple - finish the digests and put them
156 * into an array of CSSM_DATAs (allocated on poolp)
157 */
158 OSStatus
159 SecCmsDigestContextFinishMultiple(SecCmsDigestContextRef cmsdigcx, PLArenaPool *poolp,
160 CSSM_DATA_PTR **digestsp)
161 {
162 CSSM_CC_HANDLE digobj;
163 CSSM_DATA_PTR *digests, digest;
164 int i;
165 void *mark;
166 OSStatus rv = SECFailure;
167
168 /* no contents? do not update digests */
169 if (digestsp == NULL || !cmsdigcx->saw_contents) {
170 for (i = 0; i < cmsdigcx->digcnt; i++)
171 if (cmsdigcx->digobjs[i])
172 CSSM_DeleteContext(cmsdigcx->digobjs[i]);
173 rv = SECSuccess;
174 if (digestsp)
175 *digestsp = NULL;
176 goto cleanup;
177 }
178
179 mark = PORT_ArenaMark (poolp);
180
181 /* allocate digest array & CSSM_DATAs on arena */
182 digests = (CSSM_DATA_PTR *)PORT_ArenaAlloc(poolp, (cmsdigcx->digcnt+1) * sizeof(CSSM_DATA_PTR));
183 digest = (CSSM_DATA_PTR)PORT_ArenaZAlloc(poolp, cmsdigcx->digcnt * sizeof(CSSM_DATA));
184 if (digests == NULL || digest == NULL) {
185 goto loser;
186 }
187
188 for (i = 0; i < cmsdigcx->digcnt; i++, digest++) {
189 digobj = cmsdigcx->digobjs[i];
190 CSSM_QUERY_SIZE_DATA dataSize;
191 CSSM_QuerySize(digobj, CSSM_FALSE, 1, &dataSize);
192 int diglength = dataSize.SizeOutputBlock;
193
194 if (digobj)
195 {
196 digest->Data = (unsigned char*)PORT_ArenaAlloc(poolp, diglength);
197 if (digest->Data == NULL)
198 goto loser;
199 digest->Length = diglength;
200 CSSM_DigestDataFinal(digobj, digest);
201 CSSM_DeleteContext(digobj);
202 }
203 else
204 {
205 digest->Data = NULL;
206 digest->Length = 0;
207 }
208
209 digests[i] = digest;
210 }
211 digests[i] = NULL;
212 *digestsp = digests;
213
214 rv = SECSuccess;
215
216 loser:
217 if (rv == SECSuccess)
218 PORT_ArenaUnmark(poolp, mark);
219 else
220 PORT_ArenaRelease(poolp, mark);
221
222 cleanup:
223 if (cmsdigcx->digcnt > 0) {
224 PORT_Free(cmsdigcx->digobjs);
225 }
226 PORT_Free(cmsdigcx);
227
228 return rv;
229 }
230
231 /*
232 * SecCmsDigestContextFinishSingle - same as SecCmsDigestContextFinishMultiple,
233 * but for one digest.
234 */
235 OSStatus
236 SecCmsDigestContextFinishSingle(SecCmsDigestContextRef cmsdigcx, SecArenaPoolRef poolp,
237 CSSM_DATA_PTR digest)
238 {
239 OSStatus rv = SECFailure;
240 CSSM_DATA_PTR *dp;
241 PLArenaPool *arena = NULL;
242
243 if ((arena = PORT_NewArena(1024)) == NULL)
244 goto loser;
245
246 /* get the digests into arena, then copy the first digest into poolp */
247 if (SecCmsDigestContextFinishMultiple(cmsdigcx, arena, &dp) != SECSuccess)
248 goto loser;
249
250 /* now copy it into poolp */
251 if (SECITEM_CopyItem((PLArenaPool *)poolp, digest, dp[0]) != SECSuccess)
252 goto loser;
253
254 rv = SECSuccess;
255
256 loser:
257 if (arena)
258 PORT_FreeArena(arena, PR_FALSE);
259
260 return rv;
261 }