/src/nss/lib/pkcs7/p7common.c
Line | Count | Source (jump to first uncovered line) |
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 | | * PKCS7 implementation -- the exported parts that are used whether |
7 | | * creating or decoding. |
8 | | */ |
9 | | |
10 | | #include "p7local.h" |
11 | | |
12 | | #include "cert.h" |
13 | | #include "secitem.h" |
14 | | #include "secoid.h" |
15 | | #include "pk11func.h" |
16 | | |
17 | | /* |
18 | | * Find out (saving pointer to lookup result for future reference) |
19 | | * and return the inner content type. |
20 | | */ |
21 | | SECOidTag |
22 | | SEC_PKCS7ContentType(SEC_PKCS7ContentInfo *cinfo) |
23 | 0 | { |
24 | 0 | if (cinfo->contentTypeTag == NULL) |
25 | 0 | cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType)); |
26 | |
|
27 | 0 | if (cinfo->contentTypeTag == NULL) |
28 | 0 | return SEC_OID_UNKNOWN; |
29 | | |
30 | 0 | return cinfo->contentTypeTag->offset; |
31 | 0 | } |
32 | | |
33 | | /* |
34 | | * Destroy a PKCS7 contentInfo and all of its sub-pieces. |
35 | | */ |
36 | | void |
37 | | SEC_PKCS7DestroyContentInfo(SEC_PKCS7ContentInfo *cinfo) |
38 | 0 | { |
39 | 0 | SECOidTag kind; |
40 | 0 | CERTCertificate **certs; |
41 | 0 | CERTCertificateList **certlists; |
42 | 0 | SEC_PKCS7SignerInfo **signerinfos; |
43 | 0 | SEC_PKCS7RecipientInfo **recipientinfos; |
44 | |
|
45 | 0 | PORT_Assert(cinfo->refCount > 0); |
46 | 0 | if (cinfo->refCount <= 0) |
47 | 0 | return; |
48 | | |
49 | 0 | cinfo->refCount--; |
50 | 0 | if (cinfo->refCount > 0) |
51 | 0 | return; |
52 | | |
53 | 0 | certs = NULL; |
54 | 0 | certlists = NULL; |
55 | 0 | recipientinfos = NULL; |
56 | 0 | signerinfos = NULL; |
57 | |
|
58 | 0 | kind = SEC_PKCS7ContentType(cinfo); |
59 | 0 | switch (kind) { |
60 | 0 | case SEC_OID_PKCS7_ENVELOPED_DATA: { |
61 | 0 | SEC_PKCS7EnvelopedData *edp; |
62 | |
|
63 | 0 | edp = cinfo->content.envelopedData; |
64 | 0 | if (edp != NULL) { |
65 | 0 | recipientinfos = edp->recipientInfos; |
66 | 0 | } |
67 | 0 | } break; |
68 | 0 | case SEC_OID_PKCS7_SIGNED_DATA: { |
69 | 0 | SEC_PKCS7SignedData *sdp; |
70 | |
|
71 | 0 | sdp = cinfo->content.signedData; |
72 | 0 | if (sdp != NULL) { |
73 | 0 | certs = sdp->certs; |
74 | 0 | certlists = sdp->certLists; |
75 | 0 | signerinfos = sdp->signerInfos; |
76 | 0 | } |
77 | 0 | } break; |
78 | 0 | case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: { |
79 | 0 | SEC_PKCS7SignedAndEnvelopedData *saedp; |
80 | |
|
81 | 0 | saedp = cinfo->content.signedAndEnvelopedData; |
82 | 0 | if (saedp != NULL) { |
83 | 0 | certs = saedp->certs; |
84 | 0 | certlists = saedp->certLists; |
85 | 0 | recipientinfos = saedp->recipientInfos; |
86 | 0 | signerinfos = saedp->signerInfos; |
87 | 0 | if (saedp->sigKey != NULL) |
88 | 0 | PK11_FreeSymKey(saedp->sigKey); |
89 | 0 | } |
90 | 0 | } break; |
91 | 0 | default: |
92 | | /* XXX Anything else that needs to be "manually" freed/destroyed? */ |
93 | 0 | break; |
94 | 0 | } |
95 | | |
96 | 0 | if (certs != NULL) { |
97 | 0 | CERTCertificate *cert; |
98 | |
|
99 | 0 | while ((cert = *certs++) != NULL) { |
100 | 0 | CERT_DestroyCertificate(cert); |
101 | 0 | } |
102 | 0 | } |
103 | |
|
104 | 0 | if (certlists != NULL) { |
105 | 0 | CERTCertificateList *certlist; |
106 | |
|
107 | 0 | while ((certlist = *certlists++) != NULL) { |
108 | 0 | CERT_DestroyCertificateList(certlist); |
109 | 0 | } |
110 | 0 | } |
111 | |
|
112 | 0 | if (recipientinfos != NULL) { |
113 | 0 | SEC_PKCS7RecipientInfo *ri; |
114 | |
|
115 | 0 | while ((ri = *recipientinfos++) != NULL) { |
116 | 0 | if (ri->cert != NULL) |
117 | 0 | CERT_DestroyCertificate(ri->cert); |
118 | 0 | } |
119 | 0 | } |
120 | |
|
121 | 0 | if (signerinfos != NULL) { |
122 | 0 | SEC_PKCS7SignerInfo *si; |
123 | |
|
124 | 0 | while ((si = *signerinfos++) != NULL) { |
125 | 0 | if (si->cert != NULL) |
126 | 0 | CERT_DestroyCertificate(si->cert); |
127 | 0 | if (si->certList != NULL) |
128 | 0 | CERT_DestroyCertificateList(si->certList); |
129 | 0 | } |
130 | 0 | } |
131 | |
|
132 | 0 | if (cinfo->poolp != NULL) { |
133 | 0 | PORT_FreeArena(cinfo->poolp, PR_FALSE); /* XXX clear it? */ |
134 | 0 | } |
135 | 0 | } |
136 | | |
137 | | /* |
138 | | * Return a copy of the given contentInfo. The copy may be virtual |
139 | | * or may be real -- either way, the result needs to be passed to |
140 | | * SEC_PKCS7DestroyContentInfo later (as does the original). |
141 | | */ |
142 | | SEC_PKCS7ContentInfo * |
143 | | SEC_PKCS7CopyContentInfo(SEC_PKCS7ContentInfo *cinfo) |
144 | 0 | { |
145 | 0 | if (cinfo == NULL) |
146 | 0 | return NULL; |
147 | | |
148 | 0 | PORT_Assert(cinfo->refCount > 0); |
149 | |
|
150 | 0 | if (cinfo->created) { |
151 | | /* |
152 | | * Want to do a real copy of these; otherwise subsequent |
153 | | * changes made to either copy are likely to be a surprise. |
154 | | * XXX I suspect that this will not actually be called for yet, |
155 | | * which is why the assert, so to notice if it is... |
156 | | */ |
157 | 0 | PORT_Assert(0); |
158 | | /* |
159 | | * XXX Create a new pool here, and copy everything from |
160 | | * within. For cert stuff, need to call the appropriate |
161 | | * copy functions, etc. |
162 | | */ |
163 | 0 | } |
164 | |
|
165 | 0 | cinfo->refCount++; |
166 | 0 | return cinfo; |
167 | 0 | } |
168 | | |
169 | | /* |
170 | | * Return a pointer to the actual content. In the case of those types |
171 | | * which are encrypted, this returns the *plain* content. |
172 | | * XXX Needs revisiting if/when we handle nested encrypted types. |
173 | | */ |
174 | | SECItem * |
175 | | SEC_PKCS7GetContent(SEC_PKCS7ContentInfo *cinfo) |
176 | 0 | { |
177 | 0 | SECOidTag kind; |
178 | |
|
179 | 0 | kind = SEC_PKCS7ContentType(cinfo); |
180 | 0 | switch (kind) { |
181 | 0 | case SEC_OID_PKCS7_DATA: |
182 | 0 | return cinfo->content.data; |
183 | 0 | case SEC_OID_PKCS7_DIGESTED_DATA: { |
184 | 0 | SEC_PKCS7DigestedData *digd; |
185 | |
|
186 | 0 | digd = cinfo->content.digestedData; |
187 | 0 | if (digd == NULL) |
188 | 0 | break; |
189 | 0 | return SEC_PKCS7GetContent(&(digd->contentInfo)); |
190 | 0 | } |
191 | 0 | case SEC_OID_PKCS7_ENCRYPTED_DATA: { |
192 | 0 | SEC_PKCS7EncryptedData *encd; |
193 | |
|
194 | 0 | encd = cinfo->content.encryptedData; |
195 | 0 | if (encd == NULL) |
196 | 0 | break; |
197 | 0 | return &(encd->encContentInfo.plainContent); |
198 | 0 | } |
199 | 0 | case SEC_OID_PKCS7_ENVELOPED_DATA: { |
200 | 0 | SEC_PKCS7EnvelopedData *envd; |
201 | |
|
202 | 0 | envd = cinfo->content.envelopedData; |
203 | 0 | if (envd == NULL) |
204 | 0 | break; |
205 | 0 | return &(envd->encContentInfo.plainContent); |
206 | 0 | } |
207 | 0 | case SEC_OID_PKCS7_SIGNED_DATA: { |
208 | 0 | SEC_PKCS7SignedData *sigd; |
209 | |
|
210 | 0 | sigd = cinfo->content.signedData; |
211 | 0 | if (sigd == NULL) |
212 | 0 | break; |
213 | 0 | return SEC_PKCS7GetContent(&(sigd->contentInfo)); |
214 | 0 | } |
215 | 0 | case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: { |
216 | 0 | SEC_PKCS7SignedAndEnvelopedData *saed; |
217 | |
|
218 | 0 | saed = cinfo->content.signedAndEnvelopedData; |
219 | 0 | if (saed == NULL) |
220 | 0 | break; |
221 | 0 | return &(saed->encContentInfo.plainContent); |
222 | 0 | } |
223 | 0 | default: |
224 | 0 | PORT_Assert(0); |
225 | 0 | break; |
226 | 0 | } |
227 | | |
228 | 0 | return NULL; |
229 | 0 | } |
230 | | |
231 | | /* |
232 | | * XXX Fix the placement and formatting of the |
233 | | * following routines (i.e. make them consistent with the rest of |
234 | | * the pkcs7 code -- I think some/many belong in other files and |
235 | | * they all need a formatting/style rehaul) |
236 | | */ |
237 | | |
238 | | /* retrieve the algorithm identifier for encrypted data. |
239 | | * the identifier returned is a copy of the algorithm identifier |
240 | | * in the content info and needs to be freed after being used. |
241 | | * |
242 | | * cinfo is the content info for which to retrieve the |
243 | | * encryption algorithm. |
244 | | * |
245 | | * if the content info is not encrypted data or an error |
246 | | * occurs NULL is returned. |
247 | | */ |
248 | | SECAlgorithmID * |
249 | | SEC_PKCS7GetEncryptionAlgorithm(SEC_PKCS7ContentInfo *cinfo) |
250 | 0 | { |
251 | 0 | SECAlgorithmID *alg = 0; |
252 | 0 | switch (SEC_PKCS7ContentType(cinfo)) { |
253 | 0 | case SEC_OID_PKCS7_ENCRYPTED_DATA: |
254 | 0 | alg = &cinfo->content.encryptedData->encContentInfo.contentEncAlg; |
255 | 0 | break; |
256 | 0 | case SEC_OID_PKCS7_ENVELOPED_DATA: |
257 | 0 | alg = &cinfo->content.envelopedData->encContentInfo.contentEncAlg; |
258 | 0 | break; |
259 | 0 | case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: |
260 | 0 | alg = &cinfo->content.signedAndEnvelopedData |
261 | 0 | ->encContentInfo.contentEncAlg; |
262 | 0 | break; |
263 | 0 | default: |
264 | 0 | alg = 0; |
265 | 0 | break; |
266 | 0 | } |
267 | | |
268 | 0 | return alg; |
269 | 0 | } |
270 | | |
271 | | /* set the content of the content info. For data content infos, |
272 | | * the data is set. For encrytped content infos, the plainContent |
273 | | * is set, and is expected to be encrypted later. |
274 | | * |
275 | | * cinfo is the content info where the data will be set |
276 | | * |
277 | | * buf is a buffer of the data to set |
278 | | * |
279 | | * len is the length of the data being set. |
280 | | * |
281 | | * in the event of an error, SECFailure is returned. SECSuccess |
282 | | * indicates the content was successfully set. |
283 | | */ |
284 | | SECStatus |
285 | | SEC_PKCS7SetContent(SEC_PKCS7ContentInfo *cinfo, |
286 | | const char *buf, |
287 | | unsigned long len) |
288 | 0 | { |
289 | 0 | SECOidTag cinfo_type; |
290 | 0 | SECStatus rv; |
291 | 0 | SECItem content; |
292 | 0 | SECOidData *contentTypeTag = NULL; |
293 | |
|
294 | 0 | content.type = siBuffer; |
295 | 0 | content.data = (unsigned char *)buf; |
296 | 0 | content.len = len; |
297 | |
|
298 | 0 | cinfo_type = SEC_PKCS7ContentType(cinfo); |
299 | | |
300 | | /* set inner content */ |
301 | 0 | switch (cinfo_type) { |
302 | 0 | case SEC_OID_PKCS7_SIGNED_DATA: |
303 | 0 | if (content.len > 0) { |
304 | | /* we "leak" the old content here, but as it's all in the pool */ |
305 | | /* it does not really matter */ |
306 | | |
307 | | /* create content item if necessary */ |
308 | 0 | if (cinfo->content.signedData->contentInfo.content.data == NULL) |
309 | 0 | cinfo->content.signedData->contentInfo.content.data = SECITEM_AllocItem(cinfo->poolp, NULL, 0); |
310 | 0 | rv = SECITEM_CopyItem(cinfo->poolp, |
311 | 0 | cinfo->content.signedData->contentInfo.content.data, |
312 | 0 | &content); |
313 | 0 | } else { |
314 | 0 | cinfo->content.signedData->contentInfo.content.data->data = NULL; |
315 | 0 | cinfo->content.signedData->contentInfo.content.data->len = 0; |
316 | 0 | rv = SECSuccess; |
317 | 0 | } |
318 | 0 | if (rv == SECFailure) |
319 | 0 | goto loser; |
320 | | |
321 | 0 | break; |
322 | 0 | case SEC_OID_PKCS7_ENCRYPTED_DATA: |
323 | | /* XXX this forces the inner content type to be "data" */ |
324 | | /* do we really want to override without asking or reason? */ |
325 | 0 | contentTypeTag = SECOID_FindOIDByTag(SEC_OID_PKCS7_DATA); |
326 | 0 | if (contentTypeTag == NULL) |
327 | 0 | goto loser; |
328 | 0 | rv = SECITEM_CopyItem(cinfo->poolp, |
329 | 0 | &(cinfo->content.encryptedData->encContentInfo.contentType), |
330 | 0 | &(contentTypeTag->oid)); |
331 | 0 | if (rv == SECFailure) |
332 | 0 | goto loser; |
333 | 0 | if (content.len > 0) { |
334 | 0 | rv = SECITEM_CopyItem(cinfo->poolp, |
335 | 0 | &(cinfo->content.encryptedData->encContentInfo.plainContent), |
336 | 0 | &content); |
337 | 0 | } else { |
338 | 0 | cinfo->content.encryptedData->encContentInfo.plainContent.data = NULL; |
339 | 0 | cinfo->content.encryptedData->encContentInfo.encContent.data = NULL; |
340 | 0 | cinfo->content.encryptedData->encContentInfo.plainContent.len = 0; |
341 | 0 | cinfo->content.encryptedData->encContentInfo.encContent.len = 0; |
342 | 0 | rv = SECSuccess; |
343 | 0 | } |
344 | 0 | if (rv == SECFailure) |
345 | 0 | goto loser; |
346 | 0 | break; |
347 | 0 | case SEC_OID_PKCS7_DATA: |
348 | 0 | cinfo->content.data = (SECItem *)PORT_ArenaZAlloc(cinfo->poolp, |
349 | 0 | sizeof(SECItem)); |
350 | 0 | if (cinfo->content.data == NULL) |
351 | 0 | goto loser; |
352 | 0 | if (content.len > 0) { |
353 | 0 | rv = SECITEM_CopyItem(cinfo->poolp, |
354 | 0 | cinfo->content.data, &content); |
355 | 0 | } else { |
356 | | /* handle case with NULL content */ |
357 | 0 | rv = SECSuccess; |
358 | 0 | } |
359 | 0 | if (rv == SECFailure) |
360 | 0 | goto loser; |
361 | 0 | break; |
362 | 0 | default: |
363 | 0 | goto loser; |
364 | 0 | } |
365 | | |
366 | 0 | return SECSuccess; |
367 | | |
368 | 0 | loser: |
369 | |
|
370 | 0 | return SECFailure; |
371 | 0 | } |
372 | | |
373 | | /* the content of an encrypted data content info is encrypted. |
374 | | * it is assumed that for encrypted data, that the data has already |
375 | | * been set and is in the "plainContent" field of the content info. |
376 | | * |
377 | | * cinfo is the content info to encrypt |
378 | | * |
379 | | * key is the key with which to perform the encryption. if the |
380 | | * algorithm is a password based encryption algorithm, the |
381 | | * key is actually a password which will be processed per |
382 | | * PKCS #5. |
383 | | * |
384 | | * in the event of an error, SECFailure is returned. SECSuccess |
385 | | * indicates a success. |
386 | | */ |
387 | | SECStatus |
388 | | SEC_PKCS7EncryptContents(PLArenaPool *poolp, |
389 | | SEC_PKCS7ContentInfo *cinfo, |
390 | | SECItem *key, |
391 | | void *wincx) |
392 | 0 | { |
393 | 0 | SECAlgorithmID *algid = NULL; |
394 | 0 | SECItem *src; |
395 | 0 | SECItem *dest; |
396 | 0 | SECItem *blocked_data = NULL; |
397 | 0 | void *mark; |
398 | 0 | void *cx; |
399 | 0 | PK11SymKey *eKey = NULL; |
400 | 0 | PK11SlotInfo *slot = NULL; |
401 | |
|
402 | 0 | CK_MECHANISM_TYPE cryptoMechType; |
403 | 0 | int bs; |
404 | 0 | SECStatus rv = SECFailure; |
405 | 0 | SECItem *c_param = NULL; |
406 | |
|
407 | 0 | if ((cinfo == NULL) || (key == NULL)) |
408 | 0 | return SECFailure; |
409 | | |
410 | 0 | if (SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA) |
411 | 0 | return SECFailure; |
412 | | |
413 | 0 | algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo); |
414 | 0 | if (algid == NULL) |
415 | 0 | return SECFailure; |
416 | | |
417 | 0 | if (poolp == NULL) |
418 | 0 | poolp = cinfo->poolp; |
419 | |
|
420 | 0 | mark = PORT_ArenaMark(poolp); |
421 | |
|
422 | 0 | src = &cinfo->content.encryptedData->encContentInfo.plainContent; |
423 | 0 | dest = &cinfo->content.encryptedData->encContentInfo.encContent; |
424 | 0 | dest->data = (unsigned char *)PORT_ArenaZAlloc(poolp, (src->len + 64)); |
425 | 0 | dest->len = (src->len + 64); |
426 | 0 | if (dest->data == NULL) { |
427 | 0 | rv = SECFailure; |
428 | 0 | goto loser; |
429 | 0 | } |
430 | | |
431 | 0 | slot = PK11_GetInternalKeySlot(); |
432 | 0 | if (slot == NULL) { |
433 | 0 | rv = SECFailure; |
434 | 0 | goto loser; |
435 | 0 | } |
436 | | |
437 | 0 | eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx); |
438 | 0 | if (eKey == NULL) { |
439 | 0 | rv = SECFailure; |
440 | 0 | goto loser; |
441 | 0 | } |
442 | | |
443 | 0 | cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key); |
444 | 0 | if (cryptoMechType == CKM_INVALID_MECHANISM) { |
445 | 0 | rv = SECFailure; |
446 | 0 | goto loser; |
447 | 0 | } |
448 | | |
449 | | /* block according to PKCS 8 */ |
450 | 0 | bs = PK11_GetBlockSize(cryptoMechType, c_param); |
451 | 0 | rv = SECSuccess; |
452 | 0 | if (bs) { |
453 | 0 | char pad_char; |
454 | 0 | pad_char = (char)(bs - (src->len % bs)); |
455 | 0 | if (src->len % bs) { |
456 | 0 | rv = SECSuccess; |
457 | 0 | blocked_data = PK11_BlockData(src, bs); |
458 | 0 | if (blocked_data) { |
459 | 0 | PORT_Memset((blocked_data->data + blocked_data->len - (int)pad_char), |
460 | 0 | pad_char, (int)pad_char); |
461 | 0 | } else { |
462 | 0 | rv = SECFailure; |
463 | 0 | goto loser; |
464 | 0 | } |
465 | 0 | } else { |
466 | 0 | blocked_data = SECITEM_DupItem(src); |
467 | 0 | if (blocked_data) { |
468 | 0 | blocked_data->data = (unsigned char *)PORT_Realloc( |
469 | 0 | blocked_data->data, |
470 | 0 | blocked_data->len + bs); |
471 | 0 | if (blocked_data->data) { |
472 | 0 | blocked_data->len += bs; |
473 | 0 | PORT_Memset((blocked_data->data + src->len), (char)bs, bs); |
474 | 0 | } else { |
475 | 0 | rv = SECFailure; |
476 | 0 | goto loser; |
477 | 0 | } |
478 | 0 | } else { |
479 | 0 | rv = SECFailure; |
480 | 0 | goto loser; |
481 | 0 | } |
482 | 0 | } |
483 | 0 | } else { |
484 | 0 | blocked_data = SECITEM_DupItem(src); |
485 | 0 | if (!blocked_data) { |
486 | 0 | rv = SECFailure; |
487 | 0 | goto loser; |
488 | 0 | } |
489 | 0 | } |
490 | | |
491 | 0 | cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT, |
492 | 0 | eKey, c_param); |
493 | 0 | if (cx == NULL) { |
494 | 0 | rv = SECFailure; |
495 | 0 | goto loser; |
496 | 0 | } |
497 | | |
498 | 0 | rv = PK11_CipherOp((PK11Context *)cx, dest->data, (int *)(&dest->len), |
499 | 0 | (int)(src->len + 64), blocked_data->data, |
500 | 0 | (int)blocked_data->len); |
501 | 0 | PK11_DestroyContext((PK11Context *)cx, PR_TRUE); |
502 | |
|
503 | 0 | loser: |
504 | | /* let success fall through */ |
505 | 0 | if (blocked_data != NULL) |
506 | 0 | SECITEM_ZfreeItem(blocked_data, PR_TRUE); |
507 | |
|
508 | 0 | if (rv == SECFailure) |
509 | 0 | PORT_ArenaRelease(poolp, mark); |
510 | 0 | else |
511 | 0 | PORT_ArenaUnmark(poolp, mark); |
512 | |
|
513 | 0 | if (eKey != NULL) |
514 | 0 | PK11_FreeSymKey(eKey); |
515 | |
|
516 | 0 | if (slot != NULL) |
517 | 0 | PK11_FreeSlot(slot); |
518 | |
|
519 | 0 | if (c_param != NULL) |
520 | 0 | SECITEM_ZfreeItem(c_param, PR_TRUE); |
521 | |
|
522 | 0 | return rv; |
523 | 0 | } |
524 | | |
525 | | /* the content of an encrypted data content info is decrypted. |
526 | | * it is assumed that for encrypted data, that the data has already |
527 | | * been set and is in the "encContent" field of the content info. |
528 | | * |
529 | | * cinfo is the content info to decrypt |
530 | | * |
531 | | * key is the key with which to perform the decryption. if the |
532 | | * algorithm is a password based encryption algorithm, the |
533 | | * key is actually a password which will be processed per |
534 | | * PKCS #5. |
535 | | * |
536 | | * in the event of an error, SECFailure is returned. SECSuccess |
537 | | * indicates a success. |
538 | | */ |
539 | | SECStatus |
540 | | SEC_PKCS7DecryptContents(PLArenaPool *poolp, |
541 | | SEC_PKCS7ContentInfo *cinfo, |
542 | | SECItem *key, |
543 | | void *wincx) |
544 | 0 | { |
545 | 0 | SECAlgorithmID *algid = NULL; |
546 | 0 | SECStatus rv = SECFailure; |
547 | 0 | SECItem *dest, *src; |
548 | 0 | void *mark; |
549 | |
|
550 | 0 | PK11SymKey *eKey = NULL; |
551 | 0 | PK11SlotInfo *slot = NULL; |
552 | 0 | CK_MECHANISM_TYPE cryptoMechType; |
553 | 0 | void *cx; |
554 | 0 | SECItem *c_param = NULL; |
555 | 0 | int bs; |
556 | |
|
557 | 0 | if ((cinfo == NULL) || (key == NULL)) |
558 | 0 | return SECFailure; |
559 | | |
560 | 0 | if (SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA) |
561 | 0 | return SECFailure; |
562 | | |
563 | 0 | algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo); |
564 | 0 | if (algid == NULL) |
565 | 0 | return SECFailure; |
566 | | |
567 | 0 | if (poolp == NULL) |
568 | 0 | poolp = cinfo->poolp; |
569 | |
|
570 | 0 | mark = PORT_ArenaMark(poolp); |
571 | |
|
572 | 0 | src = &cinfo->content.encryptedData->encContentInfo.encContent; |
573 | 0 | dest = &cinfo->content.encryptedData->encContentInfo.plainContent; |
574 | 0 | dest->data = (unsigned char *)PORT_ArenaZAlloc(poolp, (src->len + 64)); |
575 | 0 | dest->len = (src->len + 64); |
576 | 0 | if (dest->data == NULL) { |
577 | 0 | rv = SECFailure; |
578 | 0 | goto loser; |
579 | 0 | } |
580 | | |
581 | 0 | slot = PK11_GetInternalKeySlot(); |
582 | 0 | if (slot == NULL) { |
583 | 0 | rv = SECFailure; |
584 | 0 | goto loser; |
585 | 0 | } |
586 | | |
587 | 0 | eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx); |
588 | 0 | if (eKey == NULL) { |
589 | 0 | rv = SECFailure; |
590 | 0 | goto loser; |
591 | 0 | } |
592 | | |
593 | 0 | cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key); |
594 | 0 | if (cryptoMechType == CKM_INVALID_MECHANISM) { |
595 | 0 | rv = SECFailure; |
596 | 0 | goto loser; |
597 | 0 | } |
598 | | |
599 | 0 | cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT, |
600 | 0 | eKey, c_param); |
601 | 0 | if (cx == NULL) { |
602 | 0 | rv = SECFailure; |
603 | 0 | goto loser; |
604 | 0 | } |
605 | | |
606 | 0 | rv = PK11_CipherOp((PK11Context *)cx, dest->data, (int *)(&dest->len), |
607 | 0 | (int)(src->len + 64), src->data, (int)src->len); |
608 | 0 | PK11_DestroyContext((PK11Context *)cx, PR_TRUE); |
609 | |
|
610 | 0 | bs = PK11_GetBlockSize(cryptoMechType, c_param); |
611 | 0 | if (bs) { |
612 | | /* check for proper badding in block algorithms. this assumes |
613 | | * RC2 cbc or a DES cbc variant. and the padding is thus defined |
614 | | */ |
615 | 0 | if (((int)dest->data[dest->len - 1] <= bs) && |
616 | 0 | ((int)dest->data[dest->len - 1] > 0)) { |
617 | 0 | dest->len -= (int)dest->data[dest->len - 1]; |
618 | 0 | } else { |
619 | 0 | rv = SECFailure; |
620 | | /* set an error ? */ |
621 | 0 | } |
622 | 0 | } |
623 | |
|
624 | 0 | loser: |
625 | | /* let success fall through */ |
626 | 0 | if (rv == SECFailure) |
627 | 0 | PORT_ArenaRelease(poolp, mark); |
628 | 0 | else |
629 | 0 | PORT_ArenaUnmark(poolp, mark); |
630 | |
|
631 | 0 | if (eKey != NULL) |
632 | 0 | PK11_FreeSymKey(eKey); |
633 | |
|
634 | 0 | if (slot != NULL) |
635 | 0 | PK11_FreeSlot(slot); |
636 | |
|
637 | 0 | if (c_param != NULL) |
638 | 0 | SECITEM_ZfreeItem(c_param, PR_TRUE); |
639 | |
|
640 | 0 | return rv; |
641 | 0 | } |
642 | | |
643 | | SECItem ** |
644 | | SEC_PKCS7GetCertificateList(SEC_PKCS7ContentInfo *cinfo) |
645 | 0 | { |
646 | 0 | switch (SEC_PKCS7ContentType(cinfo)) { |
647 | 0 | case SEC_OID_PKCS7_SIGNED_DATA: |
648 | 0 | return cinfo->content.signedData->rawCerts; |
649 | 0 | break; |
650 | 0 | default: |
651 | 0 | return NULL; |
652 | 0 | break; |
653 | 0 | } |
654 | 0 | } |
655 | | |
656 | | int |
657 | | SEC_PKCS7GetKeyLength(SEC_PKCS7ContentInfo *cinfo) |
658 | 0 | { |
659 | 0 | if (cinfo->contentTypeTag->offset == SEC_OID_PKCS7_ENVELOPED_DATA) |
660 | 0 | return cinfo->content.envelopedData->encContentInfo.keysize; |
661 | 0 | else |
662 | 0 | return 0; |
663 | 0 | } |