]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/cmscinfo.c
Security-59754.80.3.tar.gz
[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 OSStatus status = PORT_GetError();
197 PORT_SetError(0); // clean the thread since we've returned this error
198 return status;
199 }
200 cinfo->rawContent = (detached) ?
201 NULL : (data) ?
202 data : SECITEM_AllocItem(cinfo->cmsg->poolp, NULL, 1);
203 return errSecSuccess;
204 }
205
206 OSStatus
207 SecCmsContentInfoSetContentSignedData(SecCmsContentInfoRef cinfo, SecCmsSignedDataRef sigd)
208 {
209 return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_SIGNED_DATA, (void *)sigd);
210 }
211
212 OSStatus
213 SecCmsContentInfoSetContentEnvelopedData(SecCmsContentInfoRef cinfo, SecCmsEnvelopedDataRef envd)
214 {
215 return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_ENVELOPED_DATA, (void *)envd);
216 }
217
218 OSStatus
219 SecCmsContentInfoSetContentDigestedData(SecCmsContentInfoRef cinfo, SecCmsDigestedDataRef digd)
220 {
221 return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DIGESTED_DATA, (void *)digd);
222 }
223
224 OSStatus
225 SecCmsContentInfoSetContentEncryptedData(SecCmsContentInfoRef cinfo, SecCmsEncryptedDataRef encd)
226 {
227 return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_ENCRYPTED_DATA, (void *)encd);
228 }
229
230 OSStatus
231 SecCmsContentInfoSetContentOther(SecCmsContentInfoRef cinfo, SecAsn1Item *data, Boolean detached, const SecAsn1Oid *eContentType)
232 {
233 SECStatus srtn;
234 SECOidData *tmpOidData;
235
236 /* just like SecCmsContentInfoSetContentData, except override the contentType and
237 * contentTypeTag. This OID is for encoding... */
238 srtn = SECITEM_CopyItem (cinfo->cmsg->poolp, &(cinfo->contentType), eContentType);
239 if (srtn != SECSuccess) {
240 return errSecAllocate;
241 }
242
243 /* this serves up a contentTypeTag with an empty OID */
244 tmpOidData = SECOID_FindOIDByTag(SEC_OID_OTHER);
245 /* but that's const: cook up a new one we can write to */
246 cinfo->contentTypeTag = (SECOidData *)PORT_ArenaZAlloc(cinfo->cmsg->poolp, sizeof(SECOidData));
247 *cinfo->contentTypeTag = *tmpOidData;
248 /* now fill in the OID */
249 srtn = SECITEM_CopyItem (cinfo->cmsg->poolp, &(cinfo->contentTypeTag->oid), eContentType);
250 if (srtn != SECSuccess) {
251 return errSecAllocate;
252 }
253 cinfo->content.pointer = data;
254 cinfo->rawContent = (detached) ? NULL : (data) ?
255 data : SECITEM_AllocItem(cinfo->cmsg->poolp, NULL, 1);
256 return noErr;
257 }
258
259 /*
260 * SecCmsContentInfoGetContent - get pointer to inner content
261 *
262 * needs to be casted...
263 */
264 void *
265 SecCmsContentInfoGetContent(SecCmsContentInfoRef cinfo)
266 {
267 SECOidTag tag = (cinfo && cinfo->contentTypeTag)
268 ? cinfo->contentTypeTag->offset
269 : SEC_OID_UNKNOWN;
270 switch (tag) {
271 case SEC_OID_PKCS7_DATA:
272 case SEC_OID_PKCS7_SIGNED_DATA:
273 case SEC_OID_PKCS7_ENVELOPED_DATA:
274 case SEC_OID_PKCS7_DIGESTED_DATA:
275 case SEC_OID_PKCS7_ENCRYPTED_DATA:
276 return cinfo->content.pointer;
277 default:
278 return NULL;
279 }
280 }
281
282 /*
283 * SecCmsContentInfoGetInnerContent - get pointer to innermost content
284 *
285 * this is typically only called by SecCmsMessageGetContent()
286 */
287 const SecAsn1Item *
288 SecCmsContentInfoGetInnerContent(SecCmsContentInfoRef cinfo)
289 {
290 SecCmsContentInfoRef ccinfo;
291 SECOidTag tag;
292 SecAsn1Item * pItem;
293
294 tag = SecCmsContentInfoGetContentTypeTag(cinfo);
295 switch (tag) {
296 case SEC_OID_PKCS7_DATA:
297 /* end of recursion - every message has to have a data cinfo */
298 pItem = cinfo->content.data;
299 break;
300 case SEC_OID_PKCS7_DIGESTED_DATA:
301 case SEC_OID_PKCS7_ENCRYPTED_DATA:
302 case SEC_OID_PKCS7_ENVELOPED_DATA:
303 case SEC_OID_PKCS7_SIGNED_DATA:
304 ccinfo = SecCmsContentInfoGetChildContentInfo(cinfo);
305 if (ccinfo == NULL)
306 pItem = NULL;
307 else
308 pItem = SecCmsContentInfoGetContent(ccinfo);
309 break;
310 default:
311 PORT_Assert(0);
312 pItem = NULL;
313 break;
314 }
315 return pItem;
316 }
317
318 /*
319 * SecCmsContentInfoGetContentType{Tag,OID} - find out (saving pointer to lookup result
320 * for future reference) and return the inner content type.
321 */
322 SECOidTag
323 SecCmsContentInfoGetContentTypeTag(SecCmsContentInfoRef cinfo)
324 {
325 if (cinfo->contentTypeTag == NULL)
326 cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
327
328 if (cinfo->contentTypeTag == NULL)
329 return SEC_OID_UNKNOWN;
330
331 return cinfo->contentTypeTag->offset;
332 }
333
334 SecAsn1Oid *
335 SecCmsContentInfoGetContentTypeOID(SecCmsContentInfoRef cinfo)
336 {
337 if (cinfo->contentTypeTag == NULL)
338 cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
339
340 if (cinfo->contentTypeTag == NULL)
341 return NULL;
342
343 return &(cinfo->contentTypeTag->oid);
344 }
345
346 /*
347 * SecCmsContentInfoGetContentEncAlgTag - find out (saving pointer to lookup result
348 * for future reference) and return the content encryption algorithm tag.
349 */
350 SECOidTag
351 SecCmsContentInfoGetContentEncAlgTag(SecCmsContentInfoRef cinfo)
352 {
353 if (cinfo->contentEncAlgTag == SEC_OID_UNKNOWN)
354 cinfo->contentEncAlgTag = SECOID_GetAlgorithmTag(&(cinfo->contentEncAlg));
355
356 return cinfo->contentEncAlgTag;
357 }
358
359 /*
360 * SecCmsContentInfoGetContentEncAlg - find out and return the content encryption algorithm tag.
361 */
362 SECAlgorithmID *
363 SecCmsContentInfoGetContentEncAlg(SecCmsContentInfoRef cinfo)
364 {
365 return &(cinfo->contentEncAlg);
366 }
367
368 OSStatus
369 SecCmsContentInfoSetContentEncAlg(SecCmsContentInfoRef cinfo,
370 SECOidTag bulkalgtag, const SecAsn1Item *parameters, int keysize)
371 {
372 PLArenaPool *poolp = cinfo->cmsg->poolp;
373 OSStatus rv;
374
375 rv = SECOID_SetAlgorithmID(poolp, &(cinfo->contentEncAlg), bulkalgtag, parameters);
376 if (rv != SECSuccess)
377 return SECFailure;
378 cinfo->keysize = keysize;
379 return SECSuccess;
380 }
381
382 OSStatus
383 SecCmsContentInfoSetContentEncAlgID(SecCmsContentInfoRef cinfo,
384 SECAlgorithmID *algid, int keysize)
385 {
386 PLArenaPool *poolp = cinfo->cmsg->poolp;
387 OSStatus rv;
388
389 rv = SECOID_CopyAlgorithmID(poolp, &(cinfo->contentEncAlg), algid);
390 if (rv != SECSuccess)
391 return SECFailure;
392 if (keysize >= 0)
393 cinfo->keysize = keysize;
394 return SECSuccess;
395 }
396
397 void
398 SecCmsContentInfoSetBulkKey(SecCmsContentInfoRef cinfo, SecSymmetricKeyRef bulkkey)
399 {
400 #ifdef USE_CDSA_CRYPTO
401 const CSSM_KEY *cssmKey = NULL;
402 #endif
403 if (!bulkkey || !cinfo) return;
404 cinfo->bulkkey = bulkkey;
405 CFRetain(cinfo->bulkkey);
406 #ifdef USE_CDSA_CRYPTO
407 SecKeyGetCSSMKey(cinfo->bulkkey, &cssmKey);
408 cinfo->keysize = cssmKey ? cssmKey->KeyHeader.LogicalKeySizeInBits : 0;
409 #else
410 long long bulkKeySize = CFDataGetLength((CFDataRef)bulkkey) * 8;
411 if (bulkKeySize < INT_MAX) {
412 cinfo->keysize = (int)bulkKeySize;
413 } else {
414 CFRelease(cinfo->bulkkey);
415 cinfo->bulkkey = NULL;
416 cinfo->keysize = 0;
417 }
418 #endif
419 }
420
421 SecSymmetricKeyRef
422 SecCmsContentInfoGetBulkKey(SecCmsContentInfoRef cinfo)
423 {
424 if (cinfo->bulkkey == NULL)
425 return NULL;
426
427 CFRetain(cinfo->bulkkey);
428 return cinfo->bulkkey;
429 }
430
431 int
432 SecCmsContentInfoGetBulkKeySize(SecCmsContentInfoRef cinfo)
433 {
434 return cinfo->keysize;
435 }