]>
Commit | Line | Data |
---|---|---|
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" | |
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 | } |