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    }