comparison nss/lib/pkcs7/p7encode.c @ 0:1e5118fa0cb1

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