001 // Copyright (C) 2002 IAIK
002 // https://jce.iaik.tugraz.at
003 //
004 // Copyright (C) 2003 - 2025 Stiftung Secure Information and
005 // Communication Technologies SIC
006 // https://sic.tech
007 //
008 // All rights reserved.
009 //
010 // Redistribution and use in source and binary forms, with or without
011 // modification, are permitted provided that the following conditions
012 // are met:
013 // 1. Redistributions of source code must retain the above copyright
014 // notice, this list of conditions and the following disclaimer.
015 // 2. Redistributions in binary form must reproduce the above copyright
016 // notice, this list of conditions and the following disclaimer in the
017 // documentation and/or other materials provided with the distribution.
018 //
019 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
020 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
021 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
022 // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
023 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
024 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
025 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
026 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
027 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
028 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
029 // SUCH DAMAGE.
030
031 // Copyright (C) 2002 IAIK
032 // https://sic.tech/
033 //
034 // Copyright (C) 2003 - 2025 Stiftung Secure Information and
035 // Communication Technologies SIC
036 // https://sic.tech/
037 //
038 // All rights reserved.
039 //
040 // This source is provided for inspection purposes and recompilation only,
041 // unless specified differently in a contract with IAIK. This source has to
042 // be kept in strict confidence and must not be disclosed to any third party
043 // under any circumstances. Redistribution in source and binary forms, with
044 // or without modification, are <not> permitted in any case!
045 //
046 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
047 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
048 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
049 // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
050 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
051 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
052 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
053 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
054 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
055 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
056 // SUCH DAMAGE.
057 //
058 // $Header: /IAIK-CMS/current/src/demo/cms/signedData/CounterSignatureDemo.java 30 12.02.25 17:58 Dbratko $
059 // $Revision: 30 $
060 //
061
062 package demo.cms.signedData;
063
064 import iaik.asn1.CodingException;
065 import iaik.asn1.ObjectID;
066 import iaik.asn1.structures.AlgorithmID;
067 import iaik.asn1.structures.Attribute;
068 import iaik.asn1.structures.AttributeValue;
069 import iaik.cms.CMSException;
070 import iaik.cms.ContentInfo;
071 import iaik.cms.ContentInfoStream;
072 import iaik.cms.IssuerAndSerialNumber;
073 import iaik.cms.SignedData;
074 import iaik.cms.SignedDataStream;
075 import iaik.cms.SignerInfo;
076 import iaik.cms.attributes.CMSContentType;
077 import iaik.cms.attributes.CounterSignature;
078 import iaik.cms.attributes.SigningTime;
079 import iaik.utils.Util;
080 import iaik.x509.X509Certificate;
081
082 import java.io.ByteArrayInputStream;
083 import java.io.ByteArrayOutputStream;
084 import java.io.IOException;
085 import java.io.InputStream;
086 import java.security.NoSuchAlgorithmException;
087 import java.security.PrivateKey;
088 import java.security.SignatureException;
089
090 import demo.DemoUtil;
091 import demo.keystore.CMSKeyStore;
092
093 /**
094 * This class demonstrates the usage of the CounterSignature attribute.
095 * <p>
096 * A {@link iaik.cms.attributes.CounterSignature CounterSignature} attribute may be included
097 * as an unsigned attribute into a {@link iaik.cms.SignerInfo SignerInfo} for counter signing
098 * (signing in serial) the signature value of a SignerInfo included in a SignedData. The value
099 * of a CounterSignature attribute itself is a SignerInfo.
100 * <p>
101 * This demo shows how a CounterSignature attribute may be added to some SignerInfo that belongs
102 * to a SignedData object just parsed/verified. This class demonstrates adding/verifying of a
103 * CounterSignature attribute to both the {@link iaik.cms.SignedDataStream stream} and the
104 * {@link iaik.cms.SignedData non-stream} implementations of the SignedData type. Since when
105 * parsing an implicit -- where the content is included -- SignedData object, SignerInfos
106 * can not accessed before the data has been processed, adding a counter signature to
107 * a {@link iaik.cms.SignedDataStream SignedDataStream} may require a different proceeding
108 * than adding it to a {@link iaik.cms.SignedData SignedData} object. For that reason a
109 * {@link CounterSignatureListener CounterSignatureListener} is used for the
110 * stream demos to listen on and add the counter signature during the encoding process.
111 *
112 * @see CounterSignatureListener
113 * @see iaik.cms.attributes.CounterSignature
114 * @see iaik.cms.SDSEncodeListener
115 * @see iaik.cms.SignedDataStream
116 * @see iaik.cms.SignerInfo
117 */
118 public class CounterSignatureDemo {
119
120 byte[] message;
121
122 // signing certificate of user 1
123 X509Certificate user1_sign;
124 // signing private key of user 1
125 PrivateKey user1_sign_pk;
126 // signing certificate of user 2 (counter signer)
127 X509Certificate user2_sign;
128 // signing private key of user 2 (counter signer)
129 PrivateKey user2_sign_pk;
130
131 // a certificate chain containing the user certs + CA
132 X509Certificate[] certificates;
133
134 /**
135 * Constructor.
136 * Reads required keys/certs from the demo keystore.
137 */
138 public CounterSignatureDemo() {
139
140 System.out.println();
141 System.out.println("**********************************************************************************");
142 System.out.println("* CounterSignatureDemo demo *");
143 System.out.println("* (shows the usage of the CounterSignature attribute implementation) *");
144 System.out.println("**********************************************************************************");
145 System.out.println();
146
147 message = "This is a test of the CMS implementation!".getBytes();
148 // signing certs
149 certificates = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
150 user1_sign = certificates[0];
151 user1_sign_pk = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
152 user2_sign = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1)[0];
153 user2_sign_pk = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
154 }
155
156 /**
157 * Creates a CMS <code>SignedData</code> object.
158 * <p>
159 *
160 * @param message the message to be signed, as byte representation
161 * @param mode the mode indicating whether to include the content
162 * (SignedDataStream.IMPLICIT) or not (SignedDataStream.EXPLICIT)
163 * @return the encoding of the <code>SignedData</code> object just created
164 * @throws Exception if the <code>SignedData</code> object cannot
165 * be created for some reason
166 */
167 public byte[] createSignedDataStream(byte[] message, int mode) throws Exception {
168
169 System.out.println("Create a new message signed by user 1:");
170
171 // we are testing the stream interface
172 ByteArrayInputStream is = new ByteArrayInputStream(message);
173 // create a new SignedData object which includes the data
174 SignedDataStream signed_data = new SignedDataStream(is, mode);
175
176 // SignedData shall include the certificate chain for verifying
177 signed_data.setCertificates(certificates);
178
179 // cert at index 0 is the user certificate
180 IssuerAndSerialNumber issuer = new IssuerAndSerialNumber(user1_sign);
181
182 // create a new SignerInfo
183 SignerInfo signer_info = new SignerInfo(issuer, (AlgorithmID)AlgorithmID.sha256.clone(), user1_sign_pk);
184 // create some authenticated attributes
185 // the message digest attribute is automatically added
186 Attribute[] attributes = new Attribute[2];
187 // content type is data
188 attributes[0] = new Attribute(new CMSContentType(ObjectID.cms_data));
189 // signing time is now
190 attributes[1] = new Attribute(new SigningTime());
191 // set the attributes
192 signer_info.setSignedAttributes(attributes);
193 // finish the creation of SignerInfo by calling method addSigner
194 try {
195 signed_data.addSignerInfo(signer_info);
196
197 } catch (NoSuchAlgorithmException ex) {
198 throw new CMSException("No implementation for signature algorithm: "+ex.getMessage());
199 }
200 // ensure block encoding
201 signed_data.setBlockSize(2048);
202
203 // write the data through SignedData to any out-of-band place
204 if (mode == SignedDataStream.EXPLICIT) {
205 InputStream data_is = signed_data.getInputStream();
206 byte[] buf = new byte[1024];
207 int r;
208 while ((r = data_is.read(buf)) > 0) {
209 ; // skip data
210 }
211 }
212
213 // return the SignedData as encoded byte array with block size 2048
214 ByteArrayOutputStream os = new ByteArrayOutputStream();
215 // wrap into ContentInfo
216 ContentInfoStream ci = new ContentInfoStream(signed_data);
217 ci.writeTo(os);
218 return os.toByteArray();
219 }
220
221 /**
222 * Parses a CMS <code>SignedData</code> object and verifies the signatures
223 * for all participated signers.
224 *
225 * @param signedData the SignedData, as BER encoded byte array
226 * @param message the the message which was transmitted out-of-band (explicit signed)
227 * @param counterSign whether to use a SDSEncodeListener to add a SignerInfo
228 * and encode the SignedData again
229 *
230 * @return the inherent message as byte array, or the BER encoded SignedData if
231 * it shall be encoded again (counter signing phase)
232 * @throws Exception if an error occurs
233 */
234 public byte[] getSignedDataStream(byte[] signedData, byte[] message, boolean counterSign)
235 throws Exception {
236
237 // we are testing the stream interface
238 ByteArrayInputStream is = new ByteArrayInputStream(signedData);
239
240 // the ByteArrayOutputStream to which to write the content
241 ByteArrayOutputStream os = new ByteArrayOutputStream();
242
243 SignedDataStream signed_data = new SignedDataStream(is);
244
245 // content included (implicit mode)?
246 boolean implicit = (signed_data.getMode() == SignedDataStream.IMPLICIT);
247
248 if (implicit == false) {
249 // in explicit mode explicitly supply the content for hash computation
250 signed_data.setInputStream(new ByteArrayInputStream(message));
251 }
252
253
254 if (counterSign) {
255 // we want to write the SignedData again
256 // we add a counter signature attribute to the first signer
257
258 // add the CounterSignature via SDSEncodeListener
259 CounterSignatureListener csl =
260 new CounterSignatureListener(new IssuerAndSerialNumber(user2_sign),
261 (AlgorithmID)AlgorithmID.sha256.clone(),
262 user2_sign_pk);
263 // we only want to counter sign some specific signer
264 csl.setCertOfSignerToBeCounterSigned(user1_sign);
265
266 if (implicit) {
267 // in implicit mode copy data to os
268 csl.setOutputStream(os);
269 signed_data.setSDSEncodeListener(csl);
270
271 } else {
272 signed_data.setSDSEncodeListener(csl);
273 // get an InputStream for reading the signed content
274 InputStream data = signed_data.getInputStream();
275 Util.copyStream(data, os, null);
276 }
277
278 // ensure block encoding
279 signed_data.setBlockSize(2048);
280 // return the SignedData as encoded byte array with block size 2048
281 ByteArrayOutputStream baos = new ByteArrayOutputStream();
282 // wrap into ContentInfo
283 ContentInfoStream ci = new ContentInfoStream(signed_data);
284 ci.writeTo(baos);
285
286 // we read the content
287 byte[] content = os.toByteArray();
288 System.out.println("Content: " + new String(content));
289
290 // return encoded SignedData
291 return baos.toByteArray();
292
293 } else {
294
295 // get an InputStream for reading the signed content
296 InputStream data = signed_data.getInputStream();
297 os = new ByteArrayOutputStream();
298 Util.copyStream(data, os, null);
299
300 System.out.println("SignedData contains the following signer information:");
301 SignerInfo[] signer_infos = signed_data.getSignerInfos();
302
303 int numberOfSignerInfos = signer_infos.length;
304 if (numberOfSignerInfos == 0) {
305 String warning = "Warning: Unsigned message (no SignerInfo included)!";
306 System.err.println(warning);
307 throw new CMSException(warning);
308 } else {
309 for (int i = 0; i < numberOfSignerInfos; i++) {
310 try {
311 // verify the signed data using the SignerInfo at index i
312 X509Certificate signer_cert = signed_data.verify(i);
313 // if the signature is OK the certificate of the signer is returned
314 System.out.println("Signature OK from signer: "+signer_cert.getSubjectDN());
315 // get signed attributes
316 // signing time
317 SigningTime signingTime = (SigningTime)signer_infos[i].getSignedAttributeValue(ObjectID.signingTime);
318 if (signingTime != null) {
319 System.out.println("This message has been signed at " + signingTime.get());
320 }
321 // content type
322 CMSContentType contentType = (CMSContentType)signer_infos[i].getSignedAttributeValue(ObjectID.contentType);
323 if (contentType != null) {
324 System.out.println("The content has CMS content type " + contentType.get().getName());
325 }
326 // counter signature?
327 Attribute counterSignatureAttribute = signer_infos[i].getUnsignedAttribute(ObjectID.countersignature);
328 if (counterSignatureAttribute != null) {
329 AttributeValue[] counterSignatures = counterSignatureAttribute.getAttributeValues();
330 System.out.println("This SignerInfo is counter signed from: ");
331 for (int j = 0; j < counterSignatures.length; j++) {
332 CounterSignature counterSignature = (CounterSignature)counterSignatures[j];
333 try {
334 if (counterSignature.verify(user2_sign.getPublicKey(), signer_infos[i])) {
335 System.out.println("Signature OK from counter signer: "+counterSignature.getSignerIdentifier());
336 } else {
337 System.out.println("Signature ERROR from counter signer: "+counterSignature.getSignerIdentifier());
338 }
339 } catch (SignatureException ex) {
340 System.out.println("Signature ERROR from counter signer: "+counterSignature.getSignerIdentifier());
341 throw new CMSException(ex.toString());
342 }
343 signingTime = (SigningTime)counterSignature.getSignedAttributeValue(ObjectID.signingTime);
344 if (signingTime != null) {
345 System.out.println("Counter signature has been created " + signingTime.get());
346 }
347 }
348 }
349
350 } catch (SignatureException ex) {
351 // if the signature is not OK a SignatureException is thrown
352 System.err.println("Signature ERROR from signer: "+signed_data.getCertificate((signer_infos[i].getSignerIdentifier())).getSubjectDN());
353 throw new CMSException(ex.toString());
354 } catch (CodingException ex) {
355 throw new CMSException("Attribute decoding error: " + ex.toString());
356 }
357 }
358 // in practice we also would validate the signer certificate(s)
359 }
360
361 // return content
362 return os.toByteArray();
363 }
364 }
365
366
367 /**
368 * Creates a CMS <code>SignedData</code> object.
369 * <p>
370 *
371 * @param message the message to be signed, as byte representation
372 * @param mode the mode indicating whether to include the content
373 * (SignedDataStream.IMPLICIT) or not (SignedDataStream.EXPLICIT)
374 * @return the encoding of the <code>SignedData</code> object just created
375 * @throws CMSException if the <code>SignedData</code> object cannot
376 * be created
377 * @throws Exception if an error occurs
378 */
379 public byte[] createSignedData(byte[] message, int mode) throws Exception {
380
381 System.out.println("Create a new message signed by user 1:");
382
383 // create a new SignedData object
384 SignedData signed_data = new SignedData(message, mode);
385
386 // SignedData shall include the certificate chain for verifying
387 signed_data.setCertificates(certificates);
388
389 // cert at index 0 is the user certificate
390 IssuerAndSerialNumber issuer = new IssuerAndSerialNumber(user1_sign);
391
392 // create a new SignerInfo
393 SignerInfo signer_info = new SignerInfo(issuer, (AlgorithmID)AlgorithmID.sha256.clone(), user1_sign_pk);
394 // create some authenticated attributes
395 // the message digest attribute is automatically added
396 Attribute[] attributes = new Attribute[2];
397 // content type is data
398 attributes[0] = new Attribute(new CMSContentType(ObjectID.cms_data));
399 // signing time is now
400 attributes[1] = new Attribute(new SigningTime());
401 // set the attributes
402 signer_info.setSignedAttributes(attributes);
403 // finish the creation of SignerInfo by calling method addSigner
404 try {
405 signed_data.addSignerInfo(signer_info);
406
407 } catch (NoSuchAlgorithmException ex) {
408 throw new CMSException("No implementation for signature algorithm: "+ex.getMessage());
409 }
410
411 // return the SignedData as encoded byte array with block size 2048
412 ByteArrayOutputStream os = new ByteArrayOutputStream();
413 // wrap into ContentInfo
414 ContentInfo ci = new ContentInfo(signed_data);
415 ci.writeTo(os);
416 return os.toByteArray();
417 }
418
419 /**
420 * Parses a CMS <code>SignedData</code> object and verifies the signatures
421 * for all participated signers.
422 *
423 * @param signedData the SignedData, as BER encoded byte array
424 * @param message the the message which was transmitted out-of-band (explicit signed)
425 * @param counterSign whether to use a SDSEncodeListener to add a SignerInfo
426 * and encode the SignedData again
427 *
428 * @return the inherent message as byte array, or the BER encoded SignedData if
429 * it shall be encoded again (counter signing phase)
430 * @throws Exception if any error occurs
431 */
432 public byte[] getSignedData(byte[] signedData, byte[] message, boolean counterSign)
433 throws Exception {
434
435 // we are testing the stream interface
436 ByteArrayInputStream is = new ByteArrayInputStream(signedData);
437
438 SignedData signed_data = new SignedData(is);
439
440 // content included (implicit mode)?
441 boolean implicit = (signed_data.getMode() == SignedData.IMPLICIT);
442 if (implicit == false) {
443 // in explcit mode explictly supply the content data to do the hash calculation
444 signed_data.setContent(message);
445 }
446
447 System.out.println("SignedData contains the following signer information:");
448 SignerInfo[] signer_infos = signed_data.getSignerInfos();
449
450 int numberOfSignerInfos = signer_infos.length;
451 if (numberOfSignerInfos == 0) {
452 String warning = "Warning: Unsigned message (no SignerInfo included)!";
453 System.err.println(warning);
454 throw new CMSException(warning);
455 } else {
456 for (int i = 0; i < numberOfSignerInfos; i++) {
457 try {
458 // verify the signed data using the SignerInfo at index i
459 X509Certificate signer_cert = signed_data.verify(i);
460 // if the signature is OK the certificate of the signer is returned
461 System.out.println("Signature OK from signer: "+signer_cert.getSubjectDN());
462 // get signed attributes
463 // signing time
464 SigningTime signingTime = (SigningTime)signer_infos[i].getSignedAttributeValue(ObjectID.signingTime);
465 if (signingTime != null) {
466 System.out.println("This message has been signed at " + signingTime.get());
467 }
468 // content type
469 CMSContentType contentType = (CMSContentType)signer_infos[i].getSignedAttributeValue(ObjectID.contentType);
470 if (contentType != null) {
471 System.out.println("The content has CMS content type " + contentType.get().getName());
472 }
473 // counter signature?
474 Attribute counterSignatureAttribute = signer_infos[i].getUnsignedAttribute(ObjectID.countersignature);
475 if (counterSignatureAttribute != null) {
476 AttributeValue[] counterSignatures = counterSignatureAttribute.getAttributeValues();
477 System.out.println("This SignerInfo is counter signed from: ");
478 for (int j = 0; j < counterSignatures.length; j++) {
479 CounterSignature counterSignature = (CounterSignature)counterSignatures[j];
480 try {
481 if (counterSignature.verify(user2_sign.getPublicKey(), signer_infos[i])) {
482 System.out.println("Signature OK from counter signer: "+counterSignature.getSignerIdentifier());
483 } else {
484 System.out.println("Signature ERROR from counter signer: "+counterSignature.getSignerIdentifier());
485 }
486 } catch (SignatureException ex) {
487 System.out.println("Signature ERROR from counter signer: "+counterSignature.getSignerIdentifier());
488 throw new CMSException(ex.toString());
489 }
490 signingTime = (SigningTime)counterSignature.getSignedAttributeValue(ObjectID.signingTime);
491 if (signingTime != null) {
492 System.out.println("Counter signature has been created " + signingTime.get());
493 }
494 }
495 }
496
497 } catch (SignatureException ex) {
498 // if the signature is not OK a SignatureException is thrown
499 System.out.println("Signature ERROR from signer: "+signed_data.getCertificate((signer_infos[i].getSignerIdentifier())).getSubjectDN());
500 throw new CMSException(ex.toString());
501 } catch (CodingException ex) {
502 throw new CMSException("Attribute decoding error: " + ex.toString());
503 }
504 }
505 // in practice we also would validate the signer certificate(s)
506 }
507
508 if (counterSign) {
509 // we want to write the SignedData again
510 // we add a counter signature attribute to the first signer
511 CounterSignature counterSignature = new CounterSignature(new IssuerAndSerialNumber(user2_sign),
512 (AlgorithmID)AlgorithmID.sha256.clone(), user2_sign_pk);
513 // create some authenticated attributes
514 // the message digest attribute is automatically added
515 // signing time is now
516 SigningTime signingTime = new SigningTime();
517 Attribute[] attributes = { new Attribute(signingTime) };
518 // set the attributes
519 counterSignature.setSignedAttributes(attributes);
520 // now counter sign first SignerInfo
521 counterSignature.counterSign(signer_infos[0]);
522 // and add the counter signature as unsigned attribute
523 Attribute[] usignedAttributes = { new Attribute(counterSignature) };
524 signer_infos[0].addUnsignedAttributes(usignedAttributes);
525
526 ByteArrayOutputStream baos = new ByteArrayOutputStream();
527 ContentInfo ci = new ContentInfo(signed_data);
528 ci.writeTo(baos);
529 signed_data.writeTo(baos);
530
531 // we read the content
532 System.out.println("Content: " + new String(signed_data.getContent()));
533
534 return baos.toByteArray();
535
536 } else {
537 // return the content
538 return signed_data.getContent();
539 }
540
541
542 }
543
544 /**
545 * Starts the demo.
546 */
547 public void start() {
548
549 try {
550
551 byte[] data;
552 byte[] received_message = null;
553
554 //
555 // test CMS Implicit SignedDataStream
556 //
557 System.out.println("\nImplicit SignedDataStream demo [create]:\n");
558 data = createSignedDataStream(message, SignedDataStream.IMPLICIT);
559 // parse and encode again
560 System.out.println("\nImplicit SignedDataStream demo [counter sign]:\n");
561 data = getSignedDataStream(data, null, true);
562 // parse
563 System.out.println("\nImplicit SignedDataStream demo [parse]:\n");
564 received_message = getSignedDataStream(data, null, false);
565 System.out.print("\nSigned content: ");
566 System.out.println(new String(received_message));
567
568 //
569 // test CMS Explicit SignedDataStream
570 //
571 System.out.println("\nExplicit SignedDataStream demo [create]:\n");
572 data = createSignedDataStream(message, SignedDataStream.EXPLICIT);
573 // parse and encode again
574 System.out.println("\nExplicit SignedDataStream demo [counter sign]:\n");
575 data = getSignedDataStream(data, message, true);
576
577 System.out.println("\nExplicit SignedDataStream demo [parse]:\n");
578 received_message = getSignedDataStream(data, message, false);
579 System.out.print("\nSigned content: ");
580 System.out.println(new String(received_message));
581
582 //
583 // test CMS Implicit SignedData
584 //
585 System.out.println("\nImplicit SignedData demo [create]:\n");
586 data = createSignedData(message, SignedData.IMPLICIT);
587 // parse and encode again
588 System.out.println("\nImplicit SignedData demo [counter sign]:\n");
589 data = getSignedData(data, null, true);
590 // parse
591 System.out.println("\nImplicit SignedData demo [parse]:\n");
592 received_message = getSignedData(data, null, false);
593 System.out.print("\nSigned content: ");
594 System.out.println(new String(received_message));
595
596 //
597 // test CMS Explicit SignedData
598 //
599 System.out.println("\nExplicit SignedData demo [create]:\n");
600 data = createSignedData(message, SignedData.EXPLICIT);
601 // parse and encode again
602 System.out.println("\nExplicit SignedData demo [counter sign]:\n");
603 data = getSignedData(data, message, true);
604
605 System.out.println("\nExplicit SignedData demo [parse]:\n");
606 received_message = getSignedData(data, message, false);
607 System.out.print("\nSigned content: ");
608 System.out.println(new String(received_message));
609
610 } catch (Exception ex) {
611 ex.printStackTrace();
612 throw new RuntimeException(ex.toString());
613 }
614 }
615
616
617 /**
618 * Main method.
619 *
620 * @throws IOException
621 * if an I/O error occurs when reading required keys
622 * and certificates from files
623 */
624 public static void main(String argv[]) throws IOException {
625 try {
626 DemoUtil.initDemos();
627 (new CounterSignatureDemo()).start();
628 System.out.println("\nReady!");
629 } catch (Exception ex) {
630 ex.printStackTrace();
631 }
632 DemoUtil.waitKey();
633 }
634 }