]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/cmsencdata.c
Security-59306.11.20.tar.gz
[apple/security.git] / libsecurity_smime / lib / cmsencdata.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 encryptedData methods.
36 */
37
38 #include <Security/SecCmsEncryptedData.h>
39
40 #include <Security/SecCmsContentInfo.h>
41
42 #include "cmslocal.h"
43
44 #include "SecAsn1Item.h"
45 #include "secoid.h"
46
47 #include <security_asn1/secasn1.h>
48 #include <security_asn1/secerr.h>
49 #include <security_asn1/secport.h>
50
51 /*
52 * SecCmsEncryptedDataCreate - create an empty encryptedData object.
53 *
54 * "algorithm" specifies the bulk encryption algorithm to use.
55 * "keysize" is the key size.
56 *
57 * An error results in a return value of NULL and an error set.
58 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
59 */
60 SecCmsEncryptedDataRef
61 SecCmsEncryptedDataCreate(SecCmsMessageRef cmsg, SECOidTag algorithm, int keysize)
62 {
63 void *mark;
64 SecCmsEncryptedDataRef encd;
65 PLArenaPool *poolp;
66 #if 0
67 SECAlgorithmID *pbe_algid;
68 #endif
69 OSStatus rv;
70
71 poolp = cmsg->poolp;
72
73 mark = PORT_ArenaMark(poolp);
74
75 encd = (SecCmsEncryptedDataRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsEncryptedData));
76 if (encd == NULL)
77 goto loser;
78
79 encd->contentInfo.cmsg = cmsg;
80
81 /* version is set in SecCmsEncryptedDataEncodeBeforeStart() */
82
83 switch (algorithm) {
84 /* XXX hmmm... hardcoded algorithms? */
85 case SEC_OID_AES_128_CBC:
86 case SEC_OID_AES_192_CBC:
87 case SEC_OID_AES_256_CBC:
88 case SEC_OID_RC2_CBC:
89 case SEC_OID_DES_EDE3_CBC:
90 case SEC_OID_DES_CBC:
91 rv = SecCmsContentInfoSetContentEncAlg(&(encd->contentInfo), algorithm, NULL, keysize);
92 break;
93 default:
94 /* Assume password-based-encryption. At least, try that. */
95 #if 1
96 // @@@ Fix me
97 rv = SECFailure;
98 break;
99 #else
100 pbe_algid = PK11_CreatePBEAlgorithmID(algorithm, 1, NULL);
101 if (pbe_algid == NULL) {
102 rv = SECFailure;
103 break;
104 }
105 rv = SecCmsContentInfoSetContentEncAlgID(&(encd->contentInfo), pbe_algid, keysize);
106 SECOID_DestroyAlgorithmID (pbe_algid, PR_TRUE);
107 break;
108 #endif
109 }
110 if (rv != SECSuccess)
111 goto loser;
112
113 PORT_ArenaUnmark(poolp, mark);
114 return encd;
115
116 loser:
117 PORT_ArenaRelease(poolp, mark);
118 return NULL;
119 }
120
121 /*
122 * SecCmsEncryptedDataDestroy - destroy an encryptedData object
123 */
124 void
125 SecCmsEncryptedDataDestroy(SecCmsEncryptedDataRef encd)
126 {
127 if (encd == NULL) {
128 return;
129 }
130 /* everything's in a pool, so don't worry about the storage */
131 SecCmsContentInfoDestroy(&(encd->contentInfo));
132 return;
133 }
134
135 /*
136 * SecCmsEncryptedDataGetContentInfo - return pointer to encryptedData object's contentInfo
137 */
138 SecCmsContentInfoRef
139 SecCmsEncryptedDataGetContentInfo(SecCmsEncryptedDataRef encd)
140 {
141 return &(encd->contentInfo);
142 }
143
144 /*
145 * SecCmsEncryptedDataEncodeBeforeStart - do all the necessary things to a EncryptedData
146 * before encoding begins.
147 *
148 * In particular:
149 * - set the correct version value.
150 * - get the encryption key
151 */
152 OSStatus
153 SecCmsEncryptedDataEncodeBeforeStart(SecCmsEncryptedDataRef encd)
154 {
155 int version;
156 SecSymmetricKeyRef bulkkey = NULL;
157 SecAsn1Item * dummy;
158 SecCmsContentInfoRef cinfo = &(encd->contentInfo);
159
160 if (SecCmsArrayIsEmpty((void **)encd->unprotectedAttr))
161 version = SEC_CMS_ENCRYPTED_DATA_VERSION;
162 else
163 version = SEC_CMS_ENCRYPTED_DATA_VERSION_UPATTR;
164
165 dummy = SEC_ASN1EncodeInteger (encd->contentInfo.cmsg->poolp, &(encd->version), version);
166 if (dummy == NULL)
167 return SECFailure;
168
169 /* now get content encryption key (bulk key) by using our cmsg callback */
170 if (encd->contentInfo.cmsg->decrypt_key_cb)
171 bulkkey = (*encd->contentInfo.cmsg->decrypt_key_cb)(encd->contentInfo.cmsg->decrypt_key_cb_arg,
172 SecCmsContentInfoGetContentEncAlg(cinfo));
173 if (bulkkey == NULL)
174 return SECFailure;
175
176 /* store the bulk key in the contentInfo so that the encoder can find it */
177 SecCmsContentInfoSetBulkKey(cinfo, bulkkey);
178 CFRelease(bulkkey); /* This assumes the decrypt_key_cb hands us a copy of the key --mb */
179
180 return SECSuccess;
181 }
182
183 /*
184 * SecCmsEncryptedDataEncodeBeforeData - set up encryption
185 */
186 OSStatus
187 SecCmsEncryptedDataEncodeBeforeData(SecCmsEncryptedDataRef encd)
188 {
189 SecCmsContentInfoRef cinfo;
190 SecSymmetricKeyRef bulkkey;
191 SECAlgorithmID *algid;
192
193 cinfo = &(encd->contentInfo);
194
195 /* find bulkkey and algorithm - must have been set by SecCmsEncryptedDataEncodeBeforeStart */
196 bulkkey = SecCmsContentInfoGetBulkKey(cinfo);
197 if (bulkkey == NULL)
198 return SECFailure;
199 algid = SecCmsContentInfoGetContentEncAlg(cinfo);
200 if (algid == NULL)
201 return SECFailure;
202
203 /* this may modify algid (with IVs generated in a token).
204 * it is therefore essential that algid is a pointer to the "real" contentEncAlg,
205 * not just to a copy */
206 cinfo->ciphcx = SecCmsCipherContextStartEncrypt(encd->contentInfo.cmsg->poolp, bulkkey, algid);
207 CFRelease(bulkkey);
208 if (cinfo->ciphcx == NULL)
209 return SECFailure;
210
211 return SECSuccess;
212 }
213
214 /*
215 * SecCmsEncryptedDataEncodeAfterData - finalize this encryptedData for encoding
216 */
217 OSStatus
218 SecCmsEncryptedDataEncodeAfterData(SecCmsEncryptedDataRef encd)
219 {
220 if (encd->contentInfo.ciphcx) {
221 SecCmsCipherContextDestroy(encd->contentInfo.ciphcx);
222 encd->contentInfo.ciphcx = NULL;
223 }
224
225 /* nothing to do after data */
226 return SECSuccess;
227 }
228
229
230 /*
231 * SecCmsEncryptedDataDecodeBeforeData - find bulk key & set up decryption
232 */
233 OSStatus
234 SecCmsEncryptedDataDecodeBeforeData(SecCmsEncryptedDataRef encd)
235 {
236 SecSymmetricKeyRef bulkkey = NULL;
237 SecCmsContentInfoRef cinfo;
238 SECAlgorithmID *bulkalg;
239 OSStatus rv = SECFailure;
240
241 cinfo = &(encd->contentInfo);
242
243 bulkalg = SecCmsContentInfoGetContentEncAlg(cinfo);
244
245 if (encd->contentInfo.cmsg->decrypt_key_cb == NULL) /* no callback? no key../ */
246 goto loser;
247
248 bulkkey = (*encd->contentInfo.cmsg->decrypt_key_cb)(encd->contentInfo.cmsg->decrypt_key_cb_arg, bulkalg);
249 if (bulkkey == NULL)
250 /* no success finding a bulk key */
251 goto loser;
252
253 SecCmsContentInfoSetBulkKey(cinfo, bulkkey);
254
255 cinfo->ciphcx = SecCmsCipherContextStartDecrypt(bulkkey, bulkalg);
256 if (cinfo->ciphcx == NULL)
257 goto loser; /* error has been set by SecCmsCipherContextStartDecrypt */
258
259 #if 1
260 // @@@ Not done yet
261 #else
262 /*
263 * HACK ALERT!!
264 * For PKCS5 Encryption Algorithms, the bulkkey is actually a different
265 * structure. Therefore, we need to set the bulkkey to the actual key
266 * prior to freeing it.
267 */
268 if (SEC_PKCS5IsAlgorithmPBEAlg(bulkalg)) {
269 SEC_PKCS5KeyAndPassword *keyPwd = (SEC_PKCS5KeyAndPassword *)bulkkey;
270 bulkkey = keyPwd->key;
271 }
272 #endif
273
274 /* we are done with (this) bulkkey now. */
275 CFRelease(bulkkey);
276
277 rv = SECSuccess;
278
279 loser:
280 return rv;
281 }
282
283 /*
284 * SecCmsEncryptedDataDecodeAfterData - finish decrypting this encryptedData's content
285 */
286 OSStatus
287 SecCmsEncryptedDataDecodeAfterData(SecCmsEncryptedDataRef encd)
288 {
289 if (encd->contentInfo.ciphcx) {
290 SecCmsCipherContextDestroy(encd->contentInfo.ciphcx);
291 encd->contentInfo.ciphcx = NULL;
292 }
293
294 return SECSuccess;
295 }
296
297 /*
298 * SecCmsEncryptedDataDecodeAfterEnd - finish decoding this encryptedData
299 */
300 OSStatus
301 SecCmsEncryptedDataDecodeAfterEnd(SecCmsEncryptedDataRef encd)
302 {
303 /* apply final touches */
304 return SECSuccess;
305 }