security/nss/lib/smime/cmsencdata.c

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:8d14dcd16c06
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 /*
6 * CMS encryptedData methods.
7 */
8
9 #include "cmslocal.h"
10
11 #include "key.h"
12 #include "secasn1.h"
13 #include "secitem.h"
14 #include "secoid.h"
15 #include "pk11func.h"
16 #include "prtime.h"
17 #include "secerr.h"
18 #include "secpkcs5.h"
19
20 /*
21 * NSS_CMSEncryptedData_Create - create an empty encryptedData object.
22 *
23 * "algorithm" specifies the bulk encryption algorithm to use.
24 * "keysize" is the key size.
25 *
26 * An error results in a return value of NULL and an error set.
27 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
28 */
29 NSSCMSEncryptedData *
30 NSS_CMSEncryptedData_Create(NSSCMSMessage *cmsg, SECOidTag algorithm,
31 int keysize)
32 {
33 void *mark;
34 NSSCMSEncryptedData *encd;
35 PLArenaPool *poolp;
36 SECAlgorithmID *pbe_algid;
37 SECStatus rv;
38
39 poolp = cmsg->poolp;
40
41 mark = PORT_ArenaMark(poolp);
42
43 encd = PORT_ArenaZNew(poolp, NSSCMSEncryptedData);
44 if (encd == NULL)
45 goto loser;
46
47 encd->cmsg = cmsg;
48
49 /* version is set in NSS_CMSEncryptedData_Encode_BeforeStart() */
50
51 if (!SEC_PKCS5IsAlgorithmPBEAlgTag(algorithm)) {
52 rv = NSS_CMSContentInfo_SetContentEncAlg(poolp, &(encd->contentInfo),
53 algorithm, NULL, keysize);
54 } else {
55 /* Assume password-based-encryption.
56 * Note: we can't generate pkcs5v2 from this interface.
57 * PK11_CreateBPEAlgorithmID generates pkcs5v2 by accepting
58 * non-PBE oids and assuming that they are pkcs5v2 oids, but
59 * NSS_CMSEncryptedData_Create accepts non-PBE oids as regular
60 * CMS encrypted data, so we can't tell NSS_CMS_EncryptedData_Create
61 * to create pkcs5v2 PBEs */
62 pbe_algid = PK11_CreatePBEAlgorithmID(algorithm, 1, NULL);
63 if (pbe_algid == NULL) {
64 rv = SECFailure;
65 } else {
66 rv = NSS_CMSContentInfo_SetContentEncAlgID(poolp,
67 &(encd->contentInfo), pbe_algid, keysize);
68 SECOID_DestroyAlgorithmID (pbe_algid, PR_TRUE);
69 }
70 }
71 if (rv != SECSuccess)
72 goto loser;
73
74 PORT_ArenaUnmark(poolp, mark);
75 return encd;
76
77 loser:
78 PORT_ArenaRelease(poolp, mark);
79 return NULL;
80 }
81
82 /*
83 * NSS_CMSEncryptedData_Destroy - destroy an encryptedData object
84 */
85 void
86 NSS_CMSEncryptedData_Destroy(NSSCMSEncryptedData *encd)
87 {
88 /* everything's in a pool, so don't worry about the storage */
89 NSS_CMSContentInfo_Destroy(&(encd->contentInfo));
90 return;
91 }
92
93 /*
94 * NSS_CMSEncryptedData_GetContentInfo - return pointer to encryptedData object's contentInfo
95 */
96 NSSCMSContentInfo *
97 NSS_CMSEncryptedData_GetContentInfo(NSSCMSEncryptedData *encd)
98 {
99 return &(encd->contentInfo);
100 }
101
102 /*
103 * NSS_CMSEncryptedData_Encode_BeforeStart - do all the necessary things to a EncryptedData
104 * before encoding begins.
105 *
106 * In particular:
107 * - set the correct version value.
108 * - get the encryption key
109 */
110 SECStatus
111 NSS_CMSEncryptedData_Encode_BeforeStart(NSSCMSEncryptedData *encd)
112 {
113 int version;
114 PK11SymKey *bulkkey = NULL;
115 SECItem *dummy;
116 NSSCMSContentInfo *cinfo = &(encd->contentInfo);
117
118 if (NSS_CMSArray_IsEmpty((void **)encd->unprotectedAttr))
119 version = NSS_CMS_ENCRYPTED_DATA_VERSION;
120 else
121 version = NSS_CMS_ENCRYPTED_DATA_VERSION_UPATTR;
122
123 dummy = SEC_ASN1EncodeInteger (encd->cmsg->poolp, &(encd->version), version);
124 if (dummy == NULL)
125 return SECFailure;
126
127 /* now get content encryption key (bulk key) by using our cmsg callback */
128 if (encd->cmsg->decrypt_key_cb)
129 bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg,
130 NSS_CMSContentInfo_GetContentEncAlg(cinfo));
131 if (bulkkey == NULL)
132 return SECFailure;
133
134 /* store the bulk key in the contentInfo so that the encoder can find it */
135 NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey);
136 PK11_FreeSymKey (bulkkey);
137
138 return SECSuccess;
139 }
140
141 /*
142 * NSS_CMSEncryptedData_Encode_BeforeData - set up encryption
143 */
144 SECStatus
145 NSS_CMSEncryptedData_Encode_BeforeData(NSSCMSEncryptedData *encd)
146 {
147 NSSCMSContentInfo *cinfo;
148 PK11SymKey *bulkkey;
149 SECAlgorithmID *algid;
150 SECStatus rv;
151
152 cinfo = &(encd->contentInfo);
153
154 /* find bulkkey and algorithm - must have been set by NSS_CMSEncryptedData_Encode_BeforeStart */
155 bulkkey = NSS_CMSContentInfo_GetBulkKey(cinfo);
156 if (bulkkey == NULL)
157 return SECFailure;
158 algid = NSS_CMSContentInfo_GetContentEncAlg(cinfo);
159 if (algid == NULL)
160 return SECFailure;
161
162 rv = NSS_CMSContentInfo_Private_Init(cinfo);
163 if (rv != SECSuccess) {
164 return SECFailure;
165 }
166 /* this may modify algid (with IVs generated in a token).
167 * it is therefore essential that algid is a pointer to the "real" contentEncAlg,
168 * not just to a copy */
169 cinfo->privateInfo->ciphcx = NSS_CMSCipherContext_StartEncrypt(encd->cmsg->poolp, bulkkey, algid);
170 PK11_FreeSymKey(bulkkey);
171 if (cinfo->privateInfo->ciphcx == NULL)
172 return SECFailure;
173
174 return SECSuccess;
175 }
176
177 /*
178 * NSS_CMSEncryptedData_Encode_AfterData - finalize this encryptedData for encoding
179 */
180 SECStatus
181 NSS_CMSEncryptedData_Encode_AfterData(NSSCMSEncryptedData *encd)
182 {
183 if (encd->contentInfo.privateInfo && encd->contentInfo.privateInfo->ciphcx) {
184 NSS_CMSCipherContext_Destroy(encd->contentInfo.privateInfo->ciphcx);
185 encd->contentInfo.privateInfo->ciphcx = NULL;
186 }
187
188 /* nothing to do after data */
189 return SECSuccess;
190 }
191
192
193 /*
194 * NSS_CMSEncryptedData_Decode_BeforeData - find bulk key & set up decryption
195 */
196 SECStatus
197 NSS_CMSEncryptedData_Decode_BeforeData(NSSCMSEncryptedData *encd)
198 {
199 PK11SymKey *bulkkey = NULL;
200 NSSCMSContentInfo *cinfo;
201 SECAlgorithmID *bulkalg;
202 SECStatus rv = SECFailure;
203
204 cinfo = &(encd->contentInfo);
205
206 bulkalg = NSS_CMSContentInfo_GetContentEncAlg(cinfo);
207
208 if (encd->cmsg->decrypt_key_cb == NULL) /* no callback? no key../ */
209 goto loser;
210
211 bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, bulkalg);
212 if (bulkkey == NULL)
213 /* no success finding a bulk key */
214 goto loser;
215
216 NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey);
217
218 rv = NSS_CMSContentInfo_Private_Init(cinfo);
219 if (rv != SECSuccess) {
220 goto loser;
221 }
222 rv = SECFailure;
223
224 cinfo->privateInfo->ciphcx = NSS_CMSCipherContext_StartDecrypt(bulkkey, bulkalg);
225 if (cinfo->privateInfo->ciphcx == NULL)
226 goto loser; /* error has been set by NSS_CMSCipherContext_StartDecrypt */
227
228
229 /* we are done with (this) bulkkey now. */
230 PK11_FreeSymKey(bulkkey);
231
232 rv = SECSuccess;
233
234 loser:
235 return rv;
236 }
237
238 /*
239 * NSS_CMSEncryptedData_Decode_AfterData - finish decrypting this encryptedData's content
240 */
241 SECStatus
242 NSS_CMSEncryptedData_Decode_AfterData(NSSCMSEncryptedData *encd)
243 {
244 if (encd->contentInfo.privateInfo && encd->contentInfo.privateInfo->ciphcx) {
245 NSS_CMSCipherContext_Destroy(encd->contentInfo.privateInfo->ciphcx);
246 encd->contentInfo.privateInfo->ciphcx = NULL;
247 }
248
249 return SECSuccess;
250 }
251
252 /*
253 * NSS_CMSEncryptedData_Decode_AfterEnd - finish decoding this encryptedData
254 */
255 SECStatus
256 NSS_CMSEncryptedData_Decode_AfterEnd(NSSCMSEncryptedData *encd)
257 {
258 /* apply final touches */
259 return SECSuccess;
260 }

mercurial