]> git.saurik.com Git - apple/security.git/blame - libsecurity_smime/lib/cmsdigest.c
Security-55179.13.tar.gz
[apple/security.git] / libsecurity_smime / lib / cmsdigest.c
CommitLineData
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
46
47struct 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 */
57SecCmsDigestContextRef
58SecCmsDigestContextStartMultiple(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
103loser:
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 */
115SecCmsDigestContextRef
116SecCmsDigestContextStartSingle(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 */
127void
128SecCmsDigestContextUpdate(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 */
144void
145SecCmsDigestContextCancel(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 */
158OSStatus
159SecCmsDigestContextFinishMultiple(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
216loser:
217 if (rv == SECSuccess)
218 PORT_ArenaUnmark(poolp, mark);
219 else
220 PORT_ArenaRelease(poolp, mark);
221
222cleanup:
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 */
235OSStatus
236SecCmsDigestContextFinishSingle(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
256loser:
257 if (arena)
258 PORT_FreeArena(arena, PR_FALSE);
259
260 return rv;
261}