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/
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.
12 * The Original Code is the Netscape security libraries.
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
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
35 * CMS encryptedData methods.
38 #include <Security/SecCmsEncryptedData.h>
40 #include <Security/SecCmsContentInfo.h>
44 #include "SecAsn1Item.h"
47 #include <security_asn1/secasn1.h>
48 #include <security_asn1/secerr.h>
49 #include <security_asn1/secport.h>
52 * SecCmsEncryptedDataCreate - create an empty encryptedData object.
54 * "algorithm" specifies the bulk encryption algorithm to use.
55 * "keysize" is the key size.
57 * An error results in a return value of NULL and an error set.
58 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
60 SecCmsEncryptedDataRef
61 SecCmsEncryptedDataCreate(SecCmsMessageRef cmsg
, SECOidTag algorithm
, int keysize
)
64 SecCmsEncryptedDataRef encd
;
66 SECAlgorithmID
*pbe_algid
;
71 mark
= PORT_ArenaMark(poolp
);
73 encd
= (SecCmsEncryptedDataRef
)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsEncryptedData
));
77 encd
->contentInfo
.cmsg
= cmsg
;
79 /* version is set in SecCmsEncryptedDataEncodeBeforeStart() */
82 /* XXX hmmm... hardcoded algorithms? */
83 case SEC_OID_AES_128_CBC
:
84 case SEC_OID_AES_192_CBC
:
85 case SEC_OID_AES_256_CBC
:
87 case SEC_OID_DES_EDE3_CBC
:
89 rv
= SecCmsContentInfoSetContentEncAlg(&(encd
->contentInfo
), algorithm
, NULL
, keysize
);
92 /* Assume password-based-encryption. At least, try that. */
97 pbe_algid
= PK11_CreatePBEAlgorithmID(algorithm
, 1, NULL
);
99 if (pbe_algid
== NULL
) {
103 rv
= SecCmsContentInfoSetContentEncAlgID(&(encd
->contentInfo
), pbe_algid
, keysize
);
104 SECOID_DestroyAlgorithmID (pbe_algid
, PR_TRUE
);
107 if (rv
!= SECSuccess
)
110 PORT_ArenaUnmark(poolp
, mark
);
114 PORT_ArenaRelease(poolp
, mark
);
119 * SecCmsEncryptedDataDestroy - destroy an encryptedData object
122 SecCmsEncryptedDataDestroy(SecCmsEncryptedDataRef encd
)
124 /* everything's in a pool, so don't worry about the storage */
125 SecCmsContentInfoDestroy(&(encd
->contentInfo
));
130 * SecCmsEncryptedDataGetContentInfo - return pointer to encryptedData object's contentInfo
133 SecCmsEncryptedDataGetContentInfo(SecCmsEncryptedDataRef encd
)
135 return &(encd
->contentInfo
);
139 * SecCmsEncryptedDataEncodeBeforeStart - do all the necessary things to a EncryptedData
140 * before encoding begins.
143 * - set the correct version value.
144 * - get the encryption key
147 SecCmsEncryptedDataEncodeBeforeStart(SecCmsEncryptedDataRef encd
)
150 SecSymmetricKeyRef bulkkey
= NULL
;
152 SecCmsContentInfoRef cinfo
= &(encd
->contentInfo
);
154 if (SecCmsArrayIsEmpty((void **)encd
->unprotectedAttr
))
155 version
= SEC_CMS_ENCRYPTED_DATA_VERSION
;
157 version
= SEC_CMS_ENCRYPTED_DATA_VERSION_UPATTR
;
159 dummy
= SEC_ASN1EncodeInteger (encd
->contentInfo
.cmsg
->poolp
, &(encd
->version
), version
);
163 /* now get content encryption key (bulk key) by using our cmsg callback */
164 if (encd
->contentInfo
.cmsg
->decrypt_key_cb
)
165 bulkkey
= (*encd
->contentInfo
.cmsg
->decrypt_key_cb
)(encd
->contentInfo
.cmsg
->decrypt_key_cb_arg
,
166 SecCmsContentInfoGetContentEncAlg(cinfo
));
170 /* store the bulk key in the contentInfo so that the encoder can find it */
171 SecCmsContentInfoSetBulkKey(cinfo
, bulkkey
);
172 CFRelease(bulkkey
); /* This assumes the decrypt_key_cb hands us a copy of the key --mb */
178 * SecCmsEncryptedDataEncodeBeforeData - set up encryption
181 SecCmsEncryptedDataEncodeBeforeData(SecCmsEncryptedDataRef encd
)
183 SecCmsContentInfoRef cinfo
;
184 SecSymmetricKeyRef bulkkey
;
185 SECAlgorithmID
*algid
;
187 cinfo
= &(encd
->contentInfo
);
189 /* find bulkkey and algorithm - must have been set by SecCmsEncryptedDataEncodeBeforeStart */
190 bulkkey
= SecCmsContentInfoGetBulkKey(cinfo
);
193 algid
= SecCmsContentInfoGetContentEncAlg(cinfo
);
197 /* this may modify algid (with IVs generated in a token).
198 * it is therefore essential that algid is a pointer to the "real" contentEncAlg,
199 * not just to a copy */
200 cinfo
->ciphcx
= SecCmsCipherContextStartEncrypt(encd
->contentInfo
.cmsg
->poolp
, bulkkey
, algid
);
202 if (cinfo
->ciphcx
== NULL
)
209 * SecCmsEncryptedDataEncodeAfterData - finalize this encryptedData for encoding
212 SecCmsEncryptedDataEncodeAfterData(SecCmsEncryptedDataRef encd
)
214 if (encd
->contentInfo
.ciphcx
) {
215 SecCmsCipherContextDestroy(encd
->contentInfo
.ciphcx
);
216 encd
->contentInfo
.ciphcx
= NULL
;
219 /* nothing to do after data */
225 * SecCmsEncryptedDataDecodeBeforeData - find bulk key & set up decryption
228 SecCmsEncryptedDataDecodeBeforeData(SecCmsEncryptedDataRef encd
)
230 SecSymmetricKeyRef bulkkey
= NULL
;
231 SecCmsContentInfoRef cinfo
;
232 SECAlgorithmID
*bulkalg
;
233 OSStatus rv
= SECFailure
;
235 cinfo
= &(encd
->contentInfo
);
237 bulkalg
= SecCmsContentInfoGetContentEncAlg(cinfo
);
239 if (encd
->contentInfo
.cmsg
->decrypt_key_cb
== NULL
) /* no callback? no key../ */
242 bulkkey
= (*encd
->contentInfo
.cmsg
->decrypt_key_cb
)(encd
->contentInfo
.cmsg
->decrypt_key_cb_arg
, bulkalg
);
244 /* no success finding a bulk key */
247 SecCmsContentInfoSetBulkKey(cinfo
, bulkkey
);
249 cinfo
->ciphcx
= SecCmsCipherContextStartDecrypt(bulkkey
, bulkalg
);
250 if (cinfo
->ciphcx
== NULL
)
251 goto loser
; /* error has been set by SecCmsCipherContextStartDecrypt */
258 * For PKCS5 Encryption Algorithms, the bulkkey is actually a different
259 * structure. Therefore, we need to set the bulkkey to the actual key
260 * prior to freeing it.
262 if (SEC_PKCS5IsAlgorithmPBEAlg(bulkalg
)) {
263 SEC_PKCS5KeyAndPassword
*keyPwd
= (SEC_PKCS5KeyAndPassword
*)bulkkey
;
264 bulkkey
= keyPwd
->key
;
268 /* we are done with (this) bulkkey now. */
278 * SecCmsEncryptedDataDecodeAfterData - finish decrypting this encryptedData's content
281 SecCmsEncryptedDataDecodeAfterData(SecCmsEncryptedDataRef encd
)
283 if (encd
->contentInfo
.ciphcx
) {
284 SecCmsCipherContextDestroy(encd
->contentInfo
.ciphcx
);
285 encd
->contentInfo
.ciphcx
= NULL
;
292 * SecCmsEncryptedDataDecodeAfterEnd - finish decoding this encryptedData
295 SecCmsEncryptedDataDecodeAfterEnd(SecCmsEncryptedDataRef encd
)
297 /* apply final touches */