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