]>
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" | |
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 | */ | |
60 | void | |
61 | SecCmsContentInfoDestroy(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 | */ | |
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: | |
b1ab9ed8 A |
131 | default: |
132 | break; | |
133 | } | |
134 | return (ptr ? ccinfo : NULL); | |
135 | } | |
136 | ||
137 | /* | |
138 | * SecCmsContentInfoSetContent - set content type & content | |
139 | */ | |
140 | OSStatus | |
d8f41ccd | 141 | SecCmsContentInfoSetContent(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 | */ | |
178 | OSStatus | |
d8f41ccd | 179 | SecCmsContentInfoSetContentData(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 | ||
203 | OSStatus | |
d8f41ccd | 204 | SecCmsContentInfoSetContentSignedData(SecCmsContentInfoRef cinfo, SecCmsSignedDataRef sigd) |
b1ab9ed8 | 205 | { |
d8f41ccd | 206 | return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_SIGNED_DATA, (void *)sigd); |
b1ab9ed8 A |
207 | } |
208 | ||
209 | OSStatus | |
d8f41ccd | 210 | SecCmsContentInfoSetContentEnvelopedData(SecCmsContentInfoRef cinfo, SecCmsEnvelopedDataRef envd) |
b1ab9ed8 | 211 | { |
d8f41ccd | 212 | return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_ENVELOPED_DATA, (void *)envd); |
b1ab9ed8 A |
213 | } |
214 | ||
215 | OSStatus | |
d8f41ccd | 216 | SecCmsContentInfoSetContentDigestedData(SecCmsContentInfoRef cinfo, SecCmsDigestedDataRef digd) |
b1ab9ed8 | 217 | { |
d8f41ccd | 218 | return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DIGESTED_DATA, (void *)digd); |
b1ab9ed8 A |
219 | } |
220 | ||
221 | OSStatus | |
d8f41ccd | 222 | SecCmsContentInfoSetContentEncryptedData(SecCmsContentInfoRef cinfo, SecCmsEncryptedDataRef encd) |
b1ab9ed8 | 223 | { |
d8f41ccd | 224 | return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_ENCRYPTED_DATA, (void *)encd); |
b1ab9ed8 A |
225 | } |
226 | ||
866f8763 A |
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 | ||
b1ab9ed8 A |
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 | |
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 | 284 | const SecAsn1Item * |
b1ab9ed8 A |
285 | SecCmsContentInfoGetInnerContent(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 | */ | |
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) | |
d8f41ccd | 326 | return SEC_OID_UNKNOWN; |
b1ab9ed8 A |
327 | |
328 | return cinfo->contentTypeTag->offset; | |
329 | } | |
330 | ||
d8f41ccd | 331 | SecAsn1Oid * |
b1ab9ed8 A |
332 | SecCmsContentInfoGetContentTypeOID(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 | */ | |
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 | |
d8f41ccd A |
366 | SecCmsContentInfoSetContentEncAlg(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 | ||
379 | OSStatus | |
d8f41ccd | 380 | SecCmsContentInfoSetContentEncAlgID(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 | ||
394 | void | |
395 | SecCmsContentInfoSetBulkKey(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 | ||
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 | } |