]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/cmscinfo.c
9a7ebaf1fb4d16bbe4dc552be2b4fabe442adc6c
[apple/security.git] / libsecurity_smime / lib / cmscinfo.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 contentInfo methods.
36 */
37
38 #include <Security/SecCmsContentInfo.h>
39
40 #include <Security/SecCmsDigestContext.h>
41 #include <Security/SecCmsDigestedData.h>
42 #include <Security/SecCmsEncryptedData.h>
43 #include <Security/SecCmsEnvelopedData.h>
44 #include <Security/SecCmsSignedData.h>
45
46 #include "cmslocal.h"
47
48 //#include "pk11func.h"
49 #include "secoid.h"
50 #include "SecAsn1Item.h"
51
52 #include <security_asn1/secerr.h>
53 #include <security_asn1/secport.h>
54
55 #include <Security/SecBase.h>
56
57 /*
58 * SecCmsContentInfoDestroy - destroy a CMS contentInfo and all of its sub-pieces.
59 */
60 void
61 SecCmsContentInfoDestroy(SecCmsContentInfoRef cinfo)
62 {
63 SECOidTag kind;
64
65 if(!cinfo) return;
66
67 kind = SecCmsContentInfoGetContentTypeTag(cinfo);
68 switch (kind) {
69 case SEC_OID_PKCS7_ENVELOPED_DATA:
70 SecCmsEnvelopedDataDestroy(cinfo->content.envelopedData);
71 break;
72 case SEC_OID_PKCS7_SIGNED_DATA:
73 SecCmsSignedDataDestroy(cinfo->content.signedData);
74 break;
75 case SEC_OID_PKCS7_ENCRYPTED_DATA:
76 SecCmsEncryptedDataDestroy(cinfo->content.encryptedData);
77 break;
78 case SEC_OID_PKCS7_DIGESTED_DATA:
79 SecCmsDigestedDataDestroy(cinfo->content.digestedData);
80 break;
81 default:
82 /* XXX Anything else that needs to be "manually" freed/destroyed? */
83 break;
84 }
85 if (cinfo->digcx) {
86 /* must destroy digest objects */
87 SecCmsDigestContextCancel(cinfo->digcx);
88 cinfo->digcx = NULL;
89 }
90 if (cinfo->bulkkey)
91 CFRelease(cinfo->bulkkey);
92 /* @@@ private key is only here as a workaround for 3401088. Note this *must* be released after bulkkey */
93 if (cinfo->privkey)
94 CFRelease(cinfo->privkey);
95
96 if (cinfo->ciphcx) {
97 SecCmsCipherContextDestroy(cinfo->ciphcx);
98 cinfo->ciphcx = NULL;
99 }
100
101 /* we live in a pool, so no need to worry about storage */
102 }
103
104 /*
105 * SecCmsContentInfoGetChildContentInfo - get content's contentInfo (if it exists)
106 */
107 SecCmsContentInfoRef
108 SecCmsContentInfoGetChildContentInfo(SecCmsContentInfoRef cinfo)
109 {
110 void *ptr = NULL;
111 SecCmsContentInfoRef ccinfo = NULL;
112 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(cinfo);
113 switch (tag) {
114 case SEC_OID_PKCS7_SIGNED_DATA:
115 ptr = (void *)cinfo->content.signedData;
116 ccinfo = &(cinfo->content.signedData->contentInfo);
117 break;
118 case SEC_OID_PKCS7_ENVELOPED_DATA:
119 ptr = (void *)cinfo->content.envelopedData;
120 ccinfo = &(cinfo->content.envelopedData->contentInfo);
121 break;
122 case SEC_OID_PKCS7_DIGESTED_DATA:
123 ptr = (void *)cinfo->content.digestedData;
124 ccinfo = &(cinfo->content.digestedData->contentInfo);
125 break;
126 case SEC_OID_PKCS7_ENCRYPTED_DATA:
127 ptr = (void *)cinfo->content.encryptedData;
128 ccinfo = &(cinfo->content.encryptedData->contentInfo);
129 break;
130 case SEC_OID_PKCS7_DATA:
131 default:
132 break;
133 }
134 return (ptr ? ccinfo : NULL);
135 }
136
137 /*
138 * SecCmsContentInfoSetContent - set content type & content
139 */
140 OSStatus
141 SecCmsContentInfoSetContent(SecCmsContentInfoRef cinfo, SECOidTag type, void *ptr)
142 {
143 OSStatus rv;
144
145 cinfo->contentTypeTag = SECOID_FindOIDByTag(type);
146 if (cinfo->contentTypeTag == NULL)
147 return errSecParam;
148
149 /* do not copy the oid, just create a reference */
150 rv = SECITEM_CopyItem (cinfo->cmsg->poolp, &(cinfo->contentType), &(cinfo->contentTypeTag->oid));
151 if (rv != SECSuccess)
152 return errSecAllocate;
153
154 cinfo->content.pointer = ptr;
155
156 if (type != SEC_OID_PKCS7_DATA) {
157 /* as we always have some inner data,
158 * we need to set it to something, just to fool the encoder enough to work on it
159 * and get us into nss_cms_encoder_notify at that point */
160 cinfo->rawContent = SECITEM_AllocItem(cinfo->cmsg->poolp, NULL, 1);
161 if (cinfo->rawContent == NULL) {
162 PORT_SetError(SEC_ERROR_NO_MEMORY);
163 return errSecAllocate;
164 }
165 }
166
167 return errSecSuccess;
168 }
169
170 /*
171 * SecCmsContentInfoSetContentXXXX - typesafe wrappers for SecCmsContentInfoSetContent
172 */
173
174 /*
175 * data == NULL -> pass in data via SecCmsEncoderUpdate
176 * data != NULL -> take this data
177 */
178 OSStatus
179 SecCmsContentInfoSetContentData(SecCmsContentInfoRef cinfo, CFDataRef dataRef, Boolean detached)
180 {
181 SecAsn1Item * data = NULL;
182 if (dataRef) {
183 /* @@@ Fixme CFRetain the passed in data rather than
184 always copying it for performance. */
185 data = PORT_ArenaAlloc(cinfo->cmsg->poolp, sizeof(SecAsn1Item));
186 data->Length = CFDataGetLength(dataRef);
187 if (data->Length) {
188 data->Data = PORT_ArenaAlloc(cinfo->cmsg->poolp, data->Length);
189 memcpy(data->Data, CFDataGetBytePtr(dataRef), data->Length);
190 }
191 else
192 data->Data = NULL;
193 }
194
195 if (SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, (void *)data) != SECSuccess)
196 return PORT_GetError();
197 cinfo->rawContent = (detached) ?
198 NULL : (data) ?
199 data : SECITEM_AllocItem(cinfo->cmsg->poolp, NULL, 1);
200 return errSecSuccess;
201 }
202
203 OSStatus
204 SecCmsContentInfoSetContentSignedData(SecCmsContentInfoRef cinfo, SecCmsSignedDataRef sigd)
205 {
206 return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_SIGNED_DATA, (void *)sigd);
207 }
208
209 OSStatus
210 SecCmsContentInfoSetContentEnvelopedData(SecCmsContentInfoRef cinfo, SecCmsEnvelopedDataRef envd)
211 {
212 return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_ENVELOPED_DATA, (void *)envd);
213 }
214
215 OSStatus
216 SecCmsContentInfoSetContentDigestedData(SecCmsContentInfoRef cinfo, SecCmsDigestedDataRef digd)
217 {
218 return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DIGESTED_DATA, (void *)digd);
219 }
220
221 OSStatus
222 SecCmsContentInfoSetContentEncryptedData(SecCmsContentInfoRef cinfo, SecCmsEncryptedDataRef encd)
223 {
224 return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_ENCRYPTED_DATA, (void *)encd);
225 }
226
227 /*
228 * SecCmsContentInfoGetContent - get pointer to inner content
229 *
230 * needs to be casted...
231 */
232 void *
233 SecCmsContentInfoGetContent(SecCmsContentInfoRef cinfo)
234 {
235 SECOidTag tag = (cinfo && cinfo->contentTypeTag)
236 ? cinfo->contentTypeTag->offset
237 : SEC_OID_UNKNOWN;
238 switch (tag) {
239 case SEC_OID_PKCS7_DATA:
240 case SEC_OID_PKCS7_SIGNED_DATA:
241 case SEC_OID_PKCS7_ENVELOPED_DATA:
242 case SEC_OID_PKCS7_DIGESTED_DATA:
243 case SEC_OID_PKCS7_ENCRYPTED_DATA:
244 return cinfo->content.pointer;
245 default:
246 return NULL;
247 }
248 }
249
250 /*
251 * SecCmsContentInfoGetInnerContent - get pointer to innermost content
252 *
253 * this is typically only called by SecCmsMessageGetContent()
254 */
255 const SecAsn1Item *
256 SecCmsContentInfoGetInnerContent(SecCmsContentInfoRef cinfo)
257 {
258 SecCmsContentInfoRef ccinfo;
259 SECOidTag tag;
260 SecAsn1Item * pItem;
261
262 tag = SecCmsContentInfoGetContentTypeTag(cinfo);
263 switch (tag) {
264 case SEC_OID_PKCS7_DATA:
265 /* end of recursion - every message has to have a data cinfo */
266 pItem = cinfo->content.data;
267 break;
268 case SEC_OID_PKCS7_DIGESTED_DATA:
269 case SEC_OID_PKCS7_ENCRYPTED_DATA:
270 case SEC_OID_PKCS7_ENVELOPED_DATA:
271 case SEC_OID_PKCS7_SIGNED_DATA:
272 ccinfo = SecCmsContentInfoGetChildContentInfo(cinfo);
273 if (ccinfo == NULL)
274 pItem = NULL;
275 else
276 pItem = SecCmsContentInfoGetContent(ccinfo);
277 break;
278 default:
279 PORT_Assert(0);
280 pItem = NULL;
281 break;
282 }
283 return pItem;
284 }
285
286 /*
287 * SecCmsContentInfoGetContentType{Tag,OID} - find out (saving pointer to lookup result
288 * for future reference) and return the inner content type.
289 */
290 SECOidTag
291 SecCmsContentInfoGetContentTypeTag(SecCmsContentInfoRef cinfo)
292 {
293 if (cinfo->contentTypeTag == NULL)
294 cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
295
296 if (cinfo->contentTypeTag == NULL)
297 return SEC_OID_UNKNOWN;
298
299 return cinfo->contentTypeTag->offset;
300 }
301
302 SecAsn1Oid *
303 SecCmsContentInfoGetContentTypeOID(SecCmsContentInfoRef cinfo)
304 {
305 if (cinfo->contentTypeTag == NULL)
306 cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
307
308 if (cinfo->contentTypeTag == NULL)
309 return NULL;
310
311 return &(cinfo->contentTypeTag->oid);
312 }
313
314 /*
315 * SecCmsContentInfoGetContentEncAlgTag - find out (saving pointer to lookup result
316 * for future reference) and return the content encryption algorithm tag.
317 */
318 SECOidTag
319 SecCmsContentInfoGetContentEncAlgTag(SecCmsContentInfoRef cinfo)
320 {
321 if (cinfo->contentEncAlgTag == SEC_OID_UNKNOWN)
322 cinfo->contentEncAlgTag = SECOID_GetAlgorithmTag(&(cinfo->contentEncAlg));
323
324 return cinfo->contentEncAlgTag;
325 }
326
327 /*
328 * SecCmsContentInfoGetContentEncAlg - find out and return the content encryption algorithm tag.
329 */
330 SECAlgorithmID *
331 SecCmsContentInfoGetContentEncAlg(SecCmsContentInfoRef cinfo)
332 {
333 return &(cinfo->contentEncAlg);
334 }
335
336 OSStatus
337 SecCmsContentInfoSetContentEncAlg(SecCmsContentInfoRef cinfo,
338 SECOidTag bulkalgtag, const SecAsn1Item *parameters, int keysize)
339 {
340 PLArenaPool *poolp = cinfo->cmsg->poolp;
341 OSStatus rv;
342
343 rv = SECOID_SetAlgorithmID(poolp, &(cinfo->contentEncAlg), bulkalgtag, parameters);
344 if (rv != SECSuccess)
345 return SECFailure;
346 cinfo->keysize = keysize;
347 return SECSuccess;
348 }
349
350 OSStatus
351 SecCmsContentInfoSetContentEncAlgID(SecCmsContentInfoRef cinfo,
352 SECAlgorithmID *algid, int keysize)
353 {
354 PLArenaPool *poolp = cinfo->cmsg->poolp;
355 OSStatus rv;
356
357 rv = SECOID_CopyAlgorithmID(poolp, &(cinfo->contentEncAlg), algid);
358 if (rv != SECSuccess)
359 return SECFailure;
360 if (keysize >= 0)
361 cinfo->keysize = keysize;
362 return SECSuccess;
363 }
364
365 void
366 SecCmsContentInfoSetBulkKey(SecCmsContentInfoRef cinfo, SecSymmetricKeyRef bulkkey)
367 {
368 if (!bulkkey || !cinfo) return;
369
370 cinfo->bulkkey = bulkkey;
371 CFRetain(cinfo->bulkkey);
372
373 long long bulkKeySize = CFDataGetLength((CFDataRef)bulkkey) * 8;
374 if (bulkKeySize < INT_MAX) {
375 cinfo->keysize = (int)bulkKeySize;
376 } else {
377 CFRelease(cinfo->bulkkey);
378 cinfo->bulkkey = NULL;
379 cinfo->keysize = 0;
380 }
381 }
382
383 SecSymmetricKeyRef
384 SecCmsContentInfoGetBulkKey(SecCmsContentInfoRef cinfo)
385 {
386 if (cinfo->bulkkey == NULL)
387 return NULL;
388
389 CFRetain(cinfo->bulkkey);
390 return cinfo->bulkkey;
391 }
392
393 int
394 SecCmsContentInfoGetBulkKeySize(SecCmsContentInfoRef cinfo)
395 {
396 return cinfo->keysize;
397 }