]> git.saurik.com Git - apple/security.git/blame - libsecurity_smime/lib/cmscinfo.c
Security-58286.41.2.tar.gz
[apple/security.git] / libsecurity_smime / lib / cmscinfo.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 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"
d8f41ccd 50#include "SecAsn1Item.h"
b1ab9ed8
A
51
52#include <security_asn1/secerr.h>
d8f41ccd 53#include <security_asn1/secport.h>
b1ab9ed8 54
d8f41ccd 55#include <Security/SecBase.h>
b1ab9ed8
A
56
57/*
58 * SecCmsContentInfoDestroy - destroy a CMS contentInfo and all of its sub-pieces.
59 */
60void
61SecCmsContentInfoDestroy(SecCmsContentInfoRef cinfo)
62{
63 SECOidTag kind;
64
fa7225c8
A
65 if(!cinfo) return;
66
b1ab9ed8
A
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 */
107SecCmsContentInfoRef
108SecCmsContentInfoGetChildContentInfo(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:
b1ab9ed8
A
131 default:
132 break;
133 }
134 return (ptr ? ccinfo : NULL);
135}
136
137/*
138 * SecCmsContentInfoSetContent - set content type & content
139 */
140OSStatus
d8f41ccd 141SecCmsContentInfoSetContent(SecCmsContentInfoRef cinfo, SECOidTag type, void *ptr)
b1ab9ed8
A
142{
143 OSStatus rv;
144
145 cinfo->contentTypeTag = SECOID_FindOIDByTag(type);
146 if (cinfo->contentTypeTag == NULL)
d8f41ccd 147 return errSecParam;
b1ab9ed8
A
148
149 /* do not copy the oid, just create a reference */
d8f41ccd 150 rv = SECITEM_CopyItem (cinfo->cmsg->poolp, &(cinfo->contentType), &(cinfo->contentTypeTag->oid));
b1ab9ed8 151 if (rv != SECSuccess)
d8f41ccd 152 return errSecAllocate;
b1ab9ed8
A
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 */
d8f41ccd 160 cinfo->rawContent = SECITEM_AllocItem(cinfo->cmsg->poolp, NULL, 1);
b1ab9ed8
A
161 if (cinfo->rawContent == NULL) {
162 PORT_SetError(SEC_ERROR_NO_MEMORY);
d8f41ccd 163 return errSecAllocate;
b1ab9ed8
A
164 }
165 }
166
d8f41ccd 167 return errSecSuccess;
b1ab9ed8
A
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 */
178OSStatus
d8f41ccd 179SecCmsContentInfoSetContentData(SecCmsContentInfoRef cinfo, CFDataRef dataRef, Boolean detached)
b1ab9ed8 180{
d8f41ccd
A
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)
b1ab9ed8
A
196 return PORT_GetError();
197 cinfo->rawContent = (detached) ?
198 NULL : (data) ?
d8f41ccd
A
199 data : SECITEM_AllocItem(cinfo->cmsg->poolp, NULL, 1);
200 return errSecSuccess;
b1ab9ed8
A
201}
202
203OSStatus
d8f41ccd 204SecCmsContentInfoSetContentSignedData(SecCmsContentInfoRef cinfo, SecCmsSignedDataRef sigd)
b1ab9ed8 205{
d8f41ccd 206 return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_SIGNED_DATA, (void *)sigd);
b1ab9ed8
A
207}
208
209OSStatus
d8f41ccd 210SecCmsContentInfoSetContentEnvelopedData(SecCmsContentInfoRef cinfo, SecCmsEnvelopedDataRef envd)
b1ab9ed8 211{
d8f41ccd 212 return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_ENVELOPED_DATA, (void *)envd);
b1ab9ed8
A
213}
214
215OSStatus
d8f41ccd 216SecCmsContentInfoSetContentDigestedData(SecCmsContentInfoRef cinfo, SecCmsDigestedDataRef digd)
b1ab9ed8 217{
d8f41ccd 218 return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DIGESTED_DATA, (void *)digd);
b1ab9ed8
A
219}
220
221OSStatus
d8f41ccd 222SecCmsContentInfoSetContentEncryptedData(SecCmsContentInfoRef cinfo, SecCmsEncryptedDataRef encd)
b1ab9ed8 223{
d8f41ccd 224 return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_ENCRYPTED_DATA, (void *)encd);
b1ab9ed8
A
225}
226
866f8763
A
227OSStatus
228SecCmsContentInfoSetContentOther(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
b1ab9ed8
A
256/*
257 * SecCmsContentInfoGetContent - get pointer to inner content
258 *
259 * needs to be casted...
260 */
261void *
262SecCmsContentInfoGetContent(SecCmsContentInfoRef cinfo)
263{
264 SECOidTag tag = (cinfo && cinfo->contentTypeTag)
265 ? cinfo->contentTypeTag->offset
d8f41ccd 266 : SEC_OID_UNKNOWN;
b1ab9ed8
A
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:
b1ab9ed8
A
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 */
d8f41ccd 284const SecAsn1Item *
b1ab9ed8
A
285SecCmsContentInfoGetInnerContent(SecCmsContentInfoRef cinfo)
286{
d8f41ccd 287 SecCmsContentInfoRef ccinfo;
b1ab9ed8 288 SECOidTag tag;
d8f41ccd 289 SecAsn1Item * pItem;
b1ab9ed8 290
d8f41ccd
A
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;
b1ab9ed8 311 }
d8f41ccd 312 return pItem;
b1ab9ed8
A
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 */
319SECOidTag
320SecCmsContentInfoGetContentTypeTag(SecCmsContentInfoRef cinfo)
321{
322 if (cinfo->contentTypeTag == NULL)
323 cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
324
325 if (cinfo->contentTypeTag == NULL)
d8f41ccd 326 return SEC_OID_UNKNOWN;
b1ab9ed8
A
327
328 return cinfo->contentTypeTag->offset;
329}
330
d8f41ccd 331SecAsn1Oid *
b1ab9ed8
A
332SecCmsContentInfoGetContentTypeOID(SecCmsContentInfoRef cinfo)
333{
334 if (cinfo->contentTypeTag == NULL)
335 cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
336
d8f41ccd
A
337 if (cinfo->contentTypeTag == NULL)
338 return NULL;
339
b1ab9ed8
A
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 */
347SECOidTag
348SecCmsContentInfoGetContentEncAlgTag(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 */
359SECAlgorithmID *
360SecCmsContentInfoGetContentEncAlg(SecCmsContentInfoRef cinfo)
361{
362 return &(cinfo->contentEncAlg);
363}
364
365OSStatus
d8f41ccd
A
366SecCmsContentInfoSetContentEncAlg(SecCmsContentInfoRef cinfo,
367 SECOidTag bulkalgtag, const SecAsn1Item *parameters, int keysize)
b1ab9ed8 368{
d8f41ccd 369 PLArenaPool *poolp = cinfo->cmsg->poolp;
b1ab9ed8
A
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
379OSStatus
d8f41ccd 380SecCmsContentInfoSetContentEncAlgID(SecCmsContentInfoRef cinfo,
b1ab9ed8
A
381 SECAlgorithmID *algid, int keysize)
382{
d8f41ccd 383 PLArenaPool *poolp = cinfo->cmsg->poolp;
b1ab9ed8
A
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
394void
395SecCmsContentInfoSetBulkKey(SecCmsContentInfoRef cinfo, SecSymmetricKeyRef bulkkey)
396{
866f8763
A
397#ifdef USE_CDSA_CRYPTO
398 const CSSM_KEY *cssmKey = NULL;
399#endif
fa7225c8 400 if (!bulkkey || !cinfo) return;
b1ab9ed8
A
401 cinfo->bulkkey = bulkkey;
402 CFRetain(cinfo->bulkkey);
866f8763
A
403#ifdef USE_CDSA_CRYPTO
404 SecKeyGetCSSMKey(cinfo->bulkkey, &cssmKey);
405 cinfo->keysize = cssmKey ? cssmKey->KeyHeader.LogicalKeySizeInBits : 0;
406#else
fa7225c8
A
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 }
866f8763 415#endif
b1ab9ed8
A
416}
417
418SecSymmetricKeyRef
419SecCmsContentInfoGetBulkKey(SecCmsContentInfoRef cinfo)
420{
421 if (cinfo->bulkkey == NULL)
422 return NULL;
423
424 CFRetain(cinfo->bulkkey);
425 return cinfo->bulkkey;
426}
427
428int
429SecCmsContentInfoGetBulkKeySize(SecCmsContentInfoRef cinfo)
430{
431 return cinfo->keysize;
432}