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