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