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