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

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

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

Powered by Google App Engine
This is Rietveld 408576698