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