Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: mozilla/security/nss/lib/pkcs7/p7encode.c

Issue 14249009: Change the NSS and NSPR source tree to the new directory structure to be (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/nss/
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « mozilla/security/nss/lib/pkcs7/p7decode.c ('k') | mozilla/security/nss/lib/pkcs7/p7local.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 encoding.
7 *
8 * $Id: p7encode.c,v 1.15 2012/04/25 14:50:06 gerv%gerv.net Exp $
9 */
10
11 #include "p7local.h"
12
13 #include "cert.h"
14 #include "cryptohi.h"
15 #include "keyhi.h"
16 #include "secasn1.h"
17 #include "secoid.h"
18 #include "secitem.h"
19 #include "pk11func.h"
20 #include "secerr.h"
21 #include "sechash.h" /* for HASH_GetHashObject() */
22
23 struct sec_pkcs7_encoder_output {
24 SEC_PKCS7EncoderOutputCallback outputfn;
25 void *outputarg;
26 };
27
28 struct SEC_PKCS7EncoderContextStr {
29 SEC_ASN1EncoderContext *ecx;
30 SEC_PKCS7ContentInfo *cinfo;
31 struct sec_pkcs7_encoder_output output;
32 sec_PKCS7CipherObject *encryptobj;
33 const SECHashObject *digestobj;
34 void *digestcx;
35 };
36
37
38 /*
39 * The little output function that the ASN.1 encoder calls to hand
40 * us bytes which we in turn hand back to our caller (via the callback
41 * they gave us).
42 */
43 static void
44 sec_pkcs7_encoder_out(void *arg, const char *buf, unsigned long len,
45 int depth, SEC_ASN1EncodingPart data_kind)
46 {
47 struct sec_pkcs7_encoder_output *output;
48
49 output = (struct sec_pkcs7_encoder_output*)arg;
50 output->outputfn (output->outputarg, buf, len);
51 }
52
53 static sec_PKCS7CipherObject *
54 sec_pkcs7_encoder_start_encrypt (SEC_PKCS7ContentInfo *cinfo,
55 PK11SymKey *orig_bulkkey)
56 {
57 SECOidTag kind;
58 sec_PKCS7CipherObject *encryptobj;
59 SEC_PKCS7RecipientInfo **recipientinfos, *ri;
60 SEC_PKCS7EncryptedContentInfo *enccinfo;
61 SECKEYPublicKey *publickey = NULL;
62 SECKEYPrivateKey *ourPrivKey = NULL;
63 PK11SymKey *bulkkey;
64 void *mark, *wincx;
65 int i;
66 PRArenaPool *arena = NULL;
67
68 /* Get the context in case we need it below. */
69 wincx = cinfo->pwfn_arg;
70
71 kind = SEC_PKCS7ContentType (cinfo);
72 switch (kind) {
73 default:
74 case SEC_OID_PKCS7_DATA:
75 case SEC_OID_PKCS7_DIGESTED_DATA:
76 case SEC_OID_PKCS7_SIGNED_DATA:
77 recipientinfos = NULL;
78 enccinfo = NULL;
79 break;
80 case SEC_OID_PKCS7_ENCRYPTED_DATA:
81 {
82 SEC_PKCS7EncryptedData *encdp;
83
84 /* To do EncryptedData we *must* be given a bulk key. */
85 PORT_Assert (orig_bulkkey != NULL);
86 if (orig_bulkkey == NULL) {
87 /* XXX error? */
88 return NULL;
89 }
90
91 encdp = cinfo->content.encryptedData;
92 recipientinfos = NULL;
93 enccinfo = &(encdp->encContentInfo);
94 }
95 break;
96 case SEC_OID_PKCS7_ENVELOPED_DATA:
97 {
98 SEC_PKCS7EnvelopedData *envdp;
99
100 envdp = cinfo->content.envelopedData;
101 recipientinfos = envdp->recipientInfos;
102 enccinfo = &(envdp->encContentInfo);
103 }
104 break;
105 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
106 {
107 SEC_PKCS7SignedAndEnvelopedData *saedp;
108
109 saedp = cinfo->content.signedAndEnvelopedData;
110 recipientinfos = saedp->recipientInfos;
111 enccinfo = &(saedp->encContentInfo);
112 }
113 break;
114 }
115
116 if (enccinfo == NULL)
117 return NULL;
118
119 bulkkey = orig_bulkkey;
120 if (bulkkey == NULL) {
121 CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(enccinfo->encalg);
122 PK11SlotInfo *slot;
123
124
125 slot = PK11_GetBestSlot(type,cinfo->pwfn_arg);
126 if (slot == NULL) {
127 return NULL;
128 }
129 bulkkey = PK11_KeyGen(slot,type,NULL, enccinfo->keysize/8,
130 cinfo->pwfn_arg);
131 PK11_FreeSlot(slot);
132 if (bulkkey == NULL) {
133 return NULL;
134 }
135 }
136
137 encryptobj = NULL;
138 mark = PORT_ArenaMark (cinfo->poolp);
139
140 /*
141 * Encrypt the bulk key with the public key of each recipient.
142 */
143 for (i = 0; recipientinfos && (ri = recipientinfos[i]) != NULL; i++) {
144 CERTCertificate *cert;
145 SECOidTag certalgtag, encalgtag;
146 SECStatus rv;
147 int data_len;
148 SECItem *params = NULL;
149
150 cert = ri->cert;
151 PORT_Assert (cert != NULL);
152 if (cert == NULL)
153 continue;
154
155 /*
156 * XXX Want an interface that takes a cert and some data and
157 * fills in an algorithmID and encrypts the data with the public
158 * key from the cert. Or, give me two interfaces -- one which
159 * gets the algorithm tag from a cert (I should not have to go
160 * down into the subjectPublicKeyInfo myself) and another which
161 * takes a public key and algorithm tag and data and encrypts
162 * the data. Or something like that. The point is that all
163 * of the following hardwired RSA stuff should be done elsewhere.
164 */
165
166 certalgtag=SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm ));
167
168 switch (certalgtag) {
169 case SEC_OID_PKCS1_RSA_ENCRYPTION:
170 encalgtag = certalgtag;
171 publickey = CERT_ExtractPublicKey (cert);
172 if (publickey == NULL) goto loser;
173
174 data_len = SECKEY_PublicKeyStrength(publickey);
175 ri->encKey.data =
176 (unsigned char*)PORT_ArenaAlloc(cinfo->poolp ,data_len);
177 ri->encKey.len = data_len;
178 if (ri->encKey.data == NULL) goto loser;
179
180 rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(certalgtag),publickey ,
181 bulkkey,&ri->encKey);
182
183 SECKEY_DestroyPublicKey(publickey);
184 publickey = NULL;
185 if (rv != SECSuccess) goto loser;
186 params = NULL; /* paranoia */
187 break;
188 default:
189 PORT_SetError (SEC_ERROR_INVALID_ALGORITHM);
190 goto loser;
191 }
192
193 rv = SECOID_SetAlgorithmID(cinfo->poolp, &ri->keyEncAlg, encalgtag,
194 params);
195 if (rv != SECSuccess)
196 goto loser;
197 if (arena) PORT_FreeArena(arena,PR_FALSE);
198 arena = NULL;
199 }
200
201 encryptobj = sec_PKCS7CreateEncryptObject (cinfo->poolp, bulkkey,
202 enccinfo->encalg,
203 &(enccinfo->contentEncAlg));
204 if (encryptobj != NULL) {
205 PORT_ArenaUnmark (cinfo->poolp, mark);
206 mark = NULL; /* good one; do not want to release */
207 }
208 /* fallthru */
209
210 loser:
211 if (arena) {
212 PORT_FreeArena(arena, PR_FALSE);
213 }
214 if (publickey) {
215 SECKEY_DestroyPublicKey(publickey);
216 }
217 if (ourPrivKey) {
218 SECKEY_DestroyPrivateKey(ourPrivKey);
219 }
220 if (mark != NULL) {
221 PORT_ArenaRelease (cinfo->poolp, mark);
222 }
223 if (orig_bulkkey == NULL) {
224 if (bulkkey) PK11_FreeSymKey(bulkkey);
225 }
226
227 return encryptobj;
228 }
229
230
231 static void
232 sec_pkcs7_encoder_notify (void *arg, PRBool before, void *dest, int depth)
233 {
234 SEC_PKCS7EncoderContext *p7ecx;
235 SEC_PKCS7ContentInfo *cinfo;
236 SECOidTag kind;
237 PRBool before_content;
238
239 /*
240 * We want to notice just before the content field. After fields are
241 * not interesting to us.
242 */
243 if (!before)
244 return;
245
246 p7ecx = (SEC_PKCS7EncoderContext*)arg;
247 cinfo = p7ecx->cinfo;
248
249 before_content = PR_FALSE;
250
251 /*
252 * Watch for the content field, at which point we want to instruct
253 * the ASN.1 encoder to start taking bytes from the buffer.
254 *
255 * XXX The following assumes the inner content type is data;
256 * if/when we want to handle fully nested types, this will have
257 * to recurse until reaching the innermost data content.
258 */
259 kind = SEC_PKCS7ContentType (cinfo);
260 switch (kind) {
261 default:
262 case SEC_OID_PKCS7_DATA:
263 if (dest == &(cinfo->content.data))
264 before_content = PR_TRUE;
265 break;
266
267 case SEC_OID_PKCS7_DIGESTED_DATA:
268 {
269 SEC_PKCS7DigestedData *digd;
270
271 digd = cinfo->content.digestedData;
272 if (digd == NULL)
273 break;
274
275 if (dest == &(digd->contentInfo.content))
276 before_content = PR_TRUE;
277 }
278 break;
279
280 case SEC_OID_PKCS7_ENCRYPTED_DATA:
281 {
282 SEC_PKCS7EncryptedData *encd;
283
284 encd = cinfo->content.encryptedData;
285 if (encd == NULL)
286 break;
287
288 if (dest == &(encd->encContentInfo.encContent))
289 before_content = PR_TRUE;
290 }
291 break;
292
293 case SEC_OID_PKCS7_ENVELOPED_DATA:
294 {
295 SEC_PKCS7EnvelopedData *envd;
296
297 envd = cinfo->content.envelopedData;
298 if (envd == NULL)
299 break;
300
301 if (dest == &(envd->encContentInfo.encContent))
302 before_content = PR_TRUE;
303 }
304 break;
305
306 case SEC_OID_PKCS7_SIGNED_DATA:
307 {
308 SEC_PKCS7SignedData *sigd;
309
310 sigd = cinfo->content.signedData;
311 if (sigd == NULL)
312 break;
313
314 if (dest == &(sigd->contentInfo.content))
315 before_content = PR_TRUE;
316 }
317 break;
318
319 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
320 {
321 SEC_PKCS7SignedAndEnvelopedData *saed;
322
323 saed = cinfo->content.signedAndEnvelopedData;
324 if (saed == NULL)
325 break;
326
327 if (dest == &(saed->encContentInfo.encContent))
328 before_content = PR_TRUE;
329 }
330 break;
331 }
332
333 if (before_content) {
334 /*
335 * This will cause the next SEC_ASN1EncoderUpdate to take the
336 * contents bytes from the passed-in buffer.
337 */
338 SEC_ASN1EncoderSetTakeFromBuf (p7ecx->ecx);
339 /*
340 * And that is all we needed this notify function for.
341 */
342 SEC_ASN1EncoderClearNotifyProc (p7ecx->ecx);
343 }
344 }
345
346
347 static SEC_PKCS7EncoderContext *
348 sec_pkcs7_encoder_start_contexts (SEC_PKCS7ContentInfo *cinfo,
349 PK11SymKey *bulkkey)
350 {
351 SEC_PKCS7EncoderContext *p7ecx;
352 SECOidTag kind;
353 PRBool encrypt;
354 SECItem **digests;
355 SECAlgorithmID *digestalg, **digestalgs;
356
357 p7ecx =
358 (SEC_PKCS7EncoderContext*)PORT_ZAlloc (sizeof(SEC_PKCS7EncoderContext));
359 if (p7ecx == NULL)
360 return NULL;
361
362 digests = NULL;
363 digestalg = NULL;
364 digestalgs = NULL;
365 encrypt = PR_FALSE;
366
367 kind = SEC_PKCS7ContentType (cinfo);
368 switch (kind) {
369 default:
370 case SEC_OID_PKCS7_DATA:
371 break;
372 case SEC_OID_PKCS7_DIGESTED_DATA:
373 digestalg = &(cinfo->content.digestedData->digestAlg);
374 break;
375 case SEC_OID_PKCS7_SIGNED_DATA:
376 digests = cinfo->content.signedData->digests;
377 digestalgs = cinfo->content.signedData->digestAlgorithms;
378 break;
379 case SEC_OID_PKCS7_ENCRYPTED_DATA:
380 case SEC_OID_PKCS7_ENVELOPED_DATA:
381 encrypt = PR_TRUE;
382 break;
383 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
384 digests = cinfo->content.signedAndEnvelopedData->digests;
385 digestalgs = cinfo->content.signedAndEnvelopedData->digestAlgorithms;
386 encrypt = PR_TRUE;
387 break;
388 }
389
390 if (encrypt) {
391 p7ecx->encryptobj = sec_pkcs7_encoder_start_encrypt (cinfo, bulkkey);
392 if (p7ecx->encryptobj == NULL) {
393 PORT_Free (p7ecx);
394 return NULL;
395 }
396 }
397
398 if (digestalgs != NULL) {
399 if (digests != NULL) {
400 /* digests already created (probably for detached data) */
401 digestalg = NULL;
402 } else {
403 /*
404 * XXX Some day we should handle multiple digests; for now,
405 * assume only one will be done.
406 */
407 PORT_Assert (digestalgs[0] != NULL && digestalgs[1] == NULL);
408 digestalg = digestalgs[0];
409 }
410 }
411
412 if (digestalg != NULL) {
413 SECOidTag oidTag = SECOID_FindOIDTag(&(digestalg->algorithm));
414
415 p7ecx->digestobj = HASH_GetHashObjectByOidTag(oidTag);
416 if (p7ecx->digestobj != NULL) {
417 p7ecx->digestcx = (* p7ecx->digestobj->create) ();
418 if (p7ecx->digestcx == NULL)
419 p7ecx->digestobj = NULL;
420 else
421 (* p7ecx->digestobj->begin) (p7ecx->digestcx);
422 }
423 if (p7ecx->digestobj == NULL) {
424 if (p7ecx->encryptobj != NULL)
425 sec_PKCS7DestroyEncryptObject (p7ecx->encryptobj);
426 PORT_Free (p7ecx);
427 return NULL;
428 }
429 }
430
431 p7ecx->cinfo = cinfo;
432 return p7ecx;
433 }
434
435
436 SEC_PKCS7EncoderContext *
437 SEC_PKCS7EncoderStart (SEC_PKCS7ContentInfo *cinfo,
438 SEC_PKCS7EncoderOutputCallback outputfn,
439 void *outputarg,
440 PK11SymKey *bulkkey)
441 {
442 SEC_PKCS7EncoderContext *p7ecx;
443 SECStatus rv;
444
445 p7ecx = sec_pkcs7_encoder_start_contexts (cinfo, bulkkey);
446 if (p7ecx == NULL)
447 return NULL;
448
449 p7ecx->output.outputfn = outputfn;
450 p7ecx->output.outputarg = outputarg;
451
452 /*
453 * Initialize the BER encoder.
454 */
455 p7ecx->ecx = SEC_ASN1EncoderStart (cinfo, sec_PKCS7ContentInfoTemplate,
456 sec_pkcs7_encoder_out, &(p7ecx->output));
457 if (p7ecx->ecx == NULL) {
458 PORT_Free (p7ecx);
459 return NULL;
460 }
461
462 /*
463 * Indicate that we are streaming. We will be streaming until we
464 * get past the contents bytes.
465 */
466 SEC_ASN1EncoderSetStreaming (p7ecx->ecx);
467
468 /*
469 * The notify function will watch for the contents field.
470 */
471 SEC_ASN1EncoderSetNotifyProc (p7ecx->ecx, sec_pkcs7_encoder_notify, p7ecx);
472
473 /*
474 * This will encode everything up to the content bytes. (The notify
475 * function will then cause the encoding to stop there.) Then our
476 * caller can start passing contents bytes to our Update, which we
477 * will pass along.
478 */
479 rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, NULL, 0);
480 if (rv != SECSuccess) {
481 PORT_Free (p7ecx);
482 return NULL;
483 }
484
485 return p7ecx;
486 }
487
488
489 /*
490 * XXX If/when we support nested contents, this needs to be revised.
491 */
492 static SECStatus
493 sec_pkcs7_encoder_work_data (SEC_PKCS7EncoderContext *p7ecx, SECItem *dest,
494 const unsigned char *data, unsigned long len,
495 PRBool final)
496 {
497 unsigned char *buf = NULL;
498 SECStatus rv;
499
500
501 rv = SECSuccess; /* may as well be optimistic */
502
503 /*
504 * We should really have data to process, or we should be trying
505 * to finish/flush the last block. (This is an overly paranoid
506 * check since all callers are in this file and simple inspection
507 * proves they do it right. But it could find a bug in future
508 * modifications/development, that is why it is here.)
509 */
510 PORT_Assert ((data != NULL && len) || final);
511
512 /*
513 * Update the running digest.
514 * XXX This needs modification if/when we handle multiple digests.
515 */
516 if (len && p7ecx->digestobj != NULL) {
517 (* p7ecx->digestobj->update) (p7ecx->digestcx, data, len);
518 }
519
520 /*
521 * Encrypt this chunk.
522 */
523 if (p7ecx->encryptobj != NULL) {
524 /* XXX the following lengths should all be longs? */
525 unsigned int inlen; /* length of data being encrypted */
526 unsigned int outlen; /* length of encrypted data */
527 unsigned int buflen; /* length available for encrypted data */
528
529 inlen = len;
530 buflen = sec_PKCS7EncryptLength (p7ecx->encryptobj, inlen, final);
531 if (buflen == 0) {
532 /*
533 * No output is expected, but the input data may be buffered
534 * so we still have to call Encrypt.
535 */
536 rv = sec_PKCS7Encrypt (p7ecx->encryptobj, NULL, NULL, 0,
537 data, inlen, final);
538 if (final) {
539 len = 0;
540 goto done;
541 }
542 return rv;
543 }
544
545 if (dest != NULL)
546 buf = (unsigned char*)PORT_ArenaAlloc(p7ecx->cinfo->poolp, buflen);
547 else
548 buf = (unsigned char*)PORT_Alloc (buflen);
549
550 if (buf == NULL) {
551 rv = SECFailure;
552 } else {
553 rv = sec_PKCS7Encrypt (p7ecx->encryptobj, buf, &outlen, buflen,
554 data, inlen, final);
555 data = buf;
556 len = outlen;
557 }
558 if (rv != SECSuccess) {
559 if (final)
560 goto done;
561 return rv;
562 }
563 }
564
565 if (p7ecx->ecx != NULL) {
566 /*
567 * Encode the contents bytes.
568 */
569 if(len) {
570 rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, (const char *)data, len);
571 }
572 }
573
574 done:
575 if (p7ecx->encryptobj != NULL) {
576 if (final)
577 sec_PKCS7DestroyEncryptObject (p7ecx->encryptobj);
578 if (dest != NULL) {
579 dest->data = buf;
580 dest->len = len;
581 } else if (buf != NULL) {
582 PORT_Free (buf);
583 }
584 }
585
586 if (final && p7ecx->digestobj != NULL) {
587 SECItem *digest, **digests, ***digestsp;
588 unsigned char *digdata;
589 SECOidTag kind;
590
591 kind = SEC_PKCS7ContentType (p7ecx->cinfo);
592 switch (kind) {
593 default:
594 PORT_Assert (0);
595 return SECFailure;
596 case SEC_OID_PKCS7_DIGESTED_DATA:
597 digest = &(p7ecx->cinfo->content.digestedData->digest);
598 digestsp = NULL;
599 break;
600 case SEC_OID_PKCS7_SIGNED_DATA:
601 digest = NULL;
602 digestsp = &(p7ecx->cinfo->content.signedData->digests);
603 break;
604 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
605 digest = NULL;
606 digestsp = &(p7ecx->cinfo->content.signedAndEnvelopedData->digests);
607 break;
608 }
609
610 digdata = (unsigned char*)PORT_ArenaAlloc (p7ecx->cinfo->poolp,
611 p7ecx->digestobj->length);
612 if (digdata == NULL)
613 return SECFailure;
614
615 if (digestsp != NULL) {
616 PORT_Assert (digest == NULL);
617
618 digest = (SECItem*)PORT_ArenaAlloc (p7ecx->cinfo->poolp,
619 sizeof(SECItem));
620 digests = (SECItem**)PORT_ArenaAlloc (p7ecx->cinfo->poolp,
621 2 * sizeof(SECItem *));
622 if (digests == NULL || digest == NULL)
623 return SECFailure;
624
625 digests[0] = digest;
626 digests[1] = NULL;
627
628 *digestsp = digests;
629 }
630
631 PORT_Assert (digest != NULL);
632
633 digest->data = digdata;
634 digest->len = p7ecx->digestobj->length;
635
636 (* p7ecx->digestobj->end) (p7ecx->digestcx, digest->data,
637 &(digest->len), digest->len);
638 (* p7ecx->digestobj->destroy) (p7ecx->digestcx, PR_TRUE);
639 }
640
641 return rv;
642 }
643
644
645 SECStatus
646 SEC_PKCS7EncoderUpdate (SEC_PKCS7EncoderContext *p7ecx,
647 const char *data, unsigned long len)
648 {
649 /* XXX Error handling needs help. Return what? Do "Finish" on failure? */
650 return sec_pkcs7_encoder_work_data (p7ecx, NULL,
651 (const unsigned char *)data, len,
652 PR_FALSE);
653 }
654
655 static SECStatus
656 sec_pkcs7_encoder_sig_and_certs (SEC_PKCS7ContentInfo *cinfo,
657 SECKEYGetPasswordKey pwfn, void *pwfnarg)
658 {
659 SECOidTag kind;
660 CERTCertificate **certs;
661 CERTCertificateList **certlists;
662 SECAlgorithmID **digestalgs;
663 SECItem **digests;
664 SEC_PKCS7SignerInfo *signerinfo, **signerinfos;
665 SECItem **rawcerts, ***rawcertsp;
666 PRArenaPool *poolp;
667 int certcount;
668 int ci, cli, rci, si;
669
670 kind = SEC_PKCS7ContentType (cinfo);
671 switch (kind) {
672 default:
673 case SEC_OID_PKCS7_DATA:
674 case SEC_OID_PKCS7_DIGESTED_DATA:
675 case SEC_OID_PKCS7_ENCRYPTED_DATA:
676 case SEC_OID_PKCS7_ENVELOPED_DATA:
677 certs = NULL;
678 certlists = NULL;
679 digestalgs = NULL;
680 digests = NULL;
681 signerinfos = NULL;
682 rawcertsp = NULL;
683 break;
684 case SEC_OID_PKCS7_SIGNED_DATA:
685 {
686 SEC_PKCS7SignedData *sdp;
687
688 sdp = cinfo->content.signedData;
689 certs = sdp->certs;
690 certlists = sdp->certLists;
691 digestalgs = sdp->digestAlgorithms;
692 digests = sdp->digests;
693 signerinfos = sdp->signerInfos;
694 rawcertsp = &(sdp->rawCerts);
695 }
696 break;
697 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
698 {
699 SEC_PKCS7SignedAndEnvelopedData *saedp;
700
701 saedp = cinfo->content.signedAndEnvelopedData;
702 certs = saedp->certs;
703 certlists = saedp->certLists;
704 digestalgs = saedp->digestAlgorithms;
705 digests = saedp->digests;
706 signerinfos = saedp->signerInfos;
707 rawcertsp = &(saedp->rawCerts);
708 }
709 break;
710 }
711
712 if (certs == NULL && certlists == NULL && signerinfos == NULL)
713 return SECSuccess; /* nothing for us to do! */
714
715 poolp = cinfo->poolp;
716 certcount = 0;
717
718 if (signerinfos != NULL) {
719 SECOidTag digestalgtag;
720 int di;
721 SECStatus rv;
722 CERTCertificate *cert;
723 SECKEYPrivateKey *privkey;
724 SECItem signature;
725 SECOidTag signalgtag;
726
727 PORT_Assert (digestalgs != NULL && digests != NULL);
728
729 /*
730 * If one fails, we bail right then. If we want to continue and
731 * try to do subsequent signatures, this loop, and the departures
732 * from it, will need to be reworked.
733 */
734 for (si = 0; signerinfos[si] != NULL; si++) {
735
736 signerinfo = signerinfos[si];
737
738 /* find right digest */
739 digestalgtag = SECOID_GetAlgorithmTag (&(signerinfo->digestAlg));
740 for (di = 0; digestalgs[di] != NULL; di++) {
741 /* XXX Should I be comparing more than the tag? */
742 if (digestalgtag == SECOID_GetAlgorithmTag (digestalgs[di]))
743 break;
744 }
745 if (digestalgs[di] == NULL) {
746 /* XXX oops; do what? set an error? */
747 return SECFailure;
748 }
749 PORT_Assert (digests[di] != NULL);
750
751 cert = signerinfo->cert;
752 privkey = PK11_FindKeyByAnyCert (cert, pwfnarg);
753 if (privkey == NULL)
754 return SECFailure;
755
756 /*
757 * XXX I think there should be a cert-level interface for this,
758 * so that I do not have to know about subjectPublicKeyInfo...
759 */
760 signalgtag = SECOID_GetAlgorithmTag (&(cert->subjectPublicKeyInfo.al gorithm));
761
762 if (signerinfo->authAttr != NULL) {
763 SEC_PKCS7Attribute *attr;
764 SECItem encoded_attrs;
765 SECItem *dummy;
766 SECOidTag algid;
767
768 /*
769 * First, find and fill in the message digest attribute.
770 */
771 attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
772 SEC_OID_PKCS9_MESSAGE_DIGEST,
773 PR_TRUE);
774 PORT_Assert (attr != NULL);
775 if (attr == NULL) {
776 SECKEY_DestroyPrivateKey (privkey);
777 return SECFailure;
778 }
779
780 /*
781 * XXX The second half of the following assertion prevents
782 * the encoder from being called twice on the same content.
783 * Either just remove the second half the assertion, or
784 * change the code to check if the value already there is
785 * the same as digests[di], whichever seems more right.
786 */
787 PORT_Assert (attr->values != NULL && attr->values[0] == NULL);
788 attr->values[0] = digests[di];
789
790 /*
791 * Before encoding, reorder the attributes so that when they
792 * are encoded, they will be conforming DER, which is required
793 * to have a specific order and that is what must be used for
794 * the hash/signature. We do this here, rather than building
795 * it into EncodeAttributes, because we do not want to do
796 * such reordering on incoming messages (which also uses
797 * EncodeAttributes) or our old signatures (and other "broken"
798 * implementations) will not verify. So, we want to guarantee
799 * that we send out good DER encodings of attributes, but not
800 * to expect to receive them.
801 */
802 rv = sec_PKCS7ReorderAttributes (signerinfo->authAttr);
803 if (rv != SECSuccess) {
804 SECKEY_DestroyPrivateKey (privkey);
805 return SECFailure;
806 }
807
808 encoded_attrs.data = NULL;
809 encoded_attrs.len = 0;
810 dummy = sec_PKCS7EncodeAttributes (NULL, &encoded_attrs,
811 &(signerinfo->authAttr));
812 if (dummy == NULL) {
813 SECKEY_DestroyPrivateKey (privkey);
814 return SECFailure;
815 }
816
817 algid = SEC_GetSignatureAlgorithmOidTag(privkey->keyType,
818 digestalgtag);
819 if (algid == SEC_OID_UNKNOWN) {
820 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
821 SECKEY_DestroyPrivateKey (privkey);
822 return SECFailure;
823 }
824 rv = SEC_SignData (&signature,
825 encoded_attrs.data, encoded_attrs.len,
826 privkey,
827 algid);
828 SECITEM_FreeItem (&encoded_attrs, PR_FALSE);
829 } else {
830 rv = SGN_Digest (privkey, digestalgtag, &signature,
831 digests[di]);
832 }
833
834 SECKEY_DestroyPrivateKey (privkey);
835
836 if (rv != SECSuccess)
837 return rv;
838
839 rv = SECITEM_CopyItem (poolp, &(signerinfo->encDigest), &signature);
840 if (rv != SECSuccess)
841 return rv;
842
843 SECITEM_FreeItem (&signature, PR_FALSE);
844
845 rv = SECOID_SetAlgorithmID (poolp, &(signerinfo->digestEncAlg),
846 signalgtag, NULL);
847 if (rv != SECSuccess)
848 return SECFailure;
849
850 /*
851 * Count the cert chain for this signer.
852 */
853 if (signerinfo->certList != NULL)
854 certcount += signerinfo->certList->len;
855 }
856 }
857
858 if (certs != NULL) {
859 for (ci = 0; certs[ci] != NULL; ci++)
860 certcount++;
861 }
862
863 if (certlists != NULL) {
864 for (cli = 0; certlists[cli] != NULL; cli++)
865 certcount += certlists[cli]->len;
866 }
867
868 if (certcount == 0)
869 return SECSuccess; /* signing done; no certs */
870
871 /*
872 * Combine all of the certs and cert chains into rawcerts.
873 * Note: certcount is an upper bound; we may not need that many slots
874 * but we will allocate anyway to avoid having to do another pass.
875 * (The temporary space saving is not worth it.)
876 */
877 rawcerts = (SECItem**)PORT_ArenaAlloc (poolp,
878 (certcount + 1) * sizeof(SECItem *));
879 if (rawcerts == NULL)
880 return SECFailure;
881
882 /*
883 * XXX Want to check for duplicates and not add *any* cert that is
884 * already in the set. This will be more important when we start
885 * dealing with larger sets of certs, dual-key certs (signing and
886 * encryption), etc. For the time being we can slide by...
887 */
888 rci = 0;
889 if (signerinfos != NULL) {
890 for (si = 0; signerinfos[si] != NULL; si++) {
891 signerinfo = signerinfos[si];
892 for (ci = 0; ci < signerinfo->certList->len; ci++)
893 rawcerts[rci++] = &(signerinfo->certList->certs[ci]);
894 }
895
896 }
897
898 if (certs != NULL) {
899 for (ci = 0; certs[ci] != NULL; ci++)
900 rawcerts[rci++] = &(certs[ci]->derCert);
901 }
902
903 if (certlists != NULL) {
904 for (cli = 0; certlists[cli] != NULL; cli++) {
905 for (ci = 0; ci < certlists[cli]->len; ci++)
906 rawcerts[rci++] = &(certlists[cli]->certs[ci]);
907 }
908 }
909
910 rawcerts[rci] = NULL;
911 *rawcertsp = rawcerts;
912
913 return SECSuccess;
914 }
915
916
917 SECStatus
918 SEC_PKCS7EncoderFinish (SEC_PKCS7EncoderContext *p7ecx,
919 SECKEYGetPasswordKey pwfn, void *pwfnarg)
920 {
921 SECStatus rv;
922
923 /*
924 * Flush out any remaining data.
925 */
926 rv = sec_pkcs7_encoder_work_data (p7ecx, NULL, NULL, 0, PR_TRUE);
927
928 /*
929 * Turn off streaming stuff.
930 */
931 SEC_ASN1EncoderClearTakeFromBuf (p7ecx->ecx);
932 SEC_ASN1EncoderClearStreaming (p7ecx->ecx);
933
934 if (rv != SECSuccess)
935 goto loser;
936
937 rv = sec_pkcs7_encoder_sig_and_certs (p7ecx->cinfo, pwfn, pwfnarg);
938 if (rv != SECSuccess)
939 goto loser;
940
941 rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, NULL, 0);
942
943 loser:
944 SEC_ASN1EncoderFinish (p7ecx->ecx);
945 PORT_Free (p7ecx);
946 return rv;
947 }
948
949 /*
950 * Abort the ASN.1 stream. Used by pkcs 12
951 */
952 void
953 SEC_PKCS7EncoderAbort(SEC_PKCS7EncoderContext *p7ecx, int error)
954 {
955 PORT_Assert(p7ecx);
956 SEC_ASN1EncoderAbort(p7ecx->ecx, error);
957 }
958
959 /*
960 * After this routine is called, the entire PKCS7 contentInfo is ready
961 * to be encoded. This is used internally, but can also be called from
962 * elsewhere for those who want to be able to just have pointers to
963 * the ASN1 template for pkcs7 contentInfo built into their own encodings.
964 */
965 SECStatus
966 SEC_PKCS7PrepareForEncode (SEC_PKCS7ContentInfo *cinfo,
967 PK11SymKey *bulkkey,
968 SECKEYGetPasswordKey pwfn,
969 void *pwfnarg)
970 {
971 SEC_PKCS7EncoderContext *p7ecx;
972 SECItem *content, *enc_content;
973 SECStatus rv;
974
975 p7ecx = sec_pkcs7_encoder_start_contexts (cinfo, bulkkey);
976 if (p7ecx == NULL)
977 return SECFailure;
978
979 content = SEC_PKCS7GetContent (cinfo);
980
981 if (p7ecx->encryptobj != NULL) {
982 SECOidTag kind;
983 SEC_PKCS7EncryptedContentInfo *enccinfo;
984
985 kind = SEC_PKCS7ContentType (p7ecx->cinfo);
986 switch (kind) {
987 default:
988 PORT_Assert (0);
989 rv = SECFailure;
990 goto loser;
991 case SEC_OID_PKCS7_ENCRYPTED_DATA:
992 enccinfo = &(p7ecx->cinfo->content.encryptedData->encContentInfo);
993 break;
994 case SEC_OID_PKCS7_ENVELOPED_DATA:
995 enccinfo = &(p7ecx->cinfo->content.envelopedData->encContentInfo);
996 break;
997 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
998 enccinfo = &(p7ecx->cinfo->content.signedAndEnvelopedData->encConten tInfo);
999 break;
1000 }
1001 enc_content = &(enccinfo->encContent);
1002 } else {
1003 enc_content = NULL;
1004 }
1005
1006 if (content != NULL && content->data != NULL && content->len) {
1007 rv = sec_pkcs7_encoder_work_data (p7ecx, enc_content,
1008 content->data, content->len, PR_TRUE);
1009 if (rv != SECSuccess)
1010 goto loser;
1011 }
1012
1013 rv = sec_pkcs7_encoder_sig_and_certs (cinfo, pwfn, pwfnarg);
1014
1015 loser:
1016 PORT_Free (p7ecx);
1017 return rv;
1018 }
1019
1020
1021 /*
1022 * Encode a PKCS7 object, in one shot. All necessary components
1023 * of the object must already be specified. Either the data has
1024 * already been included (via SetContent), or the data is detached,
1025 * or there is no data at all (certs-only).
1026 *
1027 * "cinfo" specifies the object to be encoded.
1028 *
1029 * "outputfn" is where the encoded bytes will be passed.
1030 *
1031 * "outputarg" is an opaque argument to the above callback.
1032 *
1033 * "bulkkey" specifies the bulk encryption key to use. This argument
1034 * can be NULL if no encryption is being done, or if the bulk key should
1035 * be generated internally (usually the case for EnvelopedData but never
1036 * for EncryptedData, which *must* provide a bulk encryption key).
1037 *
1038 * "pwfn" is a callback for getting the password which protects the
1039 * private key of the signer. This argument can be NULL if it is known
1040 * that no signing is going to be done.
1041 *
1042 * "pwfnarg" is an opaque argument to the above callback.
1043 */
1044 SECStatus
1045 SEC_PKCS7Encode (SEC_PKCS7ContentInfo *cinfo,
1046 SEC_PKCS7EncoderOutputCallback outputfn,
1047 void *outputarg,
1048 PK11SymKey *bulkkey,
1049 SECKEYGetPasswordKey pwfn,
1050 void *pwfnarg)
1051 {
1052 SECStatus rv;
1053
1054 rv = SEC_PKCS7PrepareForEncode (cinfo, bulkkey, pwfn, pwfnarg);
1055 if (rv == SECSuccess) {
1056 struct sec_pkcs7_encoder_output outputcx;
1057
1058 outputcx.outputfn = outputfn;
1059 outputcx.outputarg = outputarg;
1060
1061 rv = SEC_ASN1Encode (cinfo, sec_PKCS7ContentInfoTemplate,
1062 sec_pkcs7_encoder_out, &outputcx);
1063 }
1064
1065 return rv;
1066 }
1067
1068
1069 /*
1070 * Encode a PKCS7 object, in one shot. All necessary components
1071 * of the object must already be specified. Either the data has
1072 * already been included (via SetContent), or the data is detached,
1073 * or there is no data at all (certs-only). The output, rather than
1074 * being passed to an output function as is done above, is all put
1075 * into a SECItem.
1076 *
1077 * "pool" specifies a pool from which to allocate the result.
1078 * It can be NULL, in which case memory is allocated generically.
1079 *
1080 * "dest" specifies a SECItem in which to put the result data.
1081 * It can be NULL, in which case the entire item is allocated, too.
1082 *
1083 * "cinfo" specifies the object to be encoded.
1084 *
1085 * "bulkkey" specifies the bulk encryption key to use. This argument
1086 * can be NULL if no encryption is being done, or if the bulk key should
1087 * be generated internally (usually the case for EnvelopedData but never
1088 * for EncryptedData, which *must* provide a bulk encryption key).
1089 *
1090 * "pwfn" is a callback for getting the password which protects the
1091 * private key of the signer. This argument can be NULL if it is known
1092 * that no signing is going to be done.
1093 *
1094 * "pwfnarg" is an opaque argument to the above callback.
1095 */
1096 SECItem *
1097 SEC_PKCS7EncodeItem (PRArenaPool *pool,
1098 SECItem *dest,
1099 SEC_PKCS7ContentInfo *cinfo,
1100 PK11SymKey *bulkkey,
1101 SECKEYGetPasswordKey pwfn,
1102 void *pwfnarg)
1103 {
1104 SECStatus rv;
1105
1106 rv = SEC_PKCS7PrepareForEncode (cinfo, bulkkey, pwfn, pwfnarg);
1107 if (rv != SECSuccess)
1108 return NULL;
1109
1110 return SEC_ASN1EncodeItem (pool, dest, cinfo, sec_PKCS7ContentInfoTemplate);
1111 }
1112
OLDNEW
« no previous file with comments | « mozilla/security/nss/lib/pkcs7/p7decode.c ('k') | mozilla/security/nss/lib/pkcs7/p7local.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698