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