]>
Commit | Line | Data |
---|---|---|
d8f41ccd 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 message methods. | |
36 | */ | |
37 | ||
38 | #include <Security/SecCmsMessage.h> | |
39 | ||
40 | #include <Security/SecCmsContentInfo.h> | |
41 | #include <Security/SecCmsSignedData.h> | |
42 | ||
43 | #include "cmslocal.h" | |
44 | ||
45 | #include "secitem.h" | |
46 | #include "secoid.h" | |
47 | ||
48 | #include <security_asn1/secasn1.h> | |
49 | #include <security_asn1/secerr.h> | |
50 | ||
51 | /* | |
52 | * SecCmsMessageCreate - create a CMS message object | |
53 | * | |
54 | * "poolp" - arena to allocate memory from, or NULL if new arena should be created | |
55 | */ | |
56 | SecCmsMessageRef | |
57 | SecCmsMessageCreate(SecArenaPoolRef pool) | |
58 | { | |
59 | PLArenaPool *poolp = (PLArenaPool *)pool; | |
60 | void *mark = NULL; | |
6b200bc3 | 61 | SecCmsMessageRef cmsg = NULL; |
d8f41ccd A |
62 | Boolean poolp_is_ours = PR_FALSE; |
63 | ||
64 | if (poolp == NULL) { | |
65 | poolp = PORT_NewArena (1024); /* XXX what is right value? */ | |
66 | if (poolp == NULL) | |
67 | return NULL; | |
68 | poolp_is_ours = PR_TRUE; | |
69 | } | |
70 | ||
71 | if (!poolp_is_ours) | |
72 | mark = PORT_ArenaMark(poolp); | |
73 | ||
74 | cmsg = (SecCmsMessageRef)PORT_ArenaZAlloc (poolp, sizeof(SecCmsMessage)); | |
75 | if (cmsg == NULL) { | |
76 | if (!poolp_is_ours) { | |
77 | if (mark) { | |
78 | PORT_ArenaRelease(poolp, mark); | |
79 | } | |
80 | } else | |
81 | PORT_FreeArena(poolp, PR_FALSE); | |
82 | return NULL; | |
83 | } | |
84 | ||
85 | cmsg->poolp = poolp; | |
86 | cmsg->poolp_is_ours = poolp_is_ours; | |
87 | cmsg->refCount = 1; | |
88 | ||
89 | if (mark) | |
90 | PORT_ArenaUnmark(poolp, mark); | |
91 | ||
92 | return cmsg; | |
93 | } | |
94 | ||
95 | /* | |
96 | * SecCmsMessageSetEncodingParams - set up a CMS message object for encoding or decoding | |
97 | * | |
98 | * "cmsg" - message object | |
99 | * "pwfn", pwfn_arg" - callback function for getting token password | |
100 | * "decrypt_key_cb", "decrypt_key_cb_arg" - callback function for getting bulk key for encryptedData | |
101 | * "detached_digestalgs", "detached_digests" - digests from detached content | |
102 | */ | |
103 | void | |
104 | SecCmsMessageSetEncodingParams(SecCmsMessageRef cmsg, | |
105 | PK11PasswordFunc pwfn, void *pwfn_arg, | |
106 | SecCmsGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg, | |
107 | SECAlgorithmID **detached_digestalgs, CSSM_DATA_PTR *detached_digests) | |
108 | { | |
109 | #if 0 | |
110 | // @@@ Deal with password stuff. | |
111 | if (pwfn) | |
112 | PK11_SetPasswordFunc(pwfn); | |
113 | #endif | |
114 | cmsg->pwfn_arg = pwfn_arg; | |
115 | cmsg->decrypt_key_cb = decrypt_key_cb; | |
116 | cmsg->decrypt_key_cb_arg = decrypt_key_cb_arg; | |
117 | cmsg->detached_digestalgs = detached_digestalgs; | |
118 | cmsg->detached_digests = detached_digests; | |
119 | } | |
120 | ||
121 | /* | |
122 | * SecCmsMessageDestroy - destroy a CMS message and all of its sub-pieces. | |
123 | */ | |
124 | void | |
125 | SecCmsMessageDestroy(SecCmsMessageRef cmsg) | |
126 | { | |
127 | PORT_Assert (cmsg->refCount > 0); | |
128 | if (cmsg->refCount <= 0) /* oops */ | |
129 | return; | |
130 | ||
131 | cmsg->refCount--; /* thread safety? */ | |
132 | if (cmsg->refCount > 0) | |
133 | return; | |
134 | ||
135 | SecCmsContentInfoDestroy(&(cmsg->contentInfo)); | |
136 | ||
137 | /* if poolp is not NULL, cmsg is the owner of its arena */ | |
6b200bc3 A |
138 | if (cmsg->poolp_is_ours && cmsg->poolp) { |
139 | PORT_FreeArena (cmsg->poolp, PR_TRUE); | |
fa7225c8 | 140 | } |
d8f41ccd A |
141 | } |
142 | ||
143 | /* | |
144 | * SecCmsMessageCopy - return a copy of the given message. | |
145 | * | |
146 | * The copy may be virtual or may be real -- either way, the result needs | |
147 | * to be passed to SecCmsMessageDestroy later (as does the original). | |
148 | */ | |
149 | SecCmsMessageRef | |
150 | SecCmsMessageCopy(SecCmsMessageRef cmsg) | |
151 | { | |
152 | if (cmsg == NULL) | |
153 | return NULL; | |
154 | ||
155 | PORT_Assert (cmsg->refCount > 0); | |
156 | ||
157 | cmsg->refCount++; /* XXX chrisk thread safety? */ | |
158 | return cmsg; | |
159 | } | |
160 | ||
161 | /* | |
162 | * SecCmsMessageGetArena - return a pointer to the message's arena pool | |
163 | */ | |
164 | SecArenaPoolRef | |
165 | SecCmsMessageGetArena(SecCmsMessageRef cmsg) | |
166 | { | |
167 | return (SecArenaPoolRef)cmsg->poolp; | |
168 | } | |
169 | ||
170 | /* | |
171 | * SecCmsMessageGetContentInfo - return a pointer to the top level contentInfo | |
172 | */ | |
173 | SecCmsContentInfoRef | |
174 | SecCmsMessageGetContentInfo(SecCmsMessageRef cmsg) | |
175 | { | |
176 | return &(cmsg->contentInfo); | |
177 | } | |
178 | ||
179 | /* | |
180 | * Return a pointer to the actual content. | |
181 | * In the case of those types which are encrypted, this returns the *plain* content. | |
182 | * In case of nested contentInfos, this descends and retrieves the innermost content. | |
183 | */ | |
184 | CSSM_DATA_PTR | |
185 | SecCmsMessageGetContent(SecCmsMessageRef cmsg) | |
186 | { | |
187 | /* this is a shortcut */ | |
188 | SecCmsContentInfoRef cinfo = SecCmsMessageGetContentInfo(cmsg); | |
189 | CSSM_DATA_PTR pItem = SecCmsContentInfoGetInnerContent(cinfo); | |
190 | return pItem; | |
191 | } | |
192 | ||
193 | /* | |
194 | * SecCmsMessageContentLevelCount - count number of levels of CMS content objects in this message | |
195 | * | |
196 | * CMS data content objects do not count. | |
197 | */ | |
198 | int | |
199 | SecCmsMessageContentLevelCount(SecCmsMessageRef cmsg) | |
200 | { | |
201 | int count = 0; | |
202 | SecCmsContentInfoRef cinfo; | |
203 | ||
204 | /* walk down the chain of contentinfos */ | |
205 | for (cinfo = &(cmsg->contentInfo); cinfo != NULL; ) { | |
206 | count++; | |
207 | cinfo = SecCmsContentInfoGetChildContentInfo(cinfo); | |
208 | } | |
209 | return count; | |
210 | } | |
211 | ||
212 | /* | |
213 | * SecCmsMessageContentLevel - find content level #n | |
214 | * | |
215 | * CMS data content objects do not count. | |
216 | */ | |
217 | SecCmsContentInfoRef | |
218 | SecCmsMessageContentLevel(SecCmsMessageRef cmsg, int n) | |
219 | { | |
220 | int count = 0; | |
221 | SecCmsContentInfoRef cinfo; | |
222 | ||
223 | /* walk down the chain of contentinfos */ | |
224 | for (cinfo = &(cmsg->contentInfo); cinfo != NULL && count < n; cinfo = SecCmsContentInfoGetChildContentInfo(cinfo)) { | |
225 | count++; | |
226 | } | |
227 | ||
228 | return cinfo; | |
229 | } | |
230 | ||
231 | /* | |
232 | * SecCmsMessageContainsCertsOrCrls - see if message contains certs along the way | |
233 | */ | |
234 | Boolean | |
235 | SecCmsMessageContainsCertsOrCrls(SecCmsMessageRef cmsg) | |
236 | { | |
237 | SecCmsContentInfoRef cinfo; | |
238 | ||
239 | /* descend into CMS message */ | |
240 | for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = SecCmsContentInfoGetChildContentInfo(cinfo)) { | |
241 | if (SecCmsContentInfoGetContentTypeTag(cinfo) != SEC_OID_PKCS7_SIGNED_DATA) | |
242 | continue; /* next level */ | |
243 | ||
244 | if (SecCmsSignedDataContainsCertsOrCrls(cinfo->content.signedData)) | |
245 | return PR_TRUE; | |
246 | } | |
247 | return PR_FALSE; | |
248 | } | |
249 | ||
250 | /* | |
251 | * SecCmsMessageIsEncrypted - see if message contains a encrypted submessage | |
252 | */ | |
253 | Boolean | |
254 | SecCmsMessageIsEncrypted(SecCmsMessageRef cmsg) | |
255 | { | |
256 | SecCmsContentInfoRef cinfo; | |
257 | ||
258 | /* walk down the chain of contentinfos */ | |
259 | for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = SecCmsContentInfoGetChildContentInfo(cinfo)) | |
260 | { | |
261 | switch (SecCmsContentInfoGetContentTypeTag(cinfo)) { | |
262 | case SEC_OID_PKCS7_ENVELOPED_DATA: | |
263 | case SEC_OID_PKCS7_ENCRYPTED_DATA: | |
264 | return PR_TRUE; | |
265 | default: | |
266 | break; | |
267 | } | |
268 | } | |
269 | return PR_FALSE; | |
270 | } | |
271 | ||
272 | /* | |
273 | * SecCmsMessageIsSigned - see if message contains a signed submessage | |
274 | * | |
275 | * If the CMS message has a SignedData with a signature (not just a SignedData) | |
276 | * return true; false otherwise. This can/should be called before calling | |
277 | * VerifySignature, which will always indicate failure if no signature is | |
278 | * present, but that does not mean there even was a signature! | |
279 | * Note that the content itself can be empty (detached content was sent | |
280 | * another way); it is the presence of the signature that matters. | |
281 | */ | |
282 | Boolean | |
283 | SecCmsMessageIsSigned(SecCmsMessageRef cmsg) | |
284 | { | |
285 | SecCmsContentInfoRef cinfo; | |
286 | ||
287 | /* walk down the chain of contentinfos */ | |
288 | for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = SecCmsContentInfoGetChildContentInfo(cinfo)) | |
289 | { | |
290 | switch (SecCmsContentInfoGetContentTypeTag(cinfo)) { | |
291 | case SEC_OID_PKCS7_SIGNED_DATA: | |
292 | if (!SecCmsArrayIsEmpty((void **)cinfo->content.signedData->signerInfos)) | |
293 | return PR_TRUE; | |
294 | break; | |
295 | default: | |
296 | break; | |
297 | } | |
298 | } | |
299 | return PR_FALSE; | |
300 | } | |
301 | ||
302 | /* | |
303 | * SecCmsMessageIsContentEmpty - see if content is empty | |
304 | * | |
305 | * returns PR_TRUE is innermost content length is < minLen | |
306 | * XXX need the encrypted content length (why?) | |
307 | */ | |
308 | Boolean | |
309 | SecCmsMessageIsContentEmpty(SecCmsMessageRef cmsg, unsigned int minLen) | |
310 | { | |
311 | CSSM_DATA_PTR item = NULL; | |
312 | ||
313 | if (cmsg == NULL) | |
314 | return PR_TRUE; | |
315 | ||
316 | item = SecCmsContentInfoGetContent(SecCmsMessageGetContentInfo(cmsg)); | |
317 | ||
318 | if (!item) { | |
319 | return PR_TRUE; | |
320 | } else if(item->Length <= minLen) { | |
321 | return PR_TRUE; | |
322 | } | |
323 | ||
324 | return PR_FALSE; | |
325 | } | |
326 | ||
327 | /* | |
328 | * SecCmsMessageContainsTSTInfo - see if message contains a TimeStamping info block | |
329 | */ | |
330 | Boolean | |
331 | SecCmsMessageContainsTSTInfo(SecCmsMessageRef cmsg) | |
332 | { | |
333 | SecCmsContentInfoRef cinfo; | |
334 | ||
335 | /* walk down the chain of contentinfos */ | |
336 | for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = SecCmsContentInfoGetChildContentInfo(cinfo)) | |
337 | { | |
338 | switch (SecCmsContentInfoGetContentTypeTag(cinfo)) | |
339 | { | |
340 | case SEC_OID_PKCS9_ID_CT_TSTInfo: | |
341 | // TSTInfo is in cinfo->rawContent->Data | |
342 | return PR_TRUE; | |
343 | default: | |
344 | break; | |
345 | } | |
346 | } | |
347 | return PR_FALSE; | |
348 | } | |
349 | ||
350 | void | |
351 | SecCmsMessageSetTSACallback(SecCmsMessageRef cmsg, SecCmsTSACallback tsaCallback) | |
352 | { | |
353 | if (cmsg) | |
354 | cmsg->tsaCallback = tsaCallback; | |
355 | } | |
356 | ||
357 | void | |
358 | SecCmsMessageSetTSAContext(SecCmsMessageRef cmsg, const void *tsaContext) //CFTypeRef | |
359 | { | |
360 | if (cmsg) | |
361 | cmsg->tsaContext = tsaContext; | |
362 | } | |
363 |